diff --git a/src/main/java/ru/bclib/BCLib.java b/src/main/java/ru/bclib/BCLib.java index f5f6eb3c..1e450f96 100644 --- a/src/main/java/ru/bclib/BCLib.java +++ b/src/main/java/ru/bclib/BCLib.java @@ -12,7 +12,6 @@ import ru.bclib.api.dataexchange.handler.autosync.HelloClient; import ru.bclib.api.dataexchange.handler.autosync.HelloServer; import ru.bclib.api.dataexchange.handler.autosync.RequestFiles; import ru.bclib.api.dataexchange.handler.autosync.SendFiles; -import ru.bclib.api.datafixer.DataFixerAPI; import ru.bclib.config.Configs; import ru.bclib.recipes.CraftingRecipes; import ru.bclib.registry.BaseBlockEntities; @@ -50,8 +49,7 @@ public class BCLib implements ModInitializer { Chunker.DESCRIPTOR )); - DataFixerAPI.registerPatch(() -> new BCLibPatch()); - + BCLibPatch.register(); Configs.save(); } diff --git a/src/main/java/ru/bclib/BCLibPatch.java b/src/main/java/ru/bclib/BCLibPatch.java index d05bf60a..d7db7d40 100644 --- a/src/main/java/ru/bclib/BCLibPatch.java +++ b/src/main/java/ru/bclib/BCLibPatch.java @@ -1,14 +1,23 @@ package ru.bclib; import net.minecraft.nbt.CompoundTag; +import ru.bclib.api.datafixer.DataFixerAPI; import ru.bclib.api.datafixer.Patch; import ru.bclib.api.datafixer.PatchFunction; -public final class BCLibPatch extends Patch { + + +public final class BCLibPatch { + public static void register(){ + DataFixerAPI.registerPatch(BiomeSourcePatch::new); + } +} + +final class BiomeSourcePatch extends Patch { private static final String NETHER_BIOME_SOURCE = "bclib:nether_biome_source"; private static final String END_BIOME_SOURCE = "bclib:end_biome_source"; - protected BCLibPatch() { + protected BiomeSourcePatch() { super(BCLib.MOD_ID, "0.4.0"); } diff --git a/src/main/java/ru/bclib/api/datafixer/ForcedLevelPatch.java b/src/main/java/ru/bclib/api/datafixer/ForcedLevelPatch.java new file mode 100644 index 00000000..c6ec75dc --- /dev/null +++ b/src/main/java/ru/bclib/api/datafixer/ForcedLevelPatch.java @@ -0,0 +1,47 @@ +package ru.bclib.api.datafixer; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * A Patch for level.dat that is always executed no matter what Patchlevel is set in a world. + */ +public abstract class ForcedLevelPatch extends Patch { + protected ForcedLevelPatch(@NotNull String modID, String version) { + super(modID, version, true); + } + + @Override + public final Map getIDReplacements() { + return new HashMap(); + } + + @Override + public final PatchFunction getWorldDataPatcher() { return null; } + + @Override + public final PatchBiFunction getBlockStatePatcher() { return null; } + + @Override + public final List getWorldDataIDPaths() { + return null; + } + + @Override + public PatchFunction getLevelDatPatcher() { return this::runLevelDatPatch; } + + /** + * Called with the contents of level.dat in {@Code root} + * @param root The contents of level.dat + * @param profile The active migration profile + * @return true, if the run did change the contents of root + */ + abstract protected Boolean runLevelDatPatch(CompoundTag root, MigrationProfile profile); +} + diff --git a/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java b/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java index 6ad9dd58..26065093 100644 --- a/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java +++ b/src/main/java/ru/bclib/api/datafixer/MigrationProfile.java @@ -57,7 +57,7 @@ public class MigrationProfile { List paths = patch.getWorldDataIDPaths(); if (paths!=null) worldDataIDPaths.put(modID, paths); - if (applyAll || currentPatchLevel(modID) < patch.level) { + if (applyAll || currentPatchLevel(modID) < patch.level || patch.alwaysApply) { replacements.putAll(patch.getIDReplacements()); if (patch.getLevelDatPatcher()!=null) levelPatches.add(patch.getLevelDatPatcher()); diff --git a/src/main/java/ru/bclib/api/datafixer/Patch.java b/src/main/java/ru/bclib/api/datafixer/Patch.java index dafa6dd3..bc64e3c5 100644 --- a/src/main/java/ru/bclib/api/datafixer/Patch.java +++ b/src/main/java/ru/bclib/api/datafixer/Patch.java @@ -31,6 +31,11 @@ public abstract class Patch { @NotNull public final String modID; + /** + * This Mod is tested for each level start + */ + public final boolean alwaysApply; + static List getALL() { return ALL; } @@ -82,6 +87,19 @@ public abstract class Patch { * {@link Patch#maxPatchVersion(String)} */ protected Patch(@NotNull String modID, String version) { + this(modID, version, false); + } + + /** + * Internal Constructor used to create patches that can allways run (no matter what patchlevel a level has) + * @param modID The ID of the Mod + * @param version The mod-version that introduces the patch. When {@Code runAllways} is set, this version will + * determine the patchlevel that is written to the level + * @param alwaysApply When true, this patch is always active, no matter the patchlevel of the world. + * This should be used sparingly and just for patches that apply to level.dat (as they only take + * effect when changes are detected). Use {@link ForcedLevelPatch} to instatiate. + */ + Patch(@NotNull String modID, String version, boolean alwaysApply) { //Patchlevels need to be unique and registered in ascending order if (modID == null || "".equals(modID)) { throw new RuntimeException("[INTERNAL ERROR] Patches need a valid modID!"); @@ -92,6 +110,7 @@ public abstract class Patch { } this.version = version; + this.alwaysApply = alwaysApply; this.level = ModUtil.convertModVersion(version); if (!ALL.stream() .filter(p -> p.modID @@ -185,7 +204,7 @@ public abstract class Patch { } /** - * Returns a list of paths,where your mod may IDs in your {@link ru.bclib.api.WorldDataAPI}-File. + * Returns a list of paths where your mod stores IDs in your {@link ru.bclib.api.WorldDataAPI}-File. *

* {@link DataFixerAPI} will use information from the latest patch that returns a non-null-result. This list is used * to automatically fix changed IDs from all active patches (see {@link Patch#getIDReplacements()}