From 137c266e3a55d5132ed3d623d9949ed9a4ad4af8 Mon Sep 17 00:00:00 2001
From: Matthew Miller
Date: Sat, 6 Feb 2021 20:23:29 +1000
Subject: [PATCH 01/10] Migrate to adventure-nbt
---
buildSrc/src/main/kotlin/LibsConfig.kt | 3 +-
.../sk89q/worldedit/bukkit/BukkitPlayer.java | 2 +-
.../sk89q/worldedit/bukkit/BukkitWorld.java | 8 +-
.../worldedit/blocks/MobSpawnerBlock.java | 120 ++++++++--------
.../com/sk89q/worldedit/blocks/SignBlock.java | 19 +--
.../sk89q/worldedit/blocks/SkullBlock.java | 18 +--
.../com/sk89q/jnbt/AdventureNBTConverter.java | 132 ++++++++++++++++++
.../java/com/sk89q/jnbt/ByteArrayTag.java | 29 ++--
.../src/main/java/com/sk89q/jnbt/ByteTag.java | 21 ++-
.../main/java/com/sk89q/jnbt/CompoundTag.java | 28 ++--
.../com/sk89q/jnbt/CompoundTagBuilder.java | 3 +
.../main/java/com/sk89q/jnbt/DoubleTag.java | 22 ++-
.../src/main/java/com/sk89q/jnbt/EndTag.java | 10 +-
.../main/java/com/sk89q/jnbt/FloatTag.java | 22 ++-
.../main/java/com/sk89q/jnbt/IntArrayTag.java | 30 ++--
.../src/main/java/com/sk89q/jnbt/IntTag.java | 22 ++-
.../src/main/java/com/sk89q/jnbt/ListTag.java | 45 ++++--
.../java/com/sk89q/jnbt/ListTagBuilder.java | 3 +
.../java/com/sk89q/jnbt/LongArrayTag.java | 30 ++--
.../src/main/java/com/sk89q/jnbt/LongTag.java | 22 ++-
.../java/com/sk89q/jnbt/NBTConstants.java | 6 +-
.../java/com/sk89q/jnbt/NBTInputStream.java | 3 +
.../java/com/sk89q/jnbt/NBTOutputStream.java | 3 +
.../main/java/com/sk89q/jnbt/NBTUtils.java | 4 +-
.../main/java/com/sk89q/jnbt/NamedTag.java | 3 +
.../main/java/com/sk89q/jnbt/ShortTag.java | 22 ++-
.../main/java/com/sk89q/jnbt/StringTag.java | 22 ++-
.../src/main/java/com/sk89q/jnbt/Tag.java | 11 +-
.../com/sk89q/worldedit/LocalSession.java | 14 +-
.../com/sk89q/worldedit/blocks/BaseItem.java | 39 +++++-
.../sk89q/worldedit/blocks/BaseItemStack.java | 15 ++
.../sk89q/worldedit/entity/BaseEntity.java | 25 +++-
.../factory/parser/DefaultItemParser.java | 84 ++++++++---
.../extent/world/SurvivalModeExtent.java | 3 +-
.../function/block/ExtentBlockCopy.java | 20 +--
.../internal/cui/ServerCUIHandler.java | 53 ++++---
.../com/sk89q/worldedit/util/NbtUtils.java | 49 +++++++
.../util/collection/Int2BaseBlockMap.java | 2 +-
.../com/sk89q/worldedit/world/NbtValued.java | 77 +++++++++-
.../worldedit/world/block/BaseBlock.java | 79 +++++++----
.../worldedit/world/block/BlockState.java | 10 ++
.../world/block/BlockStateHolder.java | 14 ++
.../worldedit/world/chunk/AnvilChunk.java | 101 ++++++++------
.../worldedit/world/chunk/AnvilChunk13.java | 88 +++++++-----
.../worldedit/world/chunk/AnvilChunk16.java | 13 ++
.../sk89q/worldedit/world/chunk/OldChunk.java | 78 ++++++-----
.../src/main/resources/lang/strings.json | 2 +
worldedit-libs/core/build.gradle.kts | 1 +
.../sk89q/worldedit/sponge/SpongeWorld.java | 4 +-
49 files changed, 1019 insertions(+), 415 deletions(-)
create mode 100644 worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java
create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/NbtUtils.java
diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt
index 29c5bfa3a8..959b39f9cd 100644
--- a/buildSrc/src/main/kotlin/LibsConfig.kt
+++ b/buildSrc/src/main/kotlin/LibsConfig.kt
@@ -28,7 +28,8 @@ 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.minecraft" to "com.sk89q.worldedit.util.kyori",
+ "net.kyori.adventure.nbt" to "com.sk89q.worldedit.util.nbt"
)
tasks.register("jar") {
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 a5f5d615a9..5f44d3ea0e 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
@@ -295,7 +295,7 @@ public > void sendFakeBlock(BlockVector3 pos, B bl
player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData());
} else {
player.sendBlockChange(loc, BukkitAdapter.adapt(block));
- if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) {
+ if (block instanceof BaseBlock && ((BaseBlock) block).hasNbt()) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK) {
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
index 4d6edd2616..720ff750b1 100644
--- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
+++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
@@ -149,8 +149,8 @@ public com.sk89q.worldedit.entity.Entity createEntity(com.sk89q.worldedit.util.L
}
} catch (Exception e) {
logger.warn("Corrupt entity found when creating: " + entity.getType().getId());
- if (entity.getNbtData() != null) {
- logger.warn(entity.getNbtData().toString());
+ if (entity.getNbt() != null) {
+ logger.warn(entity.getNbt().toString());
}
e.printStackTrace();
return null;
@@ -457,9 +457,9 @@ public > boolean setBlock(BlockVector3 position, B
try {
return worldNativeAccess.setBlock(position, block, sideEffects);
} catch (Exception e) {
- if (block instanceof BaseBlock && ((BaseBlock) block).getNbtData() != null) {
+ if (block instanceof BaseBlock && ((BaseBlock) block).getNbt() != null) {
logger.warn("Tried to set a corrupt tile entity at " + position.toString()
- + ": " + ((BaseBlock) block).getNbtData(), e);
+ + ": " + ((BaseBlock) block).getNbt(), e);
} else {
logger.warn("Failed to set block via adapter, falling back to generic", e);
}
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 a43ef366d5..d88852f8ac 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
@@ -21,20 +21,18 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.sk89q.jnbt.CompoundTag;
-import com.sk89q.jnbt.IntTag;
-import com.sk89q.jnbt.ListTag;
-import com.sk89q.jnbt.NBTUtils;
-import com.sk89q.jnbt.ShortTag;
-import com.sk89q.jnbt.StringTag;
-import com.sk89q.jnbt.Tag;
+import com.sk89q.worldedit.util.NbtUtils;
+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.util.nbt.ShortBinaryTag;
+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.storage.InvalidFormatException;
-import java.util.HashMap;
-import java.util.Map;
-
/**
* A mob spawner block.
*/
@@ -46,8 +44,8 @@ public class MobSpawnerBlock extends BaseBlock {
// advanced mob spawner features
private short spawnCount = 4;
private short spawnRange = 4;
- private CompoundTag spawnData;
- private ListTag spawnPotentials;
+ private CompoundBinaryTag spawnData;
+ private ListBinaryTag spawnPotentials;
private short minSpawnDelay = 200;
private short maxSpawnDelay = 800;
private short maxNearbyEntities = 6;
@@ -110,7 +108,7 @@ public void setDelay(short delay) {
}
@Override
- public boolean hasNbtData() {
+ public boolean hasNbt() {
return true;
}
@@ -120,50 +118,52 @@ public String getNbtId() {
}
@Override
- public CompoundTag getNbtData() {
- Map values = new HashMap<>();
- values.put("Delay", new ShortTag(delay));
- values.put("SpawnCount", new ShortTag(spawnCount));
- values.put("SpawnRange", new ShortTag(spawnRange));
- values.put("MinSpawnDelay", new ShortTag(minSpawnDelay));
- values.put("MaxSpawnDelay", new ShortTag(maxSpawnDelay));
- values.put("MaxNearbyEntities", new ShortTag(maxNearbyEntities));
- values.put("RequiredPlayerRange", new ShortTag(requiredPlayerRange));
+ public CompoundBinaryTag getNbt() {
+ CompoundBinaryTag.Builder values = CompoundBinaryTag.builder();
+ values.put("Delay", ShortBinaryTag.of(delay));
+ values.put("SpawnCount", ShortBinaryTag.of(spawnCount));
+ values.put("SpawnRange", ShortBinaryTag.of(spawnRange));
+ values.put("MinSpawnDelay", ShortBinaryTag.of(minSpawnDelay));
+ values.put("MaxSpawnDelay", ShortBinaryTag.of(maxSpawnDelay));
+ values.put("MaxNearbyEntities", ShortBinaryTag.of(maxNearbyEntities));
+ values.put("RequiredPlayerRange", ShortBinaryTag.of(requiredPlayerRange));
if (spawnData == null) {
- values.put("SpawnData", new CompoundTag(ImmutableMap.of("id", new StringTag(mobType))));
+ values.put("SpawnData", CompoundBinaryTag.builder().put("id", StringBinaryTag.of(mobType)).build());
} else {
- values.put("SpawnData", new CompoundTag(spawnData.getValue()));
+ values.put("SpawnData", spawnData);
}
if (spawnPotentials == null) {
- values.put("SpawnPotentials", new ListTag(CompoundTag.class, ImmutableList.of(
- new CompoundTag(ImmutableMap.of("Weight", new IntTag(1), "Entity",
- new CompoundTag(ImmutableMap.of("id", new StringTag(mobType))))))));
+ values.put("SpawnPotentials", ListBinaryTag.of(
+ BinaryTagTypes.COMPOUND,
+ ImmutableList.of(CompoundBinaryTag.from(ImmutableMap.of(
+ "Weight", IntBinaryTag.of(1),
+ "Entity", CompoundBinaryTag.from(ImmutableMap.of("id", StringBinaryTag.of(mobType)))
+ )))
+ ));
} else {
- values.put("SpawnPotentials", new ListTag(CompoundTag.class, spawnPotentials.getValue()));
+ values.put("SpawnPotentials", spawnPotentials);
}
- return new CompoundTag(values);
+ return values.build();
}
@Override
- public void setNbtData(CompoundTag rootTag) {
+ public void setNbt(CompoundBinaryTag rootTag) {
if (rootTag == null) {
return;
}
- Map values = rootTag.getValue();
-
- Tag t = values.get("id");
- if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) {
+ BinaryTag t = rootTag.get("id");
+ if (!(t instanceof StringBinaryTag) || !((StringBinaryTag) t).value().equals(getNbtId())) {
throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId()));
}
- CompoundTag spawnDataTag;
+ CompoundBinaryTag spawnDataTag;
String mobType;
- ShortTag delayTag;
+ ShortBinaryTag delayTag;
try {
- spawnDataTag = NBTUtils.getChildTag(values, "SpawnData", CompoundTag.class);
+ spawnDataTag = NbtUtils.getChildTag(rootTag, "SpawnData", CompoundBinaryTag.class);
mobType = spawnDataTag.getString("id");
if (mobType.equals("")) {
throw new InvalidFormatException("No spawn id.");
@@ -174,68 +174,68 @@ public void setNbtData(CompoundTag rootTag) {
throw new RuntimeException("Invalid mob spawner data: no SpawnData and/or no Delay");
}
try {
- delayTag = NBTUtils.getChildTag(values, "Delay", ShortTag.class);
- this.delay = delayTag.getValue();
+ delayTag = NbtUtils.getChildTag(rootTag, "Delay", ShortBinaryTag.class);
+ this.delay = delayTag.value();
} catch (InvalidFormatException ignored) {
this.delay = -1;
}
- ShortTag spawnCountTag = null;
- ShortTag spawnRangeTag = null;
- ShortTag minSpawnDelayTag = null;
- ShortTag maxSpawnDelayTag = null;
- ShortTag maxNearbyEntitiesTag = null;
- ShortTag requiredPlayerRangeTag = null;
- ListTag spawnPotentialsTag = null;
+ ShortBinaryTag spawnCountTag = null;
+ ShortBinaryTag spawnRangeTag = null;
+ ShortBinaryTag minSpawnDelayTag = null;
+ ShortBinaryTag maxSpawnDelayTag = null;
+ ShortBinaryTag maxNearbyEntitiesTag = null;
+ ShortBinaryTag requiredPlayerRangeTag = null;
+ ListBinaryTag spawnPotentialsTag = null;
try {
- spawnCountTag = NBTUtils.getChildTag(values, "SpawnCount", ShortTag.class);
+ spawnCountTag = NbtUtils.getChildTag(rootTag, "SpawnCount", ShortBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
try {
- spawnRangeTag = NBTUtils.getChildTag(values, "SpawnRange", ShortTag.class);
+ spawnRangeTag = NbtUtils.getChildTag(rootTag, "SpawnRange", ShortBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
try {
- minSpawnDelayTag = NBTUtils.getChildTag(values, "MinSpawnDelay", ShortTag.class);
+ minSpawnDelayTag = NbtUtils.getChildTag(rootTag, "MinSpawnDelay", ShortBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
try {
- maxSpawnDelayTag = NBTUtils.getChildTag(values, "MaxSpawnDelay", ShortTag.class);
+ maxSpawnDelayTag = NbtUtils.getChildTag(rootTag, "MaxSpawnDelay", ShortBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
try {
- maxNearbyEntitiesTag = NBTUtils.getChildTag(values, "MaxNearbyEntities", ShortTag.class);
+ maxNearbyEntitiesTag = NbtUtils.getChildTag(rootTag, "MaxNearbyEntities", ShortBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
try {
- requiredPlayerRangeTag = NBTUtils.getChildTag(values, "RequiredPlayerRange", ShortTag.class);
+ requiredPlayerRangeTag = NbtUtils.getChildTag(rootTag, "RequiredPlayerRange", ShortBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
try {
- spawnPotentialsTag = NBTUtils.getChildTag(values, "SpawnPotentials", ListTag.class);
+ spawnPotentialsTag = NbtUtils.getChildTag(rootTag, "SpawnPotentials", ListBinaryTag.class);
} catch (InvalidFormatException ignored) {
}
if (spawnCountTag != null) {
- this.spawnCount = spawnCountTag.getValue();
+ this.spawnCount = spawnCountTag.value();
}
if (spawnRangeTag != null) {
- this.spawnRange = spawnRangeTag.getValue();
+ this.spawnRange = spawnRangeTag.value();
}
if (minSpawnDelayTag != null) {
- this.minSpawnDelay = minSpawnDelayTag.getValue();
+ this.minSpawnDelay = minSpawnDelayTag.value();
}
if (maxSpawnDelayTag != null) {
- this.maxSpawnDelay = maxSpawnDelayTag.getValue();
+ this.maxSpawnDelay = maxSpawnDelayTag.value();
}
if (maxNearbyEntitiesTag != null) {
- this.maxNearbyEntities = maxNearbyEntitiesTag.getValue();
+ this.maxNearbyEntities = maxNearbyEntitiesTag.value();
}
if (requiredPlayerRangeTag != null) {
- this.requiredPlayerRange = requiredPlayerRangeTag.getValue();
+ this.requiredPlayerRange = requiredPlayerRangeTag.value();
}
if (spawnPotentialsTag != null) {
- this.spawnPotentials = new ListTag(CompoundTag.class, spawnPotentialsTag.getValue());
+ this.spawnPotentials = spawnPotentialsTag;
}
}
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 db8c4b2be9..a52442285e 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
@@ -23,10 +23,11 @@
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.util.gson.GsonUtil;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
-import java.util.HashMap;
import java.util.Map;
/**
@@ -82,7 +83,7 @@ public void setText(String[] text) {
}
@Override
- public boolean hasNbtData() {
+ public boolean hasNbt() {
return true;
}
@@ -92,13 +93,13 @@ public String getNbtId() {
}
@Override
- public CompoundTag getNbtData() {
- Map values = new HashMap<>();
- values.put("Text1", new StringTag(text[0]));
- values.put("Text2", new StringTag(text[1]));
- values.put("Text3", new StringTag(text[2]));
- values.put("Text4", new StringTag(text[3]));
- return new CompoundTag(values);
+ public CompoundBinaryTag getNbt() {
+ CompoundBinaryTag.Builder values = CompoundBinaryTag.builder();
+ values.put("Text1", StringBinaryTag.of(text[0]));
+ values.put("Text2", StringBinaryTag.of(text[1]));
+ values.put("Text3", StringBinaryTag.of(text[2]));
+ values.put("Text4", StringBinaryTag.of(text[3]));
+ return values.build();
}
@Override
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 e754fb4536..e33b7fe830 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
@@ -19,14 +19,16 @@
package com.sk89q.worldedit.blocks;
+import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.internal.util.DeprecationUtil;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
-import java.util.HashMap;
import java.util.Map;
/**
@@ -81,7 +83,7 @@ public String getOwner() {
}
@Override
- public boolean hasNbtData() {
+ public boolean hasNbt() {
return true;
}
@@ -91,12 +93,12 @@ public String getNbtId() {
}
@Override
- public CompoundTag getNbtData() {
- 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);
+ public CompoundBinaryTag getNbt() {
+ CompoundBinaryTag.Builder values = CompoundBinaryTag.builder();
+ values.put(DeprecationUtil.getHeadOwnerKey(), CompoundBinaryTag.from(
+ ImmutableMap.of("Name", StringBinaryTag.of(owner))
+ ));
+ return values.build();
}
@Override
diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java b/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java
new file mode 100644
index 0000000000..407bcb0099
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/AdventureNBTConverter.java
@@ -0,0 +1,132 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (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.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;
+
+/**
+ * Converts between JNBT and Adventure-NBT classes.
+ *
+ * @deprecated JNBT is being removed in WE8.
+ */
+@Deprecated
+public class AdventureNBTConverter {
+
+ private AdventureNBTConverter() {
+
+ }
+
+ public static Tag fromAdventure(BinaryTag other) {
+ if (other instanceof IntArrayBinaryTag) {
+ return fromAdventure((IntArrayBinaryTag) other);
+ } else if (other instanceof ListBinaryTag) {
+ return fromAdventure((ListBinaryTag) other);
+ } else if (other instanceof EndBinaryTag) {
+ return fromAdventure();
+ } else if (other instanceof LongBinaryTag) {
+ return fromAdventure((LongBinaryTag) other);
+ } else if (other instanceof LongArrayBinaryTag) {
+ return fromAdventure((LongArrayBinaryTag) other);
+ } else if (other instanceof StringBinaryTag) {
+ return fromAdventure((StringBinaryTag) other);
+ } else if (other instanceof IntBinaryTag) {
+ return fromAdventure((IntBinaryTag) other);
+ } else if (other instanceof ByteBinaryTag) {
+ return fromAdventure((ByteBinaryTag) other);
+ } else if (other instanceof ByteArrayBinaryTag) {
+ return fromAdventure((ByteArrayBinaryTag) other);
+ } else if (other instanceof CompoundBinaryTag) {
+ return fromAdventure((CompoundBinaryTag) other);
+ } else if (other instanceof FloatBinaryTag) {
+ return fromAdventure((FloatBinaryTag) other);
+ } else if (other instanceof ShortBinaryTag) {
+ return fromAdventure((ShortBinaryTag) other);
+ } else if (other instanceof DoubleBinaryTag) {
+ return fromAdventure((DoubleBinaryTag) other);
+ } else {
+ throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName());
+ }
+ }
+
+ public static DoubleTag fromAdventure(DoubleBinaryTag other) {
+ return new DoubleTag(other);
+ }
+
+ public static ShortTag fromAdventure(ShortBinaryTag other) {
+ return new ShortTag(other);
+ }
+
+ public static FloatTag fromAdventure(FloatBinaryTag other) {
+ return new FloatTag(other);
+ }
+
+ public static CompoundTag fromAdventure(CompoundBinaryTag other) {
+ return new CompoundTag(other);
+ }
+
+ public static ByteArrayTag fromAdventure(ByteArrayBinaryTag other) {
+ return new ByteArrayTag(other);
+ }
+
+ public static ByteTag fromAdventure(ByteBinaryTag other) {
+ return new ByteTag(other);
+ }
+
+ public static IntTag fromAdventure(IntBinaryTag other) {
+ return new IntTag(other);
+ }
+
+ public static StringTag fromAdventure(StringBinaryTag other) {
+ return new StringTag(other);
+ }
+
+ public static LongArrayTag fromAdventure(LongArrayBinaryTag other) {
+ return new LongArrayTag(other);
+ }
+
+ public static LongTag fromAdventure(LongBinaryTag other) {
+ return new LongTag(other);
+ }
+
+ public static EndTag fromAdventure() {
+ return new EndTag();
+ }
+
+ public static ListTag fromAdventure(ListBinaryTag other) {
+ return new ListTag(other);
+ }
+
+ public static IntArrayTag fromAdventure(IntArrayBinaryTag other) {
+ return new IntArrayTag(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 78a9d7521b..6c511e63c3 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java
@@ -19,14 +19,19 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag;
+
import java.util.Locale;
/**
* The {@code TAG_Byte_Array} tag.
+ *
+ * @deprecated Use {@link ByteArrayBinaryTag}.
*/
+@Deprecated
public final class ByteArrayTag extends Tag {
- private final byte[] value;
+ private final ByteArrayBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -35,25 +40,21 @@ public final class ByteArrayTag extends Tag {
*/
public ByteArrayTag(byte[] value) {
super();
- this.value = value;
+ this.innerTag = ByteArrayBinaryTag.of(value);
+ }
+
+ ByteArrayTag(ByteArrayBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
public byte[] getValue() {
- return value;
+ return innerTag.value();
}
@Override
- public String toString() {
- StringBuilder hex = new StringBuilder();
- for (byte b : value) {
- String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT);
- if (hexDigits.length() == 1) {
- hex.append("0");
- }
- hex.append(hexDigits).append(" ");
- }
- return "TAG_Byte_Array(" + hex + ")";
+ public ByteArrayBinaryTag asBinaryTag() {
+ return innerTag;
}
-
}
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 e7fe1cc407..834f1ba7e4 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteTag.java
@@ -19,12 +19,17 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.ByteBinaryTag;
+
/**
* The {@code TAG_Byte} tag.
+ *
+ * @deprecated Use {@link ByteBinaryTag}.
*/
+@Deprecated
public final class ByteTag extends Tag {
- private final byte value;
+ private final ByteBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -33,17 +38,21 @@ public final class ByteTag extends Tag {
*/
public ByteTag(byte value) {
super();
- this.value = value;
+ this.innerTag = ByteBinaryTag.of(value);
+ }
+
+ ByteTag(ByteBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
public Byte getValue() {
- return value;
+ return innerTag.value();
}
@Override
- public String toString() {
- return "TAG_Byte(" + value + ")";
+ public ByteBinaryTag asBinaryTag() {
+ return innerTag;
}
-
}
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 3a382effec..c2e02b3585 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTag.java
@@ -19,14 +19,20 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* The {@code TAG_Compound} tag.
+ *
+ * @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag}.
*/
+@Deprecated
public final class CompoundTag extends Tag {
private final Map value;
@@ -41,6 +47,15 @@ public CompoundTag(Map value) {
this.value = Collections.unmodifiableMap(value);
}
+ CompoundTag(CompoundBinaryTag adventureTag) {
+ Set tags = adventureTag.keySet();
+ Map map = new HashMap<>();
+ for (String tagName : tags) {
+ map.put(tagName, AdventureNBTConverter.fromAdventure(adventureTag.get(tagName)));
+ }
+ this.value = Collections.unmodifiableMap(map);
+ }
+
/**
* Returns whether this compound tag contains the given key.
*
@@ -425,14 +440,11 @@ public String getString(String key) {
}
@Override
- public String toString() {
- StringBuilder bldr = new StringBuilder();
- bldr.append("TAG_Compound").append(": ").append(value.size()).append(" entries\r\n{\r\n");
- for (Map.Entry entry : value.entrySet()) {
- bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
+ public CompoundBinaryTag asBinaryTag() {
+ CompoundBinaryTag.Builder builder = CompoundBinaryTag.builder();
+ for (Map.Entry child : getValue().entrySet()) {
+ builder.put(child.getKey(), child.getValue().asBinaryTag());
}
- bldr.append("}");
- return bldr.toString();
+ return builder.build();
}
-
}
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 7267a72e0a..941fe9fa71 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java
@@ -26,7 +26,10 @@
/**
* Helps create compound tags.
+ *
+ * @deprecated Use {@link com.sk89q.worldedit.util.nbt.CompoundBinaryTag.Builder}.
*/
+@Deprecated
public class CompoundTagBuilder {
private final Map entries;
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 b579308571..769cee761b 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/DoubleTag.java
@@ -19,12 +19,17 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.DoubleBinaryTag;
+
/**
* The {@code TAG_Double} tag.
+ *
+ * @deprecated Use {@link DoubleBinaryTag}.
*/
+@Deprecated
public final class DoubleTag extends Tag {
- private final double value;
+ private final DoubleBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -33,17 +38,22 @@ public final class DoubleTag extends Tag {
*/
public DoubleTag(double value) {
super();
- this.value = value;
+ this.innerTag = DoubleBinaryTag.of(value);
+ }
+
+ DoubleTag(DoubleBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public Double getValue() {
- return value;
+ public DoubleBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- return "TAG_Double(" + value + ")";
+ public Double getValue() {
+ return innerTag.value();
}
}
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 c6fc635983..3f179e54fd 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/EndTag.java
@@ -19,9 +19,14 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.EndBinaryTag;
+
/**
* The {@code TAG_End} tag.
+ *
+ * @deprecated Use {@link com.sk89q.worldedit.util.nbt.EndBinaryTag}.
*/
+@Deprecated
public final class EndTag extends Tag {
@Override
@@ -30,8 +35,7 @@ public Object getValue() {
}
@Override
- public String toString() {
- return "TAG_End";
+ public EndBinaryTag asBinaryTag() {
+ return EndBinaryTag.get();
}
-
}
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 e1281ea131..2477caa93d 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/FloatTag.java
@@ -19,12 +19,17 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.FloatBinaryTag;
+
/**
* The {@code TAG_Float} tag.
+ *
+ * @deprecated Use {@link FloatBinaryTag}.
*/
+@Deprecated
public final class FloatTag extends Tag {
- private final float value;
+ private final FloatBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -33,17 +38,22 @@ public final class FloatTag extends Tag {
*/
public FloatTag(float value) {
super();
- this.value = value;
+ this.innerTag = FloatBinaryTag.of(value);
+ }
+
+ FloatTag(FloatBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public Float getValue() {
- return value;
+ public FloatBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- return "TAG_Float(" + value + ")";
+ public Float getValue() {
+ return innerTag.value();
}
}
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 39c6217359..1146ac1e66 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java
@@ -19,16 +19,19 @@
package com.sk89q.jnbt;
-import java.util.Locale;
+import com.sk89q.worldedit.util.nbt.IntArrayBinaryTag;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* The {@code TAG_Int_Array} tag.
+ *
+ * @deprecated Use {@link IntArrayBinaryTag}.
*/
+@Deprecated
public final class IntArrayTag extends Tag {
- private final int[] value;
+ private final IntArrayBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -38,25 +41,22 @@ public final class IntArrayTag extends Tag {
public IntArrayTag(int[] value) {
super();
checkNotNull(value);
- this.value = value;
+ this.innerTag = IntArrayBinaryTag.of(value);
+ }
+
+ IntArrayTag(IntArrayBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public int[] getValue() {
- return value;
+ public IntArrayBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- StringBuilder hex = new StringBuilder();
- for (int b : value) {
- String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT);
- if (hexDigits.length() == 1) {
- hex.append("0");
- }
- hex.append(hexDigits).append(" ");
- }
- return "TAG_Int_Array(" + hex + ")";
+ public int[] getValue() {
+ return innerTag.value();
}
}
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 359cf85b9b..8583579c03 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntTag.java
@@ -19,12 +19,17 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.IntBinaryTag;
+
/**
* The {@code TAG_Int} tag.
+ *
+ * @deprecated Use {@link IntBinaryTag}.
*/
+@Deprecated
public final class IntTag extends Tag {
- private final int value;
+ private final IntBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -33,17 +38,22 @@ public final class IntTag extends Tag {
*/
public IntTag(int value) {
super();
- this.value = value;
+ this.innerTag = IntBinaryTag.of(value);
+ }
+
+ IntTag(IntBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public Integer getValue() {
- return value;
+ public IntBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- return "TAG_Int(" + value + ")";
+ public Integer getValue() {
+ return innerTag.value();
}
}
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 8134a3f74e..39023d0226 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTag.java
@@ -19,6 +19,10 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.BinaryTag;
+import com.sk89q.worldedit.util.nbt.ListBinaryTag;
+
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
@@ -27,7 +31,10 @@
/**
* The {@code TAG_List} tag.
+ *
+ * @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag}.
*/
+@Deprecated
public final class ListTag extends Tag {
private final Class extends Tag> type;
@@ -46,6 +53,33 @@ public ListTag(Class extends Tag> type, List extends Tag> value) {
this.value = Collections.unmodifiableList(value);
}
+ ListTag(ListBinaryTag adventureTag) {
+ super();
+ List list = new ArrayList<>();
+ Class extends Tag> listClass = StringTag.class;
+ int tags = adventureTag.size();
+ for (int i = 0; i < tags; i++) {
+ Tag child = AdventureNBTConverter.fromAdventure(adventureTag.get(0));
+ list.add(child);
+ listClass = child.getClass();
+ }
+
+ this.type = listClass;
+ this.value = Collections.unmodifiableList(list);
+ }
+
+ @Override
+ public ListBinaryTag asBinaryTag() {
+ ListBinaryTag.Builder builder = ListBinaryTag.builder();
+ for (Tag child : getValue()) {
+ if (child instanceof EndTag) {
+ continue;
+ }
+ builder.add(child.asBinaryTag());
+ }
+ return builder.build();
+ }
+
/**
* Gets the type of item in this list.
*
@@ -415,15 +449,4 @@ public String getString(int index) {
}
}
- @Override
- public String toString() {
- StringBuilder bldr = new StringBuilder();
- bldr.append("TAG_List").append(": ").append(value.size()).append(" entries of type ").append(NBTUtils.getTypeName(type)).append("\r\n{\r\n");
- for (Tag t : value) {
- bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
- }
- bldr.append("}");
- return bldr.toString();
- }
-
}
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 b98c667e50..ad3a6e25cf 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ListTagBuilder.java
@@ -28,7 +28,10 @@
/**
* Helps create list tags.
+ *
+ * @deprecated Use {@link com.sk89q.worldedit.util.nbt.ListBinaryTag.Builder}.
*/
+@Deprecated
public class ListTagBuilder {
private final Class extends Tag> type;
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 c2e9688d08..7ca5df0dc2 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java
@@ -19,16 +19,19 @@
package com.sk89q.jnbt;
-import java.util.Locale;
+import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* The {@code TAG_Long_Array} tag.
+ *
+ * @deprecated Use {@link LongArrayBinaryTag}.
*/
+@Deprecated
public class LongArrayTag extends Tag {
- private final long[] value;
+ private final LongArrayBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -38,25 +41,22 @@ public class LongArrayTag extends Tag {
public LongArrayTag(long[] value) {
super();
checkNotNull(value);
- this.value = value;
+ this.innerTag = LongArrayBinaryTag.of(value);
+ }
+
+ LongArrayTag(LongArrayBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public long[] getValue() {
- return value;
+ public LongArrayBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- StringBuilder hex = new StringBuilder();
- for (long b : value) {
- String hexDigits = Long.toHexString(b).toUpperCase(Locale.ROOT);
- if (hexDigits.length() == 1) {
- hex.append("0");
- }
- hex.append(hexDigits).append(" ");
- }
- return "TAG_Long_Array(" + hex + ")";
+ public long[] getValue() {
+ return innerTag.value();
}
}
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 8f894520a2..aa7e74f10d 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongTag.java
@@ -19,12 +19,17 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.LongBinaryTag;
+
/**
* The {@code TAG_Long} tag.
+ *
+ * @deprecated Use {@link LongBinaryTag}.
*/
+@Deprecated
public final class LongTag extends Tag {
- private final long value;
+ private final LongBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -33,17 +38,22 @@ public final class LongTag extends Tag {
*/
public LongTag(long value) {
super();
- this.value = value;
+ this.innerTag = LongBinaryTag.of(value);
+ }
+
+ LongTag(LongBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public Long getValue() {
- return value;
+ public LongBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- return "TAG_Long(" + value + ")";
+ public Long getValue() {
+ return innerTag.value();
}
}
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 db6689cb52..9d65f5e79d 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTConstants.java
@@ -20,13 +20,17 @@
package com.sk89q.jnbt;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
/**
* A class which holds constant values.
+ *
+ * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
*/
+@Deprecated
public final class NBTConstants {
- public static final Charset CHARSET = Charset.forName("UTF-8");
+ public static final Charset CHARSET = StandardCharsets.UTF_8;
public static final int TYPE_END = 0;
public static final int TYPE_BYTE = 1;
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 35a0bb62e1..1b41180851 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java
@@ -38,7 +38,10 @@
* found at
* https://minecraft.gamepedia.com/NBT_format.
*
+ *
+ * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
*/
+@Deprecated
public final class NBTInputStream implements Closeable {
private final DataInputStream is;
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 98ccb72db0..ae92946ae0 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java
@@ -37,7 +37,10 @@
* found at
* https://minecraft.gamepedia.com/NBT_format.
*
+ *
+ * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
*/
+@Deprecated
public final class NBTOutputStream implements Closeable {
/**
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 c6e53e598c..52d21ca451 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTUtils.java
@@ -29,7 +29,9 @@
/**
* A class which contains NBT-related utility methods.
*
+ * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
*/
+@Deprecated
public final class NBTUtils {
/**
@@ -72,7 +74,7 @@ public static String getTypeName(Class extends Tag> clazz) {
} else if (clazz.equals(LongArrayTag.class)) {
return "TAG_Long_Array";
} else {
- throw new IllegalArgumentException("Invalid tag classs ("
+ throw new IllegalArgumentException("Invalid tag class ("
+ clazz.getName() + ").");
}
}
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 c7089e3f48..80742783c8 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NamedTag.java
@@ -23,7 +23,10 @@
/**
* A tag that has a name.
+ *
+ * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
*/
+@Deprecated
public class NamedTag {
private final String name;
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 f8224ab0ed..486ae69a67 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ShortTag.java
@@ -19,12 +19,17 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
+
/**
* The {@code TAG_Short} tag.
+ *
+ * @deprecated Use {@link ShortBinaryTag}.
*/
+@Deprecated
public final class ShortTag extends Tag {
- private final short value;
+ private final ShortBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -33,17 +38,22 @@ public final class ShortTag extends Tag {
*/
public ShortTag(short value) {
super();
- this.value = value;
+ this.innerTag = ShortBinaryTag.of(value);
+ }
+
+ ShortTag(ShortBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public Short getValue() {
- return value;
+ public ShortBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- return "TAG_Short(" + value + ")";
+ public Short getValue() {
+ return innerTag.value();
}
}
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 3727f8d8e1..124f72f48b 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/StringTag.java
@@ -19,14 +19,19 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.StringBinaryTag;
+
import static com.google.common.base.Preconditions.checkNotNull;
/**
* The {@code TAG_String} tag.
+ *
+ * @deprecated Use {@link StringBinaryTag}.
*/
+@Deprecated
public final class StringTag extends Tag {
- private final String value;
+ private final StringBinaryTag innerTag;
/**
* Creates the tag with an empty name.
@@ -36,17 +41,22 @@ public final class StringTag extends Tag {
public StringTag(String value) {
super();
checkNotNull(value);
- this.value = value;
+ this.innerTag = StringBinaryTag.of(value);
+ }
+
+ StringTag(StringBinaryTag adventureTag) {
+ super();
+ this.innerTag = adventureTag;
}
@Override
- public String getValue() {
- return value;
+ public StringBinaryTag asBinaryTag() {
+ return this.innerTag;
}
@Override
- public String toString() {
- return "TAG_String(" + value + ")";
+ public String getValue() {
+ return innerTag.value();
}
}
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 a94b3b3bb3..5a3bd1d484 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/Tag.java
@@ -19,10 +19,15 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.BinaryTagLike;
+
/**
* Represents a NBT tag.
+ *
+ * @deprecated JNBT is being removed for adventure-nbt in WorldEdit 8.
*/
-public abstract class Tag {
+@Deprecated
+public abstract class Tag implements BinaryTagLike {
/**
* Gets the value of this tag.
@@ -31,4 +36,8 @@ public abstract class Tag {
*/
public abstract Object getValue();
+ @Override
+ public String toString() {
+ return asBinaryTag().toString();
+ }
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java
index 837db9498c..f83815225f 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java
@@ -23,8 +23,7 @@
import com.sk89q.jchronic.Options;
import com.sk89q.jchronic.utils.Span;
import com.sk89q.jchronic.utils.Time;
-import com.sk89q.jnbt.IntTag;
-import com.sk89q.jnbt.Tag;
+import com.sk89q.jnbt.AdventureNBTConverter;
import com.sk89q.worldedit.command.tool.BlockTool;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
@@ -51,6 +50,7 @@
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
+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;
@@ -803,13 +803,13 @@ public void updateServerCUI(Actor actor) {
}
BaseBlock block = ServerCUIHandler.createStructureBlock(player);
- if (block != null) {
+ if (block != null && block.hasNbt()) {
// If it's null, we don't need to do anything. The old was already removed.
- Map tags = block.getNbtData().getValue();
+ CompoundBinaryTag tags = block.getNbt();
BlockVector3 tempCuiTemporaryBlock = BlockVector3.at(
- ((IntTag) tags.get("x")).getValue(),
- ((IntTag) tags.get("y")).getValue(),
- ((IntTag) tags.get("z")).getValue()
+ tags.getInt("x"),
+ tags.getInt("y"),
+ tags.getInt("z")
);
if (cuiTemporaryBlock != null && !tempCuiTemporaryBlock.equals(cuiTemporaryBlock)) {
// Update the existing block if it's the same location
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 a365bc4b14..c6ad28b38d 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,9 +20,13 @@
package com.sk89q.worldedit.blocks;
import com.sk89q.jnbt.CompoundTag;
+import com.sk89q.worldedit.WorldEdit;
+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 java.io.IOException;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -37,7 +41,7 @@ public class BaseItem implements NbtValued {
private ItemType itemType;
@Nullable
- private CompoundTag nbtData;
+ private CompoundBinaryTag nbtData;
/**
* Construct the object.
@@ -49,13 +53,24 @@ public BaseItem(ItemType itemType) {
this.itemType = itemType;
}
+ /**
+ * Construct the object.
+ *
+ * @param itemType Type of the item
+ * @param nbtData NBT Compound tag
+ */
+ @Deprecated
+ public BaseItem(ItemType itemType, CompoundTag nbtData) {
+ this(itemType, checkNotNull(nbtData).asBinaryTag());
+ }
+
/**
* Construct the object.
*
* @param itemType Type of the item
* @param tag NBT Compound tag
*/
- public BaseItem(ItemType itemType, @Nullable CompoundTag tag) {
+ public BaseItem(ItemType itemType, @Nullable CompoundBinaryTag tag) {
checkNotNull(itemType);
this.itemType = itemType;
this.nbtData = tag;
@@ -80,18 +95,32 @@ public void setType(ItemType itemType) {
}
@Override
- public boolean hasNbtData() {
+ public boolean hasNbt() {
return this.nbtData != null;
}
@Nullable
@Override
- public CompoundTag getNbtData() {
+ public CompoundBinaryTag getNbt() {
return this.nbtData;
}
@Override
- public void setNbtData(@Nullable CompoundTag nbtData) {
+ public void setNbt(@Nullable CompoundBinaryTag nbtData) {
this.nbtData = nbtData;
}
+
+ @Override
+ public String toString() {
+ String nbtString = "";
+ if (hasNbt()) {
+ try {
+ nbtString = TagStringIO.get().asString(nbtData);
+ } catch (IOException e) {
+ WorldEdit.logger.error("Failed to parse NBT of Item", e);
+ }
+ }
+
+ return getType().getId() + 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 10655963a0..461dc31dfc 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
@@ -23,6 +23,7 @@
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.util.formatting.text.Component;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.item.ItemType;
/**
@@ -60,12 +61,26 @@ public BaseItemStack(ItemType itemType, int amount) {
* @param id The item type
* @param tag Tag value
* @param amount amount in the stack
+ * @deprecated Use {@link #BaseItemStack(ItemType, CompoundBinaryTag, int)}
*/
+ @Deprecated
public BaseItemStack(ItemType id, CompoundTag tag, int amount) {
super(id, tag);
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, CompoundBinaryTag tag, int amount) {
+ super(id, tag);
+ this.amount = amount;
+ }
+
/**
* Get the number of items in the stack.
*
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 393023df81..ef26da7b80 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
@@ -20,6 +20,7 @@
package com.sk89q.worldedit.entity;
import com.sk89q.jnbt.CompoundTag;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.NbtValued;
import com.sk89q.worldedit.world.entity.EntityType;
@@ -43,19 +44,33 @@
public class BaseEntity implements NbtValued {
private final EntityType type;
- private CompoundTag nbtData;
+ @Nullable
+ private CompoundBinaryTag nbtData;
/**
* Create a new base entity.
*
* @param type the entity type
* @param nbtData NBT data
+ * @deprecated Use {@link BaseEntity#BaseEntity(EntityType, CompoundBinaryTag)}
*/
+ @Deprecated
public BaseEntity(EntityType type, CompoundTag nbtData) {
this(type);
setNbtData(nbtData);
}
+ /**
+ * Create a new base entity.
+ *
+ * @param type the entity type
+ * @param nbtData NBT data
+ */
+ public BaseEntity(EntityType type, CompoundBinaryTag nbtData) {
+ this(type);
+ setNbt(nbtData);
+ }
+
/**
* Create a new base entity with no NBT data.
*
@@ -73,22 +88,22 @@ public BaseEntity(EntityType type) {
public BaseEntity(BaseEntity other) {
checkNotNull(other);
this.type = other.getType();
- setNbtData(other.getNbtData());
+ setNbt(other.getNbt());
}
@Override
- public boolean hasNbtData() {
+ public boolean hasNbt() {
return true;
}
@Nullable
@Override
- public CompoundTag getNbtData() {
+ public CompoundBinaryTag getNbt() {
return nbtData;
}
@Override
- public void setNbtData(@Nullable CompoundTag nbtData) {
+ public void setNbt(@Nullable CompoundBinaryTag nbtData) {
this.nbtData = nbtData;
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java
index 186fff5560..2a9d3bf8fc 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
@@ -32,10 +32,13 @@
import com.sk89q.worldedit.util.HandSide;
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 java.io.IOException;
import java.util.Locale;
import java.util.stream.Stream;
@@ -52,44 +55,87 @@ public Stream getSuggestions(String input) {
@Override
public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException {
+ ItemType itemType;
+ CompoundBinaryTag itemNbtData = null;
+
BaseItem item = null;
+
// Legacy matcher
if (context.isTryingLegacy()) {
try {
String[] split = input.split(":");
- ItemType type;
if (split.length == 0) {
throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.invalid-colon"));
} else if (split.length == 1) {
- type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]));
+ itemType = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]));
} else {
- type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
+ itemType = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
}
- if (type != null) {
- item = new BaseItem(type);
+ if (itemType != null) {
+ item = new BaseItem(itemType);
}
} catch (NumberFormatException ignored) {
}
}
- if ("hand".equalsIgnoreCase(input)) {
- return getItemInHand(context.requireActor(), HandSide.MAIN_HAND);
- } else if ("offhand".equalsIgnoreCase(input)) {
- return getItemInHand(context.requireActor(), HandSide.OFF_HAND);
- }
-
if (item == null) {
- ItemType type = ItemTypes.get(input.toLowerCase(Locale.ROOT));
- if (type != null) {
- item = new BaseItem(type);
+ String typeString;
+ String nbtString = null;
+ int nbtStart = input.indexOf('{');
+
+ if (nbtStart == -1) {
+ typeString = input;
+ } else {
+ typeString = input.substring(0, nbtStart);
+ if (nbtStart + 1 >= input.length()) {
+ throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.hanging-lbracket", TextComponent.of(nbtStart)));
+ }
+ int stateEnd = input.lastIndexOf('}');
+ if (stateEnd < 0) {
+ throw new InputParseException(TranslatableComponent.of("worldedit.error.parser.missing-rbracket"));
+ }
+ nbtString = input.substring(nbtStart);
}
- }
- if (item == null) {
- throw new NoMatchException(TranslatableComponent.of("worldedit.error.no-match", TextComponent.of(input)));
- } else {
- return item;
+ if ("hand".equalsIgnoreCase(typeString)) {
+ BaseItemStack heldItem = getItemInHand(context.requireActor(), HandSide.MAIN_HAND);
+ itemType = heldItem.getType();
+ itemNbtData = heldItem.getNbt();
+ } else if ("offhand".equalsIgnoreCase(typeString)) {
+ BaseItemStack heldItem = getItemInHand(context.requireActor(), HandSide.OFF_HAND);
+ itemType = heldItem.getType();
+ itemNbtData = heldItem.getNbt();
+ } else {
+ itemType = ItemTypes.get(typeString.toLowerCase(Locale.ROOT));
+ }
+
+ if (itemType == null) {
+ throw new NoMatchException(TranslatableComponent.of("worldedit.error.unknown-item", TextComponent.of(input)));
+ }
+
+ if (nbtString != null) {
+ try {
+ CompoundBinaryTag otherTag = TagStringIO.get().asCompound(nbtString);
+ if (itemNbtData == null) {
+ itemNbtData = otherTag;
+ } else {
+ for (String key : otherTag.keySet()) {
+ itemNbtData.put(key, otherTag.get(key));
+ }
+ }
+ } catch (IOException e) {
+ throw new NoMatchException(TranslatableComponent.of(
+ "worldedit.error.invalid-nbt",
+ TextComponent.of(input),
+ TextComponent.of(e.getMessage())
+ ));
+ }
+ }
+
+ item = new BaseItem(itemType, itemNbtData);
}
+
+ return item;
}
private BaseItemStack getItemInHand(Actor actor, HandSide handSide) throws InputParseException {
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 2cb6b02c82..21c287cd79 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
@@ -23,6 +23,7 @@
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;
@@ -95,7 +96,7 @@ public > boolean setBlock(BlockVector3 location, B
} else {
// Can't be an inlined check due to inconsistent generic return type
if (stripNbt) {
- return super.setBlock(location, block.toBaseBlock(null));
+ return super.setBlock(location, block.toBaseBlock((CompoundBinaryTag) 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 7f56aed565..56ae3ed10e 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
@@ -19,8 +19,6 @@
package com.sk89q.worldedit.function.block;
-import com.sk89q.jnbt.CompoundTag;
-import com.sk89q.jnbt.CompoundTagBuilder;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.RegionFunction;
@@ -30,6 +28,9 @@
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Direction.Flag;
+import com.sk89q.worldedit.util.nbt.BinaryTag;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+import com.sk89q.worldedit.util.nbt.IntBinaryTag;
import com.sk89q.worldedit.world.block.BaseBlock;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -87,12 +88,13 @@ public boolean apply(BlockVector3 position) throws WorldEditException {
* @return a new state or the existing one
*/
private BaseBlock transformNbtData(BaseBlock state) {
- CompoundTag tag = state.getNbtData();
+ CompoundBinaryTag tag = state.getNbt();
if (tag != null) {
// Handle blocks which store their rotation in NBT
- if (tag.containsKey("Rot")) {
- int rot = tag.asInt("Rot");
+ BinaryTag rotTag = tag.get("Rot");
+ if (rotTag instanceof IntBinaryTag) {
+ int rot = ((IntBinaryTag) rotTag).value();
Direction direction = MCDirections.fromRotation(rot);
@@ -101,11 +103,9 @@ private BaseBlock transformNbtData(BaseBlock state) {
Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL | Flag.ORDINAL | Flag.SECONDARY_ORDINAL);
if (newDirection != null) {
- CompoundTagBuilder builder = tag.createBuilder();
-
- builder.putByte("Rot", (byte) MCDirections.toRotation(newDirection));
-
- return state.toBaseBlock(builder.build());
+ return state.toBaseBlock(
+ tag.putByte("Rot", (byte) MCDirections.toRotation(newDirection))
+ );
}
}
}
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 591dcca399..1624254215 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
@@ -19,11 +19,6 @@
package com.sk89q.worldedit.internal.cui;
-import com.sk89q.jnbt.ByteTag;
-import com.sk89q.jnbt.CompoundTag;
-import com.sk89q.jnbt.IntTag;
-import com.sk89q.jnbt.StringTag;
-import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@@ -33,11 +28,13 @@
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.ByteBinaryTag;
+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.BlockTypes;
-import java.util.HashMap;
-import java.util.Map;
import javax.annotation.Nullable;
/**
@@ -126,7 +123,7 @@ public static BaseBlock createStructureBlock(Player player) {
int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12);
int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3));
- Map structureTag = new HashMap<>();
+ CompoundBinaryTag.Builder structureTag = CompoundBinaryTag.builder();
posX -= x;
posY -= y;
@@ -137,25 +134,25 @@ public static BaseBlock createStructureBlock(Player player) {
return null;
}
- structureTag.put("name", new StringTag("worldedit:" + player.getName()));
- structureTag.put("author", new StringTag(player.getName()));
- structureTag.put("metadata", new StringTag(""));
- structureTag.put("x", new IntTag(x));
- structureTag.put("y", new IntTag(y));
- structureTag.put("z", new IntTag(z));
- structureTag.put("posX", new IntTag(posX));
- structureTag.put("posY", new IntTag(posY));
- structureTag.put("posZ", new IntTag(posZ));
- structureTag.put("sizeX", new IntTag(width));
- structureTag.put("sizeY", new IntTag(height));
- structureTag.put("sizeZ", new IntTag(length));
- structureTag.put("rotation", new StringTag("NONE"));
- structureTag.put("mirror", new StringTag("NONE"));
- structureTag.put("mode", new StringTag("SAVE"));
- structureTag.put("ignoreEntities", new ByteTag((byte) 1));
- structureTag.put("showboundingbox", new ByteTag((byte) 1));
- structureTag.put("id", new StringTag(BlockTypes.STRUCTURE_BLOCK.getId()));
-
- return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(new CompoundTag(structureTag));
+ structureTag.put("name", StringBinaryTag.of("worldedit:" + player.getName()));
+ structureTag.put("author", StringBinaryTag.of(player.getName()));
+ structureTag.put("metadata", StringBinaryTag.of(""));
+ structureTag.put("x", IntBinaryTag.of(x));
+ structureTag.put("y", IntBinaryTag.of(y));
+ structureTag.put("z", IntBinaryTag.of(z));
+ structureTag.put("posX", IntBinaryTag.of(posX));
+ structureTag.put("posY", IntBinaryTag.of(posY));
+ structureTag.put("posZ", IntBinaryTag.of(posZ));
+ structureTag.put("sizeX", IntBinaryTag.of(width));
+ structureTag.put("sizeY", IntBinaryTag.of(height));
+ structureTag.put("sizeZ", IntBinaryTag.of(length));
+ structureTag.put("rotation", StringBinaryTag.of("NONE"));
+ structureTag.put("mirror", StringBinaryTag.of("NONE"));
+ structureTag.put("mode", StringBinaryTag.of("SAVE"));
+ structureTag.put("ignoreEntities", ByteBinaryTag.of((byte) 1));
+ structureTag.put("showboundingbox", ByteBinaryTag.of((byte) 1));
+ structureTag.put("id", StringBinaryTag.of(BlockTypes.STRUCTURE_BLOCK.getId()));
+
+ return BlockTypes.STRUCTURE_BLOCK.getDefaultState().toBaseBlock(structureTag.build());
}
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/NbtUtils.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/NbtUtils.java
new file mode 100644
index 0000000000..17be01289b
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/NbtUtils.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.util;
+
+import com.sk89q.worldedit.util.nbt.BinaryTag;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+import com.sk89q.worldedit.world.storage.InvalidFormatException;
+
+public class NbtUtils {
+
+ /**
+ * Get child tag of a NBT structure.
+ *
+ * @param tag the tag to read from
+ * @param key the key to look for
+ * @param expected the expected NBT class type
+ * @return child tag
+ * @throws InvalidFormatException if the format of the items is invalid
+ */
+ public static T getChildTag(CompoundBinaryTag tag, String key, Class expected) throws InvalidFormatException {
+ BinaryTag childTag = tag.get(key);
+ if (childTag == null) {
+ throw new InvalidFormatException("Missing a \"" + key + "\" tag");
+ }
+
+ if (!expected.isInstance(childTag)) {
+ throw new InvalidFormatException(key + " tag is not of tag type " + expected.getName());
+ }
+ return expected.cast(childTag);
+ }
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java
index ee571c6436..21d480d692 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/Int2BaseBlockMap.java
@@ -50,7 +50,7 @@ class Int2BaseBlockMap extends AbstractInt2ObjectMap {
* @return the internal ID, or {@link BlockStateIdAccess#invalidId()} if not useful
*/
private static int optimizedInternalId(BaseBlock block) {
- if (block.hasNbtData()) {
+ if (block.hasNbt()) {
return BlockStateIdAccess.invalidId();
}
return BlockStateIdAccess.getBlockStateId(block.toImmutableState());
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 86ea9b454b..b2f6ae5423 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
@@ -19,7 +19,11 @@
package com.sk89q.worldedit.world;
+import com.sk89q.jnbt.AdventureNBTConverter;
import com.sk89q.jnbt.CompoundTag;
+import com.sk89q.worldedit.internal.util.DeprecationUtil;
+import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import javax.annotation.Nullable;
@@ -35,8 +39,12 @@ public interface NbtValued {
* must not return null if this method returns true.
*
* @return true if there is NBT data
+ * @deprecated See {@link #hasNbt()}
*/
- boolean hasNbtData();
+ @Deprecated
+ default boolean hasNbtData() {
+ return hasNbt();
+ }
/**
* Get the object's NBT data (tile entity data). The returned tag, if
@@ -49,15 +57,78 @@ public interface NbtValued {
* not return null.
*
* @return compound tag, or null
+ * @deprecated See {@link #getNbt()}
*/
+ @Deprecated
@Nullable
- CompoundTag getNbtData();
+ default CompoundTag getNbtData() {
+ return AdventureNBTConverter.fromAdventure(getNbt());
+ }
/**
* Set the object's NBT data (tile entity data).
*
* @param nbtData NBT data, or null if no data
+ * @deprecated See {@link #setNbt(CompoundBinaryTag)}
*/
- void setNbtData(@Nullable CompoundTag nbtData);
+ @Deprecated
+ default void setNbtData(@Nullable CompoundTag nbtData) {
+ setNbt(nbtData == null ? null : nbtData.asBinaryTag());
+ }
+
+ /**
+ * Returns whether the block contains NBT data. {@link #getNbt()} ()}
+ * must not return null if this method returns true.
+ *
+ * @return true if there is NBT data
+ */
+ @NonAbstractForCompatibility(
+ delegateName = "hasNbtData",
+ delegateParams = { }
+ )
+ default boolean hasNbt() {
+ DeprecationUtil.checkDelegatingOverride(getClass());
+
+ return hasNbtData();
+ }
+
+ /**
+ * Get the object's NBT data (tile entity data). The returned tag, if
+ * modified in any way, should be sent to {@link #setNbt(CompoundBinaryTag)}
+ * so that the instance knows of the changes. Making changes without
+ * calling {@link #setNbt(CompoundBinaryTag)} could have unintended
+ * consequences.
+ *
+ * {@link #hasNbt()} must return true if and only if method does
+ * not return null.
+ *
+ * @return compound tag, or null
+ */
+ @NonAbstractForCompatibility(
+ delegateName = "getNbtData",
+ delegateParams = { }
+ )
+ @Nullable
+ default CompoundBinaryTag getNbt() {
+ DeprecationUtil.checkDelegatingOverride(getClass());
+
+ CompoundTag nbtData = getNbtData();
+ return nbtData == null ? null : nbtData.asBinaryTag();
+ }
+
+ /**
+ * Set the object's NBT data (tile entity data).
+ *
+ * @param nbtData NBT data, or null if no data
+ */
+ @NonAbstractForCompatibility(
+ delegateName = "setNbtData",
+ delegateParams = { CompoundTag.class }
+ )
+ default void setNbt(@Nullable CompoundBinaryTag nbtData) {
+ DeprecationUtil.checkDelegatingOverride(getClass());
+
+ setNbtData(nbtData == null ? null : AdventureNBTConverter.fromAdventure(nbtData));
+ }
}
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 a7d50f6b1c..a488f59057 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
@@ -20,11 +20,13 @@
package com.sk89q.worldedit.world.block;
import com.sk89q.jnbt.CompoundTag;
-import com.sk89q.jnbt.StringTag;
-import com.sk89q.jnbt.Tag;
+import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.registry.state.Property;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+import com.sk89q.worldedit.util.nbt.TagStringIO;
+import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
@@ -44,7 +46,7 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock {
private final BlockState blockState;
@Nullable
- private final CompoundTag nbtData;
+ private final CompoundBinaryTag nbtData;
/**
* Construct a block with a state.
@@ -62,7 +64,19 @@ protected BaseBlock(BlockState blockState) {
* @param state The block state
* @param nbtData NBT data, which must be provided
*/
+ @Deprecated
protected BaseBlock(BlockState state, CompoundTag nbtData) {
+ this(state, checkNotNull(nbtData).asBinaryTag());
+ }
+
+
+ /**
+ * Construct a block with the given ID, data value and NBT data structure.
+ *
+ * @param state The block state
+ * @param nbtData NBT data, which must be provided
+ */
+ protected BaseBlock(BlockState state, CompoundBinaryTag nbtData) {
checkNotNull(nbtData);
this.blockState = state;
this.nbtData = nbtData;
@@ -85,7 +99,7 @@ public BlockType getBlockType() {
@Override
public BaseBlock with(Property property, V value) {
- return this.blockState.with(property, value).toBaseBlock(getNbtData());
+ return this.blockState.with(property, value).toBaseBlock(getNbt());
}
/**
@@ -99,33 +113,28 @@ public V getState(Property property) {
return this.blockState.getState(property);
}
- @Override
- public boolean hasNbtData() {
- return getNbtData() != null;
- }
-
@Override
public String getNbtId() {
- CompoundTag nbtData = getNbtData();
+ CompoundBinaryTag nbtData = this.nbtData;
if (nbtData == null) {
return "";
}
- Tag idTag = nbtData.getValue().get("id");
- if (idTag instanceof StringTag) {
- return ((StringTag) idTag).getValue();
- } else {
- return "";
- }
+ return nbtData.getString("id");
+ }
+
+ @Override
+ public boolean hasNbt() {
+ return this.nbtData != null;
}
@Nullable
@Override
- public CompoundTag getNbtData() {
+ public CompoundBinaryTag getNbt() {
return this.nbtData;
}
@Override
- public void setNbtData(@Nullable CompoundTag nbtData) {
+ public void setNbt(@Nullable CompoundBinaryTag nbtData) {
throw new UnsupportedOperationException("This class is immutable.");
}
@@ -135,7 +144,7 @@ public void setNbtData(@Nullable CompoundTag nbtData) {
@Override
public boolean equals(Object o) {
if (!(o instanceof BaseBlock)) {
- if (!hasNbtData() && o instanceof BlockStateHolder) {
+ if (!hasNbt() && o instanceof BlockStateHolder) {
return Objects.equals(toImmutableState(), ((BlockStateHolder>) o).toImmutableState());
}
return false;
@@ -143,7 +152,7 @@ public boolean equals(Object o) {
final BaseBlock otherBlock = (BaseBlock) o;
- return this.blockState.equalsFuzzy(otherBlock.blockState) && Objects.equals(getNbtData(), otherBlock.getNbtData());
+ return this.blockState.equalsFuzzy(otherBlock.blockState) && Objects.equals(getNbt(), otherBlock.getNbt());
}
/**
@@ -167,8 +176,22 @@ public BaseBlock toBaseBlock() {
return this;
}
+ @Deprecated
@Override
public BaseBlock toBaseBlock(CompoundTag compoundTag) {
+ if (compoundTag == null) {
+ return this.blockState.toBaseBlock();
+ } else if (compoundTag.asBinaryTag() == this.nbtData) {
+ // The above reference equality check is fine, as JNBT classes contain an internal
+ // Adventure reference.
+ return this;
+ } else {
+ return new BaseBlock(this.blockState, compoundTag);
+ }
+ }
+
+ @Override
+ public BaseBlock toBaseBlock(CompoundBinaryTag compoundTag) {
if (compoundTag == null) {
return this.blockState.toBaseBlock();
} else if (compoundTag == this.nbtData) {
@@ -181,16 +204,24 @@ public BaseBlock toBaseBlock(CompoundTag compoundTag) {
@Override
public int hashCode() {
int ret = toImmutableState().hashCode() << 3;
- if (hasNbtData()) {
- ret += getNbtData().hashCode();
+ if (hasNbt()) {
+ ret += getNbt().hashCode();
}
return ret;
}
@Override
public String toString() {
- // TODO use a json serializer for the NBT data
- return blockState.getAsString() + (hasNbtData() ? "{hasNbt}" : "");
+ String nbtString = "";
+ if (hasNbt()) {
+ try {
+ nbtString = TagStringIO.get().asString(getNbt());
+ } catch (IOException e) {
+ WorldEdit.logger.error("Failed to parse NBT of Block", e);
+ }
+ }
+
+ 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 fdbdd92d42..be4584b03b 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java
@@ -28,6 +28,7 @@
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.registry.state.Property;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import java.util.Collections;
import java.util.Comparator;
@@ -210,6 +211,7 @@ public BaseBlock toBaseBlock() {
return this.emptyBaseBlock;
}
+ @Deprecated
@Override
public BaseBlock toBaseBlock(CompoundTag compoundTag) {
if (compoundTag == null) {
@@ -218,6 +220,14 @@ public BaseBlock toBaseBlock(CompoundTag compoundTag) {
return new BaseBlock(this, compoundTag);
}
+ @Override
+ public BaseBlock toBaseBlock(CompoundBinaryTag compoundTag) {
+ if (compoundTag == null) {
+ return toBaseBlock();
+ }
+ return new BaseBlock(this, compoundTag);
+ }
+
/**
* Internal method used for creating the initial BlockState.
*
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 93aaa55ed4..875da7895d 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java
@@ -19,10 +19,12 @@
package com.sk89q.worldedit.world.block;
+import com.sk89q.jnbt.AdventureNBTConverter;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.Property;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import java.util.Locale;
import java.util.Map;
@@ -88,9 +90,21 @@ public interface BlockStateHolder> extends Pattern
*
* @param compoundTag The NBT Data to apply
* @return The BaseBlock
+ * @deprecated Use {@link BlockStateHolder#toBaseBlock(CompoundBinaryTag)}.
*/
+ @Deprecated
BaseBlock toBaseBlock(CompoundTag compoundTag);
+ /**
+ * Gets a {@link BaseBlock} from this BlockStateHolder.
+ *
+ * @param compoundTag The NBT Data to apply
+ * @return The BaseBlock
+ */
+ default BaseBlock toBaseBlock(CompoundBinaryTag compoundTag) {
+ return toBaseBlock(AdventureNBTConverter.fromAdventure(compoundTag));
+ }
+
@Override
default BaseBlock applyBlock(BlockVector3 position) {
return toBaseBlock();
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 dd8e407b94..8ecd71034d 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,15 +19,16 @@
package com.sk89q.worldedit.world.chunk;
-import com.sk89q.jnbt.ByteArrayTag;
-import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.CompoundTag;
-import com.sk89q.jnbt.IntTag;
-import com.sk89q.jnbt.ListTag;
-import com.sk89q.jnbt.NBTUtils;
-import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.util.NbtUtils;
+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.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;
@@ -36,63 +37,74 @@
import com.sk89q.worldedit.world.storage.InvalidFormatException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
public class AnvilChunk implements Chunk {
- private final CompoundTag rootTag;
+ private final CompoundBinaryTag 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)}
*/
public AnvilChunk(CompoundTag tag) throws DataException {
+ this(tag.asBinaryTag());
+ }
+
+ /**
+ * Construct the chunk with a compound tag.
+ *
+ * @param tag the tag to read
+ * @throws DataException on a data error
+ */
+ public AnvilChunk(CompoundBinaryTag tag) throws DataException {
rootTag = tag;
- rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue();
- rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue();
+ rootX = NbtUtils.getChildTag(rootTag, "xPos", IntBinaryTag.class).value();
+ rootZ = NbtUtils.getChildTag(rootTag, "zPos", IntBinaryTag.class).value();
blocks = new byte[16][16 * 16 * 16];
blocksAdd = new byte[16][16 * 16 * 8];
data = new byte[16][16 * 16 * 8];
- List sections = NBTUtils.getChildTag(rootTag.getValue(), "Sections", ListTag.class).getValue();
+ ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", ListBinaryTag.class);
- for (Tag rawSectionTag : sections) {
- if (!(rawSectionTag instanceof CompoundTag)) {
+ for (BinaryTag rawSectionTag : sections) {
+ if (!(rawSectionTag instanceof CompoundBinaryTag)) {
continue;
}
- CompoundTag sectionTag = (CompoundTag) rawSectionTag;
- if (!sectionTag.getValue().containsKey("Y")) {
+ CompoundBinaryTag sectionTag = (CompoundBinaryTag) rawSectionTag;
+ if (sectionTag.get("Y") == null) {
continue; // Empty section.
}
- int y = NBTUtils.getChildTag(sectionTag.getValue(), "Y", ByteTag.class).getValue();
+ int y = NbtUtils.getChildTag(sectionTag, "Y", ByteBinaryTag.class).value();
if (y < 0 || y >= 16) {
continue;
}
- blocks[y] = NBTUtils.getChildTag(sectionTag.getValue(),
- "Blocks", ByteArrayTag.class).getValue();
- data[y] = NBTUtils.getChildTag(sectionTag.getValue(), "Data",
- ByteArrayTag.class).getValue();
+ blocks[y] = NbtUtils.getChildTag(sectionTag,
+ "Blocks", ByteArrayBinaryTag.class).value();
+ data[y] = NbtUtils.getChildTag(sectionTag, "Data",
+ ByteArrayBinaryTag.class).value();
// 4096 ID block support
- if (sectionTag.getValue().containsKey("Add")) {
- blocksAdd[y] = NBTUtils.getChildTag(sectionTag.getValue(),
- "Add", ByteArrayTag.class).getValue();
+ if (sectionTag.get("Add") != null) {
+ blocksAdd[y] = NbtUtils.getChildTag(sectionTag,
+ "Add", ByteArrayBinaryTag.class).value();
}
}
@@ -179,50 +191,49 @@ private int getBlockData(BlockVector3 position) throws DataException {
* Used to load the tile entities.
*/
private void populateTileEntities() throws DataException {
- List tags = NBTUtils.getChildTag(rootTag.getValue(),
- "TileEntities", ListTag.class).getValue();
+ ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", ListBinaryTag.class);
tileEntities = new HashMap<>();
- for (Tag tag : tags) {
- if (!(tag instanceof CompoundTag)) {
+ for (BinaryTag tag : tags) {
+ if (!(tag instanceof CompoundBinaryTag)) {
throw new InvalidFormatException("CompoundTag expected in TileEntities");
}
- CompoundTag t = (CompoundTag) tag;
+ CompoundBinaryTag t = (CompoundBinaryTag) tag;
int x = 0;
int y = 0;
int z = 0;
- Map values = new HashMap<>();
+ CompoundBinaryTag.Builder values = CompoundBinaryTag.builder();
- for (Map.Entry entry : t.getValue().entrySet()) {
- switch (entry.getKey()) {
+ for (String key : t.keySet()) {
+ BinaryTag value = t.get(key);
+ switch (key) {
case "x":
- if (entry.getValue() instanceof IntTag) {
- x = ((IntTag) entry.getValue()).getValue();
+ if (value instanceof IntBinaryTag) {
+ x = ((IntBinaryTag) value).value();
}
break;
case "y":
- if (entry.getValue() instanceof IntTag) {
- y = ((IntTag) entry.getValue()).getValue();
+ if (value instanceof IntBinaryTag) {
+ y = ((IntBinaryTag) value).value();
}
break;
case "z":
- if (entry.getValue() instanceof IntTag) {
- z = ((IntTag) entry.getValue()).getValue();
+ if (value instanceof IntBinaryTag) {
+ z = ((IntBinaryTag) value).value();
}
break;
default:
break;
}
- values.put(entry.getKey(), entry.getValue());
+ values.put(key, value);
}
-
BlockVector3 vec = BlockVector3.at(x, y, z);
- tileEntities.put(vec, values);
+ tileEntities.put(vec, values.build());
}
}
@@ -236,17 +247,17 @@ private void populateTileEntities() throws DataException {
* @throws DataException thrown if there is a data error
*/
@Nullable
- private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException {
+ private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException {
if (tileEntities == null) {
populateTileEntities();
}
- Map values = tileEntities.get(position);
+ CompoundBinaryTag values = tileEntities.get(position);
if (values == null) {
return null;
}
- return new CompoundTag(values);
+ return values;
}
@Override
@@ -259,7 +270,7 @@ public BaseBlock getBlock(BlockVector3 position) throws DataException {
WorldEdit.logger.warn("Unknown legacy block " + id + ":" + data + " found when loading legacy anvil chunk.");
return BlockTypes.AIR.getDefaultState().toBaseBlock();
}
- CompoundTag tileEntity = getBlockTileEntity(position);
+ CompoundBinaryTag 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 512649c45a..dd3bfdbe6d 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,15 +19,17 @@
package com.sk89q.worldedit.world.chunk;
-import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.CompoundTag;
-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.NbtUtils;
+import com.sk89q.worldedit.util.nbt.BinaryTag;
+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.ListBinaryTag;
+import com.sk89q.worldedit.util.nbt.LongArrayBinaryTag;
import com.sk89q.worldedit.world.DataException;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@@ -36,7 +38,6 @@
import com.sk89q.worldedit.world.storage.InvalidFormatException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -45,62 +46,75 @@
*/
public class AnvilChunk13 implements Chunk {
- private final CompoundTag rootTag;
+ private final CompoundBinaryTag rootTag;
private final BlockState[][] blocks;
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 #AnvilChunk13(CompoundBinaryTag)}
*/
+ @Deprecated
public AnvilChunk13(CompoundTag tag) throws DataException {
+ this(tag.asBinaryTag());
+ }
+
+ /**
+ * Construct the chunk with a compound tag.
+ *
+ * @param tag the tag to read
+ * @throws DataException on a data error
+ */
+ public AnvilChunk13(CompoundBinaryTag tag) throws DataException {
rootTag = tag;
- rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue();
- rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue();
+ rootX = NbtUtils.getChildTag(rootTag, "xPos", IntBinaryTag.class).value();
+ rootZ = NbtUtils.getChildTag(rootTag, "zPos", IntBinaryTag.class).value();
blocks = new BlockState[16][];
- List sections = NBTUtils.getChildTag(rootTag.getValue(), "Sections", ListTag.class).getValue();
+ ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", ListBinaryTag.class);
- for (Tag rawSectionTag : sections) {
- if (!(rawSectionTag instanceof CompoundTag)) {
+ for (BinaryTag rawSectionTag : sections) {
+ if (!(rawSectionTag instanceof CompoundBinaryTag)) {
continue;
}
- CompoundTag sectionTag = (CompoundTag) rawSectionTag;
- if (!sectionTag.getValue().containsKey("Y")) {
+ CompoundBinaryTag sectionTag = (CompoundBinaryTag) rawSectionTag;
+ if (sectionTag.get("Y") == null) {
continue; // Empty section.
}
- int y = NBTUtils.getChildTag(sectionTag.getValue(), "Y", ByteTag.class).getValue();
+ int y = NbtUtils.getChildTag(sectionTag, "Y", ByteBinaryTag.class).value();
if (y < 0 || y >= 16) {
continue;
}
// parse palette
- List paletteEntries = sectionTag.getList("Palette", CompoundTag.class);
+ ListBinaryTag paletteEntries = sectionTag.getList("Palette", BinaryTagTypes.COMPOUND);
int paletteSize = paletteEntries.size();
if (paletteSize == 0) {
continue;
}
BlockState[] palette = new BlockState[paletteSize];
for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) {
- CompoundTag paletteEntry = paletteEntries.get(paletteEntryId);
+ CompoundBinaryTag paletteEntry = (CompoundBinaryTag) 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();
- if (paletteEntry.containsKey("Properties")) {
- CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class);
+ if (paletteEntry.get("Properties") != null) {
+ CompoundBinaryTag properties = NbtUtils.getChildTag(paletteEntry, "Properties", CompoundBinaryTag.class);
for (Property> property : blockState.getStates().keySet()) {
- if (properties.containsKey(property.getName())) {
+ if (properties.get(property.getName()) != null) {
String value = properties.getString(property.getName());
try {
blockState = getBlockStateWith(blockState, property, value);
@@ -114,7 +128,7 @@ public AnvilChunk13(CompoundTag tag) throws DataException {
}
// parse block states
- long[] blockStatesSerialized = NBTUtils.getChildTag(sectionTag.getValue(), "BlockStates", LongArrayTag.class).getValue();
+ long[] blockStatesSerialized = NbtUtils.getChildTag(sectionTag, "BlockStates", LongArrayBinaryTag.class).value();
BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16];
blocks[y] = chunkSectionBlocks;
@@ -166,26 +180,24 @@ private BlockState getBlockStateWith(BlockState source, Property property
*/
private void populateTileEntities() throws DataException {
tileEntities = new HashMap<>();
- if (!rootTag.getValue().containsKey("TileEntities")) {
+ if (rootTag.get("TileEntities") == null) {
return;
}
- List tags = NBTUtils.getChildTag(rootTag.getValue(),
- "TileEntities", ListTag.class).getValue();
+ ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", ListBinaryTag.class);
- for (Tag tag : tags) {
- if (!(tag instanceof CompoundTag)) {
+ for (BinaryTag tag : tags) {
+ if (!(tag instanceof CompoundBinaryTag)) {
throw new InvalidFormatException("CompoundTag expected in TileEntities");
}
- CompoundTag t = (CompoundTag) tag;
+ CompoundBinaryTag t = (CompoundBinaryTag) 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();
+ int x = ((IntBinaryTag) t.get("x")).value();
+ int y = ((IntBinaryTag) t.get("y")).value();
+ int z = ((IntBinaryTag) t.get("z")).value();
BlockVector3 vec = BlockVector3.at(x, y, z);
- tileEntities.put(vec, values);
+ tileEntities.put(vec, t);
}
}
@@ -199,17 +211,17 @@ private void populateTileEntities() throws DataException {
* @throws DataException thrown if there is a data error
*/
@Nullable
- private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException {
+ private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException {
if (tileEntities == null) {
populateTileEntities();
}
- Map values = tileEntities.get(position);
+ CompoundBinaryTag values = tileEntities.get(position);
if (values == null) {
return null;
}
- return new CompoundTag(values);
+ return values;
}
@Override
@@ -228,7 +240,7 @@ public BaseBlock getBlock(BlockVector3 position) throws DataException {
BlockState[] sectionBlocks = blocks[section];
BlockState state = sectionBlocks != null ? sectionBlocks[(yIndex << 8) | (z << 4) | x] : BlockTypes.AIR.getDefaultState();
- CompoundTag tileEntity = getBlockTileEntity(position);
+ CompoundBinaryTag tileEntity = getBlockTileEntity(position);
if (tileEntity != null) {
return state.toBaseBlock(tileEntity);
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 bd9d5e08a5..13e69458ae 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,6 +20,7 @@
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;
@@ -34,11 +35,23 @@ public class AnvilChunk16 extends AnvilChunk13 {
*
* @param tag the tag to read
* @throws DataException on a data error
+ * @deprecated Use {@link #AnvilChunk16(CompoundBinaryTag)}
*/
+ @Deprecated
public AnvilChunk16(CompoundTag tag) throws DataException {
super(tag);
}
+ /**
+ * Construct the chunk with a compound tag.
+ *
+ * @param tag the tag to read
+ * @throws DataException on a data error
+ */
+ public AnvilChunk16(CompoundBinaryTag tag) throws DataException {
+ super(tag);
+ }
+
@Override
protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException {
PackedIntArrayReader reader = new PackedIntArrayReader(blockStatesSerialized);
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 8f5665c449..fa4288885b 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,14 +19,15 @@
package com.sk89q.worldedit.world.chunk;
-import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag;
-import com.sk89q.jnbt.IntTag;
-import com.sk89q.jnbt.ListTag;
-import com.sk89q.jnbt.NBTUtils;
-import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.util.NbtUtils;
+import com.sk89q.worldedit.util.nbt.BinaryTag;
+import com.sk89q.worldedit.util.nbt.ByteArrayBinaryTag;
+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;
@@ -35,7 +36,6 @@
import com.sk89q.worldedit.world.storage.InvalidFormatException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -43,27 +43,40 @@
*/
public class OldChunk implements Chunk {
- private final CompoundTag rootTag;
+ private final CompoundBinaryTag 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
public OldChunk(CompoundTag tag) throws DataException {
+ this(tag.asBinaryTag());
+ }
+
+ /**
+ * Construct the chunk with a compound tag.
+ *
+ * @param tag the tag
+ * @throws DataException if there is an error getting the chunk data
+ */
+ public OldChunk(CompoundBinaryTag tag) throws DataException {
rootTag = tag;
- blocks = NBTUtils.getChildTag(rootTag.getValue(), "Blocks", ByteArrayTag.class).getValue();
- data = NBTUtils.getChildTag(rootTag.getValue(), "Data", ByteArrayTag.class).getValue();
- rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue();
- rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue();
+ blocks = NbtUtils.getChildTag(rootTag, "Blocks", ByteArrayBinaryTag.class).value();
+ data = NbtUtils.getChildTag(rootTag, "Data", ByteArrayBinaryTag.class).value();
+ rootX = NbtUtils.getChildTag(rootTag, "xPos", IntBinaryTag.class).value();
+ rootZ = NbtUtils.getChildTag(rootTag, "zPos", IntBinaryTag.class).value();
int size = 16 * 16 * 128;
if (blocks.length != size) {
@@ -83,51 +96,50 @@ public OldChunk(CompoundTag tag) throws DataException {
* @throws DataException if there is an error getting the chunk data
*/
private void populateTileEntities() throws DataException {
- List tags = NBTUtils.getChildTag(
- rootTag.getValue(), "TileEntities", ListTag.class)
- .getValue();
+ ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", ListBinaryTag.class);
tileEntities = new HashMap<>();
- for (Tag tag : tags) {
- if (!(tag instanceof CompoundTag)) {
+ for (BinaryTag tag : tags) {
+ if (!(tag instanceof CompoundBinaryTag)) {
throw new InvalidFormatException("CompoundTag expected in TileEntities");
}
- CompoundTag t = (CompoundTag) tag;
+ CompoundBinaryTag t = (CompoundBinaryTag) tag;
int x = 0;
int y = 0;
int z = 0;
- Map values = new HashMap<>();
+ CompoundBinaryTag.Builder values = CompoundBinaryTag.builder();
- for (Map.Entry entry : t.getValue().entrySet()) {
- switch (entry.getKey()) {
+ for (String key : t.keySet()) {
+ BinaryTag value = t.get(key);
+ switch (key) {
case "x":
- if (entry.getValue() instanceof IntTag) {
- x = ((IntTag) entry.getValue()).getValue();
+ if (value instanceof IntBinaryTag) {
+ x = ((IntBinaryTag) value).value();
}
break;
case "y":
- if (entry.getValue() instanceof IntTag) {
- y = ((IntTag) entry.getValue()).getValue();
+ if (value instanceof IntBinaryTag) {
+ y = ((IntBinaryTag) value).value();
}
break;
case "z":
- if (entry.getValue() instanceof IntTag) {
- z = ((IntTag) entry.getValue()).getValue();
+ if (value instanceof IntBinaryTag) {
+ z = ((IntBinaryTag) value).value();
}
break;
default:
break;
}
- values.put(entry.getKey(), entry.getValue());
+ values.put(key, value);
}
BlockVector3 vec = BlockVector3.at(x, y, z);
- tileEntities.put(vec, values);
+ tileEntities.put(vec, values.build());
}
}
@@ -140,16 +152,16 @@ private void populateTileEntities() throws DataException {
* @return a tag
* @throws DataException if there is an error getting the chunk data
*/
- private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException {
+ private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException {
if (tileEntities == null) {
populateTileEntities();
}
- Map values = tileEntities.get(position);
+ CompoundBinaryTag values = tileEntities.get(position);
if (values == null) {
return null;
}
- return new CompoundTag(values);
+ return values;
}
@Override
@@ -189,7 +201,7 @@ public BaseBlock getBlock(BlockVector3 position) throws DataException {
return BlockTypes.AIR.getDefaultState().toBaseBlock();
}
- CompoundTag tileEntity = getBlockTileEntity(position);
+ CompoundBinaryTag tileEntity = getBlockTileEntity(position);
if (tileEntity != null) {
return state.toBaseBlock(tileEntity);
diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json
index 2ed98270c1..a48412d5d7 100644
--- a/worldedit-core/src/main/resources/lang/strings.json
+++ b/worldedit-core/src/main/resources/lang/strings.json
@@ -331,6 +331,7 @@
"worldedit.error.invalid-number.matches": "Number expected; string \"{0}\" given.",
"worldedit.error.incomplete-region": "Make a region selection first.",
"worldedit.error.unknown-block": "Block name '{0}' was not recognized.",
+ "worldedit.error.unknown-item": "Item name '{0}' was not recognized.",
"worldedit.error.unknown-entity": "Entity name '{0}' was not recognized.",
"worldedit.error.unknown-mob": "Mob name '{0}' was not recognized.",
"worldedit.error.unknown-biome": "Biome name '{0}' was not recognized.",
@@ -372,6 +373,7 @@
"worldedit.error.parser.missing-random-type": "Missing the type after the % symbol for '{0}'",
"worldedit.error.parser.clipboard.missing-coordinates": "Clipboard offset needs x,y,z coordinates.",
"worldedit.error.parser.player-only": "Input '{0}' requires a player!",
+ "worldedit.error.parser.invalid-nbt": "Invalid NBT Data in input: '{0}'. Error: {1}",
"worldedit.error.disabled": "This functionality is disabled (see WorldEdit configuration).",
"worldedit.error.unknown": "Unknown error occurred: {0}",
"worldedit.error.missing-extent": "No Extent is known",
diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts
index d669216d6d..26fdba8be4 100644
--- a/worldedit-libs/core/build.gradle.kts
+++ b/worldedit-libs/core/build.gradle.kts
@@ -13,4 +13,5 @@ dependencies {
"shade"("org.enginehub.piston:core:${Versions.PISTON}")
"shade"("org.enginehub.piston.core-ap:runtime:${Versions.PISTON}")
"shade"("org.enginehub.piston:default-impl:${Versions.PISTON}")
+ "shade"("net.kyori:adventure-nbt:4.4.0")
}
diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java
index c37535160c..540808475d 100644
--- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java
+++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java
@@ -168,7 +168,7 @@ public > boolean setBlock(BlockVector3 position, B
snapshot.restore(true, notifyAndLight ? BlockChangeFlags.ALL : BlockChangeFlags.NONE);
// Create the TileEntity
- if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) {
+ if (block instanceof BaseBlock && ((BaseBlock) block).hasNbt()) {
// Kill the old TileEntity
world.getTileEntity(pos).ifPresent(tileEntity -> applyTileEntityData(tileEntity, (BaseBlock) block));
}
@@ -301,7 +301,7 @@ public Entity createEntity(Location location, BaseEntity entity) {
Vector3d pos = new Vector3d(location.getX(), location.getY(), location.getZ());
org.spongepowered.api.entity.Entity newEnt = world.createEntity(entityType, pos);
- if (entity.hasNbtData()) {
+ if (entity.hasNbt()) {
applyEntityData(newEnt, entity);
}
From 85c150e017fb79d93e903ab72c0b5789efddd96f Mon Sep 17 00:00:00 2001
From: Octavia Togami
Date: Sat, 6 Feb 2021 02:51:44 -0800
Subject: [PATCH 02/10] =?UTF-8?q?assorted=20changes=E2=84=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/com/sk89q/jnbt/NBTInputStream.java | 120 +--------
.../java/com/sk89q/jnbt/NBTOutputStream.java | 239 +-----------------
2 files changed, 17 insertions(+), 342 deletions(-)
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 1b41180851..3c9d701e9e 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTInputStream.java
@@ -19,13 +19,14 @@
package com.sk89q.jnbt;
+import com.sk89q.worldedit.util.nbt.BinaryTagIO;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+
import java.io.Closeable;
+import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -63,115 +64,10 @@ public NBTInputStream(InputStream is) {
* @throws IOException if an I/O error occurs.
*/
public NamedTag readNamedTag() throws IOException {
- return readNamedTag(0);
- }
-
- /**
- * Reads an NBT from the stream.
- *
- * @param depth the depth of this tag
- * @return The tag that was read.
- * @throws IOException if an I/O error occurs.
- */
- private NamedTag readNamedTag(int depth) throws IOException {
- int type = is.readByte() & 0xFF;
-
- String name;
- if (type != NBTConstants.TYPE_END) {
- int nameLength = is.readShort() & 0xFFFF;
- byte[] nameBytes = new byte[nameLength];
- is.readFully(nameBytes);
- name = new String(nameBytes, NBTConstants.CHARSET);
- } else {
- name = "";
- }
-
- return new NamedTag(name, readTagPayload(type, depth));
- }
-
- /**
- * Reads the payload of a tag given the type.
- *
- * @param type the type
- * @param depth the depth
- * @return the tag
- * @throws IOException if an I/O error occurs.
- */
- private Tag readTagPayload(int type, int depth) throws IOException {
- switch (type) {
- case NBTConstants.TYPE_END:
- if (depth == 0) {
- throw new IOException(
- "TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
- } else {
- return new EndTag();
- }
- case NBTConstants.TYPE_BYTE:
- return new ByteTag(is.readByte());
- case NBTConstants.TYPE_SHORT:
- return new ShortTag(is.readShort());
- case NBTConstants.TYPE_INT:
- return new IntTag(is.readInt());
- case NBTConstants.TYPE_LONG:
- return new LongTag(is.readLong());
- case NBTConstants.TYPE_FLOAT:
- return new FloatTag(is.readFloat());
- case NBTConstants.TYPE_DOUBLE:
- return new DoubleTag(is.readDouble());
- case NBTConstants.TYPE_BYTE_ARRAY:
- int length = is.readInt();
- byte[] bytes = new byte[length];
- is.readFully(bytes);
- return new ByteArrayTag(bytes);
- case NBTConstants.TYPE_STRING:
- length = is.readShort();
- bytes = new byte[length];
- is.readFully(bytes);
- return new StringTag(new String(bytes, NBTConstants.CHARSET));
- case NBTConstants.TYPE_LIST:
- int childType = is.readByte();
- length = is.readInt();
-
- List tagList = new ArrayList<>();
- for (int i = 0; i < length; ++i) {
- Tag tag = readTagPayload(childType, depth + 1);
- if (tag instanceof EndTag) {
- throw new IOException("TAG_End not permitted in a list.");
- }
- tagList.add(tag);
- }
-
- return new ListTag(NBTUtils.getTypeClass(childType), tagList);
- case NBTConstants.TYPE_COMPOUND:
- Map tagMap = new HashMap<>();
- while (true) {
- NamedTag namedTag = readNamedTag(depth + 1);
- Tag tag = namedTag.getTag();
- if (tag instanceof EndTag) {
- break;
- } else {
- tagMap.put(namedTag.getName(), tag);
- }
- }
-
- return new CompoundTag(tagMap);
- case NBTConstants.TYPE_INT_ARRAY:
- length = is.readInt();
- int[] data = new int[length];
- for (int i = 0; i < length; i++) {
- data[i] = is.readInt();
- }
- return new IntArrayTag(data);
- case NBTConstants.TYPE_LONG_ARRAY:
- length = is.readInt();
- long[] longData = new long[length];
- for (int i = 0; i < length; i++) {
- longData[i] = is.readLong();
- }
- return new LongArrayTag(longData);
- default:
- throw new IOException("Invalid tag type: " + type + ".");
- }
+ Map.Entry named = BinaryTagIO.reader().readNamed(
+ (DataInput) this.is
+ );
+ return new NamedTag(named.getKey(), new CompoundTag(named.getValue()));
}
@Override
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 ae92946ae0..59fc92bc31 100644
--- a/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java
+++ b/worldedit-core/src/main/java/com/sk89q/jnbt/NBTOutputStream.java
@@ -19,7 +19,12 @@
package com.sk89q.jnbt;
+import com.google.common.collect.Maps;
+import com.sk89q.worldedit.util.nbt.BinaryTagIO;
+import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
+
import java.io.Closeable;
+import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -70,236 +75,10 @@ public NBTOutputStream(OutputStream os) throws IOException {
* if an I/O error occurs.
*/
public void writeNamedTag(String name, Tag tag) throws IOException {
- checkNotNull(name);
- checkNotNull(tag);
-
- int type = NBTUtils.getTypeCode(tag.getClass());
- byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
-
- os.writeByte(type);
- os.writeShort(nameBytes.length);
- os.write(nameBytes);
-
- if (type == NBTConstants.TYPE_END) {
- throw new IOException("Named TAG_End not permitted.");
- }
-
- writeTagPayload(tag);
- }
-
- /**
- * Writes tag payload.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeTagPayload(Tag tag) throws IOException {
- int type = NBTUtils.getTypeCode(tag.getClass());
- switch (type) {
- case NBTConstants.TYPE_END:
- writeEndTagPayload((EndTag) tag);
- break;
- case NBTConstants.TYPE_BYTE:
- writeByteTagPayload((ByteTag) tag);
- break;
- case NBTConstants.TYPE_SHORT:
- writeShortTagPayload((ShortTag) tag);
- break;
- case NBTConstants.TYPE_INT:
- writeIntTagPayload((IntTag) tag);
- break;
- case NBTConstants.TYPE_LONG:
- writeLongTagPayload((LongTag) tag);
- break;
- case NBTConstants.TYPE_FLOAT:
- writeFloatTagPayload((FloatTag) tag);
- break;
- case NBTConstants.TYPE_DOUBLE:
- writeDoubleTagPayload((DoubleTag) tag);
- break;
- case NBTConstants.TYPE_BYTE_ARRAY:
- writeByteArrayTagPayload((ByteArrayTag) tag);
- break;
- case NBTConstants.TYPE_STRING:
- writeStringTagPayload((StringTag) tag);
- break;
- case NBTConstants.TYPE_LIST:
- writeListTagPayload((ListTag) tag);
- break;
- case NBTConstants.TYPE_COMPOUND:
- writeCompoundTagPayload((CompoundTag) tag);
- break;
- case NBTConstants.TYPE_INT_ARRAY:
- writeIntArrayTagPayload((IntArrayTag) tag);
- break;
- case NBTConstants.TYPE_LONG_ARRAY:
- writeLongArrayTagPayload((LongArrayTag) tag);
- break;
- default:
- throw new IOException("Invalid tag type: " + type + ".");
- }
- }
-
- /**
- * Writes a {@code TAG_Byte} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeByteTagPayload(ByteTag tag) throws IOException {
- os.writeByte(tag.getValue());
- }
-
- /**
- * Writes a {@code TAG_Byte_Array} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeByteArrayTagPayload(ByteArrayTag tag) throws IOException {
- byte[] bytes = tag.getValue();
- os.writeInt(bytes.length);
- os.write(bytes);
- }
-
- /**
- * Writes a {@code TAG_Compound} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeCompoundTagPayload(CompoundTag tag) throws IOException {
- for (Map.Entry entry : tag.getValue().entrySet()) {
- writeNamedTag(entry.getKey(), entry.getValue());
- }
- os.writeByte((byte) 0); // end tag - better way?
- }
-
- /**
- * Writes a {@code TAG_List} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeListTagPayload(ListTag tag) throws IOException {
- Class extends Tag> clazz = tag.getType();
- List tags = tag.getValue();
- int size = tags.size();
-
- os.writeByte(NBTUtils.getTypeCode(clazz));
- os.writeInt(size);
- for (Tag tag1 : tags) {
- writeTagPayload(tag1);
- }
- }
-
- /**
- * Writes a {@code TAG_String} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeStringTagPayload(StringTag tag) throws IOException {
- byte[] bytes = tag.getValue().getBytes(NBTConstants.CHARSET);
- os.writeShort(bytes.length);
- os.write(bytes);
- }
-
- /**
- * Writes a {@code TAG_Double} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeDoubleTagPayload(DoubleTag tag) throws IOException {
- os.writeDouble(tag.getValue());
- }
-
- /**
- * Writes a {@code TAG_Float} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeFloatTagPayload(FloatTag tag) throws IOException {
- os.writeFloat(tag.getValue());
- }
-
- /**
- * Writes a {@code TAG_Long} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeLongTagPayload(LongTag tag) throws IOException {
- os.writeLong(tag.getValue());
- }
-
- /**
- * Writes a {@code TAG_Int} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeIntTagPayload(IntTag tag) throws IOException {
- os.writeInt(tag.getValue());
- }
-
- /**
- * Writes a {@code TAG_Short} tag.
- *
- * @param tag
- * The tag.
- * @throws IOException
- * if an I/O error occurs.
- */
- private void writeShortTagPayload(ShortTag tag) throws IOException {
- os.writeShort(tag.getValue());
- }
-
- /**
- * Writes a {@code TAG_Empty} tag.
- *
- * @param tag the tag
- */
- private void writeEndTagPayload(EndTag tag) {
- /* empty */
- }
-
- private void writeIntArrayTagPayload(IntArrayTag tag) throws IOException {
- int[] data = tag.getValue();
- os.writeInt(data.length);
- for (int aData : data) {
- os.writeInt(aData);
- }
- }
-
- private void writeLongArrayTagPayload(LongArrayTag tag) throws IOException {
- long[] data = tag.getValue();
- os.writeInt(data.length);
- for (long aData : data) {
- os.writeLong(aData);
- }
+ BinaryTagIO.writer().writeNamed(
+ Maps.immutableEntry(name, (CompoundBinaryTag) tag.asBinaryTag()),
+ (DataOutput) this.os
+ );
}
@Override
From 4ac2bb3e2573db0ae63eea388da97e33837260e2 Mon Sep 17 00:00:00 2001
From: Matthew Miller
Date: Mon, 8 Feb 2021 21:48:59 +1000
Subject: [PATCH 03/10] Further work on migrating to Adventure NBT
---
.../sk89q/worldedit/bukkit/BukkitPlayer.java | 2 +-
.../bukkit/adapter/BukkitImplAdapter.java | 4 +-
.../src/main/resources/worldedit-adapters.jar | Bin 669759 -> 440499 bytes
.../com/sk89q/worldedit/blocks/BaseItem.java | 4 +-
.../internal/wna/WorldNativeAccess.java | 22 +-
.../com/sk89q/worldedit/world/NbtValued.java | 3 +-
.../sk89q/worldedit/fabric/FabricAdapter.java | 18 +-
.../worldedit/fabric/FabricDataFixer.java | 14 +-
.../sk89q/worldedit/fabric/FabricPlayer.java | 5 +-
.../sk89q/worldedit/fabric/FabricWorld.java | 8 +-
.../internal/FabricWorldNativeAccess.java | 3 +-
.../fabric/internal/NBTConverter.java | 201 +++++++++---------
.../sk89q/worldedit/forge/ForgeAdapter.java | 18 +-
.../sk89q/worldedit/forge/ForgeDataFixer.java | 14 +-
.../sk89q/worldedit/forge/ForgePlayer.java | 4 +-
.../com/sk89q/worldedit/forge/ForgeWorld.java | 8 +-
.../internal/ForgeWorldNativeAccess.java | 4 +-
.../forge/internal/NBTConverter.java | 197 +++++++++--------
18 files changed, 260 insertions(+), 269 deletions(-)
diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
index 5f44d3ea0e..487dfb804a 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
@@ -299,7 +299,7 @@ public > void sendFakeBlock(BlockVector3 pos, B bl
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK) {
- adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData());
+ adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbt());
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 f3d46ebb22..c9e0743d31 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
@@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit.adapter;
-import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
@@ -31,6 +30,7 @@
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.CompoundBinaryTag;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.block.BaseBlock;
@@ -151,7 +151,7 @@ default void tickWatchdog() {
* @param pos The position
* @param nbtData The NBT Data
*/
- void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData);
+ void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData);
/**
* Make the client think it has operator status.
diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar
index 31237d7c4686f7f1921bfd6b84402a310e708ab7..5f9fa5a89b84b266e88a53e9f2cccf18e3ff502a 100644
GIT binary patch
delta 142673
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%0Dv;iLK4YeL@i+Xubb=?Z
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
z
zhtQh_Mc&s31EdOU+TJF&9=e{G{uX2#eXxLYH%Hjqf*DS-e6h%3d%oJfad)C4@WNIP
zfX@QfYIQB7^=0G?x83*cDWX%OzWKBksB-!J>l}f@1SJhx^?<^LuGlvq-0TuXGifu=
z`$vCSTAoQgE9%WJ&PQ@cDx^vw$dMp_K3r)c$^uiWmxU|AyiK*yv!7351
za=e+>7@uMho?Ji83Op@93USvQ=#F)90z#kPBc=<}a|n=rNeU_N-k8FVM9ysE5`&2-
znDk%CN*{5Jb>lV4{~&^PS0J`7Pb-IFCThKP_Y5P^ViOLrV@
zM9PKoBJNn8cwyn8RWsH
z2X_WRT@+{_L!G*gFevYDIy9)F(S;