Better Mappings builders

Allows for mappings between json arrays and objects without a billion different constructors, also now uses the proper size for 1.18 chunks
This commit is contained in:
Nassim Jahnke 2021-11-15 21:49:02 +01:00
parent 25d74632c2
commit 3051ddb6c0
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
7 changed files with 190 additions and 41 deletions

View File

@ -29,79 +29,78 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays;
public class IntArrayMappings implements Mappings {
protected final int[] oldToNew;
private final int[] oldToNew;
private final int mappedIds;
public IntArrayMappings(int[] oldToNew) {
private IntArrayMappings(int[] oldToNew, int mappedIds) {
this.oldToNew = oldToNew;
this.mappedIds = mappedIds;
}
/**
* Maps old identifiers to the new ones.
* If an old value cannot be found in the new mappings, the diffmapping will be checked for the given entry.
*
* @param size set size of the underlying short array
* @param oldMapping mappings to map from
* @param newMapping mappings to map to
* @param diffMapping extra mappings that will be used/scanned when an entry cannot be found
*/
public static Builder<IntArrayMappings> builder() {
return Mappings.builder(IntArrayMappings::new);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(int[] oldToNew) {
this(oldToNew, -1);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(int size, JsonObject oldMapping, JsonObject newMapping, @Nullable JsonObject diffMapping) {
oldToNew = new int[size];
Arrays.fill(oldToNew, -1);
this.mappedIds = newMapping.size();
MappingDataLoader.mapIdentifiers(oldToNew, oldMapping, newMapping, diffMapping);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(JsonObject oldMapping, JsonObject newMapping, @Nullable JsonObject diffMapping) {
this(oldMapping.entrySet().size(), oldMapping, newMapping, diffMapping);
}
/**
* Maps old identifiers to the new ones.
*
* @param size set size of the underlying short array
* @param oldMapping mappings to map from
* @param newMapping mappings to map to
*/
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(int size, JsonObject oldMapping, JsonObject newMapping) {
oldToNew = new int[size];
Arrays.fill(oldToNew, -1);
mappedIds = -1;
MappingDataLoader.mapIdentifiers(oldToNew, oldMapping, newMapping);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(JsonObject oldMapping, JsonObject newMapping) {
this(oldMapping.entrySet().size(), oldMapping, newMapping);
}
/**
* Maps old identifiers to the new ones.
*
* @param size set size of the underlying short array
* @param oldMapping mappings to map from
* @param newMapping mappings to map to
* @param diffMapping extra mappings that will be used/scanned when an entry cannot be found
* @param warnOnMissing should "No key for x" be printed if there is no matching identifier
*/
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(int size, JsonArray oldMapping, JsonArray newMapping, JsonObject diffMapping, boolean warnOnMissing) {
oldToNew = new int[size];
Arrays.fill(oldToNew, -1);
mappedIds = -1;
MappingDataLoader.mapIdentifiers(oldToNew, oldMapping, newMapping, diffMapping, warnOnMissing);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(int size, JsonArray oldMapping, JsonArray newMapping, boolean warnOnMissing) {
this(size, oldMapping, newMapping, null, warnOnMissing);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(JsonArray oldMapping, JsonArray newMapping, boolean warnOnMissing) {
this(oldMapping.size(), oldMapping, newMapping, warnOnMissing);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(int size, JsonArray oldMapping, JsonArray newMapping) {
this(size, oldMapping, newMapping, true);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(JsonArray oldMapping, JsonArray newMapping, JsonObject diffMapping) {
this(oldMapping.size(), oldMapping, newMapping, diffMapping, true);
}
@Deprecated/*(forRemoval = true)*/
public IntArrayMappings(JsonArray oldMapping, JsonArray newMapping) {
this(oldMapping.size(), oldMapping, newMapping, true);
}
@ -121,6 +120,11 @@ public class IntArrayMappings implements Mappings {
return oldToNew.length;
}
@Override
public int mappedSize() {
return mappedIds;
}
public int[] getOldToNew() {
return oldToNew;
}

View File

@ -85,7 +85,7 @@ public class MappingDataBase implements MappingData {
itemMappings = new Int2IntBiHashMap();
itemMappings.defaultReturnValue(-1);
MappingDataLoader.mapIdentifiers(itemMappings, oldMappings.getAsJsonObject("items"), newMappings.getAsJsonObject("items"),
diffmapping != null ? diffmapping.getAsJsonObject("items") : null);
diffmapping != null ? diffmapping.getAsJsonObject("items") : null, true);
}
if (diffmapping != null && diffmapping.has("tags")) {
@ -195,14 +195,16 @@ public class MappingDataBase implements MappingData {
if (!oldMappings.has(key) || !newMappings.has(key)) return null;
JsonObject diff = diffMappings != null ? diffMappings.getAsJsonObject(key) : null;
return new IntArrayMappings(oldMappings.getAsJsonArray(key), newMappings.getAsJsonArray(key), diff);
return IntArrayMappings.builder().unmapped(oldMappings.getAsJsonArray(key))
.mapped(newMappings.getAsJsonArray(key)).diffMappings(diff).build();
}
protected @Nullable Mappings loadFromObject(JsonObject oldMappings, JsonObject newMappings, @Nullable JsonObject diffMappings, String key) {
if (!oldMappings.has(key) || !newMappings.has(key)) return null;
JsonObject diff = diffMappings != null ? diffMappings.getAsJsonObject(key) : null;
return new IntArrayMappings(oldMappings.getAsJsonObject(key), newMappings.getAsJsonObject(key), diff);
return IntArrayMappings.builder().unmapped(oldMappings.getAsJsonObject(key))
.mapped(newMappings.getAsJsonObject(key)).diffMappings(diff).build();
}
protected @Nullable JsonObject loadDiffFile() {

View File

@ -135,31 +135,36 @@ public class MappingDataLoader {
}
}
public static void mapIdentifiers(Int2IntBiMap output, JsonObject oldIdentifiers, JsonObject newIdentifiers, @Nullable JsonObject diffIdentifiers) {
public static void mapIdentifiers(Int2IntBiMap output, JsonObject oldIdentifiers, JsonObject newIdentifiers, @Nullable JsonObject diffIdentifiers, boolean warnOnMissing) {
Object2IntMap<String> newIdentifierMap = MappingDataLoader.indexedObjectToMap(newIdentifiers);
for (Map.Entry<String, JsonElement> entry : oldIdentifiers.entrySet()) {
int value = mapIdentifierEntry(entry, newIdentifierMap, diffIdentifiers);
int value = mapIdentifierEntry(entry, newIdentifierMap, diffIdentifiers, warnOnMissing);
if (value != -1) {
output.put(Integer.parseInt(entry.getKey()), value);
}
}
}
@Deprecated/*(forRemoval = true)*/
public static void mapIdentifiers(int[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers) {
MappingDataLoader.mapIdentifiers(output, oldIdentifiers, newIdentifiers, null);
mapIdentifiers(output, oldIdentifiers, newIdentifiers, null);
}
public static void mapIdentifiers(int[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers, @Nullable JsonObject diffIdentifiers) {
public static void mapIdentifiers(int[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers, @Nullable JsonObject diffIdentifiers, boolean warnOnMissing) {
Object2IntMap<String> newIdentifierMap = MappingDataLoader.indexedObjectToMap(newIdentifiers);
for (Map.Entry<String, JsonElement> entry : oldIdentifiers.entrySet()) {
int value = mapIdentifierEntry(entry, newIdentifierMap, diffIdentifiers);
int value = mapIdentifierEntry(entry, newIdentifierMap, diffIdentifiers, warnOnMissing);
if (value != -1) {
output[Integer.parseInt(entry.getKey())] = value;
}
}
}
private static int mapIdentifierEntry(Map.Entry<String, JsonElement> entry, Object2IntMap newIdentifierMap, @Nullable JsonObject diffIdentifiers) {
public static void mapIdentifiers(int[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers, @Nullable JsonObject diffIdentifiers) {
mapIdentifiers(output, oldIdentifiers, newIdentifiers, diffIdentifiers, true);
}
private static int mapIdentifierEntry(Map.Entry<String, JsonElement> entry, Object2IntMap newIdentifierMap, @Nullable JsonObject diffIdentifiers, boolean warnOnMissing) {
int value = newIdentifierMap.getInt(entry.getValue().getAsString());
if (value == -1) {
// Search in diff mappings
@ -170,7 +175,7 @@ public class MappingDataLoader {
}
}
if (value == -1) {
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
if (warnOnMissing && !Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
Via.getPlatform().getLogger().warning("No key for " + entry.getValue() + " :( ");
}
return -1;
@ -179,6 +184,7 @@ public class MappingDataLoader {
return value;
}
@Deprecated/*(forRemoval = true)*/
public static void mapIdentifiers(int[] output, JsonArray oldIdentifiers, JsonArray newIdentifiers, boolean warnOnMissing) {
mapIdentifiers(output, oldIdentifiers, newIdentifiers, null, warnOnMissing);
}

View File

@ -22,6 +22,10 @@
*/
package com.viaversion.viaversion.api.data;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public interface Mappings {
/**
@ -41,5 +45,135 @@ public interface Mappings {
*/
void setNewId(int id, int newId);
/**
* Returns amount of unmapped entries, being the size of the mapping.
*
* @return amount of unmapped entries
*/
int size();
/**
* Returns the amount of new ids total, even if it does not have a direct mapping.
* Returns -1 if unknown.
*
* @return amount of new ids, or -1 if unknown
*/
int mappedSize();
static <T extends Mappings> Builder<T> builder(final MappingsSupplier<T> supplier) {
return new Builder(supplier);
}
@FunctionalInterface
interface MappingsSupplier<T extends Mappings> {
T supply(int[] mappings, int mappedIds);
}
final class Builder<T extends Mappings> {
private final MappingsSupplier<T> supplier;
private JsonElement unmapped;
private JsonElement mapped;
private JsonObject diffMappings;
private int mappedSize = -1;
private int size = -1;
private boolean warnOnMissing = true;
private Builder(final MappingsSupplier<T> supplier) {
this.supplier = supplier;
}
/**
* Sets a custom entry size different to the size of the unmapped collection.
*
* @param size custom entry size
* @return self
*/
public Builder<T> customEntrySize(final int size) {
this.size = size;
return this;
}
/**
* Sets a custom entry mapped ids count different to the size of the mapped collection.
*
* @param size custom mapped id count
* @return self
*/
public Builder<T> customMappedSize(final int size) {
this.mappedSize = size;
return this;
}
/**
* Sets whether warnings should be logged for missing mapped ids.
*
* @param warnOnMissing whether warnings should be logged for missing mapped ids
* @return self
*/
public Builder<T> warnOnMissing(final boolean warnOnMissing) {
this.warnOnMissing = warnOnMissing;
return this;
}
public Builder<T> unmapped(final JsonArray unmappedArray) {
this.unmapped = unmappedArray;
return this;
}
public Builder<T> unmapped(final JsonObject unmappedObject) {
this.unmapped = unmappedObject;
return this;
}
public Builder<T> mapped(final JsonArray mappedArray) {
this.mapped = mappedArray;
return this;
}
public Builder<T> mapped(final JsonObject mappedObject) {
this.mapped = mappedObject;
return this;
}
public Builder<T> diffMappings(final JsonObject diffMappings) {
this.diffMappings = diffMappings;
return this;
}
public T 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];
// Do conversion if one is an array and the other an object, otherwise directly map
if (unmapped.isJsonArray()) {
if (mapped.isJsonObject()) {
MappingDataLoader.mapIdentifiers(mappings, toJsonObject(unmapped.getAsJsonArray()), mapped.getAsJsonObject(), diffMappings, warnOnMissing);
} else {
MappingDataLoader.mapIdentifiers(mappings, unmapped.getAsJsonArray(), mapped.getAsJsonArray(), diffMappings, warnOnMissing);
}
} else if (mapped.isJsonArray()) {
MappingDataLoader.mapIdentifiers(mappings, unmapped.getAsJsonObject(), toJsonObject(mapped.getAsJsonArray()), diffMappings, warnOnMissing);
} else {
MappingDataLoader.mapIdentifiers(mappings, unmapped.getAsJsonObject(), mapped.getAsJsonObject(), diffMappings, warnOnMissing);
}
return supplier.supply(mappings, mappedSize);
}
private int size(final JsonElement element) {
return element.isJsonObject() ? element.getAsJsonObject().size() : element.getAsJsonArray().size();
}
private JsonObject toJsonObject(final JsonArray array) {
final JsonObject object = new JsonObject();
for (int i = 0; i < array.size(); i++) {
final JsonElement element = array.get(i);
object.add(Integer.toString(i), element);
}
return object;
}
}
}

View File

@ -60,7 +60,8 @@ public class MappingData extends MappingDataBase {
loadTags(fluidTags, newMappings.getAsJsonObject("fluid_tags"));
loadEnchantments(oldEnchantmentsIds, oldMappings.getAsJsonObject("enchantments"));
enchantmentMappings = new IntArrayMappings(72, oldMappings.getAsJsonObject("enchantments"), newMappings.getAsJsonObject("enchantments"));
enchantmentMappings = IntArrayMappings.builder().customEntrySize(72)
.unmapped(oldMappings.getAsJsonObject("enchantments")).mapped(newMappings.getAsJsonObject("enchantments")).build();
// Map minecraft:snow[layers=1] of 1.12 to minecraft:snow[layers=2] in 1.13
if (Via.getConfig().isSnowCollisionFix()) {
@ -126,7 +127,8 @@ public class MappingData extends MappingDataBase {
protected Mappings loadFromObject(JsonObject oldMappings, JsonObject newMappings, @Nullable JsonObject diffMappings, String key) {
if (key.equals("blocks")) {
// Need to use a custom size since there are larger gaps in ids
return new IntArrayMappings(4084, oldMappings.getAsJsonObject("blocks"), newMappings.getAsJsonObject("blockstates"));
return IntArrayMappings.builder().customEntrySize(4084)
.unmapped(oldMappings.getAsJsonObject("blocks")).mapped(newMappings.getAsJsonObject("blockstates")).build();
} else {
return super.loadFromObject(oldMappings, newMappings, diffMappings, key);
}

View File

@ -36,6 +36,7 @@ public class MappingData extends MappingDataBase {
}
// Ignore removed sounds
return new IntArrayMappings(oldMappings.getAsJsonArray(key), newMappings.getAsJsonArray(key), false);
return IntArrayMappings.builder().warnOnMissing(false)
.unmapped(oldMappings.getAsJsonArray(key)).mapped(newMappings.getAsJsonArray(key)).build();
}
}

View File

@ -156,7 +156,7 @@ public final class WorldPackets {
final Chunk chunk = new Chunk1_18(oldChunk.getX(), oldChunk.getZ(), oldChunk.getSections(), oldChunk.getHeightMap(), blockEntities);
wrapper.write(new Chunk1_18Type(tracker.currentWorldSectionHeight(),
MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().size()),
MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().mappedSize()),
MathUtil.ceilLog2(tracker.biomesSent())), chunk);
final ChunkLightStorage lightStorage = wrapper.user().get(ChunkLightStorage.class);