Configurable Entity Despawn Time (#11454)

* Configurable Entity Despawn Time

Co-authored-by: Kevin Raneri <kevin.raneri@gmail.com>

* Rebase

* Rebase

* rebase

* throw exceptions for this map

---------

Co-authored-by: Kevin Raneri <kevin.raneri@gmail.com>
This commit is contained in:
Jake Potrebic 2024-11-23 13:27:37 -08:00
parent e598ee5d08
commit 564005cc5f
3 changed files with 335 additions and 146 deletions

View File

@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Raneri <kevin.raneri@gmail.com>
Date: Mon, 30 Sep 2024 09:50:55 -0700
Subject: [PATCH] Configurable Entity Despawn Time
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
private UUID originWorld;
public boolean freezeLocked = false; // Paper - Freeze Tick Lock API
public boolean fixedPose = false; // Paper - Expand Pose API
+ private final int despawnTime; // Paper - entity despawn time limit
public void setOrigin(@javax.annotation.Nonnull Location location) {
this.origin = location.toVector();
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public Entity(EntityType<?> type, Level world) {
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
+ this.despawnTime = type == EntityType.PLAYER ? -1 : world.paperConfig().entities.spawning.despawnTime.getOrDefault(type, io.papermc.paper.configuration.type.number.IntOr.Disabled.DISABLED).or(-1); // Paper - entity despawn time limit
this.passengers = ImmutableList.of();
this.deltaMovement = Vec3.ZERO;
this.bb = Entity.INITIAL_AABB;
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public void tick() {
+ // Paper start - entity despawn time limit
+ if (this.despawnTime >= 0 && this.tickCount >= this.despawnTime) {
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ return;
+ }
+ // Paper end - entity despawn time limit
this.baseTick();
}

View File

@ -132,23 +132,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.leangen.geantyref.TypeToken; +import io.leangen.geantyref.TypeToken;
+import io.papermc.paper.configuration.constraint.Constraint; +import io.papermc.paper.configuration.constraint.Constraint;
+import io.papermc.paper.configuration.constraint.Constraints; +import io.papermc.paper.configuration.constraint.Constraints;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.GameRules;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jetbrains.annotations.MustBeInvokedByOverriders;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.CommentedConfigurationNode;
+import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.ConfigurationOptions;
+import org.spongepowered.configurate.NodePath;
+import org.spongepowered.configurate.objectmapping.ObjectMapper;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.util.CheckedFunction;
+import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
+
+import java.io.IOException; +import java.io.IOException;
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.nio.file.AccessDeniedException; +import java.nio.file.AccessDeniedException;
@ -159,6 +142,21 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.util.NoSuchElementException; +import java.util.NoSuchElementException;
+import java.util.Objects; +import java.util.Objects;
+import java.util.function.UnaryOperator; +import java.util.function.UnaryOperator;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.GameRules;
+import org.jetbrains.annotations.MustBeInvokedByOverriders;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.CommentedConfigurationNode;
+import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.ConfigurationOptions;
+import org.spongepowered.configurate.objectmapping.ObjectMapper;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.util.CheckedFunction;
+import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
+ +
+public abstract class Configurations<G, W> { +public abstract class Configurations<G, W> {
+ +
@ -501,7 +499,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.NamedTextColor;
+import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.Packet;
+import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket; +import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger; +import org.slf4j.Logger;
+import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.ConfigSerializable;
+import org.spongepowered.configurate.objectmapping.meta.Comment; +import org.spongepowered.configurate.objectmapping.meta.Comment;
@ -829,15 +827,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.configuration; +package io.papermc.paper.configuration;
+ +
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.objectmapping.meta.NodeResolver;
+
+import java.lang.annotation.Documented; +import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType; +import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention; +import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target; +import java.lang.annotation.Target;
+import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.AnnotatedElement;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.objectmapping.meta.NodeResolver;
+ +
+@Documented +@Documented
+@Retention(RetentionPolicy.RUNTIME) +@Retention(RetentionPolicy.RUNTIME)
@ -903,6 +900,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2LongMap; +import it.unimi.dsi.fastutil.objects.Reference2LongMap;
+import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
+import java.io.File; +import java.io.File;
+import java.io.IOException; +import java.io.IOException;
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
@ -925,8 +924,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomStringUtils;
+import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.YamlConfiguration;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jetbrains.annotations.VisibleForTesting; +import org.jetbrains.annotations.VisibleForTesting;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger; +import org.slf4j.Logger;
+import org.spigotmc.SpigotConfig; +import org.spigotmc.SpigotConfig;
+import org.spigotmc.SpigotWorldConfig; +import org.spigotmc.SpigotWorldConfig;
@ -1108,6 +1107,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ .serializers(serializers -> serializers + .serializers(serializers -> serializers
+ .register(new TypeToken<Reference2IntMap<?>>() {}, new FastutilMapSerializer.SomethingToPrimitive<Reference2IntMap<?>>(Reference2IntOpenHashMap::new, Integer.TYPE)) + .register(new TypeToken<Reference2IntMap<?>>() {}, new FastutilMapSerializer.SomethingToPrimitive<Reference2IntMap<?>>(Reference2IntOpenHashMap::new, Integer.TYPE))
+ .register(new TypeToken<Reference2LongMap<?>>() {}, new FastutilMapSerializer.SomethingToPrimitive<Reference2LongMap<?>>(Reference2LongOpenHashMap::new, Long.TYPE)) + .register(new TypeToken<Reference2LongMap<?>>() {}, new FastutilMapSerializer.SomethingToPrimitive<Reference2LongMap<?>>(Reference2LongOpenHashMap::new, Long.TYPE))
+ .register(new TypeToken<Reference2ObjectMap<?, ?>>() {}, new FastutilMapSerializer.SomethingToSomething<Reference2ObjectMap<?, ?>>(Reference2ObjectOpenHashMap::new))
+ .register(new TypeToken<Table<?, ?, ?>>() {}, new TableSerializer()) + .register(new TypeToken<Table<?, ?, ?>>() {}, new TableSerializer())
+ .register(DespawnRange.class, DespawnRange.SERIALIZER) + .register(DespawnRange.class, DespawnRange.SERIALIZER)
+ .register(StringRepresentableSerializer::isValidFor, new StringRepresentableSerializer()) + .register(StringRepresentableSerializer::isValidFor, new StringRepresentableSerializer())
@ -1436,6 +1436,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; +import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
+import io.papermc.paper.configuration.mapping.MergeMap; +import io.papermc.paper.configuration.mapping.MergeMap;
+import io.papermc.paper.configuration.serializer.NbtPathSerializer; +import io.papermc.paper.configuration.serializer.NbtPathSerializer;
+import io.papermc.paper.configuration.serializer.collections.MapSerializer;
+import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration; +import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
+import io.papermc.paper.configuration.type.BooleanOrDefault; +import io.papermc.paper.configuration.type.BooleanOrDefault;
+import io.papermc.paper.configuration.type.DespawnRange; +import io.papermc.paper.configuration.type.DespawnRange;
@ -1451,6 +1452,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2LongMap; +import it.unimi.dsi.fastutil.objects.Reference2LongMap;
+import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap; +import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
+import java.util.Arrays; +import java.util.Arrays;
+import java.util.IdentityHashMap; +import java.util.IdentityHashMap;
+import java.util.List; +import java.util.List;
@ -1628,6 +1631,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ } + }
+ +
+ @MapSerializer.ThrowExceptions
+ public Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
+ map.put(EntityType.SNOWBALL, IntOr.Disabled.DISABLED);
+ map.put(EntityType.LLAMA_SPIT, IntOr.Disabled.DISABLED);
+ });
+
+ @PostProcess + @PostProcess
+ public void precomputeDespawnDistances() throws SerializationException { + public void precomputeDespawnDistances() throws SerializationException {
+ for (Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) { + for (Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
@ -2058,7 +2067,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target; +import java.lang.annotation.Target;
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.objectmapping.meta.Constraint; +import org.spongepowered.configurate.objectmapping.meta.Constraint;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+ +
@ -2101,7 +2110,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.configuration.legacy; +package io.papermc.paper.configuration.legacy;
+ +
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spigotmc.SpigotWorldConfig; +import org.spigotmc.SpigotWorldConfig;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.objectmapping.meta.NodeResolver; +import org.spongepowered.configurate.objectmapping.meta.NodeResolver;
@ -2138,10 +2147,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import com.google.common.collect.HashBasedTable; +import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table; +import com.google.common.collect.Table;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spigotmc.SpigotWorldConfig;
+import org.spongepowered.configurate.objectmapping.meta.NodeResolver;
+
+import java.lang.annotation.Documented; +import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType; +import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention; +import java.lang.annotation.Retention;
@ -2149,8 +2154,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.lang.annotation.Target; +import java.lang.annotation.Target;
+import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor; +import java.lang.reflect.Constructor;
+import java.util.Map; +import org.jspecify.annotations.Nullable;
+import java.util.concurrent.ConcurrentHashMap; +import org.spigotmc.SpigotWorldConfig;
+import org.spongepowered.configurate.objectmapping.meta.NodeResolver;
+ +
+@Documented +@Documented
+@Retention(RetentionPolicy.RUNTIME) +@Retention(RetentionPolicy.RUNTIME)
@ -2227,14 +2233,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.configuration.mapping; +package io.papermc.paper.configuration.mapping;
+ +
+import io.papermc.paper.configuration.ConfigurationPart; +import io.papermc.paper.configuration.ConfigurationPart;
+import io.papermc.paper.configuration.Configurations;
+import io.papermc.paper.configuration.PaperConfigurations;
+import io.papermc.paper.configuration.WorldConfiguration; +import io.papermc.paper.configuration.WorldConfiguration;
+import java.lang.reflect.AnnotatedType; +import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Field; +import java.lang.reflect.Field;
+import java.util.Collections; +import java.util.Collections;
+import java.util.Map; +import java.util.Map;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.objectmapping.FieldDiscoverer; +import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+ +
@ -2291,7 +2295,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.util.Iterator; +import java.util.Iterator;
+import java.util.Map; +import java.util.Map;
+import java.util.Objects; +import java.util.Objects;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.objectmapping.FieldDiscoverer; +import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+ +
@ -2323,7 +2326,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ Map.Entry<Field, Object> entry = iter.next(); + Map.Entry<Field, Object> entry = iter.next();
+ if (entry.getKey().isAnnotationPresent(MergeMap.class) && Map.class.isAssignableFrom(entry.getKey().getType()) && intermediate.get(entry.getKey()) instanceof Map<?, ?> map) { + if (entry.getKey().isAnnotationPresent(MergeMap.class) && Map.class.isAssignableFrom(entry.getKey().getType()) && intermediate.get(entry.getKey()) instanceof Map<?, ?> map) {
+ iter.remove(); + iter.remove();
+ @Nullable Map<Object, Object> existingMap = (Map<Object, Object>) entry.getKey().get(instance); + Map<Object, Object> existingMap = (Map<Object, Object>) entry.getKey().get(instance);
+ if (existingMap != null) { + if (existingMap != null) {
+ existingMap.putAll(map); + existingMap.putAll(map);
+ } else { + } else {
@ -2364,7 +2367,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.util.HashMap; +import java.util.HashMap;
+import java.util.Map; +import java.util.Map;
+import java.util.function.Supplier; +import java.util.function.Supplier;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.util.CheckedFunction; +import org.spongepowered.configurate.util.CheckedFunction;
+import org.spongepowered.configurate.util.CheckedSupplier; +import org.spongepowered.configurate.util.CheckedSupplier;
@ -2400,7 +2403,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final Constructor<?> constructor; + final Constructor<?> constructor;
+ final CheckedSupplier<Object, ReflectiveOperationException> instanceSupplier; + final CheckedSupplier<Object, ReflectiveOperationException> instanceSupplier;
+ if (type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers())) { + if (type.getEnclosingClass() != null && !Modifier.isStatic(type.getModifiers())) {
+ final @Nullable Object instance = this.instanceMap.get(type.getEnclosingClass()); + final Object instance = this.instanceMap.get(type.getEnclosingClass());
+ if (instance == null) { + if (instance == null) {
+ throw new SerializationException("Cannot create a new instance of an inner class " + type.getName() + " without an instance of its enclosing class " + type.getEnclosingClass().getName()); + throw new SerializationException("Cannot create a new instance of an inner class " + type.getName() + " without an instance of its enclosing class " + type.getEnclosingClass().getName());
+ } + }
@ -2453,18 +2456,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+@Retention(RetentionPolicy.RUNTIME) +@Retention(RetentionPolicy.RUNTIME)
+public @interface MergeMap { +public @interface MergeMap {
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/mapping/package-info.java b/src/main/java/io/papermc/paper/configuration/mapping/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/mapping/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.mapping;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/package-info.java b/src/main/java/io/papermc/paper/configuration/package-info.java diff --git a/src/main/java/io/papermc/paper/configuration/package-info.java b/src/main/java/io/papermc/paper/configuration/package-info.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null --- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/package-info.java +++ b/src/main/java/io/papermc/paper/configuration/package-info.java
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+@DefaultQualifier(NonNull.class) +@NullMarked
+package io.papermc.paper.configuration; +package io.papermc.paper.configuration;
+ +
+import org.checkerframework.checker.nullness.qual.NonNull; +import org.jspecify.annotations.NullMarked;
+import org.checkerframework.framework.qual.DefaultQualifier;
\ No newline at end of file
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java diff --git a/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/ComponentSerializer.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -2546,16 +2557,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import com.mojang.logging.LogUtils; +import com.mojang.logging.LogUtils;
+import io.leangen.geantyref.TypeToken; +import io.leangen.geantyref.TypeToken;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.util.EnumLookup;
+
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.Arrays; +import java.util.Arrays;
+import java.util.List; +import java.util.List;
+import java.util.function.Predicate; +import java.util.function.Predicate;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.util.EnumLookup;
+ +
+import static io.leangen.geantyref.GenericTypeReflector.erase; +import static io.leangen.geantyref.GenericTypeReflector.erase;
+ +
@ -2575,14 +2585,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public @Nullable Enum<?> deserialize(final Type type, final Object obj) throws SerializationException { + public @Nullable Enum<?> deserialize(final Type type, final Object obj) throws SerializationException {
+ final String enumConstant = obj.toString(); + final String enumConstant = obj.toString();
+ final Class<? extends Enum> typeClass = erase(type).asSubclass(Enum.class); + final Class<? extends Enum> typeClass = erase(type).asSubclass(Enum.class);
+ @Nullable Enum<?> ret = EnumLookup.lookupEnum(typeClass, enumConstant); + Enum<?> ret = EnumLookup.lookupEnum(typeClass, enumConstant);
+ if (ret == null) { + if (ret == null) {
+ ret = EnumLookup.lookupEnum(typeClass, enumConstant.replace("-", "_")); + ret = EnumLookup.lookupEnum(typeClass, enumConstant.replace("-", "_"));
+ } + }
+ if (ret == null) { + if (ret == null) {
+ boolean longer = typeClass.getEnumConstants().length > 10; + boolean longer = typeClass.getEnumConstants().length > 10;
+ List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList(); + List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList();
+ LOGGER.error("Invalid enum constant provided, expected one of [" + String.join(", " ,options) + (longer ? ", ..." : "") + "], but got " + enumConstant); + LOGGER.error("Invalid enum constant provided, expected one of [{}{}], but got {}", String.join(", ", options), longer ? ", ..." : "", enumConstant);
+ } + }
+ return ret; + return ret;
+ } + }
@ -2664,16 +2674,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import io.leangen.geantyref.TypeToken; +import io.leangen.geantyref.TypeToken;
+import io.papermc.paper.configuration.serializer.collections.MapSerializer; +import io.papermc.paper.configuration.serializer.collections.MapSerializer;
+import io.papermc.paper.util.ObfHelper; +import io.papermc.paper.util.ObfHelper;
+import net.minecraft.network.protocol.Packet;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.List; +import java.util.List;
+import java.util.Map; +import java.util.Map;
+import java.util.function.Predicate; +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") +@SuppressWarnings("Convert2Diamond")
+public final class PacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> implements MapSerializer.WriteBack { +public final class PacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> implements MapSerializer.WriteBack {
@ -2703,14 +2712,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ @SuppressWarnings("unchecked") + @SuppressWarnings("unchecked")
+ @Override + @Override
+ public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException { + public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException {
+ @Nullable Class<?> packetClass = null; + Class<?> packetClass = null;
+ for (final String subpackage : SUBPACKAGES) { + for (final String subpackage : SUBPACKAGES) {
+ final String fullClassName = "net.minecraft.network.protocol." + subpackage + "." + obj; + final String fullClassName = "net.minecraft.network.protocol." + subpackage + "." + obj;
+ try { + try {
+ packetClass = Class.forName(fullClassName); + packetClass = Class.forName(fullClassName);
+ break; + break;
+ } catch (final ClassNotFoundException ex) { + } catch (final ClassNotFoundException ex) {
+ final @Nullable String spigotClassName = MOJANG_TO_OBF.get(fullClassName); + final String spigotClassName = MOJANG_TO_OBF.get(fullClassName);
+ if (spigotClassName != null) { + if (spigotClassName != null) {
+ try { + try {
+ packetClass = Class.forName(spigotClassName); + packetClass = Class.forName(spigotClassName);
@ -2750,17 +2759,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.configuration.serializer; +package io.papermc.paper.configuration.serializer;
+ +
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.MobCategory;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.Collections; +import java.util.Collections;
+import java.util.Map; +import java.util.Map;
+import java.util.function.Function; +import java.util.function.Function;
+import java.util.function.Predicate; +import java.util.function.Predicate;
+import net.minecraft.util.StringRepresentable;
+import net.minecraft.world.entity.MobCategory;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+ +
+public final class StringRepresentableSerializer extends ScalarSerializer<StringRepresentable> { +public final class StringRepresentableSerializer extends ScalarSerializer<StringRepresentable> {
+ private static final Map<Type, Function<String, StringRepresentable>> TYPES = Collections.synchronizedMap(Map.ofEntries( + private static final Map<Type, Function<String, StringRepresentable>> TYPES = Collections.synchronizedMap(Map.ofEntries(
@ -2810,44 +2818,53 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import io.leangen.geantyref.GenericTypeReflector; +import io.leangen.geantyref.GenericTypeReflector;
+import io.leangen.geantyref.TypeFactory; +import io.leangen.geantyref.TypeFactory;
+import org.checkerframework.checker.nullness.qual.Nullable; +import java.lang.annotation.Annotation;
+import org.spongepowered.configurate.ConfigurationNode; +import java.lang.reflect.AnnotatedParameterizedType;
+import org.spongepowered.configurate.serialize.SerializationException; +import java.lang.reflect.AnnotatedType;
+import org.spongepowered.configurate.serialize.TypeSerializer;
+
+import java.lang.reflect.ParameterizedType; +import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.Collections; +import java.util.Collections;
+import java.util.Map; +import java.util.Map;
+import java.util.function.Function; +import java.util.function.Function;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.serialize.TypeSerializer;
+ +
+@SuppressWarnings("rawtypes") +@SuppressWarnings("rawtypes")
+public abstract class FastutilMapSerializer<M extends Map<?, ?>> implements TypeSerializer<M> { +public abstract class FastutilMapSerializer<M extends Map<?, ?>> implements TypeSerializer.Annotated<M> {
+ private final Function<Map, ? extends M> factory;
+ +
+ protected FastutilMapSerializer(final Function<Map, ? extends M> factory) { + private final Function<? super Map, ? extends M> factory;
+
+ protected FastutilMapSerializer(final Function<? super Map, ? extends M> factory) {
+ this.factory = factory; + this.factory = factory;
+ } + }
+ +
+ @Override + @Override
+ public M deserialize(final Type type, final ConfigurationNode node) throws SerializationException { + public M deserialize(final AnnotatedType annotatedType, final ConfigurationNode node) throws SerializationException {
+ @Nullable final Map map = (Map) node.get(this.createBaseMapType((ParameterizedType) type)); + final Map map = (Map) node.get(this.createAnnotatedMapType((AnnotatedParameterizedType) annotatedType));
+ return this.factory.apply(map == null ? Collections.emptyMap() : map); + return this.factory.apply(map == null ? Collections.emptyMap() : map);
+ } + }
+ +
+ @Override + @Override
+ public void serialize(final Type type, @Nullable final M obj, final ConfigurationNode node) throws SerializationException { + public void serialize(final AnnotatedType annotatedType, final @Nullable M obj, final ConfigurationNode node) throws SerializationException {
+ if (obj == null || obj.isEmpty()) { + if (obj == null || obj.isEmpty()) {
+ node.raw(null); + node.raw(null);
+ } else { + } else {
+ final Type baseMapType = this.createBaseMapType((ParameterizedType) type); + final AnnotatedType baseMapType = this.createAnnotatedMapType((AnnotatedParameterizedType) annotatedType);
+ node.set(baseMapType, obj); + node.set(baseMapType, obj);
+ } + }
+ } + }
+ +
+ private AnnotatedType createAnnotatedMapType(final AnnotatedParameterizedType type) {
+ final Type baseType = this.createBaseMapType((ParameterizedType) type.getType());
+ return GenericTypeReflector.annotate(baseType, type.getAnnotations());
+ }
+
+ protected abstract Type createBaseMapType(final ParameterizedType type); + protected abstract Type createBaseMapType(final ParameterizedType type);
+ +
+ public static final class SomethingToPrimitive<M extends Map<?, ?>> extends FastutilMapSerializer<M> { + public static final class SomethingToPrimitive<M extends Map<?, ?>> extends FastutilMapSerializer<M> {
+
+ private final Type primitiveType; + private final Type primitiveType;
+ +
+ public SomethingToPrimitive(final Function<Map, ? extends M> factory, final Type primitiveType) { + public SomethingToPrimitive(final Function<Map, ? extends M> factory, final Type primitiveType) {
@ -2862,6 +2879,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ public static final class PrimitiveToSomething<M extends Map<?, ?>> extends FastutilMapSerializer<M> { + public static final class PrimitiveToSomething<M extends Map<?, ?>> extends FastutilMapSerializer<M> {
+
+ private final Type primitiveType; + private final Type primitiveType;
+ +
+ public PrimitiveToSomething(final Function<Map, ? extends M> factory, final Type primitiveType) { + public PrimitiveToSomething(final Function<Map, ? extends M> factory, final Type primitiveType) {
@ -2874,6 +2892,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return TypeFactory.parameterizedClass(Map.class, GenericTypeReflector.box(this.primitiveType), type.getActualTypeArguments()[0]); + return TypeFactory.parameterizedClass(Map.class, GenericTypeReflector.box(this.primitiveType), type.getActualTypeArguments()[0]);
+ } + }
+ } + }
+
+ public static final class SomethingToSomething<M extends Map<?, ?>> extends FastutilMapSerializer<M> {
+
+ public SomethingToSomething(final Function<? super Map, ? extends M> factory) {
+ super(factory);
+ }
+
+ @Override
+ protected Type createBaseMapType(final ParameterizedType type) {
+ return TypeFactory.parameterizedClass(Map.class, type.getActualTypeArguments()[0], type.getActualTypeArguments()[1]);
+ }
+ }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java
new file mode 100644 new file mode 100644
@ -2885,15 +2915,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import com.mojang.logging.LogUtils; +import com.mojang.logging.LogUtils;
+import io.leangen.geantyref.TypeToken; +import io.leangen.geantyref.TypeToken;
+import org.checkerframework.checker.nullness.qual.Nullable; +import java.lang.annotation.Retention;
+import org.slf4j.Logger; +import java.lang.annotation.RetentionPolicy;
+import org.spongepowered.configurate.BasicConfigurationNode; +import java.lang.reflect.AnnotatedType;
+import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.ConfigurationOptions;
+import org.spongepowered.configurate.NodePath;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.serialize.TypeSerializer;
+
+import java.lang.reflect.ParameterizedType; +import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.Collections; +import java.util.Collections;
@ -2901,27 +2925,45 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.util.LinkedHashMap; +import java.util.LinkedHashMap;
+import java.util.Map; +import java.util.Map;
+import java.util.Set; +import java.util.Set;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.spongepowered.configurate.BasicConfigurationNode;
+import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.ConfigurationOptions;
+import org.spongepowered.configurate.NodePath;
+import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.serialize.TypeSerializer;
+import org.spongepowered.configurate.serialize.TypeSerializerCollection;
+ +
+import static java.util.Objects.requireNonNull; +import static java.util.Objects.requireNonNull;
+ +
+/** +/**
+ * Map serializer that does not throw errors on individual entry serialization failures. + * Map serializer that does not throw errors on individual entry serialization failures.
+ */ + */
+public class MapSerializer implements TypeSerializer<Map<?, ?>> { +public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
+ +
+ public static final TypeToken<Map<?, ?>> TYPE = new TypeToken<Map<?, ?>>() {}; + public static final TypeToken<Map<?, ?>> TYPE = new TypeToken<Map<?, ?>>() {};
+ +
+ private static final Logger LOGGER = LogUtils.getClassLogger(); + private static final Logger LOGGER = LogUtils.getClassLogger();
+ +
+ private final boolean clearInvalids; + private final boolean clearInvalids;
+ private final TypeSerializer<Map<?, ?>> fallback;
+ +
+ public MapSerializer(boolean clearInvalids) { + public MapSerializer(boolean clearInvalids) {
+ this.clearInvalids = clearInvalids; + this.clearInvalids = clearInvalids;
+ this.fallback = requireNonNull(TypeSerializerCollection.defaults().get(TYPE), "Could not find default Map<?, ?> serializer");
+ } + }
+ +
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface ThrowExceptions {}
+
+ @Override + @Override
+ public Map<?, ?> deserialize(Type type, ConfigurationNode node) throws SerializationException { + public Map<?, ?> deserialize(AnnotatedType annotatedType, ConfigurationNode node) throws SerializationException {
+ if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
+ return this.fallback.deserialize(annotatedType, node);
+ }
+ final Map<Object, Object> map = new LinkedHashMap<>(); + final Map<Object, Object> map = new LinkedHashMap<>();
+ final Type type = annotatedType.getType();
+ if (node.isMap()) { + if (node.isMap()) {
+ if (!(type instanceof ParameterizedType parameterizedType)) { + if (!(type instanceof ParameterizedType parameterizedType)) {
+ throw new SerializationException(type, "Raw types are not supported for collections"); + throw new SerializationException(type, "Raw types are not supported for collections");
@ -2975,7 +3017,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ @Override + @Override
+ public void serialize(Type type, @Nullable Map<?, ?> obj, ConfigurationNode node) throws SerializationException { + public void serialize(AnnotatedType annotatedType, @Nullable Map<?, ?> obj, ConfigurationNode node) throws SerializationException {
+ if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
+ this.fallback.serialize(annotatedType, obj, node);
+ return;
+ }
+ final Type type = annotatedType.getType();
+ if (!(type instanceof ParameterizedType parameterizedType)) { + if (!(type instanceof ParameterizedType parameterizedType)) {
+ throw new SerializationException(type, "Raw types are not supported for collections"); + throw new SerializationException(type, "Raw types are not supported for collections");
+ } + }
@ -3036,7 +3083,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ @Override + @Override
+ public @Nullable Map<?, ?> emptyValue(Type specificType, ConfigurationOptions options) { + public @Nullable Map<?, ?> emptyValue(AnnotatedType specificType, ConfigurationOptions options) {
+ if (specificType.isAnnotationPresent(ThrowExceptions.class)) {
+ return this.fallback.emptyValue(specificType, options);
+ }
+ return new LinkedHashMap<>(); + return new LinkedHashMap<>();
+ } + }
+ +
@ -3055,18 +3105,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import com.google.common.collect.ImmutableTable; +import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Table; +import com.google.common.collect.Table;
+import io.leangen.geantyref.TypeFactory; +import io.leangen.geantyref.TypeFactory;
+import org.checkerframework.checker.nullness.qual.Nullable; +import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Map;
+import java.util.Objects;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.BasicConfigurationNode; +import org.spongepowered.configurate.BasicConfigurationNode;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.ConfigurationOptions;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.serialize.TypeSerializer; +import org.spongepowered.configurate.serialize.TypeSerializer;
+ +
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Map;
+import java.util.Objects;
+
+public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> { +public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
+ private static final int ROW_TYPE_ARGUMENT_INDEX = 0; + private static final int ROW_TYPE_ARGUMENT_INDEX = 0;
+ private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1; + private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1;
@ -3087,13 +3136,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; + final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
+ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; + final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
+ +
+ final @Nullable TypeSerializer<R> rowKeySerializer = (TypeSerializer<R>) node.options().serializers().get(rowType); + final TypeSerializer<R> rowKeySerializer = (TypeSerializer<R>) node.options().serializers().get(rowType);
+ if (rowKeySerializer == null) { + if (rowKeySerializer == null) {
+ throw new SerializationException("Could not find serializer for table row type " + rowType); + throw new SerializationException("Could not find serializer for table row type " + rowType);
+ } + }
+ +
+ final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType); + final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType);
+ final @Nullable TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(mapType); + final TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(mapType);
+ if (columnValueSerializer == null) { + if (columnValueSerializer == null) {
+ throw new SerializationException("Could not find serializer for table column-value map " + type); + throw new SerializationException("Could not find serializer for table column-value map " + type);
+ } + }
@ -3108,7 +3157,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ @Override + @Override
+ public void serialize(final Type type, @Nullable final Table<?, ?, ?> table, final ConfigurationNode node) throws SerializationException { + public void serialize(final Type type, final @Nullable Table<?, ?, ?> table, final ConfigurationNode node) throws SerializationException {
+ if (table != null) { + if (table != null) {
+ this.serialize0(table, (ParameterizedType) type, node); + this.serialize0(table, (ParameterizedType) type, node);
+ } + }
@ -3120,7 +3169,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; + final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
+ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; + final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
+ +
+ final @Nullable TypeSerializer rowKeySerializer = node.options().serializers().get(rowType); + final TypeSerializer rowKeySerializer = node.options().serializers().get(rowType);
+ if (rowKeySerializer == null) { + if (rowKeySerializer == null) {
+ throw new SerializationException("Could not find a serializer for table row type " + rowType); + throw new SerializationException("Could not find a serializer for table row type " + rowType);
+ } + }
@ -3138,6 +3187,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return ImmutableTable.of(); + return ImmutableTable.of();
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/serializer/collections/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.serializer.collections;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/package-info.java b/src/main/java/io/papermc/paper/configuration/serializer/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/serializer/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.serializer;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -3153,7 +3222,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.minecraft.core.RegistryAccess; +import net.minecraft.core.RegistryAccess;
+import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.ResourceLocation;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer; +import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+ +
@ -3201,7 +3269,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ private ResourceKey<R> deserializeKey(final Object input) throws SerializationException { + private ResourceKey<R> deserializeKey(final Object input) throws SerializationException {
+ final @Nullable ResourceLocation key = ResourceLocation.tryParse(input.toString()); + final ResourceLocation key = ResourceLocation.tryParse(input.toString());
+ if (key == null) { + if (key == null) {
+ throw new SerializationException("Could not create a key from " + input); + throw new SerializationException("Could not create a key from " + input);
+ } + }
@ -3289,6 +3357,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return this.registry().getResourceKey(value).orElseThrow(); + return this.registry().getResourceKey(value).orElseThrow();
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/package-info.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/serializer/registry/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.serializer.registry;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java b/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java diff --git a/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java b/src/main/java/io/papermc/paper/configuration/transformation/Transformations.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -3346,6 +3424,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import com.mojang.logging.LogUtils; +import com.mojang.logging.LogUtils;
+import io.papermc.paper.configuration.Configuration; +import io.papermc.paper.configuration.Configuration;
+import java.util.function.Predicate;
+import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.MiniMessage;
@ -3353,14 +3432,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket; +import net.minecraft.network.protocol.game.ServerboundPlaceRecipePacket;
+import org.bukkit.ChatColor; +import org.bukkit.ChatColor;
+import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.YamlConfiguration;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.slf4j.Logger; +import org.slf4j.Logger;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.transformation.ConfigurationTransformation;
+import org.spongepowered.configurate.transformation.TransformAction; +import org.spongepowered.configurate.transformation.TransformAction;
+ +
+import java.util.function.Predicate;
+
+import static org.spongepowered.configurate.NodePath.path; +import static org.spongepowered.configurate.NodePath.path;
+ +
+public final class LegacyPaperConfig { +public final class LegacyPaperConfig {
@ -3425,7 +3501,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ .addAction(path("allow-perm-block-break-exploits"), (path, value) -> new Object[]{"settings", "unsupported-settings", "allow-permanent-block-break-exploits"}) + .addAction(path("allow-perm-block-break-exploits"), (path, value) -> new Object[]{"settings", "unsupported-settings", "allow-permanent-block-break-exploits"})
+ .addAction(path("settings", "unsupported-settings", "allow-tnt-duplication"), TransformAction.rename("allow-piston-duplication")) + .addAction(path("settings", "unsupported-settings", "allow-tnt-duplication"), TransformAction.rename("allow-piston-duplication"))
+ .addAction(path("settings", "save-player-data"), (path, value) -> { + .addAction(path("settings", "save-player-data"), (path, value) -> {
+ final @Nullable Object val = value.raw(); + final Object val = value.raw();
+ if (val instanceof Boolean bool) { + if (val instanceof Boolean bool) {
+ spigotConfiguration.set("players.disable-saving", !bool); + spigotConfiguration.set("players.disable-saving", !bool);
+ } + }
@ -3433,7 +3509,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return null; + return null;
+ }) + })
+ .addAction(path("settings", "log-named-entity-deaths"), (path, value) -> { + .addAction(path("settings", "log-named-entity-deaths"), (path, value) -> {
+ final @Nullable Object val = value.raw(); + final Object val = value.raw();
+ if (val instanceof Boolean bool && !bool) { + if (val instanceof Boolean bool && !bool) {
+ spigotConfiguration.set("settings.log-named-deaths", false); + spigotConfiguration.set("settings.log-named-deaths", false);
+ } + }
@ -3461,7 +3537,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ .addAction(path("packet-limiter", "limits", "all"), (path, value) -> new Object[]{"packet-limiter", "all-packets"}) + .addAction(path("packet-limiter", "limits", "all"), (path, value) -> new Object[]{"packet-limiter", "all-packets"})
+ .addAction(path("packet-limiter", "limits"), (path, value) -> new Object[]{"packet-limiter", "overrides"}) + .addAction(path("packet-limiter", "limits"), (path, value) -> new Object[]{"packet-limiter", "overrides"})
+ .addAction(path("packet-limiter", "overrides", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> { + .addAction(path("packet-limiter", "overrides", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> {
+ final @Nullable Object keyValue = value.key(); + final Object keyValue = value.key();
+ if (keyValue != null && keyValue.toString().equals("PacketPlayInAutoRecipe")) { // add special cast to handle the default for moj-mapped servers that upgrade the config + if (keyValue != null && keyValue.toString().equals("PacketPlayInAutoRecipe")) { // add special cast to handle the default for moj-mapped servers that upgrade the config
+ return path.with(path.size() - 1, ServerboundPlaceRecipePacket.class.getSimpleName()).array(); + return path.with(path.size() - 1, ServerboundPlaceRecipePacket.class.getSimpleName()).array();
+ } + }
@ -3520,7 +3596,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ private static void miniMessageWithTranslatable(final ConfigurationTransformation.Builder builder, final Predicate<String> englishCheck, final Component component, final String... strPath) { + private static void miniMessageWithTranslatable(final ConfigurationTransformation.Builder builder, final Predicate<String> englishCheck, final Component component, final String... strPath) {
+ builder.addAction(path((Object[]) strPath), (path, value) -> { + builder.addAction(path((Object[]) strPath), (path, value) -> {
+ final @Nullable Object val = value.raw(); + final Object val = value.raw();
+ if (val != null) { + if (val != null) {
+ final String strVal = val.toString(); + final String strVal = val.toString();
+ if (!englishCheck.test(strVal)) { + if (!englishCheck.test(strVal)) {
@ -3535,7 +3611,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ private static void miniMessage(final ConfigurationTransformation.Builder builder, final String... strPath) { + private static void miniMessage(final ConfigurationTransformation.Builder builder, final String... strPath) {
+ builder.addAction(path((Object[]) strPath), (path, value) -> { + builder.addAction(path((Object[]) strPath), (path, value) -> {
+ final @Nullable Object val = value.raw(); + final Object val = value.raw();
+ if (val != null) { + if (val != null) {
+ value.set(miniMessage(val.toString())); + value.set(miniMessage(val.toString()));
+ } + }
@ -3565,6 +3641,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }); + });
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/global/package-info.java b/src/main/java/io/papermc/paper/configuration/transformation/global/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/transformation/global/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.transformation.global;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V29_LogIPs.java b/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V29_LogIPs.java diff --git a/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V29_LogIPs.java b/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/V29_LogIPs.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -3576,7 +3662,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import java.util.Properties; +import java.util.Properties;
+import net.minecraft.server.MinecraftServer; +import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.DedicatedServer;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.NodePath; +import org.spongepowered.configurate.NodePath;
@ -3615,6 +3701,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/package-info.java b/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/transformation/global/versioned/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.transformation.global.versioned;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/package-info.java b/src/main/java/io/papermc/paper/configuration/transformation/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/transformation/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.transformation;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/FeatureSeedsGeneration.java b/src/main/java/io/papermc/paper/configuration/transformation/world/FeatureSeedsGeneration.java diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/FeatureSeedsGeneration.java b/src/main/java/io/papermc/paper/configuration/transformation/world/FeatureSeedsGeneration.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -3633,7 +3739,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer; +import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger; +import org.slf4j.Logger;
+import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
@ -3702,6 +3808,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import io.papermc.paper.configuration.Configuration; +import io.papermc.paper.configuration.Configuration;
+import io.papermc.paper.configuration.WorldConfiguration; +import io.papermc.paper.configuration.WorldConfiguration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import net.minecraft.core.Holder; +import net.minecraft.core.Holder;
+import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.core.registries.Registries; +import net.minecraft.core.registries.Registries;
@ -3710,16 +3821,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.item.Item; +import net.minecraft.world.item.Item;
+import org.bukkit.Material; +import org.bukkit.Material;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.transformation.ConfigurationTransformation;
+import org.spongepowered.configurate.transformation.TransformAction; +import org.spongepowered.configurate.transformation.TransformAction;
+ +
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+import static io.papermc.paper.configuration.transformation.Transformations.moveFromRoot; +import static io.papermc.paper.configuration.transformation.Transformations.moveFromRoot;
+import static io.papermc.paper.configuration.transformation.Transformations.moveFromRootAndRename; +import static io.papermc.paper.configuration.transformation.Transformations.moveFromRootAndRename;
+import static org.spongepowered.configurate.NodePath.path; +import static org.spongepowered.configurate.NodePath.path;
@ -3758,14 +3862,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }).build()) + }).build())
+ .addVersion(19, ConfigurationTransformation.builder() + .addVersion(19, ConfigurationTransformation.builder()
+ .addAction(path("anti-xray", "hidden-blocks"), (path, value) -> { + .addAction(path("anti-xray", "hidden-blocks"), (path, value) -> {
+ @Nullable final List<String> hiddenBlocks = value.getList(String.class); + final List<String> hiddenBlocks = value.getList(String.class);
+ if (hiddenBlocks != null) { + if (hiddenBlocks != null) {
+ hiddenBlocks.remove("lit_redstone_ore"); + hiddenBlocks.remove("lit_redstone_ore");
+ } + }
+ return null; + return null;
+ }) + })
+ .addAction(path("anti-xray", "replacement-blocks"), (path, value) -> { + .addAction(path("anti-xray", "replacement-blocks"), (path, value) -> {
+ @Nullable final List<String> replacementBlocks = value.getList(String.class); + final List<String> replacementBlocks = value.getList(String.class);
+ if (replacementBlocks != null) { + if (replacementBlocks != null) {
+ final int index = replacementBlocks.indexOf("planks"); + final int index = replacementBlocks.indexOf("planks");
+ if (index != -1) { + if (index != -1) {
@ -3838,9 +3942,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ value.childrenMap().forEach((key, node) -> { + value.childrenMap().forEach((key, node) -> {
+ String itemName = key.toString(); + String itemName = key.toString();
+ final Optional<Holder.Reference<Item>> itemHolder = BuiltInRegistries.ITEM.get(ResourceKey.create(Registries.ITEM, ResourceLocation.parse(itemName.toLowerCase(Locale.ROOT)))); + final Optional<Holder.Reference<Item>> itemHolder = BuiltInRegistries.ITEM.get(ResourceKey.create(Registries.ITEM, ResourceLocation.parse(itemName.toLowerCase(Locale.ROOT))));
+ final @Nullable String item; + final String item;
+ if (itemHolder.isEmpty()) { + if (itemHolder.isEmpty()) {
+ final @Nullable Material bukkitMat = Material.matchMaterial(itemName); + final Material bukkitMat = Material.matchMaterial(itemName);
+ item = bukkitMat != null ? bukkitMat.getKey().getKey() : null; + item = bukkitMat != null ? bukkitMat.getKey().getKey() : null;
+ } else { + } else {
+ item = itemHolder.get().unwrapKey().orElseThrow().location().getPath(); + item = itemHolder.get().unwrapKey().orElseThrow().location().getPath();
@ -3976,7 +4080,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ builder.addAction(path("feature-seeds", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> { + builder.addAction(path("feature-seeds", ConfigurationTransformation.WILDCARD_OBJECT), (path, value) -> {
+ final String key = path.array()[path.size() - 1].toString(); + final String key = path.array()[path.size() - 1].toString();
+ if (!key.equals("generate-random-seeds-for-all")) { + if (!"generate-random-seeds-for-all".equals(key)) {
+ return new Object[]{"feature-seeds", "features", key}; + return new Object[]{"feature-seeds", "features", key};
+ } + }
+ return null; + return null;
@ -3994,7 +4098,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ }); + });
+ +
+ builder.addAction(path("redstone-implementation"), (path, value) -> { + builder.addAction(path("redstone-implementation"), (path, value) -> {
+ if (value.require(String.class).equalsIgnoreCase("alternate-current")) { + if ("alternate-current".equalsIgnoreCase(value.require(String.class))) {
+ value.set("alternate_current"); + value.set("alternate_current");
+ } + }
+ return new Object[]{"misc", "redstone-implementation"}; + return new Object[]{"misc", "redstone-implementation"};
@ -4020,6 +4124,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ moveFromRootAndRename(builder, path("game-mechanics", oldKey), newKey, parents); + moveFromRootAndRename(builder, path("game-mechanics", oldKey), newKey, parents);
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/package-info.java b/src/main/java/io/papermc/paper/configuration/transformation/world/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/transformation/world/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.transformation.world;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -4029,7 +4143,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.configuration.transformation.world.versioned; +package io.papermc.paper.configuration.transformation.world.versioned;
+ +
+import io.papermc.paper.configuration.type.number.IntOr; +import io.papermc.paper.configuration.type.number.IntOr;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.NodePath; +import org.spongepowered.configurate.NodePath;
@ -4116,7 +4230,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import io.papermc.paper.configuration.Configurations; +import io.papermc.paper.configuration.Configurations;
+import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.GameRules;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.NodePath; +import org.spongepowered.configurate.NodePath;
+import org.spongepowered.configurate.transformation.ConfigurationTransformation; +import org.spongepowered.configurate.transformation.ConfigurationTransformation;
@ -4167,6 +4281,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/package-info.java b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.transformation.world.versioned;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java b/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java diff --git a/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java b/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -4175,14 +4299,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.configuration.type; +package io.papermc.paper.configuration.type;
+ +
+import org.apache.commons.lang3.BooleanUtils;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.Locale; +import java.util.Locale;
+import java.util.function.Predicate; +import java.util.function.Predicate;
+import org.apache.commons.lang3.BooleanUtils;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+ +
+public record BooleanOrDefault(@Nullable Boolean value) { +public record BooleanOrDefault(@Nullable Boolean value) {
+ private static final String DEFAULT_VALUE = "default"; + private static final String DEFAULT_VALUE = "default";
@ -4217,7 +4340,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ @Override + @Override
+ protected Object serialize(BooleanOrDefault item, Predicate<Class<?>> typeSupported) { + protected Object serialize(BooleanOrDefault item, Predicate<Class<?>> typeSupported) {
+ final @Nullable Boolean value = item.value; + final Boolean value = item.value;
+ if (value != null) { + if (value != null) {
+ return value.toString(); + return value.toString();
+ } else { + } else {
@ -4236,7 +4359,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import io.papermc.paper.configuration.type.number.IntOr; +import io.papermc.paper.configuration.type.number.IntOr;
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode;
+import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.SerializationException;
+import org.spongepowered.configurate.serialize.TypeSerializer; +import org.spongepowered.configurate.serialize.TypeSerializer;
@ -4349,20 +4472,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.configuration.type; +package io.papermc.paper.configuration.type;
+ +
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.Objects; +import java.util.Objects;
+import java.util.function.Predicate; +import java.util.function.Predicate;
+import java.util.regex.Pattern; +import java.util.regex.Pattern;
+import org.jspecify.annotations.Nullable;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+ +
+public final class Duration { +public final class Duration {
+ +
+ private static final Pattern SPACE = Pattern.compile(" "); + private static final Pattern SPACE = Pattern.compile(" ");
+ private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]"); + private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]");
+ public static final Serializer SERIALIZER = new Serializer(); + public static final ScalarSerializer<Duration> SERIALIZER = new Serializer();
+ +
+ private final long seconds; + private final long seconds;
+ private final String value; + private final String value;
@ -4752,17 +4874,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.configuration.type.fallback; +package io.papermc.paper.configuration.type.fallback;
+ +
+import net.minecraft.server.MinecraftServer;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.spigotmc.SpigotWorldConfig;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+
+import java.lang.reflect.Type; +import java.lang.reflect.Type;
+import java.util.HashMap; +import java.util.HashMap;
+import java.util.Map; +import java.util.Map;
+import java.util.function.Predicate; +import java.util.function.Predicate;
+import java.util.function.Supplier; +import java.util.function.Supplier;
+import net.minecraft.server.MinecraftServer;
+import org.spigotmc.SpigotWorldConfig;
+import org.spongepowered.configurate.serialize.ScalarSerializer;
+import org.spongepowered.configurate.serialize.SerializationException;
+ +
+import static io.leangen.geantyref.GenericTypeReflector.erase; +import static io.leangen.geantyref.GenericTypeReflector.erase;
+ +
@ -4789,7 +4909,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ @Override + @Override
+ public FallbackValue deserialize(Type type, Object obj) throws SerializationException { + public FallbackValue deserialize(Type type, Object obj) throws SerializationException {
+ final @Nullable FallbackCreator<?> creator = REGISTRY.get(erase(type)); + final FallbackCreator<?> creator = REGISTRY.get(erase(type));
+ if (creator == null) { + if (creator == null) {
+ throw new SerializationException(type + " does not have a FallbackCreator registered"); + throw new SerializationException(type + " does not have a FallbackCreator registered");
+ } + }
@ -4821,6 +4941,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return value < 0 ? OptionalInt.empty() : OptionalInt.of(value); + return value < 0 ? OptionalInt.empty() : OptionalInt.of(value);
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/type/fallback/package-info.java b/src/main/java/io/papermc/paper/configuration/type/fallback/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/type/fallback/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.type.fallback;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/type/number/BelowZeroToEmpty.java b/src/main/java/io/papermc/paper/configuration/type/number/BelowZeroToEmpty.java diff --git a/src/main/java/io/papermc/paper/configuration/type/number/BelowZeroToEmpty.java b/src/main/java/io/papermc/paper/configuration/type/number/BelowZeroToEmpty.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -5073,6 +5203,26 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+ protected abstract boolean belowZero(O value); + protected abstract boolean belowZero(O value);
+} +}
diff --git a/src/main/java/io/papermc/paper/configuration/type/number/package-info.java b/src/main/java/io/papermc/paper/configuration/type/number/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/type/number/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.type.number;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/io/papermc/paper/configuration/type/package-info.java b/src/main/java/io/papermc/paper/configuration/type/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/configuration/type/package-info.java
@@ -0,0 +0,0 @@
+@NullMarked
+package io.papermc.paper.configuration.type;
+
+import org.jspecify.annotations.NullMarked;
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/Main.java --- a/src/main/java/net/minecraft/server/Main.java

View File

@ -32,8 +32,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
import io.papermc.paper.configuration.serializer.collections.MapSerializer; import io.papermc.paper.configuration.serializer.collections.MapSerializer;
+import io.papermc.paper.util.MappingEnvironment; +import io.papermc.paper.util.MappingEnvironment;
import io.papermc.paper.util.ObfHelper; import io.papermc.paper.util.ObfHelper;
import net.minecraft.network.protocol.Packet; import java.lang.reflect.Type;
import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List;
@@ -0,0 +0,0 @@ public final class PacketClassSerializer extends ScalarSerializer<Class<? extend @@ -0,0 +0,0 @@ public final class PacketClassSerializer extends ScalarSerializer<Class<? extend
@Override @Override
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) { protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {