Use version String for DataFixer

This commit is contained in:
Frank Bauer 2021-07-19 22:38:27 +02:00
parent 179ada3296
commit 9728dc8dc3

View file

@ -6,7 +6,6 @@ import net.minecraft.nbt.NbtIo;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionFile;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import ru.bclib.BCLib;
import ru.bclib.config.Configs; import ru.bclib.config.Configs;
import ru.bclib.config.PathConfig; import ru.bclib.config.PathConfig;
import ru.bclib.config.SessionConfig; import ru.bclib.config.SessionConfig;
@ -19,9 +18,12 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class DataFixerAPI2 { public class DataFixerAPI2 {
@ -41,49 +43,52 @@ public class DataFixerAPI2 {
} }
List<File> regions = getAllRegions(dir, null); List<File> regions = getAllRegions(dir, null);
regions.parallelStream().forEach((file) -> { regions.parallelStream()
try { .forEach((file) -> {
LOGGER.info("Inspecting " + file); try {
boolean[] changed = new boolean[1]; LOGGER.info("Inspecting " + file);
RegionFile region = new RegionFile(file, file.getParentFile(), true); boolean[] changed = new boolean[1];
for (int x = 0; x < 32; x++) { RegionFile region = new RegionFile(file, file.getParentFile(), true);
for (int z = 0; z < 32; z++) { for (int x = 0; x < 32; x++) {
ChunkPos pos = new ChunkPos(x, z); for (int z = 0; z < 32; z++) {
changed[0] = false; ChunkPos pos = new ChunkPos(x, z);
if (region.hasChunk(pos)) { changed[0] = false;
DataInputStream input = region.getChunkDataInputStream(pos); if (region.hasChunk(pos)) {
CompoundTag root = NbtIo.read(input); DataInputStream input = region.getChunkDataInputStream(pos);
// if ((root.toString().contains("betternether") || root.toString().contains("bclib")) && root.toString().contains("chest")) { CompoundTag root = NbtIo.read(input);
// NbtIo.write(root, new File(file.toString() + "-" + x + "-" + z + ".nbt")); // if ((root.toString().contains("betternether") || root.toString().contains("bclib")) && root.toString().contains("chest")) {
// } // NbtIo.write(root, new File(file.toString() + "-" + x + "-" + z + ".nbt"));
input.close(); // }
input.close();
ListTag tileEntities = root.getCompound("Level").getList("TileEntities", 10); ListTag tileEntities = root.getCompound("Level")
fixItemArrayWithID(tileEntities, changed, data, true); .getList("TileEntities", 10);
fixItemArrayWithID(tileEntities, changed, data, true);
ListTag sections = root.getCompound("Level").getList("Sections", 10); ListTag sections = root.getCompound("Level")
sections.forEach((tag) -> { .getList("Sections", 10);
ListTag palette = ((CompoundTag) tag).getList("Palette", 10); sections.forEach((tag) -> {
palette.forEach((blockTag) -> { ListTag palette = ((CompoundTag) tag).getList("Palette", 10);
CompoundTag blockTagCompound = ((CompoundTag) blockTag); palette.forEach((blockTag) -> {
changed[0] = data.replaceStringFromIDs(blockTagCompound, "Name"); CompoundTag blockTagCompound = ((CompoundTag) blockTag);
}); changed[0] = data.replaceStringFromIDs(blockTagCompound, "Name");
}); });
if (changed[0]) { });
LOGGER.warning("Writing '{}': {}/{}", file, x, z); if (changed[0]) {
DataOutputStream output = region.getChunkDataOutputStream(pos); LOGGER.warning("Writing '{}': {}/{}", file, x, z);
NbtIo.write(root, output); DataOutputStream output = region.getChunkDataOutputStream(pos);
output.close(); NbtIo.write(root, output);
} output.close();
} }
} }
} }
region.close(); }
} region.close();
catch (Exception e) { }
e.printStackTrace(); catch (Exception e) {
} e.printStackTrace();
}); }
});
data.markApplied(); data.markApplied();
} }
@ -110,16 +115,59 @@ public class DataFixerAPI2 {
if (file.isDirectory()) { if (file.isDirectory()) {
getAllRegions(file, list); getAllRegions(file, list);
} }
else if (file.isFile() && file.getName().endsWith(".mca")) { else if (file.isFile() && file.getName()
.endsWith(".mca")) {
list.add(file); list.add(file);
} }
} }
return list; return list;
} }
/**
* Get mod version from string. String should be in format: %d.%d.%d
*
* @param version - {@link String} mod version.
* @return int mod version.
*/
public static int getModVersion(String version) {
if (version.isEmpty()) {
return 0;
}
try {
int res = 0;
final String semanticVersionPattern = "\\D*(\\d+)\\D*\\.\\D*(\\d+)\\D*\\.\\D*(\\d+)\\D*";
final Matcher matcher = Pattern.compile(semanticVersionPattern)
.matcher(version);
if (matcher.find()) {
if (matcher.groupCount() > 0) res = Integer.parseInt(matcher.group(0)) << 20;
if (matcher.groupCount() > 1) res |= Integer.parseInt(matcher.group(1)) << 12;
if (matcher.groupCount() > 2) res |= Integer.parseInt(matcher.group(2));
}
return res;
}
catch (Exception e) {
return 0;
}
}
/**
* Get mod version from integer. String will be in format %d.%d.%d
*
* @param version - mod version in integer form.
* @return {@link String} mod version.
*/
public static String getModVersion(int version) {
int a = (version >> 20) & 0xFF;
int b = (version >> 12) & 0xFF;
int c = version & 0xFFF;
return String.format(Locale.ROOT, "%d.%d.%d", a, b, c);
}
public abstract static class Patch { public abstract static class Patch {
private static List<Patch> ALL = new ArrayList<>(10); private static List<Patch> ALL = new ArrayList<>(10);
private final int level; private final int level;
private final String version;
@NotNull @NotNull
private final String modID; private final String modID;
@ -136,6 +184,22 @@ public class DataFixerAPI2 {
ALL.add(patch.get()); ALL.add(patch.get());
} }
/**
* Returns the highest Patch-Version that is available for the given mod. If no patches were
* registerd for the mod, this will return 0.0.0
*
* @param modID The ID of the mod you want to query
* @return The highest Patch-Version that was found
*/
public static String maxPatchVersion(@NotNull String modID) {
return ALL.stream()
.filter(p -> p.getModID()
.equals(modID))
.map(p -> p.version)
.reduce((p, c) -> c)
.orElse("0.0.0");
}
/** /**
* Returns the highest patch-level that is available for the given mod. If no patches were * Returns the highest patch-level that is available for the given mod. If no patches were
* registerd for the mod, this will return 0 * registerd for the mod, this will return 0
@ -144,7 +208,12 @@ public class DataFixerAPI2 {
* @return The highest Patch-Level that was found * @return The highest Patch-Level that was found
*/ */
public static int maxPatchLevel(@NotNull String modID) { public static int maxPatchLevel(@NotNull String modID) {
return ALL.stream().filter(p -> p.getModID().equals(modID)).mapToInt(p -> p.level).max().orElse(0); return ALL.stream()
.filter(p -> p.getModID()
.equals(modID))
.mapToInt(p -> p.level)
.max()
.orElse(0);
} }
/** /**
@ -153,38 +222,50 @@ public class DataFixerAPI2 {
* Performs some sanity checks on the values and might throw a #RuntimeException if any * Performs some sanity checks on the values and might throw a #RuntimeException if any
* inconsistencies are found. * inconsistencies are found.
* *
* @param modID The ID of the Mod you want to register a patch for. This should be your * @param modID The ID of the Mod you want to register a patch for. This should be your
* ModID only. The ModID can not be {@code null} or an empty String. * ModID only. The ModID can not be {@code null} or an empty String.
* @param level The level of the Patch. This needs to be a non-zero positive value. * @param version The mod-version that introduces the patch. This needs Semantic-Version String
* Developers are responsible for registering their patches in the correct * like x.x.x. Developers are responsible for registering their patches in the correct
* order (with increasing levels). You are not allowed to register a new * order (with increasing versions). You are not allowed to register a new
* Patch with a Patch-level lower or equal than * Patch with a version lower or equal than
* {@link Patch#maxPatchLevel(String)} * {@link Patch#maxPatchVersion(String)}
*/ */
protected Patch(@NotNull String modID, int level) { protected Patch(@NotNull String modID, String version) {
//Patchlevels need to be unique and registered in ascending order //Patchlevels need to be unique and registered in ascending order
if (modID == null || "".equals(modID)) { if (modID == null || "".equals(modID)) {
throw new RuntimeException("[INTERNAL ERROR] Patches need a valid modID!"); throw new RuntimeException("[INTERNAL ERROR] Patches need a valid modID!");
} }
if (!ALL.stream().filter(p -> p.getModID().equals(modID)).noneMatch(p -> p.getLevel() >= level) || level <= 0) {
if (version == null || "".equals(version)) {
throw new RuntimeException("Invalid Mod-Version");
}
this.version = version;
this.level = getModVersion(version);
if (!ALL.stream()
.filter(p -> p.getModID()
.equals(modID)
)
.noneMatch(p -> p.getLevel() >= this.level) || this.level <= 0) {
throw new RuntimeException("[INTERNAL ERROR] Patch-levels need to be created in ascending order beginning with 1."); throw new RuntimeException("[INTERNAL ERROR] Patch-levels need to be created in ascending order beginning with 1.");
} }
BCLib.LOGGER.info("Creating Patchlevel {} ({}, {})", level, ALL, ALL.stream().noneMatch(p -> p.getLevel() >= level));
this.level = level;
this.modID = modID; this.modID = modID;
} }
@Override @Override
public String toString() { public String toString() {
return "Patch{" + "level=" + getModID() + ":" + getLevel() + '}'; return "Patch{" + getModID() + ':' + getVersion() + ':' + getLevel() + '}';
} }
final public int getLevel() { final public int getLevel() {
return level; return level;
} }
final public String getVersion() {
return version;
}
/** /**
* The Mod-ID that registered this Patch * The Mod-ID that registered this Patch
* *
@ -229,19 +310,25 @@ public class DataFixerAPI2 {
private MigrationData(PathConfig config) { private MigrationData(PathConfig config) {
this.config = config; this.config = config;
this.mods = Collections.unmodifiableSet(Patch.getALL().stream().map(p -> p.modID).collect(Collectors.toSet())); this.mods = Collections.unmodifiableSet(Patch.getALL()
.stream()
.map(p -> p.modID)
.collect(Collectors.toSet()));
HashMap<String, String> replacements = new HashMap<String, String>(); HashMap<String, String> replacements = new HashMap<String, String>();
for (String modID : mods) { for (String modID : mods) {
Patch.getALL().stream().filter(p -> p.modID.equals(modID)).forEach(patch -> { Patch.getALL()
if (currentPatchLevel(modID) < patch.level) { .stream()
replacements.putAll(patch.getIDReplacements()); .filter(p -> p.modID.equals(modID))
LOGGER.info("Applying " + patch); .forEach(patch -> {
} if (currentPatchLevel(modID) < patch.level) {
else { replacements.putAll(patch.getIDReplacements());
LOGGER.info("Ignoring " + patch); LOGGER.info("Applying " + patch);
} }
}); else {
LOGGER.info("Ignoring " + patch);
}
});
} }
this.idReplacements = Collections.unmodifiableMap(replacements); this.idReplacements = Collections.unmodifiableMap(replacements);
@ -249,14 +336,24 @@ public class DataFixerAPI2 {
final public void markApplied() { final public void markApplied() {
for (String modID : mods) { for (String modID : mods) {
LOGGER.info("Updating Patch-Level for '{}' from {} to {} -> {}", modID, currentPatchLevel(modID), Patch.maxPatchLevel(modID), config.setInt(Configs.MAIN_PATCH_CATEGORY, modID, Patch.maxPatchLevel(modID))); LOGGER.info(
"Updating Patch-Level for '{}' from {} to {}",
modID,
currentPatchLevel(modID),
Patch.maxPatchLevel(modID)
);
config.setString(Configs.MAIN_PATCH_CATEGORY, modID, Patch.maxPatchVersion(modID));
} }
config.saveChanges(); config.saveChanges();
} }
public String currentPatchVersion(@NotNull String modID) {
return config.getString(Configs.MAIN_PATCH_CATEGORY, modID, "0.0.0");
}
public int currentPatchLevel(@NotNull String modID) { public int currentPatchLevel(@NotNull String modID) {
return config.getInt(Configs.MAIN_PATCH_CATEGORY, modID, 0); return getModVersion(currentPatchVersion(modID));
} }
public boolean hasAnyFixes() { public boolean hasAnyFixes() {