NbtUtils.java

net.minecraft.nbt.NbtUtils

信息

  • 全限定名:net.minecraft.nbt.NbtUtils
  • 类型:public final class
  • 包:net.minecraft.nbt
  • 源码路径:src/main/java/net/minecraft/nbt/NbtUtils.java
  • 起始行号:L42
  • 职责:

    TODO

字段/常量

  • YXZ_LISTTAG_INT_COMPARATOR

    • 类型: Comparator<ListTag>
    • 修饰符: private static final
    • 源码定位: L43
    • 说明:

      TODO

  • YXZ_LISTTAG_DOUBLE_COMPARATOR

    • 类型: Comparator<ListTag>
    • 修饰符: private static final
    • 源码定位: L46
    • 说明:

      TODO

  • BLOCK_NAME_CODEC

    • 类型: Codec<ResourceKey<Block>>
    • 修饰符: private static final
    • 源码定位: L49
    • 说明:

      TODO

  • SNBT_DATA_TAG

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

      TODO

  • PROPERTIES_START

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

      TODO

  • PROPERTIES_END

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

      TODO

  • ELEMENT_SEPARATOR

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

      TODO

  • KEY_VALUE_SEPARATOR

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

      TODO

  • COMMA_SPLITTER

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

      TODO

  • COLON_SPLITTER

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

      TODO

  • LOGGER

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

      TODO

  • INDENT

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

      TODO

  • NOT_FOUND

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

      TODO

内部类/嵌套类型

构造器

private NbtUtils() @ L61

  • 构造器名:NbtUtils
  • 源码定位:L61
  • 修饰符:private

参数:

说明:

TODO

方法

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

public static boolean compareNbt(Tag expected, Tag actual, boolean partialListMatches) @ L64

  • 方法名:compareNbt
  • 源码定位:L64
  • 返回类型:boolean
  • 修饰符:public static

参数:

  • expected: Tag
  • actual: Tag
  • partialListMatches: boolean

说明:

TODO

public static BlockState readBlockState(HolderGetter<Block> blocks, CompoundTag tag) @ L117

  • 方法名:readBlockState
  • 源码定位:L117
  • 返回类型:BlockState
  • 修饰符:public static

参数:

  • blocks: HolderGetter
  • tag: CompoundTag

说明:

TODO

private static <S extends StateHolder<?,S>,T extends Comparable<T>> S setValueHelper(S result, Property<T> property, String key, CompoundTag properties, CompoundTag tag) @ L140

  • 方法名:setValueHelper
  • 源码定位:L140
  • 返回类型:<S extends StateHolder<?,S>,T extends Comparable> S
  • 修饰符:private static

参数:

  • result: S
  • property: Property
  • key: String
  • properties: CompoundTag
  • tag: CompoundTag

说明:

TODO

private static void writeStateProperties(StateHolder<?,?> state, CompoundTag tag) @ L152

  • 方法名:writeStateProperties
  • 源码定位:L152
  • 返回类型:void
  • 修饰符:private static

参数:

  • state: StateHolder
  • tag: CompoundTag

说明:

TODO

public static CompoundTag writeBlockState(BlockState state) @ L160

  • 方法名:writeBlockState
  • 源码定位:L160
  • 返回类型:CompoundTag
  • 修饰符:public static

参数:

  • state: BlockState

说明:

TODO

public static CompoundTag writeFluidState(FluidState state) @ L167

  • 方法名:writeFluidState
  • 源码定位:L167
  • 返回类型:CompoundTag
  • 修饰符:public static

参数:

  • state: FluidState

说明:

TODO

public static String prettyPrint(Tag tag, boolean withBinaryBlobs) @ L174

  • 方法名:prettyPrint
  • 源码定位:L174
  • 返回类型:String
  • 修饰符:public static

参数:

  • tag: Tag
  • withBinaryBlobs: boolean

说明:

TODO

public static StringBuilder prettyPrint(StringBuilder builder, Tag input, int indent, boolean withBinaryBlobs) @ L178

  • 方法名:prettyPrint
  • 源码定位:L178
  • 返回类型:StringBuilder
  • 修饰符:public static

参数:

  • builder: StringBuilder
  • input: Tag
  • indent: int
  • withBinaryBlobs: boolean

说明:

TODO

private static StringBuilder indent(int indent, StringBuilder builder) @ L343

  • 方法名:indent
  • 源码定位:L343
  • 返回类型:StringBuilder
  • 修饰符:private static

参数:

  • indent: int
  • builder: StringBuilder

说明:

TODO

public static Component toPrettyComponent(Tag tag) @ L354

  • 方法名:toPrettyComponent
  • 源码定位:L354
  • 返回类型:Component
  • 修饰符:public static

参数:

  • tag: Tag

说明:

TODO

public static String structureToSnbt(CompoundTag structure) @ L358

  • 方法名:structureToSnbt
  • 源码定位:L358
  • 返回类型:String
  • 修饰符:public static

参数:

  • structure: CompoundTag

说明:

TODO

public static CompoundTag snbtToStructure(String snbt) @ L362

  • 方法名:snbtToStructure
  • 源码定位:L362
  • 返回类型:CompoundTag
  • 修饰符:public static

参数:

  • snbt: String

说明:

TODO

static CompoundTag packStructureTemplate(CompoundTag snbt) @ L366

  • 方法名:packStructureTemplate
  • 源码定位:L366
  • 返回类型:CompoundTag
  • 修饰符:static

参数:

  • snbt: CompoundTag

说明:

TODO

static CompoundTag unpackStructureTemplate(CompoundTag template) @ L412

  • 方法名:unpackStructureTemplate
  • 源码定位:L412
  • 返回类型:CompoundTag
  • 修饰符:static

参数:

  • template: CompoundTag

说明:

TODO

static String packBlockState(CompoundTag compound) @ L467

  • 方法名:packBlockState
  • 源码定位:L467
  • 返回类型:String
  • 修饰符:static

参数:

  • compound: CompoundTag

说明:

TODO

static CompoundTag unpackBlockState(String compound) @ L484

  • 方法名:unpackBlockState
  • 源码定位:L484
  • 返回类型:CompoundTag
  • 修饰符:static

参数:

  • compound: String

说明:

TODO

public static CompoundTag addCurrentDataVersion(CompoundTag tag) @ L512

  • 方法名:addCurrentDataVersion
  • 源码定位:L512
  • 返回类型:CompoundTag
  • 修饰符:public static

参数:

  • tag: CompoundTag

说明:

TODO

public static CompoundTag addDataVersion(CompoundTag tag, int version) @ L517

  • 方法名:addDataVersion
  • 源码定位:L517
  • 返回类型:CompoundTag
  • 修饰符:public static

参数:

  • tag: CompoundTag
  • version: int

说明:

TODO

public static <T> Dynamic<T> addDataVersion(Dynamic<T> tag, int version) @ L522

  • 方法名:addDataVersion
  • 源码定位:L522
  • 返回类型: Dynamic
  • 修饰符:public static

参数:

  • tag: Dynamic
  • version: int

说明:

TODO

public static void addCurrentDataVersion(ValueOutput output) @ L526

  • 方法名:addCurrentDataVersion
  • 源码定位:L526
  • 返回类型:void
  • 修饰符:public static

参数:

  • output: ValueOutput

说明:

TODO

public static void addDataVersion(ValueOutput output, int version) @ L531

  • 方法名:addDataVersion
  • 源码定位:L531
  • 返回类型:void
  • 修饰符:public static

参数:

  • output: ValueOutput
  • version: int

说明:

TODO

public static int getDataVersion(CompoundTag tag) @ L535

  • 方法名:getDataVersion
  • 源码定位:L535
  • 返回类型:int
  • 修饰符:public static

参数:

  • tag: CompoundTag

说明:

TODO

public static int getDataVersion(CompoundTag tag, int _default) @ L539

  • 方法名:getDataVersion
  • 源码定位:L539
  • 返回类型:int
  • 修饰符:public static

参数:

  • tag: CompoundTag
  • _default: int

说明:

TODO

public static int getDataVersion(Dynamic<?> dynamic) @ L543

  • 方法名:getDataVersion
  • 源码定位:L543
  • 返回类型:int
  • 修饰符:public static

参数:

  • dynamic: Dynamic<?>

说明:

TODO

public static int getDataVersion(Dynamic<?> dynamic, int _default) @ L547

  • 方法名:getDataVersion
  • 源码定位:L547
  • 返回类型:int
  • 修饰符:public static

参数:

  • dynamic: Dynamic<?>
  • _default: int

说明:

TODO

代码

public final class NbtUtils {
    private static final Comparator<ListTag> YXZ_LISTTAG_INT_COMPARATOR = Comparator.<ListTag>comparingInt(list -> list.getIntOr(1, 0))
        .thenComparingInt(list -> list.getIntOr(0, 0))
        .thenComparingInt(list -> list.getIntOr(2, 0));
    private static final Comparator<ListTag> YXZ_LISTTAG_DOUBLE_COMPARATOR = Comparator.<ListTag>comparingDouble(list -> list.getDoubleOr(1, 0.0))
        .thenComparingDouble(list -> list.getDoubleOr(0, 0.0))
        .thenComparingDouble(list -> list.getDoubleOr(2, 0.0));
    private static final Codec<ResourceKey<Block>> BLOCK_NAME_CODEC = ResourceKey.codec(Registries.BLOCK);
    public static final String SNBT_DATA_TAG = "data";
    private static final char PROPERTIES_START = '{';
    private static final char PROPERTIES_END = '}';
    private static final String ELEMENT_SEPARATOR = ",";
    private static final char KEY_VALUE_SEPARATOR = ':';
    private static final Splitter COMMA_SPLITTER = Splitter.on(",");
    private static final Splitter COLON_SPLITTER = Splitter.on(':').limit(2);
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final int INDENT = 2;
    private static final int NOT_FOUND = -1;
 
    private NbtUtils() {
    }
 
    @VisibleForTesting
    public static boolean compareNbt(@Nullable Tag expected, @Nullable Tag actual, boolean partialListMatches) {
        if (expected == actual) {
            return true;
        } else if (expected == null) {
            return true;
        } else if (actual == null) {
            return false;
        } else if (!expected.getClass().equals(actual.getClass())) {
            return false;
        } else if (expected instanceof CompoundTag expectedCompound) {
            CompoundTag actualCompound = (CompoundTag)actual;
            if (actualCompound.size() < expectedCompound.size()) {
                return false;
            } else {
                for (Entry<String, Tag> entry : expectedCompound.entrySet()) {
                    Tag tag = entry.getValue();
                    if (!compareNbt(tag, actualCompound.get(entry.getKey()), partialListMatches)) {
                        return false;
                    }
                }
 
                return true;
            }
        } else if (expected instanceof ListTag expectedList && partialListMatches) {
            ListTag actualList = (ListTag)actual;
            if (expectedList.isEmpty()) {
                return actualList.isEmpty();
            } else if (actualList.size() < expectedList.size()) {
                return false;
            } else {
                for (Tag tag : expectedList) {
                    boolean found = false;
 
                    for (Tag value : actualList) {
                        if (compareNbt(tag, value, partialListMatches)) {
                            found = true;
                            break;
                        }
                    }
 
                    if (!found) {
                        return false;
                    }
                }
 
                return true;
            }
        } else {
            return expected.equals(actual);
        }
    }
 
    public static BlockState readBlockState(HolderGetter<Block> blocks, CompoundTag tag) {
        Optional<? extends Holder<Block>> blockHolder = tag.read("Name", BLOCK_NAME_CODEC).flatMap(blocks::get);
        if (blockHolder.isEmpty()) {
            return Blocks.AIR.defaultBlockState();
        } else {
            Block block = blockHolder.get().value();
            BlockState result = block.defaultBlockState();
            Optional<CompoundTag> properties = tag.getCompound("Properties");
            if (properties.isPresent()) {
                StateDefinition<Block, BlockState> definition = block.getStateDefinition();
 
                for (String key : properties.get().keySet()) {
                    Property<?> property = definition.getProperty(key);
                    if (property != null) {
                        result = setValueHelper(result, property, key, properties.get(), tag);
                    }
                }
            }
 
            return result;
        }
    }
 
    private static <S extends StateHolder<?, S>, T extends Comparable<T>> S setValueHelper(
        S result, Property<T> property, String key, CompoundTag properties, CompoundTag tag
    ) {
        Optional<T> value = properties.getString(key).flatMap(property::getValue);
        if (value.isPresent()) {
            return result.setValue(property, value.get());
        } else {
            LOGGER.warn("Unable to read property: {} with value: {} for blockstate: {}", key, properties.get(key), tag);
            return result;
        }
    }
 
    private static void writeStateProperties(StateHolder<?, ?> state, CompoundTag tag) {
        if (!state.isSingletonState()) {
            CompoundTag properties = new CompoundTag();
            state.getValues().forEach(value -> properties.putString(value.property().getName(), value.valueName()));
            tag.put("Properties", properties);
        }
    }
 
    public static CompoundTag writeBlockState(BlockState state) {
        CompoundTag tag = new CompoundTag();
        tag.putString("Name", BuiltInRegistries.BLOCK.getKey(state.getBlock()).toString());
        writeStateProperties(state, tag);
        return tag;
    }
 
    public static CompoundTag writeFluidState(FluidState state) {
        CompoundTag tag = new CompoundTag();
        tag.putString("Name", BuiltInRegistries.FLUID.getKey(state.getType()).toString());
        writeStateProperties(state, tag);
        return tag;
    }
 
    public static String prettyPrint(Tag tag, boolean withBinaryBlobs) {
        return prettyPrint(new StringBuilder(), tag, 0, withBinaryBlobs).toString();
    }
 
    public static StringBuilder prettyPrint(StringBuilder builder, Tag input, int indent, boolean withBinaryBlobs) {
        return switch (input) {
            case PrimitiveTag primitive -> builder.append(primitive);
            case EndTag ignored -> builder;
            case ByteArrayTag tag -> {
                byte[] array = tag.getAsByteArray();
                int length = array.length;
                indent(indent, builder).append("byte[").append(length).append("] {\n");
                if (withBinaryBlobs) {
                    indent(indent + 1, builder);
 
                    for (int i = 0; i < array.length; i++) {
                        if (i != 0) {
                            builder.append(',');
                        }
 
                        if (i % 16 == 0 && i / 16 > 0) {
                            builder.append('\n');
                            if (i < array.length) {
                                indent(indent + 1, builder);
                            }
                        } else if (i != 0) {
                            builder.append(' ');
                        }
 
                        builder.append(String.format(Locale.ROOT, "0x%02X", array[i] & 255));
                    }
                } else {
                    indent(indent + 1, builder).append(" // Skipped, supply withBinaryBlobs true");
                }
 
                builder.append('\n');
                indent(indent, builder).append('}');
                yield builder;
            }
            case ListTag tagx -> {
                int size = tagx.size();
                indent(indent, builder).append("list").append("[").append(size).append("] [");
                if (size != 0) {
                    builder.append('\n');
                }
 
                for (int i = 0; i < size; i++) {
                    if (i != 0) {
                        builder.append(",\n");
                    }
 
                    indent(indent + 1, builder);
                    prettyPrint(builder, tagx.get(i), indent + 1, withBinaryBlobs);
                }
 
                if (size != 0) {
                    builder.append('\n');
                }
 
                indent(indent, builder).append(']');
                yield builder;
            }
            case IntArrayTag tagxx -> {
                int[] array = tagxx.getAsIntArray();
                int size = 0;
 
                for (int i : array) {
                    size = Math.max(size, String.format(Locale.ROOT, "%X", i).length());
                }
 
                int length = array.length;
                indent(indent, builder).append("int[").append(length).append("] {\n");
                if (withBinaryBlobs) {
                    indent(indent + 1, builder);
 
                    for (int i = 0; i < array.length; i++) {
                        if (i != 0) {
                            builder.append(',');
                        }
 
                        if (i % 16 == 0 && i / 16 > 0) {
                            builder.append('\n');
                            if (i < array.length) {
                                indent(indent + 1, builder);
                            }
                        } else if (i != 0) {
                            builder.append(' ');
                        }
 
                        builder.append(String.format(Locale.ROOT, "0x%0" + size + "X", array[i]));
                    }
                } else {
                    indent(indent + 1, builder).append(" // Skipped, supply withBinaryBlobs true");
                }
 
                builder.append('\n');
                indent(indent, builder).append('}');
                yield builder;
            }
            case CompoundTag tagxxx -> {
                List<String> keys = Lists.newArrayList(tagxxx.keySet());
                Collections.sort(keys);
                indent(indent, builder).append('{');
                if (builder.length() - builder.lastIndexOf("\n") > 2 * (indent + 1)) {
                    builder.append('\n');
                    indent(indent + 1, builder);
                }
 
                int paddingLength = keys.stream().mapToInt(String::length).max().orElse(0);
                String padding = Strings.repeat(" ", paddingLength);
 
                for (int i = 0; i < keys.size(); i++) {
                    if (i != 0) {
                        builder.append(",\n");
                    }
 
                    String key = keys.get(i);
                    indent(indent + 1, builder).append('"').append(key).append('"').append(padding, 0, padding.length() - key.length()).append(": ");
                    prettyPrint(builder, tagxxx.get(key), indent + 1, withBinaryBlobs);
                }
 
                if (!keys.isEmpty()) {
                    builder.append('\n');
                }
 
                indent(indent, builder).append('}');
                yield builder;
            }
            case LongArrayTag tagxxxx -> {
                long[] array = tagxxxx.getAsLongArray();
                long size = 0L;
 
                for (long i : array) {
                    size = Math.max(size, (long)String.format(Locale.ROOT, "%X", i).length());
                }
 
                long length = array.length;
                indent(indent, builder).append("long[").append(length).append("] {\n");
                if (withBinaryBlobs) {
                    indent(indent + 1, builder);
 
                    for (int i = 0; i < array.length; i++) {
                        if (i != 0) {
                            builder.append(',');
                        }
 
                        if (i % 16 == 0 && i / 16 > 0) {
                            builder.append('\n');
                            if (i < array.length) {
                                indent(indent + 1, builder);
                            }
                        } else if (i != 0) {
                            builder.append(' ');
                        }
 
                        builder.append(String.format(Locale.ROOT, "0x%0" + size + "X", array[i]));
                    }
                } else {
                    indent(indent + 1, builder).append(" // Skipped, supply withBinaryBlobs true");
                }
 
                builder.append('\n');
                indent(indent, builder).append('}');
                yield builder;
            }
            default -> throw new MatchException(null, null);
        };
    }
 
    private static StringBuilder indent(int indent, StringBuilder builder) {
        int index = builder.lastIndexOf("\n") + 1;
        int len = builder.length() - index;
 
        for (int i = 0; i < 2 * indent - len; i++) {
            builder.append(' ');
        }
 
        return builder;
    }
 
    public static Component toPrettyComponent(Tag tag) {
        return new TextComponentTagVisitor("").visit(tag);
    }
 
    public static String structureToSnbt(CompoundTag structure) {
        return new SnbtPrinterTagVisitor().visit(packStructureTemplate(structure));
    }
 
    public static CompoundTag snbtToStructure(String snbt) throws CommandSyntaxException {
        return unpackStructureTemplate(TagParser.parseCompoundFully(snbt));
    }
 
    @VisibleForTesting
    static CompoundTag packStructureTemplate(CompoundTag snbt) {
        Optional<ListTag> palettes = snbt.getList("palettes");
        ListTag palette;
        if (palettes.isPresent()) {
            palette = palettes.get().getListOrEmpty(0);
        } else {
            palette = snbt.getListOrEmpty("palette");
        }
 
        ListTag deflatedPalette = palette.compoundStream().map(NbtUtils::packBlockState).map(StringTag::valueOf).collect(Collectors.toCollection(ListTag::new));
        snbt.put("palette", deflatedPalette);
        if (palettes.isPresent()) {
            ListTag newPalettes = new ListTag();
            palettes.get().stream().flatMap(tag -> tag.asList().stream()).forEach(oldPalette -> {
                CompoundTag newPalette = new CompoundTag();
 
                for (int i = 0; i < oldPalette.size(); i++) {
                    newPalette.putString(deflatedPalette.getString(i).orElseThrow(), packBlockState(oldPalette.getCompound(i).orElseThrow()));
                }
 
                newPalettes.add(newPalette);
            });
            snbt.put("palettes", newPalettes);
        }
 
        Optional<ListTag> oldEntities = snbt.getList("entities");
        if (oldEntities.isPresent()) {
            ListTag newEntities = oldEntities.get()
                .compoundStream()
                .sorted(Comparator.comparing(tag -> tag.getList("pos"), Comparators.emptiesLast(YXZ_LISTTAG_DOUBLE_COMPARATOR)))
                .collect(Collectors.toCollection(ListTag::new));
            snbt.put("entities", newEntities);
        }
 
        ListTag blockData = snbt.getList("blocks")
            .stream()
            .flatMap(ListTag::compoundStream)
            .sorted(Comparator.comparing(tag -> tag.getList("pos"), Comparators.emptiesLast(YXZ_LISTTAG_INT_COMPARATOR)))
            .peek(block -> block.putString("state", deflatedPalette.getString(block.getIntOr("state", 0)).orElseThrow()))
            .collect(Collectors.toCollection(ListTag::new));
        snbt.put("data", blockData);
        snbt.remove("blocks");
        return snbt;
    }
 
    @VisibleForTesting
    static CompoundTag unpackStructureTemplate(CompoundTag template) {
        ListTag packedPalette = template.getListOrEmpty("palette");
        Map<String, Tag> palette = packedPalette.stream()
            .flatMap(tag -> tag.asString().stream())
            .collect(ImmutableMap.toImmutableMap(Function.identity(), NbtUtils::unpackBlockState));
        Optional<ListTag> oldPalettes = template.getList("palettes");
        if (oldPalettes.isPresent()) {
            template.put(
                "palettes",
                oldPalettes.get()
                    .compoundStream()
                    .map(
                        oldPalette -> palette.keySet()
                            .stream()
                            .map(key -> oldPalette.getString(key).orElseThrow())
                            .map(NbtUtils::unpackBlockState)
                            .collect(Collectors.toCollection(ListTag::new))
                    )
                    .collect(Collectors.toCollection(ListTag::new))
            );
            template.remove("palette");
        } else {
            template.put("palette", palette.values().stream().collect(Collectors.toCollection(ListTag::new)));
        }
 
        Optional<ListTag> maybeBlocks = template.getList("data");
        if (maybeBlocks.isPresent()) {
            Object2IntMap<String> paletteToId = new Object2IntOpenHashMap<>();
            paletteToId.defaultReturnValue(-1);
 
            for (int i = 0; i < packedPalette.size(); i++) {
                paletteToId.put(packedPalette.getString(i).orElseThrow(), i);
            }
 
            ListTag blocks = maybeBlocks.get();
 
            for (int i = 0; i < blocks.size(); i++) {
                CompoundTag block = blocks.getCompound(i).orElseThrow();
                String stateName = block.getString("state").orElseThrow();
                int stateId = paletteToId.getInt(stateName);
                if (stateId == -1) {
                    throw new IllegalStateException("Entry " + stateName + " missing from palette");
                }
 
                block.putInt("state", stateId);
            }
 
            template.put("blocks", blocks);
            template.remove("data");
        }
 
        return template;
    }
 
    @VisibleForTesting
    static String packBlockState(CompoundTag compound) {
        StringBuilder builder = new StringBuilder(compound.getString("Name").orElseThrow());
        compound.getCompound("Properties")
            .ifPresent(
                properties -> {
                    String keyValues = properties.entrySet()
                        .stream()
                        .sorted(Entry.comparingByKey())
                        .map(entry -> entry.getKey() + ":" + entry.getValue().asString().orElseThrow())
                        .collect(Collectors.joining(","));
                    builder.append('{').append(keyValues).append('}');
                }
            );
        return builder.toString();
    }
 
    @VisibleForTesting
    static CompoundTag unpackBlockState(String compound) {
        CompoundTag tag = new CompoundTag();
        int openIndex = compound.indexOf(123);
        String name;
        if (openIndex >= 0) {
            name = compound.substring(0, openIndex);
            CompoundTag properties = new CompoundTag();
            if (openIndex + 2 <= compound.length()) {
                String values = compound.substring(openIndex + 1, compound.indexOf(125, openIndex));
                COMMA_SPLITTER.split(values).forEach(keyValue -> {
                    List<String> parts = COLON_SPLITTER.splitToList(keyValue);
                    if (parts.size() == 2) {
                        properties.putString(parts.get(0), parts.get(1));
                    } else {
                        LOGGER.error("Something went wrong parsing: '{}' -- incorrect gamedata!", compound);
                    }
                });
                tag.put("Properties", properties);
            }
        } else {
            name = compound;
        }
 
        tag.putString("Name", name);
        return tag;
    }
 
    public static CompoundTag addCurrentDataVersion(CompoundTag tag) {
        int version = SharedConstants.getCurrentVersion().dataVersion().version();
        return addDataVersion(tag, version);
    }
 
    public static CompoundTag addDataVersion(CompoundTag tag, int version) {
        tag.putInt("DataVersion", version);
        return tag;
    }
 
    public static <T> Dynamic<T> addDataVersion(Dynamic<T> tag, int version) {
        return tag.set("DataVersion", tag.createInt(version));
    }
 
    public static void addCurrentDataVersion(ValueOutput output) {
        int version = SharedConstants.getCurrentVersion().dataVersion().version();
        addDataVersion(output, version);
    }
 
    public static void addDataVersion(ValueOutput output, int version) {
        output.putInt("DataVersion", version);
    }
 
    public static int getDataVersion(CompoundTag tag) {
        return getDataVersion(tag, -1);
    }
 
    public static int getDataVersion(CompoundTag tag, int _default) {
        return tag.getIntOr("DataVersion", _default);
    }
 
    public static int getDataVersion(Dynamic<?> dynamic) {
        return getDataVersion(dynamic, -1);
    }
 
    public static int getDataVersion(Dynamic<?> dynamic, int _default) {
        return dynamic.get("DataVersion").asInt(_default);
    }
}

引用的其他类