Paper config files

== AT ==
public org.spigotmc.SpigotWorldConfig getBoolean(Ljava/lang/String;Z)Z
public org.spigotmc.SpigotWorldConfig getDouble(Ljava/lang/String;)D
public org.spigotmc.SpigotWorldConfig getDouble(Ljava/lang/String;D)D
public org.spigotmc.SpigotWorldConfig getInt(Ljava/lang/String;)I
public org.spigotmc.SpigotWorldConfig getInt(Ljava/lang/String;I)I
public org.spigotmc.SpigotWorldConfig getList(Ljava/lang/String;Ljava/lang/Object;)Ljava/util/List;
public org.spigotmc.SpigotWorldConfig getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
public net.minecraft.server.dedicated.DedicatedServerProperties reload(Lnet/minecraft/core/RegistryAccess;Ljava/util/Properties;Ljoptsimple/OptionSet;)Lnet/minecraft/server/dedicated/DedicatedServerProperties;
public net.minecraft.world.level.NaturalSpawner SPAWNING_CATEGORIES
This commit is contained in:
Jake Potrebic
2022-06-08 22:20:16 -07:00
parent e954a5a260
commit 769119f918
81 changed files with 4997 additions and 103 deletions

View File

@@ -0,0 +1,26 @@
package io.papermc.paper.configuration.serializer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
import java.lang.reflect.Type;
import java.util.function.Predicate;
public class ComponentSerializer extends ScalarSerializer<Component> {
public ComponentSerializer() {
super(Component.class);
}
@Override
public Component deserialize(Type type, Object obj) throws SerializationException {
return MiniMessage.miniMessage().deserialize(obj.toString());
}
@Override
protected Object serialize(Component component, Predicate<Class<?>> typeSupported) {
return MiniMessage.miniMessage().serialize(component);
}
}

View File

@@ -0,0 +1,33 @@
package io.papermc.paper.configuration.serializer;
import io.papermc.paper.configuration.type.EngineMode;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
import java.lang.reflect.Type;
import java.util.function.Predicate;
public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
public EngineModeSerializer() {
super(EngineMode.class);
}
@Override
public EngineMode deserialize(Type type, Object obj) throws SerializationException {
if (obj instanceof Integer id) {
try {
return EngineMode.valueOf(id);
} catch (IllegalArgumentException e) {
throw new SerializationException(id + " is not a valid id for type " + type + " for this node");
}
}
throw new SerializationException(obj + " is not of a valid type " + type + " for this node");
}
@Override
protected Object serialize(EngineMode item, Predicate<Class<?>> typeSupported) {
return item.getId();
}
}

View File

@@ -0,0 +1,49 @@
package io.papermc.paper.configuration.serializer;
import com.mojang.logging.LogUtils;
import io.leangen.geantyref.TypeToken;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.util.EnumLookup;
import static io.leangen.geantyref.GenericTypeReflector.erase;
/**
* Enum serializer that lists options if fails and accepts `-` as `_`.
*/
public class EnumValueSerializer extends ScalarSerializer<Enum<?>> {
private static final Logger LOGGER = LogUtils.getClassLogger();
public EnumValueSerializer() {
super(new TypeToken<Enum<?>>() {});
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public @Nullable Enum<?> deserialize(final Type type, final Object obj) throws SerializationException {
final String enumConstant = obj.toString();
final Class<? extends Enum> typeClass = erase(type).asSubclass(Enum.class);
Enum<?> ret = EnumLookup.lookupEnum(typeClass, enumConstant);
if (ret == null) {
ret = EnumLookup.lookupEnum(typeClass, enumConstant.replace("-", "_"));
}
if (ret == null) {
boolean longer = typeClass.getEnumConstants().length > 10;
List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList();
LOGGER.error("Invalid enum constant provided, expected one of [{}{}], but got {}", String.join(", ", options), longer ? ", ..." : "", enumConstant);
}
return ret;
}
@Override
public Object serialize(final Enum<?> item, final Predicate<Class<?>> typeSupported) {
return item.name();
}
}

View File

@@ -0,0 +1,52 @@
package io.papermc.paper.configuration.serializer;
import com.destroystokyo.paper.util.SneakyThrow;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import net.minecraft.commands.arguments.NbtPathArgument;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath> {
public static final NbtPathSerializer SERIALIZER = new NbtPathSerializer();
private static final NbtPathArgument DUMMY_ARGUMENT = new NbtPathArgument();
private NbtPathSerializer() {
super(NbtPathArgument.NbtPath.class);
}
@Override
public NbtPathArgument.NbtPath deserialize(final Type type, final Object obj) throws SerializationException {
return fromString(obj.toString());
}
@Override
protected Object serialize(final NbtPathArgument.NbtPath item, final Predicate<Class<?>> typeSupported) {
return item.toString();
}
public static List<NbtPathArgument.NbtPath> fromString(final List<String> tags) {
List<NbtPathArgument.NbtPath> paths = new ArrayList<>();
try {
for (final String tag : tags) {
paths.add(fromString(tag));
}
} catch (SerializationException ex) {
SneakyThrow.sneaky(ex);
}
return List.copyOf(paths);
}
private static NbtPathArgument.NbtPath fromString(final String tag) throws SerializationException {
try {
return DUMMY_ARGUMENT.parse(new StringReader(tag));
} catch (CommandSyntaxException e) {
throw new SerializationException(NbtPathArgument.NbtPath.class, e);
}
}
}

View File

@@ -0,0 +1,85 @@
package io.papermc.paper.configuration.serializer;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import com.mojang.logging.LogUtils;
import io.leangen.geantyref.TypeToken;
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
import io.papermc.paper.util.ObfHelper;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import net.minecraft.network.protocol.Packet;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
@SuppressWarnings("Convert2Diamond")
public final class PacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> implements MapSerializer.WriteBack {
private static final Logger LOGGER = LogUtils.getClassLogger();
private static final TypeToken<Class<? extends Packet<?>>> TYPE = new TypeToken<Class<? extends Packet<?>>>() {};
private static final List<String> SUBPACKAGES = List.of("game", "handshake", "login", "status");
private static final BiMap<String, String> MOJANG_TO_OBF;
static {
final ImmutableBiMap.Builder<String, String> builder = ImmutableBiMap.builder();
final @Nullable Map<String, ObfHelper.ClassMapping> classMappingMap = ObfHelper.INSTANCE.mappingsByMojangName();
if (classMappingMap != null) {
classMappingMap.forEach((mojMap, classMapping) -> {
if (mojMap.startsWith("net.minecraft.network.protocol.")) {
builder.put(classMapping.mojangName(), classMapping.obfName());
}
});
}
MOJANG_TO_OBF = builder.build();
}
public PacketClassSerializer() {
super(TYPE);
}
@SuppressWarnings("unchecked")
@Override
public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException {
Class<?> packetClass = null;
for (final String subpackage : SUBPACKAGES) {
final String fullClassName = "net.minecraft.network.protocol." + subpackage + "." + obj;
try {
packetClass = Class.forName(fullClassName);
break;
} catch (final ClassNotFoundException ex) {
final String spigotClassName = MOJANG_TO_OBF.get(fullClassName);
if (spigotClassName != null) {
try {
packetClass = Class.forName(spigotClassName);
} catch (final ClassNotFoundException ignore) {}
}
}
}
if (packetClass == null || !Packet.class.isAssignableFrom(packetClass)) {
throw new SerializationException("Could not deserialize a packet from " + obj);
}
return (Class<? extends Packet<?>>) packetClass;
}
@Override
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {
final String name = packetClass.getName();
@Nullable String mojName = ObfHelper.INSTANCE.mappingsByMojangName() == null ? name : MOJANG_TO_OBF.inverse().get(name); // if the mappings are null, running on moj-mapped server
if (mojName == null && MOJANG_TO_OBF.containsKey(name)) {
mojName = name;
}
if (mojName != null) {
int pos = mojName.lastIndexOf('.');
if (pos != -1 && pos != mojName.length() - 1) {
return mojName.substring(pos + 1);
}
}
LOGGER.error("Could not serialize {} into a mojang-mapped packet class name", packetClass);
return null;
}
}

View File

@@ -0,0 +1,51 @@
package io.papermc.paper.configuration.serializer;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.MobCategory;
import org.jspecify.annotations.Nullable;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
public final class StringRepresentableSerializer extends ScalarSerializer<StringRepresentable> {
private static final Map<Type, Function<String, StringRepresentable>> TYPES = Collections.synchronizedMap(Map.ofEntries(
createEntry(MobCategory.class)
));
public StringRepresentableSerializer() {
super(StringRepresentable.class);
}
public static boolean isValidFor(final Type type) {
return TYPES.containsKey(type);
}
private static <E extends Enum<E> & StringRepresentable> Map.Entry<Type, Function<String, @Nullable StringRepresentable>> createEntry(Class<E> type) {
return Map.entry(type, s -> {
for (E value : type.getEnumConstants()) {
if (value.getSerializedName().equals(s)) {
return value;
}
}
return null;
});
}
@Override
public StringRepresentable deserialize(Type type, Object obj) throws SerializationException {
Function<String, StringRepresentable> function = TYPES.get(type);
if (function == null) {
throw new SerializationException(type + " isn't registered");
}
return function.apply(obj.toString());
}
@Override
protected Object serialize(StringRepresentable item, Predicate<Class<?>> typeSupported) {
return item.getSerializedName();
}
}

View File

@@ -0,0 +1,91 @@
package io.papermc.paper.configuration.serializer.collections;
import io.leangen.geantyref.GenericTypeReflector;
import io.leangen.geantyref.TypeFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
@SuppressWarnings("rawtypes")
public abstract class FastutilMapSerializer<M extends Map<?, ?>> implements TypeSerializer.Annotated<M> {
private final Function<? super Map, ? extends M> factory;
protected FastutilMapSerializer(final Function<? super Map, ? extends M> factory) {
this.factory = factory;
}
@Override
public M deserialize(final AnnotatedType annotatedType, final ConfigurationNode node) throws SerializationException {
final Map map = (Map) node.get(this.createAnnotatedMapType((AnnotatedParameterizedType) annotatedType));
return this.factory.apply(map == null ? Collections.emptyMap() : map);
}
@Override
public void serialize(final AnnotatedType annotatedType, final @Nullable M obj, final ConfigurationNode node) throws SerializationException {
if (obj == null || obj.isEmpty()) {
node.raw(null);
} else {
final AnnotatedType baseMapType = this.createAnnotatedMapType((AnnotatedParameterizedType) annotatedType);
node.set(baseMapType, obj);
}
}
private AnnotatedType createAnnotatedMapType(final AnnotatedParameterizedType type) {
final Type baseType = this.createBaseMapType((ParameterizedType) type.getType());
return GenericTypeReflector.annotate(baseType, type.getAnnotations());
}
protected abstract Type createBaseMapType(final ParameterizedType type);
public static final class SomethingToPrimitive<M extends Map<?, ?>> extends FastutilMapSerializer<M> {
private final Type primitiveType;
public SomethingToPrimitive(final Function<Map, ? extends M> factory, final Type primitiveType) {
super(factory);
this.primitiveType = primitiveType;
}
@Override
protected Type createBaseMapType(final ParameterizedType type) {
return TypeFactory.parameterizedClass(Map.class, type.getActualTypeArguments()[0], GenericTypeReflector.box(this.primitiveType));
}
}
public static final class PrimitiveToSomething<M extends Map<?, ?>> extends FastutilMapSerializer<M> {
private final Type primitiveType;
public PrimitiveToSomething(final Function<Map, ? extends M> factory, final Type primitiveType) {
super(factory);
this.primitiveType = primitiveType;
}
@Override
protected Type createBaseMapType(final ParameterizedType type) {
return TypeFactory.parameterizedClass(Map.class, GenericTypeReflector.box(this.primitiveType), type.getActualTypeArguments()[0]);
}
}
public static final class SomethingToSomething<M extends Map<?, ?>> extends FastutilMapSerializer<M> {
public SomethingToSomething(final Function<? super Map, ? extends M> factory) {
super(factory);
}
@Override
protected Type createBaseMapType(final ParameterizedType type) {
return TypeFactory.parameterizedClass(Map.class, type.getActualTypeArguments()[0], type.getActualTypeArguments()[1]);
}
}
}

View File

@@ -0,0 +1,182 @@
package io.papermc.paper.configuration.serializer.collections;
import com.mojang.logging.LogUtils;
import io.leangen.geantyref.TypeToken;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.spongepowered.configurate.BasicConfigurationNode;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.ConfigurationOptions;
import org.spongepowered.configurate.NodePath;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import org.spongepowered.configurate.serialize.TypeSerializerCollection;
import static java.util.Objects.requireNonNull;
/**
* Map serializer that does not throw errors on individual entry serialization failures.
*/
public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
public static final TypeToken<Map<?, ?>> TYPE = new TypeToken<Map<?, ?>>() {};
private static final Logger LOGGER = LogUtils.getClassLogger();
private final boolean clearInvalids;
private final TypeSerializer<Map<?, ?>> fallback;
public MapSerializer(boolean clearInvalids) {
this.clearInvalids = clearInvalids;
this.fallback = requireNonNull(TypeSerializerCollection.defaults().get(TYPE), "Could not find default Map<?, ?> serializer");
}
@Retention(RetentionPolicy.RUNTIME)
public @interface ThrowExceptions {}
@Override
public Map<?, ?> deserialize(AnnotatedType annotatedType, ConfigurationNode node) throws SerializationException {
if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
return this.fallback.deserialize(annotatedType, node);
}
final Map<Object, Object> map = new LinkedHashMap<>();
final Type type = annotatedType.getType();
if (node.isMap()) {
if (!(type instanceof ParameterizedType parameterizedType)) {
throw new SerializationException(type, "Raw types are not supported for collections");
}
if (parameterizedType.getActualTypeArguments().length != 2) {
throw new SerializationException(type, "Map expected two type arguments!");
}
final Type key = parameterizedType.getActualTypeArguments()[0];
final Type value = parameterizedType.getActualTypeArguments()[1];
final @Nullable TypeSerializer<?> keySerializer = node.options().serializers().get(key);
final @Nullable TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
if (keySerializer == null) {
throw new SerializationException(type, "No type serializer available for key type " + key);
}
if (valueSerializer == null) {
throw new SerializationException(type, "No type serializer available for value type " + value);
}
final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options());
final Set<Object> keysToClear = new HashSet<>();
for (Map.Entry<Object, ? extends ConfigurationNode> ent : node.childrenMap().entrySet()) {
final @Nullable Object deserializedKey = deserialize(key, keySerializer, "key", keyNode.set(ent.getKey()), node.path());
final @Nullable Object deserializedValue = deserialize(value, valueSerializer, "value", ent.getValue(), ent.getValue().path());
if (deserializedKey == null || deserializedValue == null) {
continue;
}
if (keySerializer instanceof WriteBack) {
if (serialize(key, keySerializer, deserializedKey, "key", keyNode, node.path()) && !ent.getKey().equals(requireNonNull(keyNode.raw(), "Key must not be null!"))) {
keysToClear.add(ent.getKey());
}
}
map.put(deserializedKey, deserializedValue);
}
if (keySerializer instanceof WriteBack) { // supports cleaning keys which deserialize to the same value
for (Object keyToClear : keysToClear) {
node.node(keyToClear).raw(null);
}
}
}
return map;
}
private @Nullable Object deserialize(Type type, TypeSerializer<?> serializer, String mapPart, ConfigurationNode node, NodePath path) {
try {
return serializer.deserialize(type, node);
} catch (SerializationException ex) {
ex.initPath(node::path);
LOGGER.error("Could not deserialize {} {} into {} at {}: {}", mapPart, node.raw(), type, path, ex.rawMessage());
}
return null;
}
@Override
public void serialize(AnnotatedType annotatedType, @Nullable Map<?, ?> obj, ConfigurationNode node) throws SerializationException {
if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
this.fallback.serialize(annotatedType, obj, node);
return;
}
final Type type = annotatedType.getType();
if (!(type instanceof ParameterizedType parameterizedType)) {
throw new SerializationException(type, "Raw types are not supported for collections");
}
if (parameterizedType.getActualTypeArguments().length != 2) {
throw new SerializationException(type, "Map expected two type arguments!");
}
final Type key = parameterizedType.getActualTypeArguments()[0];
final Type value = parameterizedType.getActualTypeArguments()[1];
final @Nullable TypeSerializer<?> keySerializer = node.options().serializers().get(key);
final @Nullable TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
if (keySerializer == null) {
throw new SerializationException(type, "No type serializer available for key type " + key);
}
if (valueSerializer == null) {
throw new SerializationException(type, "No type serializer available for value type " + value);
}
if (obj == null || obj.isEmpty()) {
node.set(Collections.emptyMap());
} else {
final Set<Object> unvisitedKeys;
if (node.empty()) {
node.raw(Collections.emptyMap());
unvisitedKeys = Collections.emptySet();
} else {
unvisitedKeys = new HashSet<>(node.childrenMap().keySet());
}
final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options());
for (Map.Entry<?, ?> ent : obj.entrySet()) {
if (!serialize(key, keySerializer, ent.getKey(), "key", keyNode, node.path())) {
continue;
}
final Object keyObj = requireNonNull(keyNode.raw(), "Key must not be null!");
final ConfigurationNode child = node.node(keyObj);
serialize(value, valueSerializer, ent.getValue(), "value", child, child.path());
unvisitedKeys.remove(keyObj);
}
if (this.clearInvalids) {
for (Object unusedChild : unvisitedKeys) {
node.removeChild(unusedChild);
}
}
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private boolean serialize(Type type, TypeSerializer serializer, Object object, String mapPart, ConfigurationNode node, NodePath path) {
try {
serializer.serialize(type, object, node);
return true;
} catch (SerializationException ex) {
ex.initPath(node::path);
LOGGER.error("Could not serialize {} {} from {} at {}: {}", mapPart, object, type, path, ex.rawMessage());
}
return false;
}
@Override
public @Nullable Map<?, ?> emptyValue(AnnotatedType specificType, ConfigurationOptions options) {
if (specificType.isAnnotationPresent(ThrowExceptions.class)) {
return this.fallback.emptyValue(specificType, options);
}
return new LinkedHashMap<>();
}
public interface WriteBack { // marker interface
}
}

