NbtPathArgument.java

net.minecraft.commands.arguments.NbtPathArgument

信息

  • 全限定名:net.minecraft.commands.arguments.NbtPathArgument
  • 类型:public class
  • 包:net.minecraft.commands.arguments
  • 源码路径:src/main/java/net/minecraft/commands/arguments/NbtPathArgument.java
  • 起始行号:L34
  • 实现:ArgumentType<NbtPathArgument.NbtPath>
  • 职责:

    TODO

字段/常量

  • EXAMPLES

    • 类型: Collection<String>
    • 修饰符: private static final
    • 源码定位: L35
    • 说明:

      TODO

  • ERROR_INVALID_NODE

    • 类型: SimpleCommandExceptionType
    • 修饰符: public static final
    • 源码定位: L36
    • 说明:

      TODO

  • ERROR_DATA_TOO_DEEP

    • 类型: SimpleCommandExceptionType
    • 修饰符: public static final
    • 源码定位: L37
    • 说明:

      TODO

  • ERROR_NOTHING_FOUND

    • 类型: DynamicCommandExceptionType
    • 修饰符: public static final
    • 源码定位: L38
    • 说明:

      TODO

  • ERROR_EXPECTED_LIST

    • 类型: DynamicCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L41
    • 说明:

      TODO

  • ERROR_INVALID_INDEX

    • 类型: DynamicCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L44
    • 说明:

      TODO

  • INDEX_MATCH_START

    • 类型: char
    • 修饰符: private static final
    • 源码定位: L47
    • 说明:

      TODO

  • INDEX_MATCH_END

    • 类型: char
    • 修饰符: private static final
    • 源码定位: L48
    • 说明:

      TODO

  • KEY_MATCH_START

    • 类型: char
    • 修饰符: private static final
    • 源码定位: L49
    • 说明:

      TODO

  • KEY_MATCH_END

    • 类型: char
    • 修饰符: private static final
    • 源码定位: L50
    • 说明:

      TODO

  • QUOTED_KEY_START

    • 类型: char
    • 修饰符: private static final
    • 源码定位: L51
    • 说明:

      TODO

  • SINGLE_QUOTED_KEY_START

    • 类型: char
    • 修饰符: private static final
    • 源码定位: L52
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.commands.arguments.NbtPathArgument.AllElementsNode

    • 类型: class
    • 修饰符: private static
    • 源码定位: L155
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.CompoundChildNode

    • 类型: class
    • 修饰符: private static
    • 源码定位: L228
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.IndexedElementNode

    • 类型: class
    • 修饰符: private static
    • 源码定位: L289
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.MatchElementNode

    • 类型: class
    • 修饰符: private static
    • 源码定位: L349
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.MatchObjectNode

    • 类型: class
    • 修饰符: private static
    • 源码定位: L426
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.MatchRootObjectNode

    • 类型: class
    • 修饰符: private static
    • 源码定位: L496
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.NbtPath

    • 类型: class
    • 修饰符: public static
    • 源码定位: L531
    • 说明:

      TODO

  • net.minecraft.commands.arguments.NbtPathArgument.Node

    • 类型: interface
    • 修饰符: private
    • 源码定位: L721
    • 说明:

      TODO

构造器

方法

下面的方法块按源码顺序生成。

public static NbtPathArgument nbtPath() @ L54

  • 方法名:nbtPath
  • 源码定位:L54
  • 返回类型:NbtPathArgument
  • 修饰符:public static

参数:

说明:

TODO

public static NbtPathArgument.NbtPath getPath(CommandContext<CommandSourceStack> context, String name) @ L58

  • 方法名:getPath
  • 源码定位:L58
  • 返回类型:NbtPathArgument.NbtPath
  • 修饰符:public static

参数:

  • context: CommandContext
  • name: String

说明:

TODO

public NbtPathArgument.NbtPath parse(StringReader reader) @ L62

  • 方法名:parse
  • 源码定位:L62
  • 返回类型:NbtPathArgument.NbtPath
  • 修饰符:public

参数:

  • reader: StringReader

说明:

TODO

