Merge pull request #27 from quiqueck/feature/data_fixer
Added Fixer for WorldDataAPI
This commit is contained in:
commit
990b024fdb
3 changed files with 175 additions and 31 deletions
|
@ -10,8 +10,9 @@ import net.minecraft.client.gui.screens.worldselection.EditWorldScreen;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.util.ProgressListener;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFile;
|
||||
|
@ -322,12 +323,42 @@ public class DataFixerAPI {
|
|||
|
||||
private static void fixPlayerNbt(CompoundTag player, boolean[] changed, MigrationProfile data) {
|
||||
//Checking Inventory
|
||||
ListTag inventory = player.getList("Inventory", 10);
|
||||
fixInventory(inventory, changed, data, true);
|
||||
ListTag inventory = player.getList("Inventory", Tag.TAG_COMPOUND);
|
||||
fixItemArrayWithID(inventory, changed, data, true);
|
||||
|
||||
//Checking EnderChest
|
||||
ListTag enderitems = player.getList("EnderItems", 10);
|
||||
fixInventory(enderitems, changed, data, true);
|
||||
ListTag enderitems = player.getList("EnderItems", Tag.TAG_COMPOUND);
|
||||
fixItemArrayWithID(enderitems, changed, data, true);
|
||||
|
||||
//Checking ReceipBook
|
||||
if (player.contains("recipeBook")) {
|
||||
CompoundTag recipeBook = player.getCompound("recipeBook");
|
||||
changed[0] |= fixStringIDList(recipeBook, "recipes", data);
|
||||
changed[0] |= fixStringIDList(recipeBook, "toBeDisplayed", data);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean fixStringIDList(CompoundTag root, String name, MigrationProfile data) {
|
||||
boolean _changed = false;
|
||||
if (root.contains(name)) {
|
||||
ListTag items = root.getList(name, Tag.TAG_STRING);
|
||||
ListTag newItems = new ListTag();
|
||||
|
||||
for (Tag tag : items) {
|
||||
final StringTag str = (StringTag)tag;
|
||||
final String replace = data.replaceStringFromIDs(str.getAsString());
|
||||
if (replace!=null) {
|
||||
_changed = true;
|
||||
newItems.add(StringTag.valueOf(replace));
|
||||
} else {
|
||||
newItems.add(tag);
|
||||
}
|
||||
}
|
||||
if (_changed) {
|
||||
root.put(name, newItems);
|
||||
}
|
||||
}
|
||||
return _changed;
|
||||
}
|
||||
|
||||
private static void fixRegion(MigrationProfile data, State state, File file) {
|
||||
|
@ -350,18 +381,18 @@ public class DataFixerAPI {
|
|||
|
||||
//Checking TileEntities
|
||||
ListTag tileEntities = root.getCompound("Level")
|
||||
.getList("TileEntities", 10);
|
||||
.getList("TileEntities", Tag.TAG_COMPOUND);
|
||||
fixItemArrayWithID(tileEntities, changed, data, true);
|
||||
|
||||
//Checking Entities
|
||||
ListTag entities = root.getList("Entities", 10);
|
||||
ListTag entities = root.getList("Entities", Tag.TAG_COMPOUND);
|
||||
fixItemArrayWithID(entities, changed, data, true);
|
||||
|
||||
//Checking Block Palette
|
||||
ListTag sections = root.getCompound("Level")
|
||||
.getList("Sections", 10);
|
||||
.getList("Sections", Tag.TAG_COMPOUND);
|
||||
sections.forEach((tag) -> {
|
||||
ListTag palette = ((CompoundTag) tag).getList("Palette", 10);
|
||||
ListTag palette = ((CompoundTag) tag).getList("Palette", Tag.TAG_COMPOUND);
|
||||
palette.forEach((blockTag) -> {
|
||||
CompoundTag blockTagCompound = ((CompoundTag) blockTag);
|
||||
changed[0] |= data.replaceStringFromIDs(blockTagCompound, "Name");
|
||||
|
@ -396,29 +427,14 @@ public class DataFixerAPI {
|
|||
return patchConfTag;
|
||||
}
|
||||
|
||||
private static void fixInventory(ListTag inventory, boolean[] changed, MigrationProfile data, boolean recursive) {
|
||||
inventory.forEach(item -> {
|
||||
changed[0] |= data.replaceStringFromIDs((CompoundTag)item, "id");
|
||||
|
||||
if (((CompoundTag) item).contains("tag")) {
|
||||
CompoundTag tag = (CompoundTag)((CompoundTag) item).get("tag");
|
||||
if (tag.contains("BlockEntityTag")){
|
||||
CompoundTag blockEntityTag = (CompoundTag)((CompoundTag) tag).get("BlockEntityTag");
|
||||
ListTag items = blockEntityTag.getList("Items", 10);
|
||||
fixItemArrayWithID(items, changed, data, recursive);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void fixItemArrayWithID(ListTag items, boolean[] changed, MigrationProfile data, boolean recursive) {
|
||||
static void fixItemArrayWithID(ListTag items, boolean[] changed, MigrationProfile data, boolean recursive) {
|
||||
items.forEach(inTag -> {
|
||||
fixID((CompoundTag) inTag, changed, data, recursive);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static void fixID(CompoundTag inTag, boolean[] changed, MigrationProfile data, boolean recursive) {
|
||||
static void fixID(CompoundTag inTag, boolean[] changed, MigrationProfile data, boolean recursive) {
|
||||
final CompoundTag tag = inTag;
|
||||
|
||||
changed[0] |= data.replaceStringFromIDs(tag, "id");
|
||||
|
@ -428,11 +444,20 @@ public class DataFixerAPI {
|
|||
}
|
||||
|
||||
if (recursive && tag.contains("Items")) {
|
||||
fixItemArrayWithID(tag.getList("Items", 10), changed, data, true);
|
||||
fixItemArrayWithID(tag.getList("Items", Tag.TAG_COMPOUND), changed, data, true);
|
||||
}
|
||||
if (recursive && tag.contains("Inventory")) {
|
||||
ListTag inventory = tag.getList("Inventory", 10);
|
||||
fixInventory(inventory, changed, data, recursive);
|
||||
ListTag inventory = tag.getList("Inventory", Tag.TAG_COMPOUND);
|
||||
fixItemArrayWithID(inventory, changed, data, true);
|
||||
}
|
||||
if (tag.contains("tag")) {
|
||||
CompoundTag entityTag = (CompoundTag)tag.get("tag");
|
||||
if (entityTag.contains("BlockEntityTag")){
|
||||
CompoundTag blockEntityTag = (CompoundTag)entityTag.get("BlockEntityTag");
|
||||
fixID(blockEntityTag, changed, data, recursive);
|
||||
/*ListTag items = blockEntityTag.getList("Items", Tag.TAG_COMPOUND);
|
||||
fixItemArrayWithID(items, changed, data, recursive);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package ru.bclib.api.datafixer;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.bclib.api.WorldDataAPI;
|
||||
|
||||
|
@ -17,6 +19,7 @@ public class MigrationProfile {
|
|||
final Map<String, String> idReplacements;
|
||||
final List<PatchFunction<CompoundTag, Boolean>> levelPatchers;
|
||||
final List<Patch> worldDataPatchers;
|
||||
final Map<String, List<String>> worldDataIDPaths;
|
||||
|
||||
private final CompoundTag config;
|
||||
|
||||
|
@ -31,11 +34,16 @@ public class MigrationProfile {
|
|||
HashMap<String, String> replacements = new HashMap<String, String>();
|
||||
List<PatchFunction<CompoundTag, Boolean>> levelPatches = new LinkedList<>();
|
||||
List<Patch> worldDataPatches = new LinkedList<>();
|
||||
HashMap<String, List<String>> worldDataIDPaths = new HashMap<>();
|
||||
for (String modID : mods) {
|
||||
|
||||
Patch.getALL()
|
||||
.stream()
|
||||
.filter(p -> p.modID.equals(modID))
|
||||
.forEach(patch -> {
|
||||
List<String> paths = patch.getWorldDataIDPaths();
|
||||
if (paths!=null) worldDataIDPaths.put(modID, paths);
|
||||
|
||||
if (currentPatchLevel(modID) < patch.level) {
|
||||
replacements.putAll(patch.getIDReplacements());
|
||||
if (patch.getLevelDatPatcher()!=null)
|
||||
|
@ -49,7 +57,8 @@ public class MigrationProfile {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.worldDataIDPaths = Collections.unmodifiableMap(worldDataIDPaths);
|
||||
this.idReplacements = Collections.unmodifiableMap(replacements);
|
||||
this.levelPatchers = Collections.unmodifiableList(levelPatches);
|
||||
this.worldDataPatchers = Collections.unmodifiableList(worldDataPatches);
|
||||
|
@ -74,10 +83,15 @@ public class MigrationProfile {
|
|||
public boolean hasAnyFixes() {
|
||||
return idReplacements.size() > 0 || levelPatchers.size() > 0 || worldDataPatchers.size() > 0;
|
||||
}
|
||||
|
||||
public String replaceStringFromIDs(@NotNull String val) {
|
||||
final String replace = idReplacements.get(val);
|
||||
return replace;
|
||||
}
|
||||
|
||||
public boolean replaceStringFromIDs(@NotNull CompoundTag tag, @NotNull String key) {
|
||||
if (!tag.contains(key)) return false;
|
||||
|
||||
|
||||
final String val = tag.getString(key);
|
||||
final String replace = idReplacements.get(val);
|
||||
|
||||
|
@ -89,6 +103,64 @@ public class MigrationProfile {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean replaceIDatPath(@NotNull ListTag list, @NotNull String[] parts, int level){
|
||||
boolean[] changed = {false};
|
||||
if (level == parts.length-1) {
|
||||
DataFixerAPI.fixItemArrayWithID(list, changed, this, true);
|
||||
} else {
|
||||
list.forEach(inTag -> changed[0] |= replaceIDatPath((CompoundTag)inTag, parts, level+1));
|
||||
}
|
||||
return changed[0];
|
||||
}
|
||||
|
||||
private boolean replaceIDatPath(@NotNull CompoundTag tag, @NotNull String[] parts, int level){
|
||||
boolean changed = false;
|
||||
for (int i=level; i<parts.length-1; i++) {
|
||||
final String part = parts[i];
|
||||
if (tag.contains(part)) {
|
||||
final byte type = tag.getTagType(part);
|
||||
if (type == Tag.TAG_LIST) {
|
||||
ListTag list = tag.getList(part, Tag.TAG_COMPOUND);
|
||||
return replaceIDatPath(list, parts, i);
|
||||
} else if (type == Tag.TAG_COMPOUND) {
|
||||
tag = tag.getCompound(part);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (tag!=null && parts.length>0) {
|
||||
final String key = parts[parts.length-1];
|
||||
final byte type = tag.getTagType(key);
|
||||
if (type == Tag.TAG_LIST) {
|
||||
final ListTag list = tag.getList(key, Tag.TAG_COMPOUND);
|
||||
final boolean[] _changed = {false};
|
||||
if (list.size()==0) {
|
||||
_changed[0] = DataFixerAPI.fixStringIDList(tag, key, this);
|
||||
} else {
|
||||
DataFixerAPI.fixItemArrayWithID(list, _changed, this, true);
|
||||
}
|
||||
return _changed[0];
|
||||
} else if (type == Tag.TAG_STRING) {
|
||||
return replaceStringFromIDs(tag, key);
|
||||
} else if (type == Tag.TAG_COMPOUND) {
|
||||
final CompoundTag cTag = tag.getCompound(key);
|
||||
boolean[] _changed = {false};
|
||||
DataFixerAPI.fixID(cTag, _changed, this, true);
|
||||
return _changed[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean replaceIDatPath(@NotNull CompoundTag root, @NotNull String path){
|
||||
String[] parts = path.split("\\.");
|
||||
return replaceIDatPath(root, parts, 0);
|
||||
}
|
||||
|
||||
public boolean patchLevelDat(@NotNull CompoundTag level) throws PatchDidiFailException {
|
||||
boolean changed = false;
|
||||
|
@ -106,5 +178,17 @@ public class MigrationProfile {
|
|||
WorldDataAPI.saveFile(patch.modID);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : worldDataIDPaths.entrySet()){
|
||||
CompoundTag root = WorldDataAPI.getRootTag(entry.getKey());
|
||||
boolean[] changed = {false};
|
||||
entry.getValue().forEach(path -> {
|
||||
changed[0] |= replaceIDatPath(root, path);
|
||||
});
|
||||
|
||||
if (changed[0]){
|
||||
WorldDataAPI.saveFile(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,5 +156,40 @@ public abstract class Patch {
|
|||
static MigrationProfile createMigrationData(CompoundTag config) {
|
||||
return new MigrationProfile(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of paths,where your mod may IDs in your {@link ru.bclib.api.WorldDataAPI}-File.
|
||||
* <p>
|
||||
* {@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()}
|
||||
* <p>
|
||||
* The end of the path can either be a {@link net.minecraft.nbt.StringTag}, a {@link net.minecraft.nbt.ListTag} or
|
||||
* a {@link CompoundTag}. If the Path contains a non-leaf {@link net.minecraft.nbt.ListTag}, all members of that
|
||||
* list will be processed. For example:
|
||||
* <pre>
|
||||
* - global +
|
||||
* | - key (String)
|
||||
* | - items (List) +
|
||||
* | - { id (String) }
|
||||
* | - { id (String) }
|
||||
* </pre>
|
||||
* The path <b>global.items.id</b> will fix all <i>id</i>-entries in the <i>items</i>-list, while the path
|
||||
* <b>global.key</b> will only fix the <i>key</i>-entry.
|
||||
* <p>
|
||||
* if the leaf-entry (= the last part of the path, which would be <i>items</i> in <b>global.items</b>) is a
|
||||
* {@link CompoundTag}, the system will fix any <i>id</i> entry. If the {@link CompoundTag} contains an <i>item</i>
|
||||
* or <i>tag.BlockEntityTag</i> entry, the system will recursivley continue with those. If an <i>items</i>
|
||||
* or <i>inventory</i>-{@link net.minecraft.nbt.ListTag} was found, the system will continue recursivley with
|
||||
* every item of that list.
|
||||
* <p>
|
||||
* if the leaf-entry is a {@link net.minecraft.nbt.ListTag}, it is handle the same as a child <i>items</i> entry
|
||||
* of a {@link CompoundTag}.
|
||||
*
|
||||
* @return {@code null} if nothing changes or a list of Paths in your {@link ru.bclib.api.WorldDataAPI}-File.
|
||||
* Paths are dot-seperated (see {@link ru.bclib.api.WorldDataAPI#getCompoundTag(String, String)}).
|
||||
*/
|
||||
public List<String> getWorldDataIDPaths() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue