diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1de1aa8df..c223aae35 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -27,9 +27,10 @@ body: description: Which server version version you using? If your server version is not listed, it is not supported. Update to a supported version first. multiple: false options: - - '1.20.5/6' - - '1.20' - - '1.19.4' + - '1.21' + - '1.20.6' + - '1.20.4' + - '1.20.2' validations: required: true diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index e6ad24a7f..7b578480f 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 + uses: gradle/actions/wrapper-validation@v4 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b44758dd..79aa448d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 + uses: gradle/actions/wrapper-validation@v4 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index 22d6c6083..c6e0ea2cf 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -9,7 +9,7 @@ jobs: - name: Checkout Repository uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 + uses: gradle/actions/wrapper-validation@v4 - name: Setup Java uses: actions/setup-java@v4 with: diff --git a/build.gradle.kts b/build.gradle.kts index 8fdea3200..12ad4a353 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.2") var snapshot by extra("SNAPSHOT") var revision: String by extra("") var buildNumber by extra("") @@ -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", "1.21.1") tasks { supportedVersions.forEach { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index fe8a81bc3..6f8f97859 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -28,7 +28,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/buildSrc/src/main/kotlin/CommonJavaConfig.kt b/buildSrc/src/main/kotlin/CommonJavaConfig.kt index fec02d1a0..d221a98d2 100644 --- a/buildSrc/src/main/kotlin/CommonJavaConfig.kt +++ b/buildSrc/src/main/kotlin/CommonJavaConfig.kt @@ -23,7 +23,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean val disabledLint = listOf( "processing", "path", "fallthrough", "serial", "overloads", "this-escape", ) - options.release.set(17) + options.release.set(21) options.compilerArgs.addAll(listOf("-Xlint:all") + disabledLint.map { "-Xlint:-$it" }) options.isDeprecation = true options.encoding = "UTF-8" @@ -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/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index 2c957880a..4bf9ffca2 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -40,8 +40,7 @@ fun Project.applyLibrariesConfiguration() { val relocations = mapOf( "net.kyori.text" to "com.sk89q.worldedit.util.formatting.text", - "net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori", - "net.kyori.adventure.nbt" to "com.sk89q.worldedit.util.nbt" + "net.kyori.minecraft" to "com.sk89q.worldedit.util.kyori" ) @@ -53,9 +52,14 @@ fun Project.applyLibrariesConfiguration() { exclude(dependency("com.google.guava:guava")) exclude(dependency("com.google.code.gson:gson")) exclude(dependency("com.google.errorprone:error_prone_annotations")) + exclude(dependency("com.google.guava:failureaccess")) exclude(dependency("org.checkerframework:checker-qual")) + exclude(dependency("org.jetbrains:annotations")) exclude(dependency("org.apache.logging.log4j:log4j-api")) exclude(dependency("com.google.code.findbugs:jsr305")) + exclude { + it.moduleGroup == "org.jetbrains.kotlin" + } } relocations.forEach { (from, to) -> @@ -67,11 +71,19 @@ fun Project.applyLibrariesConfiguration() { .filterIsInstance() .map { it.copy() } .map { dependency -> - dependency.artifact { - name = dependency.name - type = artifactType - extension = "jar" - classifier = artifactType + val category = dependency.attributes.getAttribute(Category.CATEGORY_ATTRIBUTE)?.name + if (category == Category.REGULAR_PLATFORM || category == Category.ENFORCED_PLATFORM) { + return@map dependency + } + try { + dependency.artifact { + name = dependency.name + type = artifactType + extension = "jar" + classifier = artifactType + } + } catch (e: Exception) { + throw RuntimeException("Failed to add artifact to dependency: $dependency", e) } dependency } @@ -85,6 +97,10 @@ fun Project.applyLibrariesConfiguration() { from({ altConfigFiles("sources") }) + + // Yeet module-info's + exclude("module-info.java") + relocations.forEach { (from, to) -> val filePattern = Regex("(.*)${from.replace('.', '/')}((?:/|$).*)") val textPattern = Regex.fromLiteral(from) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 70a4116a6..12f0abf24 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" @@ -14,22 +14,22 @@ mapmanager = "1.8.0-SNAPSHOT" griefprevention = "17.0.0" griefdefender = "2.1.0-SNAPSHOT" residence = "4.5._13.1" -towny = "0.100.3.2" -plotsquared = "7.3.8" +towny = "0.100.3.12" +plotsquared = "7.3.9" # Third party bstats = "3.0.2" sparsebitset = "1.3" parallelgzip = "1.0.5" adventure = "4.17.0" -adventure-bukkit = "4.3.3" -checkerqual = "3.43.0" +adventure-bukkit = "4.3.4" +checkerqual = "3.46.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 -antlr4 = "4.13.1" +antlr4 = "4.13.2" json-simple = "1.1.1" jlibnoise = "1.0.0" jchronic = "0.2.4a" @@ -40,6 +40,7 @@ paperlib = "1.0.8" paster = "1.1.6" vault = "1.7.1" serverlib = "2.3.6" +linbus = "0.1.2" ## 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/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a4..09523c0e5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index c2bbe1807..b8ceb0dd7 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_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/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 fa027e567..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java +++ /dev/null @@ -1,1018 +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.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.DataFixer; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.Util; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.StringRepresentable; -import net.minecraft.util.thread.BlockableEventLoop; -import net.minecraft.world.Clearable; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.StructureBlockEntity; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World.Environment; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_19_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.spigotmc.SpigotConfig; -import org.spigotmc.WatchdogThread; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -public final class PaperweightAdapter implements BukkitImplAdapter { - - private final Logger LOGGER = Logger.getLogger(getClass().getCanonicalName()); - - private final Field serverWorldsField; - private final Method getChunkFutureMethod; - private final Field chunkProviderExecutorField; - private final Watchdog watchdog; - - // ------------------------------------------------------------------------ - // Code that may break between versions of Minecraft - // ------------------------------------------------------------------------ - - public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException { - // A simple test - CraftServer.class.cast(Bukkit.getServer()); - - int dataVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - if (dataVersion != 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())); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockData data) { - net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); - int combinedId = Block.getId(state); - return combinedId == 0 && state.getBlock() != Blocks.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - Block mcBlock = getBlockFromType(state.getBlockType()); - net.minecraft.world.level.block.state.BlockState newState = mcBlock.defaultBlockState(); - Map, Object> states = state.getStates(); - newState = applyProperties(mcBlock.getStateDefinition(), newState, states); - final int combinedId = Block.getId(newState); - return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); - } - - @Override - public BlockState getBlock(Location location) { - checkNotNull(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); - int internalId = Block.getId(blockData); - BlockState state = BlockStateIdAccess.getBlockStateById(internalId); - if (state == null) { - org.bukkit.block.Block bukkitBlock = location.getBlock(); - state = BukkitAdapter.adapt(bukkitBlock.getBlockData()); - } - - return state; - } - - @Override - public BaseBlock getFullBlock(Location location) { - BlockState state = getBlock(location); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - int x = location.getBlockX(); - int y = location.getBlockY(); - int z = location.getBlockZ(); - - final ServerLevel handle = craftWorld.getHandle(); - LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); - final BlockPos blockPos = new BlockPos(x, y, z); - - // Read the NBT data - BlockEntity te = chunk.getBlockEntity(blockPos); - if (te != null) { - net.minecraft.nbt.CompoundTag tag = te.saveWithId(); - return state.toBaseBlock((CompoundBinaryTag) toNativeBinary(tag)); - } - - return state.toBaseBlock(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess(this, - new WeakReference<>(((CraftWorld) world).getHandle())); - } - - private static net.minecraft.core.Direction adapt(Direction face) { - switch (face) { - case NORTH: - return net.minecraft.core.Direction.NORTH; - case SOUTH: - return net.minecraft.core.Direction.SOUTH; - case WEST: - return net.minecraft.core.Direction.WEST; - case EAST: - return net.minecraft.core.Direction.EAST; - case DOWN: - return net.minecraft.core.Direction.DOWN; - case UP: - default: - return net.minecraft.core.Direction.UP; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private net.minecraft.world.level.block.state.BlockState applyProperties( - StateDefinition stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states - ) { - for (Map.Entry, Object> state : states.entrySet()) { - net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); - Comparable value = (Comparable) state.getValue(); - // we may need to adapt this value, depending on the source prop - if (property instanceof DirectionProperty) { - Direction dir = (Direction) value; - value = adapt(dir); - } else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - String enumName = (String) value; - value = ((net.minecraft.world.level.block.state.properties.EnumProperty) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); - } - - newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value - ); - } - return newState; - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - // Do not allow creating of passenger entity snapshots, passengers are included in the vehicle entity - if (mcEntity.isPassenger()) { - return null; - } - - String id = getEntityId(mcEntity); - - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - readEntityIntoTag(mcEntity, tag); - return new BaseEntity( - com.sk89q.worldedit.world.entity.EntityTypes.get(id), - LazyReference.from(() -> (CompoundBinaryTag) toNativeBinary(tag)) - ); - } - - @Nullable - @Override - public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state) { - checkNotNull(location); - checkNotNull(state); - - CraftWorld craftWorld = ((CraftWorld) location.getWorld()); - ServerLevel worldServer = craftWorld.getHandle(); - - Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); - - if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); - return createdEntity.getBukkitEntity(); - } else { - return null; - } - } - - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return TranslatableComponent.of(getItemFromType(itemType).getDescriptionId()); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static final LoadingCache> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); - - @SuppressWarnings({ "rawtypes" }) - @Override - public Map> getProperties(BlockType blockType) { - Map> properties = new TreeMap<>(); - Block block = getBlockFromType(blockType); - StateDefinition blockStateList = - block.getStateDefinition(); - for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { - Property property = PROPERTY_CACHE.getUnchecked(state); - properties.put(property.getName(), property); - } - return properties; - } - - @Override - public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { - ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( - new StructureBlockEntity( - new BlockPos(pos.x(), pos.y(), pos.z()), - Blocks.STRUCTURE_BLOCK.defaultBlockState() - ), - __ -> (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) - )); - } - - @Override - public void sendFakeOP(Player player) { - ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( - ((CraftPlayer) player).getHandle(), (byte) 28 - )); - } - - @Override - public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { - ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().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(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - private final LoadingCache fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); - - @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { - CraftWorld craftWorld = (CraftWorld) world; - ServerLevel worldServer = craftWorld.getHandle(); - ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); - - PaperweightFakePlayer fakePlayer; - try { - fakePlayer = fakePlayers.get(worldServer); - } catch (ExecutionException ignored) { - return false; - } - fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); - fakePlayer.absMoveTo(position.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(((CompoundBinaryTag) toNativeBinary(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; - } - - // ------------------------------------------------------------------------ - // Code that is less likely to break - // ------------------------------------------------------------------------ - - /** - * Converts from a non-native NMS NBT structure to a native WorldEdit NBT - * structure. - * - * @param foreign non-native NMS NBT structure - * @return native WorldEdit NBT structure - */ - @Override - public BinaryTag toNativeBinary(net.minecraft.nbt.Tag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); - Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); - - for (String str : foreignKeys) { - net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); - } - return CompoundBinaryTag.from(values); - } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); - } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); - } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); - } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); - } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); - } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); - } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); - } else if (foreign instanceof net.minecraft.nbt.ListTag) { - try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); - } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); - } - } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); - } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); - } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); - } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); - } - } - - /** - * Convert a foreign NBT list tag into a native WorldEdit one. - * - * @param foreign the foreign tag - * @return the converted tag - * @throws SecurityException on error - * @throws IllegalArgumentException on error - */ - private ListBinaryTag toNativeList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { - ListBinaryTag.Builder values = ListBinaryTag.builder(); - - for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); - } - - return values.build(); - } - - /** - * Converts a WorldEdit-native NBT structure to a NMS structure. - * - * @param foreign structure to convert - * @return non-native structure - */ - @Override - public net.minecraft.nbt.Tag fromNativeBinary(BinaryTag foreign) { - if (foreign == null) { - return null; - } - if (foreign instanceof CompoundBinaryTag) { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); - } - return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { - net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); - } - return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { - return net.minecraft.nbt.EndTag.INSTANCE; - } else { - throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); - } - } - - @Override - public boolean supportsWatchdog() { - return watchdog != null; - } - - @Override - public void tickWatchdog() { - watchdog.tick(); - } - - private class SpigotWatchdog implements Watchdog { - private final Field instanceField; - private final Field lastTickField; - - SpigotWatchdog() throws NoSuchFieldException { - Field instanceField = WatchdogThread.class.getDeclaredField("instance"); - instanceField.setAccessible(true); - this.instanceField = instanceField; - - Field lastTickField = WatchdogThread.class.getDeclaredField("lastTick"); - lastTickField.setAccessible(true); - this.lastTickField = lastTickField; - } - - @Override - public void tick() { - try { - WatchdogThread instance = (WatchdogThread) this.instanceField.get(null); - if ((long) lastTickField.get(instance) != 0) { - WatchdogThread.tick(); - } - } catch (IllegalAccessException e) { - LOGGER.log(Level.WARNING, "Failed to tick watchdog", e); - } - } - } - - private static class MojangWatchdog implements Watchdog { - private final DedicatedServer server; - private final Field tickField; - - MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { - this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ah") - ); - if (tickField.getType() != long.class) { - throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); - } - tickField.setAccessible(true); - this.tickField = tickField; - } - - @Override - public void tick() { - try { - tickField.set(server, Util.getMillis()); - } catch (IllegalAccessException ignored) { - } - } - } - - private static class NoOpWorldLoadListener implements ChunkProgressListener { - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) { - } - - @Override - public void start() { - } - - @Override - public void stop() { - } - - @Override - public void setChunkRadius(int radius) { - } - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_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 948c190b5..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightDataConverters.java +++ /dev/null @@ -1,2801 +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 com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.core.Direction; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import net.minecraft.util.StringUtil; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.item.DyeColor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Executor; -import java.util.stream.Collectors; -import javax.annotation.Nullable; - -/** - * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) - * - * We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy - * which is safer, faster and cleaner code. - * - * The pre DFU code did not fail when the Source version was unknown. - * - * This class also provides util methods for converting compounds to wrap the update call to - * receive the source version in the compound - */ -@SuppressWarnings({ "rawtypes", "unchecked" }) -class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { - - //FAWE start - BinaryTag - @SuppressWarnings("unchecked") - @Override - public T fixUp(FixType type, T original, int srcVer) { - if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); - } else if (type == FixTypes.BLOCK_STATE) { - return (T) fixBlockState((String) original, srcVer); - } else if (type == FixTypes.ITEM_TYPE) { - return (T) fixItemType((String) original, srcVer); - } else if (type == FixTypes.BIOME) { - return (T) fixBiome((String) original, srcVer); - } - return original; - } - - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); - } - //FAWE end - - private String fixBlockState(String blockState, int srcVer) { - net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); - Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); - net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); - return nbtToState(fixed); - } - - private String nbtToState(net.minecraft.nbt.CompoundTag tagCompound) { - StringBuilder sb = new StringBuilder(); - sb.append(tagCompound.getString("Name")); - if (tagCompound.contains("Properties", 10)) { - sb.append('['); - net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); - sb.append(props.getAllKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); - sb.append(']'); - } - return sb.toString(); - } - - private static net.minecraft.nbt.CompoundTag stateToNBT(String blockState) { - int propIdx = blockState.indexOf('['); - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - if (propIdx < 0) { - tag.putString("Name", blockState); - } else { - tag.putString("Name", blockState.substring(0, propIdx)); - net.minecraft.nbt.CompoundTag propTag = new net.minecraft.nbt.CompoundTag(); - String props = blockState.substring(propIdx + 1, blockState.length() - 1); - String[] propArr = props.split(","); - for (String pair : propArr) { - final String[] split = pair.split("="); - propTag.putString(split[0], split[1]); - } - tag.put("Properties", propTag); - } - return tag; - } - - private String fixBiome(String key, int srcVer) { - return fixName(key, srcVer, References.BIOME); - } - - private String fixItemType(String key, int srcVer) { - return fixName(key, srcVer, References.ITEM_NAME); - } - - private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, net.minecraft.nbt.StringTag.valueOf(key)), srcVer, DATA_VERSION) - .getValue().getAsString(); - } - - private final PaperweightAdapter adapter; - - private static final NbtOps OPS_NBT = NbtOps.INSTANCE; - private static final int LEGACY_VERSION = 1343; - private static int DATA_VERSION; - static PaperweightDataConverters INSTANCE; - - private final Map> converters = new EnumMap<>(LegacyType.class); - private final Map> inspectors = new EnumMap<>(LegacyType.class); - - // Set on build - private DataFixer fixer; - private static final Map DFU_TO_LEGACY = new HashMap<>(); - - public enum LegacyType { - LEVEL(References.LEVEL), - PLAYER(References.PLAYER), - CHUNK(References.CHUNK), - BLOCK_ENTITY(References.BLOCK_ENTITY), - ENTITY(References.ENTITY), - ITEM_INSTANCE(References.ITEM_STACK), - OPTIONS(References.OPTIONS), - STRUCTURE(References.STRUCTURE); - - private final TypeReference type; - - LegacyType(TypeReference type) { - this.type = type; - DFU_TO_LEGACY.put(type.typeName(), this); - } - - public TypeReference getDFUType() { - return type; - } - } - - PaperweightDataConverters(int dataVersion, PaperweightAdapter adapter) { - super(dataVersion); - DATA_VERSION = dataVersion; - INSTANCE = this; - this.adapter = adapter; - registerConverters(); - registerInspectors(); - } - - - // Called after fixers are built and ready for FIXING - @Override - public DataFixer buildUnoptimized() { - return this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); - } - - @Override - public DataFixer buildOptimized(final Set requiredTypes, Executor executor) { - return buildUnoptimized(); - } - - @SuppressWarnings("unchecked") - private class WrappedDataFixer implements DataFixer { - private final DataFixer realFixer; - - WrappedDataFixer(DataFixer realFixer) { - this.realFixer = realFixer; - } - - @Override - - public Dynamic update(TypeReference type, Dynamic dynamic, int sourceVer, int targetVer) { - LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); - if (sourceVer < LEGACY_VERSION && legacyType != null) { - net.minecraft.nbt.CompoundTag cmp = (net.minecraft.nbt.CompoundTag) dynamic.getValue(); - int desiredVersion = Math.min(targetVer, LEGACY_VERSION); - - cmp = convert(legacyType, cmp, sourceVer, desiredVersion); - sourceVer = desiredVersion; - dynamic = new Dynamic(OPS_NBT, cmp); - } - return realFixer.update(type, dynamic, sourceVer, targetVer); - } - - private net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int desiredVersion) { - List converters = PaperweightDataConverters.this.converters.get(type); - if (converters != null && !converters.isEmpty()) { - for (DataConverter converter : converters) { - int dataVersion = converter.getDataVersion(); - if (dataVersion > sourceVer && dataVersion <= desiredVersion) { - cmp = converter.convert(cmp); - } - } - } - - List inspectors = PaperweightDataConverters.this.inspectors.get(type); - if (inspectors != null && !inspectors.isEmpty()) { - for (DataInspector inspector : inspectors) { - cmp = inspector.inspect(cmp, sourceVer, desiredVersion); - } - } - - return cmp; - } - - @Override - public Schema getSchema(int i) { - return realFixer.getSchema(i); - } - } - - public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { - return convert(type.getDFUType(), cmp); - } - - public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { - return convert(type.getDFUType(), cmp, sourceVer); - } - - public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - return convert(type.getDFUType(), cmp, sourceVer, targetVer); - } - - public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp) { - int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; - return convert(type, cmp, i); - } - - public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { - return convert(type, cmp, sourceVer, DATA_VERSION); - } - - public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (sourceVer >= targetVer) { - return cmp; - } - return (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); - } - - - public interface DataInspector { - net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer); - } - - public interface DataConverter { - - int getDataVersion(); - - net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); - } - - - private void registerInspector(LegacyType type, DataInspector inspector) { - this.inspectors.computeIfAbsent(type, k -> new ArrayList<>()).add(inspector); - } - - private void registerConverter(LegacyType type, DataConverter converter) { - int version = converter.getDataVersion(); - - List list = this.converters.computeIfAbsent(type, k -> new ArrayList<>()); - if (!list.isEmpty() && list.get(list.size() - 1).getDataVersion() > version) { - for (int j = 0; j < list.size(); ++j) { - if (list.get(j).getDataVersion() > version) { - list.add(j, converter); - break; - } - } - } else { - list.add(converter); - } - } - - private void registerInspectors() { - registerEntityItemList("EntityHorseDonkey", "SaddleItem", "Items"); - registerEntityItemList("EntityHorseMule", "Items"); - registerEntityItemList("EntityMinecartChest", "Items"); - registerEntityItemList("EntityMinecartHopper", "Items"); - registerEntityItemList("EntityVillager", "Inventory"); - registerEntityItemListEquipment("EntityArmorStand"); - registerEntityItemListEquipment("EntityBat"); - registerEntityItemListEquipment("EntityBlaze"); - registerEntityItemListEquipment("EntityCaveSpider"); - registerEntityItemListEquipment("EntityChicken"); - registerEntityItemListEquipment("EntityCow"); - registerEntityItemListEquipment("EntityCreeper"); - registerEntityItemListEquipment("EntityEnderDragon"); - registerEntityItemListEquipment("EntityEnderman"); - registerEntityItemListEquipment("EntityEndermite"); - registerEntityItemListEquipment("EntityEvoker"); - registerEntityItemListEquipment("EntityGhast"); - registerEntityItemListEquipment("EntityGiantZombie"); - registerEntityItemListEquipment("EntityGuardian"); - registerEntityItemListEquipment("EntityGuardianElder"); - registerEntityItemListEquipment("EntityHorse"); - registerEntityItemListEquipment("EntityHorseDonkey"); - registerEntityItemListEquipment("EntityHorseMule"); - registerEntityItemListEquipment("EntityHorseSkeleton"); - registerEntityItemListEquipment("EntityHorseZombie"); - registerEntityItemListEquipment("EntityIronGolem"); - registerEntityItemListEquipment("EntityMagmaCube"); - registerEntityItemListEquipment("EntityMushroomCow"); - registerEntityItemListEquipment("EntityOcelot"); - registerEntityItemListEquipment("EntityPig"); - registerEntityItemListEquipment("EntityPigZombie"); - registerEntityItemListEquipment("EntityRabbit"); - registerEntityItemListEquipment("EntitySheep"); - registerEntityItemListEquipment("EntityShulker"); - registerEntityItemListEquipment("EntitySilverfish"); - registerEntityItemListEquipment("EntitySkeleton"); - registerEntityItemListEquipment("EntitySkeletonStray"); - registerEntityItemListEquipment("EntitySkeletonWither"); - registerEntityItemListEquipment("EntitySlime"); - registerEntityItemListEquipment("EntitySnowman"); - registerEntityItemListEquipment("EntitySpider"); - registerEntityItemListEquipment("EntitySquid"); - registerEntityItemListEquipment("EntityVex"); - registerEntityItemListEquipment("EntityVillager"); - registerEntityItemListEquipment("EntityVindicator"); - registerEntityItemListEquipment("EntityWitch"); - registerEntityItemListEquipment("EntityWither"); - registerEntityItemListEquipment("EntityWolf"); - registerEntityItemListEquipment("EntityZombie"); - registerEntityItemListEquipment("EntityZombieHusk"); - registerEntityItemListEquipment("EntityZombieVillager"); - registerEntityItemSingle("EntityFireworks", "FireworksItem"); - registerEntityItemSingle("EntityHorse", "ArmorItem"); - registerEntityItemSingle("EntityHorse", "SaddleItem"); - registerEntityItemSingle("EntityHorseMule", "SaddleItem"); - registerEntityItemSingle("EntityHorseSkeleton", "SaddleItem"); - registerEntityItemSingle("EntityHorseZombie", "SaddleItem"); - registerEntityItemSingle("EntityItem", "Item"); - registerEntityItemSingle("EntityItemFrame", "Item"); - registerEntityItemSingle("EntityPotion", "Potion"); - - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItem("TileEntityRecordPlayer", "RecordItem")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityBrewingStand", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityChest", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDispenser", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDropper", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityFurnace", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityHopper", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityShulkerBox", "Items")); - registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorMobSpawnerMobs()); - registerInspector(LegacyType.CHUNK, new DataInspectorChunks()); - registerInspector(LegacyType.ENTITY, new DataInspectorCommandBlock()); - registerInspector(LegacyType.ENTITY, new DataInspectorEntityPassengers()); - registerInspector(LegacyType.ENTITY, new DataInspectorMobSpawnerMinecart()); - registerInspector(LegacyType.ENTITY, new DataInspectorVillagers()); - registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorBlockEntity()); - registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorEntity()); - registerInspector(LegacyType.LEVEL, new DataInspectorLevelPlayer()); - registerInspector(LegacyType.PLAYER, new DataInspectorPlayer()); - registerInspector(LegacyType.PLAYER, new DataInspectorPlayerVehicle()); - registerInspector(LegacyType.STRUCTURE, new DataInspectorStructure()); - } - - private void registerConverters() { - registerConverter(LegacyType.ENTITY, new DataConverterEquipment()); - registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterSignText()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterMaterialId()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionId()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterSpawnEgg()); - registerConverter(LegacyType.ENTITY, new DataConverterMinecart()); - registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterMobSpawner()); - registerConverter(LegacyType.ENTITY, new DataConverterUUID()); - registerConverter(LegacyType.ENTITY, new DataConverterHealth()); - registerConverter(LegacyType.ENTITY, new DataConverterSaddle()); - registerConverter(LegacyType.ENTITY, new DataConverterHanging()); - registerConverter(LegacyType.ENTITY, new DataConverterDropChances()); - registerConverter(LegacyType.ENTITY, new DataConverterRiding()); - registerConverter(LegacyType.ENTITY, new DataConverterArmorStand()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBook()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterCookedFish()); - registerConverter(LegacyType.ENTITY, new DataConverterZombie()); - registerConverter(LegacyType.OPTIONS, new DataConverterVBO()); - registerConverter(LegacyType.ENTITY, new DataConverterGuardian()); - registerConverter(LegacyType.ENTITY, new DataConverterSkeleton()); - registerConverter(LegacyType.ENTITY, new DataConverterZombieType()); - registerConverter(LegacyType.ENTITY, new DataConverterHorse()); - registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterTileEntity()); - registerConverter(LegacyType.ENTITY, new DataConverterEntity()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBanner()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionWater()); - registerConverter(LegacyType.ENTITY, new DataConverterShulker()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterShulkerBoxItem()); - registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterShulkerBoxBlock()); - registerConverter(LegacyType.OPTIONS, new DataConverterLang()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterTotem()); - registerConverter(LegacyType.CHUNK, new DataConverterBedBlock()); - registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBedItem()); - } - - private void registerEntityItemList(String type, String... keys) { - registerInspector(LegacyType.ENTITY, new DataInspectorItemList(type, keys)); - } - - private void registerEntityItemSingle(String type, String key) { - registerInspector(LegacyType.ENTITY, new DataInspectorItem(type, key)); - } - - private void registerEntityItemListEquipment(String type) { - registerEntityItemList(type, "ArmorItems", "HandItems"); - } - - private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); - - static { - final Map map = OLD_ID_TO_KEY_MAP; - map.put("EntityItem", new ResourceLocation("item")); - map.put("EntityExperienceOrb", new ResourceLocation("xp_orb")); - map.put("EntityAreaEffectCloud", new ResourceLocation("area_effect_cloud")); - map.put("EntityGuardianElder", new ResourceLocation("elder_guardian")); - map.put("EntitySkeletonWither", new ResourceLocation("wither_skeleton")); - map.put("EntitySkeletonStray", new ResourceLocation("stray")); - map.put("EntityEgg", new ResourceLocation("egg")); - map.put("EntityLeash", new ResourceLocation("leash_knot")); - map.put("EntityPainting", new ResourceLocation("painting")); - map.put("EntityTippedArrow", new ResourceLocation("arrow")); - map.put("EntitySnowball", new ResourceLocation("snowball")); - map.put("EntityLargeFireball", new ResourceLocation("fireball")); - map.put("EntitySmallFireball", new ResourceLocation("small_fireball")); - map.put("EntityEnderPearl", new ResourceLocation("ender_pearl")); - map.put("EntityEnderSignal", new ResourceLocation("eye_of_ender_signal")); - map.put("EntityPotion", new ResourceLocation("potion")); - map.put("EntityThrownExpBottle", new ResourceLocation("xp_bottle")); - map.put("EntityItemFrame", new ResourceLocation("item_frame")); - map.put("EntityWitherSkull", new ResourceLocation("wither_skull")); - map.put("EntityTNTPrimed", new ResourceLocation("tnt")); - map.put("EntityFallingBlock", new ResourceLocation("falling_block")); - map.put("EntityFireworks", new ResourceLocation("fireworks_rocket")); - map.put("EntityZombieHusk", new ResourceLocation("husk")); - map.put("EntitySpectralArrow", new ResourceLocation("spectral_arrow")); - map.put("EntityShulkerBullet", new ResourceLocation("shulker_bullet")); - map.put("EntityDragonFireball", new ResourceLocation("dragon_fireball")); - map.put("EntityZombieVillager", new ResourceLocation("zombie_villager")); - map.put("EntityHorseSkeleton", new ResourceLocation("skeleton_horse")); - map.put("EntityHorseZombie", new ResourceLocation("zombie_horse")); - map.put("EntityArmorStand", new ResourceLocation("armor_stand")); - map.put("EntityHorseDonkey", new ResourceLocation("donkey")); - map.put("EntityHorseMule", new ResourceLocation("mule")); - map.put("EntityEvokerFangs", new ResourceLocation("evocation_fangs")); - map.put("EntityEvoker", new ResourceLocation("evocation_illager")); - map.put("EntityVex", new ResourceLocation("vex")); - map.put("EntityVindicator", new ResourceLocation("vindication_illager")); - map.put("EntityIllagerIllusioner", new ResourceLocation("illusion_illager")); - map.put("EntityMinecartCommandBlock", new ResourceLocation("commandblock_minecart")); - map.put("EntityBoat", new ResourceLocation("boat")); - map.put("EntityMinecartRideable", new ResourceLocation("minecart")); - map.put("EntityMinecartChest", new ResourceLocation("chest_minecart")); - map.put("EntityMinecartFurnace", new ResourceLocation("furnace_minecart")); - map.put("EntityMinecartTNT", new ResourceLocation("tnt_minecart")); - map.put("EntityMinecartHopper", new ResourceLocation("hopper_minecart")); - map.put("EntityMinecartMobSpawner", new ResourceLocation("spawner_minecart")); - map.put("EntityCreeper", new ResourceLocation("creeper")); - map.put("EntitySkeleton", new ResourceLocation("skeleton")); - map.put("EntitySpider", new ResourceLocation("spider")); - map.put("EntityGiantZombie", new ResourceLocation("giant")); - map.put("EntityZombie", new ResourceLocation("zombie")); - map.put("EntitySlime", new ResourceLocation("slime")); - map.put("EntityGhast", new ResourceLocation("ghast")); - map.put("EntityPigZombie", new ResourceLocation("zombie_pigman")); - map.put("EntityEnderman", new ResourceLocation("enderman")); - map.put("EntityCaveSpider", new ResourceLocation("cave_spider")); - map.put("EntitySilverfish", new ResourceLocation("silverfish")); - map.put("EntityBlaze", new ResourceLocation("blaze")); - map.put("EntityMagmaCube", new ResourceLocation("magma_cube")); - map.put("EntityEnderDragon", new ResourceLocation("ender_dragon")); - map.put("EntityWither", new ResourceLocation("wither")); - map.put("EntityBat", new ResourceLocation("bat")); - map.put("EntityWitch", new ResourceLocation("witch")); - map.put("EntityEndermite", new ResourceLocation("endermite")); - map.put("EntityGuardian", new ResourceLocation("guardian")); - map.put("EntityShulker", new ResourceLocation("shulker")); - map.put("EntityPig", new ResourceLocation("pig")); - map.put("EntitySheep", new ResourceLocation("sheep")); - map.put("EntityCow", new ResourceLocation("cow")); - map.put("EntityChicken", new ResourceLocation("chicken")); - map.put("EntitySquid", new ResourceLocation("squid")); - map.put("EntityWolf", new ResourceLocation("wolf")); - map.put("EntityMushroomCow", new ResourceLocation("mooshroom")); - map.put("EntitySnowman", new ResourceLocation("snowman")); - map.put("EntityOcelot", new ResourceLocation("ocelot")); - map.put("EntityIronGolem", new ResourceLocation("villager_golem")); - map.put("EntityHorse", new ResourceLocation("horse")); - map.put("EntityRabbit", new ResourceLocation("rabbit")); - map.put("EntityPolarBear", new ResourceLocation("polar_bear")); - map.put("EntityLlama", new ResourceLocation("llama")); - map.put("EntityLlamaSpit", new ResourceLocation("llama_spit")); - map.put("EntityParrot", new ResourceLocation("parrot")); - map.put("EntityVillager", new ResourceLocation("villager")); - map.put("EntityEnderCrystal", new ResourceLocation("ender_crystal")); - map.put("TileEntityFurnace", new ResourceLocation("furnace")); - map.put("TileEntityChest", new ResourceLocation("chest")); - map.put("TileEntityEnderChest", new ResourceLocation("ender_chest")); - map.put("TileEntityRecordPlayer", new ResourceLocation("jukebox")); - map.put("TileEntityDispenser", new ResourceLocation("dispenser")); - map.put("TileEntityDropper", new ResourceLocation("dropper")); - map.put("TileEntitySign", new ResourceLocation("sign")); - map.put("TileEntityMobSpawner", new ResourceLocation("mob_spawner")); - map.put("TileEntityNote", new ResourceLocation("noteblock")); - map.put("TileEntityPiston", new ResourceLocation("piston")); - map.put("TileEntityBrewingStand", new ResourceLocation("brewing_stand")); - map.put("TileEntityEnchantTable", new ResourceLocation("enchanting_table")); - map.put("TileEntityEnderPortal", new ResourceLocation("end_portal")); - map.put("TileEntityBeacon", new ResourceLocation("beacon")); - map.put("TileEntitySkull", new ResourceLocation("skull")); - map.put("TileEntityLightDetector", new ResourceLocation("daylight_detector")); - map.put("TileEntityHopper", new ResourceLocation("hopper")); - map.put("TileEntityComparator", new ResourceLocation("comparator")); - map.put("TileEntityFlowerPot", new ResourceLocation("flower_pot")); - map.put("TileEntityBanner", new ResourceLocation("banner")); - map.put("TileEntityStructure", new ResourceLocation("structure_block")); - map.put("TileEntityEndGateway", new ResourceLocation("end_gateway")); - map.put("TileEntityCommand", new ResourceLocation("command_block")); - map.put("TileEntityShulkerBox", new ResourceLocation("shulker_box")); - map.put("TileEntityBed", new ResourceLocation("bed")); - } - - private static ResourceLocation getKey(String type) { - final ResourceLocation key = OLD_ID_TO_KEY_MAP.get(type); - if (key == null) { - throw new IllegalArgumentException("Unknown mapping for " + type); - } - return key; - } - - private static void convertCompound(LegacyType type, net.minecraft.nbt.CompoundTag cmp, String key, int sourceVer, int targetVer) { - cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); - } - - private static void convertItem(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { - if (nbttagcompound.contains(key, 10)) { - convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); - } - } - - private static void convertItems(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { - if (nbttagcompound.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - } - - private static class DataConverterEquipment implements DataConverter { - - DataConverterEquipment() { - } - - public int getDataVersion() { - return 100; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Equipment", 10); - net.minecraft.nbt.ListTag nbttaglist1; - - if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); - cmp.put("HandItems", nbttaglist1); - } - - if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); - nbttaglist1.add(nbttaglist.get(1)); - nbttaglist1.add(nbttaglist.get(2)); - nbttaglist1.add(nbttaglist.get(3)); - nbttaglist1.add(nbttaglist.get(4)); - cmp.put("ArmorItems", nbttaglist1); - } - - cmp.remove("Equipment"); - if (cmp.contains("DropChances", 9)) { - nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; - - if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(0))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(0.0F)); - cmp.put("HandDropChances", nbttaglist2); - } - - if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new net.minecraft.nbt.ListTag(); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(1))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(2))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(3))); - nbttaglist2.add(net.minecraft.nbt.FloatTag.valueOf(nbttaglist1.getFloat(4))); - cmp.put("ArmorDropChances", nbttaglist2); - } - - cmp.remove("DropChances"); - } - - return cmp; - } - } - - private static class DataInspectorBlockEntity implements DataInspector { - - private static final Map b = Maps.newHashMap(); - private static final Map c = Maps.newHashMap(); - - DataInspectorBlockEntity() { - } - - @Nullable - private static String convertEntityId(int i, String s) { - String key = new ResourceLocation(s).toString(); - if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { - return DataInspectorBlockEntity.b.get(key); - } else { - return DataInspectorBlockEntity.c.get(key); - } - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (!cmp.contains("tag", 10)) { - return cmp; - } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - String s = cmp.getString("id"); - String s1 = convertEntityId(sourceVer, s); - boolean flag; - - if (s1 == null) { - // CraftBukkit - Remove unnecessary warning (occurs when deserializing a Shulker Box item) - // DataInspectorBlockEntity.a.warn("Unable to resolve BlockEntity for ItemInstance: {}", s); - flag = false; - } else { - flag = !nbttagcompound2.contains("id"); - nbttagcompound2.putString("id", s1); - } - - convert(LegacyType.BLOCK_ENTITY, nbttagcompound2, sourceVer, targetVer); - if (flag) { - nbttagcompound2.remove("id"); - } - } - - return cmp; - } - } - - static { - Map map = DataInspectorBlockEntity.b; - - map.put("minecraft:furnace", "Furnace"); - map.put("minecraft:lit_furnace", "Furnace"); - map.put("minecraft:chest", "Chest"); - map.put("minecraft:trapped_chest", "Chest"); - map.put("minecraft:ender_chest", "EnderChest"); - map.put("minecraft:jukebox", "RecordPlayer"); - map.put("minecraft:dispenser", "Trap"); - map.put("minecraft:dropper", "Dropper"); - map.put("minecraft:sign", "Sign"); - map.put("minecraft:mob_spawner", "MobSpawner"); - map.put("minecraft:noteblock", "Music"); - map.put("minecraft:brewing_stand", "Cauldron"); - map.put("minecraft:enhanting_table", "EnchantTable"); - map.put("minecraft:command_block", "CommandBlock"); - map.put("minecraft:beacon", "Beacon"); - map.put("minecraft:skull", "Skull"); - map.put("minecraft:daylight_detector", "DLDetector"); - map.put("minecraft:hopper", "Hopper"); - map.put("minecraft:banner", "Banner"); - map.put("minecraft:flower_pot", "FlowerPot"); - map.put("minecraft:repeating_command_block", "CommandBlock"); - map.put("minecraft:chain_command_block", "CommandBlock"); - map.put("minecraft:standing_sign", "Sign"); - map.put("minecraft:wall_sign", "Sign"); - map.put("minecraft:piston_head", "Piston"); - map.put("minecraft:daylight_detector_inverted", "DLDetector"); - map.put("minecraft:unpowered_comparator", "Comparator"); - map.put("minecraft:powered_comparator", "Comparator"); - map.put("minecraft:wall_banner", "Banner"); - map.put("minecraft:standing_banner", "Banner"); - map.put("minecraft:structure_block", "Structure"); - map.put("minecraft:end_portal", "Airportal"); - map.put("minecraft:end_gateway", "EndGateway"); - map.put("minecraft:shield", "Shield"); - map = DataInspectorBlockEntity.c; - map.put("minecraft:furnace", "minecraft:furnace"); - map.put("minecraft:lit_furnace", "minecraft:furnace"); - map.put("minecraft:chest", "minecraft:chest"); - map.put("minecraft:trapped_chest", "minecraft:chest"); - map.put("minecraft:ender_chest", "minecraft:enderchest"); - map.put("minecraft:jukebox", "minecraft:jukebox"); - map.put("minecraft:dispenser", "minecraft:dispenser"); - map.put("minecraft:dropper", "minecraft:dropper"); - map.put("minecraft:sign", "minecraft:sign"); - map.put("minecraft:mob_spawner", "minecraft:mob_spawner"); - map.put("minecraft:noteblock", "minecraft:noteblock"); - map.put("minecraft:brewing_stand", "minecraft:brewing_stand"); - map.put("minecraft:enhanting_table", "minecraft:enchanting_table"); - map.put("minecraft:command_block", "minecraft:command_block"); - map.put("minecraft:beacon", "minecraft:beacon"); - map.put("minecraft:skull", "minecraft:skull"); - map.put("minecraft:daylight_detector", "minecraft:daylight_detector"); - map.put("minecraft:hopper", "minecraft:hopper"); - map.put("minecraft:banner", "minecraft:banner"); - map.put("minecraft:flower_pot", "minecraft:flower_pot"); - map.put("minecraft:repeating_command_block", "minecraft:command_block"); - map.put("minecraft:chain_command_block", "minecraft:command_block"); - map.put("minecraft:shulker_box", "minecraft:shulker_box"); - map.put("minecraft:white_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:orange_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:magenta_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:light_blue_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:yellow_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:lime_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:pink_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:gray_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:silver_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:cyan_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:purple_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:blue_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:brown_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:green_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:red_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:black_shulker_box", "minecraft:shulker_box"); - map.put("minecraft:bed", "minecraft:bed"); - map.put("minecraft:standing_sign", "minecraft:sign"); - map.put("minecraft:wall_sign", "minecraft:sign"); - map.put("minecraft:piston_head", "minecraft:piston"); - map.put("minecraft:daylight_detector_inverted", "minecraft:daylight_detector"); - map.put("minecraft:unpowered_comparator", "minecraft:comparator"); - map.put("minecraft:powered_comparator", "minecraft:comparator"); - map.put("minecraft:wall_banner", "minecraft:banner"); - map.put("minecraft:standing_banner", "minecraft:banner"); - map.put("minecraft:structure_block", "minecraft:structure_block"); - map.put("minecraft:end_portal", "minecraft:end_portal"); - map.put("minecraft:end_gateway", "minecraft:end_gateway"); - map.put("minecraft:shield", "minecraft:shield"); - } - } - - private static class DataInspectorEntity implements DataInspector { - - DataInspectorEntity() { - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("EntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); - String s = cmp.getString("id"); - String s1; - - if ("minecraft:armor_stand".equals(s)) { - s1 = sourceVer < 515 ? "ArmorStand" : "minecraft:armor_stand"; - } else { - if (!"minecraft:spawn_egg".equals(s)) { - return cmp; - } - - s1 = nbttagcompound2.getString("id"); - } - - boolean flag; - - flag = !nbttagcompound2.contains("id", 8); - nbttagcompound2.putString("id", s1); - - convert(LegacyType.ENTITY, nbttagcompound2, sourceVer, targetVer); - if (flag) { - nbttagcompound2.remove("id"); - } - } - - return cmp; - } - } - - - private abstract static class DataInspectorTagged implements DataInspector { - - private final ResourceLocation key; - - DataInspectorTagged(String type) { - this.key = getKey(type); - } - - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (this.key.equals(new ResourceLocation(cmp.getString("id")))) { - cmp = this.inspectChecked(cmp, sourceVer, targetVer); - } - - return cmp; - } - - abstract net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer); - } - - private static class DataInspectorItemList extends DataInspectorTagged { - - private final String[] keys; - - DataInspectorItemList(String oclass, String... astring) { - super(oclass); - this.keys = astring; - } - - net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { - for (String s : this.keys) { - PaperweightDataConverters.convertItems(nbttagcompound, s, sourceVer, targetVer); - } - - return nbttagcompound; - } - } - - private static class DataInspectorItem extends DataInspectorTagged { - - private final String[] keys; - - DataInspectorItem(String oclass, String... astring) { - super(oclass); - this.keys = astring; - } - - net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { - for (String key : this.keys) { - PaperweightDataConverters.convertItem(nbttagcompound, key, sourceVer, targetVer); - } - - return nbttagcompound; - } - } - - private static class DataConverterMaterialId implements DataConverter { - - private static final String[] materials = new String[2268]; - - DataConverterMaterialId() { - } - - public int getDataVersion() { - return 102; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if (cmp.contains("id", 99)) { - short short0 = cmp.getShort("id"); - - if (short0 > 0 && short0 < materials.length && materials[short0] != null) { - cmp.putString("id", materials[short0]); - } - } - - return cmp; - } - - static { - materials[1] = "minecraft:stone"; - materials[2] = "minecraft:grass"; - materials[3] = "minecraft:dirt"; - materials[4] = "minecraft:cobblestone"; - materials[5] = "minecraft:planks"; - materials[6] = "minecraft:sapling"; - materials[7] = "minecraft:bedrock"; - materials[8] = "minecraft:flowing_water"; - materials[9] = "minecraft:water"; - materials[10] = "minecraft:flowing_lava"; - materials[11] = "minecraft:lava"; - materials[12] = "minecraft:sand"; - materials[13] = "minecraft:gravel"; - materials[14] = "minecraft:gold_ore"; - materials[15] = "minecraft:iron_ore"; - materials[16] = "minecraft:coal_ore"; - materials[17] = "minecraft:log"; - materials[18] = "minecraft:leaves"; - materials[19] = "minecraft:sponge"; - materials[20] = "minecraft:glass"; - materials[21] = "minecraft:lapis_ore"; - materials[22] = "minecraft:lapis_block"; - materials[23] = "minecraft:dispenser"; - materials[24] = "minecraft:sandstone"; - materials[25] = "minecraft:noteblock"; - materials[27] = "minecraft:golden_rail"; - materials[28] = "minecraft:detector_rail"; - materials[29] = "minecraft:sticky_piston"; - materials[30] = "minecraft:web"; - materials[31] = "minecraft:tallgrass"; - materials[32] = "minecraft:deadbush"; - materials[33] = "minecraft:piston"; - materials[35] = "minecraft:wool"; - materials[37] = "minecraft:yellow_flower"; - materials[38] = "minecraft:red_flower"; - materials[39] = "minecraft:brown_mushroom"; - materials[40] = "minecraft:red_mushroom"; - materials[41] = "minecraft:gold_block"; - materials[42] = "minecraft:iron_block"; - materials[43] = "minecraft:double_stone_slab"; - materials[44] = "minecraft:stone_slab"; - materials[45] = "minecraft:brick_block"; - materials[46] = "minecraft:tnt"; - materials[47] = "minecraft:bookshelf"; - materials[48] = "minecraft:mossy_cobblestone"; - materials[49] = "minecraft:obsidian"; - materials[50] = "minecraft:torch"; - materials[51] = "minecraft:fire"; - materials[52] = "minecraft:mob_spawner"; - materials[53] = "minecraft:oak_stairs"; - materials[54] = "minecraft:chest"; - materials[56] = "minecraft:diamond_ore"; - materials[57] = "minecraft:diamond_block"; - materials[58] = "minecraft:crafting_table"; - materials[60] = "minecraft:farmland"; - materials[61] = "minecraft:furnace"; - materials[62] = "minecraft:lit_furnace"; - materials[65] = "minecraft:ladder"; - materials[66] = "minecraft:rail"; - materials[67] = "minecraft:stone_stairs"; - materials[69] = "minecraft:lever"; - materials[70] = "minecraft:stone_pressure_plate"; - materials[72] = "minecraft:wooden_pressure_plate"; - materials[73] = "minecraft:redstone_ore"; - materials[76] = "minecraft:redstone_torch"; - materials[77] = "minecraft:stone_button"; - materials[78] = "minecraft:snow_layer"; - materials[79] = "minecraft:ice"; - materials[80] = "minecraft:snow"; - materials[81] = "minecraft:cactus"; - materials[82] = "minecraft:clay"; - materials[84] = "minecraft:jukebox"; - materials[85] = "minecraft:fence"; - materials[86] = "minecraft:pumpkin"; - materials[87] = "minecraft:netherrack"; - materials[88] = "minecraft:soul_sand"; - materials[89] = "minecraft:glowstone"; - materials[90] = "minecraft:portal"; - materials[91] = "minecraft:lit_pumpkin"; - materials[95] = "minecraft:stained_glass"; - materials[96] = "minecraft:trapdoor"; - materials[97] = "minecraft:monster_egg"; - materials[98] = "minecraft:stonebrick"; - materials[99] = "minecraft:brown_mushroom_block"; - materials[100] = "minecraft:red_mushroom_block"; - materials[101] = "minecraft:iron_bars"; - materials[102] = "minecraft:glass_pane"; - materials[103] = "minecraft:melon_block"; - materials[106] = "minecraft:vine"; - materials[107] = "minecraft:fence_gate"; - materials[108] = "minecraft:brick_stairs"; - materials[109] = "minecraft:stone_brick_stairs"; - materials[110] = "minecraft:mycelium"; - materials[111] = "minecraft:waterlily"; - materials[112] = "minecraft:nether_brick"; - materials[113] = "minecraft:nether_brick_fence"; - materials[114] = "minecraft:nether_brick_stairs"; - materials[116] = "minecraft:enchanting_table"; - materials[119] = "minecraft:end_portal"; - materials[120] = "minecraft:end_portal_frame"; - materials[121] = "minecraft:end_stone"; - materials[122] = "minecraft:dragon_egg"; - materials[123] = "minecraft:redstone_lamp"; - materials[125] = "minecraft:double_wooden_slab"; - materials[126] = "minecraft:wooden_slab"; - materials[127] = "minecraft:cocoa"; - materials[128] = "minecraft:sandstone_stairs"; - materials[129] = "minecraft:emerald_ore"; - materials[130] = "minecraft:ender_chest"; - materials[131] = "minecraft:tripwire_hook"; - materials[133] = "minecraft:emerald_block"; - materials[134] = "minecraft:spruce_stairs"; - materials[135] = "minecraft:birch_stairs"; - materials[136] = "minecraft:jungle_stairs"; - materials[137] = "minecraft:command_block"; - materials[138] = "minecraft:beacon"; - materials[139] = "minecraft:cobblestone_wall"; - materials[141] = "minecraft:carrots"; - materials[142] = "minecraft:potatoes"; - materials[143] = "minecraft:wooden_button"; - materials[145] = "minecraft:anvil"; - materials[146] = "minecraft:trapped_chest"; - materials[147] = "minecraft:light_weighted_pressure_plate"; - materials[148] = "minecraft:heavy_weighted_pressure_plate"; - materials[151] = "minecraft:daylight_detector"; - materials[152] = "minecraft:redstone_block"; - materials[153] = "minecraft:quartz_ore"; - materials[154] = "minecraft:hopper"; - materials[155] = "minecraft:quartz_block"; - materials[156] = "minecraft:quartz_stairs"; - materials[157] = "minecraft:activator_rail"; - materials[158] = "minecraft:dropper"; - materials[159] = "minecraft:stained_hardened_clay"; - materials[160] = "minecraft:stained_glass_pane"; - materials[161] = "minecraft:leaves2"; - materials[162] = "minecraft:log2"; - materials[163] = "minecraft:acacia_stairs"; - materials[164] = "minecraft:dark_oak_stairs"; - materials[170] = "minecraft:hay_block"; - materials[171] = "minecraft:carpet"; - materials[172] = "minecraft:hardened_clay"; - materials[173] = "minecraft:coal_block"; - materials[174] = "minecraft:packed_ice"; - materials[175] = "minecraft:double_plant"; - materials[256] = "minecraft:iron_shovel"; - materials[257] = "minecraft:iron_pickaxe"; - materials[258] = "minecraft:iron_axe"; - materials[259] = "minecraft:flint_and_steel"; - materials[260] = "minecraft:apple"; - materials[261] = "minecraft:bow"; - materials[262] = "minecraft:arrow"; - materials[263] = "minecraft:coal"; - materials[264] = "minecraft:diamond"; - materials[265] = "minecraft:iron_ingot"; - materials[266] = "minecraft:gold_ingot"; - materials[267] = "minecraft:iron_sword"; - materials[268] = "minecraft:wooden_sword"; - materials[269] = "minecraft:wooden_shovel"; - materials[270] = "minecraft:wooden_pickaxe"; - materials[271] = "minecraft:wooden_axe"; - materials[272] = "minecraft:stone_sword"; - materials[273] = "minecraft:stone_shovel"; - materials[274] = "minecraft:stone_pickaxe"; - materials[275] = "minecraft:stone_axe"; - materials[276] = "minecraft:diamond_sword"; - materials[277] = "minecraft:diamond_shovel"; - materials[278] = "minecraft:diamond_pickaxe"; - materials[279] = "minecraft:diamond_axe"; - materials[280] = "minecraft:stick"; - materials[281] = "minecraft:bowl"; - materials[282] = "minecraft:mushroom_stew"; - materials[283] = "minecraft:golden_sword"; - materials[284] = "minecraft:golden_shovel"; - materials[285] = "minecraft:golden_pickaxe"; - materials[286] = "minecraft:golden_axe"; - materials[287] = "minecraft:string"; - materials[288] = "minecraft:feather"; - materials[289] = "minecraft:gunpowder"; - materials[290] = "minecraft:wooden_hoe"; - materials[291] = "minecraft:stone_hoe"; - materials[292] = "minecraft:iron_hoe"; - materials[293] = "minecraft:diamond_hoe"; - materials[294] = "minecraft:golden_hoe"; - materials[295] = "minecraft:wheat_seeds"; - materials[296] = "minecraft:wheat"; - materials[297] = "minecraft:bread"; - materials[298] = "minecraft:leather_helmet"; - materials[299] = "minecraft:leather_chestplate"; - materials[300] = "minecraft:leather_leggings"; - materials[301] = "minecraft:leather_boots"; - materials[302] = "minecraft:chainmail_helmet"; - materials[303] = "minecraft:chainmail_chestplate"; - materials[304] = "minecraft:chainmail_leggings"; - materials[305] = "minecraft:chainmail_boots"; - materials[306] = "minecraft:iron_helmet"; - materials[307] = "minecraft:iron_chestplate"; - materials[308] = "minecraft:iron_leggings"; - materials[309] = "minecraft:iron_boots"; - materials[310] = "minecraft:diamond_helmet"; - materials[311] = "minecraft:diamond_chestplate"; - materials[312] = "minecraft:diamond_leggings"; - materials[313] = "minecraft:diamond_boots"; - materials[314] = "minecraft:golden_helmet"; - materials[315] = "minecraft:golden_chestplate"; - materials[316] = "minecraft:golden_leggings"; - materials[317] = "minecraft:golden_boots"; - materials[318] = "minecraft:flint"; - materials[319] = "minecraft:porkchop"; - materials[320] = "minecraft:cooked_porkchop"; - materials[321] = "minecraft:painting"; - materials[322] = "minecraft:golden_apple"; - materials[323] = "minecraft:sign"; - materials[324] = "minecraft:wooden_door"; - materials[325] = "minecraft:bucket"; - materials[326] = "minecraft:water_bucket"; - materials[327] = "minecraft:lava_bucket"; - materials[328] = "minecraft:minecart"; - materials[329] = "minecraft:saddle"; - materials[330] = "minecraft:iron_door"; - materials[331] = "minecraft:redstone"; - materials[332] = "minecraft:snowball"; - materials[333] = "minecraft:boat"; - materials[334] = "minecraft:leather"; - materials[335] = "minecraft:milk_bucket"; - materials[336] = "minecraft:brick"; - materials[337] = "minecraft:clay_ball"; - materials[338] = "minecraft:reeds"; - materials[339] = "minecraft:paper"; - materials[340] = "minecraft:book"; - materials[341] = "minecraft:slime_ball"; - materials[342] = "minecraft:chest_minecart"; - materials[343] = "minecraft:furnace_minecart"; - materials[344] = "minecraft:egg"; - materials[345] = "minecraft:compass"; - materials[346] = "minecraft:fishing_rod"; - materials[347] = "minecraft:clock"; - materials[348] = "minecraft:glowstone_dust"; - materials[349] = "minecraft:fish"; - materials[350] = "minecraft:cooked_fish"; // Paper - cooked_fished -> cooked_fish - materials[351] = "minecraft:dye"; - materials[352] = "minecraft:bone"; - materials[353] = "minecraft:sugar"; - materials[354] = "minecraft:cake"; - materials[355] = "minecraft:bed"; - materials[356] = "minecraft:repeater"; - materials[357] = "minecraft:cookie"; - materials[358] = "minecraft:filled_map"; - materials[359] = "minecraft:shears"; - materials[360] = "minecraft:melon"; - materials[361] = "minecraft:pumpkin_seeds"; - materials[362] = "minecraft:melon_seeds"; - materials[363] = "minecraft:beef"; - materials[364] = "minecraft:cooked_beef"; - materials[365] = "minecraft:chicken"; - materials[366] = "minecraft:cooked_chicken"; - materials[367] = "minecraft:rotten_flesh"; - materials[368] = "minecraft:ender_pearl"; - materials[369] = "minecraft:blaze_rod"; - materials[370] = "minecraft:ghast_tear"; - materials[371] = "minecraft:gold_nugget"; - materials[372] = "minecraft:nether_wart"; - materials[373] = "minecraft:potion"; - materials[374] = "minecraft:glass_bottle"; - materials[375] = "minecraft:spider_eye"; - materials[376] = "minecraft:fermented_spider_eye"; - materials[377] = "minecraft:blaze_powder"; - materials[378] = "minecraft:magma_cream"; - materials[379] = "minecraft:brewing_stand"; - materials[380] = "minecraft:cauldron"; - materials[381] = "minecraft:ender_eye"; - materials[382] = "minecraft:speckled_melon"; - materials[383] = "minecraft:spawn_egg"; - materials[384] = "minecraft:experience_bottle"; - materials[385] = "minecraft:fire_charge"; - materials[386] = "minecraft:writable_book"; - materials[387] = "minecraft:written_book"; - materials[388] = "minecraft:emerald"; - materials[389] = "minecraft:item_frame"; - materials[390] = "minecraft:flower_pot"; - materials[391] = "minecraft:carrot"; - materials[392] = "minecraft:potato"; - materials[393] = "minecraft:baked_potato"; - materials[394] = "minecraft:poisonous_potato"; - materials[395] = "minecraft:map"; - materials[396] = "minecraft:golden_carrot"; - materials[397] = "minecraft:skull"; - materials[398] = "minecraft:carrot_on_a_stick"; - materials[399] = "minecraft:nether_star"; - materials[400] = "minecraft:pumpkin_pie"; - materials[401] = "minecraft:fireworks"; - materials[402] = "minecraft:firework_charge"; - materials[403] = "minecraft:enchanted_book"; - materials[404] = "minecraft:comparator"; - materials[405] = "minecraft:netherbrick"; - materials[406] = "minecraft:quartz"; - materials[407] = "minecraft:tnt_minecart"; - materials[408] = "minecraft:hopper_minecart"; - materials[417] = "minecraft:iron_horse_armor"; - materials[418] = "minecraft:golden_horse_armor"; - materials[419] = "minecraft:diamond_horse_armor"; - materials[420] = "minecraft:lead"; - materials[421] = "minecraft:name_tag"; - materials[422] = "minecraft:command_block_minecart"; - materials[2256] = "minecraft:record_13"; - materials[2257] = "minecraft:record_cat"; - materials[2258] = "minecraft:record_blocks"; - materials[2259] = "minecraft:record_chirp"; - materials[2260] = "minecraft:record_far"; - materials[2261] = "minecraft:record_mall"; - materials[2262] = "minecraft:record_mellohi"; - materials[2263] = "minecraft:record_stal"; - materials[2264] = "minecraft:record_strad"; - materials[2265] = "minecraft:record_ward"; - materials[2266] = "minecraft:record_11"; - materials[2267] = "minecraft:record_wait"; - // Paper start - materials[409] = "minecraft:prismarine_shard"; - materials[410] = "minecraft:prismarine_crystals"; - materials[411] = "minecraft:rabbit"; - materials[412] = "minecraft:cooked_rabbit"; - materials[413] = "minecraft:rabbit_stew"; - materials[414] = "minecraft:rabbit_foot"; - materials[415] = "minecraft:rabbit_hide"; - materials[416] = "minecraft:armor_stand"; - materials[423] = "minecraft:mutton"; - materials[424] = "minecraft:cooked_mutton"; - materials[425] = "minecraft:banner"; - materials[426] = "minecraft:end_crystal"; - materials[427] = "minecraft:spruce_door"; - materials[428] = "minecraft:birch_door"; - materials[429] = "minecraft:jungle_door"; - materials[430] = "minecraft:acacia_door"; - materials[431] = "minecraft:dark_oak_door"; - materials[432] = "minecraft:chorus_fruit"; - materials[433] = "minecraft:chorus_fruit_popped"; - materials[434] = "minecraft:beetroot"; - materials[435] = "minecraft:beetroot_seeds"; - materials[436] = "minecraft:beetroot_soup"; - materials[437] = "minecraft:dragon_breath"; - materials[438] = "minecraft:splash_potion"; - materials[439] = "minecraft:spectral_arrow"; - materials[440] = "minecraft:tipped_arrow"; - materials[441] = "minecraft:lingering_potion"; - materials[442] = "minecraft:shield"; - materials[443] = "minecraft:elytra"; - materials[444] = "minecraft:spruce_boat"; - materials[445] = "minecraft:birch_boat"; - materials[446] = "minecraft:jungle_boat"; - materials[447] = "minecraft:acacia_boat"; - materials[448] = "minecraft:dark_oak_boat"; - materials[449] = "minecraft:totem_of_undying"; - materials[450] = "minecraft:shulker_shell"; - materials[452] = "minecraft:iron_nugget"; - materials[453] = "minecraft:knowledge_book"; - // Paper end - } - } - - private static class DataConverterArmorStand implements DataConverter { - - DataConverterArmorStand() { - } - - public int getDataVersion() { - return 147; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { - cmp.remove("Silent"); - } - - return cmp; - } - } - - private static class DataConverterBanner implements DataConverter { - - DataConverterBanner() { - } - - public int getDataVersion() { - return 804; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.contains("Base", 99)) { - cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); - if (nbttagcompound1.contains("display", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); - - if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound3.getList("Lore", 8); - - if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { - return cmp; - } - } - } - - nbttagcompound2.remove("Base"); - if (nbttagcompound2.isEmpty()) { - nbttagcompound1.remove("BlockEntityTag"); - } - - if (nbttagcompound1.isEmpty()) { - cmp.remove("tag"); - } - } - } - } - - return cmp; - } - } - - private static class DataConverterPotionId implements DataConverter { - - private static final String[] potions = new String[128]; - - DataConverterPotionId() { - } - - public int getDataVersion() { - return 102; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:potion".equals(cmp.getString("id"))) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - short short0 = cmp.getShort("Damage"); - - if (!nbttagcompound1.contains("Potion", 8)) { - String s = DataConverterPotionId.potions[short0 & 127]; - - nbttagcompound1.putString("Potion", s == null ? "minecraft:water" : s); - cmp.put("tag", nbttagcompound1); - if ((short0 & 16384) == 16384) { - cmp.putString("id", "minecraft:splash_potion"); - } - } - - if (short0 != 0) { - cmp.putShort("Damage", (short) 0); - } - } - - return cmp; - } - - static { - DataConverterPotionId.potions[0] = "minecraft:water"; - DataConverterPotionId.potions[1] = "minecraft:regeneration"; - DataConverterPotionId.potions[2] = "minecraft:swiftness"; - DataConverterPotionId.potions[3] = "minecraft:fire_resistance"; - DataConverterPotionId.potions[4] = "minecraft:poison"; - DataConverterPotionId.potions[5] = "minecraft:healing"; - DataConverterPotionId.potions[6] = "minecraft:night_vision"; - DataConverterPotionId.potions[7] = null; - DataConverterPotionId.potions[8] = "minecraft:weakness"; - DataConverterPotionId.potions[9] = "minecraft:strength"; - DataConverterPotionId.potions[10] = "minecraft:slowness"; - DataConverterPotionId.potions[11] = "minecraft:leaping"; - DataConverterPotionId.potions[12] = "minecraft:harming"; - DataConverterPotionId.potions[13] = "minecraft:water_breathing"; - DataConverterPotionId.potions[14] = "minecraft:invisibility"; - DataConverterPotionId.potions[15] = null; - DataConverterPotionId.potions[16] = "minecraft:awkward"; - DataConverterPotionId.potions[17] = "minecraft:regeneration"; - DataConverterPotionId.potions[18] = "minecraft:swiftness"; - DataConverterPotionId.potions[19] = "minecraft:fire_resistance"; - DataConverterPotionId.potions[20] = "minecraft:poison"; - DataConverterPotionId.potions[21] = "minecraft:healing"; - DataConverterPotionId.potions[22] = "minecraft:night_vision"; - DataConverterPotionId.potions[23] = null; - DataConverterPotionId.potions[24] = "minecraft:weakness"; - DataConverterPotionId.potions[25] = "minecraft:strength"; - DataConverterPotionId.potions[26] = "minecraft:slowness"; - DataConverterPotionId.potions[27] = "minecraft:leaping"; - DataConverterPotionId.potions[28] = "minecraft:harming"; - DataConverterPotionId.potions[29] = "minecraft:water_breathing"; - DataConverterPotionId.potions[30] = "minecraft:invisibility"; - DataConverterPotionId.potions[31] = null; - DataConverterPotionId.potions[32] = "minecraft:thick"; - DataConverterPotionId.potions[33] = "minecraft:strong_regeneration"; - DataConverterPotionId.potions[34] = "minecraft:strong_swiftness"; - DataConverterPotionId.potions[35] = "minecraft:fire_resistance"; - DataConverterPotionId.potions[36] = "minecraft:strong_poison"; - DataConverterPotionId.potions[37] = "minecraft:strong_healing"; - DataConverterPotionId.potions[38] = "minecraft:night_vision"; - DataConverterPotionId.potions[39] = null; - DataConverterPotionId.potions[40] = "minecraft:weakness"; - DataConverterPotionId.potions[41] = "minecraft:strong_strength"; - DataConverterPotionId.potions[42] = "minecraft:slowness"; - DataConverterPotionId.potions[43] = "minecraft:strong_leaping"; - DataConverterPotionId.potions[44] = "minecraft:strong_harming"; - DataConverterPotionId.potions[45] = "minecraft:water_breathing"; - DataConverterPotionId.potions[46] = "minecraft:invisibility"; - DataConverterPotionId.potions[47] = null; - DataConverterPotionId.potions[48] = null; - DataConverterPotionId.potions[49] = "minecraft:strong_regeneration"; - DataConverterPotionId.potions[50] = "minecraft:strong_swiftness"; - DataConverterPotionId.potions[51] = "minecraft:fire_resistance"; - DataConverterPotionId.potions[52] = "minecraft:strong_poison"; - DataConverterPotionId.potions[53] = "minecraft:strong_healing"; - DataConverterPotionId.potions[54] = "minecraft:night_vision"; - DataConverterPotionId.potions[55] = null; - DataConverterPotionId.potions[56] = "minecraft:weakness"; - DataConverterPotionId.potions[57] = "minecraft:strong_strength"; - DataConverterPotionId.potions[58] = "minecraft:slowness"; - DataConverterPotionId.potions[59] = "minecraft:strong_leaping"; - DataConverterPotionId.potions[60] = "minecraft:strong_harming"; - DataConverterPotionId.potions[61] = "minecraft:water_breathing"; - DataConverterPotionId.potions[62] = "minecraft:invisibility"; - DataConverterPotionId.potions[63] = null; - DataConverterPotionId.potions[64] = "minecraft:mundane"; - DataConverterPotionId.potions[65] = "minecraft:long_regeneration"; - DataConverterPotionId.potions[66] = "minecraft:long_swiftness"; - DataConverterPotionId.potions[67] = "minecraft:long_fire_resistance"; - DataConverterPotionId.potions[68] = "minecraft:long_poison"; - DataConverterPotionId.potions[69] = "minecraft:healing"; - DataConverterPotionId.potions[70] = "minecraft:long_night_vision"; - DataConverterPotionId.potions[71] = null; - DataConverterPotionId.potions[72] = "minecraft:long_weakness"; - DataConverterPotionId.potions[73] = "minecraft:long_strength"; - DataConverterPotionId.potions[74] = "minecraft:long_slowness"; - DataConverterPotionId.potions[75] = "minecraft:long_leaping"; - DataConverterPotionId.potions[76] = "minecraft:harming"; - DataConverterPotionId.potions[77] = "minecraft:long_water_breathing"; - DataConverterPotionId.potions[78] = "minecraft:long_invisibility"; - DataConverterPotionId.potions[79] = null; - DataConverterPotionId.potions[80] = "minecraft:awkward"; - DataConverterPotionId.potions[81] = "minecraft:long_regeneration"; - DataConverterPotionId.potions[82] = "minecraft:long_swiftness"; - DataConverterPotionId.potions[83] = "minecraft:long_fire_resistance"; - DataConverterPotionId.potions[84] = "minecraft:long_poison"; - DataConverterPotionId.potions[85] = "minecraft:healing"; - DataConverterPotionId.potions[86] = "minecraft:long_night_vision"; - DataConverterPotionId.potions[87] = null; - DataConverterPotionId.potions[88] = "minecraft:long_weakness"; - DataConverterPotionId.potions[89] = "minecraft:long_strength"; - DataConverterPotionId.potions[90] = "minecraft:long_slowness"; - DataConverterPotionId.potions[91] = "minecraft:long_leaping"; - DataConverterPotionId.potions[92] = "minecraft:harming"; - DataConverterPotionId.potions[93] = "minecraft:long_water_breathing"; - DataConverterPotionId.potions[94] = "minecraft:long_invisibility"; - DataConverterPotionId.potions[95] = null; - DataConverterPotionId.potions[96] = "minecraft:thick"; - DataConverterPotionId.potions[97] = "minecraft:regeneration"; - DataConverterPotionId.potions[98] = "minecraft:swiftness"; - DataConverterPotionId.potions[99] = "minecraft:long_fire_resistance"; - DataConverterPotionId.potions[100] = "minecraft:poison"; - DataConverterPotionId.potions[101] = "minecraft:strong_healing"; - DataConverterPotionId.potions[102] = "minecraft:long_night_vision"; - DataConverterPotionId.potions[103] = null; - DataConverterPotionId.potions[104] = "minecraft:long_weakness"; - DataConverterPotionId.potions[105] = "minecraft:strength"; - DataConverterPotionId.potions[106] = "minecraft:long_slowness"; - DataConverterPotionId.potions[107] = "minecraft:leaping"; - DataConverterPotionId.potions[108] = "minecraft:strong_harming"; - DataConverterPotionId.potions[109] = "minecraft:long_water_breathing"; - DataConverterPotionId.potions[110] = "minecraft:long_invisibility"; - DataConverterPotionId.potions[111] = null; - DataConverterPotionId.potions[112] = null; - DataConverterPotionId.potions[113] = "minecraft:regeneration"; - DataConverterPotionId.potions[114] = "minecraft:swiftness"; - DataConverterPotionId.potions[115] = "minecraft:long_fire_resistance"; - DataConverterPotionId.potions[116] = "minecraft:poison"; - DataConverterPotionId.potions[117] = "minecraft:strong_healing"; - DataConverterPotionId.potions[118] = "minecraft:long_night_vision"; - DataConverterPotionId.potions[119] = null; - DataConverterPotionId.potions[120] = "minecraft:long_weakness"; - DataConverterPotionId.potions[121] = "minecraft:strength"; - DataConverterPotionId.potions[122] = "minecraft:long_slowness"; - DataConverterPotionId.potions[123] = "minecraft:leaping"; - DataConverterPotionId.potions[124] = "minecraft:strong_harming"; - DataConverterPotionId.potions[125] = "minecraft:long_water_breathing"; - DataConverterPotionId.potions[126] = "minecraft:long_invisibility"; - DataConverterPotionId.potions[127] = null; - } - } - - private static class DataConverterSpawnEgg implements DataConverter { - - private static final String[] eggs = new String[256]; - - DataConverterSpawnEgg() { - } - - public int getDataVersion() { - return 105; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); - short short0 = cmp.getShort("Damage"); - - if (!nbttagcompound2.contains("id", 8)) { - String s = DataConverterSpawnEgg.eggs[short0 & 255]; - - if (s != null) { - nbttagcompound2.putString("id", s); - nbttagcompound1.put("EntityTag", nbttagcompound2); - cmp.put("tag", nbttagcompound1); - } - } - - if (short0 != 0) { - cmp.putShort("Damage", (short) 0); - } - } - - return cmp; - } - - static { - - DataConverterSpawnEgg.eggs[1] = "Item"; - DataConverterSpawnEgg.eggs[2] = "XPOrb"; - DataConverterSpawnEgg.eggs[7] = "ThrownEgg"; - DataConverterSpawnEgg.eggs[8] = "LeashKnot"; - DataConverterSpawnEgg.eggs[9] = "Painting"; - DataConverterSpawnEgg.eggs[10] = "Arrow"; - DataConverterSpawnEgg.eggs[11] = "Snowball"; - DataConverterSpawnEgg.eggs[12] = "Fireball"; - DataConverterSpawnEgg.eggs[13] = "SmallFireball"; - DataConverterSpawnEgg.eggs[14] = "ThrownEnderpearl"; - DataConverterSpawnEgg.eggs[15] = "EyeOfEnderSignal"; - DataConverterSpawnEgg.eggs[16] = "ThrownPotion"; - DataConverterSpawnEgg.eggs[17] = "ThrownExpBottle"; - DataConverterSpawnEgg.eggs[18] = "ItemFrame"; - DataConverterSpawnEgg.eggs[19] = "WitherSkull"; - DataConverterSpawnEgg.eggs[20] = "PrimedTnt"; - DataConverterSpawnEgg.eggs[21] = "FallingSand"; - DataConverterSpawnEgg.eggs[22] = "FireworksRocketEntity"; - DataConverterSpawnEgg.eggs[23] = "TippedArrow"; - DataConverterSpawnEgg.eggs[24] = "SpectralArrow"; - DataConverterSpawnEgg.eggs[25] = "ShulkerBullet"; - DataConverterSpawnEgg.eggs[26] = "DragonFireball"; - DataConverterSpawnEgg.eggs[30] = "ArmorStand"; - DataConverterSpawnEgg.eggs[41] = "Boat"; - DataConverterSpawnEgg.eggs[42] = "MinecartRideable"; - DataConverterSpawnEgg.eggs[43] = "MinecartChest"; - DataConverterSpawnEgg.eggs[44] = "MinecartFurnace"; - DataConverterSpawnEgg.eggs[45] = "MinecartTNT"; - DataConverterSpawnEgg.eggs[46] = "MinecartHopper"; - DataConverterSpawnEgg.eggs[47] = "MinecartSpawner"; - DataConverterSpawnEgg.eggs[40] = "MinecartCommandBlock"; - DataConverterSpawnEgg.eggs[48] = "Mob"; - DataConverterSpawnEgg.eggs[49] = "Monster"; - DataConverterSpawnEgg.eggs[50] = "Creeper"; - DataConverterSpawnEgg.eggs[51] = "Skeleton"; - DataConverterSpawnEgg.eggs[52] = "Spider"; - DataConverterSpawnEgg.eggs[53] = "Giant"; - DataConverterSpawnEgg.eggs[54] = "Zombie"; - DataConverterSpawnEgg.eggs[55] = "Slime"; - DataConverterSpawnEgg.eggs[56] = "Ghast"; - DataConverterSpawnEgg.eggs[57] = "PigZombie"; - DataConverterSpawnEgg.eggs[58] = "Enderman"; - DataConverterSpawnEgg.eggs[59] = "CaveSpider"; - DataConverterSpawnEgg.eggs[60] = "Silverfish"; - DataConverterSpawnEgg.eggs[61] = "Blaze"; - DataConverterSpawnEgg.eggs[62] = "LavaSlime"; - DataConverterSpawnEgg.eggs[63] = "EnderDragon"; - DataConverterSpawnEgg.eggs[64] = "WitherBoss"; - DataConverterSpawnEgg.eggs[65] = "Bat"; - DataConverterSpawnEgg.eggs[66] = "Witch"; - DataConverterSpawnEgg.eggs[67] = "Endermite"; - DataConverterSpawnEgg.eggs[68] = "Guardian"; - DataConverterSpawnEgg.eggs[69] = "Shulker"; - DataConverterSpawnEgg.eggs[90] = "Pig"; - DataConverterSpawnEgg.eggs[91] = "Sheep"; - DataConverterSpawnEgg.eggs[92] = "Cow"; - DataConverterSpawnEgg.eggs[93] = "Chicken"; - DataConverterSpawnEgg.eggs[94] = "Squid"; - DataConverterSpawnEgg.eggs[95] = "Wolf"; - DataConverterSpawnEgg.eggs[96] = "MushroomCow"; - DataConverterSpawnEgg.eggs[97] = "SnowMan"; - DataConverterSpawnEgg.eggs[98] = "Ozelot"; - DataConverterSpawnEgg.eggs[99] = "VillagerGolem"; - DataConverterSpawnEgg.eggs[100] = "EntityHorse"; - DataConverterSpawnEgg.eggs[101] = "Rabbit"; - DataConverterSpawnEgg.eggs[120] = "Villager"; - DataConverterSpawnEgg.eggs[200] = "EnderCrystal"; - } - } - - private static class DataConverterMinecart implements DataConverter { - - private static final List a = Lists.newArrayList("MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"); - - DataConverterMinecart() { - } - - public int getDataVersion() { - return 106; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("Minecart".equals(cmp.getString("id"))) { - String s = "MinecartRideable"; - int i = cmp.getInt("Type"); - - if (i > 0 && i < DataConverterMinecart.a.size()) { - s = DataConverterMinecart.a.get(i); - } - - cmp.putString("id", s); - cmp.remove("Type"); - } - - return cmp; - } - } - - private static class DataConverterMobSpawner implements DataConverter { - - DataConverterMobSpawner() { - } - - public int getDataVersion() { - return 107; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if (!"MobSpawner".equals(cmp.getString("id"))) { - return cmp; - } else { - if (cmp.contains("EntityId", 8)) { - String s = cmp.getString("EntityId"); - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); - - nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); - cmp.put("SpawnData", nbttagcompound1); - cmp.remove("EntityId"); - } - - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); - - if (nbttagcompound2.contains("Type", 8)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound2.getCompound("Properties"); - - nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); - nbttagcompound2.put("Entity", nbttagcompound3); - nbttagcompound2.remove("Type"); - nbttagcompound2.remove("Properties"); - } - } - } - - return cmp; - } - } - } - - private static class DataConverterUUID implements DataConverter { - - DataConverterUUID() { - } - - public int getDataVersion() { - return 108; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if (cmp.contains("UUID", 8)) { - cmp.putUUID("UUID", UUID.fromString(cmp.getString("UUID"))); - } - - return cmp; - } - } - - private static class DataConverterHealth implements DataConverter { - - private static final Set a = Sets.newHashSet("ArmorStand", "Bat", "Blaze", "CaveSpider", "Chicken", "Cow", "Creeper", "EnderDragon", "Enderman", "Endermite", "EntityHorse", "Ghast", "Giant", "Guardian", "LavaSlime", "MushroomCow", "Ozelot", "Pig", "PigZombie", "Rabbit", "Sheep", "Shulker", "Silverfish", "Skeleton", "Slime", "SnowMan", "Spider", "Squid", "Villager", "VillagerGolem", "Witch", "WitherBoss", "Wolf", "Zombie"); - - DataConverterHealth() { - } - - public int getDataVersion() { - return 109; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if (DataConverterHealth.a.contains(cmp.getString("id"))) { - float f; - - if (cmp.contains("HealF", 99)) { - f = cmp.getFloat("HealF"); - cmp.remove("HealF"); - } else { - if (!cmp.contains("Health", 99)) { - return cmp; - } - - f = cmp.getFloat("Health"); - } - - cmp.putFloat("Health", f); - } - - return cmp; - } - } - - private static class DataConverterSaddle implements DataConverter { - - DataConverterSaddle() { - } - - public int getDataVersion() { - return 110; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound1.putString("id", "minecraft:saddle"); - nbttagcompound1.putByte("Count", (byte) 1); - nbttagcompound1.putShort("Damage", (short) 0); - cmp.put("SaddleItem", nbttagcompound1); - cmp.remove("Saddle"); - } - - return cmp; - } - } - - private static class DataConverterHanging implements DataConverter { - - DataConverterHanging() { - } - - public int getDataVersion() { - return 111; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - String s = cmp.getString("id"); - boolean flag = "Painting".equals(s); - boolean flag1 = "ItemFrame".equals(s); - - if ((flag || flag1) && !cmp.contains("Facing", 99)) { - Direction enumdirection; - - if (cmp.contains("Direction", 99)) { - enumdirection = Direction.from2DDataValue(cmp.getByte("Direction")); - cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getStepX()); - cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getStepY()); - cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getStepZ()); - cmp.remove("Direction"); - if (flag1 && cmp.contains("ItemRotation", 99)) { - cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); - } - } else { - enumdirection = Direction.from2DDataValue(cmp.getByte("Dir")); - cmp.remove("Dir"); - } - - cmp.putByte("Facing", (byte) enumdirection.get2DDataValue()); - } - - return cmp; - } - } - - private static class DataConverterDropChances implements DataConverter { - - DataConverterDropChances() { - } - - public int getDataVersion() { - return 113; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist; - - if (cmp.contains("HandDropChances", 9)) { - nbttaglist = cmp.getList("HandDropChances", 5); - if (nbttaglist.size() == 2 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F) { - cmp.remove("HandDropChances"); - } - } - - if (cmp.contains("ArmorDropChances", 9)) { - nbttaglist = cmp.getList("ArmorDropChances", 5); - if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat(2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) { - cmp.remove("ArmorDropChances"); - } - } - - return cmp; - } - } - - private static class DataConverterRiding implements DataConverter { - - DataConverterRiding() { - } - - public int getDataVersion() { - return 135; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - while (cmp.contains("Riding", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = this.b(cmp); - - this.convert(cmp, nbttagcompound1); - cmp = nbttagcompound1; - } - - return cmp; - } - - protected void convert(net.minecraft.nbt.CompoundTag nbttagcompound, net.minecraft.nbt.CompoundTag nbttagcompound1) { - net.minecraft.nbt.ListTag nbttaglist = new net.minecraft.nbt.ListTag(); - - nbttaglist.add(nbttagcompound); - nbttagcompound1.put("Passengers", nbttaglist); - } - - protected net.minecraft.nbt.CompoundTag b(net.minecraft.nbt.CompoundTag nbttagcompound) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); - - nbttagcompound.remove("Riding"); - return nbttagcompound1; - } - } - - private static class DataConverterBook implements DataConverter { - - DataConverterBook() { - } - - public int getDataVersion() { - return 165; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:written_book".equals(cmp.getString("id"))) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); - - for (int i = 0; i < nbttaglist.size(); ++i) { - String s = nbttaglist.getString(i); - Component object = null; - - if (!"null".equals(s) && !StringUtil.isNullOrEmpty(s)) { - if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = Component.literal(s); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s); - } - } - } else { - object = Component.literal(""); - } - - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(object))); - } - - nbttagcompound1.put("pages", nbttaglist); - } - } - - return cmp; - } - } - - private static class DataConverterCookedFish implements DataConverter { - - private static final ResourceLocation a = new ResourceLocation("cooked_fished"); - - DataConverterCookedFish() { - } - - public int getDataVersion() { - return 502; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(new ResourceLocation(cmp.getString("id")))) { - cmp.putString("id", "minecraft:cooked_fish"); - } - - return cmp; - } - } - - private static class DataConverterZombie implements DataConverter { - - private static final Random a = new Random(); - - DataConverterZombie() { - } - - public int getDataVersion() { - return 502; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { - if (!cmp.contains("ZombieType", 99)) { - int i = -1; - - if (cmp.contains("VillagerProfession", 99)) { - try { - i = this.convert(cmp.getInt("VillagerProfession")); - } catch (RuntimeException runtimeexception) { - ; - } - } - - if (i == -1) { - i = this.convert(DataConverterZombie.a.nextInt(6)); - } - - cmp.putInt("ZombieType", i); - } - - cmp.remove("IsVillager"); - } - - return cmp; - } - - private int convert(int i) { - return i >= 0 && i < 6 ? i : -1; - } - } - - private static class DataConverterVBO implements DataConverter { - - DataConverterVBO() { - } - - public int getDataVersion() { - return 505; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - cmp.putString("useVbo", "true"); - return cmp; - } - } - - private static class DataConverterGuardian implements DataConverter { - - DataConverterGuardian() { - } - - public int getDataVersion() { - return 700; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("Guardian".equals(cmp.getString("id"))) { - if (cmp.getBoolean("Elder")) { - cmp.putString("id", "ElderGuardian"); - } - - cmp.remove("Elder"); - } - - return cmp; - } - } - - private static class DataConverterSkeleton implements DataConverter { - - DataConverterSkeleton() { - } - - public int getDataVersion() { - return 701; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - String s = cmp.getString("id"); - - if ("Skeleton".equals(s)) { - int i = cmp.getInt("SkeletonType"); - - if (i == 1) { - cmp.putString("id", "WitherSkeleton"); - } else if (i == 2) { - cmp.putString("id", "Stray"); - } - - cmp.remove("SkeletonType"); - } - - return cmp; - } - } - - private static class DataConverterZombieType implements DataConverter { - - DataConverterZombieType() { - } - - public int getDataVersion() { - return 702; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("Zombie".equals(cmp.getString("id"))) { - int i = cmp.getInt("ZombieType"); - - switch (i) { - case 0: - default: - break; - - case 1: - case 2: - case 3: - case 4: - case 5: - cmp.putString("id", "ZombieVillager"); - cmp.putInt("Profession", i - 1); - break; - - case 6: - cmp.putString("id", "Husk"); - } - - cmp.remove("ZombieType"); - } - - return cmp; - } - } - - private static class DataConverterHorse implements DataConverter { - - DataConverterHorse() { - } - - public int getDataVersion() { - return 703; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("EntityHorse".equals(cmp.getString("id"))) { - int i = cmp.getInt("Type"); - - switch (i) { - case 0: - default: - cmp.putString("id", "Horse"); - break; - - case 1: - cmp.putString("id", "Donkey"); - break; - - case 2: - cmp.putString("id", "Mule"); - break; - - case 3: - cmp.putString("id", "ZombieHorse"); - break; - - case 4: - cmp.putString("id", "SkeletonHorse"); - } - - cmp.remove("Type"); - } - - return cmp; - } - } - - private static class DataConverterTileEntity implements DataConverter { - - private static final Map a = Maps.newHashMap(); - - DataConverterTileEntity() { - } - - public int getDataVersion() { - return 704; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - String s = DataConverterTileEntity.a.get(cmp.getString("id")); - - if (s != null) { - cmp.putString("id", s); - } - - return cmp; - } - - static { - DataConverterTileEntity.a.put("Airportal", "minecraft:end_portal"); - DataConverterTileEntity.a.put("Banner", "minecraft:banner"); - DataConverterTileEntity.a.put("Beacon", "minecraft:beacon"); - DataConverterTileEntity.a.put("Cauldron", "minecraft:brewing_stand"); - DataConverterTileEntity.a.put("Chest", "minecraft:chest"); - DataConverterTileEntity.a.put("Comparator", "minecraft:comparator"); - DataConverterTileEntity.a.put("Control", "minecraft:command_block"); - DataConverterTileEntity.a.put("DLDetector", "minecraft:daylight_detector"); - DataConverterTileEntity.a.put("Dropper", "minecraft:dropper"); - DataConverterTileEntity.a.put("EnchantTable", "minecraft:enchanting_table"); - DataConverterTileEntity.a.put("EndGateway", "minecraft:end_gateway"); - DataConverterTileEntity.a.put("EnderChest", "minecraft:ender_chest"); - DataConverterTileEntity.a.put("FlowerPot", "minecraft:flower_pot"); - DataConverterTileEntity.a.put("Furnace", "minecraft:furnace"); - DataConverterTileEntity.a.put("Hopper", "minecraft:hopper"); - DataConverterTileEntity.a.put("MobSpawner", "minecraft:mob_spawner"); - DataConverterTileEntity.a.put("Music", "minecraft:noteblock"); - DataConverterTileEntity.a.put("Piston", "minecraft:piston"); - DataConverterTileEntity.a.put("RecordPlayer", "minecraft:jukebox"); - DataConverterTileEntity.a.put("Sign", "minecraft:sign"); - DataConverterTileEntity.a.put("Skull", "minecraft:skull"); - DataConverterTileEntity.a.put("Structure", "minecraft:structure_block"); - DataConverterTileEntity.a.put("Trap", "minecraft:dispenser"); - } - } - - private static class DataConverterEntity implements DataConverter { - - private static final Map a = Maps.newHashMap(); - - DataConverterEntity() { - } - - public int getDataVersion() { - return 704; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - String s = DataConverterEntity.a.get(cmp.getString("id")); - - if (s != null) { - cmp.putString("id", s); - } - - return cmp; - } - - static { - DataConverterEntity.a.put("AreaEffectCloud", "minecraft:area_effect_cloud"); - DataConverterEntity.a.put("ArmorStand", "minecraft:armor_stand"); - DataConverterEntity.a.put("Arrow", "minecraft:arrow"); - DataConverterEntity.a.put("Bat", "minecraft:bat"); - DataConverterEntity.a.put("Blaze", "minecraft:blaze"); - DataConverterEntity.a.put("Boat", "minecraft:boat"); - DataConverterEntity.a.put("CaveSpider", "minecraft:cave_spider"); - DataConverterEntity.a.put("Chicken", "minecraft:chicken"); - DataConverterEntity.a.put("Cow", "minecraft:cow"); - DataConverterEntity.a.put("Creeper", "minecraft:creeper"); - DataConverterEntity.a.put("Donkey", "minecraft:donkey"); - DataConverterEntity.a.put("DragonFireball", "minecraft:dragon_fireball"); - DataConverterEntity.a.put("ElderGuardian", "minecraft:elder_guardian"); - DataConverterEntity.a.put("EnderCrystal", "minecraft:ender_crystal"); - DataConverterEntity.a.put("EnderDragon", "minecraft:ender_dragon"); - DataConverterEntity.a.put("Enderman", "minecraft:enderman"); - DataConverterEntity.a.put("Endermite", "minecraft:endermite"); - DataConverterEntity.a.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); - DataConverterEntity.a.put("FallingSand", "minecraft:falling_block"); - DataConverterEntity.a.put("Fireball", "minecraft:fireball"); - DataConverterEntity.a.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); - DataConverterEntity.a.put("Ghast", "minecraft:ghast"); - DataConverterEntity.a.put("Giant", "minecraft:giant"); - DataConverterEntity.a.put("Guardian", "minecraft:guardian"); - DataConverterEntity.a.put("Horse", "minecraft:horse"); - DataConverterEntity.a.put("Husk", "minecraft:husk"); - DataConverterEntity.a.put("Item", "minecraft:item"); - DataConverterEntity.a.put("ItemFrame", "minecraft:item_frame"); - DataConverterEntity.a.put("LavaSlime", "minecraft:magma_cube"); - DataConverterEntity.a.put("LeashKnot", "minecraft:leash_knot"); - DataConverterEntity.a.put("MinecartChest", "minecraft:chest_minecart"); - DataConverterEntity.a.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); - DataConverterEntity.a.put("MinecartFurnace", "minecraft:furnace_minecart"); - DataConverterEntity.a.put("MinecartHopper", "minecraft:hopper_minecart"); - DataConverterEntity.a.put("MinecartRideable", "minecraft:minecart"); - DataConverterEntity.a.put("MinecartSpawner", "minecraft:spawner_minecart"); - DataConverterEntity.a.put("MinecartTNT", "minecraft:tnt_minecart"); - DataConverterEntity.a.put("Mule", "minecraft:mule"); - DataConverterEntity.a.put("MushroomCow", "minecraft:mooshroom"); - DataConverterEntity.a.put("Ozelot", "minecraft:ocelot"); - DataConverterEntity.a.put("Painting", "minecraft:painting"); - DataConverterEntity.a.put("Pig", "minecraft:pig"); - DataConverterEntity.a.put("PigZombie", "minecraft:zombie_pigman"); - DataConverterEntity.a.put("PolarBear", "minecraft:polar_bear"); - DataConverterEntity.a.put("PrimedTnt", "minecraft:tnt"); - DataConverterEntity.a.put("Rabbit", "minecraft:rabbit"); - DataConverterEntity.a.put("Sheep", "minecraft:sheep"); - DataConverterEntity.a.put("Shulker", "minecraft:shulker"); - DataConverterEntity.a.put("ShulkerBullet", "minecraft:shulker_bullet"); - DataConverterEntity.a.put("Silverfish", "minecraft:silverfish"); - DataConverterEntity.a.put("Skeleton", "minecraft:skeleton"); - DataConverterEntity.a.put("SkeletonHorse", "minecraft:skeleton_horse"); - DataConverterEntity.a.put("Slime", "minecraft:slime"); - DataConverterEntity.a.put("SmallFireball", "minecraft:small_fireball"); - DataConverterEntity.a.put("SnowMan", "minecraft:snowman"); - DataConverterEntity.a.put("Snowball", "minecraft:snowball"); - DataConverterEntity.a.put("SpectralArrow", "minecraft:spectral_arrow"); - DataConverterEntity.a.put("Spider", "minecraft:spider"); - DataConverterEntity.a.put("Squid", "minecraft:squid"); - DataConverterEntity.a.put("Stray", "minecraft:stray"); - DataConverterEntity.a.put("ThrownEgg", "minecraft:egg"); - DataConverterEntity.a.put("ThrownEnderpearl", "minecraft:ender_pearl"); - DataConverterEntity.a.put("ThrownExpBottle", "minecraft:xp_bottle"); - DataConverterEntity.a.put("ThrownPotion", "minecraft:potion"); - DataConverterEntity.a.put("Villager", "minecraft:villager"); - DataConverterEntity.a.put("VillagerGolem", "minecraft:villager_golem"); - DataConverterEntity.a.put("Witch", "minecraft:witch"); - DataConverterEntity.a.put("WitherBoss", "minecraft:wither"); - DataConverterEntity.a.put("WitherSkeleton", "minecraft:wither_skeleton"); - DataConverterEntity.a.put("WitherSkull", "minecraft:wither_skull"); - DataConverterEntity.a.put("Wolf", "minecraft:wolf"); - DataConverterEntity.a.put("XPOrb", "minecraft:xp_orb"); - DataConverterEntity.a.put("Zombie", "minecraft:zombie"); - DataConverterEntity.a.put("ZombieHorse", "minecraft:zombie_horse"); - DataConverterEntity.a.put("ZombieVillager", "minecraft:zombie_villager"); - } - } - - private static class DataConverterPotionWater implements DataConverter { - - DataConverterPotionWater() { - } - - public int getDataVersion() { - return 806; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - String s = cmp.getString("id"); - - if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals(s)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (!nbttagcompound1.contains("Potion", 8)) { - nbttagcompound1.putString("Potion", "minecraft:water"); - } - - if (!cmp.contains("tag", 10)) { - cmp.put("tag", nbttagcompound1); - } - } - - return cmp; - } - } - - private static class DataConverterShulker implements DataConverter { - - DataConverterShulker() { - } - - public int getDataVersion() { - return 808; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.contains("Color", 99)) { - cmp.putByte("Color", (byte) 10); - } - - return cmp; - } - } - - private static class DataConverterShulkerBoxItem implements DataConverter { - - public static final String[] a = new String[] { "minecraft:white_shulker_box", "minecraft:orange_shulker_box", "minecraft:magenta_shulker_box", "minecraft:light_blue_shulker_box", "minecraft:yellow_shulker_box", "minecraft:lime_shulker_box", "minecraft:pink_shulker_box", "minecraft:gray_shulker_box", "minecraft:silver_shulker_box", "minecraft:cyan_shulker_box", "minecraft:purple_shulker_box", "minecraft:blue_shulker_box", "minecraft:brown_shulker_box", "minecraft:green_shulker_box", "minecraft:red_shulker_box", "minecraft:black_shulker_box" }; - - DataConverterShulkerBoxItem() { - } - - public int getDataVersion() { - return 813; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); - - if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); - - if (nbttagcompound2.getList("Items", 10).isEmpty()) { - nbttagcompound2.remove("Items"); - } - - int i = nbttagcompound2.getInt("Color"); - - nbttagcompound2.remove("Color"); - if (nbttagcompound2.isEmpty()) { - nbttagcompound1.remove("BlockEntityTag"); - } - - if (nbttagcompound1.isEmpty()) { - cmp.remove("tag"); - } - - cmp.putString("id", DataConverterShulkerBoxItem.a[i % 16]); - } - } - - return cmp; - } - } - - private static class DataConverterShulkerBoxBlock implements DataConverter { - - DataConverterShulkerBoxBlock() { - } - - public int getDataVersion() { - return 813; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:shulker".equals(cmp.getString("id"))) { - cmp.remove("Color"); - } - - return cmp; - } - } - - private static class DataConverterLang implements DataConverter { - - DataConverterLang() { - } - - public int getDataVersion() { - return 816; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if (cmp.contains("lang", 8)) { - cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); - } - - return cmp; - } - } - - private static class DataConverterTotem implements DataConverter { - - DataConverterTotem() { - } - - public int getDataVersion() { - return 820; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:totem".equals(cmp.getString("id"))) { - cmp.putString("id", "minecraft:totem_of_undying"); - } - - return cmp; - } - } - - private static class DataConverterBedBlock implements DataConverter { - - private static final Logger a = LogManager.getLogger(PaperweightDataConverters.class); - - DataConverterBedBlock() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - int i = nbttagcompound1.getInt("xPos"); - int j = nbttagcompound1.getInt("zPos"); - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); - net.minecraft.nbt.ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); - - for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist1.getCompound(k); - byte b0 = nbttagcompound2.getByte("Y"); - byte[] abyte = nbttagcompound2.getByteArray("Blocks"); - - for (int l = 0; l < abyte.length; ++l) { - if (416 == (abyte[l] & 255) << 4) { - int i1 = l & 15; - int j1 = l >> 8 & 15; - int k1 = l >> 4 & 15; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); - - nbttagcompound3.putString("id", "bed"); - nbttagcompound3.putInt("x", i1 + (i << 4)); - nbttagcompound3.putInt("y", j1 + (b0 << 4)); - nbttagcompound3.putInt("z", k1 + (j << 4)); - nbttaglist.add(nbttagcompound3); - } - } - } - } catch (Exception exception) { - DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); - } - - return cmp; - } - } - - private static class DataConverterBedItem implements DataConverter { - - DataConverterBedItem() { - } - - public int getDataVersion() { - return 1125; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) DyeColor.RED.getId()); - } - - return cmp; - } - } - - private static class DataConverterSignText implements DataConverter { - - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - MutableComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { - if (jsonelement.isJsonPrimitive()) { - return Component.literal(jsonelement.getAsString()); - } else if (jsonelement.isJsonArray()) { - JsonArray jsonarray = jsonelement.getAsJsonArray(); - MutableComponent ichatbasecomponent = null; - Iterator iterator = jsonarray.iterator(); - - while (iterator.hasNext()) { - JsonElement jsonelement1 = (JsonElement) iterator.next(); - MutableComponent ichatbasecomponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); - - if (ichatbasecomponent == null) { - ichatbasecomponent = ichatbasecomponent1; - } else { - ichatbasecomponent.append(ichatbasecomponent1); - } - } - - return ichatbasecomponent; - } else { - throw new JsonParseException("Don't know how to turn " + jsonelement + " into a Component"); - } - } - - public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { - return this.a(jsonelement, type, jsondeserializationcontext); - } - }).create(); - - DataConverterSignText() { - } - - public int getDataVersion() { - return 101; - } - - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - if ("Sign".equals(cmp.getString("id"))) { - this.convert(cmp, "Text1"); - this.convert(cmp, "Text2"); - this.convert(cmp, "Text3"); - this.convert(cmp, "Text4"); - } - - return cmp; - } - - private void convert(net.minecraft.nbt.CompoundTag nbttagcompound, String s) { - String s1 = nbttagcompound.getString(s); - Component object = null; - - if (!"null".equals(s1) && !StringUtil.isNullOrEmpty(s1)) { - if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = Component.literal(s1); - } else { - try { - object = GsonHelper.fromJson(DataConverterSignText.a, s1, Component.class, true); - if (object == null) { - object = Component.literal(""); - } - } catch (JsonParseException jsonparseexception) { - ; - } - - if (object == null) { - try { - object = Component.Serializer.fromJson(s1); - } catch (JsonParseException jsonparseexception1) { - ; - } - } - - if (object == null) { - try { - object = Component.Serializer.fromJsonLenient(s1); - } catch (JsonParseException jsonparseexception2) { - ; - } - } - - if (object == null) { - object = Component.literal(s1); - } - } - } else { - object = Component.literal(""); - } - - nbttagcompound.putString(s, Component.Serializer.toJson(object)); - } - } - - private static class DataInspectorPlayerVehicle implements DataInspector { - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("RootVehicle"); - - if (nbttagcompound1.contains("Entity", 10)) { - convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); - } - } - - return cmp; - } - } - - private static class DataInspectorLevelPlayer implements DataInspector { - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Player", 10)) { - convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); - } - - return cmp; - } - } - - private static class DataInspectorStructure implements DataInspector { - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.ListTag nbttaglist; - int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; - - if (cmp.contains("entities", 9)) { - nbttaglist = cmp.getList("entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); - if (nbttagcompound1.contains("nbt", 10)) { - convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); - } - } - } - - if (cmp.contains("blocks", 9)) { - nbttaglist = cmp.getList("blocks", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); - if (nbttagcompound1.contains("nbt", 10)) { - convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); - } - } - } - - return cmp; - } - } - - private static class DataInspectorChunks implements DataInspector { - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag nbttaglist; - int j; - - if (nbttagcompound1.contains("Entities", 9)) { - nbttaglist = nbttagcompound1.getList("Entities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); - } - } - - if (nbttagcompound1.contains("TileEntities", 9)) { - nbttaglist = nbttagcompound1.getList("TileEntities", 10); - - for (j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); - } - } - } - - return cmp; - } - } - - private static class DataInspectorEntityPassengers implements DataInspector { - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (cmp.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Passengers", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ENTITY, nbttaglist.getCompound(j), sourceVer, targetVer)); - } - } - - return cmp; - } - } - - private static class DataInspectorPlayer implements DataInspector { - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - convertItems(cmp, "Inventory", sourceVer, targetVer); - convertItems(cmp, "EnderItems", sourceVer, targetVer); - if (cmp.contains("ShoulderEntityLeft", 10)) { - convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityLeft", sourceVer, targetVer); - } - - if (cmp.contains("ShoulderEntityRight", 10)) { - convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityRight", sourceVer, targetVer); - } - - return cmp; - } - } - - private static class DataInspectorVillagers implements DataInspector { - ResourceLocation entityVillager = getKey("EntityVillager"); - - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); - - if (nbttagcompound1.contains("Recipes", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); - - convertItem(nbttagcompound2, "buy", sourceVer, targetVer); - convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); - convertItem(nbttagcompound2, "sell", sourceVer, targetVer); - nbttaglist.set(j, nbttagcompound2); - } - } - } - - return cmp; - } - } - - private static class DataInspectorMobSpawnerMinecart implements DataInspector { - ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); - ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); - - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - String s = cmp.getString("id"); - if (entityMinecartMobSpawner.equals(new ResourceLocation(s))) { - cmp.putString("id", tileEntityMobSpawner.toString()); - convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); - cmp.putString("id", s); - } - - return cmp; - } - } - - private static class DataInspectorMobSpawnerMobs implements DataInspector { - ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); - - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { - if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); - - for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttaglist.getCompound(j); - - convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); - } - } - - convertCompound(LegacyType.ENTITY, cmp, "SpawnData", sourceVer, targetVer); - } - - return cmp; - } - } - - private static class DataInspectorCommandBlock implements DataInspector { - ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); - - @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - if (tileEntityCommand.equals(new ResourceLocation(cmp.getString("id")))) { - cmp.putString("id", "Control"); - convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); - cmp.putString("id", "MinecartCommandBlock"); - } - - return cmp; - } - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.java deleted file mode 100644 index ee7d82f09..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightFakePlayer.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; - -import com.mojang.authlib.GameProfile; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ServerboundClientInformationPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.stats.Stat; -import net.minecraft.world.MenuProvider; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.OptionalInt; -import java.util.UUID; - -class PaperweightFakePlayer extends ServerPlayer { - private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); - private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D); - - PaperweightFakePlayer(ServerLevel world) { - super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE); - } - - @Override - public Vec3 position() { - return ORIGIN; - } - - @Override - public void tick() { - } - - @Override - public void die(DamageSource damagesource) { - } - - @Override - public Entity changeDimension(ServerLevel worldserver, TeleportCause cause) { - return this; - } - - @Override - public OptionalInt openMenu(MenuProvider factory) { - return OptionalInt.empty(); - } - - @Override - public void updateOptions(ServerboundClientInformationPacket packet) { - } - - @Override - public void displayClientMessage(Component message, boolean actionBar) { - } - - @Override - public void awardStat(Stat stat, int amount) { - } - - @Override - public void awardStat(Stat stat) { - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - return true; - } - - @Override - public void openTextEdit(SignBlockEntity sign) { - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java deleted file mode 100644 index 22d9f917b..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightWorldNativeAccess.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; - -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import java.lang.ref.WeakReference; -import java.util.Objects; -import javax.annotation.Nullable; - -public class PaperweightWorldNativeAccess implements WorldNativeAccess { - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - - private final PaperweightAdapter adapter; - private final WeakReference world; - private SideEffectSet sideEffectSet; - - public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { - this.adapter = adapter; - this.world = world; - } - - private ServerLevel getWorld() { - return Objects.requireNonNull(world.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getWorld().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { - int stateId = BlockStateIdAccess.getBlockStateId(state); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { - return chunk.getBlockState(position); - } - - @Nullable - @Override - public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { - return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { - return Block.updateFromNeighbourShapes(block, getWorld(), position); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos position) { - getWorld().getChunkSource().getLightEngine().checkBlock(position); - } - - @Override - public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { - return false; - } - - @Override - public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk chunk) { - return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk chunk, BlockPos position) { - if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { - getWorld().getChunkSource().blockChanged(position); - } - } - - @Override - public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - ServerLevel world = getWorld(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - world.updateNeighborsAt(pos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - Block block = oldState.getBlock(); - fireNeighborChanged(pos, world, block, pos.west()); - fireNeighborChanged(pos, world, block, pos.east()); - fireNeighborChanged(pos, world, block, pos.below()); - fireNeighborChanged(pos, world, block, pos.above()); - fireNeighborChanged(pos, world, block, pos.north()); - fireNeighborChanged(pos, world, block, pos.south()); - } - if (newState.hasAnalogOutputSignal()) { - world.updateNeighbourForOutputSignal(pos, newState.getBlock()); - } - } - - // Not sure why neighborChanged is deprecated - @SuppressWarnings("deprecation") - private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { - world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); - } - - @Override - public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { - ServerLevel world = getWorld(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = world.getWorld(); - BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); - world.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { - getWorld().onBlockStateChange(pos, oldState, newState); - } - - @Override - public void flush() { - - } -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java deleted file mode 100644 index cbd1af53d..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightBlockMaterial.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.util.ReflectionUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; - -public class PaperweightBlockMaterial implements BlockMaterial { - - private final Block block; - private final BlockState blockState; - private final Material material; - private final boolean isTranslucent; - private final CraftBlockData craftBlockData; - private final org.bukkit.Material craftMaterial; - private final int opacity; - private final CompoundTag tile; - - public PaperweightBlockMaterial(Block block) { - this(block, block.defaultBlockState()); - } - - public PaperweightBlockMaterial(Block block, BlockState blockState) { - this.block = block; - this.blockState = blockState; - this.material = blockState.getMaterial(); - this.craftBlockData = CraftBlockData.fromData(blockState); - this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "aP")); - this.isTranslucent = !(boolean) ReflectionUtil.getField(BlockBehaviour.Properties.class, blockInfo, - Refraction.pickName("canOcclude", "n") - ); - opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); - BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity( - BlockPos.ZERO, - blockState - ); - tile = tileEntity == null - ? null - : new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - } - - public Block getBlock() { - return block; - } - - public BlockState getState() { - return blockState; - } - - public CraftBlockData getCraftBlockData() { - return craftBlockData; - } - - public Material getMaterial() { - return material; - } - - @Override - public boolean isAir() { - return blockState.isAir(); - } - - @Override - public boolean isFullCube() { - return craftMaterial.isOccluding(); - } - - @Override - public boolean isOpaque() { - return material.isSolidBlocking(); - } - - @Override - public boolean isPowerSource() { - return blockState.isSignalSource(); - } - - @Override - public boolean isLiquid() { - return material.isLiquid(); - } - - @Override - public boolean isSolid() { - return material.isSolid(); - } - - @Override - public float getHardness() { - return craftBlockData.getState().destroySpeed; - } - - @Override - public float getResistance() { - return block.getExplosionResistance(); - } - - @Override - public float getSlipperiness() { - return block.getFriction(); - } - - @Override - public int getLightValue() { - return blockState.getLightEmission(); - } - - @Override - public int getLightOpacity() { - return opacity; - } - - @Override - public boolean isFragileWhenPushed() { - return material.getPushReaction() == PushReaction.DESTROY; - } - - @Override - public boolean isUnpushable() { - return material.getPushReaction() == PushReaction.BLOCK; - } - - @Override - public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); - } - - @Override - public boolean isMovementBlocker() { - return material.isSolid(); - } - - @Override - public boolean isBurnable() { - return material.isFlammable(); - } - - @Override - public boolean isToolRequired() { - // Removed in 1.16.1, this is not present in higher versions - return false; - } - - @Override - public boolean isReplacedDuringPlacement() { - return material.isReplaceable(); - } - - @Override - public boolean isTranslucent() { - return isTranslucent; - } - - @Override - public boolean hasContainer() { - return block instanceof EntityBlock; - } - - @Override - public boolean isTile() { - return block instanceof EntityBlock; - } - - @Override - public CompoundTag getDefaultTile() { - return tile; - } - - @Override - public int getMapColor() { - // rgb field - return material.getColor().col; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/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 91fa70546..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweWorldNativeAccess.java +++ /dev/null @@ -1,286 +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.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.world.block.BlockState; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.event.block.BlockPhysicsEvent; - -import javax.annotation.Nullable; -import java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - -public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess { - - private static final int UPDATE = 1; - private static final int NOTIFY = 2; - private static final Direction[] NEIGHBOUR_ORDER = { - Direction.EAST, - Direction.WEST, - Direction.DOWN, - Direction.UP, - Direction.NORTH, - Direction.SOUTH - }; - private final PaperweightFaweAdapter paperweightFaweAdapter; - private final WeakReference level; - private final AtomicInteger lastTick; - private final Set cachedChanges = new HashSet<>(); - private final Set cachedChunksToSend = new HashSet<>(); - private SideEffectSet sideEffectSet; - - public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference level) { - this.paperweightFaweAdapter = paperweightFaweAdapter; - this.level = level; - // Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging. - // - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway. - this.lastTick = new AtomicInteger(MinecraftServer.currentTick); - } - - private Level getLevel() { - return Objects.requireNonNull(level.get(), "The reference to the world was lost"); - } - - @Override - public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { - this.sideEffectSet = sideEffectSet; - } - - @Override - public LevelChunk getChunk(int x, int z) { - return getLevel().getChunk(x, z); - } - - @Override - public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) { - int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar()); - return BlockStateIdAccess.isValidInternalId(stateId) - ? Block.stateById(stateId) - : ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState(); - } - - @Override - public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) { - return levelChunk.getBlockState(blockPos); - } - - @Nullable - @Override - public synchronized net.minecraft.world.level.block.state.BlockState setBlockState( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState blockState - ) { - int currentTick = MinecraftServer.currentTick; - if (Fawe.isMainThread()) { - return levelChunk.setBlockState(blockPos, blockState, - this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE) - ); - } - // Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( ) - cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState)); - cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ)); - boolean nextTick = lastTick.get() > currentTick; - if (nextTick || cachedChanges.size() >= 1024) { - if (nextTick) { - lastTick.set(currentTick); - } - flushAsync(nextTick); - } - return blockState; - } - - @Override - public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition( - net.minecraft.world.level.block.state.BlockState blockState, - BlockPos blockPos - ) { - return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos); - } - - @Override - public BlockPos getPosition(int x, int y, int z) { - return new BlockPos(x, y, z); - } - - @Override - public void updateLightingForBlock(BlockPos blockPos) { - getLevel().getChunkSource().getLightEngine().checkBlock(blockPos); - } - - @Override - public boolean updateTileEntity(BlockPos blockPos, CompoundBinaryTag tag) { - // We will assume that the tile entity was created for us, - // though we do not do this on the other versions - BlockEntity blockEntity = getLevel().getBlockEntity(blockPos); - if (blockEntity == null) { - return false; - } - net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeBinary(tag); - blockEntity.load((CompoundTag) nativeTag); - return true; - } - - @Override - public void notifyBlockUpdate( - LevelChunk levelChunk, BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY); - } - } - - @Override - public boolean isChunkTicking(LevelChunk levelChunk) { - return levelChunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); - } - - @Override - public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) { - if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) { - ((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos); - } - } - - @Override - public void notifyNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - Level level = getLevel(); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - level.blockUpdated(blockPos, oldState.getBlock()); - } else { - // When we don't want events, manually run the physics without them. - // Un-nest neighbour updating - for (Direction direction : NEIGHBOUR_ORDER) { - BlockPos shifted = blockPos.relative(direction); - level.getBlockState(shifted).neighborChanged(level, shifted, oldState.getBlock(), blockPos, false); - } - } - if (newState.hasAnalogOutputSignal()) { - level.updateNeighbourForOutputSignal(blockPos, newState.getBlock()); - } - } - - @Override - public void updateNeighbors( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState, - int recursionLimit - ) { - Level level = getLevel(); - // a == updateNeighbors - // b == updateDiagonalNeighbors - oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { - CraftWorld craftWorld = level.getWorld(); - if (craftWorld != null) { - BlockPhysicsEvent event = new BlockPhysicsEvent( - craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()), - CraftBlockData.fromData(newState) - ); - level.getCraftServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - } - } - newState.triggerEvent(level, blockPos, NOTIFY, recursionLimit); - newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); - } - - @Override - public void onBlockStateChange( - BlockPos blockPos, - net.minecraft.world.level.block.state.BlockState oldState, - net.minecraft.world.level.block.state.BlockState newState - ) { - getLevel().onBlockStateChange(blockPos, oldState, newState); - } - - private synchronized void flushAsync(final boolean sendChunks) { - final Set changes = Set.copyOf(cachedChanges); - cachedChanges.clear(); - final Set toSend; - if (sendChunks) { - toSend = Set.copyOf(cachedChunksToSend); - cachedChunksToSend.clear(); - } else { - toSend = Collections.emptySet(); - } - RunnableVal runnableVal = new RunnableVal<>() { - @Override - public void run(Object value) { - changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState, - sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE) - )); - if (!sendChunks) { - return; - } - for (IntPair chunk : toSend) { - PaperweightPlatformAdapter.sendChunk(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 470378715..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks.java +++ /dev/null @@ -1,1187 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.math.BitArrayUnstretched; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.queue.implementation.QueueHandler; -import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks; -import com.fastasyncworldedit.core.util.MathMan; -import com.fastasyncworldedit.core.util.collection.AdaptedMap; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import io.papermc.lib.PaperLib; -import io.papermc.paper.event.block.BeaconDeactivatedEvent; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.IdMap; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.IntTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.BitStorage; -import net.minecraft.util.ZeroBitStorage; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BeaconBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.HashMapPalette; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.LinearPalette; -import net.minecraft.world.level.chunk.Palette; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.apache.logging.log4j.Logger; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import javax.annotation.Nonnull; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Function posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - private final ReadWriteLock sectionLock = new ReentrantReadWriteLock(); - private final ReentrantLock callLock = new ReentrantLock(); - private final ServerLevel serverLevel; - private final int chunkX; - private final int chunkZ; - private final int minHeight; - private final int maxHeight; - private final int minSectionPosition; - private final int maxSectionPosition; - private final Registry biomeRegistry; - private final IdMap> biomeHolderIdMap; - private final ConcurrentHashMap copies = new ConcurrentHashMap<>(); - private final Object sendLock = new Object(); - private LevelChunkSection[] sections; - private LevelChunk levelChunk; - private DataLayer[] blockLight; - private DataLayer[] skyLight; - private boolean createCopy = false; - private boolean forceLoadSections = true; - private boolean lightUpdate = false; - private int copyKey = 0; - - public PaperweightGetBlocks(World world, int chunkX, int chunkZ) { - this(((CraftWorld) world).getHandle(), chunkX, chunkZ); - } - - public PaperweightGetBlocks(ServerLevel serverLevel, int chunkX, int chunkZ) { - super(serverLevel.getMinBuildHeight() >> 4, (serverLevel.getMaxBuildHeight() - 1) >> 4); - this.serverLevel = serverLevel; - this.chunkX = chunkX; - this.chunkZ = chunkZ; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.minSectionPosition = minHeight >> 4; - this.maxSectionPosition = maxHeight >> 4; - this.skyLight = new DataLayer[getSectionCount()]; - this.blockLight = new DataLayer[getSectionCount()]; - this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME); - this.biomeHolderIdMap = biomeRegistry.asHolderIdMap(); - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - @Override - public boolean isCreateCopy() { - return createCopy; - } - - @Override - public int setCreateCopy(boolean createCopy) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked."); - } - this.createCopy = createCopy; - // Increment regardless of whether copy will be created or not to return null from getCopy() - return ++this.copyKey; - } - - @Override - public IChunkGet getCopy(final int key) { - return copies.remove(key); - } - - @Override - public void lockCall() { - this.callLock.lock(); - } - - @Override - public void unlockCall() { - this.callLock.unlock(); - } - - @Override - public void setLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setSkyLightingToGet(char[][] light, int minSectionPosition, int maxSectionPosition) { - if (light != null) { - lightUpdate = true; - try { - fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition); - } catch (Throwable e) { - e.printStackTrace(); - } - } - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - // height + 1 to match server internal - BitArrayUnstretched bitArray = new BitArrayUnstretched(MathMan.log2nlz(getChunk().getHeight() + 1), 256); - bitArray.fromRaw(data); - Heightmap.Types nativeType = Heightmap.Types.valueOf(type.name()); - Heightmap heightMap = getChunk().heightmaps.get(nativeType); - heightMap.setRawData(getChunk(), nativeType, bitArray.getData()); - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - LevelChunkSection section = getSections(false)[(y >> 4) - getMinSectionPosition()]; - Holder biomes = section.getNoiseBiome(x >> 2, (y & 15) >> 2, z >> 2); - return PaperweightPlatformAdapter.adapt(biomes, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getDataLayerData( - sectionPos); - if (dataLayer != null) { - lightUpdate = true; - synchronized (dataLayer) { - byte[] bytes = dataLayer.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - if (sky) { - SectionPos sectionPos1 = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer1 = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.SKY) - .getDataLayerData(sectionPos1); - if (dataLayer1 != null) { - lightUpdate = true; - synchronized (dataLayer1) { - byte[] bytes = dataLayer1.getData(); - Arrays.fill(bytes, (byte) 0); - } - } - } - } - - @Override - public CompoundTag getTile(int x, int y, int z) { - BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + ( - chunkX << 4), y, (z & 15) + ( - chunkZ << 4))); - if (blockEntity == null) { - return null; - } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); - } - - @Override - public Map getTiles() { - Map nmsTiles = getChunk().getBlockEntities(); - if (nmsTiles.isEmpty()) { - return Collections.emptyMap(); - } - return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We); - } - - @Override - public int getSkyLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (skyLight[alayer] == null) { - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = - serverLevel.getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getDataLayerData(sectionPos); - // If the server hasn't generated the section's NibbleArray yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - LightLayer.BLOCK, - sectionPos, - dataLayer, - true - ); - } - skyLight[alayer] = dataLayer; - } - return skyLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int getEmittedLight(int x, int y, int z) { - int layer = y >> 4; - int alayer = layer - getMinSectionPosition(); - if (blockLight[alayer] == null) { - serverLevel.getRawBrightness(new BlockPos(1, 1, 1), 5); - SectionPos sectionPos = SectionPos.of(getChunk().getPos(), layer); - DataLayer dataLayer = serverLevel - .getChunkSource() - .getLightEngine() - .getLayerListener(LightLayer.BLOCK) - .getDataLayerData(sectionPos); - // If the server hasn't generated the section's DataLayer yet, it will be null - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - // Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway. - Arrays.fill(LAYER_COUNT, (byte) 15); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData(LightLayer.BLOCK, sectionPos, - dataLayer, true - ); - } - blockLight[alayer] = dataLayer; - } - return blockLight[alayer].get(x & 15, y & 15, z & 15); - } - - @Override - public int[] getHeightMap(HeightMapType type) { - long[] longArray = getChunk().heightmaps.get(Heightmap.Types.valueOf(type.name())).getRawData(); - BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray); - return bitArray.toRaw(new int[256]); - } - - @Override - public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); - if (entity != null) { - org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); - return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); - } - for (CompoundTag tag : getEntities()) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public Set getEntities() { - ensureLoaded(serverLevel, chunkX, chunkZ); - List entities = PaperweightPlatformAdapter.getEntities(getChunk()); - if (entities.isEmpty()) { - return Collections.emptySet(); - } - int size = entities.size(); - return new AbstractSet<>() { - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public boolean contains(Object get) { - if (!(get instanceof CompoundTag getTag)) { - return false; - } - UUID getUUID = getTag.getUUID(); - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (uuid.equals(getUUID)) { - return true; - } - } - return false; - } - - @Nonnull - @Override - public Iterator iterator() { - Iterable result = entities.stream().map(input -> { - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); - return (CompoundTag) adapter.toNative(tag); - }).collect(Collectors.toList()); - return result.iterator(); - } - }; - } - - private void removeEntity(Entity entity) { - entity.discard(); - } - - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) { - return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ); - } - - @Override - @SuppressWarnings("rawtypes") - public synchronized > T call(IChunkSet set, Runnable finalizer) { - if (!callLock.isHeldByCurrentThread()) { - throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked."); - } - forceLoadSections = false; - PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null; - if (createCopy) { - if (copies.containsKey(copyKey)) { - throw new IllegalStateException("Copy key already used."); - } - copies.put(copyKey, copy); - } - try { - ServerLevel nmsWorld = serverLevel; - LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ); - - // Remove existing tiles. Create a copy so that we can remove blocks - Map chunkTiles = new HashMap<>(nmsChunk.getBlockEntities()); - List beacons = null; - if (!chunkTiles.isEmpty()) { - for (Map.Entry entry : chunkTiles.entrySet()) { - final BlockPos pos = entry.getKey(); - final int lx = pos.getX() & 15; - final int ly = pos.getY(); - final int lz = pos.getZ() & 15; - final int layer = ly >> 4; - if (!set.hasSection(layer)) { - continue; - } - - int ordinal = set.getBlock(lx, ly, lz).getOrdinal(); - if (ordinal != BlockTypesCache.ReservedIDs.__RESERVED__) { - BlockEntity tile = entry.getValue(); - if (PaperLib.isPaper() && tile instanceof BeaconBlockEntity) { - if (beacons == null) { - beacons = new ArrayList<>(); - } - beacons.add(tile); - PaperweightPlatformAdapter.removeBeacon(tile, nmsChunk); - continue; - } - nmsChunk.removeBlockEntity(tile.getBlockPos()); - if (createCopy) { - copy.storeTile(tile); - } - } - } - } - final BiomeType[][] biomes = set.getBiomes(); - - int bitMask = 0; - synchronized (nmsChunk) { - LevelChunkSection[] levelChunkSections = nmsChunk.getSections(); - - for (int layerNo = getMinSectionPosition(); layerNo <= getMaxSectionPosition(); layerNo++) { - - int getSectionIndex = layerNo - getMinSectionPosition(); - int setSectionIndex = layerNo - set.getMinSectionPosition(); - - if (!set.hasSection(layerNo)) { - // No blocks, but might be biomes present. Handle this lazily. - if (biomes == null) { - continue; - } - if (layerNo < set.getMinSectionPosition() || layerNo > set.getMaxSectionPosition()) { - continue; - } - if (biomes[setSectionIndex] != null) { - synchronized (super.sectionLocks[getSectionIndex]) { - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - if (createCopy && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - - if (existingSection == null) { - PalettedContainer> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer( - biomes[setSectionIndex], - biomeHolderIdMap - ); - LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - new char[4096], - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, new char[4096], getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } else { - PalettedContainer> paletteBiomes = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - if (paletteBiomes != null) { - PaperweightPlatformAdapter.setBiomesToChunkSection(existingSection, paletteBiomes); - } - } - } - } - continue; - } - - bitMask |= 1 << getSectionIndex; - - // setArr is modified by PaperweightPlatformAdapter#newChunkSection. This is in order to write changes to - // this chunk GET when #updateGet is called. Future dords, please listen this time. - char[] tmp = set.load(layerNo); - char[] setArr = new char[tmp.length]; - System.arraycopy(tmp, 0, setArr, 0, tmp.length); - - // synchronise on internal section to avoid circular locking with a continuing edit if the chunk was - // submitted to keep loaded internal chunks to queue target size. - synchronized (super.sectionLocks[getSectionIndex]) { - - LevelChunkSection newSection; - LevelChunkSection existingSection = levelChunkSections[getSectionIndex]; - // Don't attempt to tick section whilst we're editing - if (existingSection != null) { - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - } - - if (createCopy) { - char[] tmpLoad = loadPrivately(layerNo); - char[] copyArr = new char[4096]; - System.arraycopy(tmpLoad, 0, copyArr, 0, 4096); - copy.storeSection(getSectionIndex, copyArr); - if (biomes != null && existingSection != null) { - copy.storeBiomes(getSectionIndex, existingSection.getBiomes()); - } - } - - if (existingSection == null) { - PalettedContainer> biomeData = biomes == null ? new PalettedContainer<>( - biomeHolderIdMap, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)), - PalettedContainer.Strategy.SECTION_BIOMES, - null - ) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap); - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - setArr, - adapter, - biomeRegistry, - biomeData - ); - if (PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - null, - newSection, - getSectionIndex - )) { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - continue; - } else { - existingSection = levelChunkSections[getSectionIndex]; - if (existingSection == null) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - continue; - } - } - } - - //ensure that the server doesn't try to tick the chunksection while we're editing it. (Again) - PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); - - // Synchronize to prevent further acquisitions - synchronized (lock) { - lock.acquire(); // Wait until we have the lock - lock.release(); - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = null; - this.reset(); - } else if (existingSection != getSections(false)[getSectionIndex]) { - this.sections[getSectionIndex] = existingSection; - this.reset(); - } else if (!Arrays.equals( - update(getSectionIndex, new char[4096], true), - loadPrivately(layerNo) - )) { - this.reset(layerNo); - /*} else if (lock.isModified()) { - this.reset(layerNo);*/ - } - } finally { - sectionLock.writeLock().unlock(); - } - - PalettedContainer> biomeData = setBiomesToPalettedContainer( - biomes, - setSectionIndex, - existingSection.getBiomes() - ); - - newSection = PaperweightPlatformAdapter.newChunkSection( - layerNo, - this::loadPrivately, - setArr, - adapter, - biomeRegistry, - biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() - ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, - newSection, - getSectionIndex - )) { - LOGGER.error("Skipping invalid null section. chunk: {}, {} layer: {}", chunkX, chunkZ, - getSectionIndex - ); - } else { - updateGet(nmsChunk, levelChunkSections, newSection, setArr, getSectionIndex); - } - } - } - } - - Map heightMaps = set.getHeightMaps(); - for (Map.Entry entry : heightMaps.entrySet()) { - PaperweightGetBlocks.this.setHeightmapToGet(entry.getKey(), entry.getValue()); - } - PaperweightGetBlocks.this.setLightingToGet( - set.getLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - PaperweightGetBlocks.this.setSkyLightingToGet( - set.getSkyLight(), - set.getMinSectionPosition(), - set.getMaxSectionPosition() - ); - - Runnable[] syncTasks = null; - - int bx = chunkX << 4; - int bz = chunkZ << 4; - - // Call beacon deactivate events here synchronously - // list will be null on spigot, so this is an implicit isPaper check - if (beacons != null && !beacons.isEmpty()) { - final List finalBeacons = beacons; - - syncTasks = new Runnable[4]; - - syncTasks[3] = () -> { - for (BlockEntity beacon : finalBeacons) { - BeaconBlockEntity.playSound(beacon.getLevel(), beacon.getBlockPos(), SoundEvents.BEACON_DEACTIVATE); - new BeaconDeactivatedEvent(CraftBlock.at(beacon.getLevel(), beacon.getBlockPos())).callEvent(); - } - }; - } - - Set entityRemoves = set.getEntityRemoves(); - if (entityRemoves != null && !entityRemoves.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[3]; - } - - syncTasks[2] = () -> { - Set entitiesRemoved = new HashSet<>(); - final List entities = PaperweightPlatformAdapter.getEntities(nmsChunk); - - for (Entity entity : entities) { - UUID uuid = entity.getUUID(); - if (entityRemoves.contains(uuid)) { - if (createCopy) { - copy.storeEntity(entity); - } - removeEntity(entity); - entitiesRemoved.add(uuid); - entityRemoves.remove(uuid); - } - } - if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) { - for (UUID uuid : entityRemoves) { - Entity entity = nmsWorld.getEntities().get(uuid); - if (entity != null) { - removeEntity(entity); - } - } - } - // Only save entities that were actually removed to history - set.getEntityRemoves().clear(); - set.getEntityRemoves().addAll(entitiesRemoved); - }; - } - - Set entities = set.getEntities(); - if (entities != null && !entities.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[2]; - } - - syncTasks[1] = () -> { - Iterator iterator = entities.iterator(); - while (iterator.hasNext()) { - final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); - final StringTag idTag = (StringTag) entityTagMap.get("Id"); - final ListTag posTag = (ListTag) entityTagMap.get("Pos"); - final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); - if (idTag == null || posTag == null || rotTag == null) { - LOGGER.error("Unknown entity tag: {}", nativeTag); - continue; - } - final double x = posTag.getDouble(0); - final double y = posTag.getDouble(1); - final double z = posTag.getDouble(2); - final float yaw = rotTag.getFloat(0); - final float pitch = rotTag.getFloat(1); - final String id = idTag.getValue(); - - EntityType type = EntityType.byString(id).orElse(null); - if (type != null) { - Entity entity = type.create(nmsWorld); - if (entity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - entity.load(tag); - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setUUID(nativeTag.getUUID()); - if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) { - LOGGER.warn( - "Error creating entity of type `{}` in world `{}` at location `{},{},{}`", - id, - nmsWorld.getWorld().getName(), - x, - y, - z - ); - // Unsuccessful create should not be saved to history - iterator.remove(); - } - } - } - } - }; - } - - // set tiles - Map tiles = set.getTiles(); - if (tiles != null && !tiles.isEmpty()) { - if (syncTasks == null) { - syncTasks = new Runnable[1]; - } - - syncTasks[0] = () -> { - for (final Map.Entry entry : tiles.entrySet()) { - final CompoundTag nativeTag = entry.getValue(); - final BlockVector3 blockHash = entry.getKey(); - final int x = blockHash.x() + bx; - final int y = blockHash.y(); - final int z = blockHash.z() + bz; - final BlockPos pos = new BlockPos(x, y, z); - - synchronized (nmsWorld) { - BlockEntity tileEntity = nmsWorld.getBlockEntity(pos); - if (tileEntity == null || tileEntity.isRemoved()) { - nmsWorld.removeBlockEntity(pos); - tileEntity = nmsWorld.getBlockEntity(pos); - } - if (tileEntity != null) { - final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative( - nativeTag); - tag.put("x", IntTag.valueOf(x)); - tag.put("y", IntTag.valueOf(y)); - tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); - } - } - } - }; - } - - Runnable callback; - if (bitMask == 0 && biomes == null && !lightUpdate) { - callback = null; - } else { - int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0; - boolean finalLightUpdate = lightUpdate; - callback = () -> { - // Set Modified - nmsChunk.setLightCorrect(true); // Set Modified - nmsChunk.mustNotSave = false; - nmsChunk.setUnsaved(true); - // send to player - if (Settings.settings().LIGHTING.MODE == 0 || !Settings.settings().LIGHTING.DELAY_PACKET_SENDING || finalMask == 0 && biomes != null) { - this.send(); - } - if (finalizer != null) { - finalizer.run(); - } - }; - } - if (syncTasks != null) { - QueueHandler queueHandler = Fawe.instance().getQueueHandler(); - Runnable[] finalSyncTasks = syncTasks; - - // Chain the sync tasks and the callback - Callable chain = () -> { - try { - // Run the sync tasks - for (Runnable task : finalSyncTasks) { - if (task != null) { - task.run(); - } - } - if (callback == null) { - if (finalizer != null) { - queueHandler.async(finalizer, null); - } - return null; - } else { - return queueHandler.async(callback, null); - } - } catch (Throwable e) { - e.printStackTrace(); - throw e; - } - }; - //noinspection unchecked - required at compile time - return (T) (Future) queueHandler.sync(chain); - } else { - if (callback == null) { - if (finalizer != null) { - finalizer.run(); - } - } else { - callback.run(); - } - } - } - return null; - } catch (Throwable e) { - e.printStackTrace(); - return null; - } finally { - forceLoadSections = true; - } - } - - private void updateGet( - LevelChunk nmsChunk, - LevelChunkSection[] chunkSections, - LevelChunkSection section, - char[] arr, - int layer - ) { - try { - sectionLock.writeLock().lock(); - if (this.getChunk() != nmsChunk) { - this.levelChunk = nmsChunk; - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - this.reset(); - } - if (this.sections == null) { - this.sections = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length); - } - if (this.sections[layer] != section) { - // Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords - this.sections[layer] = new LevelChunkSection[]{section}.clone()[0]; - } - } finally { - sectionLock.writeLock().unlock(); - } - this.blocks[layer] = arr; - } - - private char[] loadPrivately(int layer) { - layer -= getMinSectionPosition(); - if (super.sections[layer] != null) { - synchronized (super.sectionLocks[layer]) { - if (super.sections[layer].isFull() && super.blocks[layer] != null) { - return super.blocks[layer]; - } - } - } - return PaperweightGetBlocks.this.update(layer, null, true); - } - - @Override - public void send() { - synchronized (sendLock) { - PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ); - } - } - - /** - * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this - * {@link PaperweightPlatformAdapter} instance. Not synchronised to the {@link PaperweightPlatformAdapter} instance as synchronisation - * is handled where necessary in the method, and should otherwise be handled correctly by this method's caller. - * - * @param layer layer index (0 may denote a negative layer in the world, e.g. at y=-32) - * @param data array to be updated/filled with data or null - * @param aggressive if the cached section array should be re-acquired. - * @return the given array to be filled with data, or a new array if null is given. - */ - @Override - @SuppressWarnings("unchecked") - public char[] update(int layer, char[] data, boolean aggressive) { - LevelChunkSection section = getSections(aggressive)[layer]; - // Section is null, return empty array - if (section == null) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - return data; - } - if (data != null && data.length != 4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - if (data == null || data == FaweCache.INSTANCE.EMPTY_CHAR_4096) { - data = new char[4096]; - Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); - } - Semaphore lock = PaperweightPlatformAdapter.applyLock(section); - synchronized (lock) { - // Efficiently convert ChunkSection to raw data - try { - lock.acquire(); - - final PalettedContainer blocks = section.getStates(); - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocks); - final BitStorage bits = (BitStorage) PaperweightPlatformAdapter.fieldStorage.get(dataObject); - - if (bits instanceof ZeroBitStorage) { - Arrays.fill(data, adapter.adaptToChar(blocks.get(0, 0, 0))); // get(int) is only public on paper - return data; - } - - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get(dataObject); - - final int bitsPerEntry = bits.getBits(); - final long[] blockStates = bits.getRaw(); - - new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).toRaw(data); - - int num_palette; - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - num_palette = palette.getSize(); - } else { - // The section's palette is the global block palette. - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char ordinal = adapter.ibdIDToOrdinal(paletteVal); - data[i] = ordinal; - } - return data; - } - - char[] paletteToOrdinal = FaweCache.INSTANCE.PALETTE_TO_BLOCK_CHAR.get(); - try { - if (num_palette != 1) { - for (int i = 0; i < num_palette; i++) { - char ordinal = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = ordinal; - } - for (int i = 0; i < 4096; i++) { - char paletteVal = data[i]; - char val = paletteToOrdinal[paletteVal]; - if (val == Character.MAX_VALUE) { - val = ordinal(palette.valueFor(i), adapter); - paletteToOrdinal[i] = val; - } - data[i] = val; - } - } else { - char ordinal = ordinal(palette.valueFor(0), adapter); - Arrays.fill(data, ordinal); - } - } finally { - for (int i = 0; i < num_palette; i++) { - paletteToOrdinal[i] = Character.MAX_VALUE; - } - } - return data; - } catch (IllegalAccessException | InterruptedException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - lock.release(); - } - } - } - - private char ordinal(BlockState ibd, PaperweightFaweAdapter adapter) { - if (ibd == null) { - return BlockTypesCache.ReservedIDs.AIR; - } else { - return adapter.adaptToChar(ibd); - } - } - - public LevelChunkSection[] getSections(boolean force) { - force &= forceLoadSections; - LevelChunkSection[] tmp = sections; - if (tmp == null || force) { - try { - sectionLock.writeLock().lock(); - tmp = sections; - if (tmp == null || force) { - LevelChunkSection[] chunkSections = getChunk().getSections(); - tmp = new LevelChunkSection[chunkSections.length]; - System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length); - sections = tmp; - } - } finally { - sectionLock.writeLock().unlock(); - } - } - return tmp; - } - - public LevelChunk getChunk() { - LevelChunk levelChunk = this.levelChunk; - if (levelChunk == null) { - synchronized (this) { - levelChunk = this.levelChunk; - if (levelChunk == null) { - this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ); - } - } - } - return levelChunk; - } - - private void fillLightNibble(char[][] light, LightLayer lightLayer, int minSectionPosition, int maxSectionPosition) { - for (int Y = 0; Y <= maxSectionPosition - minSectionPosition; Y++) { - if (light[Y] == null) { - continue; - } - SectionPos sectionPos = SectionPos.of(levelChunk.getPos(), Y + minSectionPosition); - DataLayer dataLayer = serverLevel.getChunkSource().getLightEngine().getLayerListener(lightLayer).getDataLayerData( - sectionPos); - if (dataLayer == null) { - byte[] LAYER_COUNT = new byte[2048]; - Arrays.fill(LAYER_COUNT, lightLayer == LightLayer.SKY ? (byte) 15 : (byte) 0); - dataLayer = new DataLayer(LAYER_COUNT); - ((LevelLightEngine) serverLevel.getChunkSource().getLightEngine()).queueSectionData( - lightLayer, - sectionPos, - dataLayer, - true - ); - } - synchronized (dataLayer) { - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - int i = y << 8 | z << 4 | x; - if (light[Y][i] < 16) { - dataLayer.set(x, y, z, light[Y][i]); - } - } - } - } - } - } - } - - private PalettedContainer> setBiomesToPalettedContainer( - final BiomeType[][] biomes, - final int sectionIndex, - final PalettedContainerRO> data - ) { - BiomeType[] sectionBiomes; - if (biomes == null || (sectionBiomes = biomes[sectionIndex]) == null) { - return null; - } - PalettedContainer> biomeData = data.recreate(); - for (int y = 0, index = 0; y < 4; y++) { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 4; x++, index++) { - BiomeType biomeType = sectionBiomes[index]; - if (biomeType == null) { - biomeData.set(x, y, z, data.get(x, y, z)); - } else { - biomeData.set( - x, - y, - z, - biomeHolderIdMap.byIdOrThrow(adapter.getInternalBiomeId(biomeType)) - ); - } - } - } - } - return biomeData; - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return getSections(false)[layer] != null; - } - - @Override - @SuppressWarnings("unchecked") - public synchronized boolean trim(boolean aggressive) { - skyLight = new DataLayer[getSectionCount()]; - blockLight = new DataLayer[getSectionCount()]; - if (aggressive) { - sectionLock.writeLock().lock(); - sections = null; - levelChunk = null; - sectionLock.writeLock().unlock(); - return super.trim(true); - } else if (sections == null) { - // don't bother trimming if there are no sections stored. - return true; - } else { - for (int i = getMinSectionPosition(); i <= getMaxSectionPosition(); i++) { - int layer = i - getMinSectionPosition(); - if (!hasSection(i) || !super.sections[layer].isFull()) { - continue; - } - LevelChunkSection existing = getSections(true)[layer]; - try { - final PalettedContainer blocksExisting = existing.getStates(); - - final Object dataObject = PaperweightPlatformAdapter.fieldData.get(blocksExisting); - final Palette palette = (Palette) PaperweightPlatformAdapter.fieldPalette.get( - dataObject); - int paletteSize; - - if (palette instanceof LinearPalette || palette instanceof HashMapPalette) { - paletteSize = palette.getSize(); - } else { - super.trim(false, i); - continue; - } - if (paletteSize == 1) { - //If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks. - continue; - } - super.trim(false, i); - } catch (IllegalAccessException ignored) { - super.trim(false, i); - } - } - return true; - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java deleted file mode 100644 index dd1787868..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightGetBlocks_Copy.java +++ /dev/null @@ -1,259 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType; -import com.fastasyncworldedit.core.queue.IBlocks; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.google.common.base.Suppliers; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import org.apache.logging.log4j.Logger; - -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Future; - -public class PaperweightGetBlocks_Copy implements IChunkGet { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private final Map tiles = new HashMap<>(); - private final Set entities = new HashSet<>(); - private final char[][] blocks; - private final int minHeight; - private final int maxHeight; - final ServerLevel serverLevel; - final LevelChunk levelChunk; - private Holder[][] biomes = null; - - protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) { - this.levelChunk = levelChunk; - this.serverLevel = levelChunk.level; - this.minHeight = serverLevel.getMinBuildHeight(); - this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive. - this.blocks = new char[getSectionCount()][]; - } - - protected void storeTile(BlockEntity blockEntity) { - tiles.put( - BlockVector3.at( - blockEntity.getBlockPos().getX(), - blockEntity.getBlockPos().getY(), - blockEntity.getBlockPos().getZ() - ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) - ); - } - - @Override - public Map getTiles() { - return tiles; - } - - @Override - @Nullable - public CompoundTag getTile(int x, int y, int z) { - return tiles.get(BlockVector3.at(x, y, z)); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - protected void storeEntity(Entity entity) { - BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); - entities.add((CompoundTag) adapter.toNative(compoundTag)); - } - - @Override - public Set getEntities() { - return this.entities; - } - - @Override - public CompoundTag getEntity(UUID uuid) { - for (CompoundTag tag : entities) { - if (uuid.equals(tag.getUUID())) { - return tag; - } - } - return null; - } - - @Override - public boolean isCreateCopy() { - return false; - } - - @Override - public int setCreateCopy(boolean createCopy) { - return -1; - } - - @Override - public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) { - } - - @Override - public void setHeightmapToGet(HeightMapType type, int[] data) { - } - - @Override - public int getMaxY() { - return maxHeight; - } - - @Override - public int getMinY() { - return minHeight; - } - - @Override - public int getMaxSectionPosition() { - return maxHeight >> 4; - } - - @Override - public int getMinSectionPosition() { - return minHeight >> 4; - } - - @Override - public BiomeType getBiomeType(int x, int y, int z) { - Holder biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2]; - return PaperweightPlatformAdapter.adapt(biome, serverLevel); - } - - @Override - public void removeSectionLighting(int layer, boolean sky) { - } - - @Override - public boolean trim(boolean aggressive, int layer) { - return false; - } - - @Override - public IBlocks reset() { - return null; - } - - @Override - public int getSectionCount() { - return serverLevel.getSectionsCount(); - } - - protected void storeSection(int layer, char[] data) { - blocks[layer] = data; - } - - protected void storeBiomes(int layer, PalettedContainerRO> biomeData) { - if (biomes == null) { - biomes = new Holder[getSectionCount()][]; - } - if (biomes[layer] == null) { - biomes[layer] = new Holder[64]; - } - if (biomeData instanceof PalettedContainer> palettedContainer) { - for (int i = 0; i < 64; i++) { - biomes[layer][i] = palettedContainer.get(i); - } - } else { - LOGGER.error( - "Cannot correctly save biomes to history. Expected class type {} but got {}", - PalettedContainer.class.getSimpleName(), - biomeData.getClass().getSimpleName() - ); - } - } - - @Override - public BaseBlock getFullBlock(int x, int y, int z) { - BlockState state = BlockTypesCache.states[get(x, y, z)]; - return state.toBaseBlock(this, x, y, z); - } - - @Override - public boolean hasSection(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer] != null; - } - - @Override - public char[] load(int layer) { - layer -= getMinSectionPosition(); - if (blocks[layer] == null) { - blocks[layer] = new char[4096]; - Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR); - } - return blocks[layer]; - } - - @Override - public char[] loadIfPresent(int layer) { - layer -= getMinSectionPosition(); - return blocks[layer]; - } - - @Override - public BlockState getBlock(int x, int y, int z) { - return BlockTypesCache.states[get(x, y, z)]; - } - - @Override - public int getSkyLight(int x, int y, int z) { - return 0; - } - - @Override - public int getEmittedLight(int x, int y, int z) { - return 0; - } - - @Override - public int[] getHeightMap(HeightMapType type) { - return new int[0]; - } - - @Override - public > T call(IChunkSet set, Runnable finalize) { - return null; - } - - public char get(int x, int y, int z) { - final int layer = (y >> 4) - getMinSectionPosition(); - final int index = (y & 15) << 8 | z << 4 | x; - return blocks[layer][index]; - } - - - @Override - public boolean trim(boolean aggressive) { - return false; - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/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 334289b08..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ /dev/null @@ -1,752 +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()) { - synchronized (chunk) { - 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 - ); - } - } - 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/PaperweightStarlightRelighter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java deleted file mode 100644 index b1e0c5772..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightStarlightRelighter.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; - -import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.TicketType; -import net.minecraft.util.Unit; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; - -import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; -import java.util.function.IntConsumer; - -public class PaperweightStarlightRelighter extends StarlightRelighter { - - private static final TicketType FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0); - private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkStatus.getDistance(ChunkStatus.LIGHT); - - public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent queue) { - super(serverLevel, queue); - } - - @Override - protected ChunkPos createChunkPos(final long chunkKey) { - return new ChunkPos(chunkKey); - } - - @Override - protected long asLong(final int chunkX, final int chunkZ) { - return ChunkPos.asLong(chunkX, chunkZ); - } - - @Override - protected CompletableFuture chunkLoadFuture(final ChunkPos chunkPos) { - return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z) - .thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel( - FAWE_TICKET, - chunkPos, - LIGHT_LEVEL, - Unit.INSTANCE - )); - } - - protected void invokeRelight( - Set coords, - Consumer chunkCallback, - IntConsumer processCallback - ) { - try { - serverLevel.getChunkSource().getLightEngine().relight(coords, chunkCallback, processCallback); - } catch (Exception e) { - LOGGER.error("Error occurred on relighting", e); - } - } - - /* - * Allow the server to unload the chunks again. - * Also, if chunk packets are sent delayed, we need to do that here - */ - protected void postProcessChunks(Set coords) { - boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING; - for (ChunkPos pos : coords) { - int x = pos.x; - int z = pos.z; - if (delay) { // we still need to send the block changes of that chunk - PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z); - } - serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE); - } - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/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 7db487c3f..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/nbt/PaperweightLazyCompoundTag.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.LazyCompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import net.minecraft.nbt.NumericTag; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class PaperweightLazyCompoundTag extends LazyCompoundTag { - - private final Supplier compoundTagSupplier; - private CompoundTag compoundTag; - - public PaperweightLazyCompoundTag(Supplier compoundTagSupplier) { - super(new HashMap<>()); - this.compoundTagSupplier = compoundTagSupplier; - } - - public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) { - this(() -> compoundTag); - } - - public net.minecraft.nbt.CompoundTag get() { - return compoundTagSupplier.get(); - } - - @Override - @SuppressWarnings("unchecked") - public Map getValue() { - if (compoundTag == null) { - compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); - } - return compoundTag.getValue(); - } - - @Override - public CompoundBinaryTag asBinaryTag() { - getValue(); - return compoundTag.asBinaryTag(); - } - - public boolean containsKey(String key) { - return compoundTagSupplier.get().contains(key); - } - - public byte[] getByteArray(String key) { - return compoundTagSupplier.get().getByteArray(key); - } - - public byte getByte(String key) { - return compoundTagSupplier.get().getByte(key); - } - - public double getDouble(String key) { - return compoundTagSupplier.get().getDouble(key); - } - - public double asDouble(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsDouble(); - } - return 0; - } - - public float getFloat(String key) { - return compoundTagSupplier.get().getFloat(key); - } - - public int[] getIntArray(String key) { - return compoundTagSupplier.get().getIntArray(key); - } - - public int getInt(String key) { - return compoundTagSupplier.get().getInt(key); - } - - public int asInt(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsInt(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public List getList(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); - for (net.minecraft.nbt.Tag elem : nbtList) { - if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { - list.add(new PaperweightLazyCompoundTag(compoundTag)); - } else { - list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); - } - } - return list; - } - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - public ListTag getListTag(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof net.minecraft.nbt.ListTag) { - return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag); - } - return new ListTag(StringTag.class, Collections.emptyList()); - } - - @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { - ListTag listTag = getListTag(key); - if (listTag.getType().equals(listType)) { - return (List) listTag.getValue(); - } else { - return Collections.emptyList(); - } - } - - public long[] getLongArray(String key) { - return compoundTagSupplier.get().getLongArray(key); - } - - public long getLong(String key) { - return compoundTagSupplier.get().getLong(key); - } - - public long asLong(String key) { - net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); - if (tag instanceof NumericTag numTag) { - return numTag.getAsLong(); - } - return 0; - } - - public short getShort(String key) { - return compoundTagSupplier.get().getShort(key); - } - - public String getString(String key) { - return compoundTagSupplier.get().getString(key); - } - - @Override - public String toString() { - return compoundTagSupplier.get().toString(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java deleted file mode 100644 index 17b354535..000000000 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java +++ /dev/null @@ -1,596 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.regen; - -import com.fastasyncworldedit.bukkit.adapter.Regenerator; -import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.queue.IChunkCache; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.util.ReflectionUtils; -import com.fastasyncworldedit.core.util.TaskManager; -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Either; -import com.mojang.serialization.Lifecycle; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.PaperweightGetBlocks; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.world.RegenOptions; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.progress.ChunkProgressListener; -import net.minecraft.util.thread.ProcessorHandle; -import net.minecraft.util.thread.ProcessorMailbox; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.LevelSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.FixedBiomeSource; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.chunk.ChunkGeneratorStructureState; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; -import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; -import net.minecraft.world.level.levelgen.WorldOptions; -import net.minecraft.world.level.levelgen.blending.BlendingData; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; -import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.PrimaryLevelData; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; - -import javax.annotation.Nullable; -import java.lang.reflect.Field; -import java.nio.file.Path; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.OptionalLong; -import java.util.Random; -import java.util.concurrent.CompletableFuture; -import java.util.function.BooleanSupplier; -import java.util.function.Supplier; - -import static net.minecraft.core.registries.Registries.BIOME; - -public class PaperweightRegen extends Regenerator { - - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - private static final Field serverWorldsField; - private static final Field paperConfigField; - private static final Field flatBedrockField; - private static final Field generatorSettingFlatField; - private static final Field generatorSettingBaseSupplierField; - private static final Field delegateField; - private static final Field chunkSourceField; - private static final Field generatorStructureStateField; - private static final Field ringPositionsField; - private static final Field hasGeneratedPositionsField; - - //list of chunk stati in correct order without FULL - private static final Map chunkStati = new LinkedHashMap<>(); - - static { - chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing - chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps - chunkStati.put( - ChunkStatus.STRUCTURE_REFERENCES, - Concurrency.FULL - ); // structure refs: radius 8, but only writes to current chunk - chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // biomes: radius 0 - chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8 - chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE - chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results - chunkStati.put( - ChunkStatus.LIQUID_CARVERS, - Concurrency.NONE - ); // liquid carvers: radius 0, but RADIUS and FULL change results - chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps - chunkStati.put( - ChunkStatus.LIGHT, - Concurrency.FULL - ); // light: radius 1, but no writes to other chunks, only current chunk - chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0 - chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0 - - try { - serverWorldsField = CraftServer.class.getDeclaredField("worlds"); - serverWorldsField.setAccessible(true); - - Field tmpPaperConfigField; - Field tmpFlatBedrockField; - try { //only present on paper - tmpPaperConfigField = Level.class.getDeclaredField("paperConfig"); - tmpPaperConfigField.setAccessible(true); - - tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock"); - tmpFlatBedrockField.setAccessible(true); - } catch (Exception e) { - tmpPaperConfigField = null; - tmpFlatBedrockField = null; - } - paperConfigField = tmpPaperConfigField; - flatBedrockField = tmpFlatBedrockField; - - generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName( - "settings", "e")); - generatorSettingBaseSupplierField.setAccessible(true); - - generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d")); - generatorSettingFlatField.setAccessible(true); - - delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); - delegateField.setAccessible(true); - - chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "H")); - chunkSourceField.setAccessible(true); - - generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w")); - generatorStructureStateField.setAccessible(true); - - ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g")); - ringPositionsField.setAccessible(true); - - hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField( - Refraction.pickName("hasGeneratedPositions", "h") - ); - hasGeneratedPositionsField.setAccessible(true); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - //runtime - private ServerLevel originalServerWorld; - private ServerChunkCache originalChunkProvider; - private ServerLevel freshWorld; - private ServerChunkCache freshChunkProvider; - private LevelStorageSource.LevelStorageAccess session; - private StructureTemplateManager structureTemplateManager; - private ThreadedLevelLightEngine threadedLevelLightEngine; - private ChunkGenerator chunkGenerator; - - private Path tempDir; - - private boolean generateFlatBedrock = false; - - public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) { - super(originalBukkitWorld, region, target, options); - } - - @Override - protected boolean prepare() { - this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle(); - originalChunkProvider = originalServerWorld.getChunkSource(); - - //flat bedrock? (only on paper) - if (paperConfigField != null) { - try { - generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld)); - } catch (Exception ignored) { - } - } - - seed = options.getSeed().orElse(originalServerWorld.getSeed()); - chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c)); - - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected boolean initNewWorld() throws Exception { - //world folder - tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen"); - - //prepare for world init (see upstream implementation for reference) - org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment(); - org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator(); - LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir); - ResourceKey levelStemResourceKey = getWorldDimKey(environment); - session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey); - PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData; - - MinecraftServer server = originalServerWorld.getCraftServer().getServer(); - WorldOptions originalOpts = originalWorldData.worldGenOptions(); - WorldOptions newOpts = options.getSeed().isPresent() - ? originalOpts.withSeed(OptionalLong.of(seed)) - : originalOpts; - LevelSettings newWorldSettings = new LevelSettings( - "faweregentempworld", - originalWorldData.settings.gameType(), - originalWorldData.settings.hardcore(), - originalWorldData.settings.difficulty(), - originalWorldData.settings.allowCommands(), - originalWorldData.settings.gameRules(), - originalWorldData.settings.getDataConfiguration() - ); - - PrimaryLevelData.SpecialWorldProperty specialWorldProperty = - originalWorldData.isFlatWorld() - ? PrimaryLevelData.SpecialWorldProperty.FLAT - : originalWorldData.isDebugWorld() - ? PrimaryLevelData.SpecialWorldProperty.DEBUG - : PrimaryLevelData.SpecialWorldProperty.NONE; - PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable()); - - BiomeProvider biomeProvider = getBiomeProvider(); - - - //init world - freshWorld = Fawe.instance().getQueueHandler().sync((Supplier) () -> new ServerLevel( - server, - server.executor, - session, - newWorldData, - originalServerWorld.dimension(), - DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow() - .getOrThrow(levelStemResourceKey), - new RegenNoOpWorldLoadListener(), - originalServerWorld.isDebug(), - seed, - ImmutableList.of(), - false, - environment, - generator, - biomeProvider - ) { - - private final Holder singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) : null; - - @Override - public void tick(BooleanSupplier shouldKeepTicking) { //no ticking - } - - @Override - public Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { - if (options.hasBiomeType()) { - return singleBiome; - } - return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome( - biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler() - ); - } - }).get(); - freshWorld.noSave = true; - removeWorldFromWorldsMap(); - newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name - if (paperConfigField != null) { - paperConfigField.set(freshWorld, originalServerWorld.paperConfig()); - } - - ChunkGenerator originalGenerator = originalChunkProvider.getGenerator(); - if (originalGenerator instanceof FlatLevelSource flatLevelSource) { - FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings(); - chunkGenerator = new FlatLevelSource(generatorSettingFlat); - } else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { - Holder generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); - BiomeSource biomeSource; - if (options.hasBiomeType()) { - - biomeSource = new FixedBiomeSource( - DedicatedServer.getServer().registryAccess() - .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( - WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType()) - ) - ); - } else { - biomeSource = originalGenerator.getBiomeSource(); - } - chunkGenerator = new NoiseBasedChunkGenerator( - biomeSource, - generatorSettingBaseSupplier - ); - } else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) { - chunkGenerator = customChunkGenerator.getDelegate(); - } else { - LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName()); - return false; - } - if (generator != null) { - chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator); - generateConcurrent = generator.isParallelCapable(); - } -// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed - - freshChunkProvider = new ServerChunkCache( - freshWorld, - session, - server.getFixerUpper(), - server.getStructureManager(), - server.executor, - chunkGenerator, - freshWorld.spigotConfig.viewDistance, - freshWorld.spigotConfig.simulationDistance, - server.forceSynchronousWrites(), - new RegenNoOpWorldLoadListener(), - (chunkCoordIntPair, state) -> { - }, - () -> server.overworld().getDataStorage() - ) { - // redirect to LevelChunks created in #createChunks - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean create) { - ChunkAccess chunkAccess = getChunkAt(x, z); - if (chunkAccess == null && create) { - chunkAccess = createChunk(getProtoChunkAt(x, z)); - } - return chunkAccess; - } - }; - - if (seed == originalOpts.seed() && !options.hasBiomeType()) { - // Optimisation for needless ring position calculation when the seed and biome is the same. - ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(originalChunkProvider.chunkMap); - boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state); - if (hasGeneratedPositions) { - Map>> origPositions = - (Map>>) ringPositionsField.get(state); - Map>> copy = new Object2ObjectArrayMap<>( - origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); - ringPositionsField.set(newState, copy); - hasGeneratedPositionsField.setBoolean(newState, true); - } - } - - - chunkSourceField.set(freshWorld, freshChunkProvider); - //let's start then - structureTemplateManager = server.getStructureManager(); - threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); - - return true; - } - - @Override - protected void cleanup() { - try { - session.close(); - } catch (Exception ignored) { - } - - //shutdown chunk provider - try { - Fawe.instance().getQueueHandler().sync(() -> { - try { - freshChunkProvider.close(false); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - } catch (Exception ignored) { - } - - //remove world from server - try { - Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap); - } catch (Exception ignored) { - } - - //delete directory - try { - SafeFiles.tryHardToDeleteDir(tempDir); - } catch (Exception ignored) { - } - } - - @Override - protected ProtoChunk createProtoChunk(int x, int z) { - return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld, - this.freshWorld.registryAccess().registryOrThrow(BIOME), null - ); - } - - @Override - protected LevelChunk createChunk(ProtoChunk protoChunk) { - return new LevelChunk( - freshWorld, - protoChunk, - null // we don't want to add entities - ); - } - - @Override - protected ChunkStatusWrap getFullChunkStatus() { - return new ChunkStatusWrap(ChunkStatus.FULL); - } - - @Override - protected List getBlockPopulators() { - return originalServerWorld.getWorld().getPopulators(); - } - - @Override - protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) { - // BlockPopulator#populate has to be called synchronously for TileEntity access - TaskManager.taskManager().task(() -> { - final CraftWorld world = freshWorld.getWorld(); - final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ); - blockPopulator.populate(world, random, chunk); - }); - } - - @Override - protected IChunkCache initSourceQueueCache() { - return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) { - @Override - public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) { - return getChunkAt(x, z); - } - }; - } - - //util - @SuppressWarnings("unchecked") - private void removeWorldFromWorldsMap() { - Fawe.instance().getQueueHandler().sync(() -> { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); - } - - private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { - return switch (env) { - case NETHER -> LevelStem.NETHER; - case THE_END -> LevelStem.END; - default -> LevelStem.OVERWORLD; - }; - } - - private static class RegenNoOpWorldLoadListener implements ChunkProgressListener { - - private RegenNoOpWorldLoadListener() { - } - - @Override - public void updateSpawnPos(ChunkPos spawnPos) { - } - - @Override - public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) { - } - - @Override - public void start() { - - } - - @Override - public void stop() { - } - - // TODO Paper only(?) @Override - public void setChunkRadius(int radius) { - } - - } - - private class FastProtoChunk extends ProtoChunk { - - public FastProtoChunk( - final ChunkPos pos, - final UpgradeData upgradeData, - final LevelHeightAccessor world, - final Registry biomeRegistry, - @Nullable final BlendingData blendingData - ) { - super(pos, upgradeData, world, biomeRegistry, blendingData); - } - - // avoid warning on paper - - // compatibility with spigot - - public boolean generateFlatBedrock() { - return generateFlatBedrock; - } - - // no one will ever see the entities! - @Override - public List getEntities() { - return Collections.emptyList(); - } - - } - - protected class ChunkStatusWrap extends ChunkStatusWrapper { - - private final ChunkStatus chunkStatus; - - public ChunkStatusWrap(ChunkStatus chunkStatus) { - this.chunkStatus = chunkStatus; - } - - @Override - public int requiredNeighborChunkRadius() { - return chunkStatus.getRange(); - } - - @Override - public String name() { - return chunkStatus.getName(); - } - - @Override - public CompletableFuture processChunk(List accessibleChunks) { - return chunkStatus.generate( - Runnable::run, // TODO revisit, we might profit from this somehow? - freshWorld, - chunkGenerator, - structureTemplateManager, - threadedLevelLightEngine, - c -> CompletableFuture.completedFuture(Either.left(c)), - accessibleChunks, - true - ); - } - - } - - /** - * A light engine that does nothing. As light is calculated after pasting anyway, we can avoid - * work this way. - */ - static class NoOpLightEngine extends ThreadedLevelLightEngine { - - private static final ProcessorMailbox MAILBOX = ProcessorMailbox.create(task -> { - }, "fawe-no-op"); - private static final ProcessorHandle> HANDLE = ProcessorHandle.of("fawe-no-op", m -> { - }); - - public NoOpLightEngine(final ServerChunkCache chunkProvider) { - super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE); - } - - @Override - public CompletableFuture retainData(final ChunkAccess chunk) { - return CompletableFuture.completedFuture(chunk); - } - - @Override - public CompletableFuture lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { - return CompletableFuture.completedFuture(chunk); - } - - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts deleted file mode 100644 index 51438592a..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension - -plugins { - java -} - -applyPaperweightAdapterConfiguration() - -repositories { - gradlePluginPortal() -} - -dependencies { - // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.1-R0.1-SNAPSHOT - the().paperDevBundle("1.20.1-R0.1-20230921.165944-178") - compileOnly(libs.paperlib) -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/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 e5c7080a6..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java +++ /dev/null @@ -1,614 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; -import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; -import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.fastasyncworldedit.core.util.NbtUtils; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen.PaperweightRegen; -import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.internal.wna.WorldNativeAccess; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.registry.state.BooleanProperty; -import com.sk89q.worldedit.registry.state.DirectionalProperty; -import com.sk89q.worldedit.registry.state.EnumProperty; -import com.sk89q.worldedit.registry.state.IntegerProperty; -import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; -import com.sk89q.worldedit.world.RegenOptions; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import com.sk89q.worldedit.world.entity.EntityType; -import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.registry.BlockMaterial; -import io.papermc.lib.PaperLib; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.WritableRegistry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.StringRepresentable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.DirectionProperty; -import net.minecraft.world.level.chunk.LevelChunk; -import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.v1_20_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 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((CompoundBinaryTag) toNativeBinary(tag)); - } - } - - return state.toBaseBlock(); - } - - @Override - public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); - } - - @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); - } - - @Override - public BaseEntity getEntity(org.bukkit.entity.Entity entity) { - Preconditions.checkNotNull(entity); - - CraftEntity craftEntity = ((CraftEntity) entity); - Entity mcEntity = craftEntity.getHandle(); - - String id = getEntityId(mcEntity); - - if (id != null) { - EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); - Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); - //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); - }; - return new LazyBaseEntity(type, saveTag); - } else { - return null; - } - } - - @Override - public Component getRichBlockName(BlockType blockType) { - return parent.getRichBlockName(blockType); - } - - @Override - public Component getRichItemName(ItemType itemType) { - return parent.getRichItemName(itemType); - } - - @Override - public Component getRichItemName(BaseItemStack itemStack) { - return parent.getRichItemName(itemStack); - } - - @Override - public OptionalInt getInternalBlockStateId(BlockState state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState(); - return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState)); - } - - @Override - public BlockState adapt(BlockData blockData) { - CraftBlockData cbd = ((CraftBlockData) blockData); - net.minecraft.world.level.block.state.BlockState ibd = cbd.getState(); - return adapt(ibd); - } - - public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) { - return BlockTypesCache.states[adaptToChar(blockState)]; - } - - public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) { - int id = Block.BLOCK_STATE_REGISTRY.getId(blockState); - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - try { - init(); - return ibdToStateOrdinal[id]; - } catch (ArrayIndexOutOfBoundsException e1) { - LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!", - blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1 - ); - return BlockTypesCache.ReservedIDs.AIR; - } - } - } - - public char ibdIDToOrdinal(int id) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal[id]; - } - init(); - return ibdToStateOrdinal[id]; - } - } - - @Override - public char[] getIbdToStateOrdinal() { - if (initialised) { - return ibdToStateOrdinal; - } - synchronized (this) { - if (initialised) { - return ibdToStateOrdinal; - } - init(); - return ibdToStateOrdinal; - } - } - - public int ordinalToIbdID(char ordinal) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID[ordinal]; - } - init(); - return ordinalToIbdID[ordinal]; - } - } - - @Override - public int[] getOrdinalToIbdID() { - if (initialised) { - return ordinalToIbdID; - } - synchronized (this) { - if (initialised) { - return ordinalToIbdID; - } - init(); - return ordinalToIbdID; - } - } - - @Override - public > BlockData adapt(B state) { - PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial(); - return material.getCraftBlockData(); - } - - @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { - ServerLevel nmsWorld = getServerLevel(world); - ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); - if (map != null && 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(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; - } - - @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { - return parent.toNative(foreign); - } - - @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { - if (foreign instanceof PaperweightLazyCompoundTag) { - return ((PaperweightLazyCompoundTag) foreign).get(); - } - return parent.fromNative(foreign); - } - - @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { - return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); - } - - @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { - return new PaperweightGetBlocks(world, chunkX, chunkZ); - } - - @Override - public int getInternalBiomeId(BiomeType biomeType) { - final Registry registry = MinecraftServer - .getServer() - .registryAccess() - .registryOrThrow(BIOME); - ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.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/PaperweightMapChunkUtil.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightMapChunkUtil.java deleted file mode 100644 index 62f5d4e03..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightMapChunkUtil.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData; -import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; - -//TODO un-very-break-this -public class PaperweightMapChunkUtil extends MapChunkUtil { - - public PaperweightMapChunkUtil() throws NoSuchFieldException { - fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a")); - fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "a")); - fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "b")); - fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b")); - fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "c")); - fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c")); - fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d")); - fieldX.setAccessible(true); - fieldZ.setAccessible(true); - fieldBitMask.setAccessible(true); - fieldHeightMap.setAccessible(true); - fieldChunkData.setAccessible(true); - fieldBlockEntities.setAccessible(true); - fieldFull.setAccessible(true); - } - - @Override - public ClientboundLevelChunkWithLightPacket createPacket() { - // TODO ??? return new ClientboundLevelChunkPacket(); - throw new UnsupportedOperationException(); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java deleted file mode 100644 index 0c4bcff85..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPostProcessor.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.fastasyncworldedit.core.registry.state.PropertyKey; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; - -import javax.annotation.Nullable; - -public class PaperweightPostProcessor implements IBatchProcessor { - - @Override - public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - return set; - } - - @SuppressWarnings("deprecation") - @Override - public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) { - boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS; - // The PostProcessor shouldn't be added, but just in case - if (!tickFluid) { - return; - } - PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet; - layer: - for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) { - char[] set = iChunkSet.loadIfPresent(layer); - if (set == null) { - // No edit means no need to process - continue; - } - char[] get = null; - for (int i = 0; i < 4096; i++) { - char ordinal = set[i]; - char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__; - boolean fromGet = false; // Used for liquids - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (get == null) { - get = getBlocks.load(layer); - } - // If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't - // actually being set - if (get == null) { - continue layer; - } - fromGet = true; - ordinal = replacedOrdinal = get[i]; - } - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - continue; - } else if (!fromGet) { // if fromGet, don't do the same again - if (get == null) { - get = getBlocks.load(layer); - } - replacedOrdinal = get[i]; - } - boolean ticking = BlockTypesCache.ticking[ordinal]; - boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal]; - boolean replacedWasLiquid = false; - BlockState replacedState = null; - if (!ticking) { - // If the block being replaced was not ticking, it cannot be a liquid - if (!replacedWasTicking) { - continue; - } - // If the block being replaced is not fluid, we do not need to worry - if (!(replacedWasLiquid = - (replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) { - continue; - } - } - BlockState state = BlockState.getFromOrdinal(ordinal); - boolean liquid = state.getMaterial().isLiquid(); - int x = i & 15; - int y = (i >> 8) & 15; - int z = (i >> 4) & 15; - BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z); - if (liquid || replacedWasLiquid) { - if (liquid) { - addFluid(getBlocks.serverLevel, state, position); - continue; - } - // If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this - // may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up - // being ticked anyway. We only need it to be "hit" once. - if (!wasAdjacentToWater(get, set, i, x, y, z)) { - continue; - } - addFluid(getBlocks.serverLevel, replacedState, position); - } - } - } - } - - @Nullable - @Override - public Extent construct(final Extent child) { - throw new UnsupportedOperationException("Processing only"); - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.READING_SET_BLOCKS; - } - - private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) { - if (set == null || get == null) { - return false; - } - char ordinal; - char reserved = BlockTypesCache.ReservedIDs.__RESERVED__; - if (x > 0 && set[i - 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) { - return true; - } - } - if (x < 15 && set[i + 1] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) { - return true; - } - } - if (z > 0 && set[i - 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) { - return true; - } - } - if (z < 15 && set[i + 16] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) { - return true; - } - } - if (y > 0 && set[i - 256] != reserved) { - if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) { - return true; - } - } - if (y < 15 && set[i + 256] != reserved) { - return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal); - } - return false; - } - - @SuppressWarnings("deprecation") - private boolean isFluid(char ordinal) { - return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid(); - } - - @SuppressWarnings("deprecation") - private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) { - Fluid type; - if (replacedState.getBlockType() == BlockTypes.LAVA) { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA; - } else { - type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER; - } - serverLevel.scheduleTick( - position, - type, - type.getTickDelay(serverLevel) - ); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java deleted file mode 100644 index 83509a2bb..000000000 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighterFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; - -import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode; -import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; -import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; -import com.fastasyncworldedit.core.queue.IQueueExtent; -import com.sk89q.worldedit.world.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; - -import javax.annotation.Nonnull; - -public class PaperweightStarlightRelighterFactory implements RelighterFactory { - - @Override - public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent queue) { - org.bukkit.World w = Bukkit.getWorld(world.getName()); - if (w == null) { - return NullRelighter.INSTANCE; - } - return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue); - } - -} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index f695876cc..9aaeb7bc2 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -23,6 +23,7 @@ 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.datafixers.util.Either; @@ -54,22 +55,9 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -81,6 +69,8 @@ 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; @@ -92,6 +82,7 @@ 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.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.world.Clearable; @@ -122,6 +113,7 @@ 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.v1_20_R2.CraftServer; @@ -134,9 +126,26 @@ import org.bukkit.craftbukkit.v1_20_R2.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -144,6 +153,7 @@ 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; @@ -158,7 +168,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -172,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 @@ -345,7 +371,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { - return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { + return new PaperweightWorldNativeAccess(this, + new WeakReference<>(((CraftWorld) world).getHandle())); } private static net.minecraft.core.Direction adapt(Direction face) { @@ -379,13 +437,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + stateContainer.getProperty(state.getKey().getName()); Comparable value = (Comparable) state.getValue(); // we may need to adapt this value, depending on the source prop if (property instanceof DirectionProperty) { @@ -394,16 +452,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -427,7 +485,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +501,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override @@ -518,7 +594,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> properties = new TreeMap<>(); Block block = getBlockFromType(blockType); StateDefinition blockStateList = - block.getStateDefinition(); + block.getStateDefinition(); for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { Property property = PROPERTY_CACHE.getUnchecked(state); properties.put(property.getName(), property); @@ -527,28 +603,28 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(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); @@ -558,12 +634,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter fakePlayers - = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); @Override public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { @@ -581,7 +657,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -710,7 +787,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -734,7 +811,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -780,12 +857,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -794,7 +871,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -817,51 +933,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -872,14 +986,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -889,44 +1005,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); @@ -977,7 +1092,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -98,24 +97,23 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/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 c6d0b936c..82caa9a92 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 9e69e4a31..a27f01b70 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,20 +24,22 @@ 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_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; @@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -517,7 +517,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 91dcfe24e..23f59e8bf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -364,25 +364,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java index 911da046a..68dbc6b8e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index aa3920ccd..ded4bcfdd 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -23,6 +23,7 @@ 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.datafixers.util.Either; @@ -54,22 +55,9 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -81,6 +69,8 @@ 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; @@ -92,6 +82,7 @@ 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.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.world.Clearable; @@ -122,6 +113,7 @@ 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.v1_20_R3.CraftServer; @@ -134,9 +126,26 @@ import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -144,6 +153,7 @@ 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; @@ -158,7 +168,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -172,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 @@ -345,7 +371,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } @@ -379,13 +436,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + stateContainer.getProperty(state.getKey().getName()); Comparable value = (Comparable) state.getValue(); // we may need to adapt this value, depending on the source prop if (property instanceof DirectionProperty) { @@ -394,16 +451,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -427,7 +484,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -443,9 +500,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { + return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else if (state instanceof DirectionProperty) { + return new DirectionalProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> Direction.valueOf(((StringRepresentable) e) + .getSerializedName() + .toUpperCase(Locale.ROOT))) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { + return new EnumProperty( + state.getName(), + new ArrayList<>((List) state + .getPossibleValues() + .stream() + .map(e -> ((StringRepresentable) e).getSerializedName()) + .toList()) + ); + } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { + return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); + } else { + throw new IllegalArgumentException("WorldEdit needs an update to support " + state + .getClass() + .getSimpleName()); + } + } + }); @SuppressWarnings({ "rawtypes" }) @Override @@ -518,7 +593,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> properties = new TreeMap<>(); Block block = getBlockFromType(blockType); StateDefinition blockStateList = - block.getStateDefinition(); + block.getStateDefinition(); for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { Property property = PROPERTY_CACHE.getUnchecked(state); properties.put(property.getName(), property); @@ -527,28 +602,28 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + __ -> (net.minecraft.nbt.CompoundTag) fromNativeLin(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); @@ -558,7 +633,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -710,7 +786,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -734,7 +810,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.left().orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -780,12 +856,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -794,7 +870,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -817,51 +932,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -872,14 +985,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -889,44 +1004,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); @@ -977,7 +1091,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -99,24 +97,23 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/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 c27f4a59a..83520e453 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 b50ead936..1f51c66ca 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; @@ -70,8 +73,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -517,7 +517,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index f2f78eb7d..b69f476d3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -364,25 +364,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java index 9a8a51896..1d27f17a7 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts index 34e3569eb..1512dca87 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_20_5/build.gradle.kts @@ -12,6 +12,6 @@ repositories { dependencies { // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/ - the().paperDevBundle("1.20.6-R0.1-20240617.192752-122") + the().paperDevBundle("1.20.6-R0.1-20240702.153951-123") compileOnly(libs.paperlib) } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 964be1398..206ade66a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -23,6 +23,7 @@ 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; @@ -54,22 +55,9 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -81,12 +69,13 @@ 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.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; @@ -97,6 +86,7 @@ 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; @@ -127,6 +117,7 @@ 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; @@ -139,9 +130,26 @@ import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.generator.ChunkGenerator; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinEndTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import org.spigotmc.SpigotConfig; import org.spigotmc.WatchdogThread; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -149,6 +157,7 @@ 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; @@ -163,7 +172,6 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -181,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 @@ -375,7 +379,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public BiomeType getBiome(Location location) { + checkNotNull(location); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + + return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString())); + } + + @Override + public void setBiome(Location location, BiomeType biome) { + checkNotNull(location); + checkNotNull(biome); + + CraftWorld craftWorld = ((CraftWorld) location.getWorld()); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + final ServerLevel handle = craftWorld.getHandle(); + LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); + chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id()))))); + chunk.setUnsaved(true); + } + + @Override + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } @@ -409,13 +444,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + stateContainer.getProperty(state.getKey().getName()); Comparable value = (Comparable) state.getValue(); // we may need to adapt this value, depending on the source prop if (property instanceof DirectionProperty) { @@ -424,16 +459,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -457,7 +492,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -473,9 +508,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder .newBuilder() - .build(new CacheLoader>() { + .build(new CacheLoader<>() { @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { + 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(), - (List) state + new ArrayList<>((List) state .getPossibleValues() .stream() .map(e -> Direction.valueOf(((StringRepresentable) e) .getSerializedName() .toUpperCase(Locale.ROOT))) - .collect(Collectors.toList()) + .toList()) ); } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new EnumProperty( state.getName(), - (List) state + new ArrayList<>((List) state .getPossibleValues() .stream() .map(e -> ((StringRepresentable) e).getSerializedName()) - .collect(Collectors.toList()) + .toList()) ); } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); @@ -560,13 +595,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 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); @@ -575,33 +610,33 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + (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 + ((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(); @@ -611,30 +646,30 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount() ); } 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; @@ -645,8 +680,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); map.remove("faweregentempworld"); } catch (IllegalAccessException ignored) { } @@ -775,8 +799,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> chunkLoadings = submitChunkLoadTasks(region, serverWorld); BlockableEventLoop executor; try { @@ -787,7 +810,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -811,7 +834,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -857,12 +880,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -871,7 +894,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -894,51 +956,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -946,17 +1006,19 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -966,44 +1028,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); @@ -1021,7 +1082,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter T fixUp(FixType type, T original, int srcVer) { if (type == FixTypes.CHUNK) { - return (T) fixChunk((CompoundBinaryTag) original, srcVer); + return (T) fixChunk((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_ENTITY) { - return (T) fixBlockEntity((CompoundBinaryTag) original, srcVer); + return (T) fixBlockEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.ENTITY) { - return (T) fixEntity((CompoundBinaryTag) original, srcVer); + return (T) fixEntity((LinCompoundTag) original, srcVer); } else if (type == FixTypes.BLOCK_STATE) { return (T) fixBlockState((String) original, srcVer); } else if (type == FixTypes.ITEM_TYPE) { @@ -101,24 +99,23 @@ public class PaperweightDataConverters extends DataFixerBuilder implements com.s return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); + private LinCompoundTag fixChunk(LinCompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(originalChunk); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); + private LinCompoundTag fixBlockEntity(LinCompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origTileEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - private CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); + private LinCompoundTag fixEntity(LinCompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(origEnt); net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + return (LinCompoundTag) adapter.toNativeLin(fixed); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/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 792942843..baeec90ba 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 f7e5cee3f..c83733bf2 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,20 +24,22 @@ 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.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; @@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - tags.put("Id", StringBinaryTag.of(id)); - return CompoundBinaryTag.from(tags); + final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); + final Map> tags = NbtUtils.getLinCompoundTagValues(tag); + tags.put("Id", LinStringTag.of(id)); + return LinCompoundTag.of(tags); }; return new LazyBaseEntity(type, saveTag); } else { @@ -538,7 +538,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter (CompoundBinaryTag) toNativeBinary(tag)), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)), itemStack.getAmount() ); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java index d66057313..4fa9988b8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweWorldNativeAccess.java @@ -9,15 +9,14 @@ import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; -import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; @@ -25,6 +24,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.lang.ref.WeakReference; @@ -133,14 +133,14 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess iterator = entities.iterator(); while (iterator.hasNext()) { final CompoundTag nativeTag = iterator.next(); - final Map entityTagMap = nativeTag.getValue(); + final Map> entityTagMap = nativeTag.getValue(); final StringTag idTag = (StringTag) entityTagMap.get("Id"); final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 6c0f72590..03eabc698 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -140,7 +140,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldTickingFluidCount.setAccessible(true); fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f")); fieldTickingBlockCount.setAccessible(true); - fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i")); + Field tmpFieldBiomes; + try { + // Seems it's sometimes biomes and sometimes "i". Idk this is just easier than having to try to deal with it + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("biomes"); // apparently unobf + } catch (NoSuchFieldException ignored) { + tmpFieldBiomes = LevelChunkSection.class.getDeclaredField("i"); // apparently obf + } + fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( @@ -353,25 +360,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java index 11d3c940a..52111a4fd 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/nbt/PaperweightLazyCompoundTag.java @@ -6,8 +6,8 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import net.minecraft.nbt.NumericTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.ArrayList; import java.util.Collections; @@ -36,7 +36,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { @Override @SuppressWarnings("unchecked") - public Map getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts similarity index 78% rename from worldedit-bukkit/adapters/adapter-1_19_4/build.gradle.kts rename to worldedit-bukkit/adapters/adapter-1_21/build.gradle.kts index e53d2497e..253af67e6 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/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.19.4-R0.1-SNAPSHOT - the().paperDevBundle("1.19.4-R0.1-20230608.201059-104") + // url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/ + the().paperDevBundle("1.21.1-R0.1-20240811.223934-9") 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java similarity index 63% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index 519620061..b958c8ba7 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -17,24 +17,22 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; +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.datafixers.util.Either; +import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.PaperweightPlatformAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -55,22 +53,9 @@ import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.io.file.SafeFiles; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.RegenOptions; +import com.sk89q.worldedit.world.biome.BiomeCategory; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; @@ -78,21 +63,28 @@ 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.ChunkHolder; +import net.minecraft.server.level.ChunkResult; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.RandomSource; import net.minecraft.util.StringRepresentable; import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.world.Clearable; @@ -113,8 +105,8 @@ import net.minecraft.world.level.block.entity.StructureBlockEntity; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.storage.LevelStorageSource; @@ -123,18 +115,35 @@ 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.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.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; @@ -146,6 +155,7 @@ 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; @@ -166,13 +176,16 @@ 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; 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 // ------------------------------------------------------------------------ @@ -182,25 +195,25 @@ 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 @@ -347,22 +373,17 @@ public final class PaperweightAdapter implements BukkitImplAdapter (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 + @Override public BiomeType getBiome(Location location) { checkNotNull(location); @@ -389,14 +410,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter> 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.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(org.bukkit.World world) { - return new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightWorldNativeAccess(this, - new WeakReference<>(((CraftWorld) world).getHandle())); + public WorldNativeAccess createWorldNativeAccess(World world) { + return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); } private static net.minecraft.core.Direction adapt(Direction face) { @@ -419,13 +439,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter stateContainer, - net.minecraft.world.level.block.state.BlockState newState, - Map, Object> states + StateDefinition stateContainer, + net.minecraft.world.level.block.state.BlockState newState, + Map, Object> states ) { for (Map.Entry, Object> state : states.entrySet()) { net.minecraft.world.level.block.state.properties.Property property = - stateContainer.getProperty(state.getKey().getName()); + stateContainer.getProperty(state.getKey().getName()); Comparable value = (Comparable) state.getValue(); // we may need to adapt this value, depending on the source prop if (property instanceof DirectionProperty) { @@ -434,16 +454,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter) property) - .getValue(enumName).orElseThrow(() -> - new IllegalStateException( - "Enum property " + property.getName() + " does not contain " + enumName - ) - ); + .getValue(enumName).orElseThrow(() -> + new IllegalStateException( + "Enum property " + property.getName() + " does not contain " + enumName + ) + ); } newState = newState.setValue( - (net.minecraft.world.level.block.state.properties.Property) property, - (Comparable) value + (net.minecraft.world.level.block.state.properties.Property) property, + (Comparable) value ); } return newState; @@ -466,8 +486,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter (CompoundBinaryTag) toNativeBinary(tag)) + EntityTypes.get(id), + LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)) ); } @@ -480,21 +500,26 @@ public final class PaperweightAdapter implements BukkitImplAdapter { + loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + return loadedEntity; + }); if (createdEntity != null) { - CompoundBinaryTag nativeTag = state.getNbt(); - if (nativeTag != null) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeBinary(nativeTag); - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - readTagIntoEntity(tag, createdEntity); - } - - createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - - worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); + worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); return createdEntity.getBukkitEntity(); } else { return null; @@ -508,8 +533,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader>() { - @Override - public Property load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { - if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { - return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else if (state instanceof DirectionProperty) { - return new DirectionalProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { - return new EnumProperty(state.getName(), - (List) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); - } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { - return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); - } else { - throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); - } - } - }); + @SuppressWarnings({"unchecked", "rawtypes"}) + private static final LoadingCache> PROPERTY_CACHE = CacheBuilder + .newBuilder() + .build(new CacheLoader<>() { + @Override + public Property load(net.minecraft.world.level.block.state.properties.Property state) { + 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 @@ -558,7 +601,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter> properties = new TreeMap<>(); Block block = getBlockFromType(blockType); StateDefinition blockStateList = - block.getStateDefinition(); + block.getStateDefinition(); for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) { Property property = PROPERTY_CACHE.getUnchecked(state); properties.put(property.getName(), property); @@ -567,62 +610,73 @@ public final class PaperweightAdapter implements BukkitImplAdapter (net.minecraft.nbt.CompoundTag) fromNativeBinary(nbtData) + structureBlock, + (blockEntity, registryAccess) -> (net.minecraft.nbt.CompoundTag) fromNativeLin(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( - ((CraftPlayer) player).getHandle(), (byte) 28 + ((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 item) { + public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { + var registryAccess = DedicatedServer.getServer().registryAccess(); ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())), - item.getAmount() + registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), + baseItemStack.getAmount() ); - stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); + 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); - final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount()); - weStack.setNbt(((CompoundBinaryTag) toNativeBinary(nmsStack.getTag()))); - return weStack; + 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)); + = 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(BukkitAdapter.adapt(item instanceof BaseItemStack - ? ((BaseItemStack) item) : new BaseItemStack(item.getType(), item.getNbtData(), 1))); - stack.setTag((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())); + ItemStack stack = CraftItemStack.asNMSCopy(adapt( + item instanceof BaseItemStack + ? ((BaseItemStack) item) + : new BaseItemStack(item.getType(), item.getNbtReference(), 1) + )); PaperweightFakePlayer fakePlayer; try { @@ -632,7 +686,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter worldDimKey = getWorldDimKey(env); - try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { + try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", 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() + "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; + 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); @@ -733,8 +788,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("worldeditregentempworld"); } catch (IllegalAccessException ignored) { } SafeFiles.tryHardToDeleteDir(tempDir); @@ -761,7 +816,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter { // bail out early if a future fails if (chunkLoadings.stream().anyMatch(ftr -> - ftr.isDone() && Futures.getUnchecked(ftr) == null + ftr.isDone() && Futures.getUnchecked(ftr) == null )) { return false; } @@ -784,8 +839,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter (LinCompoundTag) toNativeLin(tag))); } extent.setBlock(vec, state.toBaseBlock()); if (options.shouldRegenBiomes()) { @@ -807,9 +862,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter>) - getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) - .thenApply(either -> either.left().orElse(null)) + ((CompletableFuture>) + getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) + .thenApply(either -> either.orElse(null)) ); } catch (IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException("Couldn't load chunk for regen.", e); @@ -831,12 +886,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + SideEffect.NEIGHBORS, + SideEffect.LIGHTING, + SideEffect.VALIDATION, + SideEffect.ENTITY_AI, + SideEffect.EVENTS, + SideEffect.UPDATE ); @Override @@ -845,7 +900,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); + biomeRegistry.getTagNames().forEach(tagKey -> { + String key = tagKey.location().toString(); + if (BiomeCategory.REGISTRY.get(key) == null) { + BiomeCategory.REGISTRY.register(key, new BiomeCategory( + key, + () -> biomeRegistry.getTag(tagKey) + .stream() + .flatMap(HolderSet.Named::stream) + .map(Holder::value) + .map(this::adapt) + .collect(Collectors.toSet())) + ); + } + }); + } + + @Override + public void sendBiomeUpdates(World world, Iterable chunks) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + + List nativeChunks = chunks instanceof Collection chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList(); + for (BlockVector2 chunk : chunks) { + nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false)); + } + originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); + } // ------------------------------------------------------------------------ // Code that is less likely to break @@ -879,51 +962,49 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLin(net.minecraft.nbt.Tag foreign) { if (foreign == null) { return null; } if (foreign instanceof net.minecraft.nbt.CompoundTag) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); Set foreignKeys = ((net.minecraft.nbt.CompoundTag) foreign).getAllKeys(); for (String str : foreignKeys) { net.minecraft.nbt.Tag base = ((net.minecraft.nbt.CompoundTag) foreign).get(str); - values.put(str, toNativeBinary(base)); + values.put(str, toNativeLin(base)); } - return CompoundBinaryTag.from(values); + return LinCompoundTag.of(values); } else if (foreign instanceof net.minecraft.nbt.ByteTag) { - return ByteBinaryTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); + return LinByteTag.of(((net.minecraft.nbt.ByteTag) foreign).getAsByte()); } else if (foreign instanceof net.minecraft.nbt.ByteArrayTag) { - return ByteArrayBinaryTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); + return LinByteArrayTag.of(((net.minecraft.nbt.ByteArrayTag) foreign).getAsByteArray()); } else if (foreign instanceof net.minecraft.nbt.DoubleTag) { - return DoubleBinaryTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); + return LinDoubleTag.of(((net.minecraft.nbt.DoubleTag) foreign).getAsDouble()); } else if (foreign instanceof net.minecraft.nbt.FloatTag) { - return FloatBinaryTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); + return LinFloatTag.of(((net.minecraft.nbt.FloatTag) foreign).getAsFloat()); } else if (foreign instanceof net.minecraft.nbt.IntTag) { - return IntBinaryTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); + return LinIntTag.of(((net.minecraft.nbt.IntTag) foreign).getAsInt()); } else if (foreign instanceof net.minecraft.nbt.IntArrayTag) { - return IntArrayBinaryTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); + return LinIntArrayTag.of(((net.minecraft.nbt.IntArrayTag) foreign).getAsIntArray()); } else if (foreign instanceof net.minecraft.nbt.LongArrayTag) { - return LongArrayBinaryTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); + return LinLongArrayTag.of(((net.minecraft.nbt.LongArrayTag) foreign).getAsLongArray()); } else if (foreign instanceof net.minecraft.nbt.ListTag) { try { - return toNativeList((net.minecraft.nbt.ListTag) foreign); + return toNativeLinList((net.minecraft.nbt.ListTag) foreign); } catch (Throwable e) { - LOGGER.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); - return ListBinaryTag.empty(); + logger.log(Level.WARNING, "Failed to convert net.minecraft.nbt.ListTag", e); } } else if (foreign instanceof net.minecraft.nbt.LongTag) { - return LongBinaryTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); + return LinLongTag.of(((net.minecraft.nbt.LongTag) foreign).getAsLong()); } else if (foreign instanceof net.minecraft.nbt.ShortTag) { - return ShortBinaryTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); + return LinShortTag.of(((net.minecraft.nbt.ShortTag) foreign).getAsShort()); } else if (foreign instanceof net.minecraft.nbt.StringTag) { - return StringBinaryTag.of(foreign.getAsString()); + return LinStringTag.of(foreign.getAsString()); } else if (foreign instanceof net.minecraft.nbt.EndTag) { - return EndBinaryTag.get(); - } else { - throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); + return LinEndTag.instance(); } + throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName()); } /** @@ -934,14 +1015,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter toNativeLinList(net.minecraft.nbt.ListTag foreign) throws SecurityException, IllegalArgumentException { + LinListTag.Builder> builder = LinListTag.builder( + LinTagType.fromId(LinTagId.fromId(foreign.getElementType())) + ); for (net.minecraft.nbt.Tag tag : foreign) { - values.add(toNativeBinary(tag)); + builder.add(toNativeLin(tag)); } - return values.build(); + return builder.build(); } /** @@ -951,44 +1034,43 @@ public final class PaperweightAdapter implements BukkitImplAdapter foreign) { if (foreign == null) { return null; } - if (foreign instanceof CompoundBinaryTag) { + if (foreign instanceof LinCompoundTag compoundTag) { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - for (String key : ((CompoundBinaryTag) foreign).keySet()) { - tag.put(key, fromNativeBinary(((CompoundBinaryTag) foreign).get(key))); + for (var entry : compoundTag.value().entrySet()) { + tag.put(entry.getKey(), fromNativeLin(entry.getValue())); } return tag; - } else if (foreign instanceof ByteBinaryTag) { - return net.minecraft.nbt.ByteTag.valueOf(((ByteBinaryTag) foreign).value()); - } else if (foreign instanceof ByteArrayBinaryTag) { - return new net.minecraft.nbt.ByteArrayTag(((ByteArrayBinaryTag) foreign).value()); - } else if (foreign instanceof DoubleBinaryTag) { - return net.minecraft.nbt.DoubleTag.valueOf(((DoubleBinaryTag) foreign).value()); - } else if (foreign instanceof FloatBinaryTag) { - return net.minecraft.nbt.FloatTag.valueOf(((FloatBinaryTag) foreign).value()); - } else if (foreign instanceof IntBinaryTag) { - return net.minecraft.nbt.IntTag.valueOf(((IntBinaryTag) foreign).value()); - } else if (foreign instanceof IntArrayBinaryTag) { - return new net.minecraft.nbt.IntArrayTag(((IntArrayBinaryTag) foreign).value()); - } else if (foreign instanceof LongArrayBinaryTag) { - return new net.minecraft.nbt.LongArrayTag(((LongArrayBinaryTag) foreign).value()); - } else if (foreign instanceof ListBinaryTag) { + } else if (foreign instanceof LinByteTag byteTag) { + return net.minecraft.nbt.ByteTag.valueOf(byteTag.valueAsByte()); + } else if (foreign instanceof LinByteArrayTag byteArrayTag) { + return new net.minecraft.nbt.ByteArrayTag(byteArrayTag.value()); + } else if (foreign instanceof LinDoubleTag doubleTag) { + return net.minecraft.nbt.DoubleTag.valueOf(doubleTag.valueAsDouble()); + } else if (foreign instanceof LinFloatTag floatTag) { + return net.minecraft.nbt.FloatTag.valueOf(floatTag.valueAsFloat()); + } else if (foreign instanceof LinIntTag intTag) { + return net.minecraft.nbt.IntTag.valueOf(intTag.valueAsInt()); + } else if (foreign instanceof LinIntArrayTag intArrayTag) { + return new net.minecraft.nbt.IntArrayTag(intArrayTag.value()); + } else if (foreign instanceof LinLongArrayTag longArrayTag) { + return new net.minecraft.nbt.LongArrayTag(longArrayTag.value()); + } else if (foreign instanceof LinListTag listTag) { net.minecraft.nbt.ListTag tag = new net.minecraft.nbt.ListTag(); - ListBinaryTag foreignList = (ListBinaryTag) foreign; - for (BinaryTag t : foreignList) { - tag.add(fromNativeBinary(t)); + for (var t : listTag.value()) { + tag.add(fromNativeLin(t)); } return tag; - } else if (foreign instanceof LongBinaryTag) { - return net.minecraft.nbt.LongTag.valueOf(((LongBinaryTag) foreign).value()); - } else if (foreign instanceof ShortBinaryTag) { - return net.minecraft.nbt.ShortTag.valueOf(((ShortBinaryTag) foreign).value()); - } else if (foreign instanceof StringBinaryTag) { - return net.minecraft.nbt.StringTag.valueOf(((StringBinaryTag) foreign).value()); - } else if (foreign instanceof EndBinaryTag) { + } else if (foreign instanceof LinLongTag longTag) { + return net.minecraft.nbt.LongTag.valueOf(longTag.valueAsLong()); + } else if (foreign instanceof LinShortTag shortTag) { + return net.minecraft.nbt.ShortTag.valueOf(shortTag.valueAsShort()); + } else if (foreign instanceof LinStringTag stringTag) { + return net.minecraft.nbt.StringTag.valueOf(stringTag.value()); + } else if (foreign instanceof LinEndTag) { return net.minecraft.nbt.EndTag.INSTANCE; } else { throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName()); @@ -1027,7 +1109,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter. */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -29,18 +29,21 @@ import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; -import com.mojang.datafixers.DSL; import com.mojang.datafixers.DSL.TypeReference; import com.mojang.datafixers.DataFixer; -import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.schemas.Schema; import com.mojang.serialization.Dynamic; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; 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; @@ -48,7 +51,9 @@ import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.item.DyeColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import javax.annotation.Nullable; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.EnumMap; @@ -60,34 +65,37 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.UUID; -import java.util.concurrent.Executor; import java.util.stream.Collectors; -import javax.annotation.Nullable; /** * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) * + *

* We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy * which is safer, faster and cleaner code. + *

* + *

* The pre DFU code did not fail when the Source version was unknown. + *

* + *

* This class also provides util methods for converting compounds to wrap the update call to * receive the source version in the compound + *

*/ @SuppressWarnings({ "rawtypes", "unchecked" }) -class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { +class PaperweightDataConverters 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,52 +106,51 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return original; } - private CompoundBinaryTag fixChunk(CompoundBinaryTag originalChunk, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(originalChunk); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + 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 CompoundBinaryTag fixBlockEntity(CompoundBinaryTag origTileEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origTileEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + private 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 CompoundBinaryTag fixEntity(CompoundBinaryTag origEnt, int srcVer) { - net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeBinary(origEnt); - net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); - return (CompoundBinaryTag) adapter.toNativeBinary(fixed); + 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); } - //FAWE end private String fixBlockState(String blockState, int srcVer) { - net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); - Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); - net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(References.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + 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(net.minecraft.nbt.CompoundTag tagCompound) { + private String nbtToState(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"); + 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) { + private static CompoundTag stateToNBT(String blockState) { int propIdx = blockState.indexOf('['); - net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + CompoundTag tag = new 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(); + CompoundTag propTag = new CompoundTag(); String props = blockState.substring(propIdx + 1, blockState.length() - 1); String[] propArr = props.split(","); for (String pair : propArr) { @@ -164,8 +171,8 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } 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(); + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, StringTag.valueOf(key)), srcVer, DATA_VERSION) + .getValue().getAsString(); } private final PaperweightAdapter adapter; @@ -205,24 +212,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } 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(); + this.fixer = new WrappedDataFixer(DataFixers.getDataFixer()); } @SuppressWarnings("unchecked") @@ -237,7 +232,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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(); + CompoundTag cmp = (CompoundTag) dynamic.getValue(); int desiredVersion = Math.min(targetVer, LEGACY_VERSION); cmp = convert(legacyType, cmp, sourceVer, desiredVersion); @@ -247,7 +242,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return realFixer.update(type, dynamic, sourceVer, targetVer); } - private net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int desiredVersion) { + 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) { @@ -274,44 +269,44 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } } - public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { + public static CompoundTag convert(LegacyType type, CompoundTag cmp) { return convert(type.getDFUType(), cmp); } - public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + public static CompoundTag convert(LegacyType type, 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) { + public static CompoundTag convert(LegacyType type, 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) { + 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 net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + public static CompoundTag convert(TypeReference type, 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) { + public static CompoundTag convert(TypeReference type, 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(); + return (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); + CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer); } public interface DataConverter { int getDataVersion(); - net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); + CompoundTag convert(CompoundTag cmp); } @@ -471,114 +466,114 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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")); + 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) { @@ -589,19 +584,19 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return key; } - private static void convertCompound(LegacyType type, net.minecraft.nbt.CompoundTag cmp, String key, int sourceVer, int targetVer) { + 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(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int 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(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + private static void convertItems(CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { if (nbttagcompound.contains(key, 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound.getList(key, 10); + 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)); @@ -619,19 +614,19 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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; + public CompoundTag convert(CompoundTag cmp) { + ListTag nbttaglist = cmp.getList("Equipment", 10); + ListTag nbttaglist1; if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); + nbttaglist1 = new ListTag(); nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); + nbttaglist1.add(new CompoundTag()); cmp.put("HandItems", nbttaglist1); } if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new net.minecraft.nbt.ListTag(); + nbttaglist1 = new ListTag(); nbttaglist1.add(nbttaglist.get(1)); nbttaglist1.add(nbttaglist.get(2)); nbttaglist1.add(nbttaglist.get(3)); @@ -642,21 +637,21 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo cmp.remove("Equipment"); if (cmp.contains("DropChances", 9)) { nbttaglist1 = cmp.getList("DropChances", 5); - net.minecraft.nbt.ListTag nbttaglist2; + 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)); + 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 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))); + 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); } @@ -677,7 +672,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo @Nullable private static String convertEntityId(int i, String s) { - String key = new ResourceLocation(s).toString(); + String key = ResourceLocation.parse(s).toString(); if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { return DataInspectorBlockEntity.b.get(key); } else { @@ -685,14 +680,14 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } } - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { if (!cmp.contains("tag", 10)) { return cmp; } else { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); String s = cmp.getString("id"); String s1 = convertEntityId(sourceVer, s); boolean flag; @@ -814,11 +809,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo DataInspectorEntity() { } - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("EntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); String s = cmp.getString("id"); String s1; @@ -856,15 +851,15 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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")))) { + 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 net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer); + abstract CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer); } private static class DataInspectorItemList extends DataInspectorTagged { @@ -876,7 +871,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo this.keys = astring; } - net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer) { for (String s : this.keys) { PaperweightDataConverters.convertItems(nbttagcompound, s, sourceVer, targetVer); } @@ -894,7 +889,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo this.keys = astring; } - net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + CompoundTag inspectChecked(CompoundTag nbttagcompound, int sourceVer, int targetVer) { for (String key : this.keys) { PaperweightDataConverters.convertItem(nbttagcompound, key, sourceVer, targetVer); } @@ -914,7 +909,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 102; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if (cmp.contains("id", 99)) { short short0 = cmp.getShort("id"); @@ -1294,7 +1289,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 147; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { cmp.remove("Silent"); } @@ -1312,20 +1307,20 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 804; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + 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"); + CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); if (nbttagcompound3.contains("Lore", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound3.getList("Lore", 8); + ListTag nbttaglist = nbttagcompound3.getList("Lore", 8); if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { return cmp; @@ -1360,9 +1355,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 102; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:potion".equals(cmp.getString("id"))) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); short short0 = cmp.getShort("Damage"); if (!nbttagcompound1.contains("Potion", 8)) { @@ -1526,10 +1521,10 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 105; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(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"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); short short0 = cmp.getShort("Damage"); if (!nbttagcompound2.contains("id", 8)) { @@ -1633,7 +1628,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 106; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("Minecart".equals(cmp.getString("id"))) { String s = "MinecartRideable"; int i = cmp.getInt("Type"); @@ -1659,13 +1654,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 107; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(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"); + CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); cmp.put("SpawnData", nbttagcompound1); @@ -1673,13 +1668,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo } if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); for (int i = 0; i < nbttaglist.size(); ++i) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); + CompoundTag nbttagcompound2 = nbttaglist.getCompound(i); if (nbttagcompound2.contains("Type", 8)) { - net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound2.getCompound("Properties"); + CompoundTag nbttagcompound3 = nbttagcompound2.getCompound("Properties"); nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); nbttagcompound2.put("Entity", nbttagcompound3); @@ -1703,7 +1698,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 108; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if (cmp.contains("UUID", 8)) { cmp.putUUID("UUID", UUID.fromString(cmp.getString("UUID"))); } @@ -1723,7 +1718,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 109; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if (DataConverterHealth.a.contains(cmp.getString("id"))) { float f; @@ -1754,9 +1749,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 110; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(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(); + CompoundTag nbttagcompound1 = new CompoundTag(); nbttagcompound1.putString("id", "minecraft:saddle"); nbttagcompound1.putByte("Count", (byte) 1); @@ -1778,7 +1773,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 111; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { String s = cmp.getString("id"); boolean flag = "Painting".equals(s); boolean flag1 = "ItemFrame".equals(s); @@ -1816,8 +1811,8 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 113; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { - net.minecraft.nbt.ListTag nbttaglist; + public CompoundTag convert(CompoundTag cmp) { + ListTag nbttaglist; if (cmp.contains("HandDropChances", 9)) { nbttaglist = cmp.getList("HandDropChances", 5); @@ -1846,9 +1841,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 135; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { while (cmp.contains("Riding", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = this.b(cmp); + CompoundTag nbttagcompound1 = this.b(cmp); this.convert(cmp, nbttagcompound1); cmp = nbttagcompound1; @@ -1857,15 +1852,15 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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(); + protected void convert(CompoundTag nbttagcompound, CompoundTag nbttagcompound1) { + ListTag nbttaglist = new ListTag(); nbttaglist.add(nbttagcompound); nbttagcompound1.put("Passengers", nbttaglist); } - protected net.minecraft.nbt.CompoundTag b(net.minecraft.nbt.CompoundTag nbttagcompound) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); + protected CompoundTag b(CompoundTag nbttagcompound) { + CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); nbttagcompound.remove("Riding"); return nbttagcompound1; @@ -1881,12 +1876,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 165; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:written_book".equals(cmp.getString("id"))) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("pages", 9)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + ListTag nbttaglist = nbttagcompound1.getList("pages", 8); for (int i = 0; i < nbttaglist.size(); ++i) { String s = nbttaglist.getString(i); @@ -1907,7 +1902,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (object == null) { try { - object = Component.Serializer.fromJson(s); + object = Component.Serializer.fromJson(s, MinecraftServer.getServer().registryAccess()); } catch (JsonParseException jsonparseexception1) { ; } @@ -1915,7 +1910,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (object == null) { try { - object = Component.Serializer.fromJsonLenient(s); + object = Component.Serializer.fromJsonLenient(s, MinecraftServer.getServer().registryAccess()); } catch (JsonParseException jsonparseexception2) { ; } @@ -1929,7 +1924,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo object = Component.literal(""); } - nbttaglist.set(i, net.minecraft.nbt.StringTag.valueOf(Component.Serializer.toJson(object))); + nbttaglist.set(i, StringTag.valueOf(Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess()))); } nbttagcompound1.put("pages", nbttaglist); @@ -1942,7 +1937,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataConverterCookedFish implements DataConverter { - private static final ResourceLocation a = new ResourceLocation("cooked_fished"); + private static final ResourceLocation a = ResourceLocation.parse("cooked_fished"); DataConverterCookedFish() { } @@ -1951,8 +1946,8 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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")))) { + public CompoundTag convert(CompoundTag cmp) { + if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(ResourceLocation.parse(cmp.getString("id")))) { cmp.putString("id", "minecraft:cooked_fish"); } @@ -1971,7 +1966,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 502; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { if (!cmp.contains("ZombieType", 99)) { int i = -1; @@ -2011,7 +2006,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 505; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { cmp.putString("useVbo", "true"); return cmp; } @@ -2026,7 +2021,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 700; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("Guardian".equals(cmp.getString("id"))) { if (cmp.getBoolean("Elder")) { cmp.putString("id", "ElderGuardian"); @@ -2048,7 +2043,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 701; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { String s = cmp.getString("id"); if ("Skeleton".equals(s)) { @@ -2076,7 +2071,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 702; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("Zombie".equals(cmp.getString("id"))) { int i = cmp.getInt("ZombieType"); @@ -2114,7 +2109,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 703; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("EntityHorse".equals(cmp.getString("id"))) { int i = cmp.getInt("Type"); @@ -2158,7 +2153,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 704; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { String s = DataConverterTileEntity.a.get(cmp.getString("id")); if (s != null) { @@ -2206,7 +2201,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 704; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { String s = DataConverterEntity.a.get(cmp.getString("id")); if (s != null) { @@ -2304,11 +2299,11 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 806; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + 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)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); if (!nbttagcompound1.contains("Potion", 8)) { nbttagcompound1.putString("Potion", "minecraft:water"); @@ -2332,7 +2327,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 808; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.contains("Color", 99)) { cmp.putByte("Color", (byte) 10); } @@ -2352,12 +2347,12 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 813; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + CompoundTag nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("BlockEntityTag", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); if (nbttagcompound2.getList("Items", 10).isEmpty()) { nbttagcompound2.remove("Items"); @@ -2391,7 +2386,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 813; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:shulker".equals(cmp.getString("id"))) { cmp.remove("Color"); } @@ -2409,7 +2404,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 816; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if (cmp.contains("lang", 8)) { cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); } @@ -2427,7 +2422,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 820; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:totem".equals(cmp.getString("id"))) { cmp.putString("id", "minecraft:totem_of_undying"); } @@ -2447,16 +2442,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 1125; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { try { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + 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); + ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); + ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); for (int k = 0; k < nbttaglist1.size(); ++k) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist1.getCompound(k); + CompoundTag nbttagcompound2 = nbttaglist1.getCompound(k); byte b0 = nbttagcompound2.getByte("Y"); byte[] abyte = nbttagcompound2.getByteArray("Blocks"); @@ -2465,7 +2460,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo int i1 = l & 15; int j1 = l >> 8 & 15; int k1 = l >> 4 & 15; - net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); + CompoundTag nbttagcompound3 = new CompoundTag(); nbttagcompound3.putString("id", "bed"); nbttagcompound3.putInt("x", i1 + (i << 4)); @@ -2492,7 +2487,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 1125; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { cmp.putShort("Damage", (short) DyeColor.RED.getId()); } @@ -2541,7 +2536,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return 101; } - public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + public CompoundTag convert(CompoundTag cmp) { if ("Sign".equals(cmp.getString("id"))) { this.convert(cmp, "Text1"); this.convert(cmp, "Text2"); @@ -2552,7 +2547,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo return cmp; } - private void convert(net.minecraft.nbt.CompoundTag nbttagcompound, String s) { + private void convert(CompoundTag nbttagcompound, String s) { String s1 = nbttagcompound.getString(s); Component object = null; @@ -2571,7 +2566,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (object == null) { try { - object = Component.Serializer.fromJson(s1); + object = Component.Serializer.fromJson(s1, MinecraftServer.getServer().registryAccess()); } catch (JsonParseException jsonparseexception1) { ; } @@ -2579,7 +2574,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo if (object == null) { try { - object = Component.Serializer.fromJsonLenient(s1); + object = Component.Serializer.fromJsonLenient(s1, MinecraftServer.getServer().registryAccess()); } catch (JsonParseException jsonparseexception2) { ; } @@ -2593,15 +2588,15 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo object = Component.literal(""); } - nbttagcompound.putString(s, Component.Serializer.toJson(object)); + nbttagcompound.putString(s, Component.Serializer.toJson(object, MinecraftServer.getServer().registryAccess())); } } private static class DataInspectorPlayerVehicle implements DataInspector { @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { if (cmp.contains("RootVehicle", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("RootVehicle"); + CompoundTag nbttagcompound1 = cmp.getCompound("RootVehicle"); if (nbttagcompound1.contains("Entity", 10)) { convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); @@ -2614,7 +2609,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataInspectorLevelPlayer implements DataInspector { @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { if (cmp.contains("Player", 10)) { convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); } @@ -2625,16 +2620,16 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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; + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + ListTag nbttaglist; int j; - net.minecraft.nbt.CompoundTag nbttagcompound1; + 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); + nbttagcompound1 = (CompoundTag) nbttaglist.get(j); if (nbttagcompound1.contains("nbt", 10)) { convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); } @@ -2645,7 +2640,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo nbttaglist = cmp.getList("blocks", 10); for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + nbttagcompound1 = (CompoundTag) nbttaglist.get(j); if (nbttagcompound1.contains("nbt", 10)) { convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); } @@ -2658,17 +2653,17 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataInspectorChunks implements DataInspector { @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { if (cmp.contains("Level", 10)) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); - net.minecraft.nbt.ListTag nbttaglist; + 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, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + nbttaglist.set(j, convert(LegacyType.ENTITY, (CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); } } @@ -2676,7 +2671,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo nbttaglist = nbttagcompound1.getList("TileEntities", 10); for (j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); } } } @@ -2687,9 +2682,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataInspectorEntityPassengers implements DataInspector { @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { if (cmp.contains("Passengers", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("Passengers", 10); + 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)); @@ -2702,7 +2697,7 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo private static class DataInspectorPlayer implements DataInspector { @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { convertItems(cmp, "Inventory", sourceVer, targetVer); convertItems(cmp, "EnderItems", sourceVer, targetVer); if (cmp.contains("ShoulderEntityLeft", 10)) { @@ -2721,15 +2716,15 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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"); + 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)) { - net.minecraft.nbt.ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); + CompoundTag nbttagcompound2 = nbttaglist.getCompound(j); convertItem(nbttagcompound2, "buy", sourceVer, targetVer); convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); @@ -2748,9 +2743,9 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @Override - public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { String s = cmp.getString("id"); - if (entityMinecartMobSpawner.equals(new ResourceLocation(s))) { + if (entityMinecartMobSpawner.equals(ResourceLocation.parse(s))) { cmp.putString("id", tileEntityMobSpawner.toString()); convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); cmp.putString("id", s); @@ -2764,13 +2759,13 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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")))) { + public CompoundTag inspect(CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(ResourceLocation.parse(cmp.getString("id")))) { if (cmp.contains("SpawnPotentials", 9)) { - net.minecraft.nbt.ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); for (int j = 0; j < nbttaglist.size(); ++j) { - net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttaglist.getCompound(j); + CompoundTag nbttagcompound1 = nbttaglist.getCompound(j); convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); } @@ -2787,8 +2782,8 @@ class PaperweightDataConverters extends DataFixerBuilder implements com.sk89q.wo 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")))) { + 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"); 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java similarity index 81% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightFakePlayer.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java index 87dca94f2..d9c89b0e3 100644 --- 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightFakePlayer.java @@ -17,20 +17,20 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; +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.network.protocol.game.ServerboundClientInformationPacket; +import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.stats.Stat; import net.minecraft.world.MenuProvider; import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.phys.Vec3; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import java.util.OptionalInt; import java.util.UUID; @@ -38,9 +38,12 @@ 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); + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO); } @Override @@ -56,18 +59,13 @@ class PaperweightFakePlayer extends ServerPlayer { 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) { + public void updateOptions(ClientInformation clientOptions) { } @Override 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java similarity index 84% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightWorldNativeAccess.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java index dc44a165a..d51295053 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightWorldNativeAccess.java @@ -17,9 +17,8 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; +package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; @@ -27,17 +26,20 @@ import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; +import org.bukkit.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; @@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess + * Copyright (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_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_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 similarity index 76% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightBlockMaterial.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java index 826874f57..359527396 100644 --- 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightBlockMaterial.java @@ -1,27 +1,24 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; +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.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.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.LiquidBlock; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.PushReaction; -import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.block.data.CraftBlockData; public class PaperweightBlockMaterial implements BlockMaterial { private final Block block; private final BlockState blockState; - private final boolean isTranslucent; private final CraftBlockData craftBlockData; private final org.bukkit.Material craftMaterial; private final int opacity; @@ -36,19 +33,14 @@ public class PaperweightBlockMaterial implements BlockMaterial { this.blockState = blockState; this.craftBlockData = CraftBlockData.fromData(blockState); this.craftMaterial = craftBlockData.getMaterial(); - BlockBehaviour.Properties blockInfo = ReflectionUtil.getField(BlockBehaviour.class, block, - Refraction.pickName("properties", "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)); + tile = tileEntity == null ? null : new PaperweightLazyCompoundTag( + Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); } public Block getBlock() { @@ -75,7 +67,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isOpaque() { - return blockState.isOpaque(); + return blockState.canOcclude(); } @Override @@ -85,14 +77,13 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isLiquid() { - // TODO: Better check ? - return block instanceof LiquidBlock; + return !blockState.getFluidState().is(Fluids.EMPTY); } @Override public boolean isSolid() { - // TODO: Replace - return blockState.isSolid(); + // No access to world -> EmptyBlockGetter + return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO); } @Override @@ -132,7 +123,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isTicksRandomly() { - return block.isRandomlyTicking(blockState); + return blockState.isRandomlyTicking(); } @Override @@ -158,7 +149,7 @@ public class PaperweightBlockMaterial implements BlockMaterial { @Override public boolean isTranslucent() { - return isTranslucent; + return !blockState.canOcclude(); } @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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java similarity index 86% rename from worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightFaweAdapter.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 688c218c6..11577ca9e 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; @@ -12,13 +12,12 @@ import com.fastasyncworldedit.core.util.NbtUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Codec; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_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.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; @@ -34,10 +33,8 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -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; @@ -51,8 +48,12 @@ 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; @@ -75,14 +76,17 @@ 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.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; @@ -108,6 +112,9 @@ public final class PaperweightFaweAdapter extends FaweAdapter COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf( + "components", DataComponentPatch.EMPTY + ).codec(); static { try { @@ -116,7 +123,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter>> allBlockProperties = null; public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException { - this.parent = new PaperweightAdapter(); + this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter(); } @Nullable @@ -136,6 +143,10 @@ public final class PaperweightFaweAdapter extends FaweAdapter getParent() { return parent; @@ -228,7 +239,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter saveTag = () -> { + Supplier saveTag = () -> { final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(mcEntity, minecraftTag); + readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work - final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag); - final Map tags = NbtUtils.getCompoundBinaryTagValues(tag); - 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 { @@ -478,12 +489,18 @@ public final class PaperweightFaweAdapter extends FaweAdapter (LinCompoundTag) toNativeLin(tag)), + itemStack.getAmount() + ); } @Override @@ -533,7 +557,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); - private static final Function nmsTile2We = - tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId)); + private static final Function nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag( + Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess())) + ); private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin .getInstance() .getBukkitImplAdapter()); @@ -263,7 +265,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (blockEntity == null) { return null; } - return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)); + return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))); } @Override @@ -336,7 +338,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc @Override public CompoundTag getEntity(UUID uuid) { - Entity entity = serverLevel.getEntity(uuid); + ensureLoaded(serverLevel, chunkX, chunkZ); + List entities = PaperweightPlatformAdapter.getEntities(getChunk()); + Entity entity = null; + for (Entity e : entities) { + if (e.getUUID().equals(uuid)) { + entity = e; + break; + } + } if (entity != null) { org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); @@ -388,7 +398,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc public Iterator iterator() { Iterable result = entities.stream().map(input -> { net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(input, tag); + input.save(tag); return (CompoundTag) adapter.toNative(tag); }).collect(Collectors.toList()); return result.iterator(); @@ -541,9 +551,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc // Don't attempt to tick section whilst we're editing if (existingSection != null) { PaperweightPlatformAdapter.clearCounts(existingSection); - if (PaperLib.isPaper()) { - existingSection.tickingList.clear(); - } } if (createCopy) { @@ -590,9 +597,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc //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 @@ -634,9 +638,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc biomeRegistry, biomeData != null ? biomeData : (PalettedContainer>) existingSection.getBiomes() ); - if (!PaperweightPlatformAdapter.setSectionAtomic( - levelChunkSections, - existingSection, + if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection, newSection, getSectionIndex )) { @@ -730,7 +732,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc 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"); @@ -803,7 +805,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc tag.put("x", IntTag.valueOf(x)); tag.put("y", IntTag.valueOf(y)); tag.put("z", IntTag.valueOf(z)); - tileEntity.load(tag); + tileEntity.loadWithComponents(tag, DedicatedServer.getServer().registryAccess()); } } } 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java similarity index 96% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java index d2412b98f..a0a4d02d9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks_Copy.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightGetBlocks_Copy.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; +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; @@ -8,7 +8,7 @@ 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.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; @@ -16,6 +16,7 @@ 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; @@ -62,7 +63,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { blockEntity.getBlockPos().getY(), blockEntity.getBlockPos().getZ() ), - new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId)) + new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))) ); } @@ -81,7 +82,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet { protected void storeEntity(Entity entity) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - PaperweightPlatformAdapter.readEntityIntoTag(entity, compoundTag); + entity.save(compoundTag); entities.add((CompoundTag) adapter.toNative(compoundTag)); } 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java similarity index 88% rename from worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightMapChunkUtil.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java index 7c7f39d9a..6819e5466 100644 --- 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightMapChunkUtil.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -10,10 +10,10 @@ public class PaperweightMapChunkUtil extends MapChunkUtil serverLevel .getChunkSource() - .addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); + .addRegionTicket(ChunkHolderManager.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE)); } public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) { @@ -362,10 +336,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { .getChunkSource() .getChunkAtIfLoadedImmediately(chunkX, chunkZ); } else { - levelChunk = ((Optional) ((Either) chunkHolder - .getTickingChunkFuture() // method is not present with new paper chunk system - .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left()) - .orElse(null); + levelChunk = chunkHolder.getTickingChunkFuture() + .getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null); } if (levelChunk == null) { return; @@ -373,25 +345,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { MinecraftServer.getServer().execute(() -> { ClientboundLevelChunkWithLightPacket packet; if (PaperLib.isPaper()) { - synchronized (chunk) { - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null, - false // last false is to not bother with x-ray - ); - } + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null, + false // last false is to not bother with x-ray + ); } else { - synchronized (chunk) { - // deprecated on paper - deprecation suppressed - packet = new ClientboundLevelChunkWithLightPacket( - levelChunk, - nmsWorld.getChunkSource().getLightEngine(), - null, - null - ); - } + // deprecated on paper - deprecation suppressed + packet = new ClientboundLevelChunkWithLightPacket( + levelChunk, + nmsWorld.getChunkSource().getLightEngine(), + null, + null + ); } nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet)); }); @@ -673,49 +641,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { } 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 + //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)); - } - 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); + throw new RuntimeException("Failed to lookup entities [PAPER=false]", e); } } 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java similarity index 99% rename from worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPostProcessor.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java index ac10f2c0a..3b4c47087 100644 --- 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPostProcessor.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; 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_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java similarity index 85% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java index 7de83af21..f9d06922e 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightStarlightRelighter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightStarlightRelighter.java @@ -1,4 +1,4 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1; +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter; import com.fastasyncworldedit.core.configuration.Settings; @@ -8,7 +8,8 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.TicketType; import net.minecraft.util.Unit; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -18,7 +19,9 @@ 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); + 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); @@ -51,7 +54,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter getValue() { + public Map> getValue() { if (compoundTag == null) { compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get()); } @@ -44,9 +44,9 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @Override - public CompoundBinaryTag asBinaryTag() { + public LinCompoundTag toLinTag() { getValue(); - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); } public boolean containsKey(String key) { @@ -94,10 +94,10 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key) { + public List> getList(String key) { net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key); if (tag instanceof net.minecraft.nbt.ListTag nbtList) { - ArrayList list = new ArrayList<>(); + ArrayList> list = new ArrayList<>(); for (net.minecraft.nbt.Tag elem : nbtList) { if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) { list.add(new PaperweightLazyCompoundTag(compoundTag)); @@ -120,7 +120,7 @@ public class PaperweightLazyCompoundTag extends LazyCompoundTag { } @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { + public > List getList(String key, Class listType) { ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_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 similarity index 84% rename from worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java rename to worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/regen/PaperweightRegen.java index 99e001837..07933adfa 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/regen/PaperweightRegen.java @@ -1,22 +1,22 @@ -package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.regen; +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.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.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; @@ -25,12 +25,15 @@ 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; @@ -43,10 +46,12 @@ 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.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; @@ -61,11 +66,12 @@ 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.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; @@ -105,23 +111,22 @@ public class PaperweightRegen extends Regenerator getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public @NotNull Holder getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) { if (options.hasBiomeType()) { return singleBiome; } @@ -285,6 +294,7 @@ public class PaperweightRegen extends Regenerator generatorSettingBaseSupplier = (Holder) generatorSettingBaseSupplierField.get( - originalGenerator); + Holder generatorSettingBaseSupplier = (Holder) + generatorSettingBaseSupplierField.get(noiseBasedChunkGenerator); BiomeSource biomeSource; if (options.hasBiomeType()) { - biomeSource = new FixedBiomeSource( DedicatedServer.getServer().registryAccess() .registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow( @@ -345,7 +354,7 @@ public class PaperweightRegen extends Regenerator>> origPositions = (Map>>) ringPositionsField.get(state); Map>> copy = new Object2ObjectArrayMap<>( origPositions); - ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(freshChunkProvider.chunkMap); + ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get( + freshChunkProvider.chunkMap); ringPositionsField.set(newState, copy); hasGeneratedPositionsField.setBoolean(newState, true); } @@ -375,6 +386,13 @@ public class PaperweightRegen extends Regenerator { - try { - Map map = (Map) serverWorldsField.get(Bukkit.getServer()); - map.remove("faweregentempworld"); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - }); + try { + Map map = (Map) serverWorldsField.get(Bukkit.getServer()); + map.remove("faweregentempworld"); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } } private ResourceKey getWorldDimKey(org.bukkit.World.Environment env) { @@ -483,11 +499,15 @@ public class PaperweightRegen extends Regenerator getEntities() { + public @NotNull List getEntities() { return Collections.emptyList(); } @@ -543,7 +562,7 @@ public class PaperweightRegen extends Regenerator 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 + 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 ); } @@ -582,7 +614,7 @@ public class PaperweightRegen extends Regenerator lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) { + 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 f136de365..8317c17e8 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -182,9 +182,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")) } @@ -215,7 +212,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}") diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IDelegateBukkitImplAdapter.java index e0d13a36b..41c5cbc79 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,15 +8,13 @@ import com.sk89q.worldedit.bukkit.BukkitPlayer; 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; 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 +31,8 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import javax.annotation.Nullable; import java.util.Map; @@ -81,7 +81,7 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { + default void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { getParent().sendFakeNBT(player, pos, nbtData); } @@ -115,6 +115,26 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { return getParent().getInternalBlockStateId(state); } + @Override + default boolean clearContainerBlockContents(World world, BlockVector3 pt) { + return getParent().clearContainerBlockContents(world, pt); + } + + @Override + default void setBiome(Location location, BiomeType biome) { + getParent().setBiome(location, biome); + } + + @Override + default BiomeType getBiome(Location location) { + return getParent().getBiome(location); + } + + @Override + default void sendBiomeUpdates(World world, Iterable chunks) { + getParent().sendBiomeUpdates(world, chunks); + } + @Override default BlockMaterial getMaterial(BlockType blockType) { return getParent().getMaterial(blockType); @@ -131,8 +151,8 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default BinaryTag toNativeBinary(T foreign) { - return getParent().toNativeBinary(foreign); + default LinTag toNativeLin(T foreign) { + return getParent().toNativeLin(foreign); } @Override @@ -141,8 +161,8 @@ public interface IDelegateBukkitImplAdapter extends BukkitImplAdapter { } @Override - default T fromNativeBinary(BinaryTag foreign) { - return getParent().fromNativeBinary(foreign); + default T fromNativeLin(LinTag foreign) { + return getParent().fromNativeLin(foreign); } @Override diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java index 792f3937e..5c6f97d21 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/regions/plotsquared/FaweDelegateSchematicHandler.java @@ -3,8 +3,8 @@ package com.fastasyncworldedit.bukkit.regions.plotsquared; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweAPI; import com.fastasyncworldedit.core.FaweCache; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2; import com.fastasyncworldedit.core.jnbt.CompressedCompoundTag; import com.fastasyncworldedit.core.jnbt.CompressedSchematicTag; import com.fastasyncworldedit.core.util.IOUtil; @@ -29,17 +29,19 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader; -import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader; +import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import net.jpountz.lz4.LZ4BlockInputStream; import org.anarres.parallelgzip.ParallelGZIPOutputStream; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.stream.LinBinaryIO; import javax.annotation.Nonnull; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.FileNotFoundException; @@ -182,7 +184,7 @@ public class FaweDelegateSchematicHandler { try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream( new BufferedOutputStream(new ParallelGZIPOutputStream(stream)))) { - new FastSchematicWriter(output).write(clipboard); + new FastSchematicWriterV2(output).write(clipboard); } } else { try (OutputStream stream = new FileOutputStream(tmp); @@ -194,7 +196,7 @@ public class FaweDelegateSchematicHandler { } else { try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new ParallelGZIPOutputStream(stream))) { - Map map = tag.getValue(); + Map> map = tag.getValue(); output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag)); } } @@ -226,7 +228,7 @@ public class FaweDelegateSchematicHandler { try { try (ParallelGZIPOutputStream gzip = new ParallelGZIPOutputStream(output)) { try (NBTOutputStream nos = new NBTOutputStream(gzip)) { - Map map = weTag.getValue(); + Map> map = weTag.getValue(); nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag)); } } @@ -239,7 +241,7 @@ public class FaweDelegateSchematicHandler { public Schematic getSchematic(@Nonnull InputStream is) { try { - FastSchematicReader schematicReader = new FastSchematicReader( + FastSchematicReaderV2 schematicReader = new FastSchematicReaderV2( new NBTInputStream(new BufferedInputStream(new GZIPInputStream(new BufferedInputStream(is))))); Clipboard clip = schematicReader.read(); return new Schematic(clip); @@ -249,8 +251,8 @@ public class FaweDelegateSchematicHandler { return null; } try { - SpongeSchematicReader schematicReader = - new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is))); + SpongeSchematicV3Reader schematicReader = + new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(is)))); Clipboard clip = schematicReader.read(); return new Schematic(clip); } catch (IOException e2) { diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java index 9916a7d9f..28fb6d990 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/util/DoNotMiniseThese.java @@ -1,6 +1,8 @@ package com.fastasyncworldedit.bukkit.util; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.io.FastBufferedInputStream; +import it.unimi.dsi.fastutil.io.FastBufferedOutputStream; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArraySet; import it.unimi.dsi.fastutil.longs.LongIterator; @@ -19,5 +21,7 @@ final class DoNotMiniseThese { private final LongSet d = null; private final Int2ObjectMap e = null; private final Object2ObjectArrayMap f = null; + private final FastBufferedInputStream g = null; + private final FastBufferedOutputStream h = null; } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 44918557e..4ced1a680 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -45,7 +45,6 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -61,6 +60,7 @@ import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.permissions.PermissionAttachment; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -430,7 +430,7 @@ public class BukkitPlayer extends AbstractPlayerActor { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (adapter != null) { if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK && block instanceof BaseBlock) { - CompoundBinaryTag nbt = ((BaseBlock) block).getNbt(); + LinCompoundTag nbt = ((BaseBlock) block).getNbt(); if (nbt != null) { adapter.sendFakeNBT(player, pos, nbt); adapter.sendFakeOP(player); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index a34494ce5..8fee3b417 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -27,7 +27,7 @@ import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; -import com.sk89q.jnbt.AdventureNBTConverter; +import com.sk89q.jnbt.LinBusConverter; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -35,14 +35,13 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.registry.state.Property; 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 +60,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import javax.annotation.Nullable; import java.util.Arrays; @@ -110,7 +111,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { BlockState getBlock(Location location); /** - * Get the block at the given location. + * Get the block with NBT data at the given location. * * @param location the location * @return the block @@ -183,7 +184,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { * @param pos The position * @param nbtData The NBT Data */ - void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData); + void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData); /** * Make the client think it has operator status. @@ -280,6 +281,46 @@ public interface BukkitImplAdapter extends IBukkitAdapter { throw new UnsupportedOperationException("This adapter does not support clearing block contents."); } + /** + * Set the biome at a location. + * + * @param location the location + * @param biome the new biome + */ + default void setBiome(Location location, BiomeType biome) { + throw new UnsupportedOperationException("This adapter does not support custom biomes."); + } + + /** + * Gets the current biome at a location. + * + * @param location the location + * @return the biome + */ + default BiomeType getBiome(Location location) { + throw new UnsupportedOperationException("This adapter does not support custom biomes."); + } + + /** + * Initialize registries that require NMS access. + */ + default void initializeRegistries() { + + } + + /** + * Sends biome updates for the given chunks. + * + *

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

+ * + * @param world the world + * @param chunks a list of chunk coordinates to send biome updates for + */ + default void sendBiomeUpdates(World world, Iterable chunks) { + } + //FAWE start default BlockMaterial getMaterial(BlockType blockType) { return getMaterial(blockType.getDefaultState()); @@ -291,11 +332,11 @@ public interface BukkitImplAdapter extends IBukkitAdapter { @Deprecated default Tag toNative(T foreign) { - return AdventureNBTConverter.fromAdventure(toNativeBinary(foreign)); + return LinBusConverter.toJnbtTag(toNativeLin(foreign)); } - default BinaryTag toNativeBinary(T foreign) { - return toNative(foreign).asBinaryTag(); + default LinTag toNativeLin(T foreign) { + return toNative(foreign).toLinTag(); } @Deprecated @@ -303,14 +344,14 @@ public interface BukkitImplAdapter extends IBukkitAdapter { if (foreign == null) { return null; } - return fromNativeBinary(foreign.asBinaryTag()); + return fromNativeLin(foreign.toLinTag()); } - default T fromNativeBinary(BinaryTag foreign) { + default T fromNativeLin(LinTag foreign) { if (foreign == null) { return null; } - return fromNative(AdventureNBTConverter.fromAdventure(foreign)); + return fromNative(LinBusConverter.toJnbtTag(foreign)); } @Nullable diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index cd12b1008..282587ce8 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -135,6 +135,7 @@ permissions: worldedit.brush.options.transform: true worldedit.brush.options.scroll: true worldedit.brush.options.visualize: true + worldedit.tool.none: true worldedit.tool.deltree: true worldedit.tool.farwand: true worldedit.tool.lrbuild: true diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index d9794d9f6..d5839d99f 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -46,7 +46,6 @@ dependencies { implementation(libs.findbugs) implementation(libs.rhino) compileOnly(libs.adventureApi) - compileOnlyApi(libs.adventureNbt) compileOnlyApi(libs.adventureMiniMessage) implementation(libs.zstd) { isTransitive = false } compileOnly(libs.paster) @@ -56,10 +55,10 @@ dependencies { antlr(libs.antlr4) implementation(libs.antlr4Runtime) implementation(libs.jsonSimple) { isTransitive = false } + implementation(platform(libs.linBus.bom)) // Tests testRuntimeOnly(libs.log4jCore) - testImplementation(libs.adventureNbt) testImplementation(libs.parallelgzip) } diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index 0420d0994..1f0efe7a1 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -125,7 +125,7 @@ public class MobSpawnerBlock extends BaseBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); values.put("Delay", new ShortTag(delay)); values.put("SpawnCount", new ShortTag(spawnCount)); values.put("SpawnRange", new ShortTag(spawnRange)); @@ -170,7 +170,7 @@ public class MobSpawnerBlock extends BaseBlock { return; } - Map values = rootTag.getValue(); + Map> values = rootTag.getValue(); Tag t = values.get("id"); if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java index 333c3336b..bf9adfa38 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -104,7 +104,7 @@ public class SignBlock extends BaseBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); if (isLegacy()) { values.put("Text1", new StringTag(text[0])); values.put("Text2", new StringTag(text[1])); @@ -112,7 +112,7 @@ public class SignBlock extends BaseBlock { values.put("Text4", new StringTag(text[3])); } else { ListTag messages = new ListTag(StringTag.class, Arrays.stream(text).map(StringTag::new).collect(Collectors.toList())); - Map frontTextTag = new HashMap<>(); + Map> frontTextTag = new HashMap<>(); frontTextTag.put("messages", messages); values.put("front_text", new CompoundTag(frontTextTag)); } @@ -125,9 +125,9 @@ public class SignBlock extends BaseBlock { return; } - Map values = rootTag.getValue(); + Map> values = rootTag.getValue(); - Tag t; + Tag t; text = new String[]{EMPTY, EMPTY, EMPTY, EMPTY}; diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java index a60ffbc09..a5b405f47 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -100,8 +100,8 @@ public class SkullBlock extends BaseBlock { @Override public CompoundTag getNbtData() { - Map values = new HashMap<>(); - Map inner = new HashMap<>(); + Map> values = new HashMap<>(); + Map> inner = new HashMap<>(); inner.put("Name", new StringTag(owner)); values.put(DeprecationUtil.getHeadOwnerKey(), new CompoundTag(inner)); return new CompoundTag(values); @@ -113,7 +113,7 @@ public class SkullBlock extends BaseBlock { return; } - Map values = rootTag.getValue(); + Map> values = rootTag.getValue(); Tag t; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index acc0d8bf3..28367a949 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -116,7 +116,10 @@ public class FaweAPI { * @param file the file to load * @return a clipboard containing the schematic * @see ClipboardFormat + * @deprecated Opens streams that are not then closed. Use {@link ClipboardFormats#findByFile(File)} and its relevant + * methods to allow closing created streams/closing the reader (which will close the stream(s)) */ + @Deprecated(forRemoval = true, since = "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/FaweCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java index 46a3a1574..526570296 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweCache.java @@ -532,7 +532,7 @@ public enum FaweCache implements Trimable { } public CompoundTag asTag(Map value) { - HashMap map = new HashMap<>(); + HashMap> map = new HashMap<>(); for (Map.Entry entry : value.entrySet()) { Object child = entry.getValue(); Tag tag = asTag(child); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java index b635c1e7d..1b60124cb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/CopyPastaBrush.java @@ -91,7 +91,7 @@ public class CopyPastaBrush implements Brush, ResettableTool { newClipboard.setOrigin(position); ClipboardHolder holder = new ClipboardHolder(newClipboard); session.setClipboard(holder); - int blocks = builder.size(); + long blocks = builder.longSize(); player.print(Caption.of("fawe.worldedit.copy.command.copy", blocks)); } else { AffineTransform transform = null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java index b28d7536b..59fc2add2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/PopulateSchem.java @@ -24,7 +24,8 @@ public record PopulateSchem(Mask mask, List clipboards, int rar CuboidRegion cuboid = new CuboidRegion( editSession.getWorld(), position.subtract(size1, size1, size1), - position.add(size1, size1, size1) + position.add(size1, size1, size1), + true ); try { editSession.addSchems(cuboid, mask, clipboards, rarity, randomRotate); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java index dd7c23984..8e34d3996 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/scroll/Scroll.java @@ -51,6 +51,7 @@ public abstract class Scroll implements ScrollTool { parserContext.setActor(player); parserContext.setWorld(player.getWorld()); parserContext.setSession(session); + parserContext.setTryLegacy(player.getLimit().ALLOW_LEGACY); switch (mode) { case CLIPBOARD: if (arguments.size() != 2) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java index d230ab05b..880b4cdf7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Config.java @@ -6,6 +6,7 @@ import com.sk89q.util.StringUtil; import com.sk89q.worldedit.internal.util.LogManagerCompat; import org.apache.logging.log4j.Logger; +import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintWriter; @@ -18,6 +19,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -31,10 +33,15 @@ public class Config { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final Map removedKeyVals = new HashMap<>(); + @Nullable + private Map> copyTo = new HashMap<>(); + private boolean performCopyTo = false; private List existingMigrateNodes = null; public Config() { - save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0); + // This is now definitely required as the save -> load -> save order means the @CopiedFrom annotated fields work + save(new PrintWriter(new ByteArrayOutputStream(0)), getClass(), this, 0, null); + performCopyTo = true; } /** @@ -60,11 +67,12 @@ public class Config { /** * Set the value of a specific node. Probably throws some error if you supply non existing keys or invalid values. + * This should only be called during loading of a config file * * @param key config node * @param value value */ - private void set(String key, Object value, Class root) { + private void setLoadedNode(String key, Object value, Class root) { String[] split = key.split("\\."); Object instance = getInstance(split, root); if (instance != null) { @@ -74,8 +82,18 @@ public class Config { if (field.getAnnotation(Final.class) != null) { return; } + if (copyTo != null) { + copyTo.remove(key); // Remove if the config field is already written + final Object finalValue = value; + copyTo.replaceAll((copyToNode, entry) -> { + if (!key.equals(entry.getKey())) { + return entry; + } + return new AbstractMap.SimpleEntry<>(key, finalValue); + }); + } Migrate migrate = field.getAnnotation(Migrate.class); - if (existingMigrateNodes != null && migrate != null) { + if (migrate != null) { existingMigrateNodes.add(migrate.value()); } if (field.getType() == String.class && !(value instanceof String)) { @@ -90,8 +108,9 @@ public class Config { } } removedKeyVals.put(key, value); - LOGGER.error( - "Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed.", + LOGGER.warn( + "Failed to set config option: {}: {} | {} | {}.yml. This is likely because it was removed or was set with an " + + "invalid value.", key, value, instance, @@ -110,7 +129,7 @@ public class Config { if (value instanceof MemorySection) { continue; } - set(key, value, getClass()); + setLoadedNode(key, value, getClass()); } for (String node : existingMigrateNodes) { removedKeyVals.remove(node); @@ -133,7 +152,7 @@ public class Config { } PrintWriter writer = new PrintWriter(file); Object instance = this; - save(writer, getClass(), instance, 0); + save(writer, getClass(), instance, 0, null); writer.close(); } catch (Throwable e) { LOGGER.error("Failed to save config file: {}", file, e); @@ -190,7 +209,7 @@ public class Config { } /** - * Indicates that a field should be instantiated / created. + * Indicates that a field should be migrated from a node that is deleted * * @since 2.10.0 */ @@ -202,6 +221,19 @@ public class Config { } + /** + * Indicates that a field's default value should match another input if the config is otherwise already generated + * + * @since 2.11.0 + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface CopiedFrom { + + String value(); + + } + @Ignore // This is not part of the config public static class ConfigBlock { @@ -254,7 +286,7 @@ public class Config { return value != null ? value.toString() : "null"; } - private void save(PrintWriter writer, Class clazz, final Object instance, int indent) { + private void save(PrintWriter writer, Class clazz, final Object instance, int indent, String parentNode) { try { String CTRF = System.lineSeparator(); String spacing = StringMan.repeat(" ", indent); @@ -274,7 +306,7 @@ public class Config { } if (current == ConfigBlock.class) { current = (Class) ((ParameterizedType) (field.getGenericType())).getActualTypeArguments()[0]; - handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current); + handleConfigBlockSave(writer, instance, indent, field, spacing, CTRF, current, parentNode); continue; } else if (!removedKeyVals.isEmpty()) { Migrate migrate = field.getAnnotation(Migrate.class); @@ -283,6 +315,18 @@ public class Config { field.set(instance, value); } } + CopiedFrom copiedFrom; + if (copyTo != null && (copiedFrom = field.getAnnotation(CopiedFrom.class)) != null) { + String node = toNodeName(field.getName()); + node = parentNode == null ? node : parentNode + "." + node; + Map.Entry entry = copyTo.remove(node); + Object copiedVal; + if (entry == null) { + 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); if (create != null) { Object value = field.get(instance); @@ -296,11 +340,12 @@ public class Config { writer.write(spacing + "# " + commentLine + CTRF); } } - writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); + String node = toNodeName(current.getSimpleName()); + writer.write(spacing + node + ":" + CTRF); if (value == null) { field.set(instance, value = current.getDeclaredConstructor().newInstance()); } - save(writer, current, value, indent + 2); + save(writer, current, value, indent + 2, parentNode == null ? node : parentNode + "." + node); } else { writer.write(spacing + toNodeName(field.getName() + ": ") + toYamlString( field.get(instance), @@ -311,6 +356,10 @@ public class Config { } catch (Throwable e) { LOGGER.error("Failed to save config file", e); } + if (parentNode == null && performCopyTo) { + performCopyTo = false; + copyTo = null; + } } private void handleConfigBlockSave( @@ -320,7 +369,8 @@ public class Config { Field field, String spacing, String CTRF, - Class current + Class current, + String parentNode ) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException { Comment comment = current.getAnnotation(Comment.class); if (comment != null) { @@ -330,6 +380,7 @@ public class Config { } BlockName blockNames = current.getAnnotation(BlockName.class); if (blockNames != null) { + String node = toNodeName(current.getSimpleName()); writer.write(spacing + toNodeName(current.getSimpleName()) + ":" + CTRF); ConfigBlock configBlock = (ConfigBlock) field.get(instance); if (configBlock == null || configBlock.getInstances().isEmpty()) { @@ -343,7 +394,7 @@ public class Config { for (Map.Entry entry : configBlock.getRaw().entrySet()) { String key = entry.getKey(); writer.write(spacing + " " + toNodeName(key) + ":" + CTRF); - save(writer, current, entry.getValue(), indent + 4); + save(writer, current, entry.getValue(), indent + 4, parentNode == null ? node : parentNode + "." + node); } } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index d069e62a1..3b80dcdfa 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -191,6 +191,7 @@ public class Settings extends Config { } } limit.UNIVERSAL_DISALLOWED_BLOCKS &= newLimit.UNIVERSAL_DISALLOWED_BLOCKS; + limit.ALLOW_LEGACY &= newLimit.ALLOW_LEGACY; if (limit.DISALLOWED_BLOCKS == null) { limit.DISALLOWED_BLOCKS = newLimit.DISALLOWED_BLOCKS.isEmpty() ? Collections.emptySet() : new HashSet<>( @@ -439,6 +440,10 @@ public class Settings extends Config { " - If fast-placement is disabled, this may cause edits to be slower." }) public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; + @Comment({ + "If legacy, mumerical, blocks IDs should be able to be used (i.e. 12:2)," + }) + public boolean ALLOW_LEGACY = true; @Comment({ "List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.", "Where block properties are specified, any blockstate with the property will be disallowed (e.g. all directions", @@ -518,6 +523,9 @@ public class Settings extends Config { public int DELETE_AFTER_DAYS = 7; @Comment("Delete history in memory on logout (does not effect disk)") public boolean DELETE_ON_LOGOUT = true; + @Comment("Delete history on disk on logout") + @CopiedFrom("history.delete-on-logout") + public boolean DELETE_DISK_ON_LOGOUT = false; @Comment({ "If history should be enabled by default for plugins using WorldEdit:", " - It is faster to have disabled", diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java index f8207f2dc..e40683f2e 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/database/RollbackDatabase.java @@ -64,26 +64,47 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future init() { return call(() -> { try (PreparedStatement stmt = connection.prepareStatement("CREATE TABLE IF NOT EXISTS`" + this.prefix + - "edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1`" + - "INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1`" + - "INT NOT NULL, `y2` INT NOT NULL, `size` INT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) { + "_edits` (`player` BLOB(16) NOT NULL,`id` INT NOT NULL, `time` INT NOT NULL,`x1` " + + "INT NOT NULL,`x2` INT NOT NULL,`z1` INT NOT NULL,`z2` INT NOT NULL,`y1` " + + "INT NOT NULL, `y2` INT NOT NULL, `size` BIGINT NOT NULL, `command` VARCHAR, PRIMARY KEY (player, id))")) { stmt.executeUpdate(); } - try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD COLUMN `command` VARCHAR")) { + String alterTablePrefix = "ALTER TABLE`" + this.prefix + "edits` "; + try (PreparedStatement stmt = + connection.prepareStatement(alterTablePrefix + "ADD COLUMN `command` VARCHAR")) { stmt.executeUpdate(); } catch (SQLException ignored) { } // Already updated - try (PreparedStatement stmt = connection.prepareStatement("ALTER TABLE`" + this.prefix + "edits` ADD SIZE INT DEFAULT 0 NOT NULL")) { + try (PreparedStatement stmt = + connection.prepareStatement(alterTablePrefix + "ADD COLUMN `size` BIGINT DEFAULT 0 NOT NULL")) { stmt.executeUpdate(); } catch (SQLException ignored) { } // Already updated + + boolean migrated = false; + try (PreparedStatement stmt = + connection.prepareStatement("INSERT INTO `" + this.prefix + "_edits` " + + "(player, id, time, x1, x2, z1, z2, y1, y2, size, command) " + + "SELECT player, id, time, x1, x2, z1, z2, y1, y2, size, command " + + "FROM `" + this.prefix + "edits`")) { + + stmt.executeUpdate(); + migrated = true; + } catch (SQLException ignored) { + } // Already updated + if (migrated) { + try (PreparedStatement stmt = connection.prepareStatement("DROP TABLE `" + this.prefix + "edits`")) { + stmt.executeUpdate(); + } + } return true; }); } public Future delete(UUID uuid, int id) { return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `player`=? AND `id`=?")) { + try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "_edits` WHERE `player`=? " + + "AND `id`=?")) { stmt.setBytes(1, toBytes(uuid)); stmt.setInt(2, id); return stmt.executeUpdate(); @@ -94,7 +115,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { public Future getEdit(@Nonnull UUID uuid, int id) { return call(() -> { try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM`" + this.prefix + - "edits` WHERE `player`=? AND `id`=?")) { + "_edits` WHERE `player`=? AND `id`=?")) { stmt.setBytes(1, toBytes(uuid)); stmt.setInt(2, id); ResultSet result = stmt.executeQuery(); @@ -119,7 +140,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { CuboidRegion region = new CuboidRegion(BlockVector3.at(x1, y1, z1), BlockVector3.at(x2, y2, z2)); long time = result.getInt("time") * 1000L; - long size = result.getInt("size"); + long size = result.getLong("size"); String command = result.getString("command"); @@ -135,7 +156,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { long now = System.currentTimeMillis() / 1000; final int then = (int) (now - diff); return call(() -> { - try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + "edits` WHERE `time` ? AND `x2` >= ? AND `x1` <= ? @@ -202,7 +223,8 @@ public class RollbackDatabase extends AsyncNotifyQueue { } if (delete && uuid != null) { try (PreparedStatement stmt = connection.prepareStatement("DELETE FROM`" + this.prefix + - "edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? AND `z1`<=?")) { + "_edits` WHERE `player`=? AND `time`>? AND `x2`>=? AND `x1`<=? AND `y2`>=? AND `y1`<=? AND `z2`>=? " + + "AND `z1`<=?")) { byte[] uuidBytes = ByteBuffer .allocate(16) .putLong(uuid.getMostSignificantBits()) @@ -249,7 +271,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { RollbackOptimizedHistory[] copy = IntStream.range(0, size) .mapToObj(i -> historyChanges.poll()).toArray(RollbackOptimizedHistory[]::new); - try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "edits`" + + try (PreparedStatement stmt = connection.prepareStatement("INSERT OR REPLACE INTO`" + this.prefix + "_edits`" + " (`player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)")) { // `player`,`id`,`time`,`x1`,`x2`,`z1`,`z2`,`y1`,`y2`,`command`,`size`) VALUES(?,?,?,?,?,?,?,?,?,?,?)" for (RollbackOptimizedHistory change : copy) { @@ -270,7 +292,7 @@ public class RollbackDatabase extends AsyncNotifyQueue { stmt.setInt(8, pos1.y() - 128); stmt.setInt(9, pos2.y() - 128); stmt.setString(10, change.getCommand()); - stmt.setInt(11, change.size()); + stmt.setLong(11, change.longSize()); stmt.executeUpdate(); stmt.clearParameters(); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java index f591cf826..325cd4191 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/entity/LazyBaseEntity.java @@ -3,25 +3,25 @@ package com.fastasyncworldedit.core.entity; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.util.TaskManager; import com.sk89q.worldedit.entity.BaseEntity; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.entity.EntityType; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.util.function.Supplier; public class LazyBaseEntity extends BaseEntity { - private Supplier saveTag; + private Supplier saveTag; - public LazyBaseEntity(EntityType type, Supplier saveTag) { + public LazyBaseEntity(EntityType type, Supplier saveTag) { super(type); this.saveTag = saveTag; } @Nullable @Override - public CompoundBinaryTag getNbt() { - Supplier tmp = saveTag; + public LinCompoundTag getNbt() { + Supplier tmp = saveTag; if (tmp != null) { saveTag = null; if (Fawe.isMainThread()) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java new file mode 100644 index 000000000..73d871135 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/exception/OutsideWorldBoundsException.java @@ -0,0 +1,17 @@ +package com.fastasyncworldedit.core.exception; + +import com.sk89q.worldedit.WorldEditException; + +public class OutsideWorldBoundsException extends WorldEditException { + + private final int y; + + public OutsideWorldBoundsException(int y) { + this.y = y; + } + + public int y() { + return y; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java index 84437c19a..1b6640ecd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/RichMaskParser.java @@ -143,7 +143,7 @@ public class RichMaskParser extends FaweParser { int end = command.lastIndexOf(']'); mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); } else { - BlockMaskBuilder builder = new BlockMaskBuilder(); + BlockMaskBuilder builder = new BlockMaskBuilder(context); try { builder.addRegex(full); } catch (InputParseException ignored) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java index c1997bb0d..615f1a586 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/platform/binding/ConsumeBindings.java @@ -200,6 +200,7 @@ public class ConsumeBindings extends Bindings { public BaseBlock baseBlock(Actor actor, String argument) { ParserContext parserContext = new ParserContext(); parserContext.setActor(actor); + parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY); if (actor instanceof Entity) { Extent extent = ((Entity) actor).getExtent(); if (extent instanceof World) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java index 103dd8824..4f4cce126 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/FaweRegionExtent.java @@ -101,7 +101,7 @@ public abstract class FaweRegionExtent extends ResettableExtent implements IBatc @Override public BiomeType getBiomeType(int x, int y, int z) { - if (!contains(x, z)) { + if (!contains(x, y, z)) { if (!limit.MAX_FAILS()) { WEManager.weManager().cancelEditSafe(this, FaweCache.OUTSIDE_REGION); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java index ded96d5aa..c0b49c333 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java @@ -29,8 +29,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -81,7 +79,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc return block; } CompoundTag nbt = localBlock.getNbtData(); - Map value = new HashMap<>(nbt.getValue()); + Map> value = new HashMap<>(nbt.getValue()); for (String key : strip) { value.remove(key); } @@ -93,7 +91,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc return entity; } CompoundTag nbt = entity.getNbtData(); - Map value = new HashMap<>(nbt.getValue()); + Map> value = new HashMap<>(nbt.getValue()); for (String key : strip) { value.remove(key); } @@ -110,7 +108,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc } boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap; for (final Map.Entry entry : tiles.entrySet()) { - ImmutableMap.Builder map = ImmutableMap.builder(); + ImmutableMap.Builder> map = ImmutableMap.builder(); final AtomicBoolean isStripped = new AtomicBoolean(false); entry.getValue().getValue().forEach((k, v) -> { if (strip.contains(k.toLowerCase())) { @@ -132,7 +130,7 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc Iterator iterator = entities.iterator(); while (iterator.hasNext()) { CompoundTag entity = iterator.next(); - ImmutableMap.Builder map = ImmutableMap.builder(); + ImmutableMap.Builder> map = ImmutableMap.builder(); final AtomicBoolean isStripped = new AtomicBoolean(false); entity.getValue().forEach((k, v) -> { if (strip.contains(k.toUpperCase(Locale.ROOT))) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java index c424c0f8c..daa731d3c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/TransformExtent.java @@ -93,7 +93,7 @@ public class TransformExtent extends BlockTransformExtent { @Override public BiomeType getBiomeType(int x, int y, int z) { BlockVector3 p = getPos(x, y, z); - return super.getBiomeType(p.x(), y, p.z()); + return super.getBiomeType(p.x(), p.y(), p.z()); } @Override diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java index 6a306fc44..77447ac4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/CPUOptimizedClipboard.java @@ -152,7 +152,7 @@ public class CPUOptimizedClipboard extends LinearClipboard { public Collection getTileEntities() { convertTilesToIndex(); nbtMapIndex.replaceAll((index, tag) -> { - Map values = new HashMap<>(tag.getValue()); + Map> values = new HashMap<>(tag.getValue()); if (!values.containsKey("x")) { int y = index / getArea(); index -= y * getArea(); @@ -176,7 +176,7 @@ public class CPUOptimizedClipboard extends LinearClipboard { } private boolean setTile(int index, CompoundTag tag) { - final Map values = new HashMap<>(tag.getValue()); + final Map> values = new HashMap<>(tag.getValue()); values.remove("x"); values.remove("y"); values.remove("z"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java index f42cdbbff..dc7193394 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/DiskOptimizedClipboard.java @@ -586,7 +586,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { for (BlockArrayClipboard.ClipboardEntity entity : entities) { if (entity.getState() != null && entity.getState().getNbtData() != null) { CompoundTag data = entity.getState().getNbtData(); - HashMap value = new HashMap<>(data.getValue()); + HashMap> value = new HashMap<>(data.getValue()); List pos = new ArrayList<>(3); pos.add(new DoubleTag(entity.getLocation().x())); pos.add(new DoubleTag(entity.getLocation().x())); @@ -710,7 +710,7 @@ public class DiskOptimizedClipboard extends LinearClipboard { @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - final Map values = new HashMap<>(tag.getValue()); + final Map> values = new HashMap<>(tag.getValue()); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java index 143168504..2e65f59ca 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/LinearClipboard.java @@ -106,7 +106,7 @@ public abstract class LinearClipboard extends SimpleClipboard { @Nullable @Override public Entity createEntity(Location location, BaseEntity entity, UUID uuid) { - Map map = new HashMap<>(entity.getNbtData().getValue()); + Map> map = new HashMap<>(entity.getNbtData().getValue()); NBTUtils.addUUIDToMap(map, uuid); entity.setNbtData(new CompoundTag(map)); BlockArrayClipboard.ClipboardEntity ret = new BlockArrayClipboard.ClipboardEntity(location, entity); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java index 6c7a910f2..426cbc32a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/MemoryOptimizedClipboard.java @@ -254,7 +254,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard { @Override public boolean setTile(int x, int y, int z, CompoundTag tag) { - final Map values = new HashMap<>(tag.getValue()); + final Map> values = new HashMap<>(tag.getValue()); values.put("x", new IntTag(x)); values.put("y", new IntTag(y)); values.put("z", new IntTag(z)); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java index 4f7245d27..2edb9cb51 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/ReadOnlyClipboard.java @@ -2,13 +2,10 @@ package com.fastasyncworldedit.core.extent.clipboard; import com.fastasyncworldedit.core.Fawe; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; @@ -18,9 +15,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.function.Supplier; @@ -77,6 +72,16 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard { }; } + @Override + public BlockVector3 getMinimumPoint() { + return region.getMinimumPoint(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return region.getMaximumPoint(); + } + @Override public Region getRegion() { return region; 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 96% 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 156e38544..4c71a9f66 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 @@ -9,7 +9,7 @@ import com.fastasyncworldedit.core.internal.io.FaweInputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate; import com.fastasyncworldedit.core.jnbt.streamer.ValueReader; -import com.sk89q.jnbt.AdventureNBTConverter; +import com.sk89q.jnbt.LinBusConverter; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.NBTInputStream; @@ -53,7 +53,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Reads schematic files using the Sponge Schematic Specification. */ -public class FastSchematicReader extends NBTSchematicReader { +public class FastSchematicReaderV2 extends NBTSchematicReader { private static final Logger LOGGER = LogManagerCompat.getLogger(); private final NBTInputStream inputStream; @@ -88,7 +88,7 @@ public class FastSchematicReader extends NBTSchematicReader { * * @param inputStream the input stream to read from */ - public FastSchematicReader(NBTInputStream inputStream) { + public FastSchematicReaderV2(NBTInputStream inputStream) { checkNotNull(inputStream); this.inputStream = inputStream; this.fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer(); @@ -109,26 +109,22 @@ public class FastSchematicReader extends NBTSchematicReader { if (fixer == null || dataVersion == -1) { return tag; } - //FAWE start - BinaryTag - return (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( + return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.BLOCK_ENTITY, - tag.asBinaryTag(), + tag.toLinTag(), dataVersion )); - //FAWE end } private CompoundTag fixEntity(CompoundTag tag) { if (fixer == null || dataVersion == -1) { return tag; } - //FAWE start - BinaryTag - return (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( + return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( DataFixer.FixTypes.ENTITY, - tag.asBinaryTag(), + tag.toLinTag(), dataVersion )); - //FAWE end } private String fixBiome(String biomePalettePart) { @@ -251,7 +247,7 @@ public class FastSchematicReader extends NBTSchematicReader { throw new IOException("This schematic version is not supported; Version: " + version + ", DataVersion: " + dataVersion + ". It's very likely your schematic has an invalid file extension," + " if the schematic has been created on a version lower than 1.13.2, the extension MUST be `.schematic`," + - " elsewise the schematic can't be read properly."); + " elsewise the schematic can't be read properly. If you are using a litematica schematic, it is not supported!"); } if (blocks != null) { @@ -344,7 +340,7 @@ public class FastSchematicReader extends NBTSchematicReader { y = pos[1]; z = pos[2]; } - Map values = new HashMap<>(tile.getValue()); + Map> values = new HashMap<>(tile.getValue()); Tag id = values.get("Id"); if (id != null) { values.put("x", new IntTag(x)); @@ -371,7 +367,7 @@ public class FastSchematicReader extends NBTSchematicReader { // entities if (entities != null && !entities.isEmpty()) { for (Map entRaw : entities) { - Map value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue()); + Map> value = new HashMap<>(FaweCache.INSTANCE.asTag(entRaw).getValue()); StringTag id = (StringTag) value.get("Id"); if (id == null) { id = (StringTag) value.get("id"); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicReaderV3.java new file mode 100644 index 000000000..8b6aa6cc8 --- /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 2.11.1 + */ +@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 97% 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 65a4a0e86..3bd302876 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV2.java @@ -48,9 +48,9 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Writes schematic files using the Sponge schematic format. */ -public class FastSchematicWriter implements ClipboardWriter { +public class FastSchematicWriterV2 implements ClipboardWriter { - private static final int CURRENT_VERSION = 2; + public static final int CURRENT_VERSION = 2; private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; private final NBTOutputStream outputStream; @@ -61,7 +61,7 @@ public class FastSchematicWriter implements ClipboardWriter { * * @param outputStream the output stream to write to */ - public FastSchematicWriter(NBTOutputStream outputStream) { + public FastSchematicWriterV2(NBTOutputStream outputStream) { checkNotNull(outputStream); this.outputStream = outputStream; } @@ -103,11 +103,11 @@ public class FastSchematicWriter implements ClipboardWriter { final DataOutput rawStream = outputStream.getOutputStream(); outputStream.writeLazyCompoundTag("Schematic", out -> { + out.writeNamedTag("Version", CURRENT_VERSION); out.writeNamedTag( "DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() ); - out.writeNamedTag("Version", CURRENT_VERSION); out.writeNamedTag("Width", (short) width); out.writeNamedTag("Height", (short) height); out.writeNamedTag("Length", (short) length); @@ -149,7 +149,7 @@ public class FastSchematicWriter implements ClipboardWriter { BaseBlock block = pos.getFullBlock(finalClipboard); CompoundTag nbt = block.getNbtData(); if (nbt != null) { - Map values = new HashMap<>(nbt.getValue()); + Map> values = new HashMap<>(nbt.getValue()); // Positions are kept in NBT, we don't want that. values.remove("x"); @@ -223,7 +223,7 @@ public class FastSchematicWriter implements ClipboardWriter { BaseEntity state = entity.getState(); if (state != null) { - Map values = new HashMap<>(); + Map> values = new HashMap<>(); // Put NBT provided data CompoundTag rawTag = state.getNbtData(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/FastSchematicWriterV3.java new file mode 100644 index 000000000..1d1f0df2a --- /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 2.11.1 + */ +@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/extent/clipboard/io/schematic/MinecraftStructure.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java index 91fb75495..0915766cc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/clipboard/io/schematic/MinecraftStructure.java @@ -70,7 +70,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { throw new IOException("Root tag has name - are you sure this is a structure?"); } - Map tags = ((CompoundTag) rootTag.getTag()).getValue(); + Map> tags = ((CompoundTag) rootTag.getTag()).getValue(); ListTag size = (ListTag) tags.get("size"); int width = size.getInt(0); @@ -89,13 +89,13 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { BlockState[] combinedArray = new BlockState[palette.size()]; for (int i = 0; i < palette.size(); i++) { CompoundTag compound = palette.get(i); - Map map = compound.getValue(); + Map> map = compound.getValue(); String name = ((StringTag) map.get("Name")).getValue(); BlockType type = BlockTypes.get(name); BlockState state = type.getDefaultState(); CompoundTag properties = (CompoundTag) map.get("Properties"); if (properties != null) { - for (Map.Entry entry : properties.getValue().entrySet()) { + for (Map.Entry> entry : properties.getValue().entrySet()) { String key = entry.getKey(); String value = ((StringTag) entry.getValue()).getValue(); Property property = type.getProperty(key); @@ -108,7 +108,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { List blocksList = (List) tags.get("blocks").getValue(); try { for (CompoundTag compound : blocksList) { - Map blockMap = compound.getValue(); + Map> blockMap = compound.getValue(); IntTag stateTag = (IntTag) blockMap.get("state"); ListTag posTag = (ListTag) blockMap.get("pos"); BlockState state = combinedArray[stateTag.getValue()]; @@ -136,7 +136,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { if (entities != null) { List entityList = (List) (List) entities.getValue(); for (CompoundTag entityEntry : entityList) { - Map entityEntryMap = entityEntry.getValue(); + Map> entityEntryMap = entityEntry.getValue(); ListTag posTag = (ListTag) entityEntryMap.get("pos"); CompoundTag nbtTag = (CompoundTag) entityEntryMap.get("nbt"); String id = nbtTag.getString("Id"); @@ -216,7 +216,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { if (!block.hasNbtData()) { blocks.add(FaweCache.INSTANCE.asMap("state", index, "pos", pos)); } else { - Map tag = new HashMap<>(block.getNbtData().getValue()); + Map> tag = new HashMap<>(block.getNbtData().getValue()); tag.remove("x"); tag.remove("y"); tag.remove("z"); @@ -246,7 +246,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter { BaseEntity state = entity.getState(); if (state != null) { CompoundTag nbt = state.getNbtData(); - Map nbtMap = new HashMap<>(nbt.getValue()); + Map> nbtMap = new HashMap<>(nbt.getValue()); // Replace rotation data nbtMap.put("Rotation", writeRotation(entity.getLocation())); nbtMap.put("id", new StringTag(state.getType().id())); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java index d49644f24..cb5339737 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/heightmap/HeightMapType.java @@ -17,19 +17,19 @@ public enum HeightMapType { MOTION_BLOCKING { @Override public boolean includes(BlockState state) { - return state.getMaterial().isSolid() || HeightMapType.hasFluid(state); + return state.getMaterial().isMovementBlocker() || HeightMapType.hasFluid(state); } }, MOTION_BLOCKING_NO_LEAVES { @Override public boolean includes(BlockState state) { - return (state.getMaterial().isSolid() || HeightMapType.hasFluid(state)) && !HeightMapType.isLeaf(state); + return (state.getMaterial().isMovementBlocker() || HeightMapType.hasFluid(state)) && !HeightMapType.isLeaf(state); } }, OCEAN_FLOOR { @Override public boolean includes(BlockState state) { - return state.getMaterial().isSolid(); + return state.getMaterial().isMovementBlocker(); } }, WORLD_SURFACE { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java index 250914c05..775e9cf4c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/SchemGen.java @@ -7,6 +7,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; import java.util.List; @@ -19,29 +20,60 @@ public class SchemGen implements Resource { private final List clipboards; private final boolean randomRotate; private final Mask mask; + private final Region region; private final MutableBlockVector3 mutable = new MutableBlockVector3(); + /** + * @deprecated Use {@link SchemGen#SchemGen(Mask, Extent, List, boolean, Region)} + */ + @Deprecated(forRemoval = true, since = "2.11.1") 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 2.11.1 + */ + public SchemGen(Mask mask, Extent extent, List clipboards, boolean randomRotate, Region region) { + this.mask = mask; + this.extent = extent; + this.clipboards = clipboards; + this.randomRotate = randomRotate; + this.region = region; + } + + private int getY(int x, int z) { + if (region == null) { + return extent.getNearestSurfaceTerrainBlock( + x, + z, + mutable.y(), + this.extent.getMinY(), + this.extent.getMaxY(), + Integer.MIN_VALUE, + Integer.MAX_VALUE + ); + } else { + int y = extent.getHighestTerrainBlock(x, z, region.getMinimumY(), region.getMaximumY(), mask); + if (y == region.getMinimumY() && !extent.getBlock(x, y, z).getMaterial().isMovementBlocker()) { + return Integer.MIN_VALUE; + } + return y; + } } @Override public boolean spawn(Random random, int x, int z) throws WorldEditException { mutable.mutX(x); mutable.mutZ(z); - int y = extent.getNearestSurfaceTerrainBlock( - x, - z, - mutable.y(), - this.extent.getMinY(), - this.extent.getMaxY(), - Integer.MIN_VALUE, - Integer.MAX_VALUE - ); + int y = getY(x, z); if (y == Integer.MIN_VALUE || y == Integer.MAX_VALUE) { return false; } @@ -54,7 +86,8 @@ public class SchemGen implements Resource { if (randomRotate) { holder.setTransform(new AffineTransform().rotateY(ThreadLocalRandom.current().nextInt(4) * 90)); } - Clipboard clipboard = holder.getClipboard(); + Clipboard clipboard = holder.getClipboards().size() == 1 ? holder.getClipboard() : + holder.getClipboards().get(ThreadLocalRandom.current().nextInt(clipboards.size())); Transform transform = holder.getTransform(); if (transform.isIdentity()) { clipboard.paste(extent, mutable, false); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java index baef7f767..7ca60bdd1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/BlockMaskBuilder.java @@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.util.MutableCharSequence; import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.world.block.BlanketBaseBlock; import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.registry.state.AbstractProperty; @@ -53,6 +54,7 @@ public class BlockMaskBuilder { private static final long[] ALL = new long[0]; private final long[][] bitSets; + private final ParserContext context; private boolean[] ordinals; private boolean optimizedStates = true; @@ -60,8 +62,28 @@ public class BlockMaskBuilder { this(new long[BlockTypes.size()][]); } + /** + * Create a new instance with a given {@link ParserContext} to use if parsing regex + * + * @since 2.11.0 + */ + 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 2.11.0 + */ + protected BlockMaskBuilder(long[][] bitSets, ParserContext context) { + this.bitSets = bitSets; + this.context = context; } private boolean handleRegex(BlockType blockType, PropertyKey key, String regex, FuzzyStateAllowingBuilder builder) { @@ -173,7 +195,7 @@ public class BlockMaskBuilder { List blockTypeList; List builders; if (StringMan.isAlphanumericUnd(charSequence)) { - BlockType type = BlockTypes.parse(charSequence.toString()); + BlockType type = BlockTypes.parse(charSequence.toString(), context); blockTypeList = Collections.singletonList(type); builders = Collections.singletonList(new FuzzyStateAllowingBuilder(type)); add(type); @@ -280,7 +302,7 @@ public class BlockMaskBuilder { } } else { if (StringMan.isAlphanumericUnd(input)) { - add(BlockTypes.parse(input)); + add(BlockTypes.parse(input, context)); } else { boolean success = false; for (BlockType myType : BlockTypesCache.values) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java index 7fa4ddc6d..b56ebc3eb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/change/MutableEntityChange.java @@ -3,7 +3,6 @@ package com.fastasyncworldedit.core.history.change; import com.fastasyncworldedit.core.util.MathMan; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.DoubleTag; -import com.sk89q.jnbt.LongTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; @@ -52,7 +51,7 @@ public class MutableEntityChange implements Change { @SuppressWarnings({"unchecked"}) public void delete(UndoContext context) { - Map map = tag.getValue(); + Map> map = tag.getValue(); UUID uuid = tag.getUUID(); if (uuid == null) { LOGGER.info("Skipping entity without uuid."); @@ -66,7 +65,7 @@ public class MutableEntityChange implements Change { } public void create(UndoContext context) { - Map map = tag.getValue(); + Map> map = tag.getValue(); Tag posTag = map.get("Pos"); if (posTag == null) { LOGGER.warn("Missing pos tag: {}", tag); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java index 08165577f..346543a0b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractChangeSet.java @@ -306,7 +306,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor { } public boolean isEmpty() { - return queue.isEmpty() && workerSemaphore.availablePermits() == 1 && size() == 0; + return queue.isEmpty() && workerSemaphore.availablePermits() == 1 && longSize() == 0; } public void add(BlockVector3 loc, BaseBlock from, BaseBlock to) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java index 195a5fdbd..a44e73013 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/AbstractDelegateChangeSet.java @@ -176,6 +176,11 @@ public class AbstractDelegateChangeSet extends AbstractChangeSet { return parent.size(); } + @Override + public long longSize() { + return parent.longSize(); + } + @Override public void delete() { parent.delete(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java index c0dc9756c..e17a78765 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/BlockBagChangeSet.java @@ -112,7 +112,7 @@ public class BlockBagChangeSet extends AbstractDelegateChangeSet { @Override public void addTileCreate(CompoundTag nbt) { if (nbt.containsKey("items")) { - Map map = new HashMap<>(nbt.getValue()); + Map> map = new HashMap<>(nbt.getValue()); map.remove("items"); } super.addTileCreate(nbt); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index ad7c82c9f..e7132bf5a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -25,6 +25,7 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; @@ -35,11 +36,18 @@ import java.util.NoSuchElementException; public abstract class FaweStreamChangeSet extends AbstractChangeSet { public static final int HEADER_SIZE = 9; - private static final int version = 1; + private static final int VERSION = 2; + // equivalent to Short#MIN_VALUE three times stored with [(x) & 0xff, ((rx) >> 8) & 0xff] + private static final byte[] MAGIC_NEW_RELATIVE = new byte[]{0, (byte) 128, 0, (byte) 128, 0, (byte) 128}; private int mode; private final int compression; private final int minY; + protected long blockSize; + private int originX; + private int originZ; + private int version; + protected FaweStreamIdDelegate idDel; protected FaweStreamPositionDelegate posDel; @@ -192,6 +200,20 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { int rx = -lx + (lx = x); int ry = -ly + (ly = y); int rz = -lz + (lz = z); + // Use LE/GE to ensure we don't accidentally write MAGIC_NEW_RELATIVE + if (rx >= Short.MAX_VALUE || rz >= Short.MAX_VALUE || rx <= Short.MIN_VALUE || rz <= Short.MIN_VALUE) { + stream.write(MAGIC_NEW_RELATIVE); + stream.write((byte) (x >> 24)); + stream.write((byte) (x >> 16)); + stream.write((byte) (x >> 8)); + stream.write((byte) (x)); + stream.write((byte) (z >> 24)); + stream.write((byte) (z >> 16)); + stream.write((byte) (z >> 8)); + stream.write((byte) (z)); + rx = 0; + rz = 0; + } stream.write((rx) & 0xff); stream.write(((rx) >> 8) & 0xff); stream.write((rz) & 0xff); @@ -203,6 +225,12 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { @Override public int readX(FaweInputStream is) throws IOException { is.readFully(buffer); + // Don't break reading version 1 history (just in case) + if (version == 2 && Arrays.equals(buffer, MAGIC_NEW_RELATIVE)) { + lx = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read()); + lz = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read()); + is.readFully(buffer); + } return lx = lx + ((buffer[0] & 0xFF) | (buffer[1] << 8)); } @@ -222,7 +250,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void writeHeader(OutputStream os, int x, int y, int z) throws IOException { os.write(mode); // Allows for version detection of history in case of changes to format. - os.write(version); + os.write(VERSION); setOrigin(x, z); os.write((byte) (x >> 24)); os.write((byte) (x >> 16)); @@ -238,8 +266,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public void readHeader(InputStream is) throws IOException { // skip mode int mode = is.read(); - int version = is.read(); - if (version != FaweStreamChangeSet.version) { + version = is.read(); + if (version != 1 && version != VERSION) { // version 1 is fine throw new UnsupportedOperationException(String.format("Version %s history not supported!", version)); } // origin @@ -266,12 +294,17 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } @Override - public int size() { + public long longSize() { // Flush so we can accurately get the size flush(); return blockSize; } + @Override + public int size() { + return (int) longSize(); + } + public abstract int getCompressedSize(); public abstract long getSizeInMemory(); @@ -304,11 +337,6 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { public abstract NBTInputStream getTileRemoveIS() throws IOException; - protected int blockSize; - - private int originX; - private int originZ; - public void setOrigin(int x, int z) { originX = x; originZ = z; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java new file mode 100644 index 000000000..17f4b9f0a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/internal/io/VarIntStreamIterator.java @@ -0,0 +1,70 @@ +package com.fastasyncworldedit.core.internal.io; + +import java.io.IOException; +import java.io.InputStream; +import java.util.NoSuchElementException; +import java.util.PrimitiveIterator; + +/** + * Basically {@link com.sk89q.worldedit.internal.util.VarIntIterator} but backed by {@link java.io.InputStream} + */ +public class VarIntStreamIterator implements PrimitiveIterator.OfInt { + + private final InputStream parent; + private final int limit; + private int index; + private boolean hasNextInt; + private int nextInt; + + public VarIntStreamIterator(final InputStream parent, int limit) { + this.parent = parent; + this.limit = limit; + } + + @Override + public boolean hasNext() { + if (hasNextInt) { + return true; + } + if (index >= limit) { + return false; + } + + try { + nextInt = readNextInt(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return hasNextInt = true; + } + + @Override + public int nextInt() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + hasNextInt = false; + return nextInt; + } + + + private int readNextInt() throws IOException { + int value = 0; + for (int bitsRead = 0; ; bitsRead += 7) { + if (index >= limit) { + throw new IllegalStateException("Ran out of bytes while reading VarInt (probably corrupted data)"); + } + byte next = (byte) this.parent.read(); + index++; + value |= (next & 0x7F) << bitsRead; + if (bitsRead > 7 * 5) { + throw new IllegalStateException("VarInt too big (probably corrupted data)"); + } + if ((next & 0x80) == 0) { + break; + } + } + return value; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java index 85bdddf09..efed01376 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedCompoundTag.java @@ -19,7 +19,7 @@ public abstract class CompressedCompoundTag extends CompoundTag { } @Override - public Map getValue() { + public Map> getValue() { if (in != null) { decompress(); } @@ -36,8 +36,8 @@ public abstract class CompressedCompoundTag extends CompoundTag { try (NBTInputStream nbtIn = new NBTInputStream(adapt(in))) { in = null; CompoundTag tag = (CompoundTag) nbtIn.readTag(); - Map value = tag.getValue(); - Map raw = super.getValue(); + Map> value = tag.getValue(); + Map> raw = super.getValue(); raw.putAll(value); } catch (IOException e) { throw new RuntimeException(e); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java index e622b1501..3c569f913 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/CompressedSchematicTag.java @@ -1,6 +1,6 @@ package com.fastasyncworldedit.core.jnbt; -import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter; +import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriterV2; import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream; import com.fastasyncworldedit.core.internal.io.FastByteArraysInputStream; import com.sk89q.jnbt.NBTOutputStream; @@ -21,7 +21,7 @@ public class CompressedSchematicTag extends CompressedCompoundTag { FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream(); try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) { NBTOutputStream nbtOut = new NBTOutputStream(lz4out); - new FastSchematicWriter(nbtOut).write(getSource()); + new FastSchematicWriterV2(nbtOut).write(getSource()); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java index 8b942895d..6cdef3dda 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/JSON2NBT.java @@ -17,7 +17,6 @@ import com.sk89q.jnbt.Tag; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.Stack; import java.util.regex.Pattern; @@ -409,7 +408,7 @@ public class JSON2NBT { } public Tag parse() throws NBTException { - HashMap map = new HashMap<>(); + HashMap> map = new HashMap<>(); for (Any JSON2NBT$any : this.tagList) { map.put(JSON2NBT$any.json, JSON2NBT$any.parse()); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java index db1984bb3..5931069c6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/jnbt/NumberTag.java @@ -1,11 +1,16 @@ package com.fastasyncworldedit.core.jnbt; import com.sk89q.jnbt.Tag; +import org.enginehub.linbus.tree.LinTag; /** * A numerical {@link Tag} */ -public abstract class NumberTag extends Tag { +public abstract class NumberTag> extends Tag { + + protected NumberTag(LT linTag) { + super(linTag); + } @Override public abstract Number getValue(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java index e30ee4db6..d17787f03 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/limit/FaweLimit.java @@ -28,6 +28,7 @@ public class FaweLimit { public boolean FAST_PLACEMENT = false; public boolean CONFIRM_LARGE = true; public boolean RESTRICT_HISTORY_TO_REGIONS = true; + public boolean ALLOW_LEGACY = true; public Set STRIP_NBT = null; public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; public Set DISALLOWED_BLOCKS = null; @@ -127,6 +128,7 @@ public class FaweLimit { MAX.RESTRICT_HISTORY_TO_REGIONS = false; MAX.STRIP_NBT = Collections.emptySet(); MAX.UNIVERSAL_DISALLOWED_BLOCKS = false; + MAX.ALLOW_LEGACY = true; MAX.DISALLOWED_BLOCKS = Collections.emptySet(); MAX.REMAP_PROPERTIES = Collections.emptySet(); MAX.MAX_RADIUS = Integer.MAX_VALUE; @@ -259,13 +261,13 @@ public class FaweLimit { && !RESTRICT_HISTORY_TO_REGIONS && (STRIP_NBT == null || STRIP_NBT.isEmpty()) // && !UNIVERSAL_DISALLOWED_BLOCKS --> do not include this, it effectively has no relevance + && ALLOW_LEGACY && (DISALLOWED_BLOCKS == null || DISALLOWED_BLOCKS.isEmpty()) && (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty()) && MAX_RADIUS == Integer.MAX_VALUE && MAX_SUPER_PICKAXE_SIZE == Integer.MAX_VALUE && MAX_BRUSH_RADIUS == Integer.MAX_VALUE && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; - } public void set(FaweLimit limit) { @@ -286,6 +288,7 @@ public class FaweLimit { RESTRICT_HISTORY_TO_REGIONS = limit.RESTRICT_HISTORY_TO_REGIONS; STRIP_NBT = limit.STRIP_NBT; UNIVERSAL_DISALLOWED_BLOCKS = limit.UNIVERSAL_DISALLOWED_BLOCKS; + ALLOW_LEGACY = limit.ALLOW_LEGACY; DISALLOWED_BLOCKS = limit.DISALLOWED_BLOCKS; REMAP_PROPERTIES = limit.REMAP_PROPERTIES; MAX_RADIUS = limit.MAX_RADIUS; @@ -313,6 +316,7 @@ public class FaweLimit { limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS; limit.STRIP_NBT = STRIP_NBT; limit.UNIVERSAL_DISALLOWED_BLOCKS = UNIVERSAL_DISALLOWED_BLOCKS; + limit.ALLOW_LEGACY = ALLOW_LEGACY; limit.DISALLOWED_BLOCKS = DISALLOWED_BLOCKS; limit.REMAP_PROPERTIES = REMAP_PROPERTIES; limit.MAX_RADIUS = MAX_RADIUS; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java index b181f9506..8911099af 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java @@ -192,12 +192,13 @@ public class BlockVectorSet extends AbstractCollection implements } public boolean remove(int x, int y, int z) { - int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11)); - LocalBlockVectorSet localMap = localSets.get(pair); + int indexedY = (y + 128) >> 9; + long triple = MathMan.tripleWorldCoord((x >> 11), indexedY, (z >> 11)); + LocalBlockVectorSet localMap = localSets.get(triple); if (localMap != null) { - if (localMap.remove(x & 2047, y, z & 2047)) { + if (localMap.remove(x & 2047, ((y + 128) & 511) - 128, z & 2047)) { if (localMap.isEmpty()) { - localSets.remove(pair); + localSets.remove(triple); } return true; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java index a56fe27d5..534a96fac 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkExtent.java @@ -124,7 +124,7 @@ public interface IChunkExtent extends Extent { @Override default Entity createEntity(Location location, BaseEntity entity, UUID uuid) { final IChunk chunk = getOrCreateChunk(location.getBlockX() >> 4, location.getBlockZ() >> 4); - Map map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data + Map> map = new HashMap<>(entity.getNbtData().getValue()); //do not modify original entity data map.put("Id", new StringTag(entity.getType().getName())); //Set pos diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java index 047394322..c338033f0 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharBlocks.java @@ -31,7 +31,9 @@ public abstract class CharBlocks implements IBlocks { char[] arr = blocks.blocks[layer]; if (arr == null) { // Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues - return EMPTY.get(blocks, layer, false); + synchronized (blocks.sectionLocks[layer]) { + return getSkipFull(blocks, layer, aggressive); + } } return arr; } @@ -54,22 +56,7 @@ public abstract class CharBlocks implements IBlocks { if (blocks.sections[layer] == FULL) { return FULL.get(blocks, layer); } - char[] arr = blocks.blocks[layer]; - if (arr == null) { - arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive); - if (arr == null) { - throw new IllegalStateException("Array cannot be null: " + blocks.getClass()); - } - } else { - blocks.blocks[layer] = blocks.update(layer, arr, aggressive); - if (blocks.blocks[layer] == null) { - throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass()); - } - } - if (blocks.blocks[layer] != null) { - blocks.sections[layer] = FULL; - } - return arr; + return getSkipFull(blocks, layer, aggressive); } } @@ -262,6 +249,25 @@ public abstract class CharBlocks implements IBlocks { get(blocks, layer)[index] = value; } + static char[] getSkipFull(CharBlocks blocks, int layer, boolean aggressive) { + char[] arr = blocks.blocks[layer]; + if (arr == null) { + arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive); + if (arr == null) { + throw new IllegalStateException("Array cannot be null: " + blocks.getClass()); + } + } else { + blocks.blocks[layer] = blocks.update(layer, arr, aggressive); + if (blocks.blocks[layer] == null) { + throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass()); + } + } + if (blocks.blocks[layer] != null) { + blocks.sections[layer] = FULL; + } + return arr; + } + } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java index a1471c9d8..675e8efb6 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/regions/PolyhedralRegion.java @@ -77,7 +77,7 @@ public class PolyhedralRegion extends AbstractRegion { minimumPoint = region.minimumPoint; maximumPoint = region.maximumPoint; centerAccum = region.centerAccum; - lastTriangle = region.lastTriangle; + lastTriangle = lastTriangle == null ? null : region.lastTriangle.clone(); } /** diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java index afab331a7..762929400 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/BrushCache.java @@ -82,7 +82,7 @@ public final class BrushCache { } CompoundTag nbt = item.getNbtData(); - Map map; + Map> map; if (nbt == null) { if (tool == null) { item.setNbtData(null); @@ -92,9 +92,10 @@ public final class BrushCache { } else { map = nbt.getValue(); } + item.setNbtData(nbt); brushCache.remove(getKey(item)); CompoundTag display = (CompoundTag) map.get("display"); - Map displayMap; + Map> displayMap; return tool; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 7d7d5d642..0c323e47b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -217,7 +217,7 @@ public class MainUtil { // } else if (changeSet instanceof CPUOptimizedChangeSet) { // return changeSet.size() + 32; } else if (changeSet != null) { - return changeSet.size() * 128L; + return changeSet.longSize() * 128; // Approx } else { return 0; } @@ -427,7 +427,7 @@ public class MainUtil { */ @Nonnull public static CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) { - Map value = new HashMap<>(tag.getValue()); + Map> value = new HashMap<>(tag.getValue()); value.put("x", new IntTag(x)); value.put("y", new IntTag(y)); value.put("z", new IntTag(z)); @@ -443,7 +443,7 @@ public class MainUtil { */ @Nonnull public static CompoundTag setEntityInfo(@Nonnull CompoundTag tag, @Nonnull Entity entity) { - Map map = new HashMap<>(tag.getValue()); + Map> map = new HashMap<>(tag.getValue()); map.put("Id", new StringTag(entity.getState().getType().id())); ListTag pos = (ListTag) map.get("Pos"); if (pos != null) { @@ -712,6 +712,12 @@ public class MainUtil { return file; } } + if (filename.matches(".*\\.[\\w].*")) { + File file = MainUtil.resolveRelative(new File(dir, filename)); + if (file.exists()) { + return file; + } + } for (ClipboardFormat f : ClipboardFormats.getAll()) { File file = MainUtil.resolveRelative(new File(dir, filename + "." + f.getPrimaryFileExtension())); if (file.exists()) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index 7abb51284..07157e820 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -1,13 +1,12 @@ package com.fastasyncworldedit.core.util; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagType; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.HashMap; import java.util.Map; @@ -23,9 +22,9 @@ public class NbtUtils { * @return child tag * @throws InvalidFormatException if the format of the items is invalid */ - public static T getChildTag(CompoundBinaryTag tag, String key, BinaryTagType expected) throws + public static T getChildTag(LinCompoundTag tag, String key, LinTagType expected) throws InvalidFormatException { - BinaryTag childTag = tag.get(key); + LinTag childTag = tag.value().get(key); if (childTag == null) { throw new InvalidFormatException("Missing a \"" + key + "\" tag"); } @@ -48,35 +47,35 @@ public class NbtUtils { * @throws InvalidFormatException if the format of the items is invalid * @since 2.1.0 */ - public static int getInt(CompoundBinaryTag tag, String key) throws InvalidFormatException { - BinaryTag childTag = tag.get(key); + public static int getInt(LinCompoundTag tag, String key) throws InvalidFormatException { + LinTag childTag = tag.value().get(key); if (childTag == null) { throw new InvalidFormatException("Missing a \"" + key + "\" tag"); } - BinaryTagType type = childTag.type(); - if (type == BinaryTagTypes.INT) { - return ((IntBinaryTag) childTag).intValue(); + LinTagType type = childTag.type(); + if (type == LinTagType.intTag()) { + return ((LinIntTag) childTag).value(); } - if (type == BinaryTagTypes.BYTE) { - return ((ByteBinaryTag) childTag).intValue(); + if (type == LinTagType.byteTag()) { + return ((LinByteTag) childTag).value(); } - if (type == BinaryTagTypes.SHORT) { - return ((ShortBinaryTag) childTag).intValue(); + if (type == LinTagType.shortTag()) { + return ((LinShortTag) childTag).value(); } throw new InvalidFormatException(key + " tag is not of int, short or byte tag type."); } /** - * Get a mutable map of the values stored inside a {@link CompoundBinaryTag} + * Get a mutable map of the values stored inside a {@link LinCompoundTag} * - * @param tag {@link CompoundBinaryTag} to get values for + * @param tag {@link LinCompoundTag} to get values for * @return Mutable map of values * @since 2.1.0 */ - public static Map getCompoundBinaryTagValues(CompoundBinaryTag tag) { - Map value = new HashMap<>(); - tag.forEach((e) -> value.put(e.getKey(), e.getValue())); + public static Map> getLinCompoundTagValues(LinCompoundTag tag) { + Map> value = new HashMap<>(); + value.putAll(tag.value()); return value; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java index 859ed9194..9fbdd88bd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/gson/BaseItemAdapter.java @@ -10,9 +10,10 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.tree.LinCompoundTag; import java.io.IOException; import java.lang.reflect.Type; @@ -36,7 +37,10 @@ public final class BaseItemAdapter implements JsonDeserializer, JsonSe return new BaseItem(itemType); } try { - return new BaseItem(itemType, LazyReference.computed(TagStringIO.get().asCompound(nbt.getAsString()))); + return new BaseItem( + itemType, + LazyReference.computed(LinCompoundTag.readFrom(LinStringIO.readFromString(nbt.getAsString()))) + ); } catch (IOException e) { throw new JsonParseException("Could not deserialize BaseItem", e); } @@ -50,12 +54,8 @@ public final class BaseItemAdapter implements JsonDeserializer, JsonSe ) { JsonObject obj = new JsonObject(); obj.add("itemType", jsonSerializationContext.serialize(baseItem.getType())); - try { - obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(TagStringIO.get().asString(baseItem.getNbt()))); - return obj; - } catch (IOException e) { - throw new JsonParseException("Could not deserialize BaseItem", e); - } + obj.add("nbt", baseItem.getNbt() == null ? null : new JsonPrimitive(LinStringIO.writeToString(baseItem.getNbt()))); + return obj; } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java b/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java deleted file mode 100644 index 1e9d36178..000000000 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * WorldEdit, a Minecraft world manipulation toolkit - * Copyright (C) sk89q - * Copyright (C) WorldEdit team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.sk89q.jnbt; - -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableMap; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagType; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -/** - * Converts between JNBT and Adventure-NBT classes. - * - * @deprecated JNBT is being removed in WE8. - */ -@Deprecated(forRemoval = true) -public class AdventureNBTConverter { - - private static final BiMap, BinaryTagType> TAG_TYPES = - new ImmutableBiMap.Builder, BinaryTagType>() - .put(ByteArrayTag.class, BinaryTagTypes.BYTE_ARRAY) - .put(ByteTag.class, BinaryTagTypes.BYTE) - .put(CompoundTag.class, BinaryTagTypes.COMPOUND) - .put(DoubleTag.class, BinaryTagTypes.DOUBLE) - .put(EndTag.class, BinaryTagTypes.END) - .put(FloatTag.class, BinaryTagTypes.FLOAT) - .put(IntArrayTag.class, BinaryTagTypes.INT_ARRAY) - .put(IntTag.class, BinaryTagTypes.INT) - .put(ListTag.class, BinaryTagTypes.LIST) - .put(LongArrayTag.class, BinaryTagTypes.LONG_ARRAY) - .put(LongTag.class, BinaryTagTypes.LONG) - .put(ShortTag.class, BinaryTagTypes.SHORT) - .put(StringTag.class, BinaryTagTypes.STRING) - .build(); - - private static final Map, Function> CONVERSION; - - static { - ImmutableMap.Builder, Function> conversion = - ImmutableMap.builder(); - - for (Map.Entry, BinaryTagType> tag : TAG_TYPES.entrySet()) { - Constructor[] constructors = tag.getKey().getConstructors(); - for (Constructor c : constructors) { - if (c.getParameterCount() == 1 && BinaryTag.class.isAssignableFrom(c.getParameterTypes()[0])) { - conversion.put(tag.getValue(), binaryTag -> { - try { - return (Tag) c.newInstance(binaryTag); - } catch (InstantiationException | IllegalAccessException e) { - throw new IllegalStateException(e); - } catch (InvocationTargetException e) { - // I assume this is always a RuntimeException since we control the ctor - throw (RuntimeException) e.getCause(); - } - }); - break; - } - } - } - - CONVERSION = conversion.build(); - } - - public static BinaryTagType getAdventureType(Class type) { - return Objects.requireNonNull(TAG_TYPES.get(type), () -> "Missing entry for " + type); - } - - public static Class getJNBTType(BinaryTagType type) { - return Objects.requireNonNull(TAG_TYPES.inverse().get(type), () -> "Missing entry for " + type); - } - - private AdventureNBTConverter() { - } - - public static Tag fromAdventure(BinaryTag other) { - if (other == null) { - return null; - } - Function conversion = CONVERSION.get(other.type()); - if (conversion == null) { - throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); - } - return conversion.apply(other); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java index 094a7c9bb..4889235eb 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -19,41 +19,26 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag; +import org.enginehub.linbus.tree.LinByteArrayTag; /** * The {@code TAG_Byte_Array} tag. * - * @deprecated Use {@link ByteArrayBinaryTag}. + * @deprecated Use {@link LinByteArrayTag}. */ @Deprecated -public final class ByteArrayTag extends Tag { - - private final ByteArrayBinaryTag innerTag; - +public final class ByteArrayTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public ByteArrayTag(byte[] value) { - super(); - this.innerTag = ByteArrayBinaryTag.of(value); + this(LinByteArrayTag.of(value)); } - public ByteArrayTag(ByteArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public byte[] getValue() { - return innerTag.value(); - } - - @Override - public ByteArrayBinaryTag asBinaryTag() { - return innerTag; + public ByteArrayTag(LinByteArrayTag tag) { + super(tag); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java index 6068b2af0..6b3d3d153 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java @@ -19,41 +19,32 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.ByteBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinByteTag; /** * The {@code TAG_Byte} tag. * - * @deprecated Use {@link ByteBinaryTag}. + * @deprecated Use {@link LinByteTag}. */ @Deprecated -public final class ByteTag extends Tag { - - private final ByteBinaryTag innerTag; - +public final class ByteTag extends NumberTag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public ByteTag(byte value) { - super(); - this.innerTag = ByteBinaryTag.of(value); + this(LinByteTag.of(value)); } - public ByteTag(ByteBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; + public ByteTag(LinByteTag tag) { + super(tag); } @Override public Byte getValue() { - return innerTag.value(); - } - - @Override - public ByteBinaryTag asBinaryTag() { - return innerTag; + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java index d91aea8fe..10e9adf08 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java @@ -25,10 +25,11 @@ import com.google.common.collect.Maps; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagLike; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.NumberBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinNumberTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.Collections; import java.util.HashMap; @@ -39,26 +40,24 @@ import java.util.UUID; /** * The {@code TAG_Compound} tag. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag}. + * @deprecated Use {@link LinCompoundTag}. */ @Deprecated -public class CompoundTag extends Tag { - - private final CompoundBinaryTag innerTag; +//FAWE start - nonfinal +public class CompoundTag extends Tag { + //FAWE end /** * Creates the tag with an empty name. * * @param value the value of the tag */ - public CompoundTag(Map value) { - this(CompoundBinaryTag.builder() - .put(Maps.transformValues(value, BinaryTagLike::asBinaryTag)) - .build()); + public CompoundTag(Map> value) { + this(LinCompoundTag.of(Maps.transformValues(value, Tag::toLinTag))); } - public CompoundTag(CompoundBinaryTag adventureTag) { - this.innerTag = adventureTag; + public CompoundTag(LinCompoundTag tag) { + super(tag); } /** @@ -68,16 +67,16 @@ public class CompoundTag extends Tag { * @return true if the tag contains the given key */ public boolean containsKey(String key) { - return innerTag.keySet().contains(key); + return linTag.value().containsKey(key); } + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override - public Map getValue() { - ImmutableMap.Builder map = ImmutableMap.builder(); - for (String key : innerTag.keySet()) { - map.put(key, AdventureNBTConverter.fromAdventure(innerTag.get(key))); - } - return map.build(); + public Map> getValue() { + return ImmutableMap.copyOf(Maps.transformValues( + linTag.value(), + tag -> (Tag) LinBusConverter.toJnbtTag((LinTag) tag) + )); } /** @@ -86,7 +85,7 @@ public class CompoundTag extends Tag { * @param value the value * @return the new compound tag */ - public CompoundTag setValue(Map value) { + public CompoundTag setValue(Map> value) { return new CompoundTag(value); } @@ -96,7 +95,7 @@ public class CompoundTag extends Tag { * @return the builder */ public CompoundTagBuilder createBuilder() { - return new CompoundTagBuilder(innerTag); + return new CompoundTagBuilder(linTag); } /** @@ -109,7 +108,8 @@ public class CompoundTag extends Tag { * @return a byte array */ public byte[] getByteArray(String key) { - return this.innerTag.getByteArray(key); + var tag = linTag.findTag(key, LinTagType.byteArrayTag()); + return tag == null ? new byte[0] : tag.value(); } /** @@ -122,7 +122,8 @@ public class CompoundTag extends Tag { * @return a byte */ public byte getByte(String key) { - return this.innerTag.getByte(key); + var tag = linTag.findTag(key, LinTagType.byteTag()); + return tag == null ? 0 : tag.value(); } /** @@ -135,7 +136,8 @@ public class CompoundTag extends Tag { * @return a double */ public double getDouble(String key) { - return this.innerTag.getDouble(key); + var tag = linTag.findTag(key, LinTagType.doubleTag()); + return tag == null ? 0 : tag.value(); } /** @@ -149,9 +151,10 @@ public class CompoundTag extends Tag { * @return a double */ public double asDouble(String key) { - BinaryTag tag = this.innerTag.get(key); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).doubleValue(); + var tag = linTag.value().get(key); + if (tag instanceof LinNumberTag numberTag) { + Number value = numberTag.value(); + return value.doubleValue(); } return 0; } @@ -166,7 +169,8 @@ public class CompoundTag extends Tag { * @return a float */ public float getFloat(String key) { - return this.innerTag.getFloat(key); + var tag = linTag.findTag(key, LinTagType.floatTag()); + return tag == null ? 0 : tag.value(); } /** @@ -179,7 +183,8 @@ public class CompoundTag extends Tag { * @return an int array */ public int[] getIntArray(String key) { - return this.innerTag.getIntArray(key); + var tag = linTag.findTag(key, LinTagType.intArrayTag()); + return tag == null ? new int[0] : tag.value(); } /** @@ -192,7 +197,8 @@ public class CompoundTag extends Tag { * @return an int */ public int getInt(String key) { - return this.innerTag.getInt(key); + var tag = linTag.findTag(key, LinTagType.intTag()); + return tag == null ? 0 : tag.value(); } /** @@ -206,9 +212,10 @@ public class CompoundTag extends Tag { * @return an int */ public int asInt(String key) { - BinaryTag tag = this.innerTag.get(key); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).intValue(); + var tag = linTag.value().get(key); + if (tag instanceof LinNumberTag numberTag) { + Number value = numberTag.value(); + return value.intValue(); } return 0; } @@ -222,7 +229,7 @@ public class CompoundTag extends Tag { * @param key the key * @return a list of tags */ - public List getList(String key) { + public List> getList(String key) { return getListTag(key).getValue(); } @@ -235,8 +242,15 @@ public class CompoundTag extends Tag { * @param key the key * @return a tag list instance */ - public ListTag getListTag(String key) { - return new ListTag(this.innerTag.getList(key)); + public > ListTag getListTag(String key) { + LinListTag tag = linTag.findTag(key, LinTagType.listTag()); + if (tag == null) { + // This is actually hella unsafe. But eh. + @SuppressWarnings("unchecked") + LinTagType endGenerically = (LinTagType) LinTagType.endTag(); + return new ListTag<>(LinListTag.empty(endGenerically)); + } + return new ListTag<>(tag); } /** @@ -253,8 +267,8 @@ public class CompoundTag extends Tag { * @return a list of tags */ @SuppressWarnings("unchecked") - public List getList(String key, Class listType) { - ListTag listTag = getListTag(key); + public > List getList(String key, Class listType) { + ListTag listTag = getListTag(key); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); } else { @@ -272,7 +286,8 @@ public class CompoundTag extends Tag { * @return an int array */ public long[] getLongArray(String key) { - return this.innerTag.getLongArray(key); + var tag = linTag.findTag(key, LinTagType.longArrayTag()); + return tag == null ? new long[0] : tag.value(); } /** @@ -285,7 +300,8 @@ public class CompoundTag extends Tag { * @return a long */ public long getLong(String key) { - return this.innerTag.getLong(key); + var tag = linTag.findTag(key, LinTagType.longTag()); + return tag == null ? 0 : tag.value(); } /** @@ -299,9 +315,10 @@ public class CompoundTag extends Tag { * @return a long */ public long asLong(String key) { - BinaryTag tag = this.innerTag.get(key); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).longValue(); + var tag = linTag.value().get(key); + if (tag instanceof LinNumberTag numberTag) { + Number value = numberTag.value(); + return value.longValue(); } return 0; } @@ -316,7 +333,8 @@ public class CompoundTag extends Tag { * @return a short */ public short getShort(String key) { - return this.innerTag.getShort(key); + var tag = linTag.findTag(key, LinTagType.shortTag()); + return tag == null ? 0 : tag.value(); } /** @@ -329,12 +347,8 @@ public class CompoundTag extends Tag { * @return a string */ public String getString(String key) { - return this.innerTag.getString(key); - } - - @Override - public CompoundBinaryTag asBinaryTag() { - return this.innerTag; + var tag = linTag.findTag(key, LinTagType.stringTag()); + return tag == null ? "" : tag.value(); } @@ -357,7 +371,7 @@ public class CompoundTag extends Tag { } public Vector3 getEntityPosition() { - List posTags = getList("Pos"); + List> posTags = getList("Pos"); double x = ((NumberTag) posTags.get(0)).getValue().doubleValue(); double y = ((NumberTag) posTags.get(1)).getValue().doubleValue(); double z = ((NumberTag) posTags.get(2)).getValue().doubleValue(); @@ -365,7 +379,7 @@ public class CompoundTag extends Tag { } public Location getEntityLocation(Extent extent) { - List rotTag = getList("Rotation"); + List> rotTag = getList("Rotation"); float yaw = ((NumberTag) rotTag.get(0)).getValue().floatValue(); float pitch = ((NumberTag) rotTag.get(1)).getValue().floatValue(); return new Location(extent, getEntityPosition(), yaw, pitch); @@ -382,7 +396,7 @@ public class CompoundTag extends Tag { if (this.getValue().isEmpty()) { return raw; } - for (Map.Entry entry : getValue().entrySet()) { + for (Map.Entry> entry : getValue().entrySet()) { raw.put(entry.getKey(), entry.getValue().toRaw()); } return raw; diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java index f21bdb8cc..535722b74 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -19,27 +19,27 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Map; -import java.util.Objects; import static com.google.common.base.Preconditions.checkNotNull; /** * Helps create compound tags. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag.Builder}. + * @deprecated Use {@link LinCompoundTag.Builder}. */ @Deprecated public class CompoundTagBuilder { - private final CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder(); + private final LinCompoundTag.Builder builder; /** * Create a new instance. */ CompoundTagBuilder() { + this.builder = LinCompoundTag.builder(); } /** @@ -47,11 +47,9 @@ public class CompoundTagBuilder { * * @param source the value */ - CompoundTagBuilder(CompoundBinaryTag source) { + CompoundTagBuilder(LinCompoundTag source) { checkNotNull(source); - for (String key : source.keySet()) { - this.builder.put(key, Objects.requireNonNull(source.get(key))); - } + this.builder = source.toBuilder(); } /** @@ -61,10 +59,10 @@ public class CompoundTagBuilder { * @param value the value * @return this object */ - public CompoundTagBuilder put(String key, Tag value) { + public CompoundTagBuilder put(String key, Tag value) { checkNotNull(key); checkNotNull(value); - this.builder.put(key, value.asBinaryTag()); + this.builder.put(key, value.toLinTag()); return this; } @@ -215,9 +213,9 @@ public class CompoundTagBuilder { * @param value the map of tags * @return this object */ - public CompoundTagBuilder putAll(Map value) { + public CompoundTagBuilder putAll(Map> value) { checkNotNull(value); - for (Map.Entry entry : value.entrySet()) { + for (Map.Entry> entry : value.entrySet()) { put(entry.getKey(), entry.getValue()); } return this; diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java index da0890ea6..6dad5186b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java @@ -20,17 +20,15 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.jnbt.NumberTag; -import com.sk89q.worldedit.util.nbt.DoubleBinaryTag; +import org.enginehub.linbus.tree.LinDoubleTag; /** * The {@code TAG_Double} tag. * - * @deprecated Use {@link DoubleBinaryTag}. + * @deprecated Use {@link LinDoubleTag}. */ @Deprecated -public final class DoubleTag extends NumberTag { - - private final DoubleBinaryTag innerTag; +public final class DoubleTag extends NumberTag { /** * Creates the tag with an empty name. @@ -38,23 +36,16 @@ public final class DoubleTag extends NumberTag { * @param value the value of the tag */ public DoubleTag(double value) { - super(); - this.innerTag = DoubleBinaryTag.of(value); + this(LinDoubleTag.of(value)); } - public DoubleTag(DoubleBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public DoubleBinaryTag asBinaryTag() { - return this.innerTag; + public DoubleTag(LinDoubleTag tag) { + super(tag); } @Override public Double getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java index 18347d928..523fcf79e 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java @@ -19,24 +19,17 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.EndBinaryTag; +import org.enginehub.linbus.tree.LinEndTag; /** * The {@code TAG_End} tag. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.EndBinaryTag}. + * @deprecated Use {@link LinEndTag}. */ @Deprecated -public final class EndTag extends Tag { - - @Override - public Object getValue() { - return null; - } - - @Override - public EndBinaryTag asBinaryTag() { - return EndBinaryTag.get(); +public final class EndTag extends Tag { + public EndTag() { + super(LinEndTag.instance()); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java index 2e1533827..128e36014 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java @@ -20,17 +20,14 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.jnbt.NumberTag; -import com.sk89q.worldedit.util.nbt.FloatBinaryTag; +import org.enginehub.linbus.tree.LinFloatTag; /** * The {@code TAG_Float} tag. * - * @deprecated Use {@link FloatBinaryTag}. + * @deprecated Use {@link LinFloatTag}. */ -@Deprecated -public final class FloatTag extends NumberTag { - - private final FloatBinaryTag innerTag; +public final class FloatTag extends NumberTag { /** * Creates the tag with an empty name. @@ -38,23 +35,16 @@ public final class FloatTag extends NumberTag { * @param value the value of the tag */ public FloatTag(float value) { - super(); - this.innerTag = FloatBinaryTag.of(value); + this(LinFloatTag.of(value)); } - public FloatTag(FloatBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public FloatBinaryTag asBinaryTag() { - return this.innerTag; + public FloatTag(LinFloatTag tag) { + super(tag); } @Override public Float getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java index 76d8fac74..0e3536eed 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -19,44 +19,33 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag; +import org.enginehub.linbus.tree.LinIntArrayTag; import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_Int_Array} tag. * - * @deprecated Use {@link IntArrayBinaryTag}. + * @deprecated Use {@link LinIntArrayTag}. */ @Deprecated -public final class IntArrayTag extends Tag { - - private final IntArrayBinaryTag innerTag; - +public final class IntArrayTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public IntArrayTag(int[] value) { - super(); - checkNotNull(value); - this.innerTag = IntArrayBinaryTag.of(value); + this(LinIntArrayTag.of(checkNotNull(value))); } - public IntArrayTag(IntArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public IntArrayBinaryTag asBinaryTag() { - return this.innerTag; + public IntArrayTag(LinIntArrayTag tag) { + super(tag); } @Override public int[] getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java index c6ff80252..c4c90889b 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java @@ -19,17 +19,16 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinIntTag; /** * The {@code TAG_Int} tag. * - * @deprecated Use {@link IntBinaryTag}. + * @deprecated Use {@link LinIntTag}. */ @Deprecated -public final class IntTag extends Tag { - - private final IntBinaryTag innerTag; +public final class IntTag extends NumberTag { /** * Creates the tag with an empty name. @@ -37,23 +36,16 @@ public final class IntTag extends Tag { * @param value the value of the tag */ public IntTag(int value) { - super(); - this.innerTag = IntBinaryTag.of(value); + this(LinIntTag.of(value)); } - public IntTag(IntBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public IntBinaryTag asBinaryTag() { - return this.innerTag; + public IntTag(LinIntTag tag) { + super(tag); } @Override public Integer getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java index 00b5aeb9a..4ce6febd6 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LazyCompoundTag.java @@ -20,27 +20,27 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Map; /** * Allows detection of the version-specific LazyCompoundTag classes. * - * @deprecated Use {@link CompoundBinaryTag}. + * @deprecated Use {@link LinCompoundTag}. */ @Deprecated public abstract class LazyCompoundTag extends CompoundTag { - public LazyCompoundTag(Map value) { + public LazyCompoundTag(Map> value) { super(value); } - public LazyCompoundTag(CompoundBinaryTag adventureTag) { + public LazyCompoundTag(LinCompoundTag adventureTag) { super(adventureTag); } @Override - public abstract CompoundBinaryTag asBinaryTag(); + public abstract LinCompoundTag toLinTag(); } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java new file mode 100644 index 000000000..52b30f599 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LinBusConverter.java @@ -0,0 +1,140 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.jnbt; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableMap; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongArrayTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +/** + * Converts between JNBT and Adventure-NBT classes. + * + * @deprecated JNBT is being removed in WE8. + */ +@Deprecated(forRemoval = true) +public class LinBusConverter { + + private static final BiMap, LinTagType> TAG_TYPES = + new ImmutableBiMap.Builder, LinTagType>() + .put(ByteArrayTag.class, LinTagType.byteArrayTag()) + .put(ByteTag.class, LinTagType.byteTag()) + .put(CompoundTag.class, LinTagType.compoundTag()) + .put(DoubleTag.class, LinTagType.doubleTag()) + .put(EndTag.class, LinTagType.endTag()) + .put(FloatTag.class, LinTagType.floatTag()) + .put(IntArrayTag.class, LinTagType.intArrayTag()) + .put(IntTag.class, LinTagType.intTag()) + .put(ListTag.class, LinTagType.listTag()) + .put(LongArrayTag.class, LinTagType.longArrayTag()) + .put(LongTag.class, LinTagType.longTag()) + .put(ShortTag.class, LinTagType.shortTag()) + .put(StringTag.class, LinTagType.stringTag()) + .build(); + + private static final Map, Function> CONVERSION; + + static { + ImmutableMap.Builder, Function> conversion = + ImmutableMap.builder(); + + for (Map.Entry, LinTagType> tag : TAG_TYPES.entrySet()) { + Constructor[] constructors = tag.getKey().getConstructors(); + for (Constructor c : constructors) { + if (c.getParameterCount() == 1 && LinTag.class.isAssignableFrom(c.getParameterTypes()[0])) { + conversion.put(tag.getValue(), linTag -> { + try { + return (Tag) c.newInstance(linTag); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + // I assume this is always a RuntimeException since we control the ctor + throw (RuntimeException) e.getCause(); + } + }); + break; + } + } + } + + CONVERSION = conversion.build(); + } + + public static LinTagType getAdventureType(Class type) { + return Objects.requireNonNull(TAG_TYPES.get(type), () -> "Missing entry for " + type); + } + + public static Class getJNBTType(LinTagType type) { + return Objects.requireNonNull(TAG_TYPES.inverse().get(type), () -> "Missing entry for " + type); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static > Tag toJnbtTag(LT tag) { + return (Tag) switch (tag.type().id()) { + case BYTE_ARRAY -> new ByteArrayTag((LinByteArrayTag) tag); + case BYTE -> new ByteTag((LinByteTag) tag); + case COMPOUND -> new CompoundTag((LinCompoundTag) tag); + case DOUBLE -> new DoubleTag((LinDoubleTag) tag); + case END -> new EndTag(); + case FLOAT -> new FloatTag((LinFloatTag) tag); + case INT_ARRAY -> new IntArrayTag((LinIntArrayTag) tag); + case INT -> new IntTag((LinIntTag) tag); + case LIST -> new ListTag((LinListTag) tag); + case LONG_ARRAY -> new LongArrayTag((LinLongArrayTag) tag); + case LONG -> new LongTag((LinLongTag) tag); + case SHORT -> new ShortTag((LinShortTag) tag); + case STRING -> new StringTag((LinStringTag) tag); + }; + } + + private LinBusConverter() { + } + + public static Tag fromLinBus(LinTag other) { + if (other == null) { + return null; + } + Function conversion = CONVERSION.get(other.type()); + if (conversion == null) { + throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); + } + return conversion.apply(other); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java index 879a0d4a3..d3c330d4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java @@ -19,10 +19,20 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagLike; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; -import com.sk89q.worldedit.util.nbt.NumberBinaryTag; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinByteTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinLongTag; +import org.enginehub.linbus.tree.LinNumberTag; +import org.enginehub.linbus.tree.LinShortTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.Collections; @@ -34,12 +44,10 @@ import java.util.stream.Collectors; /** * The {@code TAG_List} tag. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag}. + * @deprecated Use {@link LinListTag}. */ @Deprecated -public final class ListTag extends Tag { - - private final ListBinaryTag innerTag; +public final class ListTag> extends Tag> { /** * Creates the tag with an empty name. @@ -47,20 +55,15 @@ public final class ListTag extends Tag { * @param type the type of tag * @param value the value of the tag */ - public ListTag(Class type, List value) { - this(ListBinaryTag.of( - AdventureNBTConverter.getAdventureType(type), - value.stream().map(BinaryTagLike::asBinaryTag).collect(Collectors.toList()) + public ListTag(Class> type, List> value) { + this(LinListTag.of( + LinTagType.fromId(LinTagId.fromId(NBTUtils.getTypeCode(type))), + value.stream().map(Tag::toLinTag).collect(Collectors.toList()) )); } - public ListTag(ListBinaryTag adventureTag) { - this.innerTag = adventureTag; - } - - @Override - public ListBinaryTag asBinaryTag() { - return this.innerTag; + public ListTag(LinListTag tag) { + super(tag); } /** @@ -68,15 +71,14 @@ public final class ListTag extends Tag { * * @return The type of item in this list. */ - public Class getType() { - return AdventureNBTConverter.getJNBTType(this.innerTag.elementType()); + @SuppressWarnings("unchecked") + public Class> getType() { + return (Class>) NBTUtils.getTypeClass(linTag.elementType().id().id()); } @Override - public List getValue() { - return this.innerTag.stream() - .map(AdventureNBTConverter::fromAdventure) - .collect(Collectors.toList()); + public List> getValue() { + return linTag.value().stream().map(LinBusConverter::toJnbtTag).toList(); } /** @@ -85,17 +87,31 @@ public final class ListTag extends Tag { * @param list the new list * @return a new list tag */ - public ListTag setValue(List list) { - return new ListTag(getType(), list); + public ListTag setValue(List> list) { + return new ListTag<>(getType(), list); } private T accessIfExists(int index, Supplier defaultValue, IntFunction accessor) { - if (index >= this.innerTag.size()) { + if (index >= this.linTag.value().size()) { return defaultValue.get(); } return accessor.apply(index); } + @SuppressWarnings("unchecked") + private > T extractViaValue( + int index, Class requiredType, Supplier defaultValue + ) { + if (index >= this.linTag.value().size()) { + return defaultValue.get(); + } + E value = this.linTag.get(index); + if (!requiredType.isInstance(value)) { + return defaultValue.get(); + } + return (T) value.value(); + } + /** * Get the tag if it exists at the given index. * @@ -103,11 +119,11 @@ public final class ListTag extends Tag { * @return the tag or null */ @Nullable - public Tag getIfExists(int index) { + public Tag getIfExists(int index) { return accessIfExists( - index, - () -> null, - i -> AdventureNBTConverter.fromAdventure(this.innerTag.get(i)) + index, + () -> null, + i -> LinBusConverter.toJnbtTag(this.linTag.get(i)) ); } @@ -121,11 +137,7 @@ public final class ListTag extends Tag { * @return a byte array */ public byte[] getByteArray(int index) { - return accessIfExists( - index, - () -> new byte[0], - this.innerTag::getByteArray - ); + return extractViaValue(index, LinByteArrayTag.class, () -> new byte[0]); } /** @@ -138,11 +150,7 @@ public final class ListTag extends Tag { * @return a byte */ public byte getByte(int index) { - return accessIfExists( - index, - () -> (byte) 0, - this.innerTag::getByte - ); + return extractViaValue(index, LinByteTag.class, () -> (byte) 0); } /** @@ -155,11 +163,7 @@ public final class ListTag extends Tag { * @return a double */ public double getDouble(int index) { - return accessIfExists( - index, - () -> 0.0, - this.innerTag::getDouble - ); + return extractViaValue(index, LinDoubleTag.class, () -> 0.0); } /** @@ -174,15 +178,11 @@ public final class ListTag extends Tag { */ public double asDouble(int index) { return accessIfExists( - index, - () -> 0.0, - i -> { - BinaryTag tag = this.innerTag.get(i); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).doubleValue(); - } - return 0.0; - } + index, + () -> 0.0, + i -> this.linTag.get(i) instanceof LinNumberTag tag + ? tag.value().doubleValue() + : 0.0 ); } @@ -196,11 +196,7 @@ public final class ListTag extends Tag { * @return a float */ public float getFloat(int index) { - return accessIfExists( - index, - () -> 0.0f, - this.innerTag::getFloat - ); + return extractViaValue(index, LinFloatTag.class, () -> 0f); } /** @@ -213,11 +209,7 @@ public final class ListTag extends Tag { * @return an int array */ public int[] getIntArray(int index) { - return accessIfExists( - index, - () -> new int[0], - this.innerTag::getIntArray - ); + return extractViaValue(index, LinIntArrayTag.class, () -> new int[0]); } /** @@ -230,11 +222,7 @@ public final class ListTag extends Tag { * @return an int */ public int getInt(int index) { - return accessIfExists( - index, - () -> 0, - this.innerTag::getInt - ); + return extractViaValue(index, LinIntTag.class, () -> 0); } /** @@ -249,15 +237,11 @@ public final class ListTag extends Tag { */ public int asInt(int index) { return accessIfExists( - index, - () -> 0, - i -> { - BinaryTag tag = this.innerTag.get(i); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).intValue(); - } - return 0; - } + index, + () -> 0, + i -> this.linTag.get(i) instanceof LinNumberTag tag + ? tag.value().intValue() + : 0 ); } @@ -270,7 +254,7 @@ public final class ListTag extends Tag { * @param index the index * @return a list of tags */ - public List getList(int index) { + public List> getList(int index) { return getListTag(index).getValue(); } @@ -283,11 +267,12 @@ public final class ListTag extends Tag { * @param index the index * @return a tag list instance */ - public ListTag getListTag(int index) { - return new ListTag(accessIfExists( - index, - ListBinaryTag::empty, - this.innerTag::getList + @SuppressWarnings("unchecked") + public ListTag getListTag(int index) { + return new ListTag<>(extractViaValue( + index, + LinListTag.class, + () -> LinListTag.empty(LinTagType.endTag()) )); } @@ -305,8 +290,8 @@ public final class ListTag extends Tag { * @return a list of tags */ @SuppressWarnings("unchecked") - public List getList(int index, Class listType) { - ListTag listTag = getListTag(index); + public > List getList(int index, Class listType) { + ListTag listTag = getListTag(index); if (listTag.getType().equals(listType)) { return (List) listTag.getValue(); } else { @@ -324,11 +309,7 @@ public final class ListTag extends Tag { * @return a long */ public long getLong(int index) { - return accessIfExists( - index, - () -> 0L, - this.innerTag::getLong - ); + return extractViaValue(index, LinLongTag.class, () -> 0L); } /** @@ -343,15 +324,11 @@ public final class ListTag extends Tag { */ public long asLong(int index) { return accessIfExists( - index, - () -> 0L, - i -> { - BinaryTag tag = this.innerTag.get(i); - if (tag instanceof NumberBinaryTag) { - return ((NumberBinaryTag) tag).longValue(); - } - return 0L; - } + index, + () -> 0L, + i -> this.linTag.get(i) instanceof LinNumberTag tag + ? tag.value().longValue() + : 0L ); } @@ -365,11 +342,7 @@ public final class ListTag extends Tag { * @return a short */ public short getShort(int index) { - return accessIfExists( - index, - () -> (short) 0, - this.innerTag::getShort - ); + return extractViaValue(index, LinShortTag.class, () -> (short) 0); } /** @@ -382,11 +355,7 @@ public final class ListTag extends Tag { * @return a string */ public String getString(int index) { - return accessIfExists( - index, - () -> "", - this.innerTag::getString - ); + return extractViaValue(index, LinStringTag.class, () -> ""); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java index 78a8b6401..18aab079c 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java @@ -19,11 +19,11 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagType; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; +import org.enginehub.linbus.common.LinTagId; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; -import java.util.Arrays; import java.util.Collection; import static com.google.common.base.Preconditions.checkNotNull; @@ -31,12 +31,12 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Helps create list tags. * - * @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag.Builder}. + * @deprecated Use {@link LinListTag.Builder}. */ @Deprecated -public class ListTagBuilder { +public class ListTagBuilder> { - private final ListBinaryTag.Builder builder; + private final LinListTag.Builder builder; /** * Create a new instance. @@ -44,11 +44,11 @@ public class ListTagBuilder { * @param type of tag contained in this list */ @SuppressWarnings("unchecked") - ListTagBuilder(Class type) { + ListTagBuilder(Class> type) { checkNotNull(type); - this.builder = type != EndTag.class - ? ListBinaryTag.builder((BinaryTagType) AdventureNBTConverter.getAdventureType(type)) - : ListBinaryTag.builder(); + this.builder = (LinListTag.Builder) LinListTag.builder(LinTagType.fromId(LinTagId.fromId( + NBTUtils.getTypeCode(type) + ))); } /** @@ -57,9 +57,9 @@ public class ListTagBuilder { * @param value the tag * @return this object */ - public ListTagBuilder add(Tag value) { + public ListTagBuilder add(Tag value) { checkNotNull(value); - builder.add(value.asBinaryTag()); + builder.add(value.toLinTag()); return this; } @@ -69,9 +69,9 @@ public class ListTagBuilder { * @param value a list of tags * @return this object */ - public ListTagBuilder addAll(Collection value) { + public ListTagBuilder addAll(Collection> value) { checkNotNull(value); - for (Tag v : value) { + for (Tag v : value) { add(v); } return this; @@ -82,8 +82,8 @@ public class ListTagBuilder { * * @return the new list tag */ - public ListTag build() { - return new ListTag(this.builder.build()); + public ListTag build() { + return new ListTag<>(this.builder.build()); } /** @@ -91,8 +91,8 @@ public class ListTagBuilder { * * @return a new builder */ - public static ListTagBuilder create(Class type) { - return new ListTagBuilder(type); + public static > ListTagBuilder create(Class> type) { + return new ListTagBuilder<>(type); } /** @@ -100,22 +100,24 @@ public class ListTagBuilder { * * @return a new builder */ - public static ListTagBuilder createWith(Tag... entries) { + @SafeVarargs + public static > ListTagBuilder createWith(Tag... entries) { checkNotNull(entries); if (entries.length == 0) { throw new IllegalArgumentException("This method needs an array of at least one entry"); } - Class type = entries[0].getClass(); - for (int i = 1; i < entries.length; i++) { - if (!type.isInstance(entries[i])) { + @SuppressWarnings("unchecked") + Class> type = (Class>) entries[0].getClass(); + ListTagBuilder builder = new ListTagBuilder<>(type); + for (Tag entry : entries) { + if (!type.isInstance(entry)) { throw new IllegalArgumentException("An array of different tag types was provided"); } + builder.add(entry); } - ListTagBuilder builder = new ListTagBuilder(type); - builder.addAll(Arrays.asList(entries)); return builder; } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java index 81c6e3376..968019b7e 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java @@ -19,44 +19,33 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag; +import org.enginehub.linbus.tree.LinLongArrayTag; import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_Long_Array} tag. * - * @deprecated Use {@link LongArrayBinaryTag}. + * @deprecated Use {@link LinLongArrayTag}. */ @Deprecated -public class LongArrayTag extends Tag { - - private final LongArrayBinaryTag innerTag; - +public class LongArrayTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public LongArrayTag(long[] value) { - super(); - checkNotNull(value); - this.innerTag = LongArrayBinaryTag.of(value); + this(LinLongArrayTag.of(checkNotNull(value))); } - public LongArrayTag(LongArrayBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public LongArrayBinaryTag asBinaryTag() { - return this.innerTag; + public LongArrayTag(LinLongArrayTag tag) { + super(tag); } @Override public long[] getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java index 84a443746..b8632b752 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java @@ -19,41 +19,32 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.LongBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinLongTag; /** * The {@code TAG_Long} tag. * - * @deprecated Use {@link LongBinaryTag}. + * @deprecated Use {@link LinLongTag}. */ @Deprecated -public final class LongTag extends Tag { - - private final LongBinaryTag innerTag; - +public final class LongTag extends NumberTag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public LongTag(long value) { - super(); - this.innerTag = LongBinaryTag.of(value); + this(LinLongTag.of(value)); } - public LongTag(LongBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public LongBinaryTag asBinaryTag() { - return this.innerTag; + public LongTag(LinLongTag tag) { + super(tag); } @Override public Long getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java index 54746fc49..3ab1923c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java @@ -50,7 +50,6 @@ public final class NBTConstants { * Default private constructor. */ private NBTConstants() { - } /** @@ -60,37 +59,27 @@ public final class NBTConstants { * @return tag class * @throws IllegalArgumentException thrown if the tag ID is not valid */ - public static Class getClassFromType(int id) { - switch (id) { - case TYPE_END: - return EndTag.class; - case TYPE_BYTE: - return ByteTag.class; - case TYPE_SHORT: - return ShortTag.class; - case TYPE_INT: - return IntTag.class; - case TYPE_LONG: - return LongTag.class; - case TYPE_FLOAT: - return FloatTag.class; - case TYPE_DOUBLE: - return DoubleTag.class; - case TYPE_BYTE_ARRAY: - return ByteArrayTag.class; - case TYPE_STRING: - return StringTag.class; - case TYPE_LIST: - return ListTag.class; - case TYPE_COMPOUND: - return CompoundTag.class; - case TYPE_INT_ARRAY: - return IntArrayTag.class; - case TYPE_LONG_ARRAY: - return LongArrayTag.class; - default: - throw new IllegalArgumentException("Unknown tag type ID of " + id); - } + public static Class> getClassFromType(int id) { + return switch (id) { + case TYPE_END -> EndTag.class; + case TYPE_BYTE -> ByteTag.class; + case TYPE_SHORT -> ShortTag.class; + case TYPE_INT -> IntTag.class; + case TYPE_LONG -> LongTag.class; + case TYPE_FLOAT -> FloatTag.class; + case TYPE_DOUBLE -> DoubleTag.class; + case TYPE_BYTE_ARRAY -> ByteArrayTag.class; + case TYPE_STRING -> StringTag.class; + case TYPE_LIST -> { + @SuppressWarnings("unchecked") + var aClass = (Class>) (Class) ListTag.class; + yield aClass; + } + case TYPE_COMPOUND -> CompoundTag.class; + case TYPE_INT_ARRAY -> IntArrayTag.class; + case TYPE_LONG_ARRAY -> LongArrayTag.class; + default -> throw new IllegalArgumentException("Unknown tag type ID of " + id); + }; } } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java index fca025212..080ab3bea 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java @@ -21,6 +21,7 @@ package com.sk89q.jnbt; import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate; import com.fastasyncworldedit.core.jnbt.streamer.ValueReader; +import org.enginehub.linbus.stream.LinBinaryIO; import java.io.Closeable; import java.io.DataInputStream; @@ -44,8 +45,9 @@ import java.util.Map; * https://minecraft.gamepedia.com/NBT_format. *

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

* - * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. + * @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinBinaryIO} instead */ +@SuppressWarnings("removal") @Deprecated(forRemoval = true) public final class NBTOutputStream extends OutputStream implements Closeable, DataOutput { @@ -61,7 +63,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @param os The output stream. * @throws IOException if an I/O error occurs. */ - public NBTOutputStream(OutputStream os) throws IOException { + public NBTOutputStream(OutputStream os) { this(os instanceof DataOutput ? (DataOutput) os : new DataOutputStream(os)); } @@ -91,11 +93,11 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @param tag The tag to write. * @throws IOException if an I/O error occurs. */ - public void writeNamedTag(String name, Tag tag) throws IOException { + public void writeNamedTag(String name, Tag tag) throws IOException { checkNotNull(name); checkNotNull(tag); - int type = NBTUtils.getTypeCode(tag.getClass()); + int type = tag.getTypeCode(); writeNamedTagName(name, type); if (type == NBTConstants.TYPE_END) { @@ -196,7 +198,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da } public void writeTag(Tag tag) throws IOException { - int type = NBTUtils.getTypeCode(tag.getClass()); + int type = tag.getTypeCode(); os.writeByte(type); writeTagPayload(tag); } @@ -212,7 +214,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @throws IOException if an I/O error occurs. */ public void writeTagPayload(Tag tag) throws IOException { - int type = NBTUtils.getTypeCode(tag.getClass()); + int type = tag.getTypeCode(); switch (type) { case NBTConstants.TYPE_END: writeEndTagPayload((EndTag) tag); @@ -287,7 +289,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @throws IOException if an I/O error occurs. */ private void writeCompoundTagPayload(CompoundTag tag) throws IOException { - for (Map.Entry entry : tag.getValue().entrySet()) { + for (Map.Entry> entry : tag.getValue().entrySet()) { writeNamedTag(entry.getKey(), entry.getValue()); } os.writeByte((byte) 0); // end tag - better way? @@ -300,7 +302,7 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da * @throws IOException if an I/O error occurs. */ private void writeListTagPayload(ListTag tag) throws IOException { - Class clazz = tag.getType(); + Class> clazz = tag.getType(); if (clazz == null) { clazz = CompoundTag.class; } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java index c899ba07b..b742cb6f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java @@ -20,7 +20,6 @@ package com.sk89q.jnbt; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; import java.util.Map; @@ -33,6 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. */ +@SuppressWarnings("ALL") @Deprecated public final class NBTUtils { @@ -48,7 +48,7 @@ public final class NBTUtils { * @param clazz the tag class * @return The type name. */ - public static String getTypeName(Class clazz) { + public static String getTypeName(Class> clazz) { if (clazz.equals(ByteArrayTag.class)) { return "TAG_Byte_Array"; } else if (clazz.equals(ByteTag.class)) { @@ -77,7 +77,7 @@ public final class NBTUtils { return "TAG_Long_Array"; } else { throw new IllegalArgumentException("Invalid tag class (" - + clazz.getName() + ")."); + + clazz.getName() + ")."); } } @@ -88,11 +88,35 @@ public final class NBTUtils { * @return The type code. * @throws IllegalArgumentException if the tag class is invalid. */ - public static int getTypeCode(Class clazz) { - if (LazyCompoundTag.class.isAssignableFrom(clazz)) { - return BinaryTagTypes.COMPOUND.id(); + public static int getTypeCode(Class> clazz) { + if (clazz == ByteArrayTag.class) { + return NBTConstants.TYPE_BYTE_ARRAY; + } else if (clazz == ByteTag.class) { + return NBTConstants.TYPE_BYTE; + } else if (clazz == CompoundTag.class) { + return NBTConstants.TYPE_COMPOUND; + } else if (clazz == DoubleTag.class) { + return NBTConstants.TYPE_DOUBLE; + } else if (clazz == EndTag.class) { + return NBTConstants.TYPE_END; + } else if (clazz == FloatTag.class) { + return NBTConstants.TYPE_FLOAT; + } else if (clazz == IntArrayTag.class) { + return NBTConstants.TYPE_INT_ARRAY; + } else if (clazz == IntTag.class) { + return NBTConstants.TYPE_INT; + } else if (clazz.equals(ListTag.class) /* I hate this, it wouldn't do == b/c generics */) { + return NBTConstants.TYPE_LIST; + } else if (clazz == LongArrayTag.class) { + return NBTConstants.TYPE_LONG_ARRAY; + } else if (clazz == LongTag.class) { + return NBTConstants.TYPE_LONG; + } else if (clazz == ShortTag.class) { + return NBTConstants.TYPE_SHORT; + } else if (clazz == StringTag.class) { + return NBTConstants.TYPE_STRING; } - return AdventureNBTConverter.getAdventureType(clazz).id(); + throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")"); } /** @@ -102,38 +126,8 @@ public final class NBTUtils { * @return The class. * @throws IllegalArgumentException if the tag type is invalid. */ - public static Class getTypeClass(int type) { - switch (type) { - case NBTConstants.TYPE_END: - return EndTag.class; - case NBTConstants.TYPE_BYTE: - return ByteTag.class; - case NBTConstants.TYPE_SHORT: - return ShortTag.class; - case NBTConstants.TYPE_INT: - return IntTag.class; - case NBTConstants.TYPE_LONG: - return LongTag.class; - case NBTConstants.TYPE_FLOAT: - return FloatTag.class; - case NBTConstants.TYPE_DOUBLE: - return DoubleTag.class; - case NBTConstants.TYPE_BYTE_ARRAY: - return ByteArrayTag.class; - case NBTConstants.TYPE_STRING: - return StringTag.class; - case NBTConstants.TYPE_LIST: - return ListTag.class; - case NBTConstants.TYPE_COMPOUND: - return CompoundTag.class; - case NBTConstants.TYPE_INT_ARRAY: - return IntArrayTag.class; - case NBTConstants.TYPE_LONG_ARRAY: - return LongArrayTag.class; - default: - throw new IllegalArgumentException("Invalid tag type : " + type - + "."); - } + public static Class> getTypeClass(int type) { + return NBTConstants.getClassFromType(type); } /** @@ -145,7 +139,7 @@ public final class NBTUtils { * @param listTag the list tag * @return a vector */ - public static Vector3 toVector(ListTag listTag) { + public static Vector3 toVector(ListTag listTag) { checkNotNull(listTag); return Vector3.at(listTag.asDouble(0), listTag.asDouble(1), listTag.asDouble(2)); } @@ -159,12 +153,12 @@ public final class NBTUtils { * @return child tag * @throws InvalidFormatException if the format of the items is invalid */ - public static T getChildTag(Map items, String key, Class expected) throws + public static > T getChildTag(Map> items, String key, Class expected) throws InvalidFormatException { if (!items.containsKey(key)) { throw new InvalidFormatException("Missing a \"" + key + "\" tag"); } - Tag tag = items.get(key); + Tag tag = items.get(key); if (!expected.isInstance(tag)) { throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName()); } @@ -179,7 +173,7 @@ public final class NBTUtils { * @param uuid {@link UUID} to add * @since 2.4.0 */ - public static void addUUIDToMap(Map map, UUID uuid) { + public static void addUUIDToMap(Map> map, UUID uuid) { int[] uuidArray = new int[4]; uuidArray[0] = (int) (uuid.getMostSignificantBits() >> 32); uuidArray[1] = (int) uuid.getMostSignificantBits(); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java index c7e2f9f28..e83f135de 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java @@ -30,7 +30,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public class NamedTag { private final String name; - private final Tag tag; + private final Tag tag; /** * Create a new named tag. @@ -38,7 +38,7 @@ public class NamedTag { * @param name the name * @param tag the tag */ - public NamedTag(String name, Tag tag) { + public NamedTag(String name, Tag tag) { checkNotNull(name); checkNotNull(tag); this.name = name; @@ -59,7 +59,7 @@ public class NamedTag { * * @return the tag */ - public Tag getTag() { + public Tag getTag() { return tag; } diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java index abbd06b3f..d0b9590fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java @@ -19,41 +19,32 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.ShortBinaryTag; +import com.fastasyncworldedit.core.jnbt.NumberTag; +import org.enginehub.linbus.tree.LinShortTag; /** * The {@code TAG_Short} tag. * - * @deprecated Use {@link ShortBinaryTag}. + * @deprecated Use {@link LinShortTag}. */ @Deprecated -public final class ShortTag extends Tag { - - private final ShortBinaryTag innerTag; - +public final class ShortTag extends NumberTag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public ShortTag(short value) { - super(); - this.innerTag = ShortBinaryTag.of(value); + super(LinShortTag.of(value)); } - public ShortTag(ShortBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public ShortBinaryTag asBinaryTag() { - return this.innerTag; + public ShortTag(LinShortTag tag) { + super(tag); } @Override public Short getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java index 483263752..2bc78f141 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java @@ -19,44 +19,33 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; +import org.enginehub.linbus.tree.LinStringTag; import static com.google.common.base.Preconditions.checkNotNull; /** * The {@code TAG_String} tag. * - * @deprecated Use {@link StringBinaryTag}. + * @deprecated Use {@link LinStringTag}. */ @Deprecated -public final class StringTag extends Tag { - - private final StringBinaryTag innerTag; - +public final class StringTag extends Tag { /** * Creates the tag with an empty name. * * @param value the value of the tag */ public StringTag(String value) { - super(); - checkNotNull(value); - this.innerTag = StringBinaryTag.of(value); + super(LinStringTag.of(checkNotNull(value))); } - public StringTag(StringBinaryTag adventureTag) { - super(); - this.innerTag = adventureTag; - } - - @Override - public StringBinaryTag asBinaryTag() { - return this.innerTag; + public StringTag(LinStringTag tag) { + super(tag); } @Override public String getValue() { - return innerTag.value(); + return linTag.value(); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java index 6327f4133..80df4c1cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java @@ -19,26 +19,43 @@ package com.sk89q.jnbt; -import com.sk89q.worldedit.util.nbt.BinaryTagLike; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.ToLinTag; + +import javax.annotation.Nonnull; /** * Represents a NBT tag. * - * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8. + * @deprecated JNBT is being removed for lin-bus in WorldEdit 8, use {@link LinTag} instead */ -@Deprecated(forRemoval = true) -public abstract class Tag implements BinaryTagLike { +@Deprecated +public abstract class Tag> implements ToLinTag { + + protected final LT linTag; + + protected Tag(LT linTag) { + this.linTag = linTag; + } /** * Gets the value of this tag. * * @return the value */ - public abstract Object getValue(); + public V getValue() { + return linTag.value(); + } @Override public String toString() { - return asBinaryTag().toString(); + return toLinTag().toString(); + } + + @Override + @Nonnull + public LT toLinTag() { + return linTag; } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 1469ffb96..926265bfb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -3881,7 +3881,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable { @Override public void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { - spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1); + spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 7642f3d60..d82bcd463 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -76,7 +76,6 @@ import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -84,6 +83,8 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.snapshot.experimental.Snapshot; import com.zaxxer.sparsebits.SparseBitSet; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -499,7 +500,7 @@ public class LocalSession implements TextureHolder { if (Settings.settings().HISTORY.USE_DISK) { LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE; } - if (changeSet.size() == 0) { + if (changeSet.longSize() == 0) { return; } loadSessionHistoryFromDisk(player.getUniqueId(), world); @@ -1351,7 +1352,7 @@ public class LocalSession implements TextureHolder { * @param item the item type * @param tool the tool to set, which can be {@code null} * @throws InvalidToolBindException if the item can't be bound to that item - * @since TODO + * @since 2.11.0 */ public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { if (item.getType().hasBlockType()) { @@ -1513,13 +1514,13 @@ public class LocalSession implements TextureHolder { BaseBlock block = ServerCUIHandler.createStructureBlock(player); if (block != null) { - CompoundBinaryTag tags = Objects.requireNonNull( - block.getNbt(), "createStructureBlock should return nbt" + LinCompoundTag tags = Objects.requireNonNull( + block.getNbt(), "createStructureBlock should return nbt" ); BlockVector3 tempCuiTemporaryBlock = BlockVector3.at( - tags.getInt("x"), - tags.getInt("y"), - tags.getInt("z") + tags.getTag("x", LinTagType.intTag()).valueAsInt(), + tags.getTag("y", LinTagType.intTag()).valueAsInt(), + tags.getTag("z", LinTagType.intTag()).valueAsInt() ); // If it's null, we don't need to do anything. The old was already removed. if (cuiTemporaryBlock != null && !tempCuiTemporaryBlock.equals(cuiTemporaryBlock)) { @@ -1918,7 +1919,7 @@ public class LocalSession implements TextureHolder { * Get the preferred wand item for this user, or {@code null} to use the default * * @return item id of wand item, or {@code null} - * @since TODO + * @since 2.11.0 */ public BaseItem getWandBaseItem() { return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); @@ -1928,7 +1929,7 @@ public class LocalSession implements TextureHolder { * Get the preferred navigation wand item for this user, or {@code null} to use the default * * @return item id of nav wand item, or {@code null} - * @since TODO + * @since 2.11.0 */ public BaseItem getNavWandBaseItem() { return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index dc3d494b9..76daf900e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException; import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.extension.factory.TransformFactory; import com.fastasyncworldedit.core.extent.ResettableExtent; @@ -46,6 +47,7 @@ import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; @@ -463,7 +465,7 @@ public final class WorldEdit { /** * @deprecated Use {@link WorldEdit#checkMaxBrushRadius(Expression, Actor)} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException { double val = radius.evaluate(); checkArgument(val >= 0, "Radius must be a positive number."); @@ -480,7 +482,7 @@ public final class WorldEdit { * @param radius Radius to check * @param actor Actor to check for * @throws MaxRadiusException If given radius larger than allowed - * @since TODO + * @since 2.11.0 */ public void checkMaxRadius(double radius, Actor actor) { int max = actor.getLimit().MAX_RADIUS; @@ -495,7 +497,7 @@ public final class WorldEdit { * @param radius Radius to check * @param actor Actor to check for * @throws MaxRadiusException If given radius larger than allowed - * @since TODO + * @since 2.11.0 */ public void checkMaxBrushRadius(double radius, Actor actor) { int max = actor.getLimit().MAX_BRUSH_RADIUS; @@ -510,7 +512,7 @@ public final class WorldEdit { * @param expression Radius to check * @param actor Actor to check for * @throws BrushRadiusLimitException If given radius larger than allowed - * @since TODO + * @since 2.11.0 */ public void checkMaxBrushRadius(Expression expression, Actor actor) { double radius = expression.evaluate(); @@ -520,6 +522,20 @@ public final class WorldEdit { throw new BrushRadiusLimitException(max); } } + + /** + * Check if the given position is contained by the extent's min/max height + * + * @param position Position to check + * @param extent Extent to check in + * @throws OutsideWorldBoundsException If the position is outside the world height limits + * @since 2.11.0 + */ + 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/blocks/BaseItem.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java index fe2e1a635..552dc6f56 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItem.java @@ -20,15 +20,13 @@ package com.sk89q.worldedit.blocks; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.NbtValued; import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; -import java.io.IOException; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,9 +40,7 @@ public class BaseItem implements NbtValued { private ItemType itemType; @Nullable - //FAWE start - Use LR & CBT over CompoundTag - private LazyReference nbtData; - //FAWE end + private LazyReference nbtData; /** * Construct the object. @@ -56,6 +52,29 @@ public class BaseItem implements NbtValued { this.itemType = itemType; } + /** + * Construct the object. + * + * @param itemType Type of the item + * @param nbtData NBT Compound tag + */ + @Deprecated + public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) { + this(itemType, nbtData == null ? null : LazyReference.from(nbtData::toLinTag)); + } + + /** + * Construct the object. + * + * @param itemType Type of the item + * @param tag NBT Compound tag + */ + public BaseItem(ItemType itemType, @Nullable LazyReference tag) { + checkNotNull(itemType); + this.itemType = itemType; + this.nbtData = tag; + } + /** * Get the type of item. * @@ -77,29 +96,6 @@ public class BaseItem implements NbtValued { //FAWE start - /** - * Construct the object. - * - * @param itemType Type of the item - * @param nbtData NBT Compound tag - */ - @Deprecated - public BaseItem(ItemType itemType, @Nullable CompoundTag nbtData) { - this(itemType, nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag)); - } - - /** - * Construct the object. - * - * @param itemType Type of the item - * @param tag NBT Compound tag - */ - public BaseItem(ItemType itemType, @Nullable LazyReference tag) { - checkNotNull(itemType); - this.itemType = itemType; - this.nbtData = tag; - } - @Deprecated @Nullable public Object getNativeItem() { @@ -108,25 +104,20 @@ public class BaseItem implements NbtValued { @Nullable @Override - public LazyReference getNbtReference() { + public LazyReference getNbtReference() { return this.nbtData; } @Override - public void setNbtReference(@Nullable LazyReference nbtData) { + public void setNbtReference(@Nullable LazyReference nbtData) { this.nbtData = nbtData; } @Override public String toString() { String nbtString = ""; - LazyReference nbtData = this.nbtData; if (nbtData != null) { - try { - nbtString = TagStringIO.get().asString(nbtData.getValue()); - } catch (IOException e) { - WorldEdit.logger.error("Failed to serialize NBT of Item", e); - } + nbtString = LinStringIO.writeToString(nbtData.getValue()); } return getType().id() + nbtString; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java index 07a9aa147..b83efe24a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/BaseItemStack.java @@ -24,8 +24,8 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.linbus.tree.LinCompoundTag; /** * Represents a stack of BaseItems. @@ -70,6 +70,18 @@ public class BaseItemStack extends BaseItem { this.amount = amount; } + /** + * Construct the object. + * + * @param id The item type + * @param tag Tag value + * @param amount amount in the stack + */ + public BaseItemStack(ItemType id, LazyReference tag, int amount) { + super(id, tag); + this.amount = amount; + } + /** * Get the number of items in the stack. * @@ -93,18 +105,4 @@ public class BaseItemStack extends BaseItem { .getRegistries().getItemRegistry().getRichName(this); } - //FAWE start - - /** - * Construct the object. - * - * @param id The item type - * @param tag Tag value - * @param amount amount in the stack - */ - public BaseItemStack(ItemType id, LazyReference tag, int amount) { - super(id, tag); - this.amount = amount; - } - //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 7160be750..664e656c4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -645,10 +645,10 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.populateschematic") public void scatterSchemBrush( Player player, InjectedValueAccess context, - @Arg(desc = "Mask") - Mask mask, @Arg(name = "clipboard", desc = "Clipboard uri") String clipboardStr, + @Arg(desc = "Mask of block to place on. Defaults to solid blocks.", def = "") + Mask mask, @Arg(desc = "Expression", def = "30") Expression radius, @Arg(desc = "double", def = "50") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 3b271a1ec..865e6f937 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -510,6 +510,7 @@ public class GeneralCommands { parserContext.setWorld(worldArg); parserContext.setSession(session); parserContext.setExtent(editSession); + parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY); Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext); util = TextureUtil.fromMask(mask); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java index 8d28ad1eb..38fc18415 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistorySubCommands.java @@ -251,7 +251,7 @@ public class HistorySubCommands { long seconds = (System.currentTimeMillis() - edit.getBDFile().lastModified()) / 1000; String timeStr = MainUtil.secToTime(seconds); - int size = edit.size(); + long size = edit.longSize(); boolean biomes = edit.getBioFile().exists(); boolean createdEnts = edit.getEnttFile().exists(); boolean removedEnts = edit.getEntfFile().exists(); @@ -335,7 +335,7 @@ public class HistorySubCommands { long seconds = (System.currentTimeMillis() - rollback.getBDFile().lastModified()) / 1000; String timeStr = MainUtil.secToTime(seconds); - int size = edit.size(); + long size = edit.longSize(); TranslatableComponent elem = Caption.of( "fawe.worldedit.history.find.element", diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SchematicCommands.java index ba5fd52d2..a9e2b7490 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 @@ -345,7 +345,7 @@ public class SchematicCommands { : 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]); @@ -365,11 +365,13 @@ public class SchematicCommands { 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); } @@ -387,8 +389,10 @@ public class SchematicCommands { } if (format == null) { format = ClipboardFormats.findByFile(file); - if (format == null) { - actor.print(Caption.of("worldedit.schematic.unknown-format", TextComponent.of(formatName))); + if (format == null) {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; } } @@ -408,6 +412,9 @@ public class SchematicCommands { } catch (IOException e) { actor.print(Caption.of("worldedit.schematic.file-not-exist", TextComponent.of(Objects.toString(e.getMessage())))); LOGGER.warn("Failed to load a saved clipboard", e); + } catch (Exception e) { + actor.print(Caption.of("fawe.worldedit.schematic.schematic.load-failure", TextComponent.of(e.getMessage()))); + LOGGER.error("Error loading a schematic", e); } finally { if (in != null) { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index a289f7cff..c81db21d8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -242,6 +242,7 @@ public class UtilityCommands { we.checkMaxRadius(depth, actor); BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); int affected = editSession.fillDirection(pos, pattern, radius, depth, direction); actor.print(Caption.of("worldedit.fill.created", TextComponent.of(affected))); return affected; @@ -330,6 +331,7 @@ public class UtilityCommands { we.checkMaxRadius(radius, actor); BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); int affected = editSession.fillXZ(pos, pattern, radius, depth, true); actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected))); return affected; @@ -357,7 +359,9 @@ public class UtilityCommands { double radius = radiusExp.evaluate(); radius = Math.max(0, radius); we.checkMaxRadius(radius, actor); - int affected = editSession.drainArea(session.getPlacementPosition(actor), radius, waterlogged, plants); + BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); + int affected = editSession.drainArea(pos, radius, waterlogged, plants); actor.print(Caption.of("worldedit.drain.drained", TextComponent.of(affected))); return affected; } @@ -376,7 +380,9 @@ public class UtilityCommands { ) throws WorldEditException { radius = Math.max(0, radius); we.checkMaxRadius(radius, actor); - int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); + BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); + int affected = editSession.fixLiquid(pos, radius, BlockTypes.LAVA); actor.print(Caption.of("worldedit.fixlava.fixed", TextComponent.of(affected))); return affected; } @@ -395,7 +401,9 @@ public class UtilityCommands { ) throws WorldEditException { radius = Math.max(0, radius); we.checkMaxRadius(radius, actor); - int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); + BlockVector3 pos = session.getPlacementPosition(actor); + we.checkExtentHeightBounds(pos, editSession); + int affected = editSession.fixLiquid(pos, radius, BlockTypes.WATER); actor.print(Caption.of("worldedit.fixwater.fixed", TextComponent.of(affected))); return affected; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index d82d25394..d3189f1f1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -133,6 +133,7 @@ public class FactoryConverter implements ArgumentConverter { parserContext.setSession(session); parserContext.setRestricted(true); parserContext.setInjected(context); + parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY); if (contextTweaker != null) { contextTweaker.accept(parserContext); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java index 235cdf761..b369ddd87 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/BaseEntity.java @@ -21,10 +21,10 @@ package com.sk89q.worldedit.entity; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.NbtValued; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -47,7 +47,7 @@ public class BaseEntity implements NbtValued { private final EntityType type; @Nullable - private LazyReference nbtData; + private LazyReference nbtData; /** * Create a new base entity. @@ -69,7 +69,7 @@ public class BaseEntity implements NbtValued { * @param type the entity type * @param nbtData NBT data */ - public BaseEntity(EntityType type, LazyReference nbtData) { + public BaseEntity(EntityType type, LazyReference nbtData) { this(type); setNbtReference(nbtData); } @@ -97,12 +97,12 @@ public class BaseEntity implements NbtValued { @Nullable @Override - public LazyReference getNbtReference() { + public LazyReference getNbtReference() { return nbtData; } @Override - public void setNbtReference(@Nullable LazyReference nbtData) { + public void setNbtReference(@Nullable LazyReference nbtData) { this.nbtData = nbtData; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index 277d755b1..cc203190b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -22,19 +22,15 @@ package com.sk89q.worldedit.entity; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard; import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismatchException; import com.fastasyncworldedit.core.regions.FaweMaskManager; import com.fastasyncworldedit.core.util.MainUtil; -import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.util.DeprecationUtil; @@ -43,7 +39,6 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; -import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; @@ -432,7 +427,8 @@ public interface Player extends Entity, Actor { } else if (Settings.settings().CLIPBOARD.DELETE_ON_LOGOUT) { session.setClipboard(null); } - if (Settings.settings().HISTORY.DELETE_ON_LOGOUT) { + if (!Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_ON_LOGOUT + || Settings.settings().HISTORY.USE_DISK && Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT) { session.clearHistory(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index 3440b009c..dce3e1c4f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -53,6 +53,7 @@ import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser; import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser; +import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; @@ -132,6 +133,11 @@ public final class MaskFactory extends AbstractFactory { //FAWE start - rich mask parsing + @Override + public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + return super.parseFromInput(input, context); + } + @Override protected Mask getParsed(final String input, final List masks) { return switch (masks.size()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index 25955adee..242d1d7bc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -60,7 +60,9 @@ import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; +import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.AbstractFactory; @@ -130,6 +132,13 @@ public final class PatternFactory extends AbstractFactory { register(new VoronoiPatternParser(worldEdit)); } + //FAWE start - rich pattern parsing + + @Override + public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { + return super.parseFromInput(input, context); + } + @Override protected Pattern getParsed(final String input, final List patterns) { switch (patterns.size()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index b889d4dca..2eb4fbfe3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.extension.factory.parser; import com.fastasyncworldedit.core.configuration.Caption; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -35,13 +34,13 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.stream.exception.NbtParseException; +import org.enginehub.linbus.tree.LinCompoundTag; -import java.io.IOException; import java.util.Locale; import java.util.stream.Stream; @@ -59,7 +58,7 @@ public class DefaultItemParser extends InputParser { @Override public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException { ItemType itemType; - CompoundBinaryTag itemNbtData = null; + LinCompoundTag itemNbtData = null; BaseItem item = null; @@ -128,20 +127,21 @@ public class DefaultItemParser extends InputParser { } if (nbtString != null) { + LinCompoundTag otherTag; try { - CompoundBinaryTag otherTag = TagStringIO.get().asCompound(nbtString); - if (itemNbtData == null) { - itemNbtData = otherTag; - } else { - itemNbtData.put(NbtUtils.getCompoundBinaryTagValues(otherTag)); - } - } catch (IOException e) { + otherTag = LinStringIO.readFromStringUsing(nbtString, LinCompoundTag::readFrom); + } catch (NbtParseException e) { throw new NoMatchException(TranslatableComponent.of( "worldedit.error.invalid-nbt", TextComponent.of(input), TextComponent.of(e.getMessage()) )); } + if (itemNbtData == null) { + itemNbtData = otherTag; + } else { + itemNbtData = itemNbtData.toBuilder().putAll(otherTag.value()).build(); + } } item = new BaseItem(itemType, itemNbtData == null ? null : LazyReference.computed(itemNbtData)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java index de6eea718..ac94b12d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -49,6 +49,7 @@ public class BlocksMaskParser extends InputParser { ParserContext tempContext = new ParserContext(context); tempContext.setRestricted(false); tempContext.setPreferringWildcard(true); + tempContext.setTryLegacy(context.isTryingLegacy()); try { Set holders = worldEdit.getBlockFactory().parseFromListInput(component, tempContext); if (holders.isEmpty()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 6117c6850..1b4420d27 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -216,7 +216,7 @@ public interface Extent extends InputExtent, OutputExtent { */ /** - * Returns the highest solid 'terrain' block. + * Returns the highest solid 'terrain' (movement-blocking) block. * * @param x the X coordinate * @param z the Z coordinate @@ -225,6 +225,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return height of highest block found or 'minY' */ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + for (int y = maxY; y >= minY; --y) { BlockState block = getBlock(x, y, z); if (block.getBlockType().getMaterial().isMovementBlocker()) { @@ -235,7 +238,7 @@ public interface Extent extends InputExtent, OutputExtent { } /** - * Returns the highest solid 'terrain' block. + * Returns the highest block matching the given mask. * * @param x the X coordinate * @param z the Z coordinate @@ -245,6 +248,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return height of highest block found or 'minY' */ default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, Mask filter) { + if (filter == null) { + return getHighestTerrainBlock(x, z, minY, maxY); + } maxY = Math.min(maxY, getMaxY()); minY = Math.max(getMinY(), minY); @@ -259,9 +265,7 @@ public interface Extent extends InputExtent, OutputExtent { } /** - * Returns the nearest surface layer (up/down from start) - *

- * TODO: Someone understand this..? + * Returns the nearest surface layer (up/down from start), where a layer is 1/16th of a block to allow for snow, liquid, etc. * * @param x x to search from * @param z y to search from @@ -271,6 +275,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return nearest surface layer */ default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + int clearanceAbove = maxY - y; int clearanceBelow = y - minY; int clearance = Math.min(clearanceAbove, clearanceBelow); @@ -331,6 +338,9 @@ public interface Extent extends InputExtent, OutputExtent { * @return The y value of the nearest terrain block */ default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + y = Math.max(minY, Math.min(maxY, y)); int clearanceAbove = maxY - y; int clearanceBelow = y - minY; @@ -438,6 +448,9 @@ public interface Extent extends InputExtent, OutputExtent { int failedMax, boolean ignoreAir ) { + maxY = Math.min(maxY, getMaxY()); + minY = Math.max(getMinY(), minY); + y = Math.max(minY, Math.min(maxY, y)); int clearanceAbove = maxY - y; int clearanceBelow = y - minY; @@ -494,7 +507,7 @@ public interface Extent extends InputExtent, OutputExtent { default void addSchems(Region region, Mask mask, List clipboards, int rarity, boolean rotate) throws WorldEditException { - spawnResource(region, new SchemGen(mask, this, clipboards, rotate), rarity, 1); + spawnResource(region, new SchemGen(mask, this, clipboards, rotate, region), rarity, 1); } default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index b861dbd6b..cf4623739 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -186,7 +186,7 @@ public class BlockArrayClipboard implements Clipboard { } @Override - public > boolean setBlock(BlockVector3 position, B block) throws WorldEditException { + public > boolean setBlock(BlockVector3 position, B block) { if (region.contains(position)) { //FAWE - get points final int x = position.x(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java index 5aafa220e..a26e7c99a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/BuiltInClipboardFormat.java @@ -19,28 +19,39 @@ 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.Collections; import java.util.Locale; -import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -48,23 +59,14 @@ import java.util.zip.GZIPOutputStream; /** * A collection of supported clipboard formats. */ +@SuppressWarnings("removal") //FAWE: suppress JNBT deprecations public enum BuiltInClipboardFormat implements ClipboardFormat { //FAWE start - register fast clipboard io - FAST("fast", "fawe", "sponge", "schem") { - @Override - public String getPrimaryFileExtension() { - return "schem"; - } - + FAST_V3("fast", "fawe", "schem") { @Override public ClipboardReader getReader(InputStream inputStream) throws IOException { - if (inputStream instanceof FileInputStream) { - inputStream = new ResettableFileInputStream((FileInputStream) inputStream); - } - BufferedInputStream buffered = new BufferedInputStream(inputStream); - NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - return new FastSchematicReader(nbtStream); + return new FastSchematicReaderV3(inputStream); } @Override @@ -77,15 +79,106 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { gzip = new ParallelGZIPOutputStream(outputStream); } NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); - return new FastSchematicWriter(nbtStream); + return new FastSchematicWriterV3(nbtStream); + } + + @Override + public boolean isFormat(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 boolean isFormat(File file) { String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".schem") || name.endsWith(".sponge"); + if (name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce")) { + return false; + } + return super.isFormat(file); } + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("schem3", "sponge3", "fast3"); + } + }, + FAST_V2("fast.2", "fawe.2", "schem.2") { + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + if (inputStream instanceof FileInputStream) { + inputStream = new ResettableFileInputStream((FileInputStream) inputStream); + } + BufferedInputStream buffered = new BufferedInputStream(inputStream); + NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); + return new FastSchematicReaderV2(nbtStream); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + OutputStream gzip; + if (outputStream instanceof ParallelGZIPOutputStream || outputStream instanceof GZIPOutputStream) { + gzip = outputStream; + } else { + outputStream = new BufferedOutputStream(outputStream); + gzip = new ParallelGZIPOutputStream(outputStream); + } + NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); + return new FastSchematicWriterV2(nbtStream); + } + + @Override + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, FastSchematicWriterV2.CURRENT_VERSION); + } + + @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 Set getExplicitFileExtensions() { + return Set.of("schem2", "sponge2", "fast2"); + } }, //FAWE end @@ -115,7 +208,61 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public boolean isFormat(File file) { String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce"); + if (!name.endsWith(".schematic") && !name.endsWith(".mcedit") && !name.endsWith(".mce")) { + return false; + } + return super.isFormat(file); + } + + @Override + 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"); + } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("mcedit", "schem1", "sponge1", "fast1"); + } + }, + 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); + } + + @Override + public boolean isFormat(File file) { + return MCEDIT_SCHEMATIC.isFormat(file); + } + + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); } }, @@ -125,7 +272,8 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { * Avoid using with any large schematics/clipboards for reading/writing. */ @Deprecated - SPONGE_SCHEMATIC("slow", "safe") { + SPONGE_V2_SCHEMATIC("slow.2", "safe.2", "sponge.2") { // FAWE - edit aliases for fast + @Override public String getPrimaryFileExtension() { return "schem"; @@ -133,38 +281,58 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { @Override public ClipboardReader getReader(InputStream inputStream) throws IOException { - NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream)); - return new SpongeSchematicReader(nbtStream); + return new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream)))); } @Override public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { - NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream)); - return new SpongeSchematicWriter(nbtStream); + return new SpongeSchematicV2Writer(new DataOutputStream(new GZIPOutputStream(outputStream))); + } + + @Override + public boolean isFormat(InputStream inputStream) { + return detectOldSpongeSchematic(inputStream, 2); } @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(); + return FAST_V2.isFormat(file); + } - // Check - Map schematic = schematicTag.getValue(); - if (!schematic.containsKey("Version")) { - return false; - } - } catch (Exception e) { - return false; - } - - return true; + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); } }, + SPONGE_V3_SCHEMATIC("sponge.3", "slow", "safe") { // FAWE - edit aliases for fast + @Override + public String getPrimaryFileExtension() { + return "schem"; + } + + @Override + public ClipboardReader getReader(InputStream inputStream) throws IOException { + return new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(new GZIPInputStream(inputStream)))); + } + + @Override + public ClipboardWriter getWriter(OutputStream outputStream) throws IOException { + return new SpongeSchematicV3Writer(new DataOutputStream(new GZIPOutputStream(outputStream))); + } + + @Override + public boolean isFormat(File file) { + //FAWE start - delegate to stream-based isFormat approach of fast impl + 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") { @Override @@ -179,7 +347,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } BufferedInputStream buffered = new BufferedInputStream(inputStream); NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered))); - FastSchematicReader reader = new FastSchematicReader(nbtStream); + FastSchematicReaderV2 reader = new FastSchematicReaderV2(nbtStream); reader.setBrokenEntities(true); return reader; } @@ -194,7 +362,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { gzip = new ParallelGZIPOutputStream(outputStream); } NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip)); - FastSchematicWriter writer = new FastSchematicWriter(nbtStream); + FastSchematicWriterV2 writer = new FastSchematicWriterV2(nbtStream); writer.setBrokenEntities(true); return writer; } @@ -204,6 +372,10 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { return false; } + @Override + public Set getExplicitFileExtensions() { + return Collections.emptySet(); + } }, /** @@ -232,9 +404,42 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { } @Override - public boolean isFormat(File file) { - String name = file.getName().toLowerCase(Locale.ROOT); - return name.endsWith(".nbt"); + public boolean isFormat(InputStream inputStream) { + try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream))); + final NBTInputStream nbt = new NBTInputStream(stream)) { + if (stream.readByte() != NBTConstants.TYPE_COMPOUND) { + return false; + } + NamedTag namedTag = nbt.readNamedTag(); + if (!namedTag.getName().isEmpty()) { + return false; + } + + // We can't guarantee the specific order of nbt data, so scan and skip, if required + do { + byte type = stream.readByte(); + String name = stream.readUTF(); + if (type == NBTConstants.TYPE_END) { + return false; + } + if (type == NBTConstants.TYPE_LIST && name.equals("size")) { + return true; + } + nbt.readTagPayloadLazy(type, 0); + } while (true); + } catch (IOException ignored) { + } + return false; + } + + @Override + public boolean isFormat(final File file) { + return file.getName().toLowerCase(Locale.ROOT).endsWith(".nbt") && super.isFormat(file); + } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("nbt"); } }, @@ -262,9 +467,61 @@ public enum BuiltInClipboardFormat implements ClipboardFormat { public String getPrimaryFileExtension() { return "png"; } + + @Override + public Set getExplicitFileExtensions() { + return Set.of("png"); + } }; //FAWE end + private static boolean detectOldSpongeSchematic(InputStream inputStream, int version) { + //FAWE start - dont utilize linbus - WorldEdit approach is not really streamed + try (final DataInputStream stream = new DataInputStream(new FastBufferedInputStream(new GZIPInputStream(inputStream))); + final NBTInputStream nbt = new NBTInputStream(stream)) { + if (stream.readByte() != NBTConstants.TYPE_COMPOUND) { + return false; + } + stream.skipNBytes(2); // TAG name length ("Schematic" = 9) + stream.skipNBytes(9); // "Schematic" + + // We can't guarantee the specific order of nbt data, so scan and skip, if required + do { + byte type = stream.readByte(); + String name = stream.readUTF(); + if (type == NBTConstants.TYPE_END) { + return false; + } + if (type == NBTConstants.TYPE_INT && name.equals("Version")) { + return stream.readInt() == version; + } + nbt.readTagPayloadLazy(type, 0); + } while (true); + } catch (IOException ignored) { + } + return false; + } + + /** + * For backwards compatibility, this points to the Sponge Schematic Specification (Version 2) + * format. This should not be used going forwards. + * + * @deprecated Use {@link #SPONGE_V2_SCHEMATIC} or {@link #SPONGE_V3_SCHEMATIC} + */ + @Deprecated + public static final BuiltInClipboardFormat SPONGE_SCHEMATIC = SPONGE_V2_SCHEMATIC; + + //FAWE start + /** + * For backwards compatibility, this points to the fast implementation of the Sponge Schematic Specification (Version 2) + * format. This should not be used going forwards. + * + * @deprecated Use {@link #FAST_V2} or {@link #FAST_V3} + */ + @Deprecated + public static final BuiltInClipboardFormat FAST = FAST_V2; + //FAWE end + private final ImmutableSet aliases; BuiltInClipboardFormat(String... aliases) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java index cb5cd1b7a..1961dd8cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormat.java @@ -35,6 +35,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.net.URL; +import java.nio.file.Files; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -82,7 +83,29 @@ public interface ClipboardFormat { * @param file the file * @return true if the given file is of this format */ - boolean isFormat(File file); + default boolean isFormat(File file) { + try (InputStream stream = Files.newInputStream(file.toPath())) { + return isFormat(stream); + } catch (IOException e) { + return false; + } + } + + /** + * Return whether the given stream is of this format. + * + * @apiNote The caller is responsible for the following: + *

    + *
  • Closing the input stream
  • + *
+ * + * @param inputStream The stream + * @return true if the given stream is of this format + * @since 2.11.1 + */ + default boolean isFormat(InputStream inputStream) { + return false; + } /** * Get the file extension this format primarily uses. @@ -101,6 +124,13 @@ public interface ClipboardFormat { //FAWE start + /** + * Get the explicit file extensions (e.g. .schem2) this format is commonly known to use. + * + * @return The explicit file extensions this format might be known by + */ + Set getExplicitFileExtensions(); + /** * Sets the actor's clipboard. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java index b69a7a0cc..d1529c803 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardFormats.java @@ -66,6 +66,7 @@ public class ClipboardFormats { private static final Map aliasMap = new HashMap<>(); // FAWE start - keep order of ClipboardFormat entries -> prefer FAST over SPONGE_SCHEMATIC private static final Multimap fileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); + private static final Multimap explicitFileExtensionMap = Multimaps.newMultimap(new HashMap<>(), LinkedHashSet::new); // FAWE end private static final List registeredFormats = new ArrayList<>(); @@ -86,6 +87,10 @@ public class ClipboardFormats { String lowExt = ext.toLowerCase(Locale.ROOT); fileExtensionMap.put(lowExt, format); } + for (String ext : format.getExplicitFileExtensions()) { + String lowExt = ext.toLowerCase(Locale.ROOT); + explicitFileExtensionMap.put(lowExt, format); + } registeredFormats.add(format); } @@ -147,6 +152,18 @@ public class ClipboardFormats { return fileExtensionMap.keySet().toArray(new String[fileExtensionMap.keySet().size()]); } + //FAWE start + + /** + * A mapping from explicit extensions (e.g. .schem2) to formats. + * + * @return a multimap from a file extension to the potential matching formats. + */ + public static Multimap getExplicitFileExtensionMap() { + return Multimaps.unmodifiableMultimap(explicitFileExtensionMap); + } + //FAWE end + private ClipboardFormats() { } @@ -157,8 +174,10 @@ public class ClipboardFormats { * * @param extension the extension * @return the format, otherwise null if one cannot be detected + * @deprecated DO NOT USE. Sponge formats 2 and 3 both use .schem by default. */ @Nullable + @Deprecated(forRemoval = true, since = "2.11.1") public static ClipboardFormat findByExtension(String extension) { checkNotNull(extension); @@ -172,6 +191,25 @@ public class ClipboardFormats { } + /** + * Detect the format given an explicit extension, e.g. ".schem2" + * + * @param extension the extension + * @return the format, otherwise null if one cannot be detected + */ + @Nullable + public static ClipboardFormat findByExplicitExtension(String extension) { + checkNotNull(extension); + + Collection> entries = getExplicitFileExtensionMap().entries(); + for (Map.Entry entry : entries) { + if (entry.getKey().equalsIgnoreCase(extension)) { + return entry.getValue(); + } + } + return null; + } + public static MultiClipboardHolder loadAllFromInput( Actor player, String input, @@ -231,7 +269,7 @@ public class ClipboardFormats { } if (format == null && input.matches(".*\\.[\\w].*")) { String extension = input.substring(input.lastIndexOf('.') + 1); - format = findByExtension(extension); + format = findByExplicitExtension(extension); } f = MainUtil.resolve(dir, input, format, true); } @@ -302,7 +340,7 @@ public class ClipboardFormats { byte[] buffer = new byte[8192]; while ((entry = zip.getNextEntry()) != null) { String filename = entry.getName(); - ClipboardFormat format = findByExtension(filename); + ClipboardFormat format = findByExtension(filename); // FIXME if (format != null) { FastByteArrayOutputStream out = new FastByteArrayOutputStream(); int len; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java index aebef3e9a..945cd6981 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/MCEditSchematicReader.java @@ -20,17 +20,7 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.google.common.collect.ImmutableList; -import com.sk89q.jnbt.AdventureNBTConverter; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.NamedTag; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -49,7 +39,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.collection.BlockMap; -import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.entity.EntityType; @@ -57,27 +47,25 @@ import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.storage.NBTConversions; import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; +import java.io.UncheckedIOException; import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Optional; import java.util.Set; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Reads schematic files that are compatible with MCEdit and other editors. */ public class MCEditSchematicReader extends NBTSchematicReader { private static final Logger LOGGER = LogManagerCompat.getLogger(); - private final NBTInputStream inputStream; - private final DataFixer fixer; + private final LinRootEntry root; private static final ImmutableList COMPATIBILITY_HANDLERS = ImmutableList.of( new SignCompatibilityHandler(), @@ -98,30 +86,30 @@ public class MCEditSchematicReader extends NBTSchematicReader { * @param inputStream the input stream to read from */ public MCEditSchematicReader(NBTInputStream inputStream) { - checkNotNull(inputStream); - this.inputStream = inputStream; - this.fixer = null; - //com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability( - //com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer(); + try { + var tag = inputStream.readNamedTag(); + this.root = new LinRootEntry(tag.getName(), (LinCompoundTag) tag.getTag().toLinTag()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + MCEditSchematicReader(LinRootEntry root) { + this.root = root; } @Override public Clipboard read() throws IOException { // Schematic tag - NamedTag rootTag = inputStream.readNamedTag(); - if (!rootTag.getName().equals("Schematic")) { + if (!root.name().equals("Schematic")) { throw new IOException("Tag 'Schematic' does not exist or is not first"); } - CompoundTag schematicTag = (CompoundTag) rootTag.getTag(); + var schematicTag = root.value(); - // Check - Map schematic = schematicTag.getValue(); - if (!schematic.containsKey("Blocks")) { + if (!schematicTag.value().containsKey("Blocks")) { throw new IOException("Schematic file is missing a 'Blocks' tag"); } - - // Check type of Schematic - String materials = requireTag(schematic, "Materials", StringTag.class).getValue(); + String materials = schematicTag.getTag("Materials", LinTagType.stringTag()).value(); if (!materials.equals("Alpha")) { throw new IOException("Schematic file is not an Alpha schematic"); } @@ -134,42 +122,38 @@ public class MCEditSchematicReader extends NBTSchematicReader { Region region; // Get information - short width = requireTag(schematic, "Width", ShortTag.class).getValue(); - short height = requireTag(schematic, "Height", ShortTag.class).getValue(); - short length = requireTag(schematic, "Length", ShortTag.class).getValue(); + short width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort(); + short height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort(); + short length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort(); - try { - int originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue(); - int originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue(); - int originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue(); - BlockVector3 min = BlockVector3.at(originX, originY, originZ); + int originX = schematicTag.getTag("WEOriginX", LinTagType.intTag()).valueAsInt(); + int originY = schematicTag.getTag("WEOriginY", LinTagType.intTag()).valueAsInt(); + int originZ = schematicTag.getTag("WEOriginZ", LinTagType.intTag()).valueAsInt(); + BlockVector3 min = BlockVector3.at(originX, originY, originZ); - int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue(); - int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue(); - int offsetZ = requireTag(schematic, "WEOffsetZ", IntTag.class).getValue(); - BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); + int offsetX = schematicTag.getTag("WEOffsetX", LinTagType.intTag()).valueAsInt(); + int offsetY = schematicTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt(); + int offsetZ = schematicTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt(); + BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ); - origin = min.subtract(offset); - region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); - } catch (IOException ignored) { - origin = BlockVector3.ZERO; - region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); - } + origin = min.subtract(offset); + region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); // ==================================================================== // Blocks // ==================================================================== // Get blocks - byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue(); - byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue(); + byte[] blockId = schematicTag.getTag("Blocks", LinTagType.byteArrayTag()).value(); + byte[] blockData = schematicTag.getTag("Data", LinTagType.byteArrayTag()).value(); byte[] addId = new byte[0]; short[] blocks = new short[blockId.length]; // Have to later combine IDs // We support 4096 block IDs using the same method as vanilla Minecraft, where // the highest 4 bits are stored in a separate byte array. - if (schematic.containsKey("AddBlocks")) { - addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue(); + LinByteArrayTag addBlocks = schematicTag.findTag("AddBlocks", LinTagType.byteArrayTag()); + if (addBlocks != null) { + addId = addBlocks.value(); } // Combine the AddBlocks data with the first 8-bit block ID @@ -186,21 +170,17 @@ public class MCEditSchematicReader extends NBTSchematicReader { } // Need to pull out tile entities - final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class); - List tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue(); + var tileEntityTag = schematicTag.findListTag("TileEntities", LinTagType.compoundTag()); + List tileEntities = tileEntityTag == null ? List.of() : tileEntityTag.value(); BlockMap tileEntityBlocks = BlockMap.createForBaseBlock(); - for (Tag tag : tileEntities) { - if (!(tag instanceof CompoundTag)) { - continue; - } - CompoundTag t = (CompoundTag) tag; - Map values = new HashMap<>(t.getValue()); - String id = t.getString("id"); - values.put("id", new StringTag(convertBlockEntityId(id))); - int x = t.getInt("x"); - int y = t.getInt("y"); - int z = t.getInt("z"); + for (LinCompoundTag tag : tileEntities) { + var newTag = tag.toBuilder(); + String id = tag.getTag("id", LinTagType.stringTag()).value(); + newTag.putString("id", convertBlockEntityId(id)); + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); int index = y * width * length + z * width + x; //FAWE start - tile entity safety - perhaps caused by the old issue with tile entities created in the wrong @@ -211,44 +191,17 @@ public class MCEditSchematicReader extends NBTSchematicReader { } BlockState block = getBlockState(blocks[index], blockData[index]); - BlockState newBlock = block; - if (newBlock != null) { - for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { - if (handler.isAffectedBlock(newBlock)) { - newBlock = handler.updateNBT(block, values).toImmutableState(); - if (newBlock == null || values.isEmpty()) { - break; - } - } + if (block == null) { + continue; + } + var updatedBlock = block.toBaseBlock(LazyReference.from(newTag::build)); + for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { + updatedBlock = handler.updateNbt(updatedBlock); + if (updatedBlock.getNbtReference() == null) { + break; } } - if (values.isEmpty()) { - t = null; - } else { - t = new CompoundTag(values); - } - - if (fixer != null && t != null) { - //FAWE start - BinaryTag - t = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( - DataFixer.FixTypes.BLOCK_ENTITY, - t.asBinaryTag(), - -1 - )); - //FAWE end - } - - BlockVector3 vec = BlockVector3.at(x, y, z); - // Insert into the map if we have changed the block or have a tag - BlockState blockToInsert = newBlock != null - ? newBlock - : (t != null ? block : null); - if (blockToInsert != null) { - BaseBlock baseBlock = t != null - ? blockToInsert.toBaseBlock(new CompoundTag(t.getValue())) - : blockToInsert.toBaseBlock(); - tileEntityBlocks.put(vec, baseBlock); - } + tileEntityBlocks.put(BlockVector3.at(x, y, z), updatedBlock); } BlockArrayClipboard clipboard = new BlockArrayClipboard(region); @@ -261,16 +214,10 @@ public class MCEditSchematicReader extends NBTSchematicReader { for (int z = 0; z < length; ++z) { int index = y * width * length + z * width + x; BlockVector3 pt = BlockVector3.at(x, y, z); - BaseBlock state = Optional.ofNullable(tileEntityBlocks.get(pt)) - .orElseGet(() -> { - BlockState blockState = getBlockState(blocks[index], blockData[index]); - return blockState == null ? null : blockState.toBaseBlock(); - }); - - try { - if (state != null) { - clipboard.setBlock(region.getMinimumPoint().add(pt), state); - } else { + BaseBlock state = tileEntityBlocks.get(pt); + if (state == null) { + BlockState blockState = getBlockState(blocks[index], blockData[index]); + if (blockState == null) { short block = blocks[index]; byte data = blockData[index]; int combined = block << 8 | data; @@ -278,9 +225,12 @@ public class MCEditSchematicReader extends NBTSchematicReader { LOGGER.warn("Unknown block when loading schematic: {} {}. This is most likely a" + "bad schematic.", block, data); } + continue; } - } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this + state = blockState.toBaseBlock(); } + + clipboard.setBlock(region.getMinimumPoint().add(pt), state); } } } @@ -289,40 +239,25 @@ public class MCEditSchematicReader extends NBTSchematicReader { // Entities // ==================================================================== - ListTag entityList = getTag(schematic, "Entities", ListTag.class); + var entityList = schematicTag.findListTag("Entities", LinTagType.compoundTag()); if (entityList != null) { - List entityTags = entityList.getValue(); - for (Tag tag : entityTags) { - if (tag instanceof CompoundTag) { - CompoundTag compound = (CompoundTag) tag; - if (fixer != null) { - //FAWE start - BinaryTag - compound = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( - DataFixer.FixTypes.ENTITY, - compound.asBinaryTag(), - -1 - )); - //FAWE end - } - String id = convertEntityId(compound.getString("id")); - Location location = NBTConversions.toLocation( - clipboard, - compound.getListTag("Pos"), - compound.getListTag("Rotation") - ); - if (!id.isEmpty()) { - EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); - if (entityType != null) { - for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { - if (compatibilityHandler.isAffectedEntity(entityType, compound)) { - compound = compatibilityHandler.updateNBT(entityType, compound); - } - } - BaseEntity state = new BaseEntity(entityType, compound); - clipboard.createEntity(location, state); - } else { - LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT)); + for (LinCompoundTag tag : entityList.value()) { + String id = convertEntityId(tag.getTag("id", LinTagType.stringTag()).value()); + Location location = NBTConversions.toLocation( + clipboard, + tag.getListTag("Pos", LinTagType.doubleTag()), + tag.getListTag("Rotation", LinTagType.floatTag()) + ); + if (!id.isEmpty()) { + EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); + if (entityType != null) { + for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { + tag = compatibilityHandler.updateNbt(entityType, tag); } + BaseEntity state = new BaseEntity(entityType, LazyReference.computed(tag)); + clipboard.createEntity(location, state); + } else { + LOGGER.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT)); } } } @@ -494,7 +429,6 @@ public class MCEditSchematicReader extends NBTSchematicReader { @Override public void close() throws IOException { - inputStream.close(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java index 0328b1c76..017f07e9c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extent.clipboard.io; import com.sk89q.jnbt.Tag; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; import java.io.IOException; @@ -27,16 +28,19 @@ import java.util.Map; /** * Base class for NBT schematic readers. + * + * @deprecated These utility methods are provided by {@link LinCompoundTag} now. */ +@Deprecated public abstract class NBTSchematicReader implements ClipboardReader { - protected static T requireTag(Map items, String key, Class expected) throws IOException { + 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 +50,12 @@ public abstract class NBTSchematicReader implements ClipboardReader { } @Nullable - protected static T getTag(Map items, String key, Class expected) { + protected static > T getTag(Map> items, String key, Class expected) { if (!items.containsKey(key)) { return null; } - Tag test = items.get(key); + Tag test = items.get(key); if (!expected.isInstance(test)) { return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.java new file mode 100644 index 000000000..7da0aa164 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SchematicNbtUtil.java @@ -0,0 +1,61 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io; + +import com.sk89q.jnbt.Tag; + +import java.io.IOException; +import java.util.Map; +import javax.annotation.Nullable; + +// note, when clearing deprecations these methods don't need to remain -- they're introduced in 7.3.0 +public class SchematicNbtUtil { + public static T requireTag(Map items, String key, Class expected) throws IOException { + if (!items.containsKey(key)) { + throw new IOException("Schematic file is missing a \"" + key + "\" tag of type " + + expected.getName()); + } + + Tag tag = items.get(key); + if (!expected.isInstance(tag)) { + throw new IOException(key + " tag is not of tag type " + expected.getName() + ", got " + + tag.getClass().getName() + " instead"); + } + + return expected.cast(tag); + } + + @Nullable + public static T getTag(Map items, String key, Class expected) { + if (!items.containsKey(key)) { + return null; + } + + Tag test = items.get(key); + if (!expected.isInstance(test)) { + return null; + } + + return expected.cast(test); + } + + private SchematicNbtUtil() { + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java deleted file mode 100644 index a140b666a..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicReader.java +++ /dev/null @@ -1,458 +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.AdventureNBTConverter; -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 java.util.stream.Collectors; - -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) { - List> tileEntityTags = tileEntities.getValue().stream() - .map(tag -> (CompoundTag) tag) - .map(CompoundTag::getValue) - .collect(Collectors.toList()); - - for (Map tileEntity : tileEntityTags) { - int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); - final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); - Map values = Maps.newHashMap(tileEntity); - values.put("x", new IntTag(pt.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 - BinaryTag - tileEntity = ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( - DataFixer.FixTypes.BLOCK_ENTITY, - new CompoundTag(values).asBinaryTag(), - 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 - BinaryTag - entityTag = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp( - DataFixer.FixTypes.ENTITY, - entityTag.asBinaryTag(), - 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/legacycompat/BannerBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java index 826967400..d4b7347f2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BannerBlockCompatibilityHandler.java @@ -19,21 +19,16 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.CompoundTagBuilder; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler { @@ -55,17 +50,19 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler } @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.WHITE_BANNER - || block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - Tag typeTag = values.get("Base"); - if (typeTag instanceof IntTag) { + public BaseBlock updateNbt(BaseBlock block) { + var blockType = block.getBlockType(); + if (blockType != BlockTypes.WHITE_BANNER && blockType != BlockTypes.WHITE_WALL_BANNER) { + return block; + } + var nbt = block.getNbt(); + if (nbt == null) { + return block; + } + LinIntTag typeTag = nbt.findTag("Base", LinTagType.intTag()); + if (typeTag != null) { boolean isWall = block.getBlockType() == BlockTypes.WHITE_WALL_BANNER; - String bannerType = convertBannerType(((IntTag) typeTag).getValue(), isWall); + String bannerType = convertBannerType(typeTag.valueAsInt(), isWall); if (bannerType != null) { BlockType type = BlockTypes.get("minecraft:" + bannerType); if (type != null) { @@ -79,29 +76,25 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler state = state.with(rotationProp, block.getState(RotationProperty)); } - values.remove("Base"); + var nbtBuilder = nbt.toBuilder(); + nbtBuilder.remove("Base"); - Tag patternsTag = values.get("Patterns"); - if (patternsTag instanceof ListTag) { - List tempList = new ArrayList<>(); - for (Tag pattern : ((ListTag) patternsTag).getValue()) { - if (pattern instanceof CompoundTag) { - Map patternMap = ((CompoundTag) pattern).getValue(); - Tag colorTag = patternMap.get("Color"); - - CompoundTagBuilder builder = CompoundTagBuilder.create(); - builder.putAll(patternMap); - if (colorTag instanceof IntTag) { - builder.putInt("Color", 15 - ((IntTag) colorTag).getValue()); - } - tempList.add(builder.build()); + var patternsTag = nbt.findListTag("Patterns", LinTagType.compoundTag()); + if (patternsTag != null) { + var newPatterns = LinListTag.builder(LinTagType.compoundTag()); + for (LinCompoundTag pattern : patternsTag.value()) { + LinIntTag color = pattern.findTag("Color", LinTagType.intTag()); + if (color != null) { + newPatterns.add(pattern.toBuilder() + .putInt("Color", 15 - color.valueAsInt()) + .build()); } else { - tempList.add(pattern); + newPatterns.add(pattern); } } - values.put("Patterns", new ListTag(((ListTag) patternsTag).getType(), tempList)); + nbtBuilder.put("Patterns", newPatterns.build()); } - return state; + return state.toBaseBlock(nbtBuilder.build()); } } } @@ -109,58 +102,27 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler } private static String convertBannerType(int oldType, boolean isWall) { - String color; - switch (oldType) { - case 0: - color = "black"; - break; - case 1: - color = "red"; - break; - case 2: - color = "green"; - break; - case 3: - color = "brown"; - break; - case 4: - color = "blue"; - break; - case 5: - color = "purple"; - break; - case 6: - color = "cyan"; - break; - case 7: - color = "light_gray"; - break; - case 8: - color = "gray"; - break; - case 9: - color = "pink"; - break; - case 10: - color = "lime"; - break; - case 11: - color = "yellow"; - break; - case 12: - color = "light_blue"; - break; - case 13: - color = "magenta"; - break; - case 14: - color = "orange"; - break; - case 15: - color = "white"; - break; - default: - return null; + String color = switch (oldType) { + case 0 -> "black"; + case 1 -> "red"; + case 2 -> "green"; + case 3 -> "brown"; + case 4 -> "blue"; + case 5 -> "purple"; + case 6 -> "cyan"; + case 7 -> "light_gray"; + case 8 -> "gray"; + case 9 -> "pink"; + case 10 -> "lime"; + case 11 -> "yellow"; + case 12 -> "light_blue"; + case 13 -> "magenta"; + case 14 -> "orange"; + case 15 -> "white"; + default -> null; + }; + if (color == null) { + return null; } return color + (isWall ? "_wall_banner" : "_banner"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java index eea18f8df..c8c26cc91 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/BedBlockCompatibilityHandler.java @@ -19,18 +19,15 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.linbus.tree.LinTagType; -import java.util.Map; - -@SuppressWarnings("") public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { private static final Property FACING_PROPERTY; @@ -51,92 +48,63 @@ public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.RED_BED; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - Tag typeTag = values.get("color"); - if (typeTag instanceof IntTag) { - String bedType = convertBedType(((IntTag) typeTag).getValue()); - if (bedType != null) { - BlockType type = BlockTypes.get("minecraft:" + bedType); - if (type != null) { - BlockState state = type.getDefaultState(); - - Property facingProp = type.getProperty("facing"); - state = state.with(facingProp, block.getState(FACING_PROPERTY)); - - Property occupiedProp = type.getProperty("occupied"); - state = state.with(occupiedProp, false); - - Property partProp = type.getProperty("part"); - state = state.with(partProp, block.getState(PART_PROPERTY)); - - values.remove("color"); - return state; - } - } + public BaseBlock updateNbt(BaseBlock block) { + if (block.getBlockType() != BlockTypes.RED_BED) { + return block; } - return block; + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var typeTag = tag.findTag("color", LinTagType.intTag()); + if (typeTag == null) { + return block; + } + String bedType = convertBedType(typeTag.valueAsInt()); + if (bedType == null) { + return block; + } + BlockType type = BlockTypes.get("minecraft:" + bedType); + if (type == null) { + return block; + } + BlockState state = type.getDefaultState(); + + Property facingProp = type.getProperty("facing"); + state = state.with(facingProp, block.getState(FACING_PROPERTY)); + + Property occupiedProp = type.getProperty("occupied"); + state = state.with(occupiedProp, false); + + Property partProp = type.getProperty("part"); + state = state.with(partProp, block.getState(PART_PROPERTY)); + + var newTag = tag.toBuilder(); + newTag.remove("color"); + return state.toBaseBlock(LazyReference.computed(newTag.build())); } private String convertBedType(int oldType) { - String color; - switch (oldType) { - case 0: - color = "white"; - break; - case 1: - color = "orange"; - break; - case 2: - color = "magenta"; - break; - case 3: - color = "light_blue"; - break; - case 4: - color = "yellow"; - break; - case 5: - color = "lime"; - break; - case 6: - color = "pink"; - break; - case 7: - color = "gray"; - break; - case 8: - color = "light_gray"; - break; - case 9: - color = "cyan"; - break; - case 10: - color = "purple"; - break; - case 11: - color = "blue"; - break; - case 12: - color = "brown"; - break; - case 13: - color = "green"; - break; - case 14: - color = "red"; - break; - case 15: - color = "black"; - break; - default: - return null; - } - return color + "_bed"; + String color = switch (oldType) { + case 0 -> "white"; + case 1 -> "orange"; + case 2 -> "magenta"; + case 3 -> "light_blue"; + case 4 -> "yellow"; + case 5 -> "lime"; + case 6 -> "pink"; + case 7 -> "gray"; + case 8 -> "light_gray"; + case 9 -> "cyan"; + case 10 -> "purple"; + case 11 -> "blue"; + case 12 -> "brown"; + case 13 -> "green"; + case 14 -> "red"; + case 15 -> "black"; + default -> null; + }; + return color == null ? null : color + "_bed"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java index 6fcc6f422..cfd82833d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java @@ -20,12 +20,48 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.world.entity.EntityType; +import org.enginehub.linbus.tree.LinCompoundTag; public interface EntityNBTCompatibilityHandler { - boolean isAffectedEntity(EntityType type, CompoundTag entityTag); + /** + * Check if this is an entity affected by this handler. + * + * @deprecated this was never used, just return the same tag from + * {@link #updateNbt(EntityType, LinCompoundTag)} if it's not affected + */ + @Deprecated + default boolean isAffectedEntity(EntityType type, CompoundTag entityTag) { + var original = entityTag.toLinTag(); + var updated = updateNbt(type, original); + return !original.equals(updated); + } - CompoundTag updateNBT(EntityType type, CompoundTag entityTag); + @Deprecated + default CompoundTag updateNBT(EntityType type, CompoundTag entityTag) { + return new CompoundTag(updateNbt(type, entityTag.toLinTag())); + } + /** + * Given an entity type and data, update the data if needed. + * + * @param type the entity type + * @param entityTag the entity tag + * @return the updated tag, or the same tag if no update was needed + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @SuppressWarnings("deprecation") + @NonAbstractForCompatibility( + delegateName = "updateNBT", + delegateParams = { EntityType.class, CompoundTag.class } + ) + default LinCompoundTag updateNbt(EntityType type, LinCompoundTag entityTag) { + DeprecationUtil.checkDelegatingOverride(getClass()); + + return updateNBT(type, new CompoundTag(entityTag)).toLinTag(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java index 95d2fb091..803b6c237 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -19,65 +19,50 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; - -import java.util.Map; +import org.enginehub.linbus.tree.LinTagType; public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.FLOWER_POT; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - Tag item = values.get("Item"); - if (item instanceof StringTag) { - String id = ((StringTag) item).getValue(); - if (id.isEmpty()) { - return BlockTypes.FLOWER_POT.getDefaultState(); - } - int data = 0; - Tag dataTag = values.get("Data"); - if (dataTag instanceof IntTag) { - data = ((IntTag) dataTag).getValue(); - } - BlockState newState = convertLegacyBlockType(id, data); - if (newState != null) { - values.clear(); - return newState; - } + public BaseBlock updateNbt(BaseBlock block) { + if (block.getBlockType() != BlockTypes.FLOWER_POT) { + return block; } - return block; + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var item = tag.findTag("Item", LinTagType.stringTag()); + if (item == null) { + return block; + } + String id = item.value(); + if (id.isEmpty()) { + return BlockTypes.FLOWER_POT.getDefaultState().toBaseBlock(); + } + int data = 0; + var dataTag = tag.findTag("Data", LinTagType.intTag()); + if (dataTag != null) { + data = dataTag.valueAsInt(); + } + BlockState newState = convertLegacyBlockType(id, data); + return newState != null ? newState.toBaseBlock() : block; } private BlockState convertLegacyBlockType(String id, int data) { - int newId = 0; - switch (id) { - case "minecraft:red_flower": - newId = 38; // now poppy - break; - case "minecraft:yellow_flower": - newId = 37; // now dandelion - break; - case "minecraft:sapling": - newId = 6; // oak_sapling - break; - case "minecraft:deadbush": - case "minecraft:tallgrass": - newId = 31; // dead_bush with fern and grass (not 32!) - break; - default: - break; - } + int newId = switch (id) { + case "minecraft:red_flower" -> 38; // now poppy + case "minecraft:yellow_flower" -> 37; // now dandelion + case "minecraft:sapling" -> 6; // oak_sapling + case "minecraft:deadbush", "minecraft:tallgrass" -> + 31; // dead_bush with fern and grass (not 32!) + default -> 0; + }; String plantedName = null; if (newId == 0 && id.startsWith("minecraft:")) { plantedName = id.substring(10); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java index b7093dd4d..a2d32ea93 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NBTCompatibilityHandler.java @@ -19,15 +19,80 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.internal.util.DeprecationUtil; +import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; +import java.util.HashMap; import java.util.Map; public interface NBTCompatibilityHandler { - > boolean isAffectedBlock(B block); + /** + * Check if this is a block affected by this handler. + * + * @deprecated this is handled by {@link #updateNbt(BaseBlock)} now + */ + @Deprecated + default > boolean isAffectedBlock(B block) { + BaseBlock state = block.toBaseBlock(); + BaseBlock updated = updateNbt(state); + return state != updated; + } - > BlockStateHolder updateNBT(B block, Map values); + @Deprecated + default > BlockStateHolder updateNBT(B block, Map> values) { + BaseBlock changed = updateNbt(block.toBaseBlock(LazyReference.from(() -> { + var builder = LinCompoundTag.builder(); + for (var entry : values.entrySet()) { + builder.put(entry.getKey(), entry.getValue().toLinTag()); + } + return builder.build(); + }))); + CompoundTag data = changed.getNbtData(); + values.clear(); + if (data != null) { + values.putAll(data.getValue()); + } + return changed; + } + + /** + * Given a block, update the block's NBT. The NBT may be {@code null}. + * + * @param block the block to update + * @return the updated block, or the same block if no change is necessary + * @apiNote This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} + * for details + */ + @NonAbstractForCompatibility( + delegateName = "updateNBT", + delegateParams = { BlockStateHolder.class, Map.class } + ) + @SuppressWarnings("deprecated") + default BaseBlock updateNbt(BaseBlock block) { + DeprecationUtil.checkDelegatingOverride(getClass()); + if (!isAffectedBlock(block)) { + return block; + } + if (block.getNbt() == null) { + return block; + } + @SuppressWarnings("deprecation") + Map> values = new HashMap<>(new CompoundTag(block.getNbt()).getValue()); + BlockStateHolder changedBlock = updateNBT(block, values); + return changedBlock.toBaseBlock(LazyReference.from(() -> { + var builder = LinCompoundTag.builder(); + for (var entry : values.entrySet()) { + builder.put(entry.getKey(), entry.getValue().toLinTag()); + } + return builder.build(); + })); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java index 508e84280..04190197e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java @@ -19,18 +19,15 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.Map; +import org.enginehub.linbus.tree.LinTagType; public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final IntegerProperty NoteProperty; + private static final IntegerProperty NOTE_PROPERTY; static { IntegerProperty temp; @@ -39,27 +36,25 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { temp = null; } - NoteProperty = temp; + NOTE_PROPERTY = temp; } @Override - public > boolean isAffectedBlock(B block) { - return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { + public BaseBlock updateNbt(BaseBlock block) { + if (NOTE_PROPERTY == null || block.getBlockType() != BlockTypes.NOTE_BLOCK) { + return block; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } // note that instrument was not stored (in state or nbt) previously. // it will be updated to the block below when it gets set into the world for the first time - Tag noteTag = values.get("note"); - if (noteTag instanceof ByteTag) { - Byte note = ((ByteTag) noteTag).getValue(); - if (note != null) { - values.clear(); - return block.with(NoteProperty, (int) note).toImmutableState(); - } + var noteTag = tag.findTag("note", LinTagType.byteTag()); + if (noteTag == null) { + return block; } - return block; + return block.with(NOTE_PROPERTY, (int) noteTag.valueAsByte()).toBaseBlock(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 346f5f29e..f0bea016f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -19,41 +19,31 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.entity.EntityType; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinNumberTag; public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler { @Override - public boolean isAffectedEntity(EntityType type, CompoundTag tag) { - if (!type.id().startsWith("minecraft:")) { - return false; + public LinCompoundTag updateNbt(EntityType type, LinCompoundTag tag) { + if (!type.getId().startsWith("minecraft:")) { + return tag; } - boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction"); - boolean hasFacing = tag.containsKey("Facing"); - return hasLegacyDirection || hasFacing; - } - - @Override - public CompoundTag updateNBT(EntityType type, CompoundTag tag) { - boolean hasLegacyDir = tag.containsKey("Dir"); - boolean hasLegacyDirection = tag.containsKey("Direction"); - boolean hasPre113Facing = tag.containsKey("Facing"); Direction newDirection; - if (hasLegacyDir) { - newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging((byte) tag.asInt("Dir"))); - } else if (hasLegacyDirection) { - newDirection = MCDirections.fromPre13Hanging(tag.asInt("Direction")); - } else if (hasPre113Facing) { - newDirection = MCDirections.fromPre13Hanging(tag.asInt("Facing")); + if (tag.value().get("Dir") instanceof LinNumberTag legacyDir) { + newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging(legacyDir.value().byteValue())); + } else if (tag.value().get("Direction") instanceof LinNumberTag legacyDirection) { + newDirection = MCDirections.fromPre13Hanging(legacyDirection.value().intValue()); + } else if (tag.value().get("Facing") instanceof LinNumberTag legacyFacing) { + newDirection = MCDirections.fromPre13Hanging(legacyFacing.value().intValue()); } else { return tag; } byte hangingByte = (byte) MCDirections.toHanging(newDirection); - CompoundTagBuilder builder = tag.createBuilder(); + var builder = tag.toBuilder(); builder.putByte("Facing", hangingByte); return builder.build(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java index d2dd4f5a8..24c5de232 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SignCompatibilityHandler.java @@ -24,50 +24,52 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.internal.util.DeprecationUtil; -import com.sk89q.worldedit.world.block.BlockStateHolder; - -import java.util.Map; +import com.sk89q.worldedit.world.block.BaseBlock; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTagType; public class SignCompatibilityHandler implements NBTCompatibilityHandler { @Override - public > boolean isAffectedBlock(B block) { - return DeprecationUtil.isSign(block.getBlockType()); - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { + public BaseBlock updateNbt(BaseBlock block) { + if (!DeprecationUtil.isSign(block.getBlockType())) { + return block; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var newTag = tag.toBuilder(); for (int i = 0; i < 4; ++i) { String key = "Text" + (i + 1); - Tag value = values.get(key); - if (value instanceof StringTag) { - String storedString = ((StringTag) value).getValue(); - JsonElement jsonElement = null; - if (storedString != null && storedString.startsWith("{")) { - try { - jsonElement = new JsonParser().parse(storedString); - } catch (JsonSyntaxException ex) { - // ignore: jsonElement will be null in the next check - } - } - if (jsonElement == null) { - jsonElement = new JsonPrimitive(storedString == null ? "" : storedString); - } - if (jsonElement.isJsonObject()) { - continue; - } - - if (jsonElement.isJsonNull()) { - jsonElement = new JsonPrimitive(""); - } - - JsonObject jsonTextObject = new JsonObject(); - jsonTextObject.add("text", jsonElement); - values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString())); + var value = tag.findTag(key, LinTagType.stringTag()); + if (value == null) { + continue; } + String storedString = value.value(); + JsonElement jsonElement = null; + if (storedString.startsWith("{")) { + try { + jsonElement = JsonParser.parseString(storedString); + } catch (JsonSyntaxException ex) { + // ignore: jsonElement will be null in the next check + } + } + if (jsonElement == null) { + jsonElement = new JsonPrimitive(storedString); + } + if (jsonElement.isJsonObject()) { + continue; + } + + if (jsonElement.isJsonNull()) { + jsonElement = new JsonPrimitive(""); + } + + JsonObject jsonTextObject = new JsonObject(); + jsonTextObject.add("text", jsonElement); + newTag.put("Text" + (i + 1), LinStringTag.of(jsonTextObject.toString())); } return block; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java index f00622561..6d5158208 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java @@ -19,20 +19,17 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.ByteTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; - -import java.util.Map; +import org.enginehub.linbus.tree.LinTagType; public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { - private static final Property FacingProperty; + private static final Property FACING_PROPERTY; static { Property tempFacing; @@ -41,61 +38,70 @@ public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { tempFacing = null; } - FacingProperty = tempFacing; + FACING_PROPERTY = tempFacing; } @Override - public > boolean isAffectedBlock(B block) { - return block.getBlockType() == BlockTypes.SKELETON_SKULL - || block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; - } - - @Override - public > BlockStateHolder updateNBT(B block, Map values) { - boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; - Tag typeTag = values.get("SkullType"); - if (typeTag instanceof ByteTag) { - String skullType = convertSkullType(((ByteTag) typeTag).getValue(), isWall); - if (skullType != null) { - BlockType type = BlockTypes.get("minecraft:" + skullType); - if (type != null) { - BlockState state = type.getDefaultState(); - if (isWall) { - Property newProp = type.getProperty("facing"); - state = state.with(newProp, block.getState(FacingProperty)); - } else { - Tag rotTag = values.get("Rot"); - if (rotTag instanceof ByteTag) { - Property newProp = type.getProperty("rotation"); - state = state.with(newProp, (int) ((ByteTag) rotTag).getValue()); - } - } - values.remove("SkullType"); - values.remove("Rot"); - return state; - } + public BaseBlock updateNbt(BaseBlock block) { + var blockType = block.getBlockType(); + boolean isWall = blockType == BlockTypes.SKELETON_WALL_SKULL; + if (blockType != BlockTypes.SKELETON_SKULL && !isWall) { + return block; + } + if (FACING_PROPERTY == null) { + return block; + } + var tag = block.getNbt(); + if (tag == null) { + return block; + } + var typeTag = tag.findTag("SkullType", LinTagType.byteTag()); + if (typeTag == null) { + return block; + } + String skullType = convertSkullType(typeTag.valueAsByte(), isWall); + if (skullType == null) { + return block; + } + BlockType type = BlockTypes.get("minecraft:" + skullType); + if (type == null) { + return block; + } + BlockState state = type.getDefaultState(); + if (isWall) { + Property newProp = type.getProperty("facing"); + state = state.with(newProp, block.getState(FACING_PROPERTY)); + } else { + var rotTag = tag.findTag("Rot", LinTagType.byteTag()); + if (rotTag != null) { + Property newProp = type.getProperty("rotation"); + state = state.with(newProp, (int) rotTag.valueAsByte()); } } - return block; + var newTag = tag.toBuilder() + .remove("SkullType") + .remove("Rot") + .build(); + return state.toBaseBlock(newTag); } - private String convertSkullType(Byte oldType, boolean isWall) { - switch (oldType) { - case 0: - return isWall ? "skeleton_wall_skull" : "skeleton_skull"; - case 1: - return isWall ? "wither_skeleton_wall_skull" : "wither_skeleton_skull"; - case 2: - return isWall ? "zombie_wall_head" : "zombie_head"; - case 3: - return isWall ? "player_wall_head" : "player_head"; - case 4: - return isWall ? "creeper_wall_head" : "creeper_head"; - case 5: - return isWall ? "dragon_wall_head" : "dragon_head"; - default: - return null; + private String convertSkullType(byte oldType, boolean isWall) { + record SkullData(String kind, String suffix) { } + + var skullData = switch (oldType) { + case 0 -> new SkullData("skeleton", "skull"); + case 1 -> new SkullData("wither_skeleton", "skull"); + case 2 -> new SkullData("zombie", "head"); + case 3 -> new SkullData("player", "head"); + case 4 -> new SkullData("creeper", "head"); + case 5 -> new SkullData("dragon", "head"); + default -> null; + }; + if (skullData == null) { + return null; + } + return skullData.kind + (isWall ? "_wall" : "") + "_" + skullData.suffix; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java index 981debe4b..551ac5dd7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/share/BuiltInClipboardShareDestinations.java @@ -61,7 +61,7 @@ public enum BuiltInClipboardShareDestinations implements ClipboardShareDestinati PasteMetadata pasteMetadata = new PasteMetadata(); pasteMetadata.author = metadata.author(); - pasteMetadata.extension = "schem"; + pasteMetadata.extension = metadata.format().getPrimaryFileExtension(); pasteMetadata.name = metadata.name(); EngineHubPaste pasteService = new EngineHubPaste(); @@ -75,7 +75,7 @@ public enum BuiltInClipboardShareDestinations implements ClipboardShareDestinati @Override public ClipboardFormat getDefaultFormat() { - return BuiltInClipboardFormat.SPONGE_SCHEMATIC; + return BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC; } @Override @@ -119,13 +119,14 @@ public enum BuiltInClipboardShareDestinations implements ClipboardShareDestinati @Override public ClipboardFormat getDefaultFormat() { - return BuiltInClipboardFormat.FAST; + return BuiltInClipboardFormat.FAST_V3; } @Override public boolean supportsFormat(final ClipboardFormat format) { - return format == BuiltInClipboardFormat.SPONGE_SCHEMATIC || - format == BuiltInClipboardFormat.FAST || + return format == BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC || + format == BuiltInClipboardFormat.FAST_V3 || + format == BuiltInClipboardFormat.FAST_V2 || format == BuiltInClipboardFormat.MCEDIT_SCHEMATIC; } }; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java new file mode 100644 index 000000000..5c4e90264 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/ReaderUtil.java @@ -0,0 +1,283 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.VarIntIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.storage.NBTConversions; +import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Common code shared between schematic readers. + */ +public class ReaderUtil { //FAWE - make public + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + static void checkSchematicVersion(int version, LinCompoundTag schematicTag) throws IOException { + int schematicVersion = getSchematicVersion(schematicTag); + + checkState( + version == schematicVersion, + "Schematic is not version %s, but %s", version, schematicVersion + ); + } + + public static int getSchematicVersion(LinCompoundTag schematicTag) throws IOException { + return schematicTag.getTag("Version", LinTagType.intTag()).valueAsInt(); + } + + static VersionedDataFixer getVersionedDataFixer( + LinCompoundTag schematic, Platform platform, + int liveDataVersion + ) { + //FAWE start - call fawe method without NBT component requirement + return getVersionedDataFixer(schematic.getTag("DataVersion", LinTagType.intTag()).valueAsInt(), platform, + liveDataVersion + ); + //FAWE end + } + + //FAWE start - make getVersionedDataFixer without schematic compound + public + public static VersionedDataFixer getVersionedDataFixer(int schematicDataVersion, Platform platform, int liveDataVersion) { + DataFixer fixer = null; + if (schematicDataVersion < 0) { + LOGGER.warn( + "Schematic has an unknown data version ({}). Data may be incompatible.", + schematicDataVersion + ); + } else if (schematicDataVersion > liveDataVersion) { + LOGGER.warn( + "Schematic was made in a newer Minecraft version ({} > {})." + + " Data may be incompatible.", + schematicDataVersion, liveDataVersion + ); + } else if (schematicDataVersion < liveDataVersion) { + fixer = platform.getDataFixer(); + if (fixer != null) { + LOGGER.debug( + "Schematic was made in an older Minecraft version ({} < {})," + + " will attempt DFU.", + schematicDataVersion, liveDataVersion + ); + } else { + LOGGER.info( + "Schematic was made in an older Minecraft version ({} < {})," + + " but DFU is not available. Data may be incompatible.", + schematicDataVersion, liveDataVersion + ); + } + } + return new VersionedDataFixer(schematicDataVersion, fixer); + } + //FAWE end + + static Map decodePalette( + LinCompoundTag paletteObject, VersionedDataFixer fixer + ) throws IOException { + Map palette = new HashMap<>(); + + ParserContext parserContext = new ParserContext(); + parserContext.setRestricted(false); + parserContext.setTryLegacy(false); + parserContext.setPreferringWildcard(false); + + for (var palettePart : paletteObject.value().entrySet()) { + if (!(palettePart.getValue() instanceof LinIntTag idTag)) { + throw new IOException("Invalid palette entry: " + palettePart); + } + int id = idTag.valueAsInt(); + String paletteName = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart.getKey()); + BlockState state; + try { + state = WorldEdit.getInstance().getBlockFactory().parseFromInput(paletteName, parserContext).toImmutableState(); + } catch (InputParseException e) { + LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); + state = BlockTypes.AIR.getDefaultState(); + } + palette.put(id, state); + } + return palette; + } + + static void initializeClipboardFromBlocks( + Clipboard clipboard, Map palette, byte[] blocks, LinListTag tileEntities, + VersionedDataFixer fixer, boolean dataIsNested + ) throws IOException { + Map tileEntitiesMap = new HashMap<>(); + if (tileEntities != null) { + for (LinCompoundTag tileEntity : tileEntities.value()) { + final BlockVector3 pt = clipboard.getMinimumPoint().add( + decodeBlockVector3(tileEntity.getTag("Pos", LinTagType.intArrayTag())) + ); + LinCompoundTag.Builder values = extractData(dataIsNested, tileEntity); + values.putInt("x", pt.x()); + values.putInt("y", pt.y()); + values.putInt("z", pt.z()); + values.put("id", tileEntity.value().get("Id")); + if (fixer.isActive()) { + tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, values.build()); + } else { + tileEntity = values.build(); + } + tileEntitiesMap.put(pt, tileEntity); + } + } + + int width = clipboard.getRegion().getWidth(); + int length = clipboard.getRegion().getLength(); + + int index = 0; + for (VarIntIterator iter = new VarIntIterator(blocks); iter.hasNext(); index++) { + int nextBlockId = iter.nextInt(); + BlockState state = palette.get(nextBlockId); + BlockVector3 rawPos = decodePositionFromDataIndex(width, length, index); + try { + BlockVector3 offsetPos = clipboard.getMinimumPoint().add(rawPos); + LinCompoundTag tileEntity = tileEntitiesMap.get(offsetPos); + clipboard.setBlock(offsetPos, state.toBaseBlock(tileEntity)); + } catch (WorldEditException e) { + throw new IOException("Failed to load a block in the schematic", e); + } + } + } + + private static LinCompoundTag.Builder extractData(boolean dataIsNested, LinCompoundTag tag) { + if (dataIsNested) { + LinCompoundTag dataTag = tag.findTag("Data", LinTagType.compoundTag()); + return dataTag != null ? dataTag.toBuilder() : LinCompoundTag.builder(); + } else { + LinCompoundTag.Builder values = tag.toBuilder(); + values.remove("Id"); + values.remove("Pos"); + return values; + } + } + + static BlockVector3 decodePositionFromDataIndex(int width, int length, int index) { + // index = (y * width * length) + (z * width) + x + int y = index / (width * length); + int remainder = index - (y * width * length); + int z = remainder / width; + int x = remainder - z * width; + return BlockVector3.at(x, y, z); + } + + static BlockVector3 decodeBlockVector3(@Nullable LinIntArrayTag tag) throws IOException { + if (tag == null) { + return BlockVector3.ZERO; + } + int[] parts = tag.value(); + if (parts.length != 3) { + throw new IOException("Invalid block vector specified in schematic."); + } + return BlockVector3.at(parts[0], parts[1], parts[2]); + } + + static void readEntities( + BlockArrayClipboard clipboard, List entList, + VersionedDataFixer fixer, boolean positionIsRelative + ) { + if (entList.isEmpty()) { + return; + } + for (LinCompoundTag entityTag : entList) { + String id = entityTag.getTag("Id", LinTagType.stringTag()).value(); + LinCompoundTag.Builder values = extractData(positionIsRelative, entityTag); + LinCompoundTag dataTag = values.putString("id", id).build(); + dataTag = fixer.fixUp(DataFixer.FixTypes.ENTITY, dataTag); + + EntityType entityType = EntityTypes.get(id); + if (entityType != null) { + Location location = NBTConversions.toLocation( + clipboard, + entityTag.getListTag("Pos", LinTagType.doubleTag()), + dataTag.getListTag("Rotation", LinTagType.floatTag()) + ); + BaseEntity state = new BaseEntity(entityType, LazyReference.computed(dataTag)); + if (positionIsRelative) { + location = location.setPosition( + location.toVector().add(clipboard.getMinimumPoint().toVector3()) + ); + } + clipboard.createEntity(location, state); + } else { + LOGGER.warn("Unknown entity when pasting schematic: " + id); + } + } + } + + static Int2ObjectMap readBiomePalette(VersionedDataFixer fixer, LinCompoundTag paletteTag, Logger logger) throws + IOException { + Int2ObjectMap palette = new Int2ObjectLinkedOpenHashMap<>(paletteTag.value().size()); + for (var palettePart : paletteTag.value().entrySet()) { + String key = palettePart.getKey(); + key = fixer.fixUp(DataFixer.FixTypes.BIOME, key); + BiomeType biome = BiomeTypes.get(key); + if (biome == null) { + logger.warn("Unknown biome type :" + key + + " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + } + if (!(palettePart.getValue() instanceof LinIntTag idTag)) { + throw new IOException("Biome mapped to non-Int tag."); + } + palette.put(idTag.valueAsInt(), biome); + } + return palette; + } + + private ReaderUtil() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java new file mode 100644 index 000000000..7574bfe4c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV1Reader.java @@ -0,0 +1,134 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BlockState; +import org.enginehub.linbus.stream.LinStream; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.Map; +import java.util.OptionalInt; + +/** + * Reads schematic files using the Sponge Schematic Specification (Version 1). + */ +public class SpongeSchematicV1Reader implements ClipboardReader { + + private final LinStream rootStream; + + public SpongeSchematicV1Reader(LinStream rootStream) { + this.rootStream = rootStream; + } + + @Override + public Clipboard read() throws IOException { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(1, schematicTag); + + return doRead(schematicTag); + } + + // For legacy SpongeSchematicReader, can be inlined in WorldEdit 8 + public static BlockArrayClipboard doRead(LinCompoundTag schematicTag) throws IOException { + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + + // this is a relatively safe assumption unless someone imports a schematic from 1.12 + // e.g. sponge 7.1- + VersionedDataFixer fixer = new VersionedDataFixer(Constants.DATA_VERSION_MC_1_13_2, platform.getDataFixer()); + return readVersion1(schematicTag, fixer); + } + + @Override + public OptionalInt getDataVersion() { + try { + // Validate schematic version to be sure + ReaderUtil.checkSchematicVersion(1, getBaseTag()); + return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private LinCompoundTag getBaseTag() throws IOException { + return LinRootEntry.readFrom(rootStream).value(); + } + + static BlockArrayClipboard readVersion1(LinCompoundTag schematicTag, VersionedDataFixer fixer) throws IOException { + int width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + + BlockVector3 min = ReaderUtil.decodeBlockVector3(schematicTag.findTag("Offset", LinTagType.intArrayTag())); + + BlockVector3 offset = BlockVector3.ZERO; + LinCompoundTag metadataTag = schematicTag.findTag("Metadata", LinTagType.compoundTag()); + if (metadataTag != null) { + LinIntTag offsetX = metadataTag.findTag("WEOffsetX", LinTagType.intTag()); + if (offsetX != null) { + int offsetY = metadataTag.getTag("WEOffsetY", LinTagType.intTag()).valueAsInt(); + int offsetZ = metadataTag.getTag("WEOffsetZ", LinTagType.intTag()).valueAsInt(); + offset = BlockVector3.at(offsetX.valueAsInt(), offsetY, offsetZ); + } + } + + BlockVector3 origin = min.subtract(offset); + Region region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE)); + + LinIntTag paletteMaxTag = schematicTag.findTag("PaletteMax", LinTagType.intTag()); + LinCompoundTag paletteObject = schematicTag.getTag("Palette", LinTagType.compoundTag()); + if (paletteMaxTag != null && paletteObject.value().size() != paletteMaxTag.valueAsInt()) { + throw new IOException("Block palette size does not match expected size."); + } + + Map palette = ReaderUtil.decodePalette(paletteObject, fixer); + + byte[] blocks = schematicTag.getTag("BlockData", LinTagType.byteArrayTag()).value(); + + LinListTag tileEntities = schematicTag.findListTag("BlockEntities", LinTagType.compoundTag()); + if (tileEntities == null) { + tileEntities = schematicTag.findListTag("TileEntities", LinTagType.compoundTag()); + } + + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); + ReaderUtil.initializeClipboardFromBlocks(clipboard, palette, blocks, tileEntities, fixer, false); + return clipboard; + } + + @Override + public void close() throws IOException { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java new file mode 100644 index 000000000..2cd7bb1e1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Reader.java @@ -0,0 +1,144 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.VarIntIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.biome.BiomeType; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.stream.LinStream; +import org.enginehub.linbus.tree.LinByteArrayTag; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.OptionalInt; + +/** + * Reads schematic files using the Sponge Schematic Specification (Version 2). + */ +public class SpongeSchematicV2Reader implements ClipboardReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final LinStream rootStream; + + public SpongeSchematicV2Reader(LinStream rootStream) { + this.rootStream = rootStream; + } + + @Override + public Clipboard read() throws IOException { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(2, schematicTag); + + return doRead(schematicTag); + } + + // For legacy SpongeSchematicReader, can be inlined in WorldEdit 8 + public static Clipboard doRead(LinCompoundTag schematicTag) throws IOException { + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + + VersionedDataFixer fixer = ReaderUtil.getVersionedDataFixer(schematicTag, platform, liveDataVersion); + BlockArrayClipboard clip = SpongeSchematicV1Reader.readVersion1(schematicTag, fixer); + return readVersion2(clip, schematicTag, fixer); + } + + @Override + public OptionalInt getDataVersion() { + try { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(2, schematicTag); + + int dataVersion = schematicTag.getTag("DataVersion", LinTagType.intTag()).valueAsInt(); + if (dataVersion < 0) { + return OptionalInt.empty(); + } + return OptionalInt.of(dataVersion); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private LinCompoundTag getBaseTag() throws IOException { + return LinRootEntry.readFrom(rootStream).value(); + } + + private static Clipboard readVersion2( + BlockArrayClipboard version1, LinCompoundTag schematicTag, VersionedDataFixer fixer + ) throws IOException { + if (schematicTag.value().containsKey("BiomeData")) { + readBiomes2(version1, schematicTag, fixer); + } + LinListTag entities = schematicTag.findListTag("Entities", LinTagType.compoundTag()); + if (entities != null) { + ReaderUtil.readEntities(version1, entities.value(), fixer, false); + } + return version1; + } + + private static void readBiomes2( + BlockArrayClipboard clipboard, LinCompoundTag schematic, VersionedDataFixer fixer + ) throws IOException { + LinByteArrayTag dataTag = schematic.getTag("BiomeData", LinTagType.byteArrayTag()); + LinIntTag maxTag = schematic.getTag("BiomePaletteMax", LinTagType.intTag()); + LinCompoundTag paletteTag = schematic.getTag("BiomePalette", LinTagType.compoundTag()); + + if (maxTag.valueAsInt() != paletteTag.value().size()) { + throw new IOException("Biome palette size does not match expected size."); + } + + Int2ObjectMap palette = ReaderUtil.readBiomePalette(fixer, paletteTag, LOGGER); + + int width = clipboard.getDimensions().x(); + + byte[] biomes = dataTag.value(); + BlockVector3 min = clipboard.getMinimumPoint(); + int index = 0; + for (VarIntIterator iter = new VarIntIterator(biomes); iter.hasNext(); index++) { + int nextBiomeId = iter.nextInt(); + BiomeType type = palette.get(nextBiomeId); + // hack -- the x and y values from the 3d decode with length == 1 are equivalent + BlockVector3 hackDecode = ReaderUtil.decodePositionFromDataIndex(width, 1, index); + int x = hackDecode.x(); + int z = hackDecode.y(); + for (int y = 0; y < clipboard.getRegion().getHeight(); y++) { + clipboard.setBiome(min.add(x, y, z), type); + } + } + } + + @Override + public void close() throws IOException { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Writer.java similarity index 51% rename from worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Writer.java index dc313b259..8504f0fe8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/SpongeSchematicWriter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV2Writer.java @@ -17,62 +17,41 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.extent.clipboard.io; +package com.sk89q.worldedit.extent.clipboard.io.sponge; -import com.fastasyncworldedit.core.Fawe; -import com.google.common.collect.Maps; -import com.sk89q.jnbt.ByteArrayTag; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.IntArrayTag; -import com.sk89q.jnbt.IntTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.NBTOutputStream; -import com.sk89q.jnbt.ShortTag; -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import org.enginehub.linbus.stream.LinBinaryIO; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; /** - * Writes schematic files using the Sponge schematic format. - * - * @deprecated Slow, resource intensive, but sometimes safer than using the recommended - * {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter}. - * Avoid using large clipboards to create schematics with this writer. + * Writes schematic files using the Sponge Schematic Specification (Version 2). */ -@Deprecated -public class SpongeSchematicWriter implements ClipboardWriter { +public class SpongeSchematicV2Writer implements ClipboardWriter { private static final int CURRENT_VERSION = 2; private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; - private final NBTOutputStream outputStream; + private final DataOutputStream outputStream; - /** - * Create a new schematic writer. - * - * @param outputStream the output stream to write to - */ - public SpongeSchematicWriter(NBTOutputStream outputStream) { - checkNotNull(outputStream); + public SpongeSchematicV2Writer(DataOutputStream outputStream) { this.outputStream = outputStream; } @@ -82,17 +61,16 @@ public class SpongeSchematicWriter implements ClipboardWriter { // between upstream and FAWE clipboard.flush(); //FAWE end - // For now always write the latest version. Maybe provide support for earlier if more appear. - outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard))); + LinBinaryIO.write(outputStream, new LinRootEntry("Schematic", write2(clipboard))); } /** * Writes a version 2 schematic file. * * @param clipboard The clipboard - * @return The schematic map + * @return the schematic tag */ - private Map write2(Clipboard clipboard) { + private LinCompoundTag write2(Clipboard clipboard) { Region region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); BlockVector3 min = region.getMinimumPoint(); @@ -111,34 +89,49 @@ public class SpongeSchematicWriter implements ClipboardWriter { throw new IllegalArgumentException("Length of region too large for a .schematic"); } - Map schematic = new HashMap<>(); - schematic.put("Version", new IntTag(CURRENT_VERSION)); - schematic.put("DataVersion", new IntTag( - WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); + LinCompoundTag.Builder schematic = LinCompoundTag.builder(); + schematic.putInt("Version", CURRENT_VERSION); + schematic.putInt("DataVersion", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() + ); - Map metadata = new HashMap<>(); - metadata.put("WEOffsetX", new IntTag(offset.x())); - metadata.put("WEOffsetY", new IntTag(offset.y())); - metadata.put("WEOffsetZ", new IntTag(offset.z())); - metadata.put("FAWEVersion", new IntTag(Fawe.instance().getVersion().build)); + LinCompoundTag.Builder metadata = LinCompoundTag.builder(); + metadata.putInt("WEOffsetX", offset.x()); + metadata.putInt("WEOffsetY", offset.y()); + metadata.putInt("WEOffsetZ", offset.z()); - schematic.put("Metadata", new CompoundTag(metadata)); + LinCompoundTag.Builder worldEditSection = LinCompoundTag.builder(); + worldEditSection.putString("Version", WorldEdit.getVersion()); + worldEditSection.putString("EditingPlatform", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).id() + ); + worldEditSection.putIntArray("Offset", new int[]{offset.x(), offset.y(), offset.z()}); - schematic.put("Width", new ShortTag((short) width)); - schematic.put("Height", new ShortTag((short) height)); - schematic.put("Length", new ShortTag((short) length)); + LinCompoundTag.Builder platformsSection = LinCompoundTag.builder(); + for (Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) { + platformsSection.put(platform.id(), LinCompoundTag + .builder() + .putString("Name", platform.getPlatformName()) + .putString("Version", platform.getPlatformVersion()) + .build()); + } + worldEditSection.put("Platforms", platformsSection.build()); + + metadata.put("WorldEdit", worldEditSection.build()); + + schematic.put("Metadata", metadata.build()); + + schematic.putShort("Width", (short) width); + schematic.putShort("Height", (short) height); + schematic.putShort("Length", (short) length); // The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin' - schematic.put("Offset", new IntArrayTag(new int[]{ - min.x(), - min.y(), - min.z(), - })); + schematic.putIntArray("Offset", new int[]{min.x(), min.y(), min.z(),}); int paletteMax = 0; - Map palette = new HashMap<>(); + Object2IntMap palette = new Object2IntLinkedOpenHashMap<>(); - List tileEntities = new ArrayList<>(); + LinListTag.Builder tileEntities = LinListTag.builder(LinTagType.compoundTag()); ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); @@ -150,8 +143,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { int x0 = min.x() + x; BlockVector3 point = BlockVector3.at(x0, y0, z0); BaseBlock block = clipboard.getFullBlock(point); - if (block.getNbtData() != null) { - Map values = new HashMap<>(block.getNbtData().getValue()); + LinCompoundTag nbt = block.getNbt(); + if (nbt != null) { + LinCompoundTag.Builder values = nbt.toBuilder(); values.remove("id"); // Remove 'id' if it exists. We want 'Id' @@ -160,16 +154,16 @@ public class SpongeSchematicWriter implements ClipboardWriter { values.remove("y"); values.remove("z"); - values.put("Id", new StringTag(block.getNbtId())); - values.put("Pos", new IntArrayTag(new int[]{x, y, z})); + values.putString("Id", block.getNbtId()); + values.putIntArray("Pos", new int[]{x, y, z}); - tileEntities.add(new CompoundTag(values)); + tileEntities.add(values.build()); } String blockKey = block.toImmutableState().getAsString(); int blockId; if (palette.containsKey(blockKey)) { - blockId = palette.get(blockKey); + blockId = palette.getInt(blockKey); } else { blockId = paletteMax; palette.put(blockKey, blockId); @@ -185,14 +179,14 @@ public class SpongeSchematicWriter implements ClipboardWriter { } } - schematic.put("PaletteMax", new IntTag(paletteMax)); + schematic.putInt("PaletteMax", paletteMax); - Map paletteTag = new HashMap<>(); - palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + LinCompoundTag.Builder paletteTag = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(palette, e -> paletteTag.putInt(e.getKey(), e.getIntValue())); - schematic.put("Palette", new CompoundTag(paletteTag)); - schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray())); - schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities)); + schematic.put("Palette", paletteTag.build()); + schematic.putByteArray("BlockData", buffer.toByteArray()); + schematic.put("BlockEntities", tileEntities.build()); // version 2 stuff if (clipboard.hasBiomes()) { @@ -200,13 +194,16 @@ public class SpongeSchematicWriter implements ClipboardWriter { } if (!clipboard.getEntities().isEmpty()) { - writeEntities(clipboard, schematic); + LinListTag value = WriterUtil.encodeEntities(clipboard, false); + if (value != null) { + schematic.put("Entities", value); + } } - return schematic; + return schematic.build(); } - private void writeBiomes(Clipboard clipboard, Map schematic) { + private void writeBiomes(Clipboard clipboard, LinCompoundTag.Builder schematic) { BlockVector3 min = clipboard.getMinimumPoint(); int width = clipboard.getRegion().getWidth(); int length = clipboard.getRegion().getLength(); @@ -214,7 +211,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * length); int paletteMax = 0; - Map palette = new HashMap<>(); + Object2IntMap palette = new Object2IntLinkedOpenHashMap<>(); for (int z = 0; z < length; z++) { int z0 = min.z() + z; @@ -226,7 +223,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { String biomeKey = biome.id(); int biomeId; if (palette.containsKey(biomeKey)) { - biomeId = palette.get(biomeKey); + biomeId = palette.getInt(biomeKey); } else { biomeId = paletteMax; palette.put(biomeKey, biomeId); @@ -241,38 +238,13 @@ public class SpongeSchematicWriter implements ClipboardWriter { } } - schematic.put("BiomePaletteMax", new IntTag(paletteMax)); + schematic.putInt("BiomePaletteMax", paletteMax); - Map paletteTag = new HashMap<>(); - palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + LinCompoundTag.Builder paletteTag = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(palette, e -> paletteTag.putInt(e.getKey(), e.getIntValue())); - schematic.put("BiomePalette", new CompoundTag(paletteTag)); - schematic.put("BiomeData", new ByteArrayTag(buffer.toByteArray())); - } - - private void writeEntities(Clipboard clipboard, Map schematic) { - List entities = clipboard.getEntities().stream().map(e -> { - BaseEntity state = e.getState(); - if (state == null) { - return null; - } - Map values = Maps.newHashMap(); - CompoundTag rawData = state.getNbtData(); - if (rawData != null) { - values.putAll(rawData.getValue()); - } - values.remove("id"); - values.put("Id", new StringTag(state.getType().id())); - final Location location = e.getLocation(); - values.put("Pos", writeVector(location.toVector())); - values.put("Rotation", writeRotation(location)); - - return new CompoundTag(values); - }).filter(Objects::nonNull).collect(Collectors.toList()); - if (entities.isEmpty()) { - return; - } - schematic.put("Entities", new ListTag(CompoundTag.class, entities)); + schematic.put("BiomePalette", paletteTag.build()); + schematic.putByteArray("BiomeData", buffer.toByteArray()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java new file mode 100644 index 000000000..978cb8ba5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Reader.java @@ -0,0 +1,168 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.internal.util.VarIntIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockState; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.apache.logging.log4j.Logger; +import org.enginehub.linbus.stream.LinStream; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.IOException; +import java.util.Map; +import java.util.OptionalInt; + +/** + * Reads schematic files using the Sponge Schematic Specification. + */ +public class SpongeSchematicV3Reader implements ClipboardReader { + + private static final Logger LOGGER = LogManagerCompat.getLogger(); + + private final LinStream rootStream; + + public SpongeSchematicV3Reader(LinStream rootStream) { + this.rootStream = rootStream; + } + + @Override + public Clipboard read() throws IOException { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(3, schematicTag); + + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + + VersionedDataFixer fixer = ReaderUtil.getVersionedDataFixer(schematicTag, platform, liveDataVersion); + return readVersion3(schematicTag, fixer); + } + + @Override + public OptionalInt getDataVersion() { + try { + LinCompoundTag schematicTag = getBaseTag(); + ReaderUtil.checkSchematicVersion(3, schematicTag); + + int dataVersion = schematicTag.getTag("DataVersion", LinTagType.intTag()).valueAsInt(); + if (dataVersion < 0) { + return OptionalInt.empty(); + } + return OptionalInt.of(dataVersion); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + private LinCompoundTag getBaseTag() throws IOException { + return LinRootEntry.readFrom(rootStream).value().getTag("Schematic", LinTagType.compoundTag()); + } + + private Clipboard readVersion3(LinCompoundTag schematicTag, VersionedDataFixer fixer) throws IOException { + int width = schematicTag.getTag("Width", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int height = schematicTag.getTag("Height", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + int length = schematicTag.getTag("Length", LinTagType.shortTag()).valueAsShort() & 0xFFFF; + + BlockVector3 offset = ReaderUtil.decodeBlockVector3(schematicTag.findTag("Offset", LinTagType.intArrayTag())); + + BlockVector3 origin = BlockVector3.ZERO; + LinCompoundTag metadataTag = schematicTag.findTag("Metadata", LinTagType.compoundTag()); + if (metadataTag != null) { + LinCompoundTag worldeditMeta = metadataTag.findTag("WorldEdit", LinTagType.compoundTag()); + if (worldeditMeta != null) { + origin = ReaderUtil.decodeBlockVector3(worldeditMeta.findTag("Origin", LinTagType.intArrayTag())); + } + } + BlockVector3 min = offset.add(origin); + + BlockArrayClipboard clipboard = new BlockArrayClipboard(new CuboidRegion( + min, + min.add(width, height, length).subtract(BlockVector3.ONE) + )); + clipboard.setOrigin(origin); + + decodeBlocksIntoClipboard(fixer, schematicTag, clipboard); + + LinCompoundTag biomeContainer = schematicTag.findTag("Biomes", LinTagType.compoundTag()); + if (biomeContainer != null) { + readBiomes3(clipboard, biomeContainer, fixer); + } + + LinListTag entities = schematicTag.findListTag("Entities", LinTagType.compoundTag()); + if (entities != null) { + ReaderUtil.readEntities(clipboard, entities.value(), fixer, true); + } + + return clipboard; + } + + private void decodeBlocksIntoClipboard( + VersionedDataFixer fixer, LinCompoundTag schematic, BlockArrayClipboard clipboard + ) throws IOException { + LinCompoundTag blockContainer = schematic.getTag("Blocks", LinTagType.compoundTag()); + + LinCompoundTag paletteObject = blockContainer.getTag("Palette", LinTagType.compoundTag()); + Map palette = ReaderUtil.decodePalette(paletteObject, fixer); + + byte[] blocks = blockContainer.getTag("Data", LinTagType.byteArrayTag()).value(); + LinListTag blockEntities = blockContainer.getListTag("BlockEntities", LinTagType.compoundTag()); + + ReaderUtil.initializeClipboardFromBlocks(clipboard, palette, blocks, blockEntities, fixer, true); + } + + private void readBiomes3( + BlockArrayClipboard clipboard, LinCompoundTag biomeContainer, VersionedDataFixer fixer + ) throws IOException { + LinCompoundTag paletteTag = biomeContainer.getTag("Palette", LinTagType.compoundTag()); + + Int2ObjectMap palette = ReaderUtil.readBiomePalette(fixer, paletteTag, LOGGER); + + int width = clipboard.getRegion().getWidth(); + int length = clipboard.getRegion().getLength(); + + byte[] biomes = biomeContainer.getTag("Data", LinTagType.byteArrayTag()).value(); + BlockVector3 min = clipboard.getMinimumPoint(); + int index = 0; + for (VarIntIterator iter = new VarIntIterator(biomes); iter.hasNext(); index++) { + int nextBiomeId = iter.nextInt(); + BiomeType type = palette.get(nextBiomeId); + BlockVector3 pos = ReaderUtil.decodePositionFromDataIndex(width, length, index); + clipboard.setBiome(min.add(pos), type); + } + } + + @Override + public void close() throws IOException { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java new file mode 100644 index 000000000..4030c2f90 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/SpongeSchematicV3Writer.java @@ -0,0 +1,233 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.block.BaseBlock; +import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import org.enginehub.linbus.stream.LinBinaryIO; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinRootEntry; +import org.enginehub.linbus.tree.LinTagType; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.function.Function; + +/** + * Writes schematic files using the Sponge Schematic Specification (Version 3). + */ +public class SpongeSchematicV3Writer implements ClipboardWriter { + + private static final int CURRENT_VERSION = 3; + + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; + private final DataOutputStream outputStream; + + public SpongeSchematicV3Writer(DataOutputStream outputStream) { + this.outputStream = outputStream; + } + + @Override + public void write(Clipboard clipboard) throws IOException { + //FAWE start - ensure clipboard is flushed in case of using clipboard-on-disk. Maintains allowing of the same code + // between upstream and FAWE + clipboard.flush(); + //FAWE end + LinBinaryIO.write(outputStream, + new LinRootEntry("", LinCompoundTag.builder().put("Schematic", write3(clipboard)).build()) + ); + } + + /** + * Writes a version 3 schematic file. + * + * @param clipboard The clipboard + * @return The schematic map + */ + private LinCompoundTag write3(Clipboard clipboard) { + Region region = clipboard.getRegion(); + BlockVector3 origin = clipboard.getOrigin(); + BlockVector3 min = region.getMinimumPoint(); + BlockVector3 offset = min.subtract(origin); + int width = region.getWidth(); + int height = region.getHeight(); + int length = region.getLength(); + + if (width > MAX_SIZE) { + throw new IllegalArgumentException("Width of region too large for a .schematic"); + } + if (height > MAX_SIZE) { + throw new IllegalArgumentException("Height of region too large for a .schematic"); + } + if (length > MAX_SIZE) { + throw new IllegalArgumentException("Length of region too large for a .schematic"); + } + + LinCompoundTag.Builder schematic = LinCompoundTag.builder(); + schematic.putInt("Version", CURRENT_VERSION); + schematic.putInt("DataVersion", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion() + ); + + LinCompoundTag.Builder metadata = LinCompoundTag.builder(); + metadata.putLong("Date", System.currentTimeMillis()); + + LinCompoundTag.Builder worldEditSection = LinCompoundTag.builder(); + worldEditSection.putString("Version", WorldEdit.getVersion()); + worldEditSection.putString("EditingPlatform", + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).id() + ); + worldEditSection.putIntArray("Origin", new int[]{origin.x(), origin.y(), origin.z()}); + + LinCompoundTag.Builder platformsSection = LinCompoundTag.builder(); + for (Platform platform : WorldEdit.getInstance().getPlatformManager().getPlatforms()) { + platformsSection.put(platform.id(), LinCompoundTag + .builder() + .putString("Name", platform.getPlatformName()) + .putString("Version", platform.getPlatformVersion()) + .build()); + } + worldEditSection.put("Platforms", platformsSection.build()); + + metadata.put("WorldEdit", worldEditSection.build()); + + schematic.put("Metadata", metadata.build()); + + schematic.putShort("Width", (short) width); + schematic.putShort("Height", (short) height); + schematic.putShort("Length", (short) length); + + schematic.putIntArray("Offset", new int[]{offset.x(), offset.y(), offset.z(),}); + + schematic.put("Blocks", encodeBlocks(clipboard)); + + if (clipboard.hasBiomes()) { + schematic.put("Biomes", encodeBiomes(clipboard)); + } + + if (!clipboard.getEntities().isEmpty()) { + LinListTag value = WriterUtil.encodeEntities(clipboard, true); + if (value != null) { + schematic.put("Entities", value); + } + } + + return schematic.build(); + } + + private static final class PaletteMap { + + private final Object2IntMap contents = new Object2IntLinkedOpenHashMap<>(); + private int nextId = 0; + + public int getId(String key) { + int result = contents.getOrDefault(key, -1); + if (result != -1) { + return result; + } + int newValue = nextId; + nextId++; + contents.put(key, newValue); + return newValue; + } + + public LinCompoundTag toNbt() { + LinCompoundTag.Builder result = LinCompoundTag.builder(); + Object2IntMaps.fastForEach(contents, e -> result.putInt(e.getKey(), e.getIntValue())); + return result.build(); + } + + } + + private LinCompoundTag encodeBlocks(Clipboard clipboard) { + LinListTag.Builder blockEntities = LinListTag.builder(LinTagType.compoundTag()); + LinCompoundTag.Builder result = encodePalettedData(clipboard, point -> { + BaseBlock block = clipboard.getFullBlock(point); + // Also compute block entity side-effect here + LinCompoundTag nbt = block.getNbt(); + if (nbt != null) { + LinCompoundTag.Builder builder = LinCompoundTag.builder(); + + builder.putString("Id", block.getNbtId()); + BlockVector3 adjustedPos = point.subtract(clipboard.getMinimumPoint()); + builder.putIntArray("Pos", new int[]{adjustedPos.x(), adjustedPos.y(), adjustedPos.z()}); + builder.put("Data", nbt); + + blockEntities.add(builder.build()); + } + return block.toImmutableState().getAsString(); + }); + + return result.put("BlockEntities", blockEntities.build()).build(); + } + + private LinCompoundTag encodeBiomes(Clipboard clipboard) { + return encodePalettedData(clipboard, point -> clipboard.getBiome(point).id()).build(); + } + + private LinCompoundTag.Builder encodePalettedData( + Clipboard clipboard, Function keyFunction + ) { + BlockVector3 min = clipboard.getMinimumPoint(); + int width = clipboard.getRegion().getWidth(); + int height = clipboard.getRegion().getHeight(); + int length = clipboard.getRegion().getLength(); + + PaletteMap paletteMap = new PaletteMap(); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * height * length); + + for (int y = 0; y < height; y++) { + for (int z = 0; z < length; z++) { + for (int x = 0; x < width; x++) { + BlockVector3 point = min.add(x, y, z); + + String key = keyFunction.apply(point); + int id = paletteMap.getId(key); + + while ((id & -128) != 0) { + buffer.write(id & 127 | 128); + id >>>= 7; + } + buffer.write(id); + } + } + } + + return LinCompoundTag.builder().put("Palette", paletteMap.toNbt()).putByteArray("Data", buffer.toByteArray()); + } + + @Override + public void close() throws IOException { + outputStream.close(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java new file mode 100644 index 000000000..35f6d58bc --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/VersionedDataFixer.java @@ -0,0 +1,47 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + + +import com.sk89q.worldedit.world.DataFixer; + +import javax.annotation.Nullable; + +public final class VersionedDataFixer { //FAWE - public + private final int dataVersion; + @Nullable + private final DataFixer fixer; + + public VersionedDataFixer(int dataVersion, @Nullable DataFixer fixer) { //FAWE - public + this.dataVersion = dataVersion; + this.fixer = fixer; + } + + public boolean isActive() { + return fixer != null; + } + + public T fixUp(DataFixer.FixType type, T original) { + if (!isActive()) { + return original; + } + return fixer.fixUp(type, original, dataVersion); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java new file mode 100644 index 000000000..17ff5004d --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/WriterUtil.java @@ -0,0 +1,91 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.extent.clipboard.io.sponge; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Location; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; + +class WriterUtil { + + static LinListTag encodeEntities(Clipboard clipboard, boolean positionIsRelative) { + LinListTag.Builder entities = LinListTag.builder(LinTagType.compoundTag()); + for (Entity entity : clipboard.getEntities()) { + LinCompoundTag encoded = encodeEntity(clipboard, positionIsRelative, entity); + if (encoded != null) { + entities.add(encoded); + } + } + var result = entities.build(); + if (result.value().isEmpty()) { + return null; + } + return result; + } + + private static LinCompoundTag encodeEntity(Clipboard clipboard, boolean positionIsRelative, Entity e) { + BaseEntity state = e.getState(); + if (state == null) { + return null; + } + LinCompoundTag.Builder fullTagBuilder = LinCompoundTag.builder(); + LinCompoundTag.Builder dataTagBuilder = LinCompoundTag.builder(); + LinCompoundTag rawData = state.getNbt(); + if (rawData != null) { + dataTagBuilder.putAll(rawData.value()); + dataTagBuilder.remove("id"); + } + final Location location = e.getLocation(); + Vector3 pos = location.toVector(); + dataTagBuilder.put("Rotation", encodeRotation(location)); + if (positionIsRelative) { + pos = pos.subtract(clipboard.getMinimumPoint().toVector3()); + + fullTagBuilder.put("Data", dataTagBuilder.build()); + } else { + fullTagBuilder.putAll(dataTagBuilder.build().value()); + } + fullTagBuilder.putString("Id", state.getType().id()); + fullTagBuilder.put("Pos", encodeVector(pos)); + + return fullTagBuilder.build(); + } + + static LinListTag encodeVector(Vector3 vector) { + return LinListTag.builder(LinTagType.doubleTag()).add(LinDoubleTag.of(vector.x())).add(LinDoubleTag.of(vector.y())).add( + LinDoubleTag.of(vector.z())).build(); + } + + static LinListTag encodeRotation(Location location) { + return LinListTag + .builder(LinTagType.floatTag()) + .add(LinFloatTag.of(location.getYaw())) + .add(LinFloatTag.of(location.getPitch())) + .build(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java new file mode 100644 index 000000000..930ae5efb --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/sponge/package-info.java @@ -0,0 +1,26 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * This package is internal, containing implementation details of the Sponge Schematic + * Specification. Use the {@link com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats} or + * {@link com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat} classes to + * acquire readers and writers instead. + */ +package com.sk89q.worldedit.extent.clipboard.io.sponge; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index 5f434cf9b..519463760 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -401,7 +401,7 @@ public class BlockTransformExtent extends ResettableExtent { ); if (newDirection != null) { - Map values = new HashMap<>(tag.getValue()); + Map> values = new HashMap<>(tag.getValue()); values.put("Rot", new ByteTag((byte) MCDirections.toRotation(newDirection))); tag = new CompoundTag(values); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java index 88cf4fc6f..b2670113a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java @@ -26,9 +26,9 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Collection; @@ -115,9 +115,7 @@ public class SurvivalModeExtent extends AbstractDelegateExtent { } else { // Can't be an inlined check due to inconsistent generic return type if (stripNbt) { - //FAWE start - Use CompoundBinaryTag - return super.setBlock(location, block.toBaseBlock((CompoundBinaryTag) null)); - //FAWE end + return super.setBlock(location, block.toBaseBlock((LinCompoundTag) null)); } else { return super.setBlock(location, block); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java index 093a7737f..e4b390797 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -28,10 +28,9 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction.Flag; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.NumberBinaryTag; import com.sk89q.worldedit.world.block.BaseBlock; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import static com.google.common.base.Preconditions.checkNotNull; @@ -88,14 +87,13 @@ public class ExtentBlockCopy implements RegionFunction { * @return a new state or the existing one */ private BaseBlock transformNbtData(BaseBlock state) { - //FAWE start - Replace CompoundTag with CompoundBinaryTag - CompoundBinaryTag tag = state.getNbt(); + LinCompoundTag tag = state.getNbt(); if (tag != null) { // Handle blocks which store their rotation in NBT - BinaryTag rotTag = tag.get("Rot"); - if (rotTag instanceof NumberBinaryTag) { - int rot = ((NumberBinaryTag) rotTag).intValue(); + LinTag rotTag = tag.value().get("Rot"); + if (rotTag.value() instanceof Number number) { + int rot = number.intValue(); Direction direction = MCDirections.fromRotation(rot); @@ -105,8 +103,9 @@ public class ExtentBlockCopy implements RegionFunction { if (newDirection != null) { return state.toBaseBlock( - tag.putByte("Rot", (byte) MCDirections.toRotation(newDirection)) - //FAWE end + tag.toBuilder() + .putByte("Rot", (byte) MCDirections.toRotation(newDirection)) + .build() ); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java index 1106899f8..4bdbddb4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BiomeChange3D.java @@ -56,7 +56,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType * @return the position * @deprecated Use {@link #position()}. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BlockVector3 getPosition() { return position; } @@ -67,7 +67,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType * @return the previous biome * @deprecated Use {@link #previous()}. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BiomeType getPrevious() { return previous; } @@ -78,7 +78,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType * @return the current biome * @deprecated Use {@link #current()}. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BiomeType getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java index 16fc50e0d..ecde7967f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/change/BlockChange.java @@ -71,7 +71,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c * @return the position * @deprecated use {@link #position()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BlockVector3 getPosition() { return position; } @@ -82,7 +82,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c * @return the previous block * @deprecated use {@link #previous()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BaseBlock getPrevious() { return previous; } @@ -93,7 +93,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c * @return the current block * @deprecated use {@link #current()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BaseBlock getCurrent() { return current; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java index b4ab9adc1..750324569 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/ChangeSet.java @@ -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 = "2.11.1") 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 2.11.1 + */ + default long longSize() { + return size(); + } + /** * Close the changeset. */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java index b07f3f61d..b3b3b5df8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.internal.command.exception; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; +import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException; import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.internal.exception.FaweException; import com.google.common.collect.ImmutableList; @@ -146,6 +147,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { public void convert(RadiusLimitException e) throws CommandException { throw newCommandException(Caption.of("fawe.error.limit.max-radius", TextComponent.of(e.getMaxRadius())), e); } + + @ExceptionMatch + public void convert(OutsideWorldBoundsException e) throws CommandException { + throw newCommandException(Caption.of("fawe.cancel.reason.world.limit", TextComponent.of(e.y())), e); + } //FAWE end @ExceptionMatch diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java index c30f6fa4d..49fac779a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -29,9 +29,9 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -135,9 +135,6 @@ public class ServerCUIHandler { Math.min(Math.min(player.getWorld().getMaxY(), posY + MAX_DISTANCE), posY + 3) ); - //FAWE start - CBT > Map - CompoundBinaryTag.Builder structureTag = CompoundBinaryTag.builder(); - posX -= x; posY -= y; posZ -= z; @@ -147,7 +144,7 @@ public class ServerCUIHandler { return null; } - //FAWE start - see comment of CBT + LinCompoundTag.Builder structureTag = LinCompoundTag.builder(); structureTag.putString("name", "worldedit:" + player.getName()); structureTag.putString("author", player.getName()); structureTag.putString("metadata", ""); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index 0934627b9..75fae8ca2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -68,7 +68,7 @@ public abstract class AbstractFactory { * @param worldEdit the WorldEdit instance * @param defaultParser the parser to fall back to * @param richParser the rich parser - * @since TODO + * @since 2.11.0 */ protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser, FaweParser richParser) { checkNotNull(worldEdit); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java new file mode 100644 index 000000000..ac91c8365 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/VarIntIterator.java @@ -0,0 +1,81 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.internal.util; + +import it.unimi.dsi.fastutil.ints.IntIterator; + +import java.util.NoSuchElementException; +import java.util.PrimitiveIterator; + +/** + * Simple class to transform a {@code byte[]} into an iterator of the VarInts encoded in it. + */ +public class VarIntIterator implements PrimitiveIterator.OfInt { + + private final byte[] source; + private int index; + private boolean hasNextInt; + private int nextInt; + + public VarIntIterator(byte[] source) { + this.source = source; + } + + @Override + public boolean hasNext() { + if (hasNextInt) { + return true; + } + if (index >= source.length) { + return false; + } + + nextInt = readNextInt(); + return hasNextInt = true; + } + + private int readNextInt() { + int value = 0; + for (int bitsRead = 0; ; bitsRead += 7) { + if (index >= source.length) { + throw new IllegalStateException("Ran out of bytes while reading VarInt (probably corrupted data)"); + } + byte next = source[index]; + index++; + value |= (next & 0x7F) << bitsRead; + if (bitsRead > 7 * 5) { + throw new IllegalStateException("VarInt too big (probably corrupted data)"); + } + if ((next & 0x80) == 0) { + break; + } + } + return value; + } + + @Override + public int nextInt() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + hasNextInt = false; + return nextInt; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java index aa90cb816..097db6964 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/wna/WorldNativeAccess.java @@ -19,17 +19,14 @@ package com.sk89q.worldedit.internal.wna; -import com.google.common.collect.ImmutableMap; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -68,17 +65,15 @@ public interface WorldNativeAccess { // Create the TileEntity if (successful || old == newState) { - if (block instanceof BaseBlock) { - BaseBlock baseBlock = (BaseBlock) block; - //FAWE start - use CompoundBinaryTag over CompoundTag - CompoundBinaryTag tag = baseBlock.getNbt(); + if (block instanceof BaseBlock baseBlock) { + LinCompoundTag tag = baseBlock.getNbt(); if (tag != null) { - tag = tag.put(ImmutableMap.of( - "id", StringBinaryTag.of(baseBlock.getNbtId()), - "x", IntBinaryTag.of(position.x()), - "y", IntBinaryTag.of(position.y()), - "z", IntBinaryTag.of(position.z()) - )); + tag = tag.toBuilder() + .putString("id", baseBlock.getNbtId()) + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()) + .build(); // update if TE changed as well successful = updateTileEntity(pos, tag); @@ -143,7 +138,7 @@ public interface WorldNativeAccess { void updateLightingForBlock(NP position); - boolean updateTileEntity(NP position, CompoundBinaryTag tag); + boolean updateTileEntity(NP position, LinCompoundTag tag); void notifyBlockUpdate(NC chunk, NP position, NBS oldState, NBS newState); @@ -151,7 +146,9 @@ public interface WorldNativeAccess { void markBlockChanged(NC chunk, NP position); - void notifyNeighbors(NP pos, NBS oldState, NBS newState); + void notifyNeighbors(NP pos, NBS oldState, NBS newState);; + + void updateBlock(NP pos, NBS oldState, NBS newState); void updateNeighbors(NP pos, NBS oldState, NBS newState, int recursionLimit); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java index baed5ffde..7db9cd7e2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java @@ -122,7 +122,7 @@ public class BlockVector2 { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public int x() { return x; @@ -134,7 +134,7 @@ public class BlockVector2 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getX() { return x; } @@ -145,7 +145,7 @@ public class BlockVector2 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockX() { return x; } @@ -164,7 +164,7 @@ public class BlockVector2 { * Get the Z coordinate. * * @return the z coordinate - * @since TODO + * @since 2.11.0 */ public int z() { return z; @@ -176,7 +176,7 @@ public class BlockVector2 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getZ() { return z; } @@ -187,7 +187,7 @@ public class BlockVector2 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockZ() { return z; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index 3d239b352..ee2789a33 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -174,7 +174,7 @@ public abstract class BlockVector3 { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public abstract int x(); //FAWE end @@ -185,7 +185,7 @@ public abstract class BlockVector3 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getX() { return this.x(); //FAWE - access abstract getter instead of local field } @@ -196,7 +196,7 @@ public abstract class BlockVector3 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockX() { return this.x(); //FAWE - access abstract getter instead of local field } @@ -219,7 +219,7 @@ public abstract class BlockVector3 { * Get the Y coordinate. * * @return the y coordinate - * @since TODO + * @since 2.11.0 */ public abstract int y(); //FAWE end @@ -230,7 +230,7 @@ public abstract class BlockVector3 { * @return the y coordinate * @deprecated use {@link #y()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getY() { return this.y(); //FAWE - access abstract getter instead of local field } @@ -241,7 +241,7 @@ public abstract class BlockVector3 { * @return the y coordinate * @deprecated use {@link #y()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockY() { return this.y(); //FAWE - access abstract getter instead of local field } @@ -263,7 +263,7 @@ public abstract class BlockVector3 { * Get the Z coordinate. * * @return the Z coordinate - * @since TODO + * @since 2.11.0 */ public abstract int z(); //FAWE end @@ -274,7 +274,7 @@ public abstract class BlockVector3 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getZ() { return this.z(); //FAWE - access abstract getter instead of local field } @@ -285,7 +285,7 @@ public abstract class BlockVector3 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public int getBlockZ() { return this.z(); //FAWE - access abstract getter instead of local field } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java index 9d08676f9..089ed62ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector2.java @@ -57,7 +57,7 @@ public record Vector2(double x, double z) { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getX() { return x; } @@ -66,7 +66,7 @@ public record Vector2(double x, double z) { * Get the X coordinate, aligned to the block grid. * * @return the block-aligned x coordinate - * @since TODO + * @since 2.11.0 */ public int blockX() { return MathMan.roundInt(x); @@ -86,7 +86,7 @@ public record Vector2(double x, double z) { * Get the Z coordinate, aligned to the block grid. * * @return the block-aligned z coordinate - * @since TODO + * @since 2.11.0 */ public int blockZ() { return MathMan.roundInt(z); @@ -98,7 +98,7 @@ public record Vector2(double x, double z) { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getZ() { return z; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java index dd2a404fb..1f22bab53 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 @@ -164,7 +164,7 @@ public abstract class Vector3 { * Get the X coordinate. * * @return the x coordinate - * @since TODO + * @since 2.11.0 */ public abstract double x(); @@ -183,7 +183,7 @@ public abstract class Vector3 { * @return the x coordinate * @deprecated use {@link #x()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getX() { return this.x(); } @@ -205,7 +205,7 @@ public abstract class Vector3 { * Get the Y coordinate. * * @return the y coordinate - * @since TODO + * @since 2.11.0 */ public abstract double y(); @@ -224,7 +224,7 @@ public abstract class Vector3 { * @return the y coordinate * @deprecated use {@link #y()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getY() { return this.y(); } @@ -245,7 +245,7 @@ public abstract class Vector3 { * Get the Z coordinate. * * @return the z coordinate - * @since TODO + * @since 2.11.0 */ public abstract double z(); @@ -264,7 +264,7 @@ public abstract class Vector3 { * @return the z coordinate * @deprecated use {@link #z()} instead */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public double getZ() { return this.z(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java index 92a859652..e18499c04 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java @@ -23,17 +23,25 @@ import com.fastasyncworldedit.core.registry.RegistryItem; import java.util.HashSet; import java.util.Set; +import java.util.function.Supplier; //FAWE start - implements RegistryItem public abstract class Category implements RegistryItem, Keyed { //FAWE end private final Set set = new HashSet<>(); + private final Supplier> supplier; protected final String id; private boolean empty = true; - protected Category(final String id) { + public Category(final String id) { this.id = id; + this.supplier = null; + } + + public Category(String id, Supplier> contentSupplier) { + this.id = id; + this.supplier = contentSupplier; } @Override @@ -43,7 +51,11 @@ public abstract class Category implements RegistryItem, Keyed { public final Set getAll() { if (this.empty) { - this.set.addAll(this.load()); + if (supplier != null) { + this.set.addAll(this.supplier.get()); + } else { + this.set.addAll(this.load()); + } this.empty = false; } return this.set; @@ -62,6 +74,14 @@ public abstract class Category implements RegistryItem, Keyed { return internalId; } + /** + * Loads the contents of this category from the platform. + * + * @return The loaded contents of the category + * @deprecated The load system will be removed in a future WorldEdit release. The registries should be populated by + * the platforms via the supplier constructor. + */ + @Deprecated protected abstract Set load(); //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java index b31e62d7f..dfce5f833 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -33,7 +33,7 @@ public interface Keyed { * @return an id * @deprecated Use {@link #id()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") default String getId() { return id(); } @@ -43,7 +43,7 @@ public interface Keyed { * may have additional restrictions. * * @return an id - * @since TODO + * @since 2.11.0 */ @NonAbstractForCompatibility(delegateName = "getId", delegateParams = {}) default String id() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java index ff946e458..042f435e0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/LocatedBlock.java @@ -40,7 +40,7 @@ public record LocatedBlock(BlockVector3 location, BaseBlock block) { * @return The location * @deprecated This class is now a record. Use {@link #location()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BlockVector3 getLocation() { return this.location; } @@ -51,7 +51,7 @@ public record LocatedBlock(BlockVector3 location, BaseBlock block) { * @return The block * @deprecated This class is now a record. Use {@link #block()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") public BaseBlock getBlock() { return this.block; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java index 5b69ddff0..414190a98 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java @@ -20,8 +20,7 @@ package com.sk89q.worldedit.world; import com.google.common.annotations.Beta; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; /** * This entire class is subject to heavy changes. Do not use this as API. @@ -41,15 +40,12 @@ public interface DataFixer { private FixTypes() { } - //FAWE start - BinaryTag - public static FixType CHUNK = new FixType<>(); - public static FixType BLOCK_ENTITY = new FixType<>(); - public static FixType ENTITY = new FixType<>(); - //FAWE end - public static FixType BLOCK_STATE = new FixType<>(); - public static FixType BIOME = new FixType<>(); - public static FixType ITEM_TYPE = new FixType<>(); - + public static final FixType CHUNK = new FixType<>(); + public static final FixType BLOCK_ENTITY = new FixType<>(); + public static final FixType ENTITY = new FixType<>(); + public static final FixType BLOCK_STATE = new FixType<>(); + public static final FixType BIOME = new FixType<>(); + public static final FixType ITEM_TYPE = new FixType<>(); } default T fixUp(FixType type, T original) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java index a85868685..e1c5d6de0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NbtValued.java @@ -23,7 +23,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.internal.util.DeprecationUtil; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nullable; @@ -66,7 +66,7 @@ public interface NbtValued { @Deprecated @Nullable default CompoundTag getNbtData() { - CompoundBinaryTag tag = getNbt(); + LinCompoundTag tag = getNbt(); return tag == null ? null : new CompoundTag(tag); } @@ -78,7 +78,7 @@ public interface NbtValued { */ @Deprecated default void setNbtData(@Nullable CompoundTag nbtData) { - setNbtReference(nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag)); + setNbtReference(nbtData == null ? null : LazyReference.from(nbtData::toLinTag)); } /** @@ -96,11 +96,12 @@ public interface NbtValued { delegateParams = {} ) @Nullable - default LazyReference getNbtReference() { + default LazyReference getNbtReference() { DeprecationUtil.checkDelegatingOverride(getClass()); + @SuppressWarnings("deprecation") CompoundTag nbtData = getNbtData(); - return nbtData == null ? null : LazyReference.from(nbtData::asBinaryTag); + return nbtData == null ? null : LazyReference.from(nbtData::toLinTag); } /** @@ -109,8 +110,8 @@ public interface NbtValued { * @return compound tag, or null */ @Nullable - default CompoundBinaryTag getNbt() { - LazyReference ref = getNbtReference(); + default LinCompoundTag getNbt() { + LazyReference ref = getNbtReference(); return ref == null ? null : ref.getValue(); } @@ -119,11 +120,12 @@ public interface NbtValued { * * @param nbtData NBT data, or null if no data */ + @SuppressWarnings("deprecation") @NonAbstractForCompatibility( delegateName = "setNbtData", delegateParams = {CompoundTag.class} ) - default void setNbtReference(@Nullable LazyReference nbtData) { + default void setNbtReference(@Nullable LazyReference nbtData) { DeprecationUtil.checkDelegatingOverride(getClass()); setNbtData(nbtData == null ? null : new CompoundTag(nbtData.getValue())); @@ -134,7 +136,7 @@ public interface NbtValued { * * @param nbtData NBT data, or null if no data */ - default void setNbt(@Nullable CompoundBinaryTag nbtData) { + default void setNbt(@Nullable LinCompoundTag nbtData) { setNbtReference(nbtData == null ? null : LazyReference.computed(nbtData)); } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java new file mode 100644 index 000000000..ee1cca1c0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategories.java @@ -0,0 +1,112 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.biome; + +/** + * Stores a list of common {@link BiomeCategory BiomeCategories}. + * + * @see BiomeCategory + */ +@SuppressWarnings("unused") +public final class BiomeCategories { + public static final BiomeCategory ALLOWS_SURFACE_SLIME_SPAWNS = get("minecraft:allows_surface_slime_spawns"); + public static final BiomeCategory ALLOWS_TROPICAL_FISH_SPAWNS_AT_ANY_HEIGHT = get("minecraft:allows_tropical_fish_spawns_at_any_height"); + public static final BiomeCategory HAS_CLOSER_WATER_FOG = get("minecraft:has_closer_water_fog"); + public static final BiomeCategory HAS_STRUCTURE_ANCIENT_CITY = get("minecraft:has_structure/ancient_city"); + public static final BiomeCategory HAS_STRUCTURE_BASTION_REMNANT = get("minecraft:has_structure/bastion_remnant"); + public static final BiomeCategory HAS_STRUCTURE_BURIED_TREASURE = get("minecraft:has_structure/buried_treasure"); + public static final BiomeCategory HAS_STRUCTURE_DESERT_PYRAMID = get("minecraft:has_structure/desert_pyramid"); + public static final BiomeCategory HAS_STRUCTURE_END_CITY = get("minecraft:has_structure/end_city"); + public static final BiomeCategory HAS_STRUCTURE_IGLOO = get("minecraft:has_structure/igloo"); + public static final BiomeCategory HAS_STRUCTURE_JUNGLE_TEMPLE = get("minecraft:has_structure/jungle_temple"); + public static final BiomeCategory HAS_STRUCTURE_MINESHAFT = get("minecraft:has_structure/mineshaft"); + public static final BiomeCategory HAS_STRUCTURE_MINESHAFT_MESA = get("minecraft:has_structure/mineshaft_mesa"); + public static final BiomeCategory HAS_STRUCTURE_NETHER_FORTRESS = get("minecraft:has_structure/nether_fortress"); + public static final BiomeCategory HAS_STRUCTURE_NETHER_FOSSIL = get("minecraft:has_structure/nether_fossil"); + public static final BiomeCategory HAS_STRUCTURE_OCEAN_MONUMENT = get("minecraft:has_structure/ocean_monument"); + public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_COLD = get("minecraft:has_structure/ocean_ruin_cold"); + public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_WARM = get("minecraft:has_structure/ocean_ruin_warm"); + public static final BiomeCategory HAS_STRUCTURE_PILLAGER_OUTPOST = get("minecraft:has_structure/pillager_outpost"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_DESERT = get("minecraft:has_structure/ruined_portal_desert"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_JUNGLE = get("minecraft:has_structure/ruined_portal_jungle"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_MOUNTAIN = get("minecraft:has_structure/ruined_portal_mountain"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_NETHER = get("minecraft:has_structure/ruined_portal_nether"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_OCEAN = get("minecraft:has_structure/ruined_portal_ocean"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_STANDARD = get("minecraft:has_structure/ruined_portal_standard"); + public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_SWAMP = get("minecraft:has_structure/ruined_portal_swamp"); + public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK = get("minecraft:has_structure/shipwreck"); + public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK_BEACHED = get("minecraft:has_structure/shipwreck_beached"); + public static final BiomeCategory HAS_STRUCTURE_STRONGHOLD = get("minecraft:has_structure/stronghold"); + public static final BiomeCategory HAS_STRUCTURE_SWAMP_HUT = get("minecraft:has_structure/swamp_hut"); + public static final BiomeCategory HAS_STRUCTURE_TRAIL_RUINS = get("minecraft:has_structure/trail_ruins"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_DESERT = get("minecraft:has_structure/village_desert"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_PLAINS = get("minecraft:has_structure/village_plains"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SAVANNA = get("minecraft:has_structure/village_savanna"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SNOWY = get("minecraft:has_structure/village_snowy"); + public static final BiomeCategory HAS_STRUCTURE_VILLAGE_TAIGA = get("minecraft:has_structure/village_taiga"); + public static final BiomeCategory HAS_STRUCTURE_WOODLAND_MANSION = get("minecraft:has_structure/woodland_mansion"); + public static final BiomeCategory INCREASED_FIRE_BURNOUT = get("minecraft:increased_fire_burnout"); + public static final BiomeCategory IS_BADLANDS = get("minecraft:is_badlands"); + public static final BiomeCategory IS_BEACH = get("minecraft:is_beach"); + public static final BiomeCategory IS_DEEP_OCEAN = get("minecraft:is_deep_ocean"); + public static final BiomeCategory IS_END = get("minecraft:is_end"); + public static final BiomeCategory IS_FOREST = get("minecraft:is_forest"); + public static final BiomeCategory IS_HILL = get("minecraft:is_hill"); + public static final BiomeCategory IS_JUNGLE = get("minecraft:is_jungle"); + public static final BiomeCategory IS_MOUNTAIN = get("minecraft:is_mountain"); + public static final BiomeCategory IS_NETHER = get("minecraft:is_nether"); + public static final BiomeCategory IS_OCEAN = get("minecraft:is_ocean"); + public static final BiomeCategory IS_OVERWORLD = get("minecraft:is_overworld"); + public static final BiomeCategory IS_RIVER = get("minecraft:is_river"); + public static final BiomeCategory IS_SAVANNA = get("minecraft:is_savanna"); + public static final BiomeCategory IS_TAIGA = get("minecraft:is_taiga"); + public static final BiomeCategory MINESHAFT_BLOCKING = get("minecraft:mineshaft_blocking"); + public static final BiomeCategory MORE_FREQUENT_DROWNED_SPAWNS = get("minecraft:more_frequent_drowned_spawns"); + public static final BiomeCategory PLAYS_UNDERWATER_MUSIC = get("minecraft:plays_underwater_music"); + public static final BiomeCategory POLAR_BEARS_SPAWN_ON_ALTERNATE_BLOCKS = get("minecraft:polar_bears_spawn_on_alternate_blocks"); + public static final BiomeCategory PRODUCES_CORALS_FROM_BONEMEAL = get("minecraft:produces_corals_from_bonemeal"); + public static final BiomeCategory REDUCE_WATER_AMBIENT_SPAWNS = get("minecraft:reduce_water_ambient_spawns"); + public static final BiomeCategory REQUIRED_OCEAN_MONUMENT_SURROUNDING = get("minecraft:required_ocean_monument_surrounding"); + public static final BiomeCategory SNOW_GOLEM_MELTS = get("minecraft:snow_golem_melts"); + public static final BiomeCategory SPAWNS_COLD_VARIANT_FROGS = get("minecraft:spawns_cold_variant_frogs"); + public static final BiomeCategory SPAWNS_GOLD_RABBITS = get("minecraft:spawns_gold_rabbits"); + public static final BiomeCategory SPAWNS_SNOW_FOXES = get("minecraft:spawns_snow_foxes"); + public static final BiomeCategory SPAWNS_WARM_VARIANT_FROGS = get("minecraft:spawns_warm_variant_frogs"); + public static final BiomeCategory SPAWNS_WHITE_RABBITS = get("minecraft:spawns_white_rabbits"); + public static final BiomeCategory STRONGHOLD_BIASED_TO = get("minecraft:stronghold_biased_to"); + public static final BiomeCategory WATER_ON_MAP_OUTLINES = get("minecraft:water_on_map_outlines"); + public static final BiomeCategory WITHOUT_PATROL_SPAWNS = get("minecraft:without_patrol_spawns"); + public static final BiomeCategory WITHOUT_WANDERING_TRADER_SPAWNS = get("minecraft:without_wandering_trader_spawns"); + public static final BiomeCategory WITHOUT_ZOMBIE_SIEGES = get("minecraft:without_zombie_sieges"); + + private BiomeCategories() { + } + + /** + * Gets the {@link BiomeCategory} associated with the given id. + */ + public static BiomeCategory get(String id) { + BiomeCategory entry = BiomeCategory.REGISTRY.get(id); + if (entry == null) { + return new BiomeCategory(id); + } + return entry; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java new file mode 100644 index 000000000..a51a86823 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeCategory.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.biome; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +import java.util.Set; +import java.util.function.Supplier; + +/** + * A category of biomes. + */ +public class BiomeCategory extends Category implements Keyed { + + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome tag", true); + + public BiomeCategory(final String id) { + super(id); + } + + public BiomeCategory(final String id, final Supplier> contentSupplier) { + super(id, contentSupplier); + } + + @Override + protected Set load() { + return Set.of(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java index e7ec152a9..d49289093 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -47,7 +47,7 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { * Gets the ID of this biome. * * @return The id - * @since TODO + * @since 2.11.0 */ @Override public String id() { @@ -78,7 +78,7 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern { * @return The id * @deprecated use {@link #id()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @Override public String getId() { return this.id; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 9828c9069..ab93a4016 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.world.block; import com.fastasyncworldedit.core.registry.state.PropertyKey; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.TileEntityBlock; import com.sk89q.worldedit.extent.Extent; @@ -29,13 +28,13 @@ import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.TagStringIO; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.LegacyMapper; +import org.enginehub.linbus.format.snbt.LinStringIO; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; -import java.io.IOException; import java.util.Map; import java.util.Objects; @@ -54,7 +53,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { private final BlockState blockState; @Nullable - private final LazyReference nbtData; + private final LazyReference nbtData; //FAWE start @@ -93,7 +92,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { */ @Deprecated public BaseBlock(BlockState state, CompoundTag nbtData) { - this(state, LazyReference.from(checkNotNull(nbtData)::asBinaryTag)); + this(state, LazyReference.from(checkNotNull(nbtData)::toLinTag)); } //FAWE end @@ -104,7 +103,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { * @param state The block state * @param nbtData NBT data, which must be provided */ - protected BaseBlock(BlockState state, LazyReference nbtData) { + protected BaseBlock(BlockState state, LazyReference nbtData) { checkNotNull(nbtData); this.blockState = state; this.nbtData = nbtData; @@ -165,21 +164,21 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public String getNbtId() { - LazyReference nbtData = this.nbtData; + LazyReference nbtData = this.nbtData; if (nbtData == null) { return ""; } - return nbtData.getValue().getString("id"); + return nbtData.getValue().getTag("id", LinTagType.stringTag()).value(); } @Nullable @Override - public LazyReference getNbtReference() { + public LazyReference getNbtReference() { return this.nbtData; } @Override - public void setNbtReference(@Nullable LazyReference nbtData) { + public void setNbtReference(@Nullable LazyReference nbtData) { throw new UnsupportedOperationException("This class is immutable."); } @@ -244,7 +243,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { } @Override - public BaseBlock toBaseBlock(LazyReference compoundTag) { + public BaseBlock toBaseBlock(LazyReference compoundTag) { if (compoundTag == null) { return this.blockState.toBaseBlock(); } else if (compoundTag == this.nbtData) { @@ -300,20 +299,20 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { @Override public int hashCode() { - return getOrdinal(); + int ret = getOrdinal() << 3; + LinCompoundTag nbtData = getNbt(); + if (nbtData != null) { + ret += nbtData.hashCode(); + } + return ret; } //FAWE end @Override public String toString() { String nbtString = ""; - CompoundBinaryTag nbtData = getNbt(); if (nbtData != null) { - try { - nbtString = TagStringIO.get().asString(nbtData); - } catch (IOException e) { - WorldEdit.logger.error("Failed to serialize NBT of Block", e); - } + nbtString = LinStringIO.writeToString(nbtData.getValue()); } return blockState.getAsString() + nbtString; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 713204843..caa8ba919 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -45,8 +45,8 @@ import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.registry.BlockMaterial; +import org.enginehub.linbus.tree.LinCompoundTag; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -420,7 +420,7 @@ public class BlockState implements BlockStateHolder, Pattern { //FAWE end @Override - public BaseBlock toBaseBlock(LazyReference compoundTag) { + public BaseBlock toBaseBlock(LazyReference compoundTag) { if (compoundTag == null) { return toBaseBlock(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java index e40482302..f2ea08b67 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java @@ -30,8 +30,8 @@ import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.registry.BlockMaterial; +import org.enginehub.linbus.tree.LinCompoundTag; import java.util.Locale; import java.util.Map; @@ -158,7 +158,7 @@ public interface BlockStateHolder> extends TileEnt */ @Deprecated default BaseBlock toBaseBlock(CompoundTag compoundTag) { - return toBaseBlock(compoundTag == null ? null : LazyReference.from(compoundTag::asBinaryTag)); + return toBaseBlock(compoundTag == null ? null : LazyReference.from(compoundTag::toLinTag)); } /** @@ -169,11 +169,12 @@ public interface BlockStateHolder> extends TileEnt * This must be overridden by new subclasses. See {@link NonAbstractForCompatibility} * for details */ + @SuppressWarnings("deprecation") @NonAbstractForCompatibility( delegateName = "toBaseBlock", delegateParams = {CompoundTag.class} ) - default BaseBlock toBaseBlock(LazyReference compoundTag) { + default BaseBlock toBaseBlock(LazyReference compoundTag) { DeprecationUtil.checkDelegatingOverride(getClass()); return toBaseBlock(compoundTag == null ? null : new CompoundTag(compoundTag.getValue())); @@ -185,7 +186,7 @@ public interface BlockStateHolder> extends TileEnt * @param compoundTag The NBT Data to apply * @return The BaseBlock */ - default BaseBlock toBaseBlock(CompoundBinaryTag compoundTag) { + default BaseBlock toBaseBlock(LinCompoundTag compoundTag) { return toBaseBlock(compoundTag == null ? null : LazyReference.computed(compoundTag)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java index 5535f4305..8a3c3de89 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk.java @@ -19,21 +19,20 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.HashMap; @@ -41,25 +40,25 @@ import java.util.Map; public class AnvilChunk implements Chunk { - private final CompoundBinaryTag rootTag; + private final LinCompoundTag rootTag; private final byte[][] blocks; private final byte[][] blocksAdd; private final byte[][] data; private final int rootX; private final int rootZ; - private Map tileEntities; + private Map tileEntities; /** * Construct the chunk with a compound tag. * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk(LinCompoundTag)} */ @Deprecated public AnvilChunk(CompoundTag tag) throws DataException { - this(tag.asBinaryTag()); + this(tag.toLinTag()); } /** @@ -68,45 +67,40 @@ public class AnvilChunk implements Chunk { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk(CompoundBinaryTag tag) throws DataException { + public AnvilChunk(LinCompoundTag tag) throws DataException { rootTag = tag; - rootX = NbtUtils.getChildTag(rootTag, "xPos", BinaryTagTypes.INT).value(); - rootZ = NbtUtils.getChildTag(rootTag, "zPos", BinaryTagTypes.INT).value(); + rootX = rootTag.getTag("xPos", LinTagType.intTag()).value(); + rootZ = rootTag.getTag("zPos", LinTagType.intTag()).value(); blocks = new byte[16][16 * 16 * 16]; blocksAdd = new byte[16][16 * 16 * 8]; data = new byte[16][16 * 16 * 8]; - ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", BinaryTagTypes.LIST); + LinListTag> sections = rootTag.getTag("Sections", LinTagType.listTag()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag)) { + for (LinTag rawSectionTag : sections.value()) { + if (!(rawSectionTag instanceof LinCompoundTag sectionTag)) { continue; } - CompoundBinaryTag sectionTag = (CompoundBinaryTag) rawSectionTag; - if (sectionTag.get("Y") == null) { + var sectionYTag = sectionTag.findTag("Y", LinTagType.byteTag()); + if (sectionYTag == null) { continue; // Empty section. } - int y = NbtUtils.getChildTag(sectionTag, "Y", BinaryTagTypes.BYTE).value(); + int y = sectionYTag.value(); if (y < 0 || y >= 16) { continue; } - blocks[y] = NbtUtils.getChildTag(sectionTag, - "Blocks", BinaryTagTypes.BYTE_ARRAY - ).value(); - data[y] = NbtUtils.getChildTag(sectionTag, "Data", - BinaryTagTypes.BYTE_ARRAY - ).value(); + blocks[y] = sectionTag.getTag("Blocks", LinTagType.byteArrayTag()).value(); + data[y] = sectionTag.getTag("Data", LinTagType.byteArrayTag()).value(); // 4096 ID block support - if (sectionTag.get("Add") != null) { - blocksAdd[y] = NbtUtils.getChildTag(sectionTag, - "Add", BinaryTagTypes.BYTE_ARRAY - ).value(); + var addTag = sectionTag.findTag("Add", LinTagType.byteArrayTag()); + if (addTag != null) { + blocksAdd[y] = addTag.value(); } } @@ -144,17 +138,12 @@ public class AnvilChunk implements Chunk { int index = x + (z * 16 + (yindex * 16 * 16)); try { - int addId = 0; - // The block ID is the combination of the Blocks byte array with the // Add byte array. 'Blocks' stores the lowest 8 bits of a block's ID, and // 'Add' stores the highest 4 bits of the ID. The first block is stored // in the lowest nibble in the Add byte array. - if (index % 2 == 0) { - addId = (blocksAdd[section][index >> 1] & 0x0F) << 8; - } else { - addId = (blocksAdd[section][index >> 1] & 0xF0) << 4; - } + byte addByte = blocksAdd[section][index >> 1]; + int addId = (index & 1) == 0 ? (addByte & 0x0F) << 8 : (addByte & 0xF0) << 4; return (blocks[section][index] & 0xFF) + addId; } catch (IndexOutOfBoundsException e) { @@ -175,15 +164,12 @@ public class AnvilChunk implements Chunk { } int index = x + (z * 16 + (yIndex * 16 * 16)); - boolean shift = index % 2 == 0; - index /= 2; + boolean shift = (index & 1) != 0; + index >>= 2; try { - if (!shift) { - return (data[section][index] & 0xF0) >> 4; - } else { - return data[section][index] & 0xF; - } + byte dataByte = data[section][index]; + return shift ? (dataByte & 0xF0) >> 4 : dataByte & 0x0F; } catch (IndexOutOfBoundsException e) { throw new DataException("Chunk does not contain position " + position); } @@ -192,44 +178,40 @@ public class AnvilChunk implements Chunk { /** * Used to load the tile entities. */ - private void populateTileEntities() throws DataException { - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST); + private void populateTileEntities() { + LinListTag tags = rootTag.getTag("TileEntities", LinTagType.listTag()) + .asTypeChecked(LinTagType.compoundTag()); - tileEntities = new HashMap<>(); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; + tileEntities = new HashMap<>(tags.value().size()); + for (LinCompoundTag t : tags.value()) { int x = 0; int y = 0; int z = 0; - CompoundBinaryTag.Builder values = CompoundBinaryTag.builder(); + LinCompoundTag.Builder values = LinCompoundTag.builder(); - for (String key : t.keySet()) { - BinaryTag value = t.get(key); + for (String key : t.value().keySet()) { + LinTag value = t.value().get(key); switch (key) { - case "x": - if (value instanceof IntBinaryTag) { - x = ((IntBinaryTag) value).value(); + case "x" -> { + if (value instanceof LinIntTag v) { + x = v.valueAsInt(); } - break; - case "y": - if (value instanceof IntBinaryTag) { - y = ((IntBinaryTag) value).value(); + } + case "y" -> { + if (value instanceof LinIntTag v) { + y = v.valueAsInt(); } - break; - case "z": - if (value instanceof IntBinaryTag) { - z = ((IntBinaryTag) value).value(); + } + case "z" -> { + if (value instanceof LinIntTag v) { + z = v.valueAsInt(); } - break; - default: - break; + } + default -> { + // Do nothing. + } } values.put(key, value); @@ -250,14 +232,12 @@ public class AnvilChunk implements Chunk { * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } - CompoundBinaryTag values = tileEntities.get(position); - - return values; + return tileEntities.get(position); } @Override @@ -270,7 +250,7 @@ public class AnvilChunk implements Chunk { WorldEdit.logger.warn("Unknown legacy block " + id + ":" + data + " found when loading legacy anvil chunk."); return BlockTypes.AIR.getDefaultState().toBaseBlock(); } - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); if (tileEntity != null) { return state.toBaseBlock(tileEntity); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index a8c2d63c2..9b3d54027 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -19,17 +19,12 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -39,10 +34,14 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,26 +50,28 @@ import java.util.Map; */ public class AnvilChunk13 implements Chunk { - protected final CompoundBinaryTag rootTag; + protected final LinCompoundTag rootTag; + private final BlockState[][] blocks; //FAWE start - biome and entity restore protected BiomeType[] biomes; - //FAWE end - private Map tileEntities; - //FAWE start - biome and entity restore private List entities; //FAWE end + private Map tileEntities; + private final int rootX; + private final int rootZ; + /** * Construct the chunk with a compound tag. * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk13(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk13(LinCompoundTag)} */ @Deprecated public AnvilChunk13(CompoundTag tag) throws DataException { - this(tag.asBinaryTag()); + this(tag.toLinTag()); } /** @@ -79,53 +80,58 @@ public class AnvilChunk13 implements Chunk { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk13(CompoundBinaryTag tag) throws DataException { + public AnvilChunk13(LinCompoundTag tag) throws DataException { rootTag = tag; + rootX = rootTag.getTag("xPos", LinTagType.intTag()).valueAsInt(); + rootZ = rootTag.getTag("zPos", LinTagType.intTag()).valueAsInt(); + blocks = new BlockState[16][]; - ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", BinaryTagTypes.LIST); + LinListTag> sections = rootTag.getTag("Sections", LinTagType.listTag()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag)) { + for (LinTag rawSectionTag : sections.value()) { + if (!(rawSectionTag instanceof LinCompoundTag sectionTag)) { continue; } - CompoundBinaryTag sectionTag = (CompoundBinaryTag) rawSectionTag; - if (sectionTag.get("Y") == null) { + var sectionYTag = sectionTag.findTag("Y", LinTagType.byteTag()); + if (sectionYTag == null) { continue; // Empty section. } - int y = NbtUtils.getChildTag(sectionTag, "Y", BinaryTagTypes.BYTE).value(); + int y = sectionYTag.value(); if (y < 0 || y >= 16) { continue; } // parse palette - ListBinaryTag paletteEntries = sectionTag.getList("Palette", BinaryTagTypes.COMPOUND); - int paletteSize = paletteEntries.size(); + LinListTag paletteEntries = sectionTag.getTag( + "Palette", LinTagType.listTag() + ).asTypeChecked(LinTagType.compoundTag()); + int paletteSize = paletteEntries.value().size(); if (paletteSize == 0) { continue; } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId); - BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + LinCompoundTag paletteEntry = paletteEntries.get(paletteEntryId); + String blockType = paletteEntry.getTag("Name", LinTagType.stringTag()).value(); + BlockType type = BlockTypes.get(blockType); if (type == null) { - throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + throw new InvalidFormatException("Invalid block type: " + blockType); } BlockState blockState = type.getDefaultState(); - if (paletteEntry.get("Properties") != null) { - CompoundBinaryTag properties = NbtUtils.getChildTag(paletteEntry, "Properties", BinaryTagTypes.COMPOUND); + var propertiesTag = paletteEntry.findTag("Properties", LinTagType.compoundTag()); + if (propertiesTag != null) { for (Property property : blockState.getStates().keySet()) { - if (properties.get(property.getName()) != null) { - String value = properties.getString(property.getName()); + var propertyName = propertiesTag.findTag(property.getName(), LinTagType.stringTag()); + if (propertyName != null) { + String value = propertyName.value(); try { blockState = getBlockStateWith(blockState, property, value); } catch (IllegalArgumentException e) { - throw new InvalidFormatException("Invalid block state for " + blockState - .getBlockType() - .id() + ", " + property.getName() + ": " + value); + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().id() + ", " + property.getName() + ": " + value); } } } @@ -134,7 +140,7 @@ public class AnvilChunk13 implements Chunk { } // parse block states - long[] blockStatesSerialized = NbtUtils.getChildTag(sectionTag, "BlockStates", BinaryTagTypes.LONG_ARRAY).value(); + long[] blockStatesSerialized = sectionTag.getTag("BlockStates", LinTagType.longArrayTag()).value(); BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; blocks[y] = chunkSectionBlocks; @@ -143,8 +149,7 @@ public class AnvilChunk13 implements Chunk { } } - protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws - InvalidFormatException { + protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { int paletteBits = 4; while ((1 << paletteBits) < palette.length) { ++paletteBits; @@ -163,7 +168,7 @@ public class AnvilChunk13 implements Chunk { throw new InvalidFormatException("Too short block state table"); } currentSerializedValue = blockStatesSerialized[nextSerializedItem++]; - localBlockId |= (int) ((currentSerializedValue & ((1 << bitsNextLong) - 1)) << remainingBits); + localBlockId |= (int) (currentSerializedValue & ((1L << bitsNextLong) - 1)) << remainingBits; currentSerializedValue >>>= bitsNextLong; remainingBits = 64 - bitsNextLong; } else { @@ -185,27 +190,23 @@ public class AnvilChunk13 implements Chunk { /** * Used to load the tile entities. */ - private void populateTileEntities() throws DataException { - tileEntities = new HashMap<>(); - if (rootTag.get("TileEntities") == null) { - return; + private Map populateTileEntities() { + LinListTag tags = rootTag.findListTag( + "TileEntities", LinTagType.compoundTag() + ); + if (tags == null) { + return ImmutableMap.of(); } - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - int x = ((IntBinaryTag) t.get("x")).value(); - int y = ((IntBinaryTag) t.get("y")).value(); - int z = ((IntBinaryTag) t.get("z")).value(); + var tileEntities = ImmutableMap.builderWithExpectedSize(tags.value().size()); + for (LinCompoundTag tag : tags.value()) { + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntities.put(vec, t); + tileEntities.put(vec, tag); } + return tileEntities.build(); } /** @@ -215,26 +216,21 @@ public class AnvilChunk13 implements Chunk { * * @param position the position * @return the compound tag for that position, which may be null - * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) { if (tileEntities == null) { - populateTileEntities(); + this.tileEntities = populateTileEntities(); } - CompoundBinaryTag values = tileEntities.get(position); - - return values; + return tileEntities.get(position); } @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - //FAWE start - simplified - int x = position.x() & 15; + int x = position.x() - rootX * 16; int y = position.y(); - int z = position.z() & 15; - //FAWE end + int z = position.z() - rootZ * 16; int section = y >> 4; int yIndex = y & 0x0F; @@ -246,15 +242,10 @@ public class AnvilChunk13 implements Chunk { BlockState[] sectionBlocks = blocks[section]; BlockState state = sectionBlocks != null ? sectionBlocks[(yIndex << 8) | (z << 4) | x] : BlockTypes.AIR.getDefaultState(); - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); - if (tileEntity != null) { - return state.toBaseBlock(tileEntity); - } - - return state.toBaseBlock(); - } - //FAWE start - biome and entity restore + return state.toBaseBlock(tileEntity); + } //FAWE start - biome and entity restore @Override public BiomeType getBiome(final BlockVector3 position) throws DataException { @@ -277,21 +268,20 @@ public class AnvilChunk13 implements Chunk { /** * Used to load the biomes. */ - private void populateEntities() throws DataException { + private void populateEntities() { entities = new ArrayList<>(); - if (rootTag.get("Entities") == null) { + LinListTag tags = rootTag.findListTag( + "Entities", LinTagType.compoundTag() + ); + if (tags == null) { return; } - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "Entities", BinaryTagTypes.LIST); - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in Entities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t))); + for (LinCompoundTag tag : tags.value()) { + entities.add(new BaseEntity( + EntityTypes.get(tag.getTag("id", LinTagType.stringTag()).value()), + LazyReference.computed(tag) + )); } } @@ -299,12 +289,13 @@ public class AnvilChunk13 implements Chunk { /** * Used to load the biomes. */ - private void populateBiomes() throws DataException { + private void populateBiomes() { biomes = new BiomeType[256]; - if (rootTag.get("Biomes") == null) { + LinIntArrayTag biomeTag = rootTag.findTag("Biomes", LinTagType.intArrayTag()); + if (biomeTag == null) { return; } - int[] stored = NbtUtils.getChildTag(rootTag, "Biomes", BinaryTagTypes.INT_ARRAY).value(); + int[] stored = biomeTag.value(); for (int i = 0; i < 256; i++) { biomes[i] = BiomeTypes.getLegacy(stored[i]); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java index 60b9d9617..955a6e70a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk15.java @@ -19,14 +19,14 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinTagType; /** * The chunk format for Minecraft 1.15 and newer @@ -38,7 +38,7 @@ public class AnvilChunk15 extends AnvilChunk13 { * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk15(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk15(LinCompoundTag)} */ @Deprecated public AnvilChunk15(CompoundTag tag) throws DataException { @@ -51,7 +51,7 @@ public class AnvilChunk15 extends AnvilChunk13 { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk15(CompoundBinaryTag tag) throws DataException { + public AnvilChunk15(LinCompoundTag tag) throws DataException { super(tag); } @@ -68,10 +68,11 @@ public class AnvilChunk15 extends AnvilChunk13 { private void populateBiomes() throws DataException { biomes = new BiomeType[1024]; - if (rootTag.get("Biomes") == null) { + LinIntArrayTag biomeTag = rootTag.findTag("Biomes", LinTagType.intArrayTag()); + if (biomeTag == null) { return; } - int[] stored = NbtUtils.getChildTag(rootTag, "Biomes", BinaryTagTypes.INT_ARRAY).value(); + int[] stored = biomeTag.value(); for (int i = 0; i < 1024; i++) { biomes[i] = BiomeTypes.getLegacy(stored[i]); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java index 92f7f6caf..ff4c89e65 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk16.java @@ -20,10 +20,10 @@ package com.sk89q.worldedit.world.chunk; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; /** * The chunk format for Minecraft 1.16 and 1.17 @@ -35,7 +35,7 @@ public class AnvilChunk16 extends AnvilChunk15 { * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk16(CompoundBinaryTag)} + * @deprecated Use {@link #AnvilChunk16(LinCompoundTag)} */ @Deprecated public AnvilChunk16(CompoundTag tag) throws DataException { @@ -48,7 +48,7 @@ public class AnvilChunk16 extends AnvilChunk15 { * @param tag the tag to read * @throws DataException on a data error */ - public AnvilChunk16(CompoundBinaryTag tag) throws DataException { + public AnvilChunk16(LinCompoundTag tag) throws DataException { super(tag); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java index 3789f9a79..fbddb66f0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk17.java @@ -20,16 +20,12 @@ package com.sk89q.worldedit.world.chunk; import com.fastasyncworldedit.core.util.NbtUtils; +import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeTypes; @@ -39,10 +35,15 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntArrayTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinStringTag; +import org.enginehub.linbus.tree.LinTag; +import org.enginehub.linbus.tree.LinTagType; import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -52,11 +53,11 @@ import java.util.function.Supplier; */ public class AnvilChunk17 implements Chunk { - private final CompoundBinaryTag rootTag; - private final Supplier entityTagSupplier; + private final LinCompoundTag rootTag; + private final Supplier entityTagSupplier; private BiomeType[] biomes; private BlockState[][] blocks; - private Map tileEntities; + private Map tileEntities; private List entities; // initialise with default values private int minSectionPosition = 0; @@ -68,16 +69,16 @@ public class AnvilChunk17 implements Chunk { * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link #AnvilChunk17(CompoundBinaryTag, Supplier)} + * @deprecated Use {@link #AnvilChunk17(LinCompoundTag, Supplier)} */ @Deprecated public AnvilChunk17(CompoundTag tag, Supplier entitiesTag) throws DataException { - this(tag.asBinaryTag(), () -> { + this(tag.toLinTag(), () -> { CompoundTag compoundTag = entitiesTag.get(); if (compoundTag == null) { return null; } - return compoundTag.asBinaryTag(); + return compoundTag.toLinTag(); }); } @@ -89,20 +90,21 @@ public class AnvilChunk17 implements Chunk { * {@link #getEntities()} is called * @throws DataException on a data error */ - public AnvilChunk17(CompoundBinaryTag tag, Supplier entityTag) throws DataException { + public AnvilChunk17(LinCompoundTag tag, Supplier entityTag) throws DataException { rootTag = tag; entityTagSupplier = entityTag; blocks = new BlockState[16][]; // initialise with default length - ListBinaryTag sections = rootTag.getList("Sections"); + LinListTag> sections = rootTag.getTag("Sections", LinTagType.listTag()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) { + for (LinTag rawSectionTag : sections.value()) { + if (!(rawSectionTag instanceof LinCompoundTag sectionTag)) { continue; } - if (sectionTag.get("Y") == null || sectionTag.get("BlockStates") == null) { + var sectionYTag = sectionTag.findTag("Y", LinTagType.byteTag()); + if (sectionYTag == null) { continue; // Empty section. } @@ -110,30 +112,32 @@ public class AnvilChunk17 implements Chunk { updateSectionIndexRange(y); // parse palette - ListBinaryTag paletteEntries = sectionTag.getList("Palette", BinaryTagTypes.COMPOUND); - int paletteSize = paletteEntries.size(); + LinListTag paletteEntries = sectionTag.getListTag("Palette", LinTagType.compoundTag()); + int paletteSize = paletteEntries.value().size(); if (paletteSize == 0) { continue; } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId); - BlockType type = BlockTypes.get(paletteEntry.getString("Name")); + LinCompoundTag paletteEntry = (LinCompoundTag) paletteEntries.get(paletteEntryId); + BlockType type = BlockTypes.get(paletteEntry.getTag("Name", LinTagType.stringTag()).value()); if (type == null) { - throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); + throw new InvalidFormatException("Invalid block type: " + paletteEntry + .getTag("Name", LinTagType.stringTag()) + .value()); } BlockState blockState = type.getDefaultState(); - if (paletteEntry.get("Properties") != null) { - CompoundBinaryTag properties = NbtUtils.getChildTag(paletteEntry, "Properties", BinaryTagTypes.COMPOUND); + LinCompoundTag properties = paletteEntry.findTag("Properties", LinTagType.compoundTag()); + if (properties != null) { for (Property property : blockState.getStates().keySet()) { - if (properties.get(property.getName()) != null) { - String value = properties.getString(property.getName()); + LinStringTag stringTag = properties.findTag(property.getName(), LinTagType.stringTag()); + if (stringTag != null) { try { - blockState = getBlockStateWith(blockState, property, value); + blockState = getBlockStateWith(blockState, property, stringTag.value()); } catch (IllegalArgumentException e) { throw new InvalidFormatException("Invalid block state for " + blockState .getBlockType() - .id() + ", " + property.getName() + ": " + value); + .id() + ", " + property.getName() + ": " + stringTag.value()); } } } @@ -142,7 +146,7 @@ public class AnvilChunk17 implements Chunk { } // parse block states - long[] blockStatesSerialized = sectionTag.getLongArray("BlockStates"); + long[] blockStatesSerialized = sectionTag.getTag("BlockStates", LinTagType.longArrayTag()).value(); BlockState[] chunkSectionBlocks = new BlockState[4096]; blocks[y - minSectionPosition] = chunkSectionBlocks; @@ -191,27 +195,24 @@ public class AnvilChunk17 implements Chunk { /** * Used to load the tile entities. */ - private void populateTileEntities() throws DataException { - tileEntities = new HashMap<>(); - if (rootTag.get("TileEntities") == null) { + private void populateTileEntities() { + LinListTag tags = rootTag.findListTag( + "TileEntities", LinTagType.compoundTag() + ); + if (tags == null) { + tileEntities = ImmutableMap.of(); return; } - ListBinaryTag tags = rootTag.getList("TileEntities"); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - int x = ((IntBinaryTag) t.get("x")).value(); - int y = ((IntBinaryTag) t.get("y")).value(); - int z = ((IntBinaryTag) t.get("z")).value(); + var tileEntitiesBuilder = ImmutableMap.builderWithExpectedSize(tags.value().size()); + for (LinCompoundTag tag : tags.value()) { + int x = tag.getTag("x", LinTagType.intTag()).valueAsInt(); + int y = tag.getTag("y", LinTagType.intTag()).valueAsInt(); + int z = tag.getTag("z", LinTagType.intTag()).valueAsInt(); BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntities.put(vec, t); + tileEntities.put(vec, tag); } + tileEntities = tileEntitiesBuilder.build(); } /** @@ -224,7 +225,7 @@ public class AnvilChunk17 implements Chunk { * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } @@ -248,7 +249,7 @@ public class AnvilChunk17 implements Chunk { BlockState[] sectionBlocks = blocks[section - minSectionPosition]; BlockState state = sectionBlocks != null ? sectionBlocks[(yIndex << 8) | (z << 4) | x] : BlockTypes.AIR.getDefaultState(); - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); if (tileEntity != null) { return state.toBaseBlock(tileEntity); @@ -270,10 +271,11 @@ public class AnvilChunk17 implements Chunk { private void populateBiomes() throws DataException { biomes = new BiomeType[64 * blocks.length]; - if (rootTag.get("Biomes") == null) { + LinIntArrayTag biomeTag = rootTag.findTag("Biomes", LinTagType.intArrayTag()); + if (biomeTag == null) { return; } - int[] stored = rootTag.getIntArray("Biomes"); + int[] stored = biomeTag.value(); for (int i = 0; i < 1024; i++) { biomes[i] = BiomeTypes.getLegacy(stored[i]); } @@ -290,22 +292,21 @@ public class AnvilChunk17 implements Chunk { /** * Used to load the biomes. */ - private void populateEntities() throws DataException { + private void populateEntities() { entities = new ArrayList<>(); - CompoundBinaryTag entityTag; - if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) { + LinListTag tags = rootTag.findListTag( + "Entities", LinTagType.compoundTag() + ); + if (tags == null) { return; } - ListBinaryTag tags = entityTag.getList("Entities"); - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in Entities"); - } + for (LinCompoundTag tag : tags.value()) { - CompoundBinaryTag t = (CompoundBinaryTag) tag; - - entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t))); + entities.add(new BaseEntity( + EntityTypes.get(tag.getTag("id", LinTagType.stringTag()).value()), + LazyReference.computed(tag) + )); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java index 1e36938c4..c5736bfd5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -19,134 +19,93 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongArrayTag; +import com.sk89q.jnbt.NBTUtils; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; -import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; /** * The chunk format for Minecraft 1.18 and newer */ public class AnvilChunk18 implements Chunk { - //FAWE start - CBT - private final CompoundBinaryTag rootTag; - //FAWE end + private final CompoundTag rootTag; private final Int2ObjectOpenHashMap blocks; - //FAWE start - entity and biome restore - private final int sectionCount; - private final Supplier entityTagSupplier; - private Int2ObjectOpenHashMap biomes = null; - private List entities; - private Map tileEntities; - //FAWE end + private final int rootX; + private final int rootZ; + private Map>> tileEntities; /** * Construct the chunk with a compound tag. * * @param tag the tag to read * @throws DataException on a data error - * @deprecated Use {@link AnvilChunk18#AnvilChunk18(CompoundBinaryTag, Supplier)} */ - @Deprecated public AnvilChunk18(CompoundTag tag) throws DataException { - //FAWE start - CBT - this(tag.asBinaryTag(), () -> null); - } - - /** - * Construct the chunk with a compound tag. - * - * @param tag the tag to read - * @throws DataException on a data error - * @deprecated Use {@link AnvilChunk18#AnvilChunk18(CompoundBinaryTag, Supplier)} - * @since 2.1.0 - */ - @Deprecated - public AnvilChunk18(CompoundTag tag, Supplier entitiesTag) throws DataException { - //FAWE start - CBT - this(tag.asBinaryTag(), () -> { - CompoundTag compoundTag = entitiesTag.get(); - return compoundTag == null ? null : compoundTag.asBinaryTag(); - }); - } - - /** - * Construct the chunk with a compound tag. - * - * @param tag the tag to read - * @throws DataException on a data error - * @since 2.1.0 - */ - public AnvilChunk18(CompoundBinaryTag tag, Supplier entityTag) throws DataException { - //FAWE end rootTag = tag; - entityTagSupplier = entityTag; - //FAWE start - CBT - ListBinaryTag sections = rootTag.getList("sections"); - this.sectionCount = sections.size(); + rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue(); + rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue(); + List sections = NBTUtils.getChildTag(rootTag.getValue(), "sections", ListTag.class).getValue(); blocks = new Int2ObjectOpenHashMap<>(sections.size()); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) { + for (Tag rawSectionTag : sections) { + if (!(rawSectionTag instanceof CompoundTag)) { continue; } - int y = NbtUtils.getInt(sectionTag, "Y"); // sometimes a byte, sometimes an int + CompoundTag sectionTag = (CompoundTag) rawSectionTag; + Object yValue = sectionTag.getValue().get("Y").getValue(); // sometimes a byte, sometimes an int + if (!(yValue instanceof Number)) { + throw new InvalidFormatException("Y is not numeric: " + yValue); + } + int y = ((Number) yValue).intValue(); - BinaryTag rawBlockStatesTag = sectionTag.get("block_states"); // null for sections outside of the world limits - if (rawBlockStatesTag instanceof CompoundBinaryTag blockStatesTag) { + Tag rawBlockStatesTag = sectionTag.getValue().get("block_states"); // null for sections outside of the world limits + if (rawBlockStatesTag instanceof CompoundTag) { + CompoundTag blockStatesTag = (CompoundTag) rawBlockStatesTag; // parse palette - ListBinaryTag paletteEntries = blockStatesTag.getList("palette"); + List paletteEntries = blockStatesTag.getList("palette", CompoundTag.class); int paletteSize = paletteEntries.size(); if (paletteSize == 0) { continue; } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId); + CompoundTag paletteEntry = paletteEntries.get(paletteEntryId); BlockType type = BlockTypes.get(paletteEntry.getString("Name")); if (type == null) { throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); } BlockState blockState = type.getDefaultState(); - BinaryTag propertiesTag = paletteEntry.get("Properties"); - if (propertiesTag instanceof CompoundBinaryTag properties) { + if (paletteEntry.containsKey("Properties")) { + CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class); for (Property property : blockState.getStates().keySet()) { - String value; - if (!(value = properties.getString(property.getName())).isEmpty()) { + if (properties.containsKey(property.getName())) { + String value = properties.getString(property.getName()); try { blockState = getBlockStateWith(blockState, property, value); } catch (IllegalArgumentException e) { - throw new InvalidFormatException("Invalid block state for " + blockState - .getBlockType() - .id() + ", " + property.getName() + ": " + value); + throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value); } } } @@ -160,7 +119,7 @@ public class AnvilChunk18 implements Chunk { } // parse block states - long[] blockStatesSerialized = blockStatesTag.getLongArray("data"); + long[] blockStatesSerialized = NBTUtils.getChildTag(blockStatesTag.getValue(), "data", LongArrayTag.class).getValue(); BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16]; blocks.put(y, chunkSectionBlocks); @@ -168,7 +127,6 @@ public class AnvilChunk18 implements Chunk { readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks); } } - //FAWE end } protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException { @@ -190,24 +148,28 @@ public class AnvilChunk18 implements Chunk { * Used to load the tile entities. */ private void populateTileEntities() throws DataException { - //FAWE start - CBT tileEntities = new HashMap<>(); - if (!(rootTag.get("block_entities") instanceof ListBinaryTag tags)) { + if (!rootTag.getValue().containsKey("block_entities")) { return; } - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag t)) { + List tags = NBTUtils.getChildTag(rootTag.getValue(), + "block_entities", ListTag.class).getValue(); + + for (Tag tag : tags) { + if (!(tag instanceof CompoundTag)) { throw new InvalidFormatException("CompoundTag expected in block_entities"); } - int x = t.getInt("x"); - int y = t.getInt("y"); - int z = t.getInt("z"); + CompoundTag t = (CompoundTag) tag; + + Map> values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntities.put(vec, t); + tileEntities.put(vec, values); } - //FAWE end } /** @@ -220,21 +182,24 @@ public class AnvilChunk18 implements Chunk { * @throws DataException thrown if there is a data error */ @Nullable - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { - //FAWE start - CBT + private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } - return tileEntities.get(position); - //FAWE end + Map> values = tileEntities.get(position); + if (values == null) { + return null; + } + + return new CompoundTag(values); } @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - int x = position.x() & 15; - int y = position.y(); - int z = position.z() & 15; + int x = position.getX() - rootX * 16; + int y = position.getY(); + int z = position.getZ() - rootZ * 16; int section = y >> 4; int yIndex = y & 0x0F; @@ -245,7 +210,7 @@ public class AnvilChunk18 implements Chunk { } BlockState state = sectionBlocks[sectionBlocks.length == 1 ? 0 : ((yIndex << 8) | (z << 4) | x)]; - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + CompoundTag tileEntity = getBlockTileEntity(position); if (tileEntity != null) { return state.toBaseBlock(tileEntity); @@ -254,110 +219,4 @@ public class AnvilChunk18 implements Chunk { return state.toBaseBlock(); } - @Override - public BiomeType getBiome(final BlockVector3 position) throws DataException { - if (biomes == null) { - populateBiomes(); - } - int x = (position.x() & 15) >> 2; - int y = (position.y() & 15) >> 2; - int z = (position.z() & 15) >> 2; - int section = position.y() >> 4; - BiomeType[] sectionBiomes = biomes.get(section); - if (sectionBiomes.length == 1) { - return sectionBiomes[0]; - } - return biomes.get(section)[y << 4 | z << 2 | x]; - } - - private void populateBiomes() throws DataException { - biomes = new Int2ObjectOpenHashMap<>(sectionCount); - ListBinaryTag sections = rootTag.getList("sections"); - for (BinaryTag rawSectionTag : sections) { - if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) { - continue; - } - - int y = NbtUtils.getInt(sectionTag, "Y"); // sometimes a byte, sometimes an int - - BinaryTag rawBlockStatesTag = sectionTag.get("biomes"); // null for sections outside of the world limits - if (rawBlockStatesTag instanceof CompoundBinaryTag biomeTypesTag) { - - // parse palette - ListBinaryTag paletteEntries = biomeTypesTag.getList("palette"); - int paletteSize = paletteEntries.size(); - if (paletteSize == 0) { - continue; - } - BiomeType[] palette = new BiomeType[paletteSize]; - for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { - String paletteEntry = paletteEntries.getString(paletteEntryId); - BiomeType type = BiomeType.REGISTRY.get(paletteEntry); - if (type == null) { - throw new InvalidFormatException("Invalid biome type: " + paletteEntry); - } - palette[paletteEntryId] = type; - } - if (paletteSize == 1) { - // the same block everywhere - biomes.put(y, palette); - continue; - } - - // parse block states - long[] biomesSerialized = biomeTypesTag.getLongArray("data"); - if (biomesSerialized.length == 0) { - throw new InvalidFormatException("Biome data not present."); - } - - BiomeType[] chunkSectionBiomes = new BiomeType[64]; - biomes.put(y, chunkSectionBiomes); - - readBiomes(palette, biomesSerialized, chunkSectionBiomes); - } - } - } - - protected void readBiomes(BiomeType[] palette, long[] biomesSerialized, BiomeType[] chunkSectionBiomes) throws - InvalidFormatException { - PackedIntArrayReader reader = new PackedIntArrayReader(biomesSerialized, 64); - for (int biomePos = 0; biomePos < chunkSectionBiomes.length; biomePos++) { - int index = reader.get(biomePos); - if (index >= palette.length) { - throw new InvalidFormatException("Invalid biome table entry: " + index); - } - chunkSectionBiomes[biomePos] = palette[index]; - } - } - - @Override - public List getEntities() throws DataException { - if (entities == null) { - populateEntities(); - } - return entities; - } - - /** - * Used to load the biomes. - */ - private void populateEntities() throws DataException { - entities = new ArrayList<>(); - CompoundBinaryTag entityTag; - if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) { - return; - } - ListBinaryTag tags = NbtUtils.getChildTag(entityTag, "Entities", BinaryTagTypes.LIST); - - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag t)) { - throw new InvalidFormatException("CompoundTag expected in Entities"); - } - - entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t))); - } - - } - - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java index 7edb163e3..783045520 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/OldChunk.java @@ -19,21 +19,19 @@ package com.sk89q.worldedit.world.chunk; -import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.nbt.BinaryTag; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.IntBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinIntTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; import java.util.HashMap; import java.util.Map; @@ -43,24 +41,24 @@ import java.util.Map; */ public class OldChunk implements Chunk { - private final CompoundBinaryTag rootTag; + private final LinCompoundTag rootTag; private final byte[] blocks; private final byte[] data; private final int rootX; private final int rootZ; - private Map tileEntities; + private Map tileEntities; /** * Construct the chunk with a compound tag. * * @param tag the tag * @throws DataException if there is an error getting the chunk data - * @deprecated Use {@link #OldChunk(CompoundBinaryTag)} + * @deprecated Use {@link #OldChunk(LinCompoundTag)} */ @Deprecated public OldChunk(CompoundTag tag) throws DataException { - this(tag.asBinaryTag()); + this(tag.toLinTag()); } /** @@ -69,13 +67,13 @@ public class OldChunk implements Chunk { * @param tag the tag * @throws DataException if there is an error getting the chunk data */ - public OldChunk(CompoundBinaryTag tag) throws DataException { + public OldChunk(LinCompoundTag tag) throws DataException { rootTag = tag; - blocks = NbtUtils.getChildTag(rootTag, "Blocks", BinaryTagTypes.BYTE_ARRAY).value(); - data = NbtUtils.getChildTag(rootTag, "Data", BinaryTagTypes.BYTE_ARRAY).value(); - rootX = NbtUtils.getChildTag(rootTag, "xPos", BinaryTagTypes.INT).value(); - rootZ = NbtUtils.getChildTag(rootTag, "zPos", BinaryTagTypes.INT).value(); + blocks = rootTag.getTag("Blocks", LinTagType.byteArrayTag()).value(); + data = rootTag.getTag("Data", LinTagType.byteArrayTag()).value(); + rootX = rootTag.getTag("xPos", LinTagType.intTag()).value(); + rootZ = rootTag.getTag("zPos", LinTagType.intTag()).value(); int size = 16 * 16 * 128; if (blocks.length != size) { @@ -95,43 +93,39 @@ public class OldChunk implements Chunk { * @throws DataException if there is an error getting the chunk data */ private void populateTileEntities() throws DataException { - ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST); + LinListTag tags = rootTag.getTag("TileEntities", LinTagType.listTag()) + .asTypeChecked(LinTagType.compoundTag()); tileEntities = new HashMap<>(); - for (BinaryTag tag : tags) { - if (!(tag instanceof CompoundBinaryTag)) { - throw new InvalidFormatException("CompoundTag expected in TileEntities"); - } - - CompoundBinaryTag t = (CompoundBinaryTag) tag; - + for (LinCompoundTag t : tags.value()) { int x = 0; int y = 0; int z = 0; - CompoundBinaryTag.Builder values = CompoundBinaryTag.builder(); + LinCompoundTag.Builder values = LinCompoundTag.builder(); - for (String key : t.keySet()) { - BinaryTag value = t.get(key); + for (String key : t.value().keySet()) { + var value = t.value().get(key); switch (key) { - case "x": - if (value instanceof IntBinaryTag) { - x = ((IntBinaryTag) value).value(); + case "x" -> { + if (value instanceof LinIntTag v) { + x = v.valueAsInt(); } - break; - case "y": - if (value instanceof IntBinaryTag) { - y = ((IntBinaryTag) value).value(); + } + case "y" -> { + if (value instanceof LinIntTag v) { + y = v.valueAsInt(); } - break; - case "z": - if (value instanceof IntBinaryTag) { - z = ((IntBinaryTag) value).value(); + } + case "z" -> { + if (value instanceof LinIntTag v) { + z = v.valueAsInt(); } - break; - default: - break; + } + default -> { + // Do nothing. + } } values.put(key, value); @@ -151,13 +145,12 @@ public class OldChunk implements Chunk { * @return a tag * @throws DataException if there is an error getting the chunk data */ - private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException { + private LinCompoundTag getBlockTileEntity(BlockVector3 position) throws DataException { if (tileEntities == null) { populateTileEntities(); } - CompoundBinaryTag values = tileEntities.get(position); - return values; + return tileEntities.get(position); } @Override @@ -197,13 +190,9 @@ public class OldChunk implements Chunk { return BlockTypes.AIR.getDefaultState().toBaseBlock(); } - CompoundBinaryTag tileEntity = getBlockTileEntity(position); + LinCompoundTag tileEntity = getBlockTileEntity(position); - if (tileEntity != null) { - return state.toBaseBlock(tileEntity); - } - - return state.toBaseBlock(); + return state.toBaseBlock(tileEntity); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java index 1faf3bc4c..aba23b636 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -45,7 +45,7 @@ public class EntityType implements RegistryItem, Keyed { * Gets the id of this entity type. * * @return the id - * @since TODO + * @since 2.11.0 */ public String id() { return this.id; @@ -57,7 +57,7 @@ public class EntityType implements RegistryItem, Keyed { * @return the id * @deprecated use {@link #id()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @Override public String getId() { return this.id; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java index 1642ed4e9..1b191f07f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -43,7 +43,7 @@ public class FluidType implements RegistryItem, Keyed { * Gets the ID of this block. * * @return The id - * @since TODO + * @since 2.11.0 */ public String id() { return this.id; @@ -55,7 +55,7 @@ public class FluidType implements RegistryItem, Keyed { * @return The id * @deprecated use {@link #id()} */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") @Override public String getId() { return this.id; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java index db63b53a4..45071859c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/ItemMaterial.java @@ -29,7 +29,7 @@ public interface ItemMaterial { * @return the maximum quantity * @deprecated Use {@link #maxStackSize()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") default int getMaxStackSize() { return maxStackSize(); } @@ -38,7 +38,7 @@ public interface ItemMaterial { * Gets the the maximum quantity of this item that can be in a single stack. * * @return the maximum quantity - * @since TODO + * @since 2.11.0 */ @NonAbstractForCompatibility(delegateName = "getMaxStackSize", delegateParams = {}) default int maxStackSize() { @@ -52,7 +52,7 @@ public interface ItemMaterial { * @return the maximum damage, or 0 if not applicable * @deprecated Use {@link #maxDamage()} instead. */ - @Deprecated(forRemoval = true, since = "TODO") + @Deprecated(forRemoval = true, since = "2.11.0") default int getMaxDamage() { return maxDamage(); } @@ -61,7 +61,7 @@ public interface ItemMaterial { * Gets the the maximum damage this item can take before being broken. * * @return the maximum damage, or 0 if not applicable - * @since TODO + * @since 2.11.0 */ @NonAbstractForCompatibility(delegateName = "getMaxDamage", delegateParams = {}) default int maxDamage() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java index 3e3201fb6..df506c67a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRestore.java @@ -28,12 +28,15 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.chunk.Chunk; import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.MissingChunkException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; import java.io.IOException; import java.util.ArrayList; @@ -197,14 +200,14 @@ public class SnapshotRestore { if (restoreEntities) { try { for (BaseEntity entity : chunk.getEntities()) { - CompoundBinaryTag tag = entity.getNbtReference().getValue(); - ListBinaryTag pos = tag.getList("Pos"); - ListBinaryTag rotation = tag.getList("Rotation"); - double x = pos.getDouble(0); - double y = pos.getDouble(1); - double z = pos.getDouble(2); - float yRot = rotation.getFloat(0); - float xRot = rotation.getFloat(1); + LinCompoundTag tag = entity.getNbtReference().getValue(); + LinListTag pos = tag.getListTag("Pos", LinTagType.doubleTag()); + LinListTag rotation = tag.getListTag("Rotation", LinTagType.floatTag()); + double x = pos.get(0).value(); + double y = pos.get(1).value(); + double z = pos.get(2).value(); + float yRot = rotation.get(0).value(); + float xRot = rotation.get(1).value(); Location location = new Location(editSession.getWorld(), x, y, z, yRot, xRot); BlockVector3 blockVector3 = BlockVector3.at(x, y, z); if (region.contains(blockVector3) && (editSession.getMask() == null diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java index 5f9880fc0..39d4fb07b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/experimental/SnapshotRestore.java @@ -27,13 +27,15 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.nbt.BinaryTagTypes; -import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; -import com.sk89q.worldedit.util.nbt.ListBinaryTag; import com.sk89q.worldedit.world.DataException; import com.sk89q.worldedit.world.chunk.Chunk; import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.MissingChunkException; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; +import org.enginehub.linbus.tree.LinTagType; import java.io.IOException; import java.util.ArrayList; @@ -193,14 +195,14 @@ public class SnapshotRestore { if (restoreEntities) { try { for (BaseEntity entity : chunk.getEntities()) { - CompoundBinaryTag tag = entity.getNbtReference().getValue(); - ListBinaryTag pos = tag.getList("Pos", BinaryTagTypes.LIST); - ListBinaryTag rotation = tag.getList("Rotation", BinaryTagTypes.LIST); - double x = pos.getDouble(0); - double y = pos.getDouble(1); - double z = pos.getDouble(2); - float yRot = rotation.getFloat(0); - float xRot = rotation.getFloat(1); + LinCompoundTag tag = entity.getNbtReference().getValue(); + LinListTag pos = tag.getListTag("Pos", LinTagType.doubleTag()); + LinListTag rotation = tag.getListTag("Rotation", LinTagType.floatTag()); + double x = pos.get(0).value(); + double y = pos.get(1).value(); + double z = pos.get(2).value(); + float yRot = rotation.get(0).value(); + float xRot = rotation.get(1).value(); Location location = new Location(editSession.getWorld(), x, y, z, yRot, xRot); editSession.createEntity(location, entity); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java index 58692732f..c8788a9ce 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStoreHelper.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.world.storage; -import com.sk89q.jnbt.AdventureNBTConverter; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.Tag; @@ -54,7 +53,7 @@ public class ChunkStoreHelper { public static CompoundTag readCompoundTag(ChunkDataInputSupplier input) throws DataException, IOException { try (InputStream stream = input.openInputStream(); - NBTInputStream nbt = new NBTInputStream(stream)) { + NBTInputStream nbt = new NBTInputStream(stream)) { Tag tag = nbt.readNamedTag().getTag(); if (!(tag instanceof CompoundTag)) { throw new ChunkStoreException("CompoundTag expected for chunk; got " @@ -99,23 +98,20 @@ public class ChunkStoreHelper { if ((dataVersion > 0 || hasLevelSections(rootTag)) && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks final DataFixer dataFixer = platform.getDataFixer(); if (dataFixer != null) { - //FAWE start - CBT - rootTag = (CompoundTag) AdventureNBTConverter.fromAdventure(dataFixer.fixUp(DataFixer.FixTypes.CHUNK, - rootTag.asBinaryTag(), dataVersion)); - //FAWE end + rootTag = new CompoundTag(dataFixer.fixUp(DataFixer.FixTypes.CHUNK, rootTag.toLinTag(), dataVersion)); dataVersion = currentDataVersion; } } if (dataVersion >= Constants.DATA_VERSION_MC_1_18) { - return new AnvilChunk18(rootTag, entitiesTag); + return new AnvilChunk18(rootTag); } - Map children = rootTag.getValue(); + Map> children = rootTag.getValue(); CompoundTag tag = null; // Find Level tag - for (Map.Entry entry : children.entrySet()) { + for (Map.Entry> entry : children.entrySet()) { if (entry.getKey().equals("Level")) { if (entry.getValue() instanceof CompoundTag) { tag = (CompoundTag) entry.getValue(); @@ -150,7 +146,7 @@ public class ChunkStoreHelper { return new AnvilChunk13(tag); } - Map tags = tag.getValue(); + Map> tags = tag.getValue(); if (tags.containsKey("Sections")) { return new AnvilChunk(tag); } @@ -159,8 +155,8 @@ public class ChunkStoreHelper { } private static boolean hasLevelSections(CompoundTag rootTag) { - Map children = rootTag.getValue(); - Tag levelTag = children.get("Level"); + Map> children = rootTag.getValue(); + Tag levelTag = children.get("Level"); if (levelTag instanceof CompoundTag) { return ((CompoundTag) levelTag).getValue().containsKey("Sections"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java index 8d82026ff..90d552c10 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java @@ -22,6 +22,9 @@ package com.sk89q.worldedit.world.storage; import com.sk89q.jnbt.ListTag; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Location; +import org.enginehub.linbus.tree.LinDoubleTag; +import org.enginehub.linbus.tree.LinFloatTag; +import org.enginehub.linbus.tree.LinListTag; import static com.google.common.base.Preconditions.checkNotNull; @@ -44,15 +47,41 @@ public final class NBTConversions { * @param positionTag the position tag * @param directionTag the direction tag * @return a location + * @deprecated Use {@link #toLocation(Extent, LinListTag, LinListTag)} instead. */ + @Deprecated public static Location toLocation(Extent extent, ListTag positionTag, ListTag directionTag) { checkNotNull(extent); checkNotNull(positionTag); checkNotNull(directionTag); return new Location( - extent, - positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), - directionTag.getFloat(0), directionTag.getFloat(1) + extent, + positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), + directionTag.getFloat(0), directionTag.getFloat(1)); + } + + /** + * Read a {@code Location} from two list tags, the first of which contains + * three numbers for the X, Y, and Z components, and the second of + * which contains two numbers, the yaw and pitch in degrees. + * + *

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

+ * + * @param extent the extent + * @param positionTag the position tag + * @param rotationTag the rotation tag + * @return a location + */ + public static Location toLocation(Extent extent, LinListTag positionTag, LinListTag rotationTag) { + int posTagSize = positionTag.value().size(); + int rotTagSize = rotationTag.value().size(); + return new Location( + extent, + posTagSize > 0 ? positionTag.get(0).valueAsDouble() : 0, + posTagSize > 1 ? positionTag.get(1).valueAsDouble() : 0, + posTagSize > 2 ? positionTag.get(2).valueAsDouble() : 0, + rotTagSize > 0 ? rotationTag.get(0).valueAsFloat() : 0, + rotTagSize > 1 ? rotationTag.get(1).valueAsFloat() : 0 ); } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index a8dddbdcf..a56d98695 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. 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}", @@ -164,6 +165,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.", @@ -358,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.)", diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java index cd3c5c313..0d87917d9 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/NBTConverter.java @@ -126,7 +126,7 @@ public final class NBTConverter { public static net.minecraft.nbt.CompoundTag toNative(CompoundTag tag) { net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); - for (Entry child : tag.getValue().entrySet()) { + for (Entry> child : tag.getValue().entrySet()) { compound.put(child.getKey(), toNative(child.getValue())); } return compound; @@ -230,7 +230,7 @@ public final class NBTConverter { public static CompoundTag fromNative(net.minecraft.nbt.CompoundTag other) { Set tags = other.getKeys(); - Map map = new HashMap<>(); + Map> map = new HashMap<>(); for (String tagName : tags) { map.put(tagName, fromNative(other.getTag(tagName))); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java index 9c10a6d30..82ab9ae23 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/NBTConverter.java @@ -139,7 +139,7 @@ public final class NBTConverter { public static CompoundNBT toNative(CompoundTag tag) { CompoundNBT compound = new CompoundNBT(); - for (Entry child : tag.getValue().entrySet()) { + for (Entry> child : tag.getValue().entrySet()) { compound.put(child.getKey(), toNative(child.getValue())); } return compound; @@ -243,7 +243,7 @@ public final class NBTConverter { public static CompoundTag fromNative(CompoundNBT other) { Set tags = other.keySet(); - Map map = new HashMap<>(); + Map> map = new HashMap<>(); for (String tagName : tags) { map.put(tagName, fromNative(other.get(tagName))); } diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts index c5eb10887..cace30cd0 100644 --- a/worldedit-libs/core/build.gradle.kts +++ b/worldedit-libs/core/build.gradle.kts @@ -12,5 +12,10 @@ dependencies { "shade"(libs.piston) "shade"(libs.pistonRuntime) "shade"(libs.pistonImpl) - "shade"(libs.adventureNbt) + // Linbus + "shade"(platform(libs.linBus.bom)) + "shade"(libs.linBus.common) + "shade"(libs.linBus.stream) + "shade"(libs.linBus.tree) + "shade"(libs.linBus.format.snbt) }