RegionStorageUpgrader.java

net.minecraft.util.worldupdate.RegionStorageUpgrader

信息

  • 全限定名:net.minecraft.util.worldupdate.RegionStorageUpgrader
  • 类型:public class
  • 包:net.minecraft.util.worldupdate
  • 源码路径:src/main/java/net/minecraft/util/worldupdate/RegionStorageUpgrader.java
  • 起始行号:L36
  • 职责:

    TODO

字段/常量

  • LOGGER

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

      TODO

  • NEW_DIRECTORY_PREFIX

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

      TODO

  • REGEX

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

      TODO

  • dataFixer

    • 类型: DataFixer
    • 修饰符: private final
    • 源码定位: L40
    • 说明:

      TODO

  • upgradeProgress

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

      TODO

  • type

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

      TODO

  • folderName

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

      TODO

  • previousWriteFuture

    • 类型: CompletableFuture<Void>
    • 修饰符: protected
    • 源码定位: L44
    • 说明:

      TODO

  • dataFixType

    • 类型: DataFixTypes
    • 修饰符: protected final
    • 源码定位: L45
    • 说明:

      TODO

  • defaultVersion

    • 类型: int
    • 修饰符: protected final
    • 源码定位: L46
    • 说明:

      TODO

  • recreateRegionFiles

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

      TODO

  • dimensionKey

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

      TODO

  • storage

    • 类型: SimpleRegionStorage
    • 修饰符: private
    • 源码定位: L49
    • 说明:

      TODO

  • files

    • 类型: List<FileToUpgrade>
    • 修饰符: private
    • 源码定位: L50
    • 说明:

      TODO

  • startIndex

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

      TODO

  • dataFixContextTag

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

      TODO

  • tagModifiers

    • 类型: Int2ObjectMap<RegionStorageUpgrader.TagModifier>
    • 修饰符: private final
    • 源码定位: L53
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.util.worldupdate.RegionStorageUpgrader.Builder

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

      TODO

  • net.minecraft.util.worldupdate.RegionStorageUpgrader.TagModifier

    • 类型: interface
    • 修饰符: public
    • 源码定位: L378
    • 说明:

      TODO

构造器

protected RegionStorageUpgrader(DataFixer dataFixer, DataFixTypes dataFixType, String type, String folderName, int defaultVersion, boolean recreateRegionFiles, UpgradeProgress upgradeProgress, int startIndex, CompoundTag dataFixContextTag, Int2ObjectMap<RegionStorageUpgrader.TagModifier> tagModifiers) @ L55

  • 构造器名:RegionStorageUpgrader
  • 源码定位:L55
  • 修饰符:protected

参数:

  • dataFixer: DataFixer
  • dataFixType: DataFixTypes
  • type: String
  • folderName: String
  • defaultVersion: int
  • recreateRegionFiles: boolean
  • upgradeProgress: UpgradeProgress
  • startIndex: int
  • dataFixContextTag: CompoundTag
  • tagModifiers: Int2ObjectMap<RegionStorageUpgrader.TagModifier>

说明:

TODO

方法

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

public void init(ResourceKey<Level> dimensionKey, LevelStorageSource.LevelStorageAccess levelStorage) @ L79

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

参数:

  • dimensionKey: ResourceKey
  • levelStorage: LevelStorageSource.LevelStorageAccess

说明:

TODO

public void upgrade() @ L87

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

参数:

说明:

TODO

protected final SimpleRegionStorage createStorage(RegionStorageInfo info, Path regionFolder) @ L137

  • 方法名:createStorage
  • 源码定位:L137
  • 返回类型:SimpleRegionStorage
  • 修饰符:protected final

参数:

  • info: RegionStorageInfo
  • regionFolder: Path

说明:

TODO

private List<FileToUpgrade> getFilesToProcess(RegionStorageInfo info, Path regionFolder) @ L151

  • 方法名:getFilesToProcess
  • 源码定位:L151
  • 返回类型:List
  • 修饰符:private

参数:

  • info: RegionStorageInfo
  • regionFolder: Path

说明:

TODO

public int fileAmount() @ L158

  • 方法名:fileAmount
  • 源码定位:L158
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

private static List<FileToUpgrade> getAllChunkPositions(RegionStorageInfo info, Path regionFolder) @ L162

  • 方法名:getAllChunkPositions
  • 源码定位:L162
  • 返回类型:List
  • 修饰符:private static

参数:

  • info: RegionStorageInfo
  • regionFolder: Path

说明:

TODO

private boolean processOnePosition(SimpleRegionStorage storage, ChunkPos pos) @ L199

  • 方法名:processOnePosition
  • 源码定位:L199
  • 返回类型:boolean
  • 修饰符:private

参数:

  • storage: SimpleRegionStorage
  • pos: ChunkPos

说明:

TODO

protected boolean tryProcessOnePosition(SimpleRegionStorage storage, ChunkPos pos) @ L222

  • 方法名:tryProcessOnePosition
  • 源码定位:L222
  • 返回类型:boolean
  • 修饰符:protected

参数:

  • storage: SimpleRegionStorage
  • pos: ChunkPos

说明:

TODO

protected CompoundTag upgradeTag(SimpleRegionStorage storage, CompoundTag chunkTag, int targetVersion) @ L250

  • 方法名:upgradeTag
  • 源码定位:L250
  • 返回类型:CompoundTag
  • 修饰符:protected

参数:

  • storage: SimpleRegionStorage
  • chunkTag: CompoundTag
  • targetVersion: int

说明:

TODO

private void onFileFinished(RegionFile regionFile) @ L254

  • 方法名:onFileFinished
  • 源码定位:L254
  • 返回类型:void
  • 修饰符:private

参数:

  • regionFile: RegionFile

说明:

TODO

protected static Path resolveRecreateDirectory(Path directoryPath) @ L277

  • 方法名:resolveRecreateDirectory
  • 源码定位:L277
  • 返回类型:Path
  • 修饰符:protected static

参数:

  • directoryPath: Path

说明:

TODO

代码

public class RegionStorageUpgrader {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final String NEW_DIRECTORY_PREFIX = "new_";
    private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
    private final DataFixer dataFixer;
    private final UpgradeProgress upgradeProgress;
    private final String type;
    private final String folderName;
    protected @Nullable CompletableFuture<Void> previousWriteFuture;
    protected final DataFixTypes dataFixType;
    protected final int defaultVersion;
    private final boolean recreateRegionFiles;
    private @Nullable ResourceKey<Level> dimensionKey;
    private @Nullable SimpleRegionStorage storage;
    private @Nullable List<FileToUpgrade> files;
    private final int startIndex;
    private final @Nullable CompoundTag dataFixContextTag;
    private final Int2ObjectMap<RegionStorageUpgrader.TagModifier> tagModifiers;
 
    protected RegionStorageUpgrader(
        DataFixer dataFixer,
        DataFixTypes dataFixType,
        String type,
        String folderName,
        int defaultVersion,
        boolean recreateRegionFiles,
        UpgradeProgress upgradeProgress,
        int startIndex,
        @Nullable CompoundTag dataFixContextTag,
        Int2ObjectMap<RegionStorageUpgrader.TagModifier> tagModifiers
    ) {
        this.dataFixer = dataFixer;
        this.dataFixType = dataFixType;
        this.type = type;
        this.folderName = folderName;
        this.recreateRegionFiles = recreateRegionFiles;
        this.defaultVersion = defaultVersion;
        this.upgradeProgress = upgradeProgress;
        this.startIndex = startIndex;
        this.dataFixContextTag = dataFixContextTag;
        this.tagModifiers = tagModifiers;
    }
 
    public void init(ResourceKey<Level> dimensionKey, LevelStorageSource.LevelStorageAccess levelStorage) {
        RegionStorageInfo info = new RegionStorageInfo(levelStorage.getLevelId(), dimensionKey, this.type);
        Path regionFolder = levelStorage.getDimensionPath(dimensionKey).resolve(this.folderName);
        this.dimensionKey = dimensionKey;
        this.storage = this.createStorage(info, regionFolder);
        this.files = this.getFilesToProcess(info, regionFolder);
    }
 
    public void upgrade() {
        if (this.dimensionKey == null || this.storage == null || this.files == null) {
            throw new IllegalStateException("RegionStorageUpgrader has not been initialized");
        } else if (!this.files.isEmpty()) {
            float totalSize = this.upgradeProgress.getTotalFileFixStats().totalOperations();
            this.upgradeProgress.setStatus(UpgradeProgress.Status.UPGRADING);
            ListIterator<FileToUpgrade> iterator = this.files.listIterator();
 
            while (!this.upgradeProgress.isCanceled()) {
                boolean worked = false;
                float totalProgress = 0.0F;
                if (iterator.hasNext()) {
                    FileToUpgrade fileToUpgrade = iterator.next();
                    boolean converted = true;
 
                    for (ChunkPos chunkPos : fileToUpgrade.chunksToUpgrade()) {
                        converted = converted && this.processOnePosition(this.storage, chunkPos);
                        worked = true;
                    }
 
                    if (this.recreateRegionFiles) {
                        if (converted) {
                            this.onFileFinished(fileToUpgrade.file());
                        } else {
                            LOGGER.error("Failed to convert region file {}", fileToUpgrade.file().getPath());
                        }
                    }
                }
 
                int nextIndex = iterator.nextIndex();
                float currentDimensionProgress = nextIndex / totalSize;
                float currentTotalProgress = (this.startIndex + nextIndex) / totalSize;
                this.upgradeProgress.setDimensionProgress(this.dimensionKey, currentDimensionProgress);
                totalProgress += currentTotalProgress;
                this.upgradeProgress.setTotalProgress(totalProgress);
                if (!worked) {
                    break;
                }
            }
 
            this.upgradeProgress.setStatus(UpgradeProgress.Status.FINISHED);
 
            try {
                this.storage.close();
            } catch (Exception var9) {
                LOGGER.error("Error upgrading chunk", (Throwable)var9);
            }
        }
    }
 
    protected final SimpleRegionStorage createStorage(RegionStorageInfo info, Path regionFolder) {
        return (SimpleRegionStorage)(this.recreateRegionFiles
            ? new RecreatingSimpleRegionStorage(
                info.withTypeSuffix("source"),
                regionFolder,
                info.withTypeSuffix("target"),
                resolveRecreateDirectory(regionFolder),
                this.dataFixer,
                true,
                this.dataFixType
            )
            : new SimpleRegionStorage(info, regionFolder, this.dataFixer, true, this.dataFixType));
    }
 
    private List<FileToUpgrade> getFilesToProcess(RegionStorageInfo info, Path regionFolder) {
        List<FileToUpgrade> filesToUpgrade = getAllChunkPositions(info, regionFolder);
        this.upgradeProgress.addTotalFileFixOperations(filesToUpgrade.size());
        this.upgradeProgress.addTotalChunks(filesToUpgrade.stream().mapToInt(fileToUpgrade -> fileToUpgrade.chunksToUpgrade().size()).sum());
        return filesToUpgrade;
    }
 
    public int fileAmount() {
        return this.files == null ? 0 : this.files.size();
    }
 
    private static List<FileToUpgrade> getAllChunkPositions(RegionStorageInfo info, Path regionFolder) {
        File[] files = regionFolder.toFile().listFiles((dir, name) -> name.endsWith(".mca"));
        if (files == null) {
            return List.of();
        } else {
            List<FileToUpgrade> regionFileChunks = Lists.newArrayList();
 
            for (File regionFile : files) {
                Matcher regex = REGEX.matcher(regionFile.getName());
                if (regex.matches()) {
                    int xOffset = Integer.parseInt(regex.group(1)) << 5;
                    int zOffset = Integer.parseInt(regex.group(2)) << 5;
                    List<ChunkPos> chunkPositions = Lists.newArrayList();
 
                    try (RegionFile regionSource = new RegionFile(info, regionFile.toPath(), regionFolder, true)) {
                        for (int x = 0; x < 32; x++) {
                            for (int z = 0; z < 32; z++) {
                                ChunkPos pos = new ChunkPos(x + xOffset, z + zOffset);
                                if (regionSource.doesChunkExist(pos)) {
                                    chunkPositions.add(pos);
                                }
                            }
                        }
 
                        if (!chunkPositions.isEmpty()) {
                            regionFileChunks.add(new FileToUpgrade(regionSource, chunkPositions));
                        }
                    } catch (Throwable var18) {
                        LOGGER.error("Failed to read chunks from region file {}", regionFile.toPath(), var18);
                    }
                }
            }
 
            return regionFileChunks;
        }
    }
 
    private boolean processOnePosition(SimpleRegionStorage storage, ChunkPos pos) {
        boolean converted = false;
 
        try {
            converted = this.tryProcessOnePosition(storage, pos);
        } catch (CompletionException | ReportedException var6) {
            Throwable cause = var6.getCause();
            if (!(cause instanceof IOException)) {
                throw var6;
            }
 
            LOGGER.error("Error upgrading chunk {}", pos, cause);
        }
 
        if (converted) {
            this.upgradeProgress.incrementConverted();
        } else {
            this.upgradeProgress.incrementSkipped();
        }
 
        return converted;
    }
 
    protected boolean tryProcessOnePosition(SimpleRegionStorage storage, ChunkPos pos) {
        CompoundTag chunkTag = storage.read(pos).join().orElse(null);
        if (chunkTag != null) {
            int version = NbtUtils.getDataVersion(chunkTag);
            int latestVersion = SharedConstants.getCurrentVersion().dataVersion().version();
            boolean changed = false;
 
            for (Entry<RegionStorageUpgrader.TagModifier> tagFixer : this.tagModifiers.int2ObjectEntrySet()) {
                int neededVersion = tagFixer.getIntKey();
                chunkTag = this.upgradeTag(storage, chunkTag, neededVersion);
                changed |= tagFixer.getValue().modifyTagAfterFix(pos, chunkTag);
            }
 
            CompoundTag upgradedTag = this.upgradeTag(storage, chunkTag, latestVersion);
            changed |= version < latestVersion;
            if (changed || this.recreateRegionFiles) {
                if (this.previousWriteFuture != null) {
                    this.previousWriteFuture.join();
                }
 
                this.previousWriteFuture = storage.write(pos, upgradedTag);
                return true;
            }
        }
 
        return false;
    }
 
    protected CompoundTag upgradeTag(SimpleRegionStorage storage, CompoundTag chunkTag, int targetVersion) {
        return storage.upgradeChunkTag(chunkTag, this.defaultVersion, this.dataFixContextTag, targetVersion);
    }
 
    private void onFileFinished(RegionFile regionFile) {
        if (this.recreateRegionFiles) {
            if (this.previousWriteFuture != null) {
                this.previousWriteFuture.join();
            }
 
            Path filePath = regionFile.getPath();
            Path directoryPath = filePath.getParent();
            Path newFilePath = resolveRecreateDirectory(directoryPath).resolve(filePath.getFileName().toString());
 
            try {
                if (newFilePath.toFile().exists()) {
                    Files.delete(filePath);
                    Files.move(newFilePath, filePath);
                } else {
                    LOGGER.error("Failed to replace an old region file. New file {} does not exist.", newFilePath);
                }
            } catch (IOException var6) {
                LOGGER.error("Failed to replace an old region file", (Throwable)var6);
            }
        }
    }
 
    protected static Path resolveRecreateDirectory(Path directoryPath) {
        return directoryPath.resolveSibling("new_" + directoryPath.getFileName().toString());
    }
 
    public static class Builder {
        private final DataFixer dataFixer;
        private @Nullable DataFixTypes dataFixType;
        private @Nullable String type;
        private @Nullable String folderName;
        private int defaultVersion = -1;
        private boolean recreateRegionFiles;
        private UpgradeProgress upgradeProgress = new UpgradeProgress.Noop();
        private @Nullable CompoundTag dataFixContextTag;
        private Int2ObjectAVLTreeMap<RegionStorageUpgrader.TagModifier> tagModifiers = new Int2ObjectAVLTreeMap<>();
 
        public Builder(DataFixer dataFixer) {
            this.dataFixer = dataFixer;
        }
 
        public RegionStorageUpgrader.Builder setDataFixType(DataFixTypes dataFixType) {
            this.dataFixType = dataFixType;
            return this;
        }
 
        public RegionStorageUpgrader.Builder setTypeAndFolderName(String name) {
            return this.setType(name).setFolderName(name);
        }
 
        public RegionStorageUpgrader.Builder setType(String type) {
            this.type = type;
            return this;
        }
 
        public RegionStorageUpgrader.Builder setFolderName(String folderName) {
            this.folderName = folderName;
            return this;
        }
 
        public RegionStorageUpgrader.Builder setDefaultVersion(int defaultVersion) {
            this.defaultVersion = defaultVersion;
            return this;
        }
 
        public RegionStorageUpgrader.Builder setRecreateRegionFiles(boolean recreateRegionFiles) {
            this.recreateRegionFiles = recreateRegionFiles;
            return this;
        }
 
        public RegionStorageUpgrader.Builder trackProgress(UpgradeProgress upgradeProgress) {
            this.upgradeProgress = upgradeProgress;
            return this;
        }
 
        public RegionStorageUpgrader.Builder setDataFixContextTag(@Nullable CompoundTag dataFixContextTag) {
            this.dataFixContextTag = dataFixContextTag;
            return this;
        }
 
        public RegionStorageUpgrader.Builder addTagModifier(int version, RegionStorageUpgrader.TagModifier tagModifier) {
            if (this.tagModifiers.containsKey(version)) {
                throw new IllegalStateException("Can't add two fixers for the same data version");
            } else {
                this.tagModifiers.put(version, tagModifier);
                return this;
            }
        }
 
        private RegionStorageUpgrader.Builder setTagModifiers(Int2ObjectAVLTreeMap<RegionStorageUpgrader.TagModifier> tagModifiers) {
            this.tagModifiers = tagModifiers;
            return this;
        }
 
        public RegionStorageUpgrader.Builder copy() {
            return new RegionStorageUpgrader.Builder(this.dataFixer)
                .setDataFixType(this.dataFixType)
                .setType(this.type)
                .setFolderName(this.folderName)
                .setDefaultVersion(this.defaultVersion)
                .setRecreateRegionFiles(this.recreateRegionFiles)
                .trackProgress(this.upgradeProgress)
                .setDataFixContextTag(this.dataFixContextTag)
                .setTagModifiers(this.tagModifiers.clone());
        }
 
        public RegionStorageUpgrader build(int previousCopiesFileAmounts) {
            return new RegionStorageUpgrader(
                this.dataFixer,
                Objects.requireNonNull(this.dataFixType),
                Objects.requireNonNull(this.type),
                Objects.requireNonNull(this.folderName),
                this.defaultVersion,
                this.recreateRegionFiles,
                this.upgradeProgress,
                previousCopiesFileAmounts,
                this.dataFixContextTag,
                this.tagModifiers
            );
        }
    }
 
    @FunctionalInterface
    public interface TagModifier {
        boolean modifyTagAfterFix(final ChunkPos pos, final CompoundTag upgradedTag);
    }
}

引用的其他类

  • SharedConstants

    • 引用位置: 方法调用
    • 关联成员: SharedConstants.getCurrentVersion()
  • CompoundTag

    • 引用位置: 参数/字段/返回值
  • NbtUtils

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

    • 引用位置: 参数/字段
  • DataFixTypes

    • 引用位置: 参数/字段
  • FileToUpgrade

    • 引用位置: 字段/构造调用/返回值
    • 关联成员: FileToUpgrade()
  • UpgradeProgress

    • 引用位置: 参数/字段/方法调用/构造调用
    • 关联成员: Noop(), UpgradeProgress.Noop()
  • TropicalFish

    • 引用位置: 字段/方法调用
    • 关联成员: Pattern.compile()
  • ChunkPos

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

    • 引用位置: 参数/字段
  • RecreatingSimpleRegionStorage

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

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

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

    • 引用位置: 参数/字段/构造调用/返回值
    • 关联成员: SimpleRegionStorage()
  • LevelStorageSource

    • 引用位置: 参数