Read custom model data from nbt mapping files, merge dir and packed data

This commit is contained in:
Nassim Jahnke 2023-03-09 11:29:59 +01:00
parent 4a62bb2fbc
commit f7acb7ce91
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
3 changed files with 71 additions and 151 deletions

View File

@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectMap;
import com.viaversion.viaversion.libs.fastutil.ints.Int2ObjectOpenHashMap;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.NumberTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.StringTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.util.Key;
@ -60,11 +61,19 @@ public class BackwardsMappings extends MappingDataBase {
if (itemNames != null) {
Preconditions.checkNotNull(itemMappings);
backwardsItemMappings = new Int2ObjectOpenHashMap<>(itemNames.size());
final CompoundTag extraItemData = data.get("itemdata");
for (final Map.Entry<String, Tag> entry : itemNames.entrySet()) {
final StringTag name = (StringTag) entry.getValue();
final int id = Integer.parseInt(entry.getKey());
//TODO Custom model data definition
backwardsItemMappings.put(id, new MappedItem(getNewItemId(id), name.getValue()));
Integer customModelData = null;
if (extraItemData != null && extraItemData.contains(entry.getKey())) {
final CompoundTag entryTag = extraItemData.get(entry.getKey());
final NumberTag customModelDataTag = entryTag.get("custom_model_data");
customModelData = customModelDataTag != null ? customModelDataTag.asInt() : null;
}
backwardsItemMappings.put(id, new MappedItem(getNewItemId(id), name.getValue(), customModelData));
}
}
@ -72,7 +81,8 @@ public class BackwardsMappings extends MappingDataBase {
if (entityNames != null) {
this.entityNames = new HashMap<>(entityNames.size());
for (final Map.Entry<String, Tag> entry : entityNames.entrySet()) {
this.entityNames.put(entry.getKey(), ((StringTag) entry.getValue()).getValue());
final StringTag mappedTag = (StringTag) entry.getValue();
this.entityNames.put(entry.getKey(), mappedTag.getValue());
}
}
@ -80,7 +90,8 @@ public class BackwardsMappings extends MappingDataBase {
if (soundNames != null) {
backwardsSoundMappings = new HashMap<>(soundNames.size());
for (final Map.Entry<String, Tag> entry : soundNames.entrySet()) {
backwardsSoundMappings.put(entry.getKey(), ((StringTag) entry.getValue()).getValue());
final StringTag mappedTag = (StringTag) entry.getValue();
backwardsSoundMappings.put(entry.getKey(), mappedTag.getValue());
}
}
}
@ -157,6 +168,6 @@ public class BackwardsMappings extends MappingDataBase {
@Override
protected @Nullable CompoundTag readNBTFile(final String name) {
return VBMappingDataLoader.loadNBT(name);
return VBMappingDataLoader.loadNBTFromDir(name);
}
}

View File

@ -18,17 +18,12 @@
package com.viaversion.viabackwards.api.data;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.libs.fastutil.objects.Object2IntMap;
import com.viaversion.viaversion.libs.gson.JsonArray;
import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.libs.gson.JsonIOException;
import com.viaversion.viaversion.libs.gson.JsonObject;
import com.viaversion.viaversion.libs.gson.JsonPrimitive;
import com.viaversion.viaversion.libs.gson.JsonSyntaxException;
import com.viaversion.viaversion.libs.opennbt.NBTIO;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.libs.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.util.GsonUtil;
import java.io.File;
import java.io.FileReader;
@ -53,99 +48,75 @@ public final class VBMappingDataLoader {
}
}
public static JsonObject loadFromDataDir(String name) {
File file = new File(ViaBackwards.getPlatform().getDataFolder(), name);
/**
* Returns nbt data from the plugin folder or packed assets.
* If a file with the same name exists in the plugin folder, the data of the original packed tag will be merged with the file's tag.
*
* @param name name of the file
* @return nbt data from the plugin folder or packed assets
*/
public static @Nullable CompoundTag loadNBTFromDir(final String name) {
final CompoundTag packedData = loadNBT(name);
final File file = new File(ViaBackwards.getPlatform().getDataFolder(), name);
if (!file.exists()) {
return packedData;
}
try {
final CompoundTag fileData = NBTIO.readFile(file, false, false);
return mergeTags(packedData, fileData);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private static CompoundTag mergeTags(final CompoundTag original, final CompoundTag extra) {
for (final Map.Entry<String, Tag> entry : extra.entrySet()) {
if (entry.getValue() instanceof CompoundTag) {
// For compound tags, don't replace the entire tag
final CompoundTag originalEntry = original.get(entry.getKey());
if (originalEntry != null) {
mergeTags(originalEntry, (CompoundTag) entry.getValue());
continue;
}
}
original.put(entry.getKey(), entry.getValue());
}
return original;
}
public static JsonObject loadData(final String name) {
try (final InputStream stream = getResource(name)) {
if (stream == null) return null;
return GsonUtil.getGson().fromJson(new InputStreamReader(stream), JsonObject.class);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public static JsonObject loadFromDataDir(final String name) {
final File file = new File(ViaBackwards.getPlatform().getDataFolder(), name);
if (!file.exists()) {
return loadData(name);
}
// Load the file from the platform's directory if present
try (FileReader reader = new FileReader(file)) {
try (final FileReader reader = new FileReader(file)) {
return GsonUtil.getGson().fromJson(reader, JsonObject.class);
} catch (JsonSyntaxException e) {
} catch (final JsonSyntaxException e) {
ViaBackwards.getPlatform().getLogger().warning(name + " is badly formatted!");
e.printStackTrace();
ViaBackwards.getPlatform().getLogger().warning("Falling back to resource's file!");
return loadData(name);
} catch (IOException | JsonIOException e) {
} catch (final IOException | JsonIOException e) {
e.printStackTrace();
}
return null;
}
public static @Nullable InputStream getResource(String name) {
public static @Nullable InputStream getResource(final String name) {
return VBMappingDataLoader.class.getClassLoader().getResourceAsStream("assets/viabackwards/data/" + name);
}
public static JsonObject loadData(String name) {
try (InputStream stream = getResource(name)) {
if (stream == null) return null;
return GsonUtil.getGson().fromJson(new InputStreamReader(stream), JsonObject.class);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static void mapIdentifiers(int[] output, JsonObject unmappedIdentifiers, JsonObject mappedIdentifiers, JsonObject diffIdentifiers, boolean warnOnMissing) {
Object2IntMap<String> newIdentifierMap = MappingDataLoader.indexedObjectToMap(mappedIdentifiers);
for (Map.Entry<String, JsonElement> entry : unmappedIdentifiers.entrySet()) {
int mappedId = mapIdentifierEntry(entry.getValue().getAsString(), newIdentifierMap, diffIdentifiers, warnOnMissing);
if (mappedId != -1) {
output[Integer.parseInt(entry.getKey())] = mappedId;
}
}
}
public static void mapIdentifiers(int[] output, JsonArray unmappedIdentifiers, JsonArray mappedIdentifiers, JsonObject diffIdentifiers, boolean warnOnMissing) {
Object2IntMap<String> newIdentifierMap = MappingDataLoader.arrayToMap(mappedIdentifiers);
for (int id = 0; id < unmappedIdentifiers.size(); id++) {
JsonElement unmappedIdentifier = unmappedIdentifiers.get(id);
int mappedId = mapIdentifierEntry(unmappedIdentifier.getAsString(), newIdentifierMap, diffIdentifiers, warnOnMissing);
if (mappedId != -1) {
output[id] = mappedId;
}
}
}
private static int mapIdentifierEntry(String key, Object2IntMap<String> mappedIdentifiers, @Nullable JsonObject diffIdentifiers, boolean warnOnMissing) {
int mappedId = mappedIdentifiers.getInt(key);
if (mappedId == -1) {
if (diffIdentifiers != null) {
// Search in diff mappings
JsonPrimitive diffValueJson = diffIdentifiers.getAsJsonPrimitive(key);
String diffValue = diffValueJson != null ? diffValueJson.getAsString() : null;
if (diffValue != null && diffValue.isEmpty()) {
return -1;
}
int dataIndex;
if (diffValue == null && (dataIndex = key.indexOf('[')) != -1
&& (diffValueJson = diffIdentifiers.getAsJsonPrimitive(key.substring(0, dataIndex))) != null) {
// Check for wildcard mappings
diffValue = diffValueJson.getAsString();
if (diffValue != null && diffValue.isEmpty()) {
return -1;
}
// Keep original properties if value ends with [
if (diffValue.endsWith("[")) {
diffValue += key.substring(dataIndex + 1);
}
}
if (diffValue != null) {
mappedId = mappedIdentifiers.getInt(diffValue);
}
}
if (mappedId == -1) {
if (warnOnMissing && !Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
ViaBackwards.getPlatform().getLogger().warning("No key for " + key + " :( ");
}
return -1;
}
}
return mappedId;
}
}

View File

@ -1,62 +0,0 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2023 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viabackwards.api.data;
import com.viaversion.viaversion.api.data.IntArrayMappings;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.api.data.Mappings;
import java.util.Arrays;
public final class VBMappings extends IntArrayMappings {
private VBMappings(final int[] oldToNew, final int mappedIds) {
super(oldToNew, mappedIds);
}
public static Mappings.Builder<VBMappings> vbBuilder() {
return new Builder(VBMappings::new);
}
public static final class Builder extends Mappings.Builder<VBMappings> {
private Builder(final MappingsSupplier<VBMappings> supplier) {
super(supplier);
}
@Override
public VBMappings build() {
final int size = this.size != -1 ? this.size : size(unmapped);
final int mappedSize = this.mappedSize != -1 ? this.mappedSize : size(mapped);
final int[] mappings = new int[size];
Arrays.fill(mappings, -1);
// Do conversion if one is an array and the other an object, otherwise directly map
if (unmapped.isJsonArray()) {
if (mapped.isJsonObject()) {
VBMappingDataLoader.mapIdentifiers(mappings, toJsonObject(unmapped.getAsJsonArray()), mapped.getAsJsonObject(), diffMappings, warnOnMissing);
} else {
VBMappingDataLoader.mapIdentifiers(mappings, unmapped.getAsJsonArray(), mapped.getAsJsonArray(), diffMappings, warnOnMissing);
}
} else if (mapped.isJsonArray()) {
VBMappingDataLoader.mapIdentifiers(mappings, unmapped.getAsJsonObject(), toJsonObject(mapped.getAsJsonArray()), diffMappings, warnOnMissing);
} else {
VBMappingDataLoader.mapIdentifiers(mappings, unmapped.getAsJsonObject(), mapped.getAsJsonObject(), diffMappings, warnOnMissing);
}
return new VBMappings(mappings, mappedSize);
}
}
}