From 617e5a46a135278d8cf9f47debeac534dfa5188c Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 20 Jul 2025 14:05:42 -0700 Subject: [PATCH] Update to configurate 4.2.0 (#12869) --- paper-server/build.gradle.kts | 3 +- .../configuration/GlobalConfiguration.java | 5 +- .../configuration/PaperConfigurations.java | 27 ++-- .../configuration/WorldConfiguration.java | 7 +- .../configuration/mapping/Definition.java | 11 ++ .../mapping/DeserializedFieldInfo.java | 16 +++ .../configuration/mapping/FieldProcessor.java | 16 +++ .../mapping/InnerClassFieldDiscoverer.java | 81 +++++++++--- .../mapping/InnerClassInstanceFactory.java | 62 +++++---- .../mapping/InnerClassInstanceSupplier.java | 2 +- .../paper/configuration/mapping/MergeMap.java | 44 +++++++ .../serializer/ComponentSerializer.java | 13 +- .../serializer/EngineModeSerializer.java | 13 +- .../serializer/EnumValueSerializer.java | 14 +-- .../serializer/NbtPathSerializer.java | 30 ++--- .../serializer/PacketClassSerializer.java | 86 ------------- .../ResourceLocationSerializer.java | 7 +- .../ServerboundPacketClassSerializer.java | 118 ++++++++++++++++++ .../StringRepresentableSerializer.java | 23 ++-- .../TableSerializer.java | 47 ++++--- .../map}/FastutilMapSerializer.java | 3 +- .../map}/MapSerializer.java | 76 ++++++----- .../collection/map/ThrowExceptions.java | 10 ++ .../collection/map/WriteKeyBack.java | 10 ++ .../collection/map/package-info.java | 4 + .../serializer/collection/package-info.java | 4 + .../serializer/collections/package-info.java | 4 - .../registry/RegistryEntrySerializer.java | 21 +++- .../registry/RegistryHolderSerializer.java | 18 ++- .../registry/RegistryValueSerializer.java | 18 ++- .../global/versioned/V30_PacketIds.java | 67 ++++++++++ .../configuration/type/BooleanOrDefault.java | 18 +-- .../configuration/type/number/DoubleOr.java | 11 +- .../configuration/type/number/IntOr.java | 11 +- .../type/number/OptionalNumSerializer.java | 14 ++- .../packet-limiter-upgrade-data.json | 1 + 36 files changed, 623 insertions(+), 292 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/mapping/Definition.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/mapping/DeserializedFieldInfo.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/mapping/FieldProcessor.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java rename paper-server/src/main/java/io/papermc/paper/configuration/serializer/{collections => collection}/TableSerializer.java (52%) rename paper-server/src/main/java/io/papermc/paper/configuration/serializer/{collections => collection/map}/FastutilMapSerializer.java (97%) rename paper-server/src/main/java/io/papermc/paper/configuration/serializer/{collections => collection/map}/MapSerializer.java (60%) create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/ThrowExceptions.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/WriteKeyBack.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/package-info.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/package-info.java delete mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java create mode 100644 paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V30_PacketIds.java create mode 100644 paper-server/src/main/resources/config-data/packet-limiter-upgrade-data.json diff --git a/paper-server/build.gradle.kts b/paper-server/build.gradle.kts index 3f2c536993..f1474cf164 100644 --- a/paper-server/build.gradle.kts +++ b/paper-server/build.gradle.kts @@ -154,8 +154,7 @@ dependencies { implementation("io.netty:netty-codec-haproxy:4.1.118.Final") // Add support for proxy protocol implementation("org.apache.logging.log4j:log4j-iostreams:2.24.1") implementation("org.ow2.asm:asm-commons:9.8") - implementation("org.spongepowered:configurate-yaml:4.2.0-20250225.064233-199") - implementation("org.spongepowered:configurate-core:4.2.0-20250225.064233-204") // Pinned dependency of above pinned yaml snapshot. + implementation("org.spongepowered:configurate-yaml:4.2.0") // Deps that were previously in the API but have now been moved here for backwards compat, eventually to be removed runtimeOnly("commons-lang:commons-lang:2.6") diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java index c5a491acfe..3f5e76e4df 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java @@ -3,6 +3,7 @@ package io.papermc.paper.configuration; import com.mojang.logging.LogUtils; import io.papermc.paper.FeatureHooks; import io.papermc.paper.configuration.constraint.Constraints; +import io.papermc.paper.configuration.serializer.collection.map.WriteKeyBack; import io.papermc.paper.configuration.type.number.DoubleOr; import io.papermc.paper.configuration.type.number.IntOr; import io.papermc.paper.util.sanitizer.ItemObfuscationBinding; @@ -28,7 +29,7 @@ import java.util.Set; @SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"}) public class GlobalConfiguration extends ConfigurationPart { private static final Logger LOGGER = LogUtils.getLogger(); - static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): + static final int CURRENT_VERSION = 30; // (when you change the version, change the comment, so it conflicts on rebases): upgrade packet to use ids private static GlobalConfiguration instance; public static boolean isFirstStart = false; public static GlobalConfiguration get() { @@ -274,7 +275,7 @@ public class GlobalConfiguration extends ConfigurationPart { public class PacketLimiter extends ConfigurationPart { public Component kickMessage = Component.translatable("disconnect.exceeded_packet_rate", NamedTextColor.RED); public PacketLimit allPackets = new PacketLimit(7.0, 500.0, PacketLimit.ViolateAction.KICK); - public Map>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP)); + public Map<@WriteKeyBack Class>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP)); @ConfigSerializable public record PacketLimit(@Required double interval, @Required double maxPacketRate, ViolateAction action) { diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/paper-server/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java index 266932720a..a972eeddbd 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java @@ -5,21 +5,25 @@ import com.google.common.collect.Table; import com.mojang.logging.LogUtils; import io.leangen.geantyref.TypeToken; import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; +import io.papermc.paper.configuration.mapping.Definition; +import io.papermc.paper.configuration.mapping.FieldProcessor; import io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer; +import io.papermc.paper.configuration.mapping.MergeMap; import io.papermc.paper.configuration.serializer.ComponentSerializer; import io.papermc.paper.configuration.serializer.EnumValueSerializer; import io.papermc.paper.configuration.serializer.NbtPathSerializer; -import io.papermc.paper.configuration.serializer.PacketClassSerializer; +import io.papermc.paper.configuration.serializer.ServerboundPacketClassSerializer; import io.papermc.paper.configuration.serializer.ResourceLocationSerializer; import io.papermc.paper.configuration.serializer.StringRepresentableSerializer; -import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer; -import io.papermc.paper.configuration.serializer.collections.MapSerializer; -import io.papermc.paper.configuration.serializer.collections.TableSerializer; +import io.papermc.paper.configuration.serializer.collection.TableSerializer; +import io.papermc.paper.configuration.serializer.collection.map.FastutilMapSerializer; +import io.papermc.paper.configuration.serializer.collection.map.MapSerializer; import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer; import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer; import io.papermc.paper.configuration.transformation.Transformations; import io.papermc.paper.configuration.transformation.global.LegacyPaperConfig; import io.papermc.paper.configuration.transformation.global.versioned.V29_LogIPs; +import io.papermc.paper.configuration.transformation.global.versioned.V30_PacketIds; import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration; import io.papermc.paper.configuration.transformation.world.LegacyPaperWorldConfig; import io.papermc.paper.configuration.transformation.world.versioned.V29_ZeroWorldHeight; @@ -41,10 +45,12 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import java.io.File; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; @@ -196,7 +202,7 @@ public class PaperConfigurations extends Configurations builder - .register(new PacketClassSerializer()) + .register(new ServerboundPacketClassSerializer()) .register(new RegistryValueSerializer<>(new TypeToken>() {}, registryAccess, Registries.DATA_COMPONENT_TYPE, false)) ); } @@ -232,7 +238,7 @@ public class PaperConfigurations extends Configurations>> defaultFieldProcessors() { + return List.of( + MergeMap.DEFINITION + ); + } + private static ContextMap createWorldContextMap(ServerLevel level) { return createWorldContextMap(level.levelStorageAccess.levelDirectory.path(), level.serverLevelData.getLevelName(), level.dimension().location(), level.spigotConfig, level.registryAccess(), level.getGameRules()); } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java index 8e65586182..a457584fcd 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java @@ -8,7 +8,7 @@ import io.papermc.paper.configuration.legacy.MaxEntityCollisionsInitializer; import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; import io.papermc.paper.configuration.mapping.MergeMap; import io.papermc.paper.configuration.serializer.NbtPathSerializer; -import io.papermc.paper.configuration.serializer.collections.MapSerializer; +import io.papermc.paper.configuration.serializer.collection.map.ThrowExceptions; import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration; import io.papermc.paper.configuration.type.BooleanOrDefault; import io.papermc.paper.configuration.type.DespawnRange; @@ -193,15 +193,14 @@ public class WorldConfiguration extends ConfigurationPart { } } - @MapSerializer.ThrowExceptions - public Reference2ObjectMap, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> { + public @ThrowExceptions Reference2ObjectMap, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> { map.put(EntityType.SNOWBALL, IntOr.Disabled.DISABLED); map.put(EntityType.LLAMA_SPIT, IntOr.Disabled.DISABLED); }); @PostProcess public void precomputeDespawnDistances() throws SerializationException { - for (Map.Entry entry : this.despawnRanges.entrySet()) { + for (final Map.Entry entry : this.despawnRanges.entrySet()) { final MobCategory category = entry.getKey(); final DespawnRangePair range = entry.getValue(); range.hard().preComputed(category.getDespawnDistance(), category.getSerializedName()); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/Definition.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/Definition.java new file mode 100644 index 0000000000..2a22e35ecf --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/Definition.java @@ -0,0 +1,11 @@ +package io.papermc.paper.configuration.mapping; + +import io.leangen.geantyref.TypeToken; +import java.lang.annotation.Annotation; + +public record Definition(Class annotation, TypeToken type, F factory) { + + public Definition(final Class annotation, final Class type, final F factory) { + this(annotation, TypeToken.get(type), factory); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/DeserializedFieldInfo.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/DeserializedFieldInfo.java new file mode 100644 index 0000000000..9035a6389b --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/DeserializedFieldInfo.java @@ -0,0 +1,16 @@ +package io.papermc.paper.configuration.mapping; + +import java.lang.reflect.AnnotatedType; +import org.jspecify.annotations.Nullable; +import org.spongepowered.configurate.serialize.SerializationException; + +import static com.google.common.base.Preconditions.checkState; + +public record DeserializedFieldInfo(AnnotatedType fieldType, Object deserializedValue, @Nullable FieldProcessor processor) { + + @SuppressWarnings("unchecked") + public @Nullable V runProcessor(final @Nullable Object valueInField, final @Nullable Object deserializedValue) throws SerializationException { + checkState(this.processor != null, "processor is null"); + return this.processor.process(this.fieldType, (V) deserializedValue, (V) valueInField); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/FieldProcessor.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/FieldProcessor.java new file mode 100644 index 0000000000..0a32ae0ac6 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/FieldProcessor.java @@ -0,0 +1,16 @@ +package io.papermc.paper.configuration.mapping; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedType; +import org.jspecify.annotations.Nullable; +import org.spongepowered.configurate.serialize.SerializationException; + +public interface FieldProcessor { + + @Nullable V process(final AnnotatedType target, @Nullable V deserializedValue, @Nullable V valueInField) throws SerializationException; + + interface Factory { + + FieldProcessor make(A data, AnnotatedType annotatedType); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java index 05339a1760..a8a82aca70 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassFieldDiscoverer.java @@ -1,52 +1,103 @@ package io.papermc.paper.configuration.mapping; +import io.leangen.geantyref.GenericTypeReflector; import io.papermc.paper.configuration.ConfigurationPart; import io.papermc.paper.configuration.WorldConfiguration; +import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import java.util.SequencedMap; +import java.util.function.Supplier; import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.objectmapping.FieldDiscoverer; import org.spongepowered.configurate.serialize.SerializationException; import static io.leangen.geantyref.GenericTypeReflector.erase; +import static java.util.Objects.requireNonNullElseGet; -public final class InnerClassFieldDiscoverer implements FieldDiscoverer> { +public final class InnerClassFieldDiscoverer implements FieldDiscoverer>> { private final InnerClassInstanceSupplier instanceSupplier; private final FieldDiscoverer> delegate; + private final Map, List>>> fieldProcessors; - @SuppressWarnings("unchecked") - public InnerClassFieldDiscoverer(final Map, Object> initialOverrides) { - this.instanceSupplier = new InnerClassInstanceSupplier(initialOverrides); - this.delegate = (FieldDiscoverer>) FieldDiscoverer.object(this.instanceSupplier); + private InnerClassFieldDiscoverer(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer> delegate, final Map, List>>> fieldProcessors) { + this.instanceSupplier = instanceSupplier; + this.delegate = delegate; + this.fieldProcessors = fieldProcessors; } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public @Nullable InstanceFactory> discover(final AnnotatedType target, final FieldCollector, V> collector) throws SerializationException { + public @Nullable InstanceFactory>> discover(final AnnotatedType target, final FieldCollector>, V> collector) throws SerializationException { final Class clazz = erase(target.getType()); if (ConfigurationPart.class.isAssignableFrom(clazz)) { - final FieldDiscoverer.@Nullable InstanceFactory> instanceFactoryDelegate = this.delegate.discover(target, (name, type, annotations, deserializer, serializer) -> { - if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes - collector.accept(name, type, annotations, deserializer, serializer); + // we don't care about the returned instance factory, we just need to call it to collect fields + final Object dummyInstance = this.delegate.discover(target, (name, fieldType, container, deserializer, serializer) -> { + if (!erase(fieldType.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes + FieldProcessor processor = null; + processor: for (final Annotation annotation : container.getAnnotations()) { + final List>> definitions = this.fieldProcessors.get(annotation.annotationType()); + if (definitions != null) { + for (final Definition> def : definitions) { + if (GenericTypeReflector.isSuperType(def.type().getType(), GenericTypeReflector.box(fieldType.getType()))) { + processor = ((FieldProcessor.Factory)def.factory()).make(annotation, fieldType); + break processor; + } + } + } + } + final FieldProcessor finalProcessor = processor; + collector.accept( + name, + fieldType, + container, + (intermediate, newValue, implicitInitializer) -> { + // we only create this map to collect the field, it should only ever have 1 entry + final SequencedMap map = new LinkedHashMap<>(); + deserializer.accept(map, newValue, implicitInitializer); + final Object deserializedValue; + deserializedValue = requireNonNullElseGet(newValue, () -> new ImplicitProvider(implicitInitializer)); + intermediate.put(map.firstEntry().getKey(), new DeserializedFieldInfo<>(fieldType, deserializedValue, finalProcessor)); + }, + serializer + ); } }); - if (instanceFactoryDelegate instanceof MutableInstanceFactory> mutableInstanceFactoryDelegate) { - return new InnerClassInstanceFactory(this.instanceSupplier, mutableInstanceFactoryDelegate, target); + if (dummyInstance == null) { + return null; } + return new InnerClassInstanceFactory(this.instanceSupplier, target); } return null; } - public static FieldDiscoverer worldConfig(WorldConfiguration worldConfiguration) { + record ImplicitProvider(Supplier provider) { + } + + @SuppressWarnings("unchecked") + private static InnerClassFieldDiscoverer create(final Map, Object> overrides, final List>> fieldProcessors) { + final Map, List>>> processors = new LinkedHashMap<>(); + for (final Definition> definition : fieldProcessors) { + processors.computeIfAbsent(definition.annotation(), k -> new ArrayList<>()).add(definition); + } + final InnerClassInstanceSupplier instanceSupplier = new InnerClassInstanceSupplier(overrides); + return new InnerClassFieldDiscoverer(instanceSupplier, (FieldDiscoverer>) FieldDiscoverer.object(instanceSupplier), processors); + } + + public static FieldDiscoverer worldConfig(final WorldConfiguration worldConfiguration, final List>> fieldProcessors) { final Map, Object> overrides = Map.of( WorldConfiguration.class, worldConfiguration ); - return new InnerClassFieldDiscoverer(overrides); + return create(overrides, fieldProcessors); } - public static FieldDiscoverer globalConfig() { - return new InnerClassFieldDiscoverer(Collections.emptyMap()); + public static FieldDiscoverer globalConfig(final List>> fieldProcessors) { + return create(Collections.emptyMap(), fieldProcessors); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java index 25e3152c33..5c3b6937b4 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java @@ -2,56 +2,68 @@ package io.papermc.paper.configuration.mapping; import java.lang.reflect.AnnotatedType; import java.lang.reflect.Field; -import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; +import java.util.function.Supplier; import org.spongepowered.configurate.objectmapping.FieldDiscoverer; import org.spongepowered.configurate.serialize.SerializationException; import static io.leangen.geantyref.GenericTypeReflector.erase; -final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory> { +final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory>> { private final InnerClassInstanceSupplier instanceSupplier; - private final FieldDiscoverer.MutableInstanceFactory> fallback; private final AnnotatedType targetType; - InnerClassInstanceFactory(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer.MutableInstanceFactory> fallback, final AnnotatedType targetType) { + InnerClassInstanceFactory( + final InnerClassInstanceSupplier instanceSupplier, + final AnnotatedType targetType + ) { this.instanceSupplier = instanceSupplier; - this.fallback = fallback; this.targetType = targetType; } @Override - public Map begin() { - return this.fallback.begin(); + public Map> begin() { + return new LinkedHashMap<>(); } - @SuppressWarnings("unchecked") @Override - public void complete(final Object instance, final Map intermediate) throws SerializationException { - final Iterator> iter = intermediate.entrySet().iterator(); - try { - while (iter.hasNext()) { // manually merge any mergeable maps - Map.Entry entry = iter.next(); - if (entry.getKey().isAnnotationPresent(MergeMap.class) && Map.class.isAssignableFrom(entry.getKey().getType()) && intermediate.get(entry.getKey()) instanceof Map map) { - iter.remove(); - Map existingMap = (Map) entry.getKey().get(instance); - if (existingMap != null) { - existingMap.putAll(map); - } else { - entry.getKey().set(instance, entry.getValue()); + public void complete(final Object instance, final Map> intermediate) throws SerializationException { + // modeled off of native ObjectFieldDiscoverer + for (final Map.Entry> entry : intermediate.entrySet()) { + final boolean hasProcessor = entry.getValue().processor() != null; + try { + final Object valueInField = entry.getKey().get(instance); + if (entry.getValue().deserializedValue() instanceof InnerClassFieldDiscoverer.ImplicitProvider(final Supplier provider)) { + Object newFieldValue = provider.get(); + if (hasProcessor) { + newFieldValue = entry.getValue().runProcessor(valueInField, newFieldValue); } + if (newFieldValue != null) { + if (valueInField == null) { + entry.getKey().set(instance, newFieldValue); + } + } + } else { + Object newFieldValue = entry.getValue().deserializedValue(); + if (hasProcessor) { + newFieldValue = entry.getValue().runProcessor(valueInField, newFieldValue); + } + entry.getKey().set(instance, newFieldValue); } + } catch (final IllegalAccessException e) { + throw new SerializationException(this.targetType.getType(), e); + } catch (final SerializationException ex) { + ex.initType(entry.getValue().fieldType()); + } - } catch (final IllegalAccessException e) { - throw new SerializationException(this.targetType.getType(), e); } - this.fallback.complete(instance, intermediate); } @Override - public Object complete(final Map intermediate) throws SerializationException { + public Object complete(final Map> intermediate) throws SerializationException { final Object targetInstance = Objects.requireNonNull(this.instanceSupplier.instanceMap().get(erase(this.targetType.getType())), () -> this.targetType.getType() + " must already have an instance created"); this.complete(targetInstance, intermediate); return targetInstance; @@ -59,6 +71,6 @@ final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstance @Override public boolean canCreateInstances() { - return this.fallback.canCreateInstances(); + return true; } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java index 3778c47f56..e2ad18719e 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java @@ -57,7 +57,7 @@ final class InnerClassInstanceSupplier implements CheckedFunction instance; - } catch (ReflectiveOperationException e) { + } catch (final ReflectiveOperationException e) { throw new SerializationException(ConfigurationPart.class, target + " must be a valid ConfigurationPart", e); } } else { diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/MergeMap.java b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/MergeMap.java index 471b161ac5..a8ffaa3b0d 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/mapping/MergeMap.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/mapping/MergeMap.java @@ -1,11 +1,20 @@ package io.papermc.paper.configuration.mapping; +import com.google.common.collect.Sets; +import com.mojang.logging.LogUtils; import io.papermc.paper.configuration.ConfigurationPart; +import io.papermc.paper.configuration.serializer.collection.map.MapSerializer; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedType; +import java.util.Map; +import java.util.Set; +import org.slf4j.Logger; + +import static com.google.common.base.Preconditions.checkState; /** * For use in maps inside {@link ConfigurationPart}s that have default keys that shouldn't be removed by users @@ -17,4 +26,39 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MergeMap { + + Logger LOGGER = LogUtils.getClassLogger(); + Definition, Factory> DEFINITION = new Definition<>(MergeMap.class, MapSerializer.TYPE, new Factory()); + + /** + * If marked as restricted, the field won't allow new keys beyond what + * is already in the field when deserializing. + * + * @return True if restricted + */ + boolean restricted() default true; + + final class Factory implements FieldProcessor.Factory> { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public FieldProcessor> make(final MergeMap data, final AnnotatedType annotatedType) { + return (target, deserializedValue, valueInField) -> { + if (valueInField != null && deserializedValue != null) { + if (data.restricted()) { + final Set invalidKeys = Sets.difference(deserializedValue.keySet(), valueInField.keySet()).immutableCopy(); + for (final Object invalidKey : invalidKeys) { + LOGGER.error("The key {} is not allowed to be added to the field {}", invalidKey, target); + } + ((Map) deserializedValue).keySet().removeAll(invalidKeys); + } + ((Map) valueInField).putAll(deserializedValue); + return valueInField; + } else { + checkState(!data.restricted() || valueInField != null, "If marked as restricted, field must have a value"); + return deserializedValue; + } + }; + } + } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java index 9c339ef178..26e0a89e14 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java @@ -1,26 +1,25 @@ package io.papermc.paper.configuration.serializer; +import java.lang.reflect.AnnotatedType; +import java.util.function.Predicate; 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 { +public class ComponentSerializer extends ScalarSerializer.Annotated { public ComponentSerializer() { super(Component.class); } @Override - public Component deserialize(Type type, Object obj) throws SerializationException { + public Component deserialize(final AnnotatedType type, final Object obj) throws SerializationException { return MiniMessage.miniMessage().deserialize(obj.toString()); } @Override - protected Object serialize(Component component, Predicate> typeSupported) { - return MiniMessage.miniMessage().serialize(component); + protected Object serialize(final AnnotatedType type, final Component item, final Predicate> typeSupported) { + return MiniMessage.miniMessage().serialize(item); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EngineModeSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EngineModeSerializer.java index 27c0679d37..7f47516700 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EngineModeSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EngineModeSerializer.java @@ -1,11 +1,10 @@ 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; +import org.spongepowered.configurate.serialize.ScalarSerializer; +import org.spongepowered.configurate.serialize.SerializationException; public final class EngineModeSerializer extends ScalarSerializer { @@ -14,11 +13,11 @@ public final class EngineModeSerializer extends ScalarSerializer { } @Override - public EngineMode deserialize(Type type, Object obj) throws SerializationException { - if (obj instanceof Integer id) { + public EngineMode deserialize(final Type type, final Object obj) throws SerializationException { + if (obj instanceof final Integer id) { try { return EngineMode.valueOf(id); - } catch (IllegalArgumentException e) { + } catch (final IllegalArgumentException e) { throw new SerializationException(id + " is not a valid id for type " + type + " for this node"); } } @@ -27,7 +26,7 @@ public final class EngineModeSerializer extends ScalarSerializer { } @Override - protected Object serialize(EngineMode item, Predicate> typeSupported) { + protected Object serialize(final EngineMode item, final Predicate> typeSupported) { return item.getId(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EnumValueSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EnumValueSerializer.java index d24d1480e3..d56a50ee72 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EnumValueSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/EnumValueSerializer.java @@ -2,7 +2,7 @@ package io.papermc.paper.configuration.serializer; import com.mojang.logging.LogUtils; import io.leangen.geantyref.TypeToken; -import java.lang.reflect.Type; +import java.lang.reflect.AnnotatedType; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -17,7 +17,7 @@ import static io.leangen.geantyref.GenericTypeReflector.erase; /** * Enum serializer that lists options if fails and accepts `-` as `_`. */ -public class EnumValueSerializer extends ScalarSerializer> { +public class EnumValueSerializer extends ScalarSerializer.Annotated> { private static final Logger LOGGER = LogUtils.getClassLogger(); @@ -27,23 +27,23 @@ public class EnumValueSerializer extends ScalarSerializer> { @SuppressWarnings({"rawtypes", "unchecked"}) @Override - public @Nullable Enum deserialize(final Type type, final Object obj) throws SerializationException { + public @Nullable Enum deserialize(final AnnotatedType annotatedType, final Object obj) throws SerializationException { final String enumConstant = obj.toString(); - final Class typeClass = erase(type).asSubclass(Enum.class); + final Class typeClass = erase(annotatedType.getType()).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 options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList(); + final boolean longer = typeClass.getEnumConstants().length > 10; + final List 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> typeSupported) { + public Object serialize(final AnnotatedType type, final Enum item, final Predicate> typeSupported) { return item.name(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java index b44b2dc28f..2d5458c695 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java @@ -3,7 +3,7 @@ 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.lang.reflect.AnnotatedType; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; @@ -11,7 +11,7 @@ import net.minecraft.commands.arguments.NbtPathArgument; import org.spongepowered.configurate.serialize.ScalarSerializer; import org.spongepowered.configurate.serialize.SerializationException; -public class NbtPathSerializer extends ScalarSerializer { +public class NbtPathSerializer extends ScalarSerializer.Annotated { public static final NbtPathSerializer SERIALIZER = new NbtPathSerializer(); private static final NbtPathArgument DUMMY_ARGUMENT = new NbtPathArgument(); @@ -20,23 +20,13 @@ public class NbtPathSerializer extends ScalarSerializer 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> typeSupported) { - return item.toString(); - } - public static List fromString(final List tags) { - List paths = new ArrayList<>(); + final List paths = new ArrayList<>(); try { for (final String tag : tags) { paths.add(fromString(tag)); } - } catch (SerializationException ex) { + } catch (final SerializationException ex) { SneakyThrow.sneaky(ex); } return List.copyOf(paths); @@ -45,8 +35,18 @@ public class NbtPathSerializer extends ScalarSerializer private static NbtPathArgument.NbtPath fromString(final String tag) throws SerializationException { try { return DUMMY_ARGUMENT.parse(new StringReader(tag)); - } catch (CommandSyntaxException e) { + } catch (final CommandSyntaxException e) { throw new SerializationException(NbtPathArgument.NbtPath.class, e); } } + + @Override + public NbtPathArgument.NbtPath deserialize(final AnnotatedType type, final Object obj) throws SerializationException { + return fromString(obj.toString()); + } + + @Override + protected Object serialize(final AnnotatedType type, final NbtPathArgument.NbtPath item, final Predicate> typeSupported) { + return item.toString(); + } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java deleted file mode 100644 index a2fe12513b..0000000000 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/PacketClassSerializer.java +++ /dev/null @@ -1,86 +0,0 @@ -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.MappingEnvironment; -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>> implements MapSerializer.WriteBack { - - private static final Logger LOGGER = LogUtils.getClassLogger(); - private static final TypeToken>> TYPE = new TypeToken>>() {}; - private static final List SUBPACKAGES = List.of("game", "handshake", "login", "status"); - private static final BiMap MOJANG_TO_OBF; - - static { - final ImmutableBiMap.Builder builder = ImmutableBiMap.builder(); - final @Nullable Map 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> 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>) packetClass; - } - - @Override - protected @Nullable Object serialize(final Class> packetClass, final Predicate> typeSupported) { - final String name = packetClass.getName(); - @Nullable String mojName = ObfHelper.INSTANCE.mappingsByMojangName() == null || !MappingEnvironment.reobf() ? 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; - } -} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ResourceLocationSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ResourceLocationSerializer.java index 4bb8263226..9a6c278d62 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ResourceLocationSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ResourceLocationSerializer.java @@ -1,12 +1,13 @@ package io.papermc.paper.configuration.serializer; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Type; import java.util.function.Predicate; import net.minecraft.resources.ResourceLocation; import org.spongepowered.configurate.serialize.ScalarSerializer; import org.spongepowered.configurate.serialize.SerializationException; -public class ResourceLocationSerializer extends ScalarSerializer { +public class ResourceLocationSerializer extends ScalarSerializer.Annotated { public static final ScalarSerializer INSTANCE = new ResourceLocationSerializer(); @@ -15,12 +16,12 @@ public class ResourceLocationSerializer extends ScalarSerializer new SerializationException(ResourceLocation.class, s)); } @Override - protected Object serialize(final ResourceLocation item, final Predicate> typeSupported) { + protected Object serialize(final AnnotatedType annotatedType, final ResourceLocation item, final Predicate> typeSupported) { return item.toString(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java new file mode 100644 index 0000000000..1d09ba6406 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/ServerboundPacketClassSerializer.java @@ -0,0 +1,118 @@ +package io.papermc.paper.configuration.serializer; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.mojang.logging.LogUtils; +import io.leangen.geantyref.GenericTypeReflector; +import io.leangen.geantyref.TypeToken; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.network.protocol.common.CommonPacketTypes; +import net.minecraft.network.protocol.configuration.ConfigurationPacketTypes; +import net.minecraft.network.protocol.cookie.CookiePacketTypes; +import net.minecraft.network.protocol.game.GamePacketTypes; +import net.minecraft.network.protocol.handshake.HandshakePacketTypes; +import net.minecraft.network.protocol.login.LoginPacketTypes; +import net.minecraft.network.protocol.ping.PingPacketTypes; +import net.minecraft.network.protocol.status.StatusPacketTypes; +import net.minecraft.resources.ResourceLocation; +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 ServerboundPacketClassSerializer extends ScalarSerializer>> { + + private static final Logger LOGGER = LogUtils.getClassLogger(); + private static final TypeToken>> TYPE = new TypeToken>>() {}; + static final Set> PACKET_CLASS_HOLDERS = Set.of( + PingPacketTypes.class, + HandshakePacketTypes.class, + StatusPacketTypes.class, + LoginPacketTypes.class, + ConfigurationPacketTypes.class, + CommonPacketTypes.class, + CookiePacketTypes.class, + GamePacketTypes.class + ); + private static final Map ID_TO_INFO; + private static final Map, PacketInfo> CLASS_TO_INFO; + + static { + try { + final ImmutableMap.Builder idBuilder = ImmutableMap.builder(); + final ImmutableMap.Builder, PacketInfo> classBuilder = ImmutableMap.builder(); + for (final Class holder : PACKET_CLASS_HOLDERS) { + for (final Field field : holder.getDeclaredFields()) { + if (!Modifier.isStatic(field.getModifiers()) || !Modifier.isFinal(field.getModifiers()) || !field.getType().equals(PacketType.class)) { + continue; + } + final Type genericType = field.getGenericType(); + if (!(genericType instanceof final ParameterizedType parameterizedType)) { + throw new RuntimeException("Unexpected generic type: " + genericType); + } + final PacketType type = (PacketType) field.get(null); + if (type.flow() != PacketFlow.SERVERBOUND) { + // we only care about serverbound for rate limiting + continue; + } + final Class packetClass = GenericTypeReflector.erase(parameterizedType.getActualTypeArguments()[0]); + final PacketInfo info = new PacketInfo(packetClass.asSubclass(Packet.class), type); + idBuilder.put(type.id(), info); + classBuilder.put(packetClass, info); + } + } + ID_TO_INFO = idBuilder.buildOrThrow(); + CLASS_TO_INFO = classBuilder.buildOrThrow(); + Preconditions.checkState(ID_TO_INFO.size() == 74, "Packet class map must have 74 entries"); + } catch (final ReflectiveOperationException e) { + throw new RuntimeException("Could not create packet class map", e); + } + } + + public ServerboundPacketClassSerializer() { + super(TYPE); + } + + @Override + public Class> deserialize(final Type type, final Object obj) throws SerializationException { + final ResourceLocation location = ResourceLocation.tryParse(obj.toString()); + if (location == null) { + throw new SerializationException(ResourceLocation.class, "Could not deserialize a packet from " + obj); + } + final PacketInfo info = ID_TO_INFO.get(location); + if (info == null) { + throw new SerializationException("Could not deserialize a packet from " + obj); + } + return info.packetClass(); + } + + @Override + protected @Nullable Object serialize(final Class> packetClass, final Predicate> typeSupported) { + final PacketInfo info = CLASS_TO_INFO.get(packetClass); + if (info == null) { + LOGGER.error("Could not serialize {} into a packet identifier", packetClass); + return null; + } else { + return info.type().id().toString(); + } + } + + @SuppressWarnings("rawtypes") + record PacketInfo(Class clazz, PacketType type) { + + @SuppressWarnings("unchecked") + public Class> packetClass() { + return (Class>) this.clazz; + } + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java index 629012cb8e..2ce7b4c72f 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/StringRepresentableSerializer.java @@ -12,6 +12,7 @@ import org.spongepowered.configurate.serialize.ScalarSerializer; import org.spongepowered.configurate.serialize.SerializationException; public final class StringRepresentableSerializer extends ScalarSerializer { + private static final Map> TYPES = Collections.synchronizedMap(Map.ofEntries( createEntry(MobCategory.class) )); @@ -24,20 +25,22 @@ public final class StringRepresentableSerializer extends ScalarSerializer & StringRepresentable> Map.Entry> createEntry(Class type) { - return Map.entry(type, s -> { - for (E value : type.getEnumConstants()) { - if (value.getSerializedName().equals(s)) { - return value; + private static & StringRepresentable> Map.Entry> createEntry(final Class type) { + return Map.entry( + type, s -> { + for (final E value : type.getEnumConstants()) { + if (value.getSerializedName().equals(s)) { + return value; + } } + return null; } - return null; - }); + ); } @Override - public StringRepresentable deserialize(Type type, Object obj) throws SerializationException { - Function function = TYPES.get(type); + public StringRepresentable deserialize(final Type type, final Object obj) throws SerializationException { + final Function function = TYPES.get(type); if (function == null) { throw new SerializationException(type + " isn't registered"); } @@ -45,7 +48,7 @@ public final class StringRepresentableSerializer extends ScalarSerializer> typeSupported) { + protected Object serialize(final StringRepresentable item, final Predicate> typeSupported) { return item.getSerializedName(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/TableSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/TableSerializer.java similarity index 52% rename from paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/TableSerializer.java rename to paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/TableSerializer.java index c02b2aa256..9e2cacfb46 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/TableSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/TableSerializer.java @@ -1,9 +1,11 @@ -package io.papermc.paper.configuration.serializer.collections; +package io.papermc.paper.configuration.serializer.collection; 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.AnnotatedParameterizedType; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; @@ -15,33 +17,34 @@ import org.spongepowered.configurate.ConfigurationOptions; import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.serialize.TypeSerializer; -public class TableSerializer implements TypeSerializer> { +public class TableSerializer implements TypeSerializer.Annotated> { 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 { + public Table deserialize(final AnnotatedType type, final ConfigurationNode node) throws SerializationException { final Table table = HashBasedTable.create(); if (!node.empty() && node.isMap()) { - this.deserialize0(table, (ParameterizedType) type, node); + this.deserialize0(table, (AnnotatedParameterizedType) type, node); } return table; } @SuppressWarnings("unchecked") - private void deserialize0(final Table 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]; + private void deserialize0(final Table table, final AnnotatedParameterizedType type, final ConfigurationNode node) throws SerializationException { + final AnnotatedType rowType = type.getAnnotatedActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; + final AnnotatedType columnType = type.getAnnotatedActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; + final AnnotatedType valueType = type.getAnnotatedActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; final TypeSerializer rowKeySerializer = (TypeSerializer) 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> columnValueSerializer = (TypeSerializer>) node.options().serializers().get(mapType); + final ParameterizedType mapType = (ParameterizedType) TypeFactory.parameterizedClass(Map.class, columnType.getType(), valueType.getType()); + final AnnotatedParameterizedType annotatedMapType = TypeFactory.parameterizedAnnotatedType(mapType, type.getAnnotations(), columnType.getAnnotations(), valueType.getAnnotations()); + final TypeSerializer> columnValueSerializer = (TypeSerializer>) node.options().serializers().get(annotatedMapType); if (columnValueSerializer == null) { throw new SerializationException("Could not find serializer for table column-value map " + type); } @@ -56,17 +59,21 @@ public class TableSerializer implements TypeSerializer> { } @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); + public void serialize( + final AnnotatedType type, + final @Nullable Table obj, + final ConfigurationNode node + ) throws SerializationException { + if (obj != null) { + this.serialize0(obj, (AnnotatedParameterizedType) type, node); } } @SuppressWarnings({"rawtypes", "unchecked"}) - private void serialize0(final Table 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]; + private void serialize0(final Table table, final AnnotatedParameterizedType type, final ConfigurationNode node) throws SerializationException { + final AnnotatedType rowType = type.getAnnotatedActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; + final AnnotatedType columnType = type.getAnnotatedActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; + final AnnotatedType valueType = type.getAnnotatedActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; final TypeSerializer rowKeySerializer = node.options().serializers().get(rowType); if (rowKeySerializer == null) { @@ -77,12 +84,14 @@ public class TableSerializer implements TypeSerializer> { 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)); + final ParameterizedType mapType = (ParameterizedType) TypeFactory.parameterizedClass(Map.class, columnType.getType(), valueType.getType()); + final AnnotatedParameterizedType annotatedMapType = TypeFactory.parameterizedAnnotatedType(mapType, type.getAnnotations(), columnType.getAnnotations(), valueType.getAnnotations()); + node.node(keyObj).set(annotatedMapType, table.row(key)); } } @Override - public @Nullable Table emptyValue(Type specificType, ConfigurationOptions options) { + public @Nullable Table emptyValue(final Type specificType, final ConfigurationOptions options) { return ImmutableTable.of(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/FastutilMapSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/FastutilMapSerializer.java similarity index 97% rename from paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/FastutilMapSerializer.java rename to paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/FastutilMapSerializer.java index 68ed5ad7b6..eb3d49af0f 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/FastutilMapSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/FastutilMapSerializer.java @@ -1,8 +1,7 @@ -package io.papermc.paper.configuration.serializer.collections; +package io.papermc.paper.configuration.serializer.collection.map; 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; diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/MapSerializer.java similarity index 60% rename from paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java rename to paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/MapSerializer.java index 6bb8304b9d..4546b4cc43 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/MapSerializer.java @@ -1,11 +1,9 @@ -package io.papermc.paper.configuration.serializer.collections; +package io.papermc.paper.configuration.serializer.collection.map; import com.mojang.logging.LogUtils; import io.leangen.geantyref.TypeToken; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +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.HashSet; @@ -36,56 +34,54 @@ public class MapSerializer implements TypeSerializer.Annotated> { private final boolean clearInvalids; private final TypeSerializer> fallback; - public MapSerializer(boolean clearInvalids) { + public MapSerializer(final 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 { + public Map deserialize(final AnnotatedType annotatedType, final ConfigurationNode node) throws SerializationException { if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) { return this.fallback.deserialize(annotatedType, node); } final Map map = new LinkedHashMap<>(); final Type type = annotatedType.getType(); if (node.isMap()) { - if (!(type instanceof ParameterizedType parameterizedType)) { + if (!(annotatedType instanceof final AnnotatedParameterizedType annotatedParameterizedType)) { throw new SerializationException(type, "Raw types are not supported for collections"); } - if (parameterizedType.getActualTypeArguments().length != 2) { + if (annotatedParameterizedType.getAnnotatedActualTypeArguments().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); + final AnnotatedType key = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0]; + final AnnotatedType value = annotatedParameterizedType.getAnnotatedActualTypeArguments()[1]; + final TypeSerializer keySerializer = node.options().serializers().get(key); + final 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 boolean writeKeyBack = key.isAnnotationPresent(WriteKeyBack.class); final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options()); final Set keysToClear = new HashSet<>(); - for (Map.Entry 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()); + for (final Map.Entry ent : node.childrenMap().entrySet()) { + final Object deserializedKey = this.deserialize(key.getType(), keySerializer, "key", keyNode.set(ent.getKey()), node.path()); + final Object deserializedValue = this.deserialize(value.getType(), 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!"))) { + if (writeKeyBack) { + if (this.serialize(key.getType(), 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) { + if (writeKeyBack) { // supports cleaning keys which deserialize to the same value + for (final Object keyToClear : keysToClear) { node.node(keyToClear).raw(null); } } @@ -93,10 +89,10 @@ public class MapSerializer implements TypeSerializer.Annotated> { return map; } - private @Nullable Object deserialize(Type type, TypeSerializer serializer, String mapPart, ConfigurationNode node, NodePath path) { + private @Nullable Object deserialize(final Type type, final TypeSerializer serializer, final String mapPart, final ConfigurationNode node, final NodePath path) { try { return serializer.deserialize(type, node); - } catch (SerializationException ex) { + } catch (final SerializationException ex) { ex.initPath(node::path); LOGGER.error("Could not deserialize {} {} into {} at {}: {}", mapPart, node.raw(), type, path, ex.rawMessage()); } @@ -104,22 +100,22 @@ public class MapSerializer implements TypeSerializer.Annotated> { } @Override - public void serialize(AnnotatedType annotatedType, @Nullable Map obj, ConfigurationNode node) throws SerializationException { + public void serialize(final AnnotatedType annotatedType, final @Nullable Map obj, final 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)) { + if (!(annotatedType instanceof final AnnotatedParameterizedType annotatedParameterizedType)) { throw new SerializationException(type, "Raw types are not supported for collections"); } - if (parameterizedType.getActualTypeArguments().length != 2) { + if (annotatedParameterizedType.getAnnotatedActualTypeArguments().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); + final AnnotatedType key = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0]; + final AnnotatedType value = annotatedParameterizedType.getAnnotatedActualTypeArguments()[1]; + final TypeSerializer keySerializer = node.options().serializers().get(key); + final TypeSerializer valueSerializer = node.options().serializers().get(value); if (keySerializer == null) { throw new SerializationException(type, "No type serializer available for key type " + key); @@ -135,22 +131,22 @@ public class MapSerializer implements TypeSerializer.Annotated> { final Set unvisitedKeys; if (node.empty()) { node.raw(Collections.emptyMap()); - unvisitedKeys = Collections.emptySet(); + unvisitedKeys = new HashSet<>(); } 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())) { + for (final Map.Entry ent : obj.entrySet()) { + if (!this.serialize(key.getType(), 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()); + this.serialize(value.getType(), valueSerializer, ent.getValue(), "value", child, child.path()); unvisitedKeys.remove(keyObj); } if (this.clearInvalids) { - for (Object unusedChild : unvisitedKeys) { + for (final Object unusedChild : unvisitedKeys) { node.removeChild(unusedChild); } } @@ -158,11 +154,11 @@ public class MapSerializer implements TypeSerializer.Annotated> { } @SuppressWarnings({"rawtypes", "unchecked"}) - private boolean serialize(Type type, TypeSerializer serializer, Object object, String mapPart, ConfigurationNode node, NodePath path) { + private boolean serialize(final Type type, final TypeSerializer serializer, final Object object, final String mapPart, final ConfigurationNode node, final NodePath path) { try { serializer.serialize(type, object, node); return true; - } catch (SerializationException ex) { + } catch (final SerializationException ex) { ex.initPath(node::path); LOGGER.error("Could not serialize {} {} from {} at {}: {}", mapPart, object, type, path, ex.rawMessage()); } @@ -170,13 +166,11 @@ public class MapSerializer implements TypeSerializer.Annotated> { } @Override - public @Nullable Map emptyValue(AnnotatedType specificType, ConfigurationOptions options) { + public @Nullable Map emptyValue(final AnnotatedType specificType, final ConfigurationOptions options) { if (specificType.isAnnotationPresent(ThrowExceptions.class)) { return this.fallback.emptyValue(specificType, options); } return new LinkedHashMap<>(); } - public interface WriteBack { // marker interface - } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/ThrowExceptions.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/ThrowExceptions.java new file mode 100644 index 0000000000..2ae38a0f63 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/ThrowExceptions.java @@ -0,0 +1,10 @@ +package io.papermc.paper.configuration.serializer.collection.map; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ThrowExceptions {} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/WriteKeyBack.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/WriteKeyBack.java new file mode 100644 index 0000000000..25d48eb88a --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/WriteKeyBack.java @@ -0,0 +1,10 @@ +package io.papermc.paper.configuration.serializer.collection.map; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE_USE) +@Retention(RetentionPolicy.RUNTIME) +public @interface WriteKeyBack {} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/package-info.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/package-info.java new file mode 100644 index 0000000000..a200b9c8fb --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/map/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.configuration.serializer.collection.map; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/package-info.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/package-info.java new file mode 100644 index 0000000000..0513f716fe --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collection/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.configuration.serializer.collection; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java deleted file mode 100644 index 78899dc135..0000000000 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NullMarked -package io.papermc.paper.configuration.serializer.collections; - -import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java index 6b600a133f..5ca61cb1e5 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java @@ -1,6 +1,7 @@ package io.papermc.paper.configuration.serializer.registry; import io.leangen.geantyref.TypeToken; +import java.lang.reflect.AnnotatedType; import java.lang.reflect.Type; import java.util.function.Predicate; import net.minecraft.core.Registry; @@ -10,20 +11,30 @@ import net.minecraft.resources.ResourceLocation; import org.spongepowered.configurate.serialize.ScalarSerializer; import org.spongepowered.configurate.serialize.SerializationException; -abstract class RegistryEntrySerializer extends ScalarSerializer { +abstract class RegistryEntrySerializer extends ScalarSerializer.Annotated { private final RegistryAccess registryAccess; private final ResourceKey> registryKey; private final boolean omitMinecraftNamespace; - protected RegistryEntrySerializer(TypeToken type, final RegistryAccess registryAccess, ResourceKey> registryKey, boolean omitMinecraftNamespace) { + protected RegistryEntrySerializer( + final TypeToken type, + final RegistryAccess registryAccess, + final ResourceKey> registryKey, + final boolean omitMinecraftNamespace + ) { super(type); this.registryAccess = registryAccess; this.registryKey = registryKey; this.omitMinecraftNamespace = omitMinecraftNamespace; } - protected RegistryEntrySerializer(Class type, final RegistryAccess registryAccess, ResourceKey> registryKey, boolean omitMinecraftNamespace) { + protected RegistryEntrySerializer( + final Class type, + final RegistryAccess registryAccess, + final ResourceKey> registryKey, + final boolean omitMinecraftNamespace + ) { super(type); this.registryAccess = registryAccess; this.registryKey = registryKey; @@ -37,14 +48,14 @@ abstract class RegistryEntrySerializer extends ScalarSerializer { protected abstract T convertFromResourceKey(ResourceKey key) throws SerializationException; @Override - public final T deserialize(Type type, Object obj) throws SerializationException { + public final T deserialize(final AnnotatedType type, final Object obj) throws SerializationException { return this.convertFromResourceKey(this.deserializeKey(obj)); } protected abstract ResourceKey convertToResourceKey(T value); @Override - protected final Object serialize(T item, Predicate> typeSupported) { + protected final Object serialize(final AnnotatedType type, final T item, final Predicate> typeSupported) { final ResourceKey key = this.convertToResourceKey(item); if (this.omitMinecraftNamespace && key.location().getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) { return key.location().getPath(); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java index 76f6219eac..c541372296 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryHolderSerializer.java @@ -13,22 +13,32 @@ import org.spongepowered.configurate.serialize.SerializationException; public final class RegistryHolderSerializer extends RegistryEntrySerializer, T> { @SuppressWarnings("unchecked") - public RegistryHolderSerializer(TypeToken typeToken, final RegistryAccess registryAccess, ResourceKey> registryKey, boolean omitMinecraftNamespace) { + public RegistryHolderSerializer( + final TypeToken typeToken, + final RegistryAccess registryAccess, + final ResourceKey> registryKey, + final boolean omitMinecraftNamespace + ) { super((TypeToken>) TypeToken.get(TypeFactory.parameterizedClass(Holder.class, typeToken.getType())), registryAccess, registryKey, omitMinecraftNamespace); } - public RegistryHolderSerializer(Class type, final RegistryAccess registryAccess, ResourceKey> registryKey, boolean omitMinecraftNamespace) { + public RegistryHolderSerializer( + final Class type, + final RegistryAccess registryAccess, + final ResourceKey> registryKey, + final 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 convertFromResourceKey(ResourceKey key) throws SerializationException { + protected Holder convertFromResourceKey(final ResourceKey key) throws SerializationException { return this.registry().get(key).orElseThrow(() -> new SerializationException("Missing holder in " + this.registry().key() + " with key " + key)); } @Override - protected ResourceKey convertToResourceKey(Holder value) { + protected ResourceKey convertToResourceKey(final Holder value) { return value.unwrap().map(Function.identity(), r -> this.registry().getResourceKey(r).orElseThrow()); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java index 6831b7b72c..ad08f242cd 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryValueSerializer.java @@ -11,16 +11,26 @@ import org.spongepowered.configurate.serialize.SerializationException; */ public final class RegistryValueSerializer extends RegistryEntrySerializer { - public RegistryValueSerializer(TypeToken type, final RegistryAccess registryAccess, ResourceKey> registryKey, boolean omitMinecraftNamespace) { + public RegistryValueSerializer( + final TypeToken type, + final RegistryAccess registryAccess, + final ResourceKey> registryKey, + final boolean omitMinecraftNamespace + ) { super(type, registryAccess, registryKey, omitMinecraftNamespace); } - public RegistryValueSerializer(Class type, final RegistryAccess registryAccess, ResourceKey> registryKey, boolean omitMinecraftNamespace) { + public RegistryValueSerializer( + final Class type, + final RegistryAccess registryAccess, + final ResourceKey> registryKey, + final boolean omitMinecraftNamespace + ) { super(type, registryAccess, registryKey, omitMinecraftNamespace); } @Override - protected T convertFromResourceKey(ResourceKey key) throws SerializationException { + protected T convertFromResourceKey(final ResourceKey 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()); @@ -29,7 +39,7 @@ public final class RegistryValueSerializer extends RegistryEntrySerializer convertToResourceKey(T value) { + protected ResourceKey convertToResourceKey(final T value) { return this.registry().getResourceKey(value).orElseThrow(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V30_PacketIds.java b/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V30_PacketIds.java new file mode 100644 index 0000000000..9838438ef7 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V30_PacketIds.java @@ -0,0 +1,67 @@ +package io.papermc.paper.configuration.transformation.global.versioned; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.Map; +import java.util.Objects; +import net.minecraft.resources.ResourceLocation; +import org.jspecify.annotations.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.NodePath; +import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.transformation.TransformAction; + +import static java.util.Objects.requireNonNull; +import static org.spongepowered.configurate.NodePath.path; + +public class V30_PacketIds implements TransformAction { + + public static final V30_PacketIds INSTANCE = new V30_PacketIds(); + private static final int VERSION = 30; + + private static final Gson GSON = new Gson(); + private static final Map MOJANG_TO_ID; + + static { + final ImmutableMap.Builder builder2 = ImmutableMap.builder(); + final InputStream input = V30_PacketIds.class.getResourceAsStream("/config-data/packet-limiter-upgrade-data.json"); + if (input == null) { + throw new RuntimeException("Failed to load packet limiter upgrade data"); + } + try (final Reader reader = new InputStreamReader(new BufferedInputStream(input))) { + final JsonArray array = GSON.fromJson(reader, JsonArray.class); + for (final JsonElement element : array) { + final JsonObject obj = element.getAsJsonObject(); + builder2.put(obj.get("simple_class_name").getAsString(), ResourceLocation.parse(obj.get("id").getAsString())); + } + } catch (final IOException e) { + throw new RuntimeException("Failed to load packet limiter upgrade data", e); + } + MOJANG_TO_ID = builder2.build(); + } + + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformation.builder().addAction(path("packet-limiter", "overrides", ConfigurationTransformation.WILDCARD_OBJECT), INSTANCE).build()); + } + + private V30_PacketIds() { + } + + + @Override + public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) { + final String oldClassName = path.get(path.size() - 1).toString(); + if (MOJANG_TO_ID.containsKey(oldClassName)) { + return path.with(path.size() - 1, MOJANG_TO_ID.get(oldClassName).toString()).array(); + } + return null; + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java b/paper-server/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java index 1e73f51b7f..b898e1c509 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java @@ -1,6 +1,6 @@ package io.papermc.paper.configuration.type; -import java.lang.reflect.Type; +import java.lang.reflect.AnnotatedType; import java.util.Locale; import java.util.function.Predicate; import org.apache.commons.lang3.BooleanUtils; @@ -9,38 +9,38 @@ import org.spongepowered.configurate.serialize.ScalarSerializer; import org.spongepowered.configurate.serialize.SerializationException; public record BooleanOrDefault(@Nullable Boolean value) { - private static final String DEFAULT_VALUE = "default"; public static final BooleanOrDefault USE_DEFAULT = new BooleanOrDefault(null); public static final ScalarSerializer SERIALIZER = new Serializer(); + private static final String DEFAULT_VALUE = "default"; - public boolean or(boolean fallback) { + public boolean or(final boolean fallback) { return this.value == null ? fallback : this.value; } - private static final class Serializer extends ScalarSerializer { + private static final class Serializer extends ScalarSerializer.Annotated { Serializer() { super(BooleanOrDefault.class); } @Override - public BooleanOrDefault deserialize(Type type, Object obj) throws SerializationException { - if (obj instanceof String string) { + public BooleanOrDefault deserialize(final AnnotatedType type, final Object obj) throws SerializationException { + if (obj instanceof final String string) { if (DEFAULT_VALUE.equalsIgnoreCase(string)) { return USE_DEFAULT; } try { return new BooleanOrDefault(BooleanUtils.toBoolean(string.toLowerCase(Locale.ROOT), "true", "false")); - } catch (IllegalArgumentException ex) { + } catch (final IllegalArgumentException ex) { throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'", ex); } - } else if (obj instanceof Boolean bool) { + } else if (obj instanceof final Boolean bool) { return new BooleanOrDefault(bool); } throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'"); } @Override - protected Object serialize(BooleanOrDefault item, Predicate> typeSupported) { + protected Object serialize(final AnnotatedType type, final BooleanOrDefault item, final Predicate> typeSupported) { final Boolean value = item.value; if (value != null) { return value.toString(); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/type/number/DoubleOr.java b/paper-server/src/main/java/io/papermc/paper/configuration/type/number/DoubleOr.java index 0e7205e6ba..28faeffa4f 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/type/number/DoubleOr.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/type/number/DoubleOr.java @@ -1,6 +1,7 @@ package io.papermc.paper.configuration.type.number; import com.google.common.base.Preconditions; +import java.lang.reflect.AnnotatedType; import java.util.OptionalDouble; import java.util.function.DoublePredicate; import java.util.function.Function; @@ -20,17 +21,17 @@ public interface DoubleOr { } record Default(OptionalDouble value) implements DoubleOr { - private static final String DEFAULT_VALUE = "default"; public static final Default USE_DEFAULT = new Default(OptionalDouble.empty()); + private static final String DEFAULT_VALUE = "default"; public static final ScalarSerializer SERIALIZER = new Serializer<>(Default.class, Default::new, DEFAULT_VALUE, USE_DEFAULT); } record Disabled(OptionalDouble value) implements DoubleOr { - private static final String DISABLED_VALUE = "disabled"; public static final Disabled DISABLED = new Disabled(OptionalDouble.empty()); + private static final String DISABLED_VALUE = "disabled"; public static final ScalarSerializer SERIALIZER = new Serializer<>(Disabled.class, Disabled::new, DISABLED_VALUE, DISABLED); - public boolean test(DoublePredicate predicate) { + public boolean test(final DoublePredicate predicate) { return this.value.isPresent() && predicate.test(this.value.getAsDouble()); } @@ -40,12 +41,12 @@ public interface DoubleOr { } final class Serializer extends OptionalNumSerializer { - Serializer(final Class classOfT, final Function factory, String emptySerializedValue, T emptyValue) { + Serializer(final Class classOfT, final Function factory, final String emptySerializedValue, final T emptyValue) { super(classOfT, emptySerializedValue, emptyValue, OptionalDouble::empty, OptionalDouble::isEmpty, factory, double.class); } @Override - protected Object serialize(final T item, final Predicate> typeSupported) { + protected Object serialize(final AnnotatedType type, final T item, final Predicate> typeSupported) { final OptionalDouble value = item.value(); if (value.isPresent()) { return value.getAsDouble(); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/type/number/IntOr.java b/paper-server/src/main/java/io/papermc/paper/configuration/type/number/IntOr.java index 73a7b66492..70ae169348 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/type/number/IntOr.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/type/number/IntOr.java @@ -2,6 +2,7 @@ package io.papermc.paper.configuration.type.number; import com.google.common.base.Preconditions; import com.mojang.logging.LogUtils; +import java.lang.reflect.AnnotatedType; import java.util.OptionalInt; import java.util.function.Function; import java.util.function.IntPredicate; @@ -28,17 +29,17 @@ public interface IntOr { } record Default(OptionalInt value) implements IntOr { - private static final String DEFAULT_VALUE = "default"; public static final Default USE_DEFAULT = new Default(OptionalInt.empty()); + private static final String DEFAULT_VALUE = "default"; public static final ScalarSerializer SERIALIZER = new Serializer<>(Default.class, Default::new, DEFAULT_VALUE, USE_DEFAULT); } record Disabled(OptionalInt value) implements IntOr { - private static final String DISABLED_VALUE = "disabled"; public static final Disabled DISABLED = new Disabled(OptionalInt.empty()); + private static final String DISABLED_VALUE = "disabled"; public static final ScalarSerializer SERIALIZER = new Serializer<>(Disabled.class, Disabled::new, DISABLED_VALUE, DISABLED); - public boolean test(IntPredicate predicate) { + public boolean test(final IntPredicate predicate) { return this.value.isPresent() && predicate.test(this.value.getAsInt()); } @@ -49,7 +50,7 @@ public interface IntOr { final class Serializer extends OptionalNumSerializer { - private Serializer(Class classOfT, Function factory, String emptySerializedValue, T emptyValue) { + private Serializer(final Class classOfT, final Function factory, final String emptySerializedValue, final T emptyValue) { super(classOfT, emptySerializedValue, emptyValue, OptionalInt::empty, OptionalInt::isEmpty, factory, int.class); } @@ -73,7 +74,7 @@ public interface IntOr { } @Override - protected Object serialize(final T item, final Predicate> typeSupported) { + protected Object serialize(final AnnotatedType type, final T item, final Predicate> typeSupported) { final OptionalInt value = item.value(); if (value.isPresent()) { return value.getAsInt(); diff --git a/paper-server/src/main/java/io/papermc/paper/configuration/type/number/OptionalNumSerializer.java b/paper-server/src/main/java/io/papermc/paper/configuration/type/number/OptionalNumSerializer.java index 614aba60bb..480015f1ef 100644 --- a/paper-server/src/main/java/io/papermc/paper/configuration/type/number/OptionalNumSerializer.java +++ b/paper-server/src/main/java/io/papermc/paper/configuration/type/number/OptionalNumSerializer.java @@ -17,7 +17,15 @@ public abstract class OptionalNumSerializer extends ScalarSerializer.Annot private final Function factory; private final Class number; - protected OptionalNumSerializer(final Class classOfT, final String emptySerializedValue, final T emptyValue, final Supplier empty, final Predicate isEmpty, final Function factory, final Class number) { + protected OptionalNumSerializer( + final Class classOfT, + final String emptySerializedValue, + final T emptyValue, + final Supplier empty, + final Predicate isEmpty, + final Function factory, + final Class number + ) { super(classOfT); this.emptySerializedValue = emptySerializedValue; this.emptyValue = emptyValue; @@ -30,7 +38,7 @@ public abstract class OptionalNumSerializer extends ScalarSerializer.Annot @Override public final T deserialize(final AnnotatedType type, final Object obj) throws SerializationException { final O value; - if (obj instanceof String string) { + if (obj instanceof final String string) { if (this.emptySerializedValue.equalsIgnoreCase(string)) { value = this.empty.get(); } else if (NumberUtils.isParsable(string)) { @@ -38,7 +46,7 @@ public abstract class OptionalNumSerializer extends ScalarSerializer.Annot } else { throw new SerializationException("%s (%s) is not a(n) %s or '%s'".formatted(obj, type, this.number.getSimpleName(), this.emptySerializedValue)); } - } else if (obj instanceof Number num) { + } else if (obj instanceof final Number num) { value = this.full(num); } else { throw new SerializationException("%s (%s) is not a(n) %s or '%s'".formatted(obj, type, this.number.getSimpleName(), this.emptySerializedValue)); diff --git a/paper-server/src/main/resources/config-data/packet-limiter-upgrade-data.json b/paper-server/src/main/resources/config-data/packet-limiter-upgrade-data.json new file mode 100644 index 0000000000..7df83994e3 --- /dev/null +++ b/paper-server/src/main/resources/config-data/packet-limiter-upgrade-data.json @@ -0,0 +1 @@ +[{"id":"minecraft:finish_configuration","fq_class_name":"net.minecraft.network.protocol.configuration.ServerboundFinishConfigurationPacket","simple_class_name":"ServerboundFinishConfigurationPacket"},{"id":"minecraft:select_known_packs","fq_class_name":"net.minecraft.network.protocol.configuration.ServerboundSelectKnownPacks","simple_class_name":"ServerboundSelectKnownPacks"},{"id":"minecraft:ping_request","fq_class_name":"net.minecraft.network.protocol.ping.ServerboundPingRequestPacket","simple_class_name":"ServerboundPingRequestPacket"},{"id":"minecraft:intention","fq_class_name":"net.minecraft.network.protocol.handshake.ClientIntentionPacket","simple_class_name":"ClientIntentionPacket"},{"id":"minecraft:cookie_response","fq_class_name":"net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket","simple_class_name":"ServerboundCookieResponsePacket"},{"id":"minecraft:client_information","fq_class_name":"net.minecraft.network.protocol.common.ServerboundClientInformationPacket","simple_class_name":"ServerboundClientInformationPacket"},{"id":"minecraft:custom_payload","fq_class_name":"net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket","simple_class_name":"ServerboundCustomPayloadPacket"},{"id":"minecraft:keep_alive","fq_class_name":"net.minecraft.network.protocol.common.ServerboundKeepAlivePacket","simple_class_name":"ServerboundKeepAlivePacket"},{"id":"minecraft:pong","fq_class_name":"net.minecraft.network.protocol.common.ServerboundPongPacket","simple_class_name":"ServerboundPongPacket"},{"id":"minecraft:resource_pack","fq_class_name":"net.minecraft.network.protocol.common.ServerboundResourcePackPacket","simple_class_name":"ServerboundResourcePackPacket"},{"id":"minecraft:custom_click_action","fq_class_name":"net.minecraft.network.protocol.common.ServerboundCustomClickActionPacket","simple_class_name":"ServerboundCustomClickActionPacket"},{"id":"minecraft:accept_teleportation","fq_class_name":"net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket","simple_class_name":"ServerboundAcceptTeleportationPacket"},{"id":"minecraft:block_entity_tag_query","fq_class_name":"net.minecraft.network.protocol.game.ServerboundBlockEntityTagQueryPacket","simple_class_name":"ServerboundBlockEntityTagQueryPacket"},{"id":"minecraft:bundle_item_selected","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSelectBundleItemPacket","simple_class_name":"ServerboundSelectBundleItemPacket"},{"id":"minecraft:change_difficulty","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChangeDifficultyPacket","simple_class_name":"ServerboundChangeDifficultyPacket"},{"id":"minecraft:change_game_mode","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChangeGameModePacket","simple_class_name":"ServerboundChangeGameModePacket"},{"id":"minecraft:chat_ack","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatAckPacket","simple_class_name":"ServerboundChatAckPacket"},{"id":"minecraft:chat_command","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatCommandPacket","simple_class_name":"ServerboundChatCommandPacket"},{"id":"minecraft:chat_command_signed","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatCommandSignedPacket","simple_class_name":"ServerboundChatCommandSignedPacket"},{"id":"minecraft:chat","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatPacket","simple_class_name":"ServerboundChatPacket"},{"id":"minecraft:chat_session_update","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatSessionUpdatePacket","simple_class_name":"ServerboundChatSessionUpdatePacket"},{"id":"minecraft:chunk_batch_received","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChunkBatchReceivedPacket","simple_class_name":"ServerboundChunkBatchReceivedPacket"},{"id":"minecraft:client_command","fq_class_name":"net.minecraft.network.protocol.game.ServerboundClientCommandPacket","simple_class_name":"ServerboundClientCommandPacket"},{"id":"minecraft:client_tick_end","fq_class_name":"net.minecraft.network.protocol.game.ServerboundClientTickEndPacket","simple_class_name":"ServerboundClientTickEndPacket"},{"id":"minecraft:command_suggestion","fq_class_name":"net.minecraft.network.protocol.game.ServerboundCommandSuggestionPacket","simple_class_name":"ServerboundCommandSuggestionPacket"},{"id":"minecraft:configuration_acknowledged","fq_class_name":"net.minecraft.network.protocol.game.ServerboundConfigurationAcknowledgedPacket","simple_class_name":"ServerboundConfigurationAcknowledgedPacket"},{"id":"minecraft:container_button_click","fq_class_name":"net.minecraft.network.protocol.game.ServerboundContainerButtonClickPacket","simple_class_name":"ServerboundContainerButtonClickPacket"},{"id":"minecraft:container_click","fq_class_name":"net.minecraft.network.protocol.game.ServerboundContainerClickPacket","simple_class_name":"ServerboundContainerClickPacket"},{"id":"minecraft:container_close","fq_class_name":"net.minecraft.network.protocol.game.ServerboundContainerClosePacket","simple_class_name":"ServerboundContainerClosePacket"},{"id":"minecraft:container_slot_state_changed","fq_class_name":"net.minecraft.network.protocol.game.ServerboundContainerSlotStateChangedPacket","simple_class_name":"ServerboundContainerSlotStateChangedPacket"},{"id":"minecraft:debug_sample_subscription","fq_class_name":"net.minecraft.network.protocol.game.ServerboundDebugSampleSubscriptionPacket","simple_class_name":"ServerboundDebugSampleSubscriptionPacket"},{"id":"minecraft:edit_book","fq_class_name":"net.minecraft.network.protocol.game.ServerboundEditBookPacket","simple_class_name":"ServerboundEditBookPacket"},{"id":"minecraft:entity_tag_query","fq_class_name":"net.minecraft.network.protocol.game.ServerboundEntityTagQueryPacket","simple_class_name":"ServerboundEntityTagQueryPacket"},{"id":"minecraft:interact","fq_class_name":"net.minecraft.network.protocol.game.ServerboundInteractPacket","simple_class_name":"ServerboundInteractPacket"},{"id":"minecraft:jigsaw_generate","fq_class_name":"net.minecraft.network.protocol.game.ServerboundJigsawGeneratePacket","simple_class_name":"ServerboundJigsawGeneratePacket"},{"id":"minecraft:lock_difficulty","fq_class_name":"net.minecraft.network.protocol.game.ServerboundLockDifficultyPacket","simple_class_name":"ServerboundLockDifficultyPacket"},{"id":"minecraft:move_player_pos","fq_class_name":"net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos","simple_class_name":"Pos"},{"id":"minecraft:move_player_pos_rot","fq_class_name":"net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot","simple_class_name":"PosRot"},{"id":"minecraft:move_player_rot","fq_class_name":"net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot","simple_class_name":"Rot"},{"id":"minecraft:move_player_status_only","fq_class_name":"net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$StatusOnly","simple_class_name":"StatusOnly"},{"id":"minecraft:move_vehicle","fq_class_name":"net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket","simple_class_name":"ServerboundMoveVehiclePacket"},{"id":"minecraft:paddle_boat","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPaddleBoatPacket","simple_class_name":"ServerboundPaddleBoatPacket"},{"id":"minecraft:pick_item_from_block","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPickItemFromBlockPacket","simple_class_name":"ServerboundPickItemFromBlockPacket"},{"id":"minecraft:pick_item_from_entity","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPickItemFromEntityPacket","simple_class_name":"ServerboundPickItemFromEntityPacket"},{"id":"minecraft:place_recipe","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket","simple_class_name":"ServerboundPlaceRecipePacket"},{"id":"minecraft:player_abilities","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPlayerAbilitiesPacket","simple_class_name":"ServerboundPlayerAbilitiesPacket"},{"id":"minecraft:player_action","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPlayerActionPacket","simple_class_name":"ServerboundPlayerActionPacket"},{"id":"minecraft:player_command","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket","simple_class_name":"ServerboundPlayerCommandPacket"},{"id":"minecraft:player_input","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPlayerInputPacket","simple_class_name":"ServerboundPlayerInputPacket"},{"id":"minecraft:player_loaded","fq_class_name":"net.minecraft.network.protocol.game.ServerboundPlayerLoadedPacket","simple_class_name":"ServerboundPlayerLoadedPacket"},{"id":"minecraft:recipe_book_change_settings","fq_class_name":"net.minecraft.network.protocol.game.ServerboundRecipeBookChangeSettingsPacket","simple_class_name":"ServerboundRecipeBookChangeSettingsPacket"},{"id":"minecraft:recipe_book_seen_recipe","fq_class_name":"net.minecraft.network.protocol.game.ServerboundRecipeBookSeenRecipePacket","simple_class_name":"ServerboundRecipeBookSeenRecipePacket"},{"id":"minecraft:rename_item","fq_class_name":"net.minecraft.network.protocol.game.ServerboundRenameItemPacket","simple_class_name":"ServerboundRenameItemPacket"},{"id":"minecraft:seen_advancements","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSeenAdvancementsPacket","simple_class_name":"ServerboundSeenAdvancementsPacket"},{"id":"minecraft:select_trade","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSelectTradePacket","simple_class_name":"ServerboundSelectTradePacket"},{"id":"minecraft:set_beacon","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetBeaconPacket","simple_class_name":"ServerboundSetBeaconPacket"},{"id":"minecraft:set_carried_item","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetCarriedItemPacket","simple_class_name":"ServerboundSetCarriedItemPacket"},{"id":"minecraft:set_command_block","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetCommandBlockPacket","simple_class_name":"ServerboundSetCommandBlockPacket"},{"id":"minecraft:set_command_minecart","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetCommandMinecartPacket","simple_class_name":"ServerboundSetCommandMinecartPacket"},{"id":"minecraft:set_creative_mode_slot","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetCreativeModeSlotPacket","simple_class_name":"ServerboundSetCreativeModeSlotPacket"},{"id":"minecraft:set_jigsaw_block","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetJigsawBlockPacket","simple_class_name":"ServerboundSetJigsawBlockPacket"},{"id":"minecraft:set_structure_block","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetStructureBlockPacket","simple_class_name":"ServerboundSetStructureBlockPacket"},{"id":"minecraft:set_test_block","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSetTestBlockPacket","simple_class_name":"ServerboundSetTestBlockPacket"},{"id":"minecraft:test_instance_block_action","fq_class_name":"net.minecraft.network.protocol.game.ServerboundTestInstanceBlockActionPacket","simple_class_name":"ServerboundTestInstanceBlockActionPacket"},{"id":"minecraft:sign_update","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSignUpdatePacket","simple_class_name":"ServerboundSignUpdatePacket"},{"id":"minecraft:swing","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSwingPacket","simple_class_name":"ServerboundSwingPacket"},{"id":"minecraft:teleport_to_entity","fq_class_name":"net.minecraft.network.protocol.game.ServerboundTeleportToEntityPacket","simple_class_name":"ServerboundTeleportToEntityPacket"},{"id":"minecraft:use_item_on","fq_class_name":"net.minecraft.network.protocol.game.ServerboundUseItemOnPacket","simple_class_name":"ServerboundUseItemOnPacket"},{"id":"minecraft:use_item","fq_class_name":"net.minecraft.network.protocol.game.ServerboundUseItemPacket","simple_class_name":"ServerboundUseItemPacket"},{"id":"minecraft:custom_query_answer","fq_class_name":"net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket","simple_class_name":"ServerboundCustomQueryAnswerPacket"},{"id":"minecraft:hello","fq_class_name":"net.minecraft.network.protocol.login.ServerboundHelloPacket","simple_class_name":"ServerboundHelloPacket"},{"id":"minecraft:key","fq_class_name":"net.minecraft.network.protocol.login.ServerboundKeyPacket","simple_class_name":"ServerboundKeyPacket"},{"id":"minecraft:login_acknowledged","fq_class_name":"net.minecraft.network.protocol.login.ServerboundLoginAcknowledgedPacket","simple_class_name":"ServerboundLoginAcknowledgedPacket"},{"id":"minecraft:status_request","fq_class_name":"net.minecraft.network.protocol.status.ServerboundStatusRequestPacket","simple_class_name":"ServerboundStatusRequestPacket"}] \ No newline at end of file