Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support "heterogeneous" NBT lists somehow #1735

Open
SPGoding opened this issue Jan 27, 2025 · 0 comments
Open

Support "heterogeneous" NBT lists somehow #1735

SPGoding opened this issue Jan 27, 2025 · 0 comments
Labels
🐛 bug Something isn't working 🔷 nbt Relates to nbt, but is not directly handled by the nbt package

Comments

@SPGoding
Copy link
Member

SPGoding commented Jan 27, 2025

When heterogeneous SNBT lists are deserialized into NBT, non-compound entries (or wrapper compound entries? The logic of wrapIfNeeded() makes it seem like you could have double wrapped things if I'm not mistaken) are transformed into a wrapper compound. e.g. ['a', {'b': 3}] is stored as [{'': 'a'}, {'b': 3}].

net/minecraft/nbt/NbtOps
private static class HeterogenousListCollector implements NbtOps.ListCollector {
   private final ListTag result = new ListTag();

   public HeterogenousListCollector() {
      super();
   }

   public HeterogenousListCollector(Collection<Tag> list) {
      super();
      this.result.addAll(list);
   }

   public HeterogenousListCollector(IntArrayList list) {
      super();
      list.forEach((var1x) -> {
         this.result.add(wrapElement(IntTag.valueOf(var1x)));
      });
   }

   public HeterogenousListCollector(ByteArrayList list) {
      super();
      list.forEach((var1x) -> {
         this.result.add(wrapElement(ByteTag.valueOf(var1x)));
      });
   }

   public HeterogenousListCollector(LongArrayList list) {
      super();
      list.forEach((var1x) -> {
         this.result.add(wrapElement(LongTag.valueOf(var1x)));
      });
   }

   private static boolean isWrapper(CompoundTag compound) {
      return compound.size() == 1 && compound.contains("");
   }

   private static Tag wrapIfNeeded(Tag tag) {
      if (tag instanceof CompoundTag) {
         CompoundTag compound = (CompoundTag)tag;
         if (!isWrapper(compound)) {
            return compound;
         }
      }

      return wrapElement(tag);
   }

   private static CompoundTag wrapElement(Tag tag) {
      CompoundTag wrapper = new CompoundTag();
      wrapper.put("", tag);
      return wrapper;
   }

   public NbtOps.ListCollector accept(Tag tag) {
      this.result.add(wrapIfNeeded(tag));
      return this;
   }

   public Tag result() {
      return this.result;
   }
}

private static class HomogenousListCollector implements NbtOps.ListCollector {
   private final ListTag result = new ListTag();

   HomogenousListCollector(Tag tag) {
      super();
      this.result.add(tag);
   }

   HomogenousListCollector(ListTag list) {
      super();
      this.result.addAll(list);
   }

   public NbtOps.ListCollector accept(Tag tag) {
      if (tag.getId() != this.result.getElementType()) {
         return (new NbtOps.HeterogenousListCollector()).acceptAll(this.result).accept(tag);
      } else {
         this.result.add(tag);
         return this;
      }
   }

   public Tag result() {
      return this.result;
   }
}

Annoyingly, this transformation is not undone when NBT is serialized, so users could see those wrapper compounds in /data command output. We need to somehow support usage of wrapper compounds in commands.

@SPGoding SPGoding added 🐛 bug Something isn't working 🔷 nbt Relates to nbt, but is not directly handled by the nbt package labels Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working 🔷 nbt Relates to nbt, but is not directly handled by the nbt package
Projects
None yet
Development

No branches or pull requests

1 participant