private static NbtPathArgument.Node parseNode(StringReader reader, boolean firstNode) @ L86

  • 方法名:parseNode
  • 源码定位:L86
  • 返回类型:NbtPathArgument.Node
  • 修饰符:private static

参数:

  • reader: StringReader
  • firstNode: boolean

说明:

TODO

private static NbtPathArgument.Node readObjectNode(StringReader reader, String name) @ L117

  • 方法名:readObjectNode
  • 源码定位:L117
  • 返回类型:NbtPathArgument.Node
  • 修饰符:private static

参数:

  • reader: StringReader
  • name: String

说明:

TODO

private static String readUnquotedName(StringReader reader) @ L128

  • 方法名:readUnquotedName
  • 源码定位:L128
  • 返回类型:String
  • 修饰符:private static

参数:

  • reader: StringReader

说明:

TODO

public Collection<String> getExamples() @ L142

  • 方法名:getExamples
  • 源码定位:L142
  • 返回类型:Collection
  • 修饰符:public

参数:

说明:

TODO

private static boolean isAllowedInUnquotedName(char c) @ L147

  • 方法名:isAllowedInUnquotedName
  • 源码定位:L147
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • c: char

说明:

TODO

private static Predicate<Tag> createTagPredicate(CompoundTag pattern) @ L151

  • 方法名:createTagPredicate
  • 源码定位:L151
  • 返回类型:Predicate
  • 修饰符:private static

参数:

  • pattern: CompoundTag

说明:

TODO

代码

public class NbtPathArgument implements ArgumentType<NbtPathArgument.NbtPath> {
    private static final Collection<String> EXAMPLES = Arrays.asList("foo", "foo.bar", "foo[0]", "[0]", "[]", "{foo=bar}");
    public static final SimpleCommandExceptionType ERROR_INVALID_NODE = new SimpleCommandExceptionType(Component.translatable("arguments.nbtpath.node.invalid"));
    public static final SimpleCommandExceptionType ERROR_DATA_TOO_DEEP = new SimpleCommandExceptionType(Component.translatable("arguments.nbtpath.too_deep"));
    public static final DynamicCommandExceptionType ERROR_NOTHING_FOUND = new DynamicCommandExceptionType(
        path -> Component.translatableEscape("arguments.nbtpath.nothing_found", path)
    );
    private static final DynamicCommandExceptionType ERROR_EXPECTED_LIST = new DynamicCommandExceptionType(
        node -> Component.translatableEscape("commands.data.modify.expected_list", node)
    );
    private static final DynamicCommandExceptionType ERROR_INVALID_INDEX = new DynamicCommandExceptionType(
        node -> Component.translatableEscape("commands.data.modify.invalid_index", node)
    );
    private static final char INDEX_MATCH_START = '[';
    private static final char INDEX_MATCH_END = ']';
    private static final char KEY_MATCH_START = '{';
    private static final char KEY_MATCH_END = '}';
    private static final char QUOTED_KEY_START = '"';
    private static final char SINGLE_QUOTED_KEY_START = '\'';
 
    public static NbtPathArgument nbtPath() {
        return new NbtPathArgument();
    }
 
    public static NbtPathArgument.NbtPath getPath(CommandContext<CommandSourceStack> context, String name) {
        return context.getArgument(name, NbtPathArgument.NbtPath.class);
    }
 
    public NbtPathArgument.NbtPath parse(StringReader reader) throws CommandSyntaxException {
        List<NbtPathArgument.Node> nodes = Lists.newArrayList();
        int start = reader.getCursor();
        Object2IntMap<NbtPathArgument.Node> nodeToOriginalPosition = new Object2IntOpenHashMap<>();
        boolean firstNode = true;
 
        while (reader.canRead() && reader.peek() != ' ') {
            NbtPathArgument.Node node = parseNode(reader, firstNode);
            nodes.add(node);
            nodeToOriginalPosition.put(node, reader.getCursor() - start);
            firstNode = false;
            if (reader.canRead()) {
                char next = reader.peek();
                if (next != ' ' && next != '[' && next != '{') {
                    reader.expect('.');
                }
            }
        }
 
        return new NbtPathArgument.NbtPath(
            reader.getString().substring(start, reader.getCursor()), nodes.toArray(new NbtPathArgument.Node[0]), nodeToOriginalPosition
        );
    }
 
    private static NbtPathArgument.Node parseNode(StringReader reader, boolean firstNode) throws CommandSyntaxException {
        return (NbtPathArgument.Node)(switch (reader.peek()) {
            case '"', '\'' -> readObjectNode(reader, reader.readString());
            case '[' -> {
                reader.skip();
                int next = reader.peek();
                if (next == 123) {
                    CompoundTag pattern = TagParser.parseCompoundAsArgument(reader);
                    reader.expect(']');
                    yield new NbtPathArgument.MatchElementNode(pattern);
                } else if (next == 93) {
                    reader.skip();
                    yield NbtPathArgument.AllElementsNode.INSTANCE;
                } else {
                    int index = reader.readInt();
                    reader.expect(']');
                    yield new NbtPathArgument.IndexedElementNode(index);
                }
            }
            case '{' -> {
                if (!firstNode) {
                    throw ERROR_INVALID_NODE.createWithContext(reader);
                }
 
                CompoundTag pattern = TagParser.parseCompoundAsArgument(reader);
                yield new NbtPathArgument.MatchRootObjectNode(pattern);
            }
            default -> readObjectNode(reader, readUnquotedName(reader));
        });
    }
 
    private static NbtPathArgument.Node readObjectNode(StringReader reader, String name) throws CommandSyntaxException {
        if (name.isEmpty()) {
            throw ERROR_INVALID_NODE.createWithContext(reader);
        } else if (reader.canRead() && reader.peek() == '{') {
            CompoundTag pattern = TagParser.parseCompoundAsArgument(reader);
            return new NbtPathArgument.MatchObjectNode(name, pattern);
        } else {
            return new NbtPathArgument.CompoundChildNode(name);
        }
    }
 
    private static String readUnquotedName(StringReader reader) throws CommandSyntaxException {
        int start = reader.getCursor();
 
        while (reader.canRead() && isAllowedInUnquotedName(reader.peek())) {
            reader.skip();
        }
 
        if (reader.getCursor() == start) {
            throw ERROR_INVALID_NODE.createWithContext(reader);
        } else {
            return reader.getString().substring(start, reader.getCursor());
        }
    }
 
    @Override
    public Collection<String> getExamples() {
        return EXAMPLES;
    }
 
    private static boolean isAllowedInUnquotedName(char c) {
        return c != ' ' && c != '"' && c != '\'' && c != '[' && c != ']' && c != '.' && c != '{' && c != '}';
    }
 
    private static Predicate<Tag> createTagPredicate(CompoundTag pattern) {
        return tag -> NbtUtils.compareNbt(pattern, tag, true);
    }
 
    private static class AllElementsNode implements NbtPathArgument.Node {
        public static final NbtPathArgument.AllElementsNode INSTANCE = new NbtPathArgument.AllElementsNode();
 
        @Override
        public void getTag(Tag parent, List<Tag> output) {
            if (parent instanceof CollectionTag collection) {
                Iterables.addAll(output, collection);
            }
        }
 
        @Override
        public void getOrCreateTag(Tag parent, Supplier<Tag> child, List<Tag> output) {
            if (parent instanceof CollectionTag list) {
                if (list.isEmpty()) {
                    Tag result = child.get();
                    if (list.addTag(0, result)) {
                        output.add(result);
                    }
                } else {
                    Iterables.addAll(output, list);
                }
            }
        }
 
        @Override
        public Tag createPreferredParentTag() {
            return new ListTag();
        }
 
        @Override
        public int setTag(Tag parent, Supplier<Tag> toAdd) {
            if (!(parent instanceof CollectionTag list)) {
                return 0;
            } else {
                int size = list.size();
                if (size == 0) {
                    list.addTag(0, toAdd.get());
                    return 1;
                } else {
                    Tag newValue = toAdd.get();
                    int changedCount = size - (int)list.stream().filter(newValue::equals).count();
                    if (changedCount == 0) {
                        return 0;
                    } else {
                        list.clear();
                        if (!list.addTag(0, newValue)) {
                            return 0;
                        } else {
                            for (int i = 1; i < size; i++) {
                                list.addTag(i, toAdd.get());
                            }
 
                            return changedCount;
                        }
                    }
                }
            }
        }
 
