diff --git a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java index 52a78055..f9eafbec 100644 --- a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java +++ b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java @@ -139,12 +139,12 @@ public class DataFixerAPI { /** * Initializes the DataStorage for this world. If the world is new, the patch registry is initialized to the * current versions of the plugins. - * @param levelPath Folder of the world + * @param levelBaseDir Folder of the world * @param newWorld {@code true} if this is a fresh world * */ - public static void initializeWorldData(File levelPath, boolean newWorld){ - WorldDataAPI.load(new File(levelPath, "data")); + public static void initializeWorldData(File levelBaseDir, boolean newWorld){ + WorldDataAPI.load(new File(levelBaseDir, "data")); if (newWorld){ getMigrationProfile().markApplied(); @@ -153,7 +153,7 @@ public class DataFixerAPI { } private static boolean fixData(File dir, String levelID, boolean showUI, Consumer onResume) { - MigrationProfile profile = loadProfileIfNeeded(); + MigrationProfile profile = loadProfileIfNeeded(dir); Consumer runFixes = (applyFixes) -> { if (applyFixes) { @@ -203,13 +203,14 @@ public class DataFixerAPI { return false; } - private static MigrationProfile loadProfileIfNeeded(){ + private static MigrationProfile loadProfileIfNeeded(File levelBaseDir){ if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_PATCH_CATEGORY, "applyPatches", true)) { LOGGER.info("World Patches are disabled"); return null; } MigrationProfile profile = getMigrationProfile(); + profile.runPrePatches(levelBaseDir); if (!profile.hasAnyFixes()) { LOGGER.info("Everything up to date"); @@ -254,7 +255,7 @@ public class DataFixerAPI { List players = getAllPlayers(dir); players.parallelStream().forEach((file) -> fixPlayer(profile, state, file)); - fixLevel(profile, state, new File(dir, "level.dat")); + fixLevel(profile, state, dir); try { profile.patchWorldData(); @@ -269,30 +270,29 @@ public class DataFixerAPI { } } - private static void fixLevel(MigrationProfile data, State state, File file) { + private static void fixLevel(MigrationProfile profile, State state, File levelBaseDir) { try { - LOGGER.info("Inspecting " + file); - CompoundTag level = NbtIo.readCompressed(file); - boolean[] changed = { false }; - + LOGGER.info("Inspecting level.dat in " + levelBaseDir); + + //load the level (could already contain patches applied by patchLevelDat) + CompoundTag level = profile.getLevelDat(levelBaseDir); + boolean[] changed = { profile.isLevelDatChanged() }; + + if (profile.getPrePatchException()!=null){ + throw profile.getPrePatchException(); + } + if (level.contains("Data")) { CompoundTag dataTag = (CompoundTag)level.get("Data"); if (dataTag.contains("Player")) { CompoundTag player = (CompoundTag)dataTag.get("Player"); - fixPlayerNbt(player, changed, data); + fixPlayerNbt(player, changed, profile); } } - - try { - changed[0] |= data.patchLevelDat(level); - } catch (PatchDidiFailException e){ - state.didFail = true; - BCLib.LOGGER.error(e.getMessage()); - } if (changed[0]) { - LOGGER.warning("Writing '{}'", file); - NbtIo.writeCompressed(level, file); + LOGGER.warning("Writing '{}'", profile.getLevelDatFile()); + NbtIo.writeCompressed(level, profile.getLevelDatFile()); } } catch (Exception e) { diff --git a/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java b/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java index e0466207..9b55ce8d 100644 --- a/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java +++ b/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java @@ -2,10 +2,14 @@ package ru.bclib.api.datafixer; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.Tag; import org.jetbrains.annotations.NotNull; +import ru.bclib.BCLib; import ru.bclib.api.WorldDataAPI; +import java.io.File; +import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -22,6 +26,11 @@ public class MigrationProfile { final Map> worldDataIDPaths; private final CompoundTag config; + private CompoundTag level; + private File levelBaseDir; + private boolean prePatchChangedLevelDat; + private boolean didRunPrePatch; + private Exception prePatchException; MigrationProfile(CompoundTag config) { this.config = config; @@ -64,6 +73,53 @@ public class MigrationProfile { this.worldDataPatchers = Collections.unmodifiableList(worldDataPatches); } + final public CompoundTag getLevelDat(File levelBaseDir){ + if (level == null || this.levelBaseDir==null || !this.levelBaseDir.equals(levelBaseDir)){ + runPrePatches(levelBaseDir); + } + return level; + } + + final public boolean isLevelDatChanged(){ + return prePatchChangedLevelDat; + } + + final public File getLevelDatFile(){ + return new File(levelBaseDir, "level.dat"); + } + + final public Exception getPrePatchException(){ + return prePatchException; + } + + + final public void runPrePatches(File levelBaseDir){ + if (didRunPrePatch){ + BCLib.LOGGER.warning("Already did run PrePatches for " + this.levelBaseDir + "."); + } + BCLib.LOGGER.info("Running Pre Patchers on " + levelBaseDir); + + this.levelBaseDir = levelBaseDir; + this.level = null; + this.prePatchException = null; + didRunPrePatch = true; + + this.prePatchChangedLevelDat = runPreLevelPatches(getLevelDatFile()); + } + + private boolean runPreLevelPatches(File levelDat){ + try { + level = NbtIo.readCompressed(levelDat); + + boolean changed = patchLevelDat(level); + return changed; + } + catch (IOException | PatchDidiFailException e) { + prePatchException = e; + return false; + } + } + final public void markApplied() { for (String modID : mods) { DataFixerAPI.LOGGER.info("Updating Patch-Level for '{}' from {} to {}", modID, currentPatchLevel(modID), Patch.maxPatchLevel(modID)); @@ -81,7 +137,14 @@ public class MigrationProfile { } public boolean hasAnyFixes() { - return idReplacements.size() > 0 || levelPatchers.size() > 0 || worldDataPatchers.size() > 0; + boolean hasLevelDatPatches; + if (didRunPrePatch != false) { + hasLevelDatPatches = prePatchChangedLevelDat; + } else { + hasLevelDatPatches = levelPatchers.size()>0; + } + + return idReplacements.size() > 0 || hasLevelDatPatches || worldDataPatchers.size() > 0; } public String replaceStringFromIDs(@NotNull String val) { diff --git a/src/main/java/ru/bclib/api/datafixer/Patch.java b/src/main/java/ru/bclib/api/datafixer/Patch.java index 24d4d83e..7f9bf077 100644 --- a/src/main/java/ru/bclib/api/datafixer/Patch.java +++ b/src/main/java/ru/bclib/api/datafixer/Patch.java @@ -3,6 +3,7 @@ package ru.bclib.api.datafixer; import net.minecraft.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -151,6 +152,7 @@ public abstract class Patch { * A {@link #Patch} with a given {@link #level} is only included if the patch-level of the * world is less * @param config The current patch-level configuration + * @param levelBaseDir The location of the level * @return a new {@link MigrationProfile} Object. */ static MigrationProfile createMigrationData(CompoundTag config) {