FileFixerUpper.java
net.minecraft.util.filefix.FileFixerUpper
信息
- 全限定名:net.minecraft.util.filefix.FileFixerUpper
- 类型:public class
- 包:net.minecraft.util.filefix
- 源码路径:src/main/java/net/minecraft/util/filefix/FileFixerUpper.java
- 起始行号:L50
- 职责:
TODO
字段/常量
-
FILE_FIXER_INTRODUCTION_VERSION- 类型:
int - 修饰符:
private static final - 源码定位:
L51 - 说明:
TODO
- 类型:
-
GSON- 类型:
Gson - 修饰符:
private static final - 源码定位:
L52 - 说明:
TODO
- 类型:
-
FILE_FIX_DIRECTORY_NAME- 类型:
String - 修饰符:
private static final - 源码定位:
L53 - 说明:
TODO
- 类型:
-
NEW_WORLD_TEMP_NAME- 类型:
String - 修饰符:
private static final - 源码定位:
L54 - 说明:
TODO
- 类型:
-
UPGRADE_IN_PROGRESS_NAME- 类型:
String - 修饰符:
private static final - 源码定位:
L55 - 说明:
TODO
- 类型:
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L56 - 说明:
TODO
- 类型:
-
dataFixer- 类型:
Result - 修饰符:
private final - 源码定位:
L57 - 说明:
TODO
- 类型:
-
fileFixes- 类型:
List<FileFix> - 修饰符:
private final - 源码定位:
L58 - 说明:
TODO
- 类型:
-
latestFileFixerVersion- 类型:
int - 修饰符:
private final - 源码定位:
L59 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.util.filefix.FileFixerUpper.Builder- 类型:
class - 修饰符:
public static - 源码定位:
L435 - 说明:
TODO
- 类型:
-
net.minecraft.util.filefix.FileFixerUpper.UpgradeInProgress- 类型:
record - 修饰符:
public - 源码定位:
L491 - 说明:
TODO
- 类型:
构造器
public FileFixerUpper(Result dataFixer, List<FileFix> fileFixes, int latestFileFixerVersion) @ L61
- 构造器名:FileFixerUpper
- 源码定位:L61
- 修饰符:public
参数:
- dataFixer: Result
- fileFixes: List
- latestFileFixerVersion: int
说明:
TODO
方法
下面的方法块按源码顺序生成。
public static int worldVersionToFileFixerVersion(int levelDataVersion) @ L67
- 方法名:worldVersionToFileFixerVersion
- 源码定位:L67
- 返回类型:int
- 修饰符:public static
参数:
- levelDataVersion: int
说明:
TODO
public boolean requiresFileFixing(int levelDataVersion) @ L71
- 方法名:requiresFileFixing
- 源码定位:L71
- 返回类型:boolean
- 修饰符:public
参数:
- levelDataVersion: int
说明:
TODO
public Dynamic<?> fix(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, UpgradeProgress upgradeProgress) @ L75
- 方法名:fix
- 源码定位:L75
- 返回类型:Dynamic<?>
- 修饰符:public
参数:
- worldAccess: LevelStorageSource.LevelStorageAccess
- levelDataTag: Dynamic<?>
- upgradeProgress: UpgradeProgress
说明:
TODO
public Dynamic<?> fix(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, UpgradeProgress upgradeProgress, int toVersion) @ L79
- 方法名:fix
- 源码定位:L79
- 返回类型:Dynamic<?>
- 修饰符:public
参数:
- worldAccess: LevelStorageSource.LevelStorageAccess
- levelDataTag: Dynamic<?>
- upgradeProgress: UpgradeProgress
- toVersion: int
说明:
TODO
private List<FileMove> startOrContinueFileFixing(UpgradeProgress upgradeProgress, int toVersion, Path worldFolder, Path tempWorld, Path fileFixDirectory, int loadedVersion) @ L118
- 方法名:startOrContinueFileFixing
- 源码定位:L118
- 返回类型:List
- 修饰符:private
参数:
- upgradeProgress: UpgradeProgress
- toVersion: int
- worldFolder: Path
- tempWorld: Path
- fileFixDirectory: Path
- loadedVersion: int
说明:
TODO
private static void deleteDirectory(Path directory) @ L143
- 方法名:deleteDirectory
- 源码定位:L143
- 返回类型:void
- 修饰符:private static
参数:
- directory: Path
说明:
TODO
private static void cleanup(Path fileFixDirectory) @ L168
- 方法名:cleanup
- 源码定位:L168
- 返回类型:void
- 修饰符:private static
参数:
- fileFixDirectory: Path
说明:
TODO
private List<FileMove> applyFileFixersOnCow(UpgradeProgress upgradeProgress, int loadedVersion, int toVersion, Path worldFolder, Path fileFixDirectory, Path tempWorld) @ L176
- 方法名:applyFileFixersOnCow
- 源码定位:L176
- 返回类型:List
- 修饰符:private
参数:
- upgradeProgress: UpgradeProgress
- loadedVersion: int
- toVersion: int
- worldFolder: Path
- fileFixDirectory: Path
- tempWorld: Path
说明:
TODO
public void applyFileFixers(UpgradeProgress upgradeProgress, int loadedVersion, int toVersion, Path basePath) @ L194
- 方法名:applyFileFixers
- 源码定位:L194
- 返回类型:void
- 修饰符:public
参数:
- upgradeProgress: UpgradeProgress
- loadedVersion: int
- toVersion: int
- basePath: Path
说明:
TODO
private List<FileFix> getApplicableFixers(int fromVersion, int toVersion) @ L212
- 方法名:getApplicableFixers
- 源码定位:L212
- 返回类型:List
- 修饰符:private
参数:
- fromVersion: int
- toVersion: int
说明:
TODO
private void countFiles(List<FileFix> applicableFixers, UpgradeProgress upgradeProgress) @ L217
- 方法名:countFiles
- 源码定位:L217
- 返回类型:void
- 修饰符:private
参数:
- applicableFixers: List
- upgradeProgress: UpgradeProgress
说明:
TODO
private void writeUpdatedLevelData(Path worldFolder, int toVersion) @ L228
- 方法名:writeUpdatedLevelData
- 源码定位:L228
- 返回类型:void
- 修饰符:private
参数:
- worldFolder: Path
- toVersion: int
说明:
TODO
private static Dynamic<?> addVersionsToLevelData(Dynamic<?> fixed, int toVersion) @ L239
- 方法名:addVersionsToLevelData
- 源码定位:L239
- 返回类型:Dynamic<?>
- 修饰符:private static
参数:
- fixed: Dynamic<?>
- toVersion: int
说明:
TODO
protected static void swapInFixedWorld(LevelStorageSource.LevelStorageAccess worldAccess, List<FileMove> moves, Path fileFixDirectory, Path tempWorld) @ L245
- 方法名:swapInFixedWorld
- 源码定位:L245
- 返回类型:void
- 修饰符:protected static
参数:
- worldAccess: LevelStorageSource.LevelStorageAccess
- moves: List
- fileFixDirectory: Path
- tempWorld: Path
说明:
TODO
private static void writeMoves(List<FileMove> moves, Path fromDirectory, Path toDirectory, Path filePath) @ L375
- 方法名:writeMoves
- 源码定位:L375
- 返回类型:void
- 修饰符:private static
参数:
- moves: List
- fromDirectory: Path
- toDirectory: Path
- filePath: Path
说明:
TODO
private static List<FileMove> readMoves(Path fromDirectory, Path toDirectory, Path filePath) @ L381
- 方法名:readMoves
- 源码定位:L381
- 返回类型:List
- 修饰符:private static
参数:
- fromDirectory: Path
- toDirectory: Path
- filePath: Path
说明:
TODO
public static FileSystemCapabilities detectFileSystemCapabilities(Path dir) @ L387
- 方法名:detectFileSystemCapabilities
- 源码定位:L387
- 返回类型:FileSystemCapabilities
- 修饰符:public static
参数:
- dir: Path
说明:
TODO
private static boolean supportsAtomicMove(Path dir) @ L391
- 方法名:supportsAtomicMove
- 源码定位:L391
- 返回类型:boolean
- 修饰符:private static
参数:
- dir: Path
说明:
TODO
private static boolean supportsHardLinks(Path dir) @ L413
- 方法名:supportsHardLinks
- 源码定位:L413
- 返回类型:boolean
- 修饰符:private static
参数:
- dir: Path
说明:
TODO
代码
public class FileFixerUpper {
private static final int FILE_FIXER_INTRODUCTION_VERSION = 4772;
private static final Gson GSON = new Gson().newBuilder().setPrettyPrinting().create();
private static final String FILE_FIX_DIRECTORY_NAME = "filefix";
private static final String NEW_WORLD_TEMP_NAME = "new_world";
private static final String UPGRADE_IN_PROGRESS_NAME = "upgrade_in_progress.json";
private static final Logger LOGGER = LogUtils.getLogger();
private final Result dataFixer;
private final List<FileFix> fileFixes;
private final int latestFileFixerVersion;
public FileFixerUpper(Result dataFixer, List<FileFix> fileFixes, int latestFileFixerVersion) {
this.dataFixer = dataFixer;
this.fileFixes = List.copyOf(fileFixes);
this.latestFileFixerVersion = latestFileFixerVersion;
}
public static int worldVersionToFileFixerVersion(int levelDataVersion) {
return levelDataVersion < 4772 ? 0 : levelDataVersion;
}
public boolean requiresFileFixing(int levelDataVersion) {
return worldVersionToFileFixerVersion(levelDataVersion) < this.latestFileFixerVersion;
}
public Dynamic<?> fix(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, UpgradeProgress upgradeProgress) throws FileFixException {
return this.fix(worldAccess, levelDataTag, upgradeProgress, SharedConstants.getCurrentVersion().dataVersion().version());
}
@VisibleForTesting
public Dynamic<?> fix(LevelStorageSource.LevelStorageAccess worldAccess, Dynamic<?> levelDataTag, UpgradeProgress upgradeProgress, int toVersion) throws FileFixException {
int loadedVersion = NbtUtils.getDataVersion(levelDataTag);
if (this.requiresFileFixing(loadedVersion)) {
LOGGER.info("Starting upgrade for world \"{}\"", worldAccess.getLevelId());
Path worldFolder = worldAccess.getLevelDirectory().path();
Path fileFixDirectory = worldFolder.resolve("filefix");
Path tempWorld = fileFixDirectory.resolve("new_world");
List<FileMove> moves;
try {
moves = this.startOrContinueFileFixing(upgradeProgress, toVersion, worldFolder, tempWorld, fileFixDirectory, loadedVersion);
} catch (IOException var12) {
throw new AbortedFileFixException(var12);
}
try {
swapInFixedWorld(worldAccess, moves, fileFixDirectory, tempWorld);
} catch (AbortedFileFixException var13) {
if (var13.notRevertedMoves().isEmpty()) {
cleanup(fileFixDirectory);
}
throw var13;
}
try {
levelDataTag = worldAccess.getUnfixedDataTag(false);
} catch (IOException var11) {
throw new UncheckedIOException(var11);
}
loadedVersion = NbtUtils.getDataVersion(levelDataTag);
}
Dynamic<?> fixedLevelDataTag = DataFixTypes.LEVEL.updateToCurrentVersion(this.dataFixer.fixer(), levelDataTag, loadedVersion);
return addVersionsToLevelData(fixedLevelDataTag, toVersion);
}
private List<FileMove> startOrContinueFileFixing(
UpgradeProgress upgradeProgress, int toVersion, Path worldFolder, Path tempWorld, Path fileFixDirectory, int loadedVersion
) throws IOException {
Path upgradeInProgressFile = fileFixDirectory.resolve("upgrade_in_progress.json");
List<FileMove> moves;
if (Files.exists(upgradeInProgressFile)) {
LOGGER.warn("Found previously interrupted world upgrade, attempting to continue it");
moves = readMoves(worldFolder, tempWorld, upgradeInProgressFile);
} else {
if (Files.exists(fileFixDirectory)) {
deleteDirectory(fileFixDirectory);
}
try {
Files.createDirectory(fileFixDirectory);
moves = this.applyFileFixersOnCow(upgradeProgress, loadedVersion, toVersion, worldFolder, fileFixDirectory, tempWorld);
} catch (Exception var10) {
cleanup(fileFixDirectory);
throw var10;
}
}
return moves;
}
private static void deleteDirectory(Path directory) throws IOException {
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
public FileVisitResult visitFile(Path realPath, BasicFileAttributes attrs) {
try {
Files.deleteIfExists(realPath);
} catch (IOException var4) {
}
return FileVisitResult.CONTINUE;
}
public FileVisitResult postVisitDirectory(Path realPath, @Nullable IOException e) {
try {
Files.deleteIfExists(realPath);
} catch (IOException var4) {
}
return FileVisitResult.CONTINUE;
}
});
if (Files.exists(directory)) {
PathUtils.deleteDirectory(directory);
}
}
private static void cleanup(Path fileFixDirectory) {
try {
deleteDirectory(fileFixDirectory);
} catch (Exception var2) {
LOGGER.error("Failed to clean up", (Throwable)var2);
}
}
private List<FileMove> applyFileFixersOnCow(
UpgradeProgress upgradeProgress, int loadedVersion, int toVersion, Path worldFolder, Path fileFixDirectory, Path tempWorld
) throws IOException {
List var9;
try (CopyOnWriteFileSystem fs = CopyOnWriteFileSystem.create(
worldFolder.getFileName().toString(), worldFolder, fileFixDirectory.resolve("cow"), fileFixDirectory::equals
)) {
this.applyFileFixers(upgradeProgress, loadedVersion, toVersion, fs.rootPath());
CopyOnWriteFileSystem.Moves moves = fs.collectMoveOperations(tempWorld);
Files.createDirectory(tempWorld);
CopyOnWriteFileSystem.createDirectories(moves.directories());
CopyOnWriteFileSystem.moveFiles(moves.copiedFiles());
var9 = moves.preexistingFiles();
}
return var9;
}
@VisibleForTesting
public void applyFileFixers(UpgradeProgress upgradeProgress, int loadedVersion, int toVersion, Path basePath) throws IOException {
List<FileFix> applicableFixers = this.getApplicableFixers(loadedVersion, toVersion);
upgradeProgress.setType(UpgradeProgress.Type.FILES);
this.countFiles(applicableFixers, upgradeProgress);
upgradeProgress.setStatus(UpgradeProgress.Status.UPGRADING);
upgradeProgress.setApplicableFixerAmount(applicableFixers.size());
for (FileFix fileFix : applicableFixers) {
upgradeProgress.incrementRunningFileFixer();
fileFix.runFixOperations(basePath, upgradeProgress);
}
this.writeUpdatedLevelData(basePath, toVersion);
Files.deleteIfExists(basePath.resolve("level.dat_old"));
Files.deleteIfExists(basePath.resolve("session.lock"));
}
private List<FileFix> getApplicableFixers(int fromVersion, int toVersion) {
int fileFixerFromVersion = worldVersionToFileFixerVersion(fromVersion);
return this.fileFixes.stream().filter(fileFix -> fileFix.getVersion() > fileFixerFromVersion && fileFix.getVersion() <= toVersion).toList();
}
private void countFiles(List<FileFix> applicableFixers, UpgradeProgress upgradeProgress) {
upgradeProgress.setStatus(UpgradeProgress.Status.COUNTING);
int totalFiles = 0;
for (FileFix fileFix : applicableFixers) {
totalFiles += fileFix.countFileOperations();
}
upgradeProgress.addTotalFileFixOperations(totalFiles);
}
private void writeUpdatedLevelData(Path worldFolder, int toVersion) throws IOException {
Path levelDatPath = worldFolder.resolve(LevelResource.LEVEL_DATA_FILE.id());
CompoundTag unfixedLevelDat = NbtIo.readCompressed(levelDatPath, NbtAccounter.defaultQuota());
CompoundTag unfixedDataTag = unfixedLevelDat.getCompoundOrEmpty("Data");
int dataVersion = NbtUtils.getDataVersion(unfixedDataTag);
Dynamic<?> fixed = DataFixTypes.LEVEL.update(this.dataFixer.fixer(), new Dynamic<>(NbtOps.INSTANCE, unfixedDataTag), dataVersion, toVersion);
fixed = addVersionsToLevelData(fixed, toVersion);
Dynamic<?> dynamic = fixed.emptyMap().set("Data", fixed);
NbtIo.writeCompressed((CompoundTag)dynamic.convert(NbtOps.INSTANCE).getValue(), levelDatPath);
}
private static Dynamic<?> addVersionsToLevelData(Dynamic<?> fixed, int toVersion) {
fixed = NbtUtils.addDataVersion(fixed, toVersion);
fixed = PrimaryLevelData.writeLastPlayed(fixed);
return PrimaryLevelData.writeVersionTag(fixed);
}
@VisibleForTesting
protected static void swapInFixedWorld(LevelStorageSource.LevelStorageAccess worldAccess, List<FileMove> moves, Path fileFixDirectory, Path tempWorld) throws FileFixException {
Path worldFolder = worldAccess.getLevelDirectory().path();
Path savesDirectory = worldFolder.getParent();
String worldName = worldFolder.getFileName().toString();
Path tempWorldTopLevel;
Path oldWorldFolder;
FileSystemCapabilities fileSystemCapabilities;
try {
fileSystemCapabilities = detectFileSystemCapabilities(fileFixDirectory);
tempWorldTopLevel = savesDirectory.resolve(FileUtil.findAvailableName(savesDirectory, worldName + " upgraded", ""));
oldWorldFolder = savesDirectory.resolve(FileUtil.findAvailableName(savesDirectory, worldName + " OUTDATED", ""));
} catch (Exception var21) {
throw new AbortedFileFixException(var21);
}
if (!fileSystemCapabilities.atomicMove()) {
throw new AtomicMoveNotSupportedFileFixException(fileSystemCapabilities);
} else {
CopyOption[] moveOptions = fileSystemCapabilities.getMoveOptions();
LOGGER.info("File system capabilities: {}", fileSystemCapabilities);
Path movesFile = fileFixDirectory.resolve("upgrade_in_progress.json");
try {
if (fileSystemCapabilities.hardLinks()) {
CopyOnWriteFileSystem.hardLinkFiles(moves);
} else {
writeMoves(moves, worldFolder, tempWorld, movesFile);
}
} catch (Exception var20) {
throw new AbortedFileFixException(var20, List.of(), fileSystemCapabilities);
}
LOGGER.info("Applying file structure changes for world \"{}\"", worldAccess.getLevelId());
if (fileSystemCapabilities.hardLinks()) {
try {
LOGGER.info("Moving new hardlinked world to top level");
Files.move(tempWorld, tempWorldTopLevel, moveOptions);
} catch (Exception var19) {
LOGGER.error("Encountered error trying to move world folder:", (Throwable)var19);
throw new AbortedFileFixException(var19, List.of(), fileSystemCapabilities);
}
} else {
try {
LOGGER.info("Moving files into new file structure");
CopyOnWriteFileSystem.moveFilesWithRetry(moves, moveOptions);
LOGGER.info("Moving new world to top level");
Files.move(tempWorld, tempWorldTopLevel, moveOptions);
} catch (Exception var23) {
LOGGER.error("Encountered error while trying to create new world folder:", (Throwable)var23);
List<FileMove> failedMoves = CopyOnWriteFileSystem.tryRevertMoves(moves, moveOptions);
if (failedMoves.isEmpty()) {
try {
Files.deleteIfExists(movesFile);
} catch (IOException var15) {
LOGGER.warn("Failed to delete {}", movesFile, var23);
}
}
throw new AbortedFileFixException(var23, failedMoves, fileSystemCapabilities);
}
LOGGER.info("Complete move");
try {
Files.deleteIfExists(movesFile);
} catch (IOException var18) {
LOGGER.warn("Failed to delete {}", movesFile, var18);
}
}
LOGGER.info("Start cleanup");
try {
Files.deleteIfExists(worldFolder.resolve("level.dat"));
Files.deleteIfExists(worldFolder.resolve("level.dat_old"));
} catch (Exception var17) {
LOGGER.warn("Failed to delete outdated level.dat files: ", (Throwable)var17);
}
MutableBoolean succeeded = new MutableBoolean();
try {
worldAccess.releaseTemporarilyAndRun(() -> {
LOGGER.info("Moving out old world folder");
try {
Files.move(worldFolder, oldWorldFolder, moveOptions);
} catch (Exception var10x) {
LOGGER.warn("Failed to move outdated world folder out of the way; will try to delete instead: ", (Throwable)var10x);
try {
deleteDirectory(worldFolder);
} catch (Exception var9x) {
LOGGER.warn("Failed to delete outdated world folder: ", (Throwable)var10x);
throw new FailedCleanupFileFixException(var10x, tempWorldTopLevel.getFileName().toString(), fileSystemCapabilities);
}
}
LOGGER.info("Moving in new world folder");
try {
Files.move(tempWorldTopLevel, worldFolder, moveOptions);
} catch (Exception var8x) {
LOGGER.warn("Failed to move in new world folder: ", (Throwable)var8x);
throw new FailedCleanupFileFixException(var8x, tempWorldTopLevel.getFileName().toString(), fileSystemCapabilities);
}
succeeded.setTrue();
});
} catch (IOException var22) {
Path newWorldFolder = succeeded.isTrue() ? worldFolder : tempWorldTopLevel;
throw new FailedCleanupFileFixException(var22, newWorldFolder.getFileName().toString(), fileSystemCapabilities);
}
LOGGER.info("Done applying file structure changes for world \"{}\". Cleaning up outdated data...", worldAccess.getLevelId());
try {
if (Files.exists(oldWorldFolder)) {
deleteDirectory(oldWorldFolder);
}
} catch (Exception var16) {
LOGGER.warn("Failed to clean up old world folder", (Throwable)var16);
}
LOGGER.info("Upgrade done for world \"{}\"", worldAccess.getLevelId());
}
}
private static void writeMoves(List<FileMove> moves, Path fromDirectory, Path toDirectory, Path filePath) throws IOException {
Codec<FileFixerUpper.UpgradeInProgress> codec = FileFixerUpper.UpgradeInProgress.codec(fromDirectory, toDirectory);
JsonElement json = codec.encodeStart(JsonOps.INSTANCE, new FileFixerUpper.UpgradeInProgress(moves)).getOrThrow();
Files.writeString(filePath, GSON.toJson(json), StandardOpenOption.DSYNC, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
}
private static List<FileMove> readMoves(Path fromDirectory, Path toDirectory, Path filePath) throws IOException {
JsonObject json = GSON.fromJson(Files.readString(filePath), JsonObject.class);
Codec<FileFixerUpper.UpgradeInProgress> codec = FileFixerUpper.UpgradeInProgress.codec(fromDirectory, toDirectory);
return codec.decode(JsonOps.INSTANCE, json).getOrThrow().getFirst().moves;
}
public static FileSystemCapabilities detectFileSystemCapabilities(Path dir) throws IOException {
return new FileSystemCapabilities(supportsAtomicMove(dir), supportsHardLinks(dir));
}
private static boolean supportsAtomicMove(Path dir) throws IOException {
Path sourceFile = dir.resolve(UUID.randomUUID().toString());
Path targetFile = dir.resolve(UUID.randomUUID().toString());
boolean var4;
try {
Files.createFile(sourceFile);
try {
Files.move(sourceFile, targetFile, StandardCopyOption.ATOMIC_MOVE);
return true;
} catch (AtomicMoveNotSupportedException var8) {
var4 = false;
}
} finally {
Files.deleteIfExists(sourceFile);
Files.deleteIfExists(targetFile);
}
return var4;
}
private static boolean supportsHardLinks(Path dir) throws IOException {
Path sourceFile = dir.resolve(UUID.randomUUID().toString());
Path targetFile = dir.resolve(UUID.randomUUID().toString());
boolean var4;
try {
Files.createFile(sourceFile);
try {
Files.createLink(targetFile, sourceFile);
return true;
} catch (Exception var8) {
var4 = false;
}
} finally {
Files.deleteIfExists(sourceFile);
Files.deleteIfExists(targetFile);
}
return var4;
}
public static class Builder {
public final List<FileFix> fileFixes = new ArrayList<>();
private final int currentVersion;
private int latestFileFixerVersion;
private final List<Schema> knownSchemas = new ArrayList<>();
public Builder(int currentVersion) {
this.currentVersion = currentVersion;
}
public void addFixer(FileFix fileFix) {
if (!this.knownSchemas.contains(fileFix.getSchema())) {
throw new IllegalArgumentException("Tried to add file fixer with unknown schema. Add it through FileFixerUpper#addSchema instead");
} else {
int fileFixVersion = fileFix.getVersion();
if (fileFix.getVersion() > this.currentVersion) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Tried to add too recent file fix for version: %s. The data version of the game is: %s",
fileFixVersion,
this.currentVersion
)
);
} else {
if (!this.fileFixes.isEmpty()) {
FileFix last = this.fileFixes.getLast();
if (last.getVersion() > fileFixVersion) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Tried to add too recent file fix for version: %s. The most recent file fix version is %s",
fileFixVersion,
last.getVersion()
)
);
}
}
this.fileFixes.add(fileFix);
}
}
}
public Schema addSchema(DataFixerBuilder fixerUpper, int version, BiFunction<Integer, Schema, Schema> factory) {
this.latestFileFixerVersion = Math.max(version, this.latestFileFixerVersion);
Schema schema = fixerUpper.addSchema(version, factory);
this.knownSchemas.add(schema);
return schema;
}
public FileFixerUpper build(Result dataFixer) {
return new FileFixerUpper(dataFixer, this.fileFixes, this.latestFileFixerVersion);
}
}
public record UpgradeInProgress(List<FileMove> moves) {
public static Codec<FileFixerUpper.UpgradeInProgress> codec(Path fromDirectory, Path toDirectory) {
return RecordCodecBuilder.create(
i -> i.group(FileMove.moveCodec(fromDirectory, toDirectory).listOf().fieldOf("moves").forGetter(FileFixerUpper.UpgradeInProgress::moves))
.apply(i, FileFixerUpper.UpgradeInProgress::new)
);
}
}
}引用的其他类
-
- 引用位置:
方法调用 - 关联成员:
SharedConstants.getCurrentVersion()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
NbtAccounter.defaultQuota()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
NbtIo.readCompressed(), NbtIo.writeCompressed()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
NbtUtils.addDataVersion(), NbtUtils.getDataVersion()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
FileUtil.findAvailableName()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
AbortedFileFixException()
- 引用位置:
-
AtomicMoveNotSupportedFileFixException
- 引用位置:
构造调用 - 关联成员:
AtomicMoveNotSupportedFileFixException()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
FailedCleanupFileFixException()
- 引用位置:
-
- 引用位置:
参数/字段/返回值
- 引用位置:
-
- 引用位置:
构造调用/返回值 - 关联成员:
FileSystemCapabilities()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
CopyOnWriteFileSystem.create(), CopyOnWriteFileSystem.createDirectories(), CopyOnWriteFileSystem.hardLinkFiles(), CopyOnWriteFileSystem.moveFiles(), CopyOnWriteFileSystem.moveFilesWithRetry(), CopyOnWriteFileSystem.tryRevertMoves()
- 引用位置:
-
- 引用位置:
参数/方法调用/返回值 - 关联成员:
FileMove.moveCodec()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
PrimaryLevelData.writeLastPlayed(), PrimaryLevelData.writeVersionTag()
- 引用位置: