Skip to content

Commit 617e5a4

Browse files
Update to configurate 4.2.0 (#12869)
1 parent a2d37f1 commit 617e5a4

36 files changed

+623
-292
lines changed

paper-server/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ dependencies {
154154
implementation("io.netty:netty-codec-haproxy:4.1.118.Final") // Add support for proxy protocol
155155
implementation("org.apache.logging.log4j:log4j-iostreams:2.24.1")
156156
implementation("org.ow2.asm:asm-commons:9.8")
157-
implementation("org.spongepowered:configurate-yaml:4.2.0-20250225.064233-199")
158-
implementation("org.spongepowered:configurate-core:4.2.0-20250225.064233-204") // Pinned dependency of above pinned yaml snapshot.
157+
implementation("org.spongepowered:configurate-yaml:4.2.0")
159158

160159
// Deps that were previously in the API but have now been moved here for backwards compat, eventually to be removed
161160
runtimeOnly("commons-lang:commons-lang:2.6")

paper-server/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.mojang.logging.LogUtils;
44
import io.papermc.paper.FeatureHooks;
55
import io.papermc.paper.configuration.constraint.Constraints;
6+
import io.papermc.paper.configuration.serializer.collection.map.WriteKeyBack;
67
import io.papermc.paper.configuration.type.number.DoubleOr;
78
import io.papermc.paper.configuration.type.number.IntOr;
89
import io.papermc.paper.util.sanitizer.ItemObfuscationBinding;
@@ -28,7 +29,7 @@
2829
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"})
2930
public class GlobalConfiguration extends ConfigurationPart {
3031
private static final Logger LOGGER = LogUtils.getLogger();
31-
static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): <insert changes here>
32+
static final int CURRENT_VERSION = 30; // (when you change the version, change the comment, so it conflicts on rebases): upgrade packet to use ids
3233
private static GlobalConfiguration instance;
3334
public static boolean isFirstStart = false;
3435
public static GlobalConfiguration get() {
@@ -274,7 +275,7 @@ public class BookSize extends ConfigurationPart {
274275
public class PacketLimiter extends ConfigurationPart {
275276
public Component kickMessage = Component.translatable("disconnect.exceeded_packet_rate", NamedTextColor.RED);
276277
public PacketLimit allPackets = new PacketLimit(7.0, 500.0, PacketLimit.ViolateAction.KICK);
277-
public Map<Class<? extends Packet<?>>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP));
278+
public Map<@WriteKeyBack Class<? extends Packet<?>>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP));
278279

279280
@ConfigSerializable
280281
public record PacketLimit(@Required double interval, @Required double maxPacketRate, ViolateAction action) {

paper-server/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,25 @@
55
import com.mojang.logging.LogUtils;
66
import io.leangen.geantyref.TypeToken;
77
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
8+
import io.papermc.paper.configuration.mapping.Definition;
9+
import io.papermc.paper.configuration.mapping.FieldProcessor;
810
import io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer;
11+
import io.papermc.paper.configuration.mapping.MergeMap;
912
import io.papermc.paper.configuration.serializer.ComponentSerializer;
1013
import io.papermc.paper.configuration.serializer.EnumValueSerializer;
1114
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
12-
import io.papermc.paper.configuration.serializer.PacketClassSerializer;
15+
import io.papermc.paper.configuration.serializer.ServerboundPacketClassSerializer;
1316
import io.papermc.paper.configuration.serializer.ResourceLocationSerializer;
1417
import io.papermc.paper.configuration.serializer.StringRepresentableSerializer;
15-
import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer;
16-
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
17-
import io.papermc.paper.configuration.serializer.collections.TableSerializer;
18+
import io.papermc.paper.configuration.serializer.collection.TableSerializer;
19+
import io.papermc.paper.configuration.serializer.collection.map.FastutilMapSerializer;
20+
import io.papermc.paper.configuration.serializer.collection.map.MapSerializer;
1821
import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer;
1922
import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer;
2023
import io.papermc.paper.configuration.transformation.Transformations;
2124
import io.papermc.paper.configuration.transformation.global.LegacyPaperConfig;
2225
import io.papermc.paper.configuration.transformation.global.versioned.V29_LogIPs;
26+
import io.papermc.paper.configuration.transformation.global.versioned.V30_PacketIds;
2327
import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
2428
import io.papermc.paper.configuration.transformation.world.LegacyPaperWorldConfig;
2529
import io.papermc.paper.configuration.transformation.world.versioned.V29_ZeroWorldHeight;
@@ -41,10 +45,12 @@
4145
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
4246
import java.io.File;
4347
import java.io.IOException;
48+
import java.lang.annotation.Annotation;
4449
import java.lang.reflect.Type;
4550
import java.nio.file.Files;
4651
import java.nio.file.Path;
4752
import java.nio.file.StandardCopyOption;
53+
import java.util.ArrayList;
4854
import java.util.List;
4955
import java.util.function.Function;
5056
import java.util.function.Supplier;
@@ -196,7 +202,7 @@ protected ObjectMapper.Factory.Builder createGlobalObjectMapperFactoryBuilder()
196202
}
197203

198204
private static ObjectMapper.Factory.Builder defaultGlobalFactoryBuilder(ObjectMapper.Factory.Builder builder) {
199-
return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig());
205+
return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig(defaultFieldProcessors()));
200206
}
201207