        @Override
        public int removeTag(Tag parent) {
            if (parent instanceof CollectionTag list) {
                int size = list.size();
                if (size > 0) {
                    list.clear();
                    return size;
                }
            }
 
            return 0;
        }
    }
 
    private static class CompoundChildNode implements NbtPathArgument.Node {
        private final String name;
 
        public CompoundChildNode(String name) {
            this.name = name;
        }
 
        @Override
        public void getTag(Tag parent, List<Tag> output) {
            if (parent instanceof CompoundTag) {
                Tag result = ((CompoundTag)parent).get(this.name);
                if (result != null) {
                    output.add(result);
                }
            }
        }
 
        @Override
        public void getOrCreateTag(Tag parent, Supplier<Tag> child, List<Tag> output) {
            if (parent instanceof CompoundTag compound) {
                Tag result;
                if (compound.contains(this.name)) {
                    result = compound.get(this.name);
                } else {
                    result = child.get();
                    compound.put(this.name, result);
                }
 
                output.add(result);
            }
        }
 
        @Override
        public Tag createPreferredParentTag() {
            return new CompoundTag();
        }
 
        @Override
        public int setTag(Tag parent, Supplier<Tag> toAdd) {
            if (parent instanceof CompoundTag compound) {
                Tag newValue = toAdd.get();
                Tag previousValue = compound.put(this.name, newValue);
                if (!newValue.equals(previousValue)) {
                    return 1;
                }
            }
 
            return 0;
        }
 
        @Override
        public int removeTag(Tag parent) {
            if (parent instanceof CompoundTag compound && compound.contains(this.name)) {
                compound.remove(this.name);
                return 1;
            } else {
                return 0;
            }
        }
    }
 
    private static class IndexedElementNode implements NbtPathArgument.Node {
        private final int index;
 
        public IndexedElementNode(int index) {
            this.index = index;
        }
 
        @Override
        public void getTag(Tag parent, List<Tag> output) {
            if (parent instanceof CollectionTag list) {
                int size = list.size();
                int actualIndex = this.index < 0 ? size + this.index : this.index;
                if (0 <= actualIndex && actualIndex < size) {
                    output.add(list.get(actualIndex));
                }
            }
        }
 
        @Override
        public void getOrCreateTag(Tag parent, Supplier<Tag> child, List<Tag> output) {
            this.getTag(parent, output);
        }
 
        @Override
        public Tag createPreferredParentTag() {
            return new ListTag();
        }
 
        @Override
        public int setTag(Tag parent, Supplier<Tag> toAdd) {
            if (parent instanceof CollectionTag list) {
                int size = list.size();
                int actualIndex = this.index < 0 ? size + this.index : this.index;
                if (0 <= actualIndex && actualIndex < size) {
                    Tag previousValue = list.get(actualIndex);
                    Tag newValue = toAdd.get();
                    if (!newValue.equals(previousValue) && list.setTag(actualIndex, newValue)) {
                        return 1;
                    }
                }
            }
 
            return 0;
        }
 
        @Override
        public int removeTag(Tag parent) {
            if (parent instanceof CollectionTag list) {
                int size = list.size();
                int actualIndex = this.index < 0 ? size + this.index : this.index;
                if (0 <= actualIndex && actualIndex < size) {
                    list.remove(actualIndex);
                    return 1;
                }
            }
 
            return 0;
        }
    }
 
    private static class MatchElementNode implements NbtPathArgument.Node {
        private final CompoundTag pattern;
        private final Predicate<Tag> predicate;
 
        public MatchElementNode(CompoundTag pattern) {
            this.pattern = pattern;
            this.predicate = NbtPathArgument.createTagPredicate(pattern);
        }
 
        @Override
        public void getTag(Tag parent, List<Tag> output) {
            if (parent instanceof ListTag list) {
                list.stream().filter(this.predicate).forEach(output::add);
            }
        }
 
        @Override
        public void getOrCreateTag(Tag parent, Supplier<Tag> child, List<Tag> output) {
            MutableBoolean foundAnything = new MutableBoolean();
            if (parent instanceof ListTag list) {
                list.stream().filter(this.predicate).forEach(t -> {
                    output.add(t);
                    foundAnything.setTrue();
                });
                if (foundAnything.isFalse()) {
                    CompoundTag newTag = this.pattern.copy();
                    list.add(newTag);
                    output.add(newTag);
                }
            }
        }
 
        @Override
        public Tag createPreferredParentTag() {
            return new ListTag();
        }
 
        @Override
        public int setTag(Tag parent, Supplier<Tag> toAdd) {
            int changedCount = 0;
            if (parent instanceof ListTag list) {
                int size = list.size();
                if (size == 0) {
                    list.add(toAdd.get());
                    changedCount++;
                } else {
                    for (int i = 0; i < size; i++) {
                        Tag currentValue = list.get(i);
                        if (this.predicate.test(currentValue)) {
                            Tag newValue = toAdd.get();
                            if (!newValue.equals(currentValue) && list.setTag(i, newValue)) {
                                changedCount++;
                            }
                        }
                    }
                }
            }
 
            return changedCount;
        }
 
        @Override
        public int removeTag(Tag parent) {
            int changedCount = 0;
            if (parent instanceof ListTag list) {
                for (int i = list.size() - 1; i >= 0; i--) {
                    if (this.predicate.test(list.get(i))) {
                        list.remove(i);
                        changedCount++;
                    }
                }
            }
 
            return changedCount;
        }
    }
 
    private static class MatchObjectNode implements NbtPathArgument.Node {
        private final String name;
        private final CompoundTag pattern;
        private final Predicate<Tag> predicate;
 
        public MatchObjectNode(String name, CompoundTag pattern) {
            this.name = name;
            this.pattern = pattern;
            this.predicate = NbtPathArgument.createTagPredicate(pattern);
        }
 
        @Override
        public void getTag(Tag parent, List<Tag> output) {
            if (parent instanceof CompoundTag) {
                Tag result = ((CompoundTag)parent).get(this.name);
                if (this.predicate.test(result)) {
                    output.add(result);
                }
            }
        }
 
        @Override
        public void getOrCreateTag(Tag parent, Supplier<Tag> child, List<Tag> output) {
            if (parent instanceof CompoundTag compound) {
                Tag result = compound.get(this.name);
                if (result == null) {
                    Tag var6 = this.pattern.copy();
                    compound.put(this.name, var6);
                    output.add(var6);
                } else if (this.predicate.test(result)) {
                    output.add(result);
                }
            }
        }
 
        @Override
        public Tag createPreferredParentTag() {
            return new CompoundTag();
        }
 
        @Override
        public int setTag(Tag parent, Supplier<Tag> toAdd) {
            if (parent instanceof CompoundTag compound) {
                Tag currentValue = compound.get(this.name);
                if (this.predicate.test(currentValue)) {
                    Tag newValue = toAdd.get();
                    if (!newValue.equals(currentValue)) {
                        compound.put(this.name, newValue);
                        return 1;
                    }
                }
            }
 
            return 0;
        }
 
        @Override
        public int removeTag(Tag parent) {
            if (parent instanceof CompoundTag compound) {
                Tag current = compound.get(this.name);
                if (this.predicate.test(current)) {
                    compound.remove(this.name);
                    return 1;
                }
            }
 
            return 0;
        }
    }
 
    private static class MatchRootObjectNode implements NbtPathArgument.Node {
        private final Predicate<Tag> predicate;
 
        public MatchRootObjectNode(CompoundTag pattern) {
            this.predicate = NbtPathArgument.createTagPredicate(pattern);
        }
 
        @Override
        public void getTag(Tag self, List<Tag> output) {
            if (self instanceof CompoundTag && this.predicate.test(self)) {
                output.add(self);
            }
        }
 
        @Override
        public void getOrCreateTag(Tag self, Supplier<Tag> child, List<Tag> output) {
            this.getTag(self, output);
        }
 
        @Override
        public Tag createPreferredParentTag() {
            return new CompoundTag();
        }
 
        @Override
        public int setTag(Tag parent, Supplier<Tag> toAdd) {
            return 0;
        }
 
        @Override
        public int removeTag(Tag parent) {
            return 0;
        }
    }
 
    public static class NbtPath {
        private final String original;
        private final Object2IntMap<NbtPathArgument.Node> nodeToOriginalPosition;
        private final NbtPathArgument.Node[] nodes;
        public static final Codec<NbtPathArgument.NbtPath> CODEC = Codec.STRING.comapFlatMap(string -> {
            try {
                NbtPathArgument.NbtPath parsed = new NbtPathArgument().parse(new StringReader(string));
                return DataResult.success(parsed);
            } catch (CommandSyntaxException var2) {
                return DataResult.error(() -> "Failed to parse path " + string + ": " + var2.getMessage());
            }
        }, NbtPathArgument.NbtPath::asString);
 
        public static NbtPathArgument.NbtPath of(String string) throws CommandSyntaxException {
            return new NbtPathArgument().parse(new StringReader(string));
        }
 
        public NbtPath(String original, NbtPathArgument.Node[] nodes, Object2IntMap<NbtPathArgument.Node> nodeToOriginalPosition) {
            this.original = original;
            this.nodes = nodes;
            this.nodeToOriginalPosition = nodeToOriginalPosition;
        }
 
        public List<Tag> get(Tag tag) throws CommandSyntaxException {
            List<Tag> result = Collections.singletonList(tag);
 
            for (NbtPathArgument.Node node : this.nodes) {
                result = node.get(result);
                if (result.isEmpty()) {
                    throw this.createNotFoundException(node);
                }
            }
 
            return result;
        }
 
        public int countMatching(Tag tag) {
            List<Tag> result = Collections.singletonList(tag);
 
            for (NbtPathArgument.Node node : this.nodes) {
                result = node.get(result);
                if (result.isEmpty()) {
                    return 0;
                }
            }
 
            return result.size();
        }
 
        private List<Tag> getOrCreateParents(Tag tag) throws CommandSyntaxException {
            List<Tag> result = Collections.singletonList(tag);
 
            for (int i = 0; i < this.nodes.length - 1; i++) {
                NbtPathArgument.Node node = this.nodes[i];
                int next = i + 1;
                result = node.getOrCreate(result, this.nodes[next]::createPreferredParentTag);
                if (result.isEmpty()) {
                    throw this.createNotFoundException(node);
                }
            }
 
            return result;
        }
 
        public List<Tag> getOrCreate(Tag tag, Supplier<Tag> newTagValue) throws CommandSyntaxException {
            List<Tag> result = this.getOrCreateParents(tag);
            NbtPathArgument.Node lastNode = this.nodes[this.nodes.length - 1];
            return lastNode.getOrCreate(result, newTagValue);
        }
 
        private static int apply(List<Tag> targets, Function<Tag, Integer> operation) {
            return targets.stream().map(operation).reduce(0, (a, b) -> a + b);
        }
 
        public static boolean isTooDeep(Tag tag, int depth) {
            if (depth >= 512) {
                return true;
            } else {
                if (tag instanceof CompoundTag compound) {
                    for (Tag child : compound.values()) {
                        if (isTooDeep(child, depth + 1)) {
                            return true;
                        }
                    }
                } else if (tag instanceof ListTag) {
                    for (Tag listEntry : (ListTag)tag) {
                        if (isTooDeep(listEntry, depth + 1)) {
                            return true;
                        }
                    }
                }
 
                return false;
            }
        }
 
        public int set(Tag tag, Tag toAdd) throws CommandSyntaxException {
            if (isTooDeep(toAdd, this.estimatePathDepth())) {
                throw NbtPathArgument.ERROR_DATA_TOO_DEEP.create();
            } else {
                Tag firstCopy = toAdd.copy();
                List<Tag> result = this.getOrCreateParents(tag);
                if (result.isEmpty()) {
                    return 0;
                } else {
                    NbtPathArgument.Node lastNode = this.nodes[this.nodes.length - 1];
                    MutableBoolean usedFirstCopy = new MutableBoolean(false);
                    return apply(result, t -> lastNode.setTag(t, () -> {
                        if (usedFirstCopy.isFalse()) {
                            usedFirstCopy.setTrue();
                            return firstCopy;
                        } else {
                            return firstCopy.copy();
                        }
                    }));
                }
            }
        }
 
