From 3b6e5e83c98b019b1a7acf65df71921630935711 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sat, 28 Sep 2024 21:38:52 +0200 Subject: [PATCH] Fix NBT stripping and trimming (#2929) --- .../core/extent/LimitExtent.java | 4 +- .../core/extent/StripNBTExtent.java | 92 ++++++++++--------- .../core/queue/IBatchProcessor.java | 17 ++-- .../core/queue/IBlocks.java | 2 +- .../core/util/NbtUtils.java | 15 +++ 5 files changed, 74 insertions(+), 56 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java index d43078354..0bef1afc2 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/LimitExtent.java @@ -512,8 +512,8 @@ public class LimitExtent extends AbstractDelegateExtent implements IBatchProcess if (!processing) { return set; } - int tiles = set.getTiles().size(); - int ents = set.getEntities().size() + set.getEntityRemoves().size(); + int tiles = set.tiles().size(); + int ents = set.entities().size() + set.getEntityRemoves().size(); limit.THROW_MAX_CHANGES(tiles + ents); limit.THROW_MAX_BLOCKSTATES(tiles); limit.THROW_MAX_ENTITIES(ents); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java index c0b49c333..6939743d7 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/StripNBTExtent.java @@ -2,14 +2,12 @@ package com.fastasyncworldedit.core.extent; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; import com.fastasyncworldedit.core.math.BlockVector3ChunkMap; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunk; import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.util.ExtentTraverser; -import com.google.common.collect.ImmutableMap; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -20,16 +18,17 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.NbtValued; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import org.enginehub.linbus.tree.LinCompoundTag; +import org.enginehub.linbus.tree.LinTag; import javax.annotation.Nullable; -import java.util.HashMap; +import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor { @@ -75,79 +74,82 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc if (!(block instanceof BaseBlock localBlock)) { return block; } - if (!localBlock.hasNbtData()) { + final LinCompoundTag nbt = localBlock.getNbt(); + if (nbt == null) { return block; } - CompoundTag nbt = localBlock.getNbtData(); - Map> value = new HashMap<>(nbt.getValue()); + LinCompoundTag.Builder nbtBuilder = nbt.toBuilder(); for (String key : strip) { - value.remove(key); + nbtBuilder.remove(key); } - return (B) localBlock.toBaseBlock(new CompoundTag(value)); + return (B) localBlock.toBaseBlock(nbtBuilder.build()); } public T stripEntityNBT(T entity) { - if (!entity.hasNbtData()) { + LinCompoundTag nbt = entity.getNbt(); + if (nbt == null) { return entity; } - CompoundTag nbt = entity.getNbtData(); - Map> value = new HashMap<>(nbt.getValue()); + LinCompoundTag.Builder nbtBuilder = nbt.toBuilder(); for (String key : strip) { - value.remove(key); + nbtBuilder.remove(key); } - entity.setNbtData(new CompoundTag(value)); + entity.setNbt(nbtBuilder.build()); return entity; } @Override public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) { - Map tiles = set.getTiles(); - Set entities = set.getEntities(); + Map tiles = set.tiles(); + Collection entities = set.entities(); if (tiles.isEmpty() && entities.isEmpty()) { return set; } boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap; - for (final Map.Entry entry : tiles.entrySet()) { - ImmutableMap.Builder> map = ImmutableMap.builder(); - final AtomicBoolean isStripped = new AtomicBoolean(false); - entry.getValue().getValue().forEach((k, v) -> { - if (strip.contains(k.toLowerCase())) { - isStripped.set(true); - } else { - map.put(k, v); - } - }); - if (isStripped.get()) { + for (final var entry : tiles.entrySet()) { + FaweCompoundTag original = entry.getValue(); + FaweCompoundTag result = stripNbt(original); + if (original != result) { if (isBv3ChunkMap) { // Replace existing value with stripped value - tiles.put(entry.getKey(), new CompoundTag(map.build())); + tiles.put(entry.getKey(), result); } else { - entry.setValue(new CompoundTag(map.build())); + entry.setValue(result); } } } - Set stripped = new HashSet<>(); - Iterator iterator = entities.iterator(); + Set stripped = new HashSet<>(); + Iterator iterator = entities.iterator(); while (iterator.hasNext()) { - CompoundTag entity = iterator.next(); - ImmutableMap.Builder> map = ImmutableMap.builder(); - final AtomicBoolean isStripped = new AtomicBoolean(false); - entity.getValue().forEach((k, v) -> { - if (strip.contains(k.toUpperCase(Locale.ROOT))) { - isStripped.set(true); - } else { - map.put(k, v); - } - }); - if (isStripped.get()) { + FaweCompoundTag original = iterator.next(); + FaweCompoundTag result = stripNbt(original); + if (original != result) { iterator.remove(); - stripped.add(new CompoundTag(map.build())); + stripped.add(result); } } - set.getEntities().addAll(stripped); + // this relies on entities.addAll(...) not throwing an exception if empty+unmodifiable (=> stripped is empty too) + entities.addAll(stripped); return set; } + private FaweCompoundTag stripNbt( + FaweCompoundTag compoundTag + ) { + LinCompoundTag.Builder builder = LinCompoundTag.builder(); + boolean stripped = false; + for (var entry : compoundTag.linTag().value().entrySet()) { + String k = entry.getKey(); + LinTag v = entry.getValue(); + if (strip.contains(k.toLowerCase(Locale.ROOT))) { + stripped = true; + } else { + builder.put(k, v); + } + } + return stripped ? FaweCompoundTag.of(builder.build()) : compoundTag; + } + @Nullable @Override public Extent construct(final Extent child) { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java index faec2f9f5..7bce208fc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBatchProcessor.java @@ -3,15 +3,16 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor; import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor; import com.fastasyncworldedit.core.extent.processor.ProcessorScope; -import com.sk89q.jnbt.CompoundTag; +import com.fastasyncworldedit.core.nbt.FaweCompoundTag; +import com.fastasyncworldedit.core.util.NbtUtils; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypesCache; import javax.annotation.Nullable; +import java.util.Collection; import java.util.Map; -import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.function.Function; @@ -156,11 +157,11 @@ public interface IBatchProcessor { */ @Deprecated(forRemoval = true, since = "2.8.4") default boolean trimNBT(IChunkSet set, Function contains) { - Set ents = set.getEntities(); + Collection ents = set.entities(); if (!ents.isEmpty()) { - ents.removeIf(ent -> !contains.apply(ent.getEntityPosition().toBlockPoint())); + ents.removeIf(ent -> !contains.apply(NbtUtils.entityPosition(ent).toBlockPoint())); } - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (!tiles.isEmpty()) { tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !contains .apply(blockVector3CompoundTagEntry.getKey())); @@ -177,11 +178,11 @@ public interface IBatchProcessor { default boolean trimNBT( IChunkSet set, Function containsEntity, Function containsTile ) { - Set ents = set.getEntities(); + Collection ents = set.entities(); if (!ents.isEmpty()) { - ents.removeIf(ent -> !containsEntity.apply(ent.getEntityPosition().toBlockPoint())); + ents.removeIf(ent -> !containsEntity.apply(NbtUtils.entityPosition(ent).toBlockPoint())); } - Map tiles = set.getTiles(); + Map tiles = set.tiles(); if (!tiles.isEmpty()) { tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !containsTile.apply(blockVector3CompoundTagEntry.getKey())); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java index bda12dbe3..3a9d71da1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IBlocks.java @@ -61,7 +61,7 @@ public interface IBlocks extends Trimable { @Deprecated(forRemoval = true, since = "2.11.2") default Map getTiles() { - return AdaptedMap.immutable(tiles(), pos -> pos, IBlocks::toCompoundTag); + return AdaptedMap.values(tiles(), ct -> FaweCompoundTag.of(ct.toLinTag()), IBlocks::toCompoundTag); } Map tiles(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java index ac606ab24..8b427c322 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/NbtUtils.java @@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.util; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.storage.InvalidFormatException; import org.enginehub.linbus.tree.LinByteTag; @@ -211,4 +212,18 @@ public final class NbtUtils { map.put("PersistentIDLSB", LinLongTag.of(uuid.getLeastSignificantBits())); } + /** + * {@return the position data of the given tag} + * + * @param compoundTag the tag to extract position information from + * @since TODO + */ + public static Vector3 entityPosition(FaweCompoundTag compoundTag) { + LinListTag pos = compoundTag.linTag().getListTag("Pos", LinTagType.doubleTag()); + double x = pos.get(0).valueAsDouble(); + double y = pos.get(1).valueAsDouble(); + double z = pos.get(2).valueAsDouble(); + return Vector3.at(x, y, z); + } + }