159 lines
4.8 KiB
Java
159 lines
4.8 KiB
Java
package ru.bclib.api.datafixer;
|
|
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.ListTag;
|
|
import net.minecraft.nbt.NbtIo;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.chunk.storage.RegionFile;
|
|
import ru.bclib.config.Configs;
|
|
import ru.bclib.config.SessionConfig;
|
|
import ru.bclib.util.Logger;
|
|
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.File;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
public class DataFixerAPI {
|
|
static final Logger LOGGER = new Logger("DataFixerAPI");
|
|
|
|
public static void fixData(SessionConfig config) {
|
|
if (!Configs.MAIN_CONFIG.getBoolean(Configs.MAIN_PATCH_CATEGORY, "applyPatches", true)) {
|
|
LOGGER.info("World Patches are disabled");
|
|
return;
|
|
}
|
|
|
|
final File dir = config.levelFolder;
|
|
MigrationProfile data = Patch.createMigrationData(config);
|
|
if (!data.hasAnyFixes()) {
|
|
LOGGER.info("Everything up to date");
|
|
return;
|
|
}
|
|
|
|
List<File> regions = getAllRegions(dir, null);
|
|
regions.parallelStream()
|
|
.forEach((file) -> {
|
|
try {
|
|
LOGGER.info("Inspecting " + file);
|
|
boolean[] changed = new boolean[1];
|
|
RegionFile region = new RegionFile(file, file.getParentFile(), true);
|
|
for (int x = 0; x < 32; x++) {
|
|
for (int z = 0; z < 32; z++) {
|
|
ChunkPos pos = new ChunkPos(x, z);
|
|
changed[0] = false;
|
|
if (region.hasChunk(pos)) {
|
|
DataInputStream input = region.getChunkDataInputStream(pos);
|
|
CompoundTag root = NbtIo.read(input);
|
|
// 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();
|
|
|
|
ListTag tileEntities = root.getCompound("Level")
|
|
.getList("TileEntities", 10);
|
|
fixItemArrayWithID(tileEntities, changed, data, true);
|
|
|
|
ListTag sections = root.getCompound("Level")
|
|
.getList("Sections", 10);
|
|
sections.forEach((tag) -> {
|
|
ListTag palette = ((CompoundTag) tag).getList("Palette", 10);
|
|
palette.forEach((blockTag) -> {
|
|
CompoundTag blockTagCompound = ((CompoundTag) blockTag);
|
|
changed[0] = data.replaceStringFromIDs(blockTagCompound, "Name");
|
|
});
|
|
});
|
|
if (changed[0]) {
|
|
LOGGER.warning("Writing '{}': {}/{}", file, x, z);
|
|
DataOutputStream output = region.getChunkDataOutputStream(pos);
|
|
NbtIo.write(root, output);
|
|
output.close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
region.close();
|
|
}
|
|
catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
});
|
|
|
|
data.markApplied();
|
|
}
|
|
|
|
private static boolean fixItemArrayWithID(ListTag items, boolean[] changed, MigrationProfile data, boolean recursive) {
|
|
items.forEach(inTag -> {
|
|
final CompoundTag tag = (CompoundTag) inTag;
|
|
|
|
changed[0] |= data.replaceStringFromIDs(tag, "id");
|
|
|
|
if (recursive && tag.contains("Items")) {
|
|
changed[0] |= fixItemArrayWithID(tag.getList("Items", 10), changed, data, true);
|
|
}
|
|
});
|
|
|
|
return changed[0];
|
|
}
|
|
|
|
private static List<File> getAllRegions(File dir, List<File> list) {
|
|
if (list == null) {
|
|
list = new ArrayList<>();
|
|
}
|
|
for (File file : dir.listFiles()) {
|
|
if (file.isDirectory()) {
|
|
getAllRegions(file, list);
|
|
}
|
|
else if (file.isFile() && file.getName()
|
|
.endsWith(".mca")) {
|
|
list.add(file);
|
|
}
|
|
}
|
|
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*";
|
|
final Matcher matcher = Pattern.compile(semanticVersionPattern)
|
|
.matcher(version);
|
|
if (matcher.find()) {
|
|
if (matcher.groupCount() > 0) res = (Integer.parseInt(matcher.group(1)) & 0xFF) << 20;
|
|
if (matcher.groupCount() > 1) res |= (Integer.parseInt(matcher.group(2)) & 0xFF) << 12;
|
|
if (matcher.groupCount() > 2) res |= Integer.parseInt(matcher.group(3)) & 0xFFF;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
}
|