LegacyStructureFileFix.java

net.minecraft.util.filefix.fixes.LegacyStructureFileFix

信息

  • 全限定名:net.minecraft.util.filefix.fixes.LegacyStructureFileFix
  • 类型:public class
  • 包:net.minecraft.util.filefix.fixes
  • 源码路径:src/main/java/net/minecraft/util/filefix/fixes/LegacyStructureFileFix.java
  • 起始行号:L44
  • 继承:FileFix
  • 职责:

    TODO

字段/常量

  • STRUCTURE_RANGE

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

      TODO

  • OVERWORLD_LEGACY_STRUCTURES

    • 类型: List<String>
    • 修饰符: public static final
    • 源码定位: L46
    • 说明:

      TODO

  • LEGACY_TO_CURRENT_MAP

    • 类型: Map<String,String>
    • 修饰符: public static final
    • 源码定位: L47
    • 说明:

      TODO

  • NETHER_LEGACY_STRUCTURES

    • 类型: List<String>
    • 修饰符: public static final
    • 源码定位: L53
    • 说明:

      TODO

  • END_LEGACY_STRUCTURES

    • 类型: List<String>
    • 修饰符: public static final
    • 源码定位: L54
    • 说明:

      TODO

  • OVERWORLD_KEY

    • 类型: ResourceKey<Level>
    • 修饰符: private static final
    • 源码定位: L55
    • 说明:

      TODO

  • NETHER_KEY

    • 类型: ResourceKey<Level>
    • 修饰符: private static final
    • 源码定位: L56
    • 说明:

      TODO

  • END_KEY

    • 类型: ResourceKey<Level>
    • 修饰符: private static final
    • 源码定位: L57
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.util.filefix.fixes.LegacyStructureFileFix.DimensionFixEntry

    • 类型: record
    • 修饰符: private
    • 源码定位: L229
    • 说明:

      TODO

  • net.minecraft.util.filefix.fixes.LegacyStructureFileFix.LegacyStructureData

    • 类型: record
    • 修饰符: public
    • 源码定位: L237
    • 说明:

      TODO

构造器

public LegacyStructureFileFix(Schema schema) @ L59

  • 构造器名:LegacyStructureFileFix
  • 源码定位:L59
  • 修饰符:public

参数:

  • schema: Schema

说明:

TODO

方法

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

public void makeFixer() @ L63

  • 方法名:makeFixer
  • 源码定位:L63
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private static void extractAndStoreLegacyStructureData(Dynamic<Tag> levelData, List<LegacyStructureFileFix.DimensionFixEntry> dimensionFixEntries, UpgradeProgress upgradeProgress) @ L110

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

参数:

  • levelData: Dynamic
  • dimensionFixEntries: List<LegacyStructureFileFix.DimensionFixEntry>
  • upgradeProgress: UpgradeProgress

说明:

TODO

private static FileAccess<SavedDataNbt> getLegacyStructureData(FileAccessProvider files, String structureId) @ L153

  • 方法名:getLegacyStructureData
  • 源码定位:L153
  • 返回类型:FileAccess
  • 修饰符:private static

参数:

  • files: FileAccessProvider
  • structureId: String

说明:

TODO

private static void extractLegacyStructureData(Dynamic<Tag> structureData, Long2ObjectMap<LegacyStructureFileFix.LegacyStructureData> extractedDataContainer) @ L160

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

参数:

  • structureData: Dynamic
  • extractedDataContainer: Long2ObjectMap<LegacyStructureFileFix.LegacyStructureData>

说明:

TODO

private static void storeLegacyStructureDataToChunks(Long2ObjectMap<LegacyStructureFileFix.LegacyStructureData> structures, ChunkNbt chunksAccess, CompoundTag dataFixContext, UpgradeProgress upgradeProgress) @ L196

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

参数:

  • structures: Long2ObjectMap<LegacyStructureFileFix.LegacyStructureData>
  • chunksAccess: ChunkNbt
  • dataFixContext: CompoundTag
  • upgradeProgress: UpgradeProgress

说明:

TODO

代码

public class LegacyStructureFileFix extends FileFix {
    public static final int STRUCTURE_RANGE = 8;
    public static final List<String> OVERWORLD_LEGACY_STRUCTURES = List.of("Monument", "Stronghold", "Mineshaft", "Temple", "Mansion");
    public static final Map<String, String> LEGACY_TO_CURRENT_MAP = Util.make(Maps.newHashMap(), map -> {
        map.put("Iglu", "Igloo");
        map.put("TeDP", "Desert_Pyramid");
        map.put("TeJP", "Jungle_Pyramid");
        map.put("TeSH", "Swamp_Hut");
    });
    public static final List<String> NETHER_LEGACY_STRUCTURES = List.of("Fortress");
    public static final List<String> END_LEGACY_STRUCTURES = List.of("EndCity");
    private static final ResourceKey<Level> OVERWORLD_KEY = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("overworld"));
    private static final ResourceKey<Level> NETHER_KEY = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("the_nether"));
    private static final ResourceKey<Level> END_KEY = ResourceKey.create(Registries.DIMENSION, Identifier.withDefaultNamespace("the_end"));
 
    public LegacyStructureFileFix(Schema schema) {
        super(schema);
    }
 
    @Override
    public void makeFixer() {
        this.addFileContentFix(
            files -> {
                List<FileAccess<SavedDataNbt>> overworldStructureData = OVERWORLD_LEGACY_STRUCTURES.stream()
                    .map(structureId -> getLegacyStructureData(files, structureId))
                    .toList();
                RegionStorageInfo overworldInfo = new RegionStorageInfo("overworld", OVERWORLD_KEY, "chunk");
                List<FileAccess<SavedDataNbt>> netherStructureData = NETHER_LEGACY_STRUCTURES.stream()
                    .map(structureId -> getLegacyStructureData(files, structureId))
                    .toList();
                RegionStorageInfo netherInfo = new RegionStorageInfo("the_nether", NETHER_KEY, "chunk");
                List<FileAccess<SavedDataNbt>> endStructureData = END_LEGACY_STRUCTURES.stream()
                    .map(structureId -> getLegacyStructureData(files, structureId))
                    .toList();
                RegionStorageInfo endInfo = new RegionStorageInfo("the_end", END_KEY, "chunk");
                FileAccess<LevelDat> levelDat = files.getFileAccess(FileResourceTypes.LEVEL_DAT, FileRelation.ORIGIN.forFile("level.dat"));
                FileAccess<ChunkNbt> overworldChunks = files.getFileAccess(
                    FileResourceTypes.chunk(DataFixTypes.CHUNK, overworldInfo), FileRelation.OLD_OVERWORLD.resolve(FileRelation.REGION)
                );
                FileAccess<ChunkNbt> netherChunks = files.getFileAccess(
                    FileResourceTypes.chunk(DataFixTypes.CHUNK, netherInfo), FileRelation.OLD_NETHER.resolve(FileRelation.REGION)
                );
                FileAccess<ChunkNbt> endChunks = files.getFileAccess(
                    FileResourceTypes.chunk(DataFixTypes.CHUNK, endInfo), FileRelation.OLD_END.resolve(FileRelation.REGION)
                );
                return upgradeProgress -> {
                    Optional<Dynamic<Tag>> levelData = levelDat.getOnlyFile().read();
                    if (!levelData.isEmpty()) {
                        upgradeProgress.setType(UpgradeProgress.Type.LEGACY_STRUCTURES);
                        extractAndStoreLegacyStructureData(
                            levelData.get(),
                            List.of(
                                new LegacyStructureFileFix.DimensionFixEntry(
                                    OVERWORLD_KEY, overworldStructureData, overworldChunks, new Long2ObjectOpenHashMap<>()
                                ),
                                new LegacyStructureFileFix.DimensionFixEntry(NETHER_KEY, netherStructureData, netherChunks, new Long2ObjectOpenHashMap<>()),
                                new LegacyStructureFileFix.DimensionFixEntry(END_KEY, endStructureData, endChunks, new Long2ObjectOpenHashMap<>())
                            ),
                            upgradeProgress
                        );
                    }
                };
            }
        );
    }
 
    private static void extractAndStoreLegacyStructureData(
        Dynamic<Tag> levelData, List<LegacyStructureFileFix.DimensionFixEntry> dimensionFixEntries, UpgradeProgress upgradeProgress
    ) throws IOException {
        upgradeProgress.setStatus(UpgradeProgress.Status.COUNTING);
 
        for (LegacyStructureFileFix.DimensionFixEntry dimensionFixEntry : dimensionFixEntries) {
            Long2ObjectOpenHashMap<LegacyStructureFileFix.LegacyStructureData> structures = dimensionFixEntry.structures;
 
            for (FileAccess<SavedDataNbt> structureDataFileAccess : dimensionFixEntry.structureFileAccess) {
                SavedDataNbt targetFile = structureDataFileAccess.getOnlyFile();
                Optional<Dynamic<Tag>> structureData = targetFile.read();
                if (!structureData.isEmpty()) {
                    extractLegacyStructureData(structureData.get(), structures);
                }
            }
 
            upgradeProgress.addTotalFileFixOperations(structures.size());
        }
 
        upgradeProgress.setStatus(UpgradeProgress.Status.UPGRADING);
 
        for (LegacyStructureFileFix.DimensionFixEntry dimensionFixEntry : dimensionFixEntries) {
            ResourceKey<Level> dimensionKey = dimensionFixEntry.dimensionKey;
            ChunkNbt chunkNbt = dimensionFixEntry.chunkFileAccess.getOnlyFile();
            String chunkGeneratorType;
            if (dimensionKey == OVERWORLD_KEY) {
                String generatorName = levelData.get("generatorName").asString("buffet");
 
                chunkGeneratorType = switch (generatorName) {
                    case "flat" -> "minecraft:flat";
                    case "debug_all_block_states" -> "minecraft:debug";
                    default -> "minecraft:noise";
                };
            } else {
                chunkGeneratorType = "minecraft:noise";
            }
 
            Optional<Identifier> generatorIdentifier = Optional.ofNullable(Identifier.tryParse(chunkGeneratorType));
            CompoundTag dataFixContext = ChunkMap.getChunkDataFixContextTag(dimensionKey, generatorIdentifier);
            storeLegacyStructureDataToChunks(dimensionFixEntry.structures, chunkNbt, dataFixContext, upgradeProgress);
        }
    }
 
    private static FileAccess<SavedDataNbt> getLegacyStructureData(FileAccessProvider files, String structureId) {
        return files.getFileAccess(
            FileResourceTypes.savedData(References.SAVED_DATA_STRUCTURE_FEATURE_INDICES, CompressedNbt.MissingSeverity.MINOR),
            FileRelation.DATA.forFile(structureId + ".dat")
        );
    }
 
    private static void extractLegacyStructureData(
        Dynamic<Tag> structureData, Long2ObjectMap<LegacyStructureFileFix.LegacyStructureData> extractedDataContainer
    ) {
        OptionalDynamic<Tag> features = structureData.get("Features");
        Map<Dynamic<Tag>, Dynamic<Tag>> map = features.asMap(Function.identity(), Function.identity());
 
        for (Dynamic<Tag> value : map.values()) {
            long pos = ChunkPos.pack(value.get("ChunkX").asInt(0), value.get("ChunkZ").asInt(0));
            List<Dynamic<Tag>> childList = value.get("Children").asList(Function.identity());
            if (!childList.isEmpty()) {
                Optional<String> id = childList.getFirst().get("id").asString().result().map(LEGACY_TO_CURRENT_MAP::get);
                if (id.isPresent()) {
                    value = value.set("id", value.createString(id.get()));
                }
            }
 
            Dynamic<Tag> finalValue = value;
            value.get("id")
                .asString()
                .ifSuccess(
                    id -> {
                        extractedDataContainer.computeIfAbsent(pos, l -> new LegacyStructureFileFix.LegacyStructureData()).addStart(id, finalValue);
 
                        for (int neighborX = ChunkPos.getX(pos) - 8; neighborX <= ChunkPos.getX(pos) + 8; neighborX++) {
                            for (int neighborZ = ChunkPos.getZ(pos) - 8; neighborZ <= ChunkPos.getZ(pos) + 8; neighborZ++) {
                                extractedDataContainer.computeIfAbsent(
                                        ChunkPos.pack(neighborX, neighborZ), l -> new LegacyStructureFileFix.LegacyStructureData()
                                    )
                                    .addIndex(id, pos);
                            }
                        }
                    }
                );
        }
    }
 
    private static void storeLegacyStructureDataToChunks(
        Long2ObjectMap<LegacyStructureFileFix.LegacyStructureData> structures,
        ChunkNbt chunksAccess,
        CompoundTag dataFixContext,
        UpgradeProgress upgradeProgress
    ) {
        for (Entry<LegacyStructureFileFix.LegacyStructureData> entry : structures.long2ObjectEntrySet()
            .stream()
            .sorted(Comparator.comparingLong(entryx -> ChunkPos.pack(ChunkPos.getRegionX(entryx.getLongKey()), ChunkPos.getRegionZ(entryx.getLongKey()))))
            .toList()) {
            if (upgradeProgress.isCanceled()) {
                throw new CanceledFileFixException();
            }
 
            long pos = entry.getLongKey();
            LegacyStructureFileFix.LegacyStructureData legacyData = entry.getValue();
            chunksAccess.updateChunk(ChunkPos.unpack(pos), dataFixContext, tag -> {
                CompoundTag levelTag = tag.getCompoundOrEmpty("Level");
                CompoundTag structureTag = levelTag.getCompoundOrEmpty("Structures");
                CompoundTag startTag = structureTag.getCompoundOrEmpty("Starts");
                CompoundTag referencesTag = structureTag.getCompoundOrEmpty("References");
                legacyData.starts().forEach((id, value) -> startTag.put(id, value.convert(NbtOps.INSTANCE).getValue()));
                legacyData.indexes().forEach((id, indexes) -> referencesTag.putLongArray(id, indexes.toLongArray()));
                structureTag.put("Starts", startTag);
                structureTag.put("References", referencesTag);
                levelTag.put("Structures", structureTag);
                tag.put("Level", levelTag);
                return tag;
            });
            upgradeProgress.incrementFinishedOperationsBy(1);
        }
    }
 
    private record DimensionFixEntry(
        ResourceKey<Level> dimensionKey,
        List<FileAccess<SavedDataNbt>> structureFileAccess,
        FileAccess<ChunkNbt> chunkFileAccess,
        Long2ObjectOpenHashMap<LegacyStructureFileFix.LegacyStructureData> structures
    ) {
    }
 
    public record LegacyStructureData(Map<String, Dynamic<?>> starts, Map<String, LongList> indexes) {
        public LegacyStructureData() {
            this(new HashMap<>(), new HashMap<>());
        }
 
        public void addStart(String id, Dynamic<Tag> data) {
            this.starts.put(id, data);
        }
 
        public void addIndex(String id, long sourcePos) {
            this.indexes.computeIfAbsent(id, l -> new LongArrayList()).add(sourcePos);
        }
    }
}

引用的其他类

  • CompoundTag

    • 引用位置: 参数
  • Tag

    • 引用位置: 参数
  • Identifier

    • 引用位置: 方法调用
    • 关联成员: Identifier.tryParse(), Identifier.withDefaultNamespace()
  • ResourceKey

    • 引用位置: 字段/方法调用
    • 关联成员: ResourceKey.create()
  • Schema

    • 引用位置: 参数
  • ChunkMap

    • 引用位置: 方法调用
    • 关联成员: ChunkMap.getChunkDataFixContextTag()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.make()
  • CanceledFileFixException

    • 引用位置: 构造调用
    • 关联成员: CanceledFileFixException()
  • FileFix

    • 引用位置: 继承
  • ChunkNbt

    • 引用位置: 参数
  • FileAccess

    • 引用位置: 返回值
  • FileAccessProvider

    • 引用位置: 参数
  • FileResourceTypes

    • 引用位置: 方法调用
    • 关联成员: FileResourceTypes.chunk(), FileResourceTypes.savedData()
  • SavedDataNbt

    • 引用位置: 返回值
  • UpgradeProgress

    • 引用位置: 参数
  • ResolvableProfile

    • 引用位置: 参数
  • ChunkPos

    • 引用位置: 方法调用
    • 关联成员: ChunkPos.getRegionX(), ChunkPos.getRegionZ(), ChunkPos.getX(), ChunkPos.getZ(), ChunkPos.pack(), ChunkPos.unpack()
  • Level

    • 引用位置: 字段
  • RegionStorageInfo

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