From 75af797d4c7462b445461cc96590ac0f59fd841c Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 26 Jun 2024 17:32:36 +0200 Subject: [PATCH 01/59] 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 d230ab05b1..2a1a5a5ef0 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.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.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 @@ private T get(String key, Class root) { /** * 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 @@ private void set(String key, Object value, Class root) { 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 @@ private void set(String key, Object value, Class root) { } } 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 boolean load(File file) { 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 void save(File file) { } 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 void save(File file) { } /** - * 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 void save(File file) { } + /** + * 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 @@ private String toYamlString(Object value, String spacing) { 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 @@ private void save(PrintWriter writer, Class clazz, final Object instance, int } 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 @@ private void save(PrintWriter writer, Class clazz, final Object instance, int 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 @@ private void save(PrintWriter writer, Class clazz, final Object instance, int 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 @@ private void save(PrintWriter writer, Class clazz, final Object instance, int } 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 @@ private void handleConfigBlockSave( 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 @@ private void handleConfigBlockSave( } 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 @@ private void handleConfigBlockSave( 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 d069e62a12..5a10ad3448 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 static class HISTORY { 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 277d755b13..cc203190b3 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 @@ 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.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 @@ default void unregister() { } 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 02/59] 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 2a1a5a5ef0..1d6f8d146b 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 @@ private void save(PrintWriter writer, Class clazz, final Object instance, int 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 03/59] 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 | 61 ++--- .../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 | 234 ++++++---------- .../clipboard/io/NBTSchematicReader.java | 8 +- .../clipboard/io/SpongeSchematicReader.java | 49 ++-- .../clipboard/io/SpongeSchematicWriter.java | 18 +- .../BannerBlockCompatibilityHandler.java | 142 ++++------ .../BedBlockCompatibilityHandler.java | 138 ++++------ .../EntityNBTCompatibilityHandler.java | 40 ++- .../FlowerPotCompatibilityHandler.java | 79 +++--- .../legacycompat/NBTCompatibilityHandler.java | 69 ++++- .../NoteBlockCompatibilityHandler.java | 37 ++- .../Pre13HangingCompatibilityHandler.java | 34 +-- .../SignCompatibilityHandler.java | 70 ++--- .../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, 2252 insertions(+), 2536 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 2c957880a8..4bf9ffca2d 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 70a4116a65..4f64aa2732 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 fa027e567b..a5c3da0e1d 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.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.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.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 BaseBlock getFullBlock(Location location) { BlockEntity te = chunk.getBlockEntity(blockPos); if (te != null) { net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } return state.toBaseBlock(); @@ -427,7 +429,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { readEntityIntoTag(mcEntity, tag); return new BaseEntity( com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +445,9 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); + LinCompoundTag nativeTag = state.getNbt(); if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } @@ -527,13 +529,13 @@ public Property load(net.minecraft.world.level.block.state.properties.Propert } @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + 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) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -558,7 +560,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { 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()))); + weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); return weStack; } @@ -733,7 +735,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + state = state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { @@ -816,51 +818,49 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 * @return native WorldEdit NBT structure */ @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + public LinTag 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 BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { * @throws SecurityException on error * @throws IllegalArgumentException on error */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); + 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) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -888,44 +890,43 @@ private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws Sec * @return non-native structure */ @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + public net.minecraft.nbt.Tag fromNativeLin(LinTag 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 void tick() { WatchdogThread.tick(); } } catch (IllegalAccessException e) { - LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); + logger.log(Level.WARNING, "Failed to tick watchdog", e); } } } 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 index 948c190b52..50de3467e0 100644 --- 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 @@ -35,7 +35,6 @@ 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.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.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 @@ @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); + 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 T fixUp(FixType type, T original, int srcVer) { 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 22d9f917b9..7923c9e693 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 void updateLightingForBlock(BlockPos position) { } @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { - return false; + 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 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 688c218c64..0b90d942a6 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 @@ -35,9 +35,6 @@ 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; @@ -83,6 +80,9 @@ 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; @@ -274,7 +274,7 @@ public BaseBlock getFullBlock(final Location location) { 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((LinCompoundTag) toNativeLin(tag)); } } @@ -302,14 +302,14 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier 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 @@ protected ServerLevel getServerLevel(final World world) { 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()))); + weStack.setNbt((LinCompoundTag) toNativeLin(nmsStack.getTag())); return weStack; } 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 91fa705464..3301e9e63d 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 @@ -9,7 +9,6 @@ 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; @@ -24,6 +23,7 @@ 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; @@ -132,14 +132,14 @@ public void updateLightingForBlock(BlockPos blockPos) { } @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + 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.fromNativeBinary(tag); + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); blockEntity.load((CompoundTag) nativeTag); 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.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 4703787154..c3d4388e9e 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 @@ -732,7 +732,7 @@ public synchronized > T call(IChunkSet set, Runnable finaliz Iterator 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 7db487c3f2..0026c4c675 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.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 net.minecraft.nbt.CompoundTag get() { @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 Map getValue() { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public int asInt(String key) { } @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 ListTag getListTag(String key) { } @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 5196200612..f0ba19c6df 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.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.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 @@ 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 BaseBlock getFullBlock(Location location) { BlockEntity te = chunk.getBlockEntity(blockPos); if (te != null) { net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } return state.toBaseBlock(); @@ -467,7 +469,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { readEntityIntoTag(mcEntity, tag); return new BaseEntity( com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -483,9 +485,9 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); + LinCompoundTag nativeTag = state.getNbt(); if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } @@ -567,13 +569,13 @@ public Property load(net.minecraft.world.level.block.state.properties.Propert } @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + 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) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -609,7 +611,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { 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()))); + weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); return weStack; } @@ -785,7 +787,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + state = state.toBaseBlock(((LinCompoundTag) toNativeLin(tag))); } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { @@ -879,51 +881,49 @@ public void initializeRegistries() { * @return native WorldEdit NBT structure */ @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + public LinTag 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 BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { * @throws SecurityException on error * @throws IllegalArgumentException on error */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); + 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) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -951,44 +953,43 @@ private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws Sec * @return non-native structure */ @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + public net.minecraft.nbt.Tag fromNativeLin(LinTag 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 void tick() { WatchdogThread.tick(); } } catch (IllegalAccessException e) { - LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); + logger.log(Level.WARNING, "Failed to tick watchdog", e); } } } 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 index 1b56d29564..ebe674ca56 100644 --- 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 @@ -35,7 +35,6 @@ 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.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.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 @@ @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); + 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 T fixUp(FixType type, T original, int srcVer) { 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 dc44a165af..c7f3d3f3c0 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.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 void updateLightingForBlock(BlockPos position) { } @Override - public boolean updateTileEntity(BlockPos position, CompoundBinaryTag tag) { - return false; + 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 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 e5c7080a65..7fd24c7d97 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 @@ -35,9 +35,6 @@ 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; @@ -83,6 +80,9 @@ 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; @@ -274,7 +274,7 @@ public BaseBlock getFullBlock(final Location location) { 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((LinCompoundTag) toNativeLin(tag)); } } @@ -302,14 +302,14 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier 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 @@ protected ServerLevel getServerLevel(final World world) { 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()))); + weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); return weStack; } 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 index 7c771f065b..dee0bc7f0b 100644 --- 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 @@ -9,15 +9,13 @@ 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.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 +23,7 @@ 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; @@ -133,14 +132,14 @@ public void updateLightingForBlock(BlockPos blockPos) { } @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + 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.fromNativeBinary(tag); + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); blockEntity.load((CompoundTag) nativeTag); 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.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java index b26a42e743..91bcf0e922 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 @@ -730,7 +730,7 @@ public synchronized > T call(IChunkSet set, Runnable finaliz Iterator 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 dbdece6898..f2a694a2f1 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.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 net.minecraft.nbt.CompoundTag get() { @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 Map getValue() { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public int asInt(String key) { } @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 ListTag getListTag(String key) { } @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 f695876cca..e30bb2b2a1 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.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.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.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 BaseBlock getFullBlock(Location location) { BlockEntity te = chunk.getBlockEntity(blockPos); if (te != null) { net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } return state.toBaseBlock(); @@ -427,7 +429,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { readEntityIntoTag(mcEntity, tag); return new BaseEntity( com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +445,9 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); + LinCompoundTag nativeTag = state.getNbt(); if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } @@ -527,13 +529,13 @@ public Property load(net.minecraft.world.level.block.state.properties.Propert } @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + 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) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -558,7 +560,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { 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()))); + weStack.setNbt((LinCompoundTag) toNativeLin(nmsStack.getTag())); return weStack; } @@ -734,7 +736,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + state = state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { @@ -817,51 +819,49 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 * @return native WorldEdit NBT structure */ @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + public LinTag 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 BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { * @throws SecurityException on error * @throws IllegalArgumentException on error */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); + 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) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -889,44 +891,43 @@ private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws Sec * @return non-native structure */ @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + public net.minecraft.nbt.Tag fromNativeLin(LinTag 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 f7be01738f..be25d079a9 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.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.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.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 @@ @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 T fixUp(FixType type, T original, int srcVer) { 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 9e69e4a316..95ecae72aa 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.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 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 void updateLightingForBlock(BlockPos position) { } @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { + public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) { 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/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 f8f55b82fa..53f8ef671f 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 @@ -34,9 +34,6 @@ 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; @@ -82,6 +79,9 @@ import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R2.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; @@ -277,7 +277,7 @@ public BaseBlock getFullBlock(final Location location) { 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((LinCompoundTag) toNativeLin(tag)); } } @@ -305,14 +305,14 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier 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 @@ protected ServerLevel getServerLevel(final World world) { 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()))); + weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); return weStack; } 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 index a2e64c8a21..0c42d8fe70 100644 --- 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 @@ -9,15 +9,13 @@ 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.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 +23,7 @@ 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; @@ -133,14 +132,14 @@ public void updateLightingForBlock(BlockPos blockPos) { } @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + 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.fromNativeBinary(tag); + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); blockEntity.load((CompoundTag) nativeTag); 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.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 58d53d0377..93f84a1ec4 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 @@ -738,7 +738,7 @@ public synchronized > T call(IChunkSet set, Runnable finaliz Iterator 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 911da046ae..68dbc6b8eb 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.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 net.minecraft.nbt.CompoundTag get() { @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 Map getValue() { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public int asInt(String key) { } @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 ListTag getListTag(String key) { } @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 aa3920ccd0..0bc5ba09cc 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.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.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.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 BaseBlock getFullBlock(Location location) { BlockEntity te = chunk.getBlockEntity(blockPos); if (te != null) { net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } return state.toBaseBlock(); @@ -427,7 +429,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { readEntityIntoTag(mcEntity, tag); return new BaseEntity( com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +445,9 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); + LinCompoundTag nativeTag = state.getNbt(); if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } @@ -527,13 +529,13 @@ public Property load(net.minecraft.world.level.block.state.properties.Propert } @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + 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) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -558,7 +560,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { 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()))); + weStack.setNbt((LinCompoundTag) toNativeLin(nmsStack.getTag())); return weStack; } @@ -734,7 +736,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + state = state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { @@ -817,51 +819,49 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 * @return native WorldEdit NBT structure */ @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + public LinTag 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 BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { * @throws SecurityException on error * @throws IllegalArgumentException on error */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); + 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) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -889,44 +891,43 @@ private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws Sec * @return non-native structure */ @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + public net.minecraft.nbt.Tag fromNativeLin(LinTag 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 175174b752..3a80b6a3a1 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.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.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.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 @@ @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 T fixUp(FixType type, T original, int srcVer) { 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 b50ead9362..7e5a171f63 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 void updateLightingForBlock(BlockPos position) { } @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { - return false; + 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 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 fef95a3dd6..30ef3423af 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 @@ -34,9 +34,6 @@ 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; @@ -82,6 +79,9 @@ import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_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; @@ -277,7 +277,7 @@ public BaseBlock getFullBlock(final Location location) { 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((LinCompoundTag) toNativeLin(tag)); } } @@ -305,14 +305,14 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier 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 @@ protected ServerLevel getServerLevel(final World world) { 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()))); + weStack.setNbt(((LinCompoundTag) toNativeLin(nmsStack.getTag()))); return weStack; } 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 index e66007649a..671d82d6dd 100644 --- 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 @@ -9,14 +9,13 @@ 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.server.level.ServerChunkCache; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -24,6 +23,7 @@ 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; @@ -132,14 +132,14 @@ public void updateLightingForBlock(BlockPos blockPos) { } @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + 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.fromNativeBinary(tag); + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); blockEntity.load((CompoundTag) nativeTag); 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.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 afdd64baae..d2d18968aa 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 @@ -737,7 +737,7 @@ public synchronized > T call(IChunkSet set, Runnable finaliz Iterator 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 9a8a51896d..1d27f17a79 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.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 net.minecraft.nbt.CompoundTag get() { @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 Map getValue() { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public int asInt(String key) { } @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 ListTag getListTag(String key) { } @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 964be1398b..503330ad50 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.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.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.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 BaseBlock getFullBlock(Location location) { BlockEntity te = chunk.getBlockEntity(blockPos); if (te != null) { net.minecraft.nbt.CompoundTag tag = te.saveWithId(MinecraftServer.getServer().registryAccess()); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } return state.toBaseBlock(); @@ -457,7 +459,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { readEntityIntoTag(mcEntity, tag); return new BaseEntity( com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -473,9 +475,9 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); + LinCompoundTag nativeTag = state.getNbt(); if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } @@ -575,7 +577,7 @@ public Property load(net.minecraft.world.level.block.state.properties.Propert } @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + 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() @@ -583,7 +585,7 @@ public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtDa structureBlock.setLevel(((CraftPlayer) player).getHandle().level()); ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( structureBlock, - (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeLin(nbtData) )); } @@ -619,7 +621,7 @@ public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { ).getOrThrow(); return new BaseItemStack( BukkitAdapter.asItemType(itemStack.getType()), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount() ); } @@ -811,7 +813,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld BlockEntity blockEntity = chunk.getBlockEntity(pos); if (blockEntity != null) { net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(serverWorld.registryAccess()); - state = state.toBaseBlock(((CompoundBinaryTag) toNativeBinary(tag))); + state = state.toBaseBlock(((LinCompoundTag) toNativeLin(tag))); } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { @@ -894,51 +896,49 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 * @return native WorldEdit NBT structure */ @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { + public LinTag 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 BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { * * @param foreign the foreign tag * @return the converted tag - * @throws SecurityException on error + * @throws SecurityException on error * @throws IllegalArgumentException on error */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); + 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) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -966,44 +968,43 @@ private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws Sec * @return non-native structure */ @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { + public net.minecraft.nbt.Tag fromNativeLin(LinTag 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 39807b86d5..c566f0ae88 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.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.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.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 @@ @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 T fixUp(FixType type, T original, int srcVer) { 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 f7e5cee3f9..4b82a2eb0a 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.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 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 void updateLightingForBlock(BlockPos position) { } @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { + public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) { return false; } 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 3c23a9ddfd..76dc6f951a 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 @@ -36,9 +36,6 @@ 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; -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; @@ -88,6 +85,9 @@ 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; @@ -286,7 +286,7 @@ public BaseBlock getFullBlock(final Location location) { BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); if (blockEntity != null) { net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); + return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } } @@ -314,14 +314,14 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { if (id != null) { EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier 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 BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { ).getOrThrow(); return new BaseItemStack( BukkitAdapter.asItemType(itemStack.getType()), - LazyReference.from(() -> (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 d66057313b..8d33efb0fe 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.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 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 void updateLightingForBlock(BlockPos blockPos) { } @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { + 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.fromNativeBinary(tag); + net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag); blockEntity.loadWithComponents((CompoundTag) nativeTag, DedicatedServer.getServer().registryAccess()); return true; } 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 bd2873b7f7..47466ac5e7 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 @@ -738,7 +738,7 @@ public synchronized > T call(IChunkSet set, Runnable finaliz Iterator 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 11d3c940a6..52111a4fdd 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.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 net.minecraft.nbt.CompoundTag get() { @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 Map getValue() { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public int asInt(String key) { } @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 ListTag getListTag(String key) { } @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 ce6c9d1b16..258d9b83e9 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 e0d13a36bb..5cbc0f6b87 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.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.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 @@ default Entity createEntity(Location location, BaseEntity state) { } @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 @@ default Tag toNative(T foreign) { } @Override - default BinaryTag toNativeBinary(T foreign) { - return getParent().toNativeBinary(foreign); + default LinTag toNativeLin(T foreign) { + return getParent().toNativeLin(foreign); } @Override @@ -141,8 +140,8 @@ default T fromNative(Tag foreign) { } @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 792f3937e2..4b798981e0 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 boolean save(CompoundTag tag, String path) { } 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 void run(OutputStream output) { 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 44918557e2..4ced1a6805 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.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.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 > void sendFakeBlock(BlockVector3 pos, B bl 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 a34494ce59..d656e874a1 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.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.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.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 @@ default void tickWatchdog() { * @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 @@ default BlockMaterial getMaterial(BlockState blockState) { @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 @@ default T fromNative(Tag foreign) { 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 d9794d9f63..d5839d99fe 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 0420d0994a..1f0efe7a16 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 String getNbtId() { @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 void setNbtData(CompoundTag rootTag) { 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 333c3336bf..bf9adfa389 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 String getNbtId() { @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 CompoundTag getNbtData() { 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 void setNbtData(CompoundTag rootTag) { 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 a60ffbc09c..a5b405f47e 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 String getNbtId() { @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 void setNbtData(CompoundTag rootTag) { 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 46a3a1574f..5265702962 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 StringTag asTag(String value) { } 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 f591cf8265..325cd41910 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 @@ 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 ded96d5aa8..c0b49c333b 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.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 > B stripBlockNBT(B block) { 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 T stripEntityNBT(T entity) { 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 IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChun } 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 IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChun 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 6a306fc449..77447ac4c0 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 BlockState getBlock(int x, int y, int z) { 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 boolean setTile(int x, int y, int z, CompoundTag tag) { } 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 f42cdbbff7..dc71933942 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 @@ private void writeNBTToDisk() throws IOException { 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 BlockState getBlock(int x, int y, int z) { @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 143168504c..2e65f59ca9 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 Entity createEntity(Location location, BaseEntity entity) { @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 6c7a910f2a..426cbc32ae 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 int size() { @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 156e385441..b32d42c042 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.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 @@ private CompoundTag fixBlockEntity(CompoundTag tag) { 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 @@ private CompoundTag fixEntity(CompoundTag tag) { 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 Clipboard read(UUID uuid, Function createOutput) 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 Clipboard read(UUID uuid, Function createOutput) // 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 65a4a0e862..ac86fb2494 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 @@ private void write2(Clipboard clipboard) throws IOException { 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 @@ private void write2(Clipboard clipboard) throws IOException { 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 91fb75495d..0915766cc1 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 Clipboard read(UUID clipboardId) throws IOException { 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 Clipboard read(UUID clipboardId) throws IOException { 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 Clipboard read(UUID clipboardId) throws IOException { 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 Clipboard read(UUID clipboardId) throws IOException { 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 void write(Clipboard clipboard, String owner) throws IOException { 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 void write(Clipboard clipboard, String owner) throws IOException { 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 7fa4ddc6d9..b56ebc3ebb 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 @@ 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 void redo(UndoContext context) throws WorldEditException { @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 void delete(UndoContext context) { } 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 c0dc9756c4..e17a787658 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 void add(int x, int y, int z, int combinedFrom, int combinedTo) { @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 85bdddf09a..efed013762 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 CompressedCompoundTag(T in) { } @Override - public Map getValue() { + public Map> getValue() { if (in != null) { decompress(); } @@ -36,8 +36,8 @@ private void decompress() { 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 8b942895dd..6cdef3dda2 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 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 Compound(String jsonIn) { } 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 db1984bb32..5931069c6e 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 a56fe27d53..534a96fac9 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 @@ default Entity createEntity(Location location, BaseEntity entity) { @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 afab331a79..7629294001 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 static BrushTool setTool(BaseItem item, BrushTool tool) { } CompoundTag nbt = item.getNbtData(); - Map map; + Map> map; if (nbt == null) { if (tool == null) { item.setNbtData(null); @@ -92,9 +92,10 @@ public static BrushTool setTool(BaseItem item, BrushTool tool) { } 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 7d7d5d6427..6b693162e0 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 void close() { */ @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 static CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, in */ @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 7abb51284d..07157e8203 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 static T getChildTag(CompoundBinaryTag tag, String * @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 859ed9194c..9fbdd88bde 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.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 BaseItem deserialize(JsonElement json, Type type, JsonDeserializationCont 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 JsonElement serialize( ) { 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 1e9d361787..0000000000 --- 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 094a7c9bb2..4889235ebe 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); - } - - public ByteArrayTag(ByteArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; + this(LinByteArrayTag.of(value)); } - @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 6068b2af0d..6b3d3d1539 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 d91aea8fe5..10e9adf08b 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.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 @@ /** * 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 CompoundTag(CompoundBinaryTag adventureTag) { * @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 Map getValue() { * @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 CompoundTag setValue(Map value) { * @return the builder */ public CompoundTagBuilder createBuilder() { - return new CompoundTagBuilder(innerTag); + return new CompoundTagBuilder(linTag); } /** @@ -109,7 +108,8 @@ public CompoundTagBuilder createBuilder() { * @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 byte[] getByteArray(String key) { * @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 byte getByte(String key) { * @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 double getDouble(String key) { * @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 double asDouble(String key) { * @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 float getFloat(String key) { * @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 int[] getIntArray(String key) { * @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 int getInt(String key) { * @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 int asInt(String key) { * @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 List getList(String key) { * @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 ListTag getListTag(String key) { * @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 List getList(String key, Class listType) { * @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 long[] getLongArray(String key) { * @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 long getLong(String key) { * @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 long asLong(String key) { * @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 short getShort(String key) { * @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 UUID getUUID() { } 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 Vector3 getEntityPosition() { } 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 Map toRaw() { 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 f21bdb8cc8..535722b74b 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 CompoundTagBuilder remove(String key) { * @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 da0890ea62..6dad5186b6 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); - } - - public DoubleTag(DoubleBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; + this(LinDoubleTag.of(value)); } - @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 18347d928f..523fcf79eb 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 2e15338279..128e36014d 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); - } - - public FloatTag(FloatBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; + this(LinFloatTag.of(value)); } - @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 76d8fac748..0e3536eed7 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 c6ff802528..c4c90889b8 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); - } - - public IntTag(IntBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; + this(LinIntTag.of(value)); } - @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 00b5aeb9a1..4ce6febd66 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 0000000000..52b30f5998 --- /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 879a0d4a37..d3c330d4da 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 @@ /** * 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 ListBinaryTag asBinaryTag() { * * @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 List getValue() { * @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 @@ private T accessIfExists(int index, Supplier defaultValue, IntFunction * @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 Tag getIfExists(int index) { * @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 byte[] getByteArray(int index) { * @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 byte getByte(int index) { * @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 double getDouble(int index) { */ 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 double asDouble(int index) { * @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 float getFloat(int index) { * @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 int[] getIntArray(int index) { * @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 int getInt(int index) { */ 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 int asInt(int index) { * @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 List getList(int index) { * @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 ListTag getListTag(int index) { * @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 List getList(int index, Class listType) { * @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 long getLong(int index) { */ 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 long asLong(int index) { * @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 short getShort(int index) { * @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 78a8b6401a..18aab079c1 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 @@ /** * 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 ListTagBuilder add(Tag value) { * @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 ListTagBuilder addAll(Collection value) { * * @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 ListTag build() { * * @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 static ListTagBuilder create(Class type) { * * @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 81c6e3376d..968019b7e7 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 84a4437469..b8632b7520 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 54746fc49a..3ab1923c14 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 @@ private 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 fca025212b..806168327f 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 @@ 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 @@ * 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 void reset() throws IOException { * 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 @@ private Tag readTagPayload(int type, int depth) throws IOException { 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 6342455eb0..b466e6de25 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 @@ * 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 DataOutput getOutputStream() { * @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 interface LazyWrite { } 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 void writeEndTag() throws IOException { * @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 @@ private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException { * @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 @@ private void writeCompoundTagPayload(CompoundTag tag) throws IOException { * @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 c899ba07b6..b742cb6f8e 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 @@ * * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. */ +@SuppressWarnings("ALL") @Deprecated public final class NBTUtils { @@ -48,7 +48,7 @@ private 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 static String getTypeName(Class clazz) { return "TAG_Long_Array"; } else { throw new IllegalArgumentException("Invalid tag class (" - + clazz.getName() + ")."); + + clazz.getName() + ")."); } } @@ -88,11 +88,35 @@ public static String getTypeName(Class clazz) { * @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 static int getTypeCode(Class clazz) { * @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 static Class getTypeClass(int type) { * @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 static Vector3 toVector(ListTag listTag) { * @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 static T getChildTag(Map items, String key, * @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 c7e2f9f283..e83f135ded 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 @@ 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 String getName() { * * @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 abbd06b3f0..d0b9590fa6 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 4832637523..2bc78f1412 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 6327f41334..80df4c1cb1 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 7642f3d605..be1740dc40 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.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.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 void updateServerCUI(Actor actor) { 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 fe2e1a6355..552dc6f569 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. @@ -57,49 +53,49 @@ public BaseItem(ItemType itemType) { } /** - * Get the type of item. + * Construct the object. * - * @return the type + * @param itemType Type of the item + * @param nbtData NBT Compound tag */ - public ItemType getType() { - return this.itemType; + @Deprecated + public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) { + this(itemType, nbtData == null ? null : LazyReference.from(nbtData::toLinTag)); } /** - * Set the type of the item. + * Construct the object. * - * @param itemType The type to set + * @param itemType Type of the item + * @param tag NBT Compound tag */ - public void setType(ItemType itemType) { + public BaseItem(ItemType itemType, @Nullable LazyReference tag) { checkNotNull(itemType); this.itemType = itemType; + this.nbtData = tag; } - //FAWE start - /** - * Construct the object. + * Get the type of item. * - * @param itemType Type of the item - * @param nbtData NBT Compound tag + * @return the type */ - @Deprecated - public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) { - this(itemType, nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag)); + public ItemType getType() { + return this.itemType; } /** - * Construct the object. + * Set the type of the item. * - * @param itemType Type of the item - * @param tag NBT Compound tag + * @param itemType The type to set */ - public BaseItem(ItemType itemType, @Nullable LazyReference tag) { + public void setType(ItemType itemType) { checkNotNull(itemType); this.itemType = itemType; - this.nbtData = tag; } + //FAWE start + @Deprecated @Nullable public Object getNativeItem() { @@ -108,25 +104,20 @@ public Object getNativeItem() { @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 07a9aa1478..b83efe24a0 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.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 BaseItemStack(ItemType id, CompoundTag tag, int amount) { 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 Component getRichName() { .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 235cdf761c..b369ddd87a 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 @@ 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 BaseEntity(EntityType type, CompoundTag nbtData) { * @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 BaseEntity(BaseEntity other) { @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 b889d4dca7..2eb4fbfe33 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.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 Stream getSuggestions(String input) { @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 BaseItem parseFromInput(String input, ParserContext context) throws Input } 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 b861dbd6bf..cf46237390 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 BaseBlock getFullBlock(BlockVector3 position) { } @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 5aafa220ea..1fd9dda9ab 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 boolean isFormat(File file) { 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 aebef3e9aa..945cd69813 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.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.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 Clipboard read() throws IOException { 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 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); - - 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)); - } + 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)); // ==================================================================== // 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 Clipboard read() throws IOException { } // 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 Clipboard read() throws IOException { } 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 (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 + if (block == null) { + continue; } - - 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); + var updatedBlock = block.toBaseBlock(LazyReference.from(newTag::build)); + for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { + updatedBlock = handler.updateNbt(updatedBlock); + if (updatedBlock.getNbtReference() == null) { + break; + } } + tileEntityBlocks.put(BlockVector3.at(x, y, z), updatedBlock); } BlockArrayClipboard clipboard = new BlockArrayClipboard(region); @@ -261,16 +214,10 @@ public Clipboard read() throws IOException { 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 Clipboard read() throws IOException { 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 Clipboard read() throws IOException { // 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 @@ private BlockState getBlockState(int id, int data) { @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 0328b1c760..a6b9c14005 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 @@ */ 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 @@ protected static T requireTag(Map items, String key } @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 a140b666ab..ec82be2283 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 @@ 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.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 SpongeSchematicReader(NBTInputStream inputStream) { @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 Clipboard read() throws IOException { 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 @@ private CompoundTag getBaseTag() throws IOException { 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 @@ private CompoundTag getBaseTag() throws IOException { 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 @@ private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOExce 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 @@ private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOExce } 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 @@ private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOExce 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 @@ private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOExce 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 @@ private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOExce } 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 @@ private Clipboard readVersion2(BlockArrayClipboard version1, CompoundTag schemat 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 @@ private void readBiomes(BlockArrayClipboard clipboard, Map schemati 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 @@ private void readBiomes(BlockArrayClipboard clipboard, Map schemati } } - 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 @@ private void readEntities(BlockArrayClipboard clipboard, Map schema 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 dc313b2598..38c0115e50 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 void write(Clipboard clipboard) throws IOException { * @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 @@ private Map write2(Clipboard clipboard) { 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 @@ private Map write2(Clipboard clipboard) { 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 @@ private Map write2(Clipboard clipboard) { 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 @@ private Map write2(Clipboard clipboard) { 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 @@ private void writeBiomes(Clipboard clipboard, Map schematic) { 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 8269674006..d4b7347f27 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 > BlockStateHolder updateNBT(B block, Ma state = state.with(rotationProp, block.getState(RotationProperty)); } - values.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"); + var nbtBuilder = nbt.toBuilder(); + nbtBuilder.remove("Base"); - 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 > BlockStateHolder updateNBT(B block, Ma } 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 eea18f8df5..c8c26cc91e 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(); + public BaseBlock updateNbt(BaseBlock block) { + if (block.getBlockType() != BlockTypes.RED_BED) { + 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 facingProp = type.getProperty("facing"); + state = state.with(facingProp, block.getState(FACING_PROPERTY)); - Property occupiedProp = type.getProperty("occupied"); - state = state.with(occupiedProp, false); + Property occupiedProp = type.getProperty("occupied"); + state = state.with(occupiedProp, false); - Property partProp = type.getProperty("part"); - state = state.with(partProp, block.getState(PART_PROPERTY)); + Property partProp = type.getProperty("part"); + state = state.with(partProp, block.getState(PART_PROPERTY)); - values.remove("color"); - return state; - } - } - } - return block; + 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 6fcc6f4229..cfd82833dd 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 95d2fb0918..803b6c237e 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; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var item = tag.findTag("Item", LinTagType.stringTag()); + if (item == null) { + return block; } - 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 b7093dd4d9..a2d32ea930 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 508e842806..04190197ed 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; - } - - @Override - public > boolean isAffectedBlock(B block) { - return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK; + NOTE_PROPERTY = temp; } @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 346f5f29e1..f0bea016f2 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 d2dd4f5a8c..24c5de2320 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.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(""); + 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; + } - JsonObject jsonTextObject = new JsonObject(); - jsonTextObject.add("text", jsonElement); - values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString())); + 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 f00622561c..6d51582081 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; - } - - @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.SKELETON_SKULL - || block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; + FACING_PROPERTY = tempFacing; } @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 5f434cf9b6..519463760f 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 @@ private static BaseBlock transformBaseBlockNBT(BlockState transformed, CompoundT ); 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 88cf4fc6ff..b2670113a1 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.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 void run(Object value) { } 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 093a7737f8..e4b3907976 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.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 boolean apply(BlockVector3 position) throws WorldEditException { * @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 @@ private BaseBlock transformNbtData(BaseBlock state) { 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 c30f6fa4d6..49fac779a4 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.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 static BaseBlock createStructureBlock(Player player) { 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 static BaseBlock createStructureBlock(Player player) { 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 aa90cb816f..56cab805f1 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 @@ default > boolean setBlock(BlockVector3 position, // 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 @@ default void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { 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 5b69ddff01..414190a98c 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 @@ final class FixTypes { 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 a858686850..e1c5d6de01 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.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 @@ default boolean hasNbtData() { @Deprecated @Nullable default CompoundTag getNbtData() { - CompoundBinaryTag tag = getNbt(); + LinCompoundTag tag = getNbt(); return tag == null ? null : new CompoundTag(tag); } @@ -78,7 +78,7 @@ default CompoundTag getNbtData() { */ @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 @@ default void setNbtData(@Nullable CompoundTag nbtData) { 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 @@ default LazyReference getNbtReference() { * @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 @@ default CompoundBinaryTag getNbt() { * * @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 @@ default void setNbtReference(@Nullable LazyReference nbtData) * * @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 9828c90697..ab93a40160 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 @@ 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.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 BaseBlock(BlockState blockState) { */ @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 BaseBlock(BlockState state, CompoundTag nbtData) { * @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 V getState(Property property) { @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 BaseBlock toBaseBlock() { } @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 BlockState toBlockState() { @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 7132048436..caa8ba919b 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.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 CompoundTag getNbtData() { //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 e404823027..f2ea08b67f 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.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 @@ default BaseBlock toBaseBlock(CompoundTag compoundTag) { * 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 @@ default BaseBlock toBaseBlock(LazyReference compoundTag) { * @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 5535f4305e..8a3c3de897 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 @@ 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 AnvilChunk(CompoundTag tag) throws DataException { * @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 @@ private int getBlockID(BlockVector3 position) throws DataException { 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 @@ private int getBlockData(BlockVector3 position) throws DataException { } 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 @@ private int getBlockData(BlockVector3 position) throws DataException { /** * 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 @@ private void populateTileEntities() throws DataException { * @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 BaseBlock getBlock(BlockVector3 position) throws DataException { 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 a8c2d63c2d..9b3d54027b 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.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 @@ */ 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 AnvilChunk13(CompoundTag tag) throws DataException { * @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 AnvilChunk13(CompoundBinaryTag tag) throws DataException { } // 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 AnvilChunk13(CompoundBinaryTag tag) throws DataException { } } - 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 @@ protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialize 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 @@ private BlockState getBlockStateWith(BlockState source, Property property /** * 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 @@ private void populateTileEntities() throws DataException { * * @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 BaseBlock getBlock(BlockVector3 position) throws DataException { 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 List getEntities() throws DataException { /** * 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 @@ private void populateEntities() throws DataException { /** * 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 60b9d9617a..955a6e70ae 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 AnvilChunk15(CompoundTag tag) throws DataException { * @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 BiomeType getBiome(final BlockVector3 position) throws DataException { 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 92f7f6caf6..ff4c89e65a 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 AnvilChunk16(CompoundTag tag) throws DataException { * @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 3789f9a79c..fbddb66f08 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.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 @@ */ 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 AnvilChunk17(CompoundTag tag, Supplier entitiesTag) throws D * {@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 AnvilChunk17(CompoundBinaryTag tag, Supplier entityTag 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 AnvilChunk17(CompoundBinaryTag tag, Supplier entityTag } // 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 @@ private BlockState getBlockStateWith(BlockState source, Property property /** * 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 @@ private void populateTileEntities() throws DataException { * @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 BaseBlock getBlock(BlockVector3 position) throws DataException { 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 BiomeType getBiome(final BlockVector3 position) throws DataException { 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 List getEntities() throws DataException { /** * 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"); - } - CompoundBinaryTag t = (CompoundBinaryTag) tag; + for (LinCompoundTag tag : tags.value()) { - 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 1e36938c47..c5736bfd5f 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 AnvilChunk18(CompoundBinaryTag tag, Supplier entityTag } // 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 AnvilChunk18(CompoundBinaryTag tag, Supplier entityTag readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks); } } - //FAWE end } protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { @@ -190,24 +148,28 @@ private BlockState getBlockStateWith(BlockState source, Property property * 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 @@ private void populateTileEntities() throws DataException { * @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 BaseBlock getBlock(BlockVector3 position) throws DataException { } 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 BaseBlock getBlock(BlockVector3 position) throws DataException { 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 7edb163e3a..7830455206 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 @@ */ 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 OldChunk(CompoundTag tag) throws DataException { * @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 OldChunk(CompoundBinaryTag tag) throws DataException { * @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 @@ private void populateTileEntities() throws DataException { * @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 BaseBlock getBlock(BlockVector3 position) throws DataException { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } - CompoundBinaryTag tileEntity = getBlockTileEntity(position); - - if (tileEntity != null) { - return state.toBaseBlock(tileEntity); - } + LinCompoundTag tileEntity = getBlockTileEntity(position); - 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 3e3201fb64..df506c67a9 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.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 void restore() throws MaxChangedBlocksException { 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 5f9880fc0d..39d4fb07ba 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.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 void restore() throws MaxChangedBlocksException { 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 58692732f4..c8788a9ce8 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 interface ChunkDataInputSupplier { 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 static Chunk getChunk(CompoundTag rootTag, Supplier entities 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 static Chunk getChunk(CompoundTag rootTag, Supplier entities 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 static Chunk getChunk(CompoundTag rootTag, Supplier entities } 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 8d82026ff0..90d552c107 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 @@ 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 @@ private 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 cd3c5c3133..0d87917d9b 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 static net.minecraft.nbt.ByteArrayTag toNative(ByteArrayTag tag) { 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 static ByteArrayTag fromNative(net.minecraft.nbt.ByteArrayTag other) { 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 9c10a6d304..82ab9ae234 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 static ByteArrayNBT toNative(ByteArrayTag tag) { 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 static ByteArrayTag fromNative(ByteArrayNBT other) { 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 c5eb108876..cace30cd08 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 04/59] 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 | 370 ++++++++++-------- .../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, 976 insertions(+), 372 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 a5c3da0e1d..5b696c8f66 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.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.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 @@ 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(); @@ -806,6 +818,34 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 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 // ------------------------------------------------------------------------ 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 7923c9e693..424422ce6c 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 void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state. } } + @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) { 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 3301e9e63d..0c57f9ca60 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 @@ -217,6 +217,12 @@ public void updateNeighbors( 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, 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 f0ba19c6df..233212aef5 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 @@ -57,6 +57,7 @@ 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; @@ -68,6 +69,8 @@ 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; @@ -310,6 +313,29 @@ public OptionalInt getInternalBlockStateId(BlockState state) { 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); @@ -579,17 +605,6 @@ public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) )); } - /*@Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag 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) fromNative(nbtData) - )); - }*/ - @Override public void sendFakeOP(Player player) { ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( @@ -858,7 +873,7 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 return false; } - /*@Override + @Override public void initializeRegistries() { DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); // Biomes @@ -867,8 +882,24 @@ public void initializeRegistries() { 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 // ------------------------------------------------------------------------ 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 c7f3d3f3c0..ffca9e50de 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 void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state. } } + @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) { 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 index dee0bc7f0b..b06d962a08 100644 --- 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 @@ -217,6 +217,12 @@ public void updateNeighbors( 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, 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 e30bb2b2a1..19f9aa5964 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 @@ -23,6 +23,7 @@ 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.datafixers.util.Either; @@ -56,6 +57,7 @@ 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 +69,8 @@ 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; @@ -78,6 +82,7 @@ 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; @@ -108,6 +113,7 @@ 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.v1_20_R2.CraftServer; @@ -147,6 +153,7 @@ 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; @@ -174,6 +181,8 @@ 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,8 +381,40 @@ public BaseBlock getFullBlock(Location location) { 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())); + 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 @@ private static net.minecraft.core.Direction adapt(Direction face) { @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 + 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 @@ private net.minecraft.world.level.block.state.BlockState applyProperties( } 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 - ) - ); + .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 Property load(net.minecraft.world.level.block.state.properties.Propert 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())); + (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 Property load(net.minecraft.world.level.block.state.properties.Propert 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); @@ -542,15 +598,15 @@ public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) @Override public void sendFakeOP(Player player) { ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 + ((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() + 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); @@ -565,7 +621,7 @@ public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { } private final LoadingCache 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 boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba } fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.absMoveTo(position.x(), position.y(), position.z(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + (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); @@ -603,14 +659,14 @@ public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { + 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(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { + public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) { try { doRegen(bukkitWorld, region, extent, options); } catch (Exception e) { @@ -620,7 +676,7 @@ public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent ex return true; } - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { Environment env = bukkitWorld.getEnvironment(); ChunkGenerator gen = bukkitWorld.getGenerator(); @@ -630,51 +686,52 @@ private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); + .getWorldData().overworldData(); WorldOptions originalOpts = levelProperties.worldGenOptions(); long seed = options.getSeed().orElse(originalWorld.getSeed()); WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; + ? 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() + "faweregentempworld", + 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; + 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() + 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); @@ -684,7 +741,7 @@ private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, } finally { try { @SuppressWarnings("unchecked") - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -712,7 +769,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld executor.managedBlock(() -> { // 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 @@ private List> submitChunkLoadTasks(Region region, try { //noinspection unchecked chunkLoadings.add( - ((CompletableFuture>) - 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 @@ private ResourceKey getWorldDimKey(Environment env) { } private static final Set 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 Set getSupportedSideEffects() { } @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { + public boolean clearContainerBlockContents(World world, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); @@ -807,6 +864,45 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 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 // ------------------------------------------------------------------------ @@ -978,7 +1074,7 @@ private static class MojangWatchdog implements Watchdog { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { this.server = server; Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ah") + Refraction.pickName("nextTickTime", "ag") ); if (tickField.getType() != long.class) { throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); 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 c6d0b936ce..82caa9a92d 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 @@ -41,7 +41,7 @@ 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 + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false ); PaperweightFakePlayer(ServerLevel world) { 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 95ecae72aa..a27f01b704 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 @@ -26,9 +26,11 @@ 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_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; @@ -70,8 +72,8 @@ public LevelChunk getChunk(int x, int z) { 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(); + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); } @Override @@ -102,7 +104,14 @@ public void updateLightingForBlock(BlockPos position) { @Override public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) { - return false; + // 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 @@ -144,6 +153,12 @@ public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state. } } + @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) { @@ -153,8 +168,6 @@ private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, B @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(); 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 index 0c42d8fe70..352e9b9583 100644 --- 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 @@ -217,6 +217,12 @@ public void updateNeighbors( 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, 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 0bc5ba09cc..571fc61cc4 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 @@ -23,6 +23,7 @@ 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.datafixers.util.Either; @@ -56,6 +57,7 @@ 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 +69,8 @@ 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; @@ -78,6 +82,7 @@ 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; @@ -108,6 +113,7 @@ 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.v1_20_R3.CraftServer; @@ -147,6 +153,7 @@ 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; @@ -174,6 +181,8 @@ 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 BaseBlock getFullBlock(Location location) { private static final HashMap, 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 @@ private static net.minecraft.core.Direction adapt(Direction face) { @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 + 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 @@ private net.minecraft.world.level.block.state.BlockState applyProperties( } 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 - ) - ); + .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 Property load(net.minecraft.world.level.block.state.properties.Propert 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())); + (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 Property load(net.minecraft.world.level.block.state.properties.Propert 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); @@ -542,15 +597,15 @@ public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) @Override public void sendFakeOP(Player player) { ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 + ((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() + 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); @@ -583,7 +638,7 @@ public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba } fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.absMoveTo(position.x(), position.y(), position.z(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + (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); @@ -603,14 +658,14 @@ public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { + 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(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) { + public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) { try { doRegen(bukkitWorld, region, extent, options); } catch (Exception e) { @@ -620,7 +675,7 @@ public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent ex return true; } - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { Environment env = bukkitWorld.getEnvironment(); ChunkGenerator gen = bukkitWorld.getGenerator(); @@ -630,51 +685,52 @@ private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); + .getWorldData().overworldData(); WorldOptions originalOpts = levelProperties.worldGenOptions(); long seed = options.getSeed().orElse(originalWorld.getSeed()); WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; + ? 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() + "faweregentempworld", + 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; + 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() + 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); @@ -684,7 +740,7 @@ private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, } finally { try { @SuppressWarnings("unchecked") - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -712,7 +768,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld executor.managedBlock(() -> { // 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 @@ private List> submitChunkLoadTasks(Region region, try { //noinspection unchecked chunkLoadings.add( - ((CompletableFuture>) - 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 @@ private ResourceKey getWorldDimKey(Environment env) { } private static final Set 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 Set getSupportedSideEffects() { } @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { + public boolean clearContainerBlockContents(World world, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); @@ -807,6 +863,45 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 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 // ------------------------------------------------------------------------ @@ -978,7 +1073,7 @@ private static class MojangWatchdog implements Watchdog { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { this.server = server; Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ah") + Refraction.pickName("nextTickTime", "ag") ); if (tickField.getType() != long.class) { throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); 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 index c27f4a59a6..83520e4532 100644 --- 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 @@ -41,7 +41,7 @@ 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 + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false ); PaperweightFakePlayer(ServerLevel world) { 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 7e5a171f63..1f51c66ca9 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 @@ -73,8 +73,8 @@ public LevelChunk getChunk(int x, int z) { 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(); + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); } @Override @@ -110,7 +110,7 @@ public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) { if (tileEntity == null) { return false; } - Tag nativeTag = adapter.fromNative(new CompoundTag(tag)); + Tag nativeTag = adapter.fromNativeLin(tag); PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity); return true; } @@ -154,6 +154,12 @@ public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state. } } + @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) { @@ -163,8 +169,6 @@ private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, B @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(); @@ -187,5 +191,4 @@ public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.sta 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/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 index 671d82d6dd..4fb3e04851 100644 --- 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 @@ -217,6 +217,12 @@ public void updateNeighbors( 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, 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 503330ad50..89acd6847c 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 @@ -23,6 +23,7 @@ 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; @@ -56,6 +57,7 @@ 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,12 +69,13 @@ 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.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; @@ -83,6 +86,7 @@ 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; @@ -113,6 +117,7 @@ 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; @@ -152,6 +157,7 @@ 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; @@ -183,6 +189,8 @@ 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 BaseBlock getFullBlock(Location location) { private static final HashMap, 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 @@ private static net.minecraft.core.Direction adapt(Direction face) { @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 + 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 @@ private net.minecraft.world.level.block.state.BlockState applyProperties( } 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 - ) - ); + .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 org.bukkit.entity.Entity createEntity(Location location, BaseEntity state createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); + worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); return createdEntity.getBukkitEntity(); } else { return null; @@ -524,51 +557,33 @@ 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({ "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 Property load(net.minecraft.world.level.block.state.properties.Propert @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() + 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( @@ -592,18 +607,18 @@ public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) @Override public void sendFakeOP(Player player) { ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 + ((CraftPlayer) player).getHandle(), (byte) 28 )); } @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { + 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(item.getType().id())), - item.getAmount() + registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), + baseItemStack.getAmount() ); - final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()); + final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); final DataComponentPatch patch = COMPONENTS_CODEC .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) .getOrThrow(); @@ -613,11 +628,11 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { - final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); + var registryAccess = DedicatedServer.getServer().registryAccess(); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final Tag tag = COMPONENTS_CODEC.encodeStart( - registryAccess.createSerializationContext(NbtOps.INSTANCE), - nmsStack.getComponentsPatch() + CompoundTag tag = (CompoundTag) COMPONENTS_CODEC.encodeStart( + registryAccess.createSerializationContext(NbtOps.INSTANCE), + nmsStack.getComponentsPatch() ).getOrThrow(); return new BaseItemStack( BukkitAdapter.asItemType(itemStack.getType()), @@ -627,16 +642,16 @@ public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { } private final LoadingCache 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 boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba } fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.absMoveTo(position.x(), position.y(), position.z(), - (float) face.toVector().toYaw(), (float) face.toVector().toPitch() - ); + (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); @@ -657,10 +671,7 @@ public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba 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()) { + 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(); @@ -671,17 +682,14 @@ public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, Ba } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) { + 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()) - ); + 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) { + public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) { try { doRegen(bukkitWorld, region, extent, options); } catch (Exception e) { @@ -691,7 +699,7 @@ public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent ex return true; } - private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { + private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception { Environment env = bukkitWorld.getEnvironment(); ChunkGenerator gen = bukkitWorld.getGenerator(); @@ -701,56 +709,52 @@ private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() - .getWorldData().overworldData(); + .getWorldData().overworldData(); WorldOptions originalOpts = levelProperties.worldGenOptions(); long seed = options.getSeed().orElse(originalWorld.getSeed()); WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; + ? 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() + "faweregentempworld", + 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() - ); + 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() + 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); @@ -760,7 +764,7 @@ private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, } finally { try { @SuppressWarnings("unchecked") - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -777,8 +781,7 @@ private BiomeType adapt(ServerLevel serverWorld, Biome origBiome) { } @SuppressWarnings("unchecked") - private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws - WorldEditException { + private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException { List> chunkLoadings = submitChunkLoadTasks(region, serverWorld); BlockableEventLoop executor; try { @@ -789,7 +792,7 @@ private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld executor.managedBlock(() -> { // 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 @@ private List> submitChunkLoadTasks(Region region, try { //noinspection unchecked chunkLoadings.add( - ((CompletableFuture>) - 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 @@ private ResourceKey getWorldDimKey(Environment env) { } private static final Set 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 Set getSupportedSideEffects() { } @Override - public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { + public boolean clearContainerBlockContents(World world, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); @@ -884,6 +887,45 @@ public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 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 // ------------------------------------------------------------------------ @@ -1022,7 +1064,6 @@ public void tickWatchdog() { } private class SpigotWatchdog implements Watchdog { - private final Field instanceField; private final Field lastTickField; @@ -1047,18 +1088,16 @@ public void tick() { 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") + Refraction.pickName("nextTickTime", "ag") ); if (tickField.getType() != long.class) { throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); @@ -1074,21 +1113,15 @@ public void tick() { } catch (IllegalAccessException ignored) { } } - } private static class NoOpWorldLoadListener implements ChunkProgressListener { - @Override public void updateSpawnPos(ChunkPos spawnPos) { } @Override - public void onStatusChange( - final ChunkPos pos, - @org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status - ) { - + public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { } @Override @@ -1100,5 +1133,4 @@ public void stop() { } } - } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/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 index 792942843b..baeec90baa 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/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 @@ -41,7 +41,7 @@ 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 + "en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false ); PaperweightFakePlayer(ServerLevel world) { 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 4b82a2eb0a..c83733bf28 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 @@ -26,9 +26,11 @@ 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; @@ -70,8 +72,8 @@ public LevelChunk getChunk(int x, int z) { 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(); + ? Block.stateById(stateId) + : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); } @Override @@ -102,7 +104,14 @@ public void updateLightingForBlock(BlockPos position) { @Override public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) { - return false; + // 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 @@ -144,7 +153,12 @@ public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state. } } - // Not sure why neighborChanged is deprecated + @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); } @@ -152,8 +166,6 @@ private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, B @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(); @@ -174,7 +186,6 @@ public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.sta @Override public void flush() { - + } - } 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 8d33efb0fe..4fa9988b81 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 @@ -218,6 +218,12 @@ public void updateNeighbors( 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, 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 5cbc0f6b87..41c5cbc794 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 @@ -8,6 +8,7 @@ import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.registry.state.Property; @@ -114,6 +115,26 @@ default OptionalInt getInternalBlockStateId(BlockState state) { 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 d656e874a1..8fee3b4170 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.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 @@ default void tickWatchdog() { 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 @@ default boolean clearContainerBlockContents(World world, BlockVector3 pt) { 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 b32d42c042..71d1397897 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 @@ private CompoundTag fixBlockEntity(CompoundTag tag) { 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 56cab805f1..097db6964a 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 @@ default void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { 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 92a859652e..e18499c04b 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 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 final String id() { 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 int getInternalId() { 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 0000000000..ee1cca1c09 --- /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 0000000000..a51a868237 --- /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 05/59] 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 5b696c8f66..87135fa863 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 Component getRichItemName(BaseItemStack itemStack) { } @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()); - } - } - }); + 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 233212aef5..0cecbb45bb 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 Component getRichItemName(BaseItemStack itemStack) { } @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()); - } - } - }); + 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 19f9aa5964..9aaeb7bc23 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 Component getRichItemName(BaseItemStack itemStack) { } @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()); - } - } - }); + 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 571fc61cc4..ded4bcfdd7 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 Component getRichItemName(BaseItemStack itemStack) { } @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()); - } - } - }); + 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 89acd6847c..206ade66a5 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 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))).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 06/59] 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 0000000000..73d871135b --- /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 be4c9af8c5..402310def2 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 @@ 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.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 void checkMaxBrushRadius(Expression expression, Actor actor) { 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 a289f7cff0..c81db21d83 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 int fill( 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 int fillr( 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 int drain( 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 int fixLava( ) 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 int fixWater( ) 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 b07f3f61d4..b3b3b5df8f 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 @@ 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 void convert(BrushRadiusLimitException e) throws CommandException { 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 a8dddbdcfa..16e10a00d3 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 07/59] 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 dd7c239848..8e34d3996c 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 static Scroll fromArguments( 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 5a10ad3448..3b80dcdfa0 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 FaweLimit getLimit(Actor actor) { } } 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 static class LIMITS extends ConfigBlock { " - 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 84437c19a4..1b6640ecd8 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 Mask parseFromInput(String input, ParserContext context) throws InputPars 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 c1997bb0de..615f1a5869 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 BlockState blockState(Actor actor, String argument) { 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 baef7f7676..33ea8e3f73 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.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 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 BlockMaskBuilder addRegex(final String input) throws InputParseException 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 BlockMaskBuilder addRegex(final String input) throws InputParseException } } 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 e30ee4db62..d17787f033 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 void THROW_MAX_ENTITIES(int amt) { 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 boolean isUnlimited() { && !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 void set(FaweLimit limit) { 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 FaweLimit copy() { 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 3b271a1ec0..865e6f937b 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 void gtexture( 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 d82d25394d..d3189f1f1c 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 @@ private ParserContext createContext(InjectedValueAccess context) { 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 de6eea718e..ac94b12d4f 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 Mask parseFromInput(String component, ParserContext context) throws Input 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 8eb6df7557..4358a69321 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 BaseBlock getBlock(String input, boolean allAllowed) throws WorldEditExce 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 Pattern getBlockPattern(String list) throws WorldEditException { 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 Set getBlocks(String list, boolean allBlocksAllowed) throws Wo 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 08/59] 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 8fdea32009..0f188deebf 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 fec02d1a04..60860f7f75 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 4f64aa2732..b02ec474b3 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 48318b9085..de52de2f92 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 0000000000..39ff980f6b --- /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 0000000000..f66bb1460a --- /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 0000000000..e84ba0d4eb --- /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 0000000000..d9c89b0e30 --- /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 0000000000..d51295053f --- /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 0000000000..5056a7981e --- /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 0000000000..3595273960 --- /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 0000000000..e0dae1b2f8 --- /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 0000000000..f7c2dc8e84 --- /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 0000000000..bdd9d0648c --- /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 0000000000..a0a4d02d92 --- /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 0000000000..6819e54665 --- /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 0000000000..33c7a8597f --- /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 0000000000..3b4c47087e --- /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 0000000000..f9d06922e4 --- /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 0000000000..beaffc9a69 --- /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 0000000000..e2ed21584b --- /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 0000000000..07933adfa8 --- /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 258d9b83e9..088ab22a0e 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 09/59] 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 b02ec474b3..d3c7ef643e 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 10/59] 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 d3c7ef643e..0b88f66c62 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 11/59] 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 0b88f66c62..8fb4a51ebe 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 12/59] 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 8fb4a51ebe..5c82ca09da 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 13/59] 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 b82aa23a4f..a4413138c9 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 14/59] 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 0f188deebf..14be0a0a2b 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 1d6f8d146b..880b4cdf79 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 void save(File file) { /** * 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 33ea8e3f73..7ca60bdd17 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 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 @@ protected BlockMaskBuilder(long[][] bitSets) { /** * 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 be1740dc40..48e2a8078d 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 void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindEx * @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 String getNavWandItem() { * 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 BaseItem getWandBaseItem() { * 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 402310def2..8fbf614365 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 void checkMaxBrushRadius(double radius) throws MaxBrushRadiusException { /** * @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 void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusExceptio * @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 void checkMaxRadius(double radius, Actor actor) { * @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 void checkMaxBrushRadius(double radius, Actor actor) { * @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 void checkMaxBrushRadius(Expression expression, Actor actor) { * @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 8c0b69ec94..3784497557 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 @@ private void createCopy( 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 1106899f8d..4bdbddb4d9 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 BlockVector3 getPosition() { * @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 BiomeType getPrevious() { * @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 16fc50e0d2..ecde7967fc 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 , BC extends BlockStateHolder> BlockC * @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 BlockVector3 getPosition() { * @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 BaseBlock getPrevious() { * @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 0934627b9b..75fae8ca26 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 @@ protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser) { * @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 baed5ffde3..7db9cd7e21 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 MutableBlockVector2 mutZ(int z) { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public int x() { return x; @@ -134,7 +134,7 @@ public int x() { * @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 int getX() { * @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 BlockVector2 withX(int x) { * Get the Z coordinate. * * @return the z coordinate - * @since TODO + * @since 2.11.0 */ public int z() { return z; @@ -176,7 +176,7 @@ public int z() { * @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 int getZ() { * @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 3d239b3523..ee2789a338 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 BlockVector3 toImmutable() { * 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 BlockVector3 toImmutable() { * @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 int getX() { * @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 BlockVector3 withX(int x) { * 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 BlockVector3 withX(int x) { * @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 int getY() { * @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 BlockVector3 withY(int y) { * 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 BlockVector3 withY(int y) { * @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 int getZ() { * @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 9d08676f94..089ed62ca1 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 static Vector2 at(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 double getX() { * 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 Vector2 withX(double x) { * 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 int blockZ() { * @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 898bb52412..3b359920b0 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 MutableVector3 mutZ(double z) { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public abstract double x(); @@ -179,7 +179,7 @@ public int blockX() { * @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 Vector3 withX(double x) { * Get the Y coordinate. * * @return the y coordinate - * @since TODO + * @since 2.11.0 */ public abstract double y(); @@ -220,7 +220,7 @@ public int blockY() { * @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 Vector3 withY(double y) { * Get the Z coordinate. * * @return the z coordinate - * @since TODO + * @since 2.11.0 */ public abstract double z(); @@ -260,7 +260,7 @@ public int blockZ() { * @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 b31e62d7fc..dfce5f8338 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 @@ default String getId() { * 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 ff946e4587..042f435e03 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 BlockVector3 getLocation() { * @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 e7ec152a99..d49289093b 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 BiomeType(String id) { * Gets the ID of this biome. * * @return The id - * @since TODO + * @since 2.11.0 */ @Override public String id() { @@ -78,7 +78,7 @@ public int getInternalId() { * @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 1faf3bc4c1..aba23b6361 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 EntityType(String id) { * 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 String id() { * @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 1642ed4e98..1b191f07f3 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 FluidType(String id) { * 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 String id() { * @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 db63b53a4f..45071859c1 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 @@ default int getMaxStackSize() { * 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 @@ default int maxStackSize() { * @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 @@ default int getMaxDamage() { * 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 15/59] 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 14be0a0a2b..4dd632c1de 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 16/59] 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 33c7a8597f..8c7da74faf 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 17/59] 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 4f7245d27f..2edb9cb514 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 @@ 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.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 @@ private static Supplier supply() { }; } + @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 18/59] 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 334289b085..aec3cfd249 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 static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int 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 91dcfe24ef..23f59e8bf1 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 static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int 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 f2f78eb7d0..b69f476d35 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 static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int 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 6c0f72590e..1389cdda38 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 static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int 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 8c7da74faf..c2931d7ff6 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 static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int 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 19/59] 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 e0dae1b2f8..0a2fe6f606 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.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 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 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) { From eedd8ee044d4ddced24fd9fdff224931b5b1a0e1 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Tue, 2 Jul 2024 20:34:02 +0200 Subject: [PATCH 20/59] 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 d49644f242..cb5339737e 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 21/59] 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 103dd8824f..4f4cce126c 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 BiomeType getBiome(BlockVector3 position) { @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 c424c0f8c7..daa731d3c8 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 BaseBlock getFullBlock(BlockVector3 position) { @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 22/59] 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 0a2fe6f606..757ba0e296 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 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 boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + throw new UnsupportedOperationException("Regen support for 1.21 not yet implemented."); + } @Override public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { From 8f353e8f0dedc9db14b1575d2fa3fcb486cdf94f Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 5 Jul 2024 15:05:55 +0200 Subject: [PATCH 23/59] 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 a1471c9d87..675e8efb67 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 PolyhedralRegion(PolyhedralRegion region) { 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 24/59] 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 1389cdda38..03eabc6981 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 25/59] 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 cd12b10086..282587ce8d 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 26/59] 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 34e3569eb1..1512dca87d 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 27/59] 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 5c82ca09da..48f436e070 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 28/59] 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 | 258 +++++- .../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} | 190 ++-- .../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, 2805 insertions(+), 625 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 4b798981e0..5c6f97d212 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 @@ 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.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 boolean save(CompoundTag tag, String path) { 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 void run(OutputStream output) { 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 Schematic getSchematic(@Nonnull InputStream is) { 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 9916a7d9fc..28fb6d990a 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 71d1397897..97fdd1f275 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 @@ /** * 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 0000000000..db98d22038 --- /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 ac86fb2494..3bd302876d 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 @@ /** * 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 @@ private void write2(Clipboard clipboard) throws IOException { 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 0000000000..e00839eb0a --- /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 0000000000..17f4b9f0a3 --- /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 e622b1501d..3c569f9139 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 LZ4BlockInputStream adapt(Clipboard src) throws IOException { 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 806168327f..080ab3bea8 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 @@ private long[] readLongArrayRaw(int length) throws IOException { * @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 1fd9dda9ab..8a57411d6e 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,10 +58,66 @@ /** * 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") { + FAST_V3("fast", "fawe", "schem") { + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + return new FastSchematicReaderV3(inputStream); + } + + @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 FastSchematicWriterV3(nbtStream); + } + + @Override + 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"; @@ -64,7 +130,7 @@ public ClipboardReader getReader(InputStream inputStream) throws IOException { } BufferedInputStream buffered = new BufferedInputStream(inputStream); NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - return new FastSchematicReader(nbtStream); + return new FastSchematicReaderV2(nbtStream); } @Override @@ -77,13 +143,12 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { gzip = new ParallelGZIPOutputStream(outputStream); } NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); - return new FastSchematicWriter(nbtStream); + return new FastSchematicWriterV2(nbtStream); } @Override - public boolean isFormat(File file) { - String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".schem") || name.endsWith(".sponge"); + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, FastSchematicWriterV2.CURRENT_VERSION); } }, @@ -113,9 +178,39 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { } @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 boolean isFormat(File file) { * 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 String getPrimaryFileExtension() { @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(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(); + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, 2); + } + }, + SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast - // Check - Map> schematic = schematicTag.getValue(); - if (!schematic.containsKey("Version")) { - return false; - } - } catch (Exception e) { - return false; - } + @Override + public String getPrimaryFileExtension() { + return "schem"; + } - return true; + @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) { + //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 ClipboardReader getReader(InputStream inputStream) throws IOException { } 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 ClipboardWriter getWriter(OutputStream outputStream) throws IOException { 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 ClipboardWriter getWriter(OutputStream outputStream) throws IOException { } @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 String getPrimaryFileExtension() { }; //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 cb5cd1b7aa..7b4b1bf3bc 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.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 a6b9c14005..017f07e9c9 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 @@ /** * 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 0000000000..7da0aa164f --- /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 ec82be2283..0000000000 --- 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 981debe4b7..551ac5dd76 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 Consumer share(ClipboardShareMetadata metadata, ShareOutputProvide 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 Consumer share(ClipboardShareMetadata metadata, ShareOutputProvide @Override public ClipboardFormat getDefaultFormat() { - return BuiltInClipboardFormat.SPONGE_SCHEMATIC; + return BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC; } @Override @@ -119,13 +119,14 @@ public Consumer share(final ClipboardShareMetadata metadata, final ShareO @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 0000000000..5c4e902649 --- /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 0000000000..7574bfe4cb --- /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 0000000000..2cd7bb1e12 --- /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 38c0115e50..8504f0fe83 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; - -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; +package com.sk89q.worldedit.extent.clipboard.io.sponge; + 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 void write(Clipboard clipboard) throws IOException { // 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 void write(Clipboard clipboard) throws IOException { 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() + ); + + LinCompoundTag.Builder metadata = LinCompoundTag.builder(); + metadata.putInt("WEOffsetX", offset.x()); + metadata.putInt("WEOffsetY", offset.y()); + metadata.putInt("WEOffsetZ", offset.z()); + + 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()}); + + 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()); - 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)); + metadata.put("WorldEdit", worldEditSection.build()); - schematic.put("Metadata", new CompoundTag(metadata)); + schematic.put("Metadata", metadata.build()); - schematic.put("Width", new ShortTag((short) width)); - schematic.put("Height", new ShortTag((short) height)); - schematic.put("Length", new ShortTag((short) length)); + 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 void write(Clipboard clipboard) throws IOException { 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 void write(Clipboard clipboard) throws IOException { 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 void write(Clipboard clipboard) throws IOException { } } - 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 void write(Clipboard clipboard) throws IOException { } 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 @@ private void writeBiomes(Clipboard clipboard, Map> schematic) 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 @@ private void writeBiomes(Clipboard clipboard, Map> schematic) 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 @@ private void writeBiomes(Clipboard clipboard, Map> schematic) } } - schematic.put("BiomePaletteMax", new IntTag(paletteMax)); - - Map> paletteTag = new HashMap<>(); - palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + schematic.putInt("BiomePaletteMax", paletteMax); - schematic.put("BiomePalette", new CompoundTag(paletteTag)); - schematic.put("BiomeData", new ByteArrayTag(buffer.toByteArray())); - } + LinCompoundTag.Builder paletteTag = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(palette, e -> paletteTag.putInt(e.getKey(), e.getIntValue())); - 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 0000000000..978cb8ba55 --- /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 0000000000..4030c2f906 --- /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 0000000000..35f6d58bcb --- /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 0000000000..17ff5004d7 --- /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 0000000000..930ae5efb9 --- /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 0000000000..ac91c8365f --- /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 29/59] 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 48f436e070..79d9258b85 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 30/59] 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 a4413138c9..09523c0e54 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 31/59] 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 920a249011..8a7751bd4f 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 void load( 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 void load( .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 32/59] 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 8a57411d6e..7361670566 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 boolean isFormat(final InputStream inputStream) { 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 boolean isFormat(InputStream inputStream) { 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 ClipboardWriter getWriter(OutputStream outputStream) throws IOException { //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 33/59] 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 7361670566..bfd6b20299 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 boolean isFormat(File file) { } return super.isFormat(file); } - }, //FAWE end @@ -239,6 +238,11 @@ public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { 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 ClipboardWriter getWriter(OutputStream outputStream) throws IOException { 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 34/59] 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 1de1aa8dfa..c223aae358 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 60860f7f75..d221a98d25 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 de52de2f92..4e1b292c56 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 e53d2497ec..0000000000 --- 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 87135fa863..0000000000 --- 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 50de3467e0..0000000000 --- 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 ee7d82f09c..0000000000 --- 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 424422ce6c..0000000000 --- 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 cbd1af53d4..0000000000 --- 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 0b90d942a6..0000000000 --- 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 0c57f9ca60..0000000000 --- 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 c3d4388e9e..0000000000 --- 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 dd17878684..0000000000 --- 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 7c7f39d9ac..0000000000 --- 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 aec3cfd249..0000000000 --- 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 ac10f2c0aa..0000000000 --- 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 b1e0c5772e..0000000000 --- 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 78c623c7ac..0000000000 --- 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 0026c4c675..0000000000 --- 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 17b3545352..0000000000 --- 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 51438592a7..0000000000 --- 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 0cecbb45bb..0000000000 --- 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 ebe674ca56..0000000000 --- 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 87dca94f21..0000000000 --- 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 ffca9e50de..0000000000 --- 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 826874f573..0000000000 --- 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 7fd24c7d97..0000000000 --- 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 b06d962a08..0000000000 --- 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 91bcf0e922..0000000000 --- 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 d2412b98ff..0000000000 --- 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 62f5d4e034..0000000000 --- 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 05c0b58f9d..0000000000 --- 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 0c4bcff85f..0000000000 --- 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 7de83af213..0000000000 --- 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 83509a2bbd..0000000000 --- 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 f2a694a2f1..0000000000 --- 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 99e001837a..0000000000 --- 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 35/59] 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 3440b009c3..dce3e1c4f6 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.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 List getSuggestions(String input, final ParserContext parserConte //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 25955adeed..242d1d7bce 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.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 PatternFactory(WorldEdit worldEdit) { 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 36/59] 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 b181f95067..8911099af2 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 boolean add(int x, int y, int z) { } 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 37/59] 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 79d9258b85..2c62943077 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 38/59] 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 2c62943077..4f8f18a17b 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 39/59] 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 b28d7536b9..59fc2add2f 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 void build(EditSession editSession, BlockVector3 position, Pattern patter 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 250914c056..83207f50bf 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.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 boolean spawn(Random random, int x, int z) throws WorldEditException { 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 1469ffb96f..926265bfbc 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 void generate(Region region, GenBase gen) throws WorldEditException { @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 7160be7506..664e656c41 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 void scatterBrush( @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 6117c6850b..1b4420d27c 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 @@ default boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullabl */ /** - * 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 @@ default boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullabl * @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 @@ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) } /** - * 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 @@ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) * @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 @@ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, } /** - * 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 @@ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, * @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 @@ default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { * @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 @@ default int getNearestSurfaceTerrainBlock( 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 @@ default void generate(Region region, GenBase gen) throws WorldEditException { 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 40/59] fix: improve schematic format selection (#2838) - no longer allow selecting a format specifically because of the generic extension `.schem` --- .../worldedit/command/SchematicCommands.java | 10 +++-- .../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, 100 insertions(+), 6 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 8a7751bd4f..e6a369502b 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 void load( actor.print(Caption.of("fawe.error.no-perm", "worldedit.schematic.load.other")); return; } - if (noExplicitFormat && filename.matches(".*\\.[\\w].*")) { + if (!noExplicitFormat) { + format = ClipboardFormats.findByAlias(formatName); + } else if (filename.matches(".*\\.[\\w].*")) { format = ClipboardFormats - .findByExtension(filename.substring(filename.lastIndexOf('.') + 1)); + .findByExplicitExtension(filename.substring(filename.lastIndexOf('.') + 1)); } else { - format = ClipboardFormats.findByAlias(formatName); + format = null; } file = MainUtil.resolve(dir, filename, format, false); } @@ -396,7 +398,7 @@ public void load( .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 bfd6b20299..a26e7c99ac 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.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 boolean isFormat(File file) { 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 boolean isFormat(File file) { } return super.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("schem2", "sponge2", "fast2"); + } }, //FAWE end @@ -217,6 +228,11 @@ public boolean isFormat(InputStream inputStream) { } 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 boolean isFormat(InputStream inputStream) { public boolean isFormat(File file) { return MCEDIT_SCHEMATIC.isFormat(file); } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -277,6 +298,11 @@ public boolean isFormat(InputStream inputStream) { 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 boolean isFormat(File file) { 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 boolean isFormat(File file) { return false; } + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -401,6 +436,11 @@ public boolean isFormat(InputStream inputStream) { 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 boolean isFormat(File file) { 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 7b4b1bf3bc..cb1b97e2ac 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 @@ default boolean isFormat(InputStream inputStream) { //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 b69a7a0cc4..786af54fa5 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 static void registerClipboardFormat(ClipboardFormat format) { 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 static String[] getFileExtensionArray() { 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 @@ private 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 static ClipboardFormat findByExtension(String extension) { } + /** + * 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 static MultiClipboardHolder loadAllFromInput( } 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 static MultiClipboardHolder loadAllFromUrl(URL url) throws IOException { 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 16e10a00d3..7d49114b5c 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 41/59] 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 acc0d8bf33..0bf621bc68 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 static URL upload(final Clipboard clipboard, final ClipboardFormat format * @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 42/59] 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 97fdd1f275..4c71a9f66e 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 Clipboard read(UUID uuid, Function createOutput) 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 e6a369502b..2d75b65b81 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 void load( } 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 7d49114b5c..a56d986950 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 43/59] 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 5265702962..3ed494298f 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 V apply(final long input) { 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 0000000000..1fd588ec4d --- /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 bc1e2bfbff..3e38b17241 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 @@ 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.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.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 LocalSession getLocalSession(Actor actor) { @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 d02ff9320d..33f19bfaa6 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.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.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 LimitExtent(Extent extent, FaweLimit limit) { * @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 @@ private void handleException(FaweException e) { 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 List getEntities(Region region) { 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 Entity createEntity(Location location, BaseEntity entity) { 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 Entity createEntity(Location location, BaseEntity entity, UUID uuid) { 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 void removeEntity(int x, int y, int z, UUID uuid) { 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 void removeEntity(int x, int y, int z, UUID uuid) { @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 boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable 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 int getHighestTerrainBlock(int x, int z, int minY, int maxY) { 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 int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) 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 int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { 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 int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY 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 int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY 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 int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY 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 int getNearestSurfaceTerrainBlock( ) { 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 > 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 T apply(Iterable positions, T filter) { } 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 BlockState getBlock(BlockVector3 position) { 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 BlockState getBlock(int x, int y, int z) { 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 BaseBlock getFullBlock(BlockVector3 position) { 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 BaseBlock getFullBlock(int x, int y, int z) { 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 BiomeType getBiome(BlockVector3 position) { 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 > boolean setBlock(BlockVector3 position, T 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 > boolean setBlock(int x, int y, int z, T b 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 > boolean setBlock(int x, int y, int z, T b @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 boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditEx 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 boolean setBiome(BlockVector3 position, BiomeType biome) { 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 579f04a9a6..f569ff0bb9 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 synchronized final void filter(Filter filter, Region region) { @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 7fdebdded7..ed5b028dda 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 boolean test(Extent extent, BlockVector3 vector) { @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 2b3ad7edba..84b8f77ade 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 DataMask(Extent extent) { @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 49c90183ae..b0ba4fb591 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 boolean test(Extent extent, BlockVector3 vector) { @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 32d853bda1..400f321630 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 @@ private SingleBlockStateMask(Extent extent, char ordinal, boolean isAir) { @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 2509696166..d80399be43 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 boolean test(BlockVector3 vector) { 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 0000000000..91ec1621de --- /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 d17787f033..f7a99dd35d 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 @@ 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 boolean MAX_ENTITIES() { 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 boolean isUnlimited() { && 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 String toString() { 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 0000000000..47c97a78b1 --- /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 4ba91a4f38..6a5473979e 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 @@ default boolean processGet(int chunkX, int chunkZ) { } /** - * 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 926265bfbc..7bc2431346 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 void resetLimit() { * @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 ca6f3b6a56..5cf0cf7456 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 EditSessionBuilder combineStages(@Nullable Boolean combineStages) { 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 EditSessionBuilder compile() { }; } 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 48e2a8078d..aa5f51e57f 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 Calendar detectDate(String input) { * @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 EditSession createEditSession(Actor actor, String command) { } // 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 EditSession createEditSession(Actor actor, String command) { } 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 a60968da15..1f551aefa1 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.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 void biomeInfo( ) @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 664e656c41..8f1733fbb3 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 void command( 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 3784497557..a8fa5076e4 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.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 void run(OutputStream out) { 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 void place( 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 4b2f98e0cf..f2a3c80ed4 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.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 GenerationCommands(WorldEdit worldEdit) { ) @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 int hcyl( ) @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 int cyl( ) @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 int cone(Actor actor, LocalSession session, EditSession editSession, ) @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 int hsphere( ) @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 int sphere( ) @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 int forestGen( ) @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 int pumpkins( ) @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 int hollowPyramid( ) @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 int pyramid( ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generate( Actor actor, LocalSession session, EditSession editSession, @@ -486,6 +497,7 @@ Formula must return positive numbers (true) if the point is inside the shape @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 int generateBiome( @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 void caves( @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 void ores( desc = "Generate an image" ) @CommandPermissions("worldedit.generation.image") + @SynchronousSettingExpected @Logging(PLACEMENT) public void image( Actor actor, @@ -685,6 +700,7 @@ public void image( @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 void ore( 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 d1a647587b..ba736e45e9 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.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 HistoryCommands(WorldEdit worldEdit) { 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 void undo( 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 6a121aa024..ac3490ccaa 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.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 void setskylighting(Actor actor, @Selection Region region) { ) @CommandPermissions("worldedit.region.line") @Logging(REGION) + @SynchronousSettingExpected public int line( Actor actor, EditSession editSession, @Selection Region region, @@ -257,6 +259,7 @@ public int line( @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 int replace( @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 int overlay( @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 void lay( ) @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 int center( @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 int faces( @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 void wer(Player player) throws WorldEditException { @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 int snowSmooth( @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 int move( @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 void fall( ) @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 int stack( ) @CommandPermissions("worldedit.regen") @Logging(REGION) + @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) void regenerate( Actor actor, World world, LocalSession session, EditSession editSession, @@ -737,6 +751,7 @@ void regenerate( @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 int deform( @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 int hollow( @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 int forest( @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 b987856314..0747115217 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.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 SnapshotUtilCommands(WorldEdit we) { ) @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 c81db21d83..c7c6ab9a1e 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.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 void cancel(Player player) { ) @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 String separateArg(String arg) { ) @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 int fillr( ) @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 int drain( ) @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 int fixLava( ) @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 int fixWater( ) @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 int removeAbove( ) @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 int removeBelow( ) @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 int replaceNear( ) @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 int snow( ) @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 int thaw( ) @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 int green( ) @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 void confirm(Actor actor) throws WorldEditException { } } -// @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 299908d993..e1996520a9 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 boolean actPrimary(Platform server, LocalConfiguration config, Player pla 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 2d35b22260..304fb9e771 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 @@ private boolean handleCycle( 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 75ef200c69..957ed3d83b 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 boolean actPrimary( ) { 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 6021102a24..74b06b1f57 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 boolean act(BrushAction action, Player player, LocalSession session) { 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 385fcd2f30..81d755b8c0 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 boolean actPrimary( 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 3d8d63f7d1..6381e93561 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 boolean actPrimary( 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 9e60fdcf30..b1686ccd52 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 boolean actSecondary(Platform server, LocalConfiguration config, Player p } 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 boolean actPrimary(Platform server, LocalConfiguration config, Player pla } 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 9fad39f9d3..a8b666ff68 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 boolean actPrimary( 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 b35865fb31..152f7016a9 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 boolean actPrimary( 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 614bbcf327..8aa5761f51 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 boolean actPrimary( } 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 1f52ff1034..b2f6ae7cfc 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 boolean actPrimary( @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 8efe2ab776..e38ae0d998 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 067f9cfebf..5d6b66483b 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.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 9e1dc106f6..037c94e5b0 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.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 0000000000..3cc936fdab --- /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 006432a732..f7f2932774 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 b03e4ce542..65fc7c196b 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.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.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 PlatformCommandManager(final WorldEdit worldEdit, PlatformManager platfor new ConfirmHandler(), new PreloadHandler() //FAWE end - )); // setup separate from main constructor // ensures that everything is definitely assigned @@ -312,20 +311,6 @@ private void registerAlwaysInjectedValues() { } ); //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 MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor 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 cd3ef56d5d..ab919b35f5 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 Collection getBiomes() { @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 bad9781ea9..a1b869efb8 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 BlockCategoryMask(Extent extent, BlockCategory category) { @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 9f191a4cc8..c7d3473f3b 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 boolean test(BlockState state) { @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 ac558520c2..0c563cdf7a 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 BlockStateMask(Extent extent, Map states, boolean strict) //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 17f1419e50..c3567b6d55 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 Collection getBlocks() { //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 b75a4cd1e8..be62c2eae7 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 ExistingBlockMask(Extent extent) { @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 e8b14b95ac..6bb39b9581 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 @@ private InverseSingleBlockStateMask(Extent extent, char ordinal, boolean isAir) @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 a56d986950..fea3e7dd57 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 44/59] 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 b635c1e7dd..1b60124cba 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 boolean test(BlockVector3 vector) { 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 f8207f2dcf..e40683f2e4 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 @@ private byte[] toBytes(UUID uuid) { 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 Future delete(UUID uuid, int id) { 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 @@ private Supplier create(ResultSet result) throws SQLEx 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 Future purge(int diff) { 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`> getEdits( try { int count = 0; String stmtStr = """ - SELECT * FROM `%sedits` + SELECT * FROM `%s_edits` WHERE `time` > ? AND `x2` >= ? AND `x1` <= ? @@ -202,7 +223,8 @@ public Iterable> getEdits( } 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 @@ private boolean sendBatch() throws SQLException { 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 @@ private boolean sendBatch() throws SQLException { 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 08165577f7..346543a0b8 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 void add(BlockChange change) { } 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 195a5fdbd3..a44e730135 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 int size() { 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 ad7c82c9f1..e7132bf5af 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.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 @@ 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 void write(OutputStream stream, int x, int y, int z) throws IOException { 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 void write(OutputStream stream, int x, int y, int z) throws IOException { @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 int readZ(FaweInputStream is) throws IOException { 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 void writeHeader(OutputStream os, int x, int y, int z) throws IOException 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 boolean isEmpty() { } @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 long getSizeOnDisk() { 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 6b693162e0..83f951c136 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 static long getSize(ChangeSet changeSet) { // } 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 aa5f51e57f..3dd5f56381 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 void remember(Identifiable player, World world, ChangeSet changeSet, Fawe 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 8d28ad1eb2..38fc184150 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 synchronized void summary( 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 Component apply(@Nullable Supplier input) { 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 b4ab9adc16..890b247d6e 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 45/59] 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 3ed494298f..5265702962 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 V apply(final long input) { 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 1fd588ec4d..0000000000 --- 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 3e38b17241..bc1e2bfbff 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 @@ 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.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.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 LocalSession getLocalSession(Actor actor) { @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 33f19bfaa6..d02ff9320d 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.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.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 LimitExtent(Extent extent, FaweLimit limit) { * @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 @@ private void handleException(FaweException e) { 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 List getEntities(Region region) { 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 Entity createEntity(Location location, BaseEntity entity) { 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 Entity createEntity(Location location, BaseEntity entity, UUID uuid) { 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 void removeEntity(int x, int y, int z, UUID uuid) { 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 void removeEntity(int x, int y, int z, UUID uuid) { @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 boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable 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 int getHighestTerrainBlock(int x, int z, int minY, int maxY) { 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 int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) 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 int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { 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 int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY 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 int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY 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 int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY 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 int getNearestSurfaceTerrainBlock( ) { 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 > 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 T apply(Iterable positions, T filter) { } 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 BlockState getBlock(BlockVector3 position) { 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 BlockState getBlock(int x, int y, int z) { 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 BaseBlock getFullBlock(BlockVector3 position) { 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 BaseBlock getFullBlock(int x, int y, int z) { 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 BiomeType getBiome(BlockVector3 position) { 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 > boolean setBlock(BlockVector3 position, T 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 > boolean setBlock(int x, int y, int z, T b 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 > boolean setBlock(int x, int y, int z, T b @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 boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditEx 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 boolean setBiome(BlockVector3 position, BiomeType biome) { 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 f569ff0bb9..579f04a9a6 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 synchronized final void filter(Filter filter, Region region) { @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 ed5b028dda..7fdebdded7 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 boolean test(Extent extent, BlockVector3 vector) { @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 84b8f77ade..2b3ad7edba 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 DataMask(Extent extent) { @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 b0ba4fb591..49c90183ae 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 boolean test(Extent extent, BlockVector3 vector) { @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 400f321630..32d853bda1 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 @@ private SingleBlockStateMask(Extent extent, char ordinal, boolean isAir) { @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 d80399be43..2509696166 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 boolean test(BlockVector3 vector) { 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 91ec1621de..0000000000 --- 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 f7a99dd35d..d17787f033 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 @@ 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 boolean MAX_ENTITIES() { 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 boolean isUnlimited() { && 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 String toString() { 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 47c97a78b1..0000000000 --- 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 6a5473979e..4ba91a4f38 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 @@ default boolean processGet(int chunkX, int chunkZ) { } /** - * 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 7bc2431346..926265bfbc 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 void resetLimit() { * @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 5cf0cf7456..ca6f3b6a56 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 EditSessionBuilder combineStages(@Nullable Boolean combineStages) { 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 EditSessionBuilder compile() { }; } 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 3dd5f56381..d82bcd4639 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 Calendar detectDate(String input) { * @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 EditSession createEditSession(Actor actor, String command, boolean expect } // 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 EditSession createEditSession(Actor actor, String command, boolean expect } 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 1f551aefa1..a60968da15 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.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 void biomeInfo( ) @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 8f1733fbb3..664e656c41 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 void command( 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 a8fa5076e4..3784497557 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.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 void run(OutputStream out) { 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 void place( 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 f2a3c80ed4..4b2f98e0cf 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.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 GenerationCommands(WorldEdit worldEdit) { ) @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 int hcyl( ) @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 int cyl( ) @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 int cone(Actor actor, LocalSession session, EditSession editSession, ) @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 int hsphere( ) @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 int sphere( ) @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 int forestGen( ) @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 int pumpkins( ) @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 int hollowPyramid( ) @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 int pyramid( ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) public int generate( Actor actor, LocalSession session, EditSession editSession, @@ -497,7 +486,6 @@ Formula must return positive numbers (true) if the point is inside the shape @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 int generateBiome( @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 void caves( @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 void ores( desc = "Generate an image" ) @CommandPermissions("worldedit.generation.image") - @SynchronousSettingExpected @Logging(PLACEMENT) public void image( Actor actor, @@ -700,7 +685,6 @@ public void image( @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 void ore( 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 ba736e45e9..d1a647587b 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.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 HistoryCommands(WorldEdit worldEdit) { 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 void undo( 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 ac3490ccaa..6a121aa024 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.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 void setskylighting(Actor actor, @Selection Region region) { ) @CommandPermissions("worldedit.region.line") @Logging(REGION) - @SynchronousSettingExpected public int line( Actor actor, EditSession editSession, @Selection Region region, @@ -259,7 +257,6 @@ public int line( @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 int replace( @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 int overlay( @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 void lay( ) @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 int center( @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 int faces( @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 void wer(Player player) throws WorldEditException { @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 int snowSmooth( @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 int move( @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 void fall( ) @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 int stack( ) @CommandPermissions("worldedit.regen") @Logging(REGION) - @SynchronousSettingExpected @Confirm(Confirm.Processor.REGION) void regenerate( Actor actor, World world, LocalSession session, EditSession editSession, @@ -751,7 +737,6 @@ void regenerate( @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 int deform( @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 int hollow( @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 int forest( @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 0747115217..b987856314 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.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 SnapshotUtilCommands(WorldEdit we) { ) @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 c7c6ab9a1e..c81db21d83 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.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 void cancel(Player player) { ) @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 String separateArg(String arg) { ) @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 int fillr( ) @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 int drain( ) @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 int fixLava( ) @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 int fixWater( ) @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 int removeAbove( ) @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 int removeBelow( ) @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 int replaceNear( ) @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 int snow( ) @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 int thaw( ) @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 int green( ) @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 void confirm(Actor actor) throws WorldEditException { } } +// @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 e1996520a9..299908d993 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 boolean actPrimary(Platform server, LocalConfiguration config, Player pla 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 304fb9e771..2d35b22260 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 @@ private boolean handleCycle( 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 957ed3d83b..75ef200c69 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 boolean actPrimary( ) { 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 74b06b1f57..6021102a24 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 boolean act(BrushAction action, Player player, LocalSession session) { 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 81d755b8c0..385fcd2f30 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 boolean actPrimary( 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 6381e93561..3d8d63f7d1 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 boolean actPrimary( 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 b1686ccd52..9e60fdcf30 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 boolean actSecondary(Platform server, LocalConfiguration config, Player p } 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 boolean actPrimary(Platform server, LocalConfiguration config, Player pla } 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 a8b666ff68..9fad39f9d3 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 boolean actPrimary( 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 152f7016a9..b35865fb31 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 boolean actPrimary( 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 8aa5761f51..614bbcf327 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 boolean actPrimary( } 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 b2f6ae7cfc..1f52ff1034 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 boolean actPrimary( @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 e38ae0d998..8efe2ab776 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 5d6b66483b..067f9cfebf 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.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 037c94e5b0..9e1dc106f6 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.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 3cc936fdab..0000000000 --- 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 f7f2932774..006432a732 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 65fc7c196b..b03e4ce542 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.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.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 PlatformCommandManager(final WorldEdit worldEdit, PlatformManager platfor new ConfirmHandler(), new PreloadHandler() //FAWE end + )); // setup separate from main constructor // ensures that everything is definitely assigned @@ -311,6 +312,20 @@ private void registerAlwaysInjectedValues() { } ); //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 MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor 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 ab919b35f5..cd3ef56d5d 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 Collection getBiomes() { @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 a1b869efb8..bad9781ea9 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 BlockCategoryMask(Extent extent, BlockCategory category) { @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 c7d3473f3b..9f191a4cc8 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 boolean test(BlockState state) { @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 0c563cdf7a..ac558520c2 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 BlockStateMask(Extent extent, Map states, boolean strict) //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 c3567b6d55..17f1419e50 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 Collection getBlocks() { //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 be62c2eae7..b75a4cd1e8 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 ExistingBlockMask(Extent extent) { @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 6bb39b9581..e8b14b95ac 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 @@ private InverseSingleBlockStateMask(Extent extent, char ordinal, boolean isAir) @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 fea3e7dd57..a56d986950 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 46/59] 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 4f8f18a17b..4e8b5252df 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 47/59] 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 83f951c136..0c323e47b5 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 static File resolve(File dir, String filename, @Nullable ClipboardFormat 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 2d75b65b81..615702a198 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 void load( 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 786af54fa5..801baa187a 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 static ClipboardFormat findByExplicitExtension(String extension) { } } 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 48/59] 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 4e8b5252df..c46ddf207f 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 49/59] 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 c46ddf207f..69d0fc0079 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 50/59] 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 e6ad24a7fd..7b578480f8 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 5b44758dd6..79aa448d8d 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 22d6c60830..c6e0ea2cf0 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 51/59] 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 69d0fc0079..89f03b0e10 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 52/59] 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 0473943227..c338033f0a 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 char[] get(CharBlocks blocks, int layer, boolean aggressive) { 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 char[] get(CharBlocks blocks, int layer, boolean aggressive) { 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 final synchronized void set(CharBlocks blocks, int layer, int index, char 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 53/59] 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 89f03b0e10..d16c6493d1 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 54/59] 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 d16c6493d1..243c51c38e 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 55/59] 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 4dd632c1de..94f8120b9f 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 f116fd23e2..1ad464f557 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 39ff980f6b..5067b921a3 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 f66bb1460a..b958c8ba7f 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 PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { CraftServer.class.cast(Bukkit.getServer()); int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 3953) { - throw new UnsupportedClassVersionError("Not 1.21!"); + if (dataVersion != 3953 && dataVersion != 3955) { + throw new UnsupportedClassVersionError("Not 1.21(.1)!"); } serverWorldsField = CraftServer.class.getDeclaredField("worlds"); 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 757ba0e296..11577ca9e6 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 @@ -624,15 +624,14 @@ public IBatchProcessor getTickingPostProcessor() { } 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 - } + 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; } - // 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/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 c2931d7ff6..ab55c7814d 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 @@ -2,7 +2,6 @@ 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; @@ -117,9 +116,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { 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 { @@ -189,28 +186,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { 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) { @@ -657,32 +641,22 @@ static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) { } 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 + //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 56/59] 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 94f8120b9f..b0216b3bf8 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 0bf621bc68..28367a949a 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 static URL upload(final Clipboard clipboard, final ClipboardFormat format * @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 db98d22038..8b6aa6cc82 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 @@ * 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 e00839eb0a..1d1f0df2a7 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 @@ * 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 83207f50bf..775e9cf4cd 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 SchemGen(Mask mask, Extent extent, List clipboards, bool /** * 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 cb1b97e2ac..1961dd8cb2 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 @@ default boolean isFormat(File file) { * * @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 801baa187a..d1529c803c 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 @@ private 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 890b247d6e..750324569a 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 57/59] 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 b0216b3bf8..12ad4a3535 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 58/59] 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 5067b921a3..253af67e65 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 59/59] 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 243c51c38e..12f0abf242 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"