202208
@Override
@@ -209,7 +215,7 @@ private static ConfigurationOptions defaultGlobalOptions(RegistryAccess registry
209215
return options
210216
.header(GLOBAL_HEADER)
211217
.serializers(builder -> builder
212-
.register(new PacketClassSerializer())
218+
.register(new ServerboundPacketClassSerializer())
213219
.register(new RegistryValueSerializer<>(new TypeToken<DataComponentType<?>>() {}, registryAccess, Registries.DATA_COMPONENT_TYPE, false))
214220
);
215221
}
@@ -232,7 +238,7 @@ protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(fin
232238
return super.createWorldObjectMapperFactoryBuilder(contextMap)
233239
.addNodeResolver(new RequiresSpigotInitialization.Factory(contextMap.require(SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get()))
234240
.addNodeResolver(new NestedSetting.Factory())
235-
.addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap)));
241+
.addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap), defaultFieldProcessors()));
236242
}
237243

238244
private static WorldConfiguration createWorldConfigInstance(ContextMap contextMap) {
@@ -291,6 +297,7 @@ protected void applyGlobalConfigTransformations(ConfigurationNode node) throws C
291297

292298
final ConfigurationTransformation.VersionedBuilder versionedBuilder = Transformations.versionedBuilder();
293299
V29_LogIPs.apply(versionedBuilder);
300+
V30_PacketIds.apply(versionedBuilder);
294301
// ADD FUTURE VERSIONED TRANSFORMS TO versionedBuilder HERE
295302
versionedBuilder.build().apply(node);
296303
}
@@ -334,6 +341,12 @@ public void reloadConfigs(MinecraftServer server) {
334341
}
335342
}
336343

344+
private static List<Definition<? extends Annotation, ?, ? extends FieldProcessor.Factory<?, ?>>> defaultFieldProcessors() {
345+
return List.of(
346+
MergeMap.DEFINITION
347+
);
348+
}
349+
337350
private static ContextMap createWorldContextMap(ServerLevel level) {
338351
return createWorldContextMap(level.levelStorageAccess.levelDirectory.path(), level.serverLevelData.getLevelName(), level.dimension().location(), level.spigotConfig, level.registryAccess(), level.getGameRules());
339352
}

paper-server/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
99
import io.papermc.paper.configuration.mapping.MergeMap;
1010
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
11-
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
11+
import io.papermc.paper.configuration.serializer.collection.map.ThrowExceptions;
1212
import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
1313
import io.papermc.paper.configuration.type.BooleanOrDefault;
1414
import io.papermc.paper.configuration.type.DespawnRange;
@@ -193,15 +193,14 @@ public static DespawnRangePair createDefault() {
193193
}
194194
}
195195

196-
@MapSerializer.ThrowExceptions
197-
public Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
196+
public @ThrowExceptions Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
198197
map.put(EntityType.SNOWBALL, IntOr.Disabled.DISABLED);
199198
map.put(EntityType.LLAMA_SPIT, IntOr.Disabled.DISABLED);
200199
});
201200

202201
@PostProcess
203202
public void precomputeDespawnDistances() throws SerializationException {
204-
for (Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
203+
for (final Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
205204
final MobCategory category = entry.getKey();
206205
final DespawnRangePair range = entry.getValue();
207206
range.hard().preComputed(category.getDespawnDistance(), category.getSerializedName());
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.papermc.paper.configuration.mapping;
2+
3+
import io.leangen.geantyref.TypeToken;
4+
import java.lang.annotation.Annotation;
5+
6+
public record Definition<A extends Annotation, T, F>(Class<A> annotation, TypeToken<T> type, F factory) {
7+
8+
public Definition(final Class<A> annotation, final Class<T> type, final F factory) {
9+
this(annotation, TypeToken.get(type), factory);
10+
}
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.papermc.paper.configuration.mapping;
2+
3+
import java.lang.reflect.AnnotatedType;
4+
import org.jspecify.annotations.Nullable;
5+
import org.spongepowered.configurate.serialize.SerializationException;
6+
7+
import static com.google.common.base.Preconditions.checkState;
8+
9+
public record DeserializedFieldInfo<V>(AnnotatedType fieldType, Object deserializedValue, @Nullable FieldProcessor<V> processor) {
10+
11+
@SuppressWarnings("unchecked")
12+
public @Nullable V runProcessor(final @Nullable Object valueInField, final @Nullable Object deserializedValue) throws SerializationException {
13+
checkState(this.processor != null, "processor is null");
14+
return this.processor.process(this.fieldType, (V) deserializedValue, (V) valueInField);
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.papermc.paper.configuration.mapping;
2+
3+
import java.lang.annotation.Annotation;
4+
import java.lang.reflect.AnnotatedType;
5+
import org.jspecify.annotations.Nullable;
6+
import org.spongepowered.configurate.serialize.SerializationException;
7+
8+
public interface FieldProcessor<V> {
9+
10+
@Nullable V process(final AnnotatedType target, @Nullable V deserializedValue, @Nullable V valueInField) throws SerializationException;
11+
12+
interface Factory<A extends Annotation, T> {
13+
14+
FieldProcessor<T> make(A data, AnnotatedType annotatedType);
15+
}
16+
}
Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,103 @@
11
package io.papermc.paper.configuration.mapping;
22

3+
import io.leangen.geantyref.GenericTypeReflector;
34
import io.papermc.paper.configuration.ConfigurationPart;
45
import io.papermc.paper.configuration.WorldConfiguration;
6+
import java.lang.annotation.Annotation;
57
import java.lang.reflect.AnnotatedType;
68
import java.lang.reflect.Field;
9+
import java.util.ArrayList;
710
import java.util.Collections;
11+
import java.util.LinkedHashMap;
12+
import java.util.List;
813
import java.util.Map;
14+
import java.util.SequencedMap;
15+
import java.util.function.Supplier;
916
import org.jspecify.annotations.Nullable;
1017
import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
1118
import org.spongepowered.configurate.serialize.SerializationException;
1219

1320
import static io.leangen.geantyref.GenericTypeReflector.erase;
21+
import static java.util.Objects.requireNonNullElseGet;
1422

15-
public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, Object>> {
23+
public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, DeserializedFieldInfo<?>>> {
1624

1725
private final InnerClassInstanceSupplier instanceSupplier;
1826
private final FieldDiscoverer<Map<Field, Object>> delegate;
27+
private final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors;
1928

20-
@SuppressWarnings("unchecked")
21-
public InnerClassFieldDiscoverer(final Map<Class<?>, Object> initialOverrides) {
22-
this.instanceSupplier = new InnerClassInstanceSupplier(initialOverrides);
23-
this.delegate = (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(this.instanceSupplier);
29+
private InnerClassFieldDiscoverer(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer<Map<Field, Object>> delegate, final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors) {
30+
this.instanceSupplier = instanceSupplier;
31+
this.delegate = delegate;
32+
this.fieldProcessors = fieldProcessors;
2433
}
2534

35+
@SuppressWarnings({"unchecked", "rawtypes"})
2636
@Override
27-
public @Nullable <V> InstanceFactory<Map<Field, Object>> discover(final AnnotatedType target, final FieldCollector<Map<Field, Object>, V> collector) throws SerializationException {
37+
public @Nullable <V> InstanceFactory<Map<Field, DeserializedFieldInfo<?>>> discover(final AnnotatedType target, final FieldCollector<Map<Field, DeserializedFieldInfo<?>>, V> collector) throws SerializationException {
2838
final Class<?> clazz = erase(target.getType());
2939
if (ConfigurationPart.class.isAssignableFrom(clazz)) {
30-
final FieldDiscoverer.@Nullable InstanceFactory<Map<Field, Object>> instanceFactoryDelegate = this.delegate.<V>discover(target, (name, type, annotations, deserializer, serializer) -> {
31-
if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
32-
collector.accept(name, type, annotations, deserializer, serializer);
40+
// we don't care about the returned instance factory, we just need to call it to collect fields
41+
final Object dummyInstance = this.delegate.<V>discover(target, (name, fieldType, container, deserializer, serializer) -> {
42+
if (!erase(fieldType.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
43+
FieldProcessor<?> processor = null;
44+
processor: for (final Annotation annotation : container.getAnnotations()) {
45+
final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> definitions = this.fieldProcessors.get(annotation.annotationType());
46+
if (definitions != null) {
47+
for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> def : definitions) {
48+
if (GenericTypeReflector.isSuperType(def.type().getType(), GenericTypeReflector.box(fieldType.getType()))) {
49+
processor = ((FieldProcessor.Factory)def.factory()).make(annotation, fieldType);
50+
break processor;
51+
}
52+
}
53+
}
54+
}
55+
final FieldProcessor<?> finalProcessor = processor;
56+
collector.accept(
57+
name,
58+
fieldType,
59+
container,
60+
(intermediate, newValue, implicitInitializer) -> {
61+
// we only create this map to collect the field, it should only ever have 1 entry
62+
final SequencedMap<Field, Object> map = new LinkedHashMap<>();
63+
deserializer.accept(map, newValue, implicitInitializer);
64+
final Object deserializedValue;
65+
deserializedValue = requireNonNullElseGet(newValue, () -> new ImplicitProvider(implicitInitializer));
66+
intermediate.put(map.firstEntry().getKey(), new DeserializedFieldInfo<>(fieldType, deserializedValue, finalProcessor));
67+
},
68+
serializer
69+
);
3370
}
3471
});
35-
if (instanceFactoryDelegate instanceof MutableInstanceFactory<Map<Field, Object>> mutableInstanceFactoryDelegate) {
36-
return new InnerClassInstanceFactory(this.instanceSupplier, mutableInstanceFactoryDelegate, target);
72+
if (dummyInstance == null) {
73+
return null;
3774
}
75+
return new InnerClassInstanceFactory(this.instanceSupplier, target);
3876
}
3977
return null;
4078
}
4179

42-
public static FieldDiscoverer<?> worldConfig(WorldConfiguration worldConfiguration) {
80+
record ImplicitProvider(Supplier<Object> provider) {
81+
}
82+
83+
@SuppressWarnings("unchecked")
84+
private static InnerClassFieldDiscoverer create(final Map<Class<?>, Object> overrides, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
85+
final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> processors = new LinkedHashMap<>();
86+
for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> definition : fieldProcessors) {
87+
processors.computeIfAbsent(definition.annotation(), k -> new ArrayList<>()).add(definition);
88+
}
89+
final InnerClassInstanceSupplier instanceSupplier = new InnerClassInstanceSupplier(overrides);
90+
return new InnerClassFieldDiscoverer(instanceSupplier, (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(instanceSupplier), processors);
91+
}
92+
93+
public static FieldDiscoverer<?> worldConfig(final WorldConfiguration worldConfiguration, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
4394
final Map<Class<?>, Object> overrides = Map.of(
4495
WorldConfiguration.class, worldConfiguration
4596
);
46-
return new InnerClassFieldDiscoverer(overrides);
97+
return create(overrides, fieldProcessors);
4798
}
4899

49-
public static FieldDiscoverer<?> globalConfig() {
50-
return new InnerClassFieldDiscoverer(Collections.emptyMap());
100+
public static FieldDiscoverer<?> globalConfig(final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
101+
return create(Collections.emptyMap(), fieldProcessors);
51102
}
52103
}

0 commit comments

Comments
 (0)