View File

@@ -0,0 +1,88 @@
package io.papermc.paper.configuration.serializer.collections;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import io.leangen.geantyref.TypeFactory;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.spongepowered.configurate.BasicConfigurationNode;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.ConfigurationOptions;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
private static final int ROW_TYPE_ARGUMENT_INDEX = 0;
private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1;
private static final int VALUE_TYPE_ARGUMENT_INDEX = 2;
@Override
public Table<?, ?, ?> deserialize(final Type type, final ConfigurationNode node) throws SerializationException {
final Table<?, ?, ?> table = HashBasedTable.create();
if (!node.empty() && node.isMap()) {
this.deserialize0(table, (ParameterizedType) type, node);
}
return table;
}
@SuppressWarnings("unchecked")
private <R, C, V> void deserialize0(final Table<R, C, V> table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException {
final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
final TypeSerializer<R> rowKeySerializer = (TypeSerializer<R>) node.options().serializers().get(rowType);
if (rowKeySerializer == null) {
throw new SerializationException("Could not find serializer for table row type " + rowType);
}
final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType);
final TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(mapType);
if (columnValueSerializer == null) {
throw new SerializationException("Could not find serializer for table column-value map " + type);
}
final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options());
for (final Object key : node.childrenMap().keySet()) {
final R rowKey = rowKeySerializer.deserialize(rowType, rowKeyNode.set(key));
final Map<C, V> map = columnValueSerializer.deserialize(mapType, node.node(rowKeyNode.raw()));
map.forEach((column, value) -> table.put(rowKey, column, value));
}
}
@Override
public void serialize(final Type type, final @Nullable Table<?, ?, ?> table, final ConfigurationNode node) throws SerializationException {
if (table != null) {
this.serialize0(table, (ParameterizedType) type, node);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private <R, C, V> void serialize0(final Table<R, C, V> table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException {
final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
final TypeSerializer rowKeySerializer = node.options().serializers().get(rowType);
if (rowKeySerializer == null) {
throw new SerializationException("Could not find a serializer for table row type " + rowType);
}
final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options());
for (final R key : table.rowKeySet()) {
rowKeySerializer.serialize(rowType, key, rowKeyNode.set(key));
final Object keyObj = Objects.requireNonNull(rowKeyNode.raw());
node.node(keyObj).set(TypeFactory.parameterizedClass(Map.class, columnType, valueType), table.row(key));
}
}
@Override
public @Nullable Table<?, ?, ?> emptyValue(Type specificType, ConfigurationOptions options) {
return ImmutableTable.of();
}
}

View File

@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.paper.configuration.serializer.collections;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.paper.configuration.serializer;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,63 @@
package io.papermc.paper.configuration.serializer.registry;
import io.leangen.geantyref.TypeToken;
import java.lang.reflect.Type;
import java.util.function.Predicate;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.configurate.serialize.ScalarSerializer;
import org.spongepowered.configurate.serialize.SerializationException;
abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer<T> {
private final RegistryAccess registryAccess;
private final ResourceKey<? extends Registry<R>> registryKey;
private final boolean omitMinecraftNamespace;
protected RegistryEntrySerializer(TypeToken<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<R>> registryKey, boolean omitMinecraftNamespace) {
super(type);
this.registryAccess = registryAccess;
this.registryKey = registryKey;
this.omitMinecraftNamespace = omitMinecraftNamespace;
}
protected RegistryEntrySerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<R>> registryKey, boolean omitMinecraftNamespace) {
super(type);
this.registryAccess = registryAccess;
this.registryKey = registryKey;
this.omitMinecraftNamespace = omitMinecraftNamespace;
}
protected final Registry<R> registry() {
return this.registryAccess.lookupOrThrow(this.registryKey);
}
protected abstract T convertFromResourceKey(ResourceKey<R> key) throws SerializationException;
@Override
public final T deserialize(Type type, Object obj) throws SerializationException {
return this.convertFromResourceKey(this.deserializeKey(obj));
}
protected abstract ResourceKey<R> convertToResourceKey(T value);
@Override
protected final Object serialize(T item, Predicate<Class<?>> typeSupported) {
final ResourceKey<R> key = this.convertToResourceKey(item);
if (this.omitMinecraftNamespace && key.location().getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
return key.location().getPath();
} else {
return key.location().toString();
}
}
private ResourceKey<R> deserializeKey(final Object input) throws SerializationException {
final ResourceLocation key = ResourceLocation.tryParse(input.toString());
if (key == null) {
throw new SerializationException("Could not create a key from " + input);
}
return ResourceKey.create(this.registryKey, key);
}
}