        private int estimatePathDepth() {
            return this.nodes.length;
        }
 
        public int insert(int index, CompoundTag target, List<Tag> toInsert) throws CommandSyntaxException {
            List<Tag> toInsertCopy = new ArrayList<>(toInsert.size());
 
            for (Tag tag : toInsert) {
                Tag copy = tag.copy();
                toInsertCopy.add(copy);
                if (isTooDeep(copy, this.estimatePathDepth())) {
                    throw NbtPathArgument.ERROR_DATA_TOO_DEEP.create();
                }
            }
 
            Collection<Tag> targets = this.getOrCreate(target, ListTag::new);
            int modifiedCount = 0;
            boolean usedFirst = false;
 
            for (Tag targetTag : targets) {
                if (!(targetTag instanceof CollectionTag targetList)) {
                    throw NbtPathArgument.ERROR_EXPECTED_LIST.create(targetTag);
                }
 
                boolean modified = false;
                int actualIndex = index < 0 ? targetList.size() + index + 1 : index;
 
                for (Tag sourceTag : toInsertCopy) {
                    try {
                        if (targetList.addTag(actualIndex, usedFirst ? sourceTag.copy() : sourceTag)) {
                            actualIndex++;
                            modified = true;
                        }
                    } catch (IndexOutOfBoundsException var16) {
                        throw NbtPathArgument.ERROR_INVALID_INDEX.create(actualIndex);
                    }
                }
 
                usedFirst = true;
                modifiedCount += modified ? 1 : 0;
            }
 
            return modifiedCount;
        }
 
        public int remove(Tag tag) {
            List<Tag> result = Collections.singletonList(tag);
 
            for (int i = 0; i < this.nodes.length - 1; i++) {
                result = this.nodes[i].get(result);
            }
 
            NbtPathArgument.Node lastNode = this.nodes[this.nodes.length - 1];
            return apply(result, lastNode::removeTag);
        }
 
        private CommandSyntaxException createNotFoundException(NbtPathArgument.Node node) {
            int index = this.nodeToOriginalPosition.getInt(node);
            return NbtPathArgument.ERROR_NOTHING_FOUND.create(this.original.substring(0, index));
        }
 
        @Override
        public String toString() {
            return this.original;
        }
 
        public String asString() {
            return this.original;
        }
    }
 
    private interface Node {
        void getTag(Tag parent, final List<Tag> output);
 
        void getOrCreateTag(Tag parent, Supplier<Tag> child, final List<Tag> output);
 
        Tag createPreferredParentTag();
 
        int setTag(Tag parent, Supplier<Tag> toAdd);
 
        int removeTag(Tag parent);
 
        default List<Tag> get(List<Tag> tags) {
            return this.collect(tags, this::getTag);
        }
 
        default List<Tag> getOrCreate(List<Tag> tags, Supplier<Tag> child) {
            return this.collect(tags, (tag, output) -> this.getOrCreateTag(tag, child, output));
        }
 
        default List<Tag> collect(List<Tag> tags, BiConsumer<Tag, List<Tag>> collector) {
            List<Tag> result = Lists.newArrayList();
 
            for (Tag tag : tags) {
                collector.accept(tag, result);
            }
 
            return result;
        }
    }
}

引用的其他类

  • CommandSourceStack

    • 引用位置: 参数
  • CompoundTag

    • 引用位置: 参数/构造调用
    • 关联成员: CompoundTag()
  • ListTag

    • 引用位置: 构造调用
    • 关联成员: ListTag()
  • NbtUtils

    • 引用位置: 方法调用
    • 关联成员: NbtUtils.compareNbt()
  • Tag

    • 引用位置: 返回值
  • TagParser

    • 引用位置: 方法调用
    • 关联成员: TagParser.parseCompoundAsArgument()
  • Component

    • 引用位置: 方法调用
    • 关联成员: Component.translatable(), Component.translatableEscape()