View File

@@ -0,0 +1,34 @@
package io.papermc.paper.configuration.serializer.registry;
import com.google.common.base.Preconditions;
import io.leangen.geantyref.TypeFactory;
import io.leangen.geantyref.TypeToken;
import java.util.function.Function;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import org.spongepowered.configurate.serialize.SerializationException;
public final class RegistryHolderSerializer<T> extends RegistryEntrySerializer<Holder<T>, T> {
@SuppressWarnings("unchecked")
public RegistryHolderSerializer(TypeToken<T> typeToken, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
super((TypeToken<Holder<T>>) TypeToken.get(TypeFactory.parameterizedClass(Holder.class, typeToken.getType())), registryAccess, registryKey, omitMinecraftNamespace);
}
public RegistryHolderSerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
this(TypeToken.get(type), registryAccess, registryKey, omitMinecraftNamespace);
Preconditions.checkArgument(type.getTypeParameters().length == 0, "%s must have 0 type parameters", type);
}
@Override
protected Holder<T> convertFromResourceKey(ResourceKey<T> key) throws SerializationException {
return this.registry().get(key).orElseThrow(() -> new SerializationException("Missing holder in " + this.registry().key() + " with key " + key));
}
@Override
protected ResourceKey<T> convertToResourceKey(Holder<T> value) {
return value.unwrap().map(Function.identity(), r -> this.registry().getResourceKey(r).orElseThrow());
}
}

View File

@@ -0,0 +1,35 @@
package io.papermc.paper.configuration.serializer.registry;
import io.leangen.geantyref.TypeToken;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import org.spongepowered.configurate.serialize.SerializationException;
/**
* Use {@link RegistryHolderSerializer} for datapack-configurable things.
*/
public final class RegistryValueSerializer<T> extends RegistryEntrySerializer<T, T> {
public RegistryValueSerializer(TypeToken<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
super(type, registryAccess, registryKey, omitMinecraftNamespace);
}
public RegistryValueSerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
super(type, registryAccess, registryKey, omitMinecraftNamespace);
}
@Override
protected T convertFromResourceKey(ResourceKey<T> key) throws SerializationException {
final T value = this.registry().getValue(key);
if (value == null) {
throw new SerializationException("Missing value in " + this.registry() + " with key " + key.location());
}
return value;
}
@Override
protected ResourceKey<T> convertToResourceKey(T value) {
return this.registry().getResourceKey(value).orElseThrow();
}
}

View File

@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.paper.configuration.serializer.registry;
import org.jspecify.annotations.NullMarked;