Skip to content

Feat/add addable sponge config serializers#278

Merged
ammodev merged 3 commits into
version/1.21.11from
feat/add-addable-sponge-config-serializers
Apr 3, 2026
Merged

Feat/add addable sponge config serializers#278
ammodev merged 3 commits into
version/1.21.11from
feat/add-addable-sponge-config-serializers

Conversation

@ammodev

@ammodev ammodev commented Apr 3, 2026

Copy link
Copy Markdown
Member

Warten bis @TheBjoRedCraft updated hat, bevor merge.

https://i.imgur.com/ZeMLBRs.png

@ammodev ammodev self-assigned this Apr 3, 2026
@ammodev ammodev added the status: blocked Issue or Request is waiting on some other issue or change. label Apr 3, 2026
@ammodev ammodev marked this pull request as ready for review April 3, 2026 22:04
Copilot AI review requested due to automatic review settings April 3, 2026 22:04
@ammodev ammodev merged commit ce89e8d into version/1.21.11 Apr 3, 2026
3 of 4 checks passed
@ammodev ammodev deleted the feat/add-addable-sponge-config-serializers branch April 3, 2026 22:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a platform-extensible way to register Sponge Configurate serializers by moving SpongeConfigSerializers to a ServiceLoader-provided service and adding platform-specific providers (Paper/Velocity).

Changes:

  • Reworked SpongeConfigSerializers (core-api) into an abstract, registry-based serializer provider loaded via requiredService().
  • Updated SpongeConfigManager to use the service-provided serializer module when building Configurate loaders.
  • Added Paper/Velocity @AutoService implementations (including a Bukkit ItemStack serializer).

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
surf-api-velocity/.../VelocitySpongeConfigSerializers.kt Adds Velocity ServiceLoader provider for SpongeConfigSerializers.
surf-api-core/.../SpongeConfigSerializers.kt Refactors serializers into a service-loaded abstract registry with registration APIs.
surf-api-core/.../SpongeConfigManager.kt Switches loader options to use service-provided serializer module.
surf-api-core-api/api/surf-api-core-api.api Updates API surface to reflect new SpongeConfigSerializers shape and new accessor.
surf-api-bukkit/.../PaperSpongeConfigSerializers.kt Adds Paper provider and ItemStack Base64 serializer.
surf-api-bukkit/surf-api-bukkit-server/build.gradle.kts Moves generatePaperPluginDescription block (no functional change expected).
surf-api-bukkit-api/api/surf-api-bukkit-api.api API dump reflects removal of legacy inventory GUI APIs (large, unrelated surface change).

import dev.slne.surf.surfapi.core.api.config.serializer.SpongeConfigSerializers

@AutoService(SpongeConfigSerializers::class)
object VelocitySpongeConfigSerializers : SpongeConfigSerializers() No newline at end of file

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AutoService providers are instantiated via ServiceLoader, but Kotlin object singletons have a private constructor. This will cause ServiceLoader to fail to instantiate the provider at runtime (ServiceConfigurationError). Convert this to a regular class with a public no-arg constructor (or provide a @JvmStatic provider factory pattern) so the service can be loaded.

Suggested change
object VelocitySpongeConfigSerializers : SpongeConfigSerializers()
class VelocitySpongeConfigSerializers : SpongeConfigSerializers()

Copilot uses AI. Check for mistakes.
Comment on lines 229 to 234
): SpongeConfigManager<C> {
val loader = builder.path(configFolder.resolve(configFileName))
.defaultOptions {
it.serializers(SpongeConfigSerializers.SERIALIZERS)
it.serializers(surfSpongeConfigSerializers.buildSerializersModule())
.shouldCopyDefaults(true)
}

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpongeConfigManager now pulls serializers from surfSpongeConfigSerializers (a required ServiceLoader service). There is currently no SpongeConfigSerializers provider in the standalone artifact (only Bukkit/Velocity providers exist), so standalone usage of SpongeConfigManager will throw ServiceConfigurationError. Add a @AutoService(SpongeConfigSerializers::class) provider in surf-api-standalone (or provide a safe default/fallback implementation) to avoid breaking standalone configs.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +28
val surfSpongeConfigSerializers = requiredService<SpongeConfigSerializers>()

/**
* Serializers for Sponge configurations, including support for Adventure [Component] and other types.
*/
object SpongeConfigSerializers {
abstract class SpongeConfigSerializers {

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New public API val surfSpongeConfigSerializers = requiredService<SpongeConfigSerializers>() is missing KDoc. Other top-level surf* service accessors in core-api include KDoc (e.g. surfCoreApi, surfConfigApi), and this should too to keep public API documentation consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +58
private val _typeTokenSerializers = mutableObject2ObjectMapOf<TypeToken<*>, TypeSerializer<*>>()
val typeTokenSerializers get() = _typeTokenSerializers.freeze()

private val _classSerializers = mutableObject2ObjectMapOf<Class<*>, TypeSerializer<*>>()
val classSerializers get() = _classSerializers.freeze()

init {
registerClassSerializer(Component::class.java, ComponentSerializer())
registerTypeTokenSerializer(LinkedListSerializer.TYPE, LinkedListSerializer())
}

fun <T : Any> registerClassSerializer(clazz: Class<T>, serializer: TypeSerializer<T>) {
_classSerializers[clazz] = serializer
}

inline fun <reified T : Any> registerClassSerializer(serializer: TypeSerializer<T>) {
registerClassSerializer(T::class.java, serializer)
}

fun unregisterSerializer(clazz: Class<*>) {
_classSerializers.remove(clazz)
}

fun registerTypeTokenSerializer(typeToken: TypeToken<*>, serializer: TypeSerializer<*>) {
_typeTokenSerializers[typeToken] = serializer
}

fun unregisterTypeTokenSerializer(typeToken: TypeToken<*>) {
_typeTokenSerializers.remove(typeToken)
}

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpongeConfigSerializers exposes several new public API members (typeTokenSerializers, classSerializers, register*/unregister*) without KDoc. Given this is in core-api and will be consumed externally, add KDoc for these members to clarify intended usage (especially around when/how it is safe to mutate the registries).

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +27
?: throw SerializationException("Expected a Base64 string for ItemStack deserialization")
val decoded = Base64.getDecoder().decode(itemStackBase64)

return ItemStack.deserializeBytes(decoded)

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ItemStackSerializer.deserialize can throw IllegalArgumentException (invalid Base64) and whatever ItemStack.deserializeBytes throws (invalid payload). Those exceptions will currently bubble up without node context. Catch and wrap them in a SerializationException (ideally including the node/path) so configuration errors are reported as proper Configurate serialization failures.

Suggested change
?: throw SerializationException("Expected a Base64 string for ItemStack deserialization")
val decoded = Base64.getDecoder().decode(itemStackBase64)
return ItemStack.deserializeBytes(decoded)
?: throw SerializationException(
node,
type,
"Expected a Base64 string for ItemStack deserialization"
)
try {
val decoded = Base64.getDecoder().decode(itemStackBase64)
return ItemStack.deserializeBytes(decoded)
} catch (e: SerializationException) {
throw e
} catch (e: Exception) {
throw SerializationException(
node,
type,
"Failed to deserialize ItemStack from Base64",
e
)
}

Copilot uses AI. Check for mistakes.
Comment on lines 703 to 707
public abstract fun parse (Lorg/bukkit/OfflinePlayer;Ljava/util/List;)Ljava/lang/String;
}

public abstract interface class dev/slne/surf/surfapi/bukkit/api/inventory/SinglePlayerGui : dev/slne/surf/surfapi/bukkit/api/inventory/SurfGui {
public abstract fun getPlayer ()Lorg/bukkit/entity/Player;
public fun open ()V
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/SinglePlayerGui$DefaultImpls {
public static fun backToParent (Ldev/slne/surf/surfapi/bukkit/api/inventory/SinglePlayerGui;Lorg/bukkit/entity/HumanEntity;)V
public static fun item (Ldev/slne/surf/surfapi/bukkit/api/inventory/SinglePlayerGui;Lcom/github/stefvanschie/inventoryframework/pane/StaticPane;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;Lorg/bukkit/inventory/ItemStack;Lkotlin/jvm/functions/Function1;)V
public static fun open (Ldev/slne/surf/surfapi/bukkit/api/inventory/SinglePlayerGui;)V
public static fun walkParents (Ldev/slne/surf/surfapi/bukkit/api/inventory/SinglePlayerGui;)Ljava/util/List;
}

public abstract interface class dev/slne/surf/surfapi/bukkit/api/inventory/SurfGui {
public fun backToParent (Lorg/bukkit/entity/HumanEntity;)V
public abstract fun getGui ()Lcom/github/stefvanschie/inventoryframework/gui/type/util/NamedGui;
public abstract fun getParent ()Ldev/slne/surf/surfapi/bukkit/api/inventory/SurfGui;
public fun item (Lcom/github/stefvanschie/inventoryframework/pane/StaticPane;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;Lorg/bukkit/inventory/ItemStack;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun item$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/SurfGui;Lcom/github/stefvanschie/inventoryframework/pane/StaticPane;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;Lorg/bukkit/inventory/ItemStack;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public fun walkParents ()Ljava/util/List;
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/SurfGui$DefaultImpls {
public static fun backToParent (Ldev/slne/surf/surfapi/bukkit/api/inventory/SurfGui;Lorg/bukkit/entity/HumanEntity;)V
public static fun item (Ldev/slne/surf/surfapi/bukkit/api/inventory/SurfGui;Lcom/github/stefvanschie/inventoryframework/pane/StaticPane;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;Lorg/bukkit/inventory/ItemStack;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun item$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/SurfGui;Lcom/github/stefvanschie/inventoryframework/pane/StaticPane;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;Lorg/bukkit/inventory/ItemStack;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static fun walkParents (Ldev/slne/surf/surfapi/bukkit/api/inventory/SurfGui;)Ljava/util/List;
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/dsl/GuiKt {
public static final fun childMenu (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lnet/kyori/adventure/text/Component;ILkotlin/jvm/functions/Function1;)Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;
public static final fun childPlayerMenu (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestSinglePlayerGui;Lnet/kyori/adventure/text/Component;ILkotlin/jvm/functions/Function1;)Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestSinglePlayerGui;
public static final fun menu (Lnet/kyori/adventure/text/Component;ILkotlin/jvm/functions/Function1;)Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;
public static synthetic fun menu$default (Lnet/kyori/adventure/text/Component;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;
public static final fun playerMenu (Lnet/kyori/adventure/text/Component;Lorg/bukkit/entity/Player;ILkotlin/jvm/functions/Function1;)Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestSinglePlayerGui;
public static synthetic fun playerMenu$default (Lnet/kyori/adventure/text/Component;Lorg/bukkit/entity/Player;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestSinglePlayerGui;
public static final fun staticPane (Lcom/github/stefvanschie/inventoryframework/gui/type/util/MergedGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;)V
public static synthetic fun staticPane$default (Lcom/github/stefvanschie/inventoryframework/gui/type/util/MergedGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}

public abstract interface annotation class dev/slne/surf/surfapi/bukkit/api/inventory/dsl/MenuMarker : java/lang/annotation/Annotation {
}

public abstract interface annotation class dev/slne/surf/surfapi/bukkit/api/inventory/dsl/PaneMarker : java/lang/annotation/Annotation {
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/dsl/PanesKt {
public static final fun addItem (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;Lcom/github/stefvanschie/inventoryframework/gui/GuiItem;)V
public static final fun addItems (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;[Lkotlin/Pair;)V
public static final fun drawOutline (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILcom/github/stefvanschie/inventoryframework/gui/GuiItem;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static final fun drawOutline (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static synthetic fun drawOutline$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILcom/github/stefvanschie/inventoryframework/gui/GuiItem;ILjava/lang/Object;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static synthetic fun drawOutline$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static final fun drawOutlineRow (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;IILcom/github/stefvanschie/inventoryframework/gui/GuiItem;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static final fun drawOutlineRow (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;IILkotlin/jvm/functions/Function1;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static synthetic fun drawOutlineRow$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;IILcom/github/stefvanschie/inventoryframework/gui/GuiItem;ILjava/lang/Object;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static synthetic fun drawOutlineRow$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;IILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/stefvanschie/inventoryframework/pane/OutlinePane;
public static final fun makeStaticPane (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;)Lcom/github/stefvanschie/inventoryframework/pane/StaticPane;
public static final fun makeSubmitItemPane (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILjava/util/List;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/surfapi/bukkit/api/inventory/pane/SubmitItemPane;
public static final fun makeSubmitItemPane (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Ldev/slne/surf/surfapi/bukkit/api/inventory/pane/SubmitItemPane;
public static synthetic fun makeSubmitItemPane$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILjava/util/List;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/surfapi/bukkit/api/inventory/pane/SubmitItemPane;
public static synthetic fun makeSubmitItemPane$default (Ldev/slne/surf/surfapi/bukkit/api/inventory/types/SurfChestGui;Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;IILkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldev/slne/surf/surfapi/bukkit/api/inventory/pane/SubmitItemPane;
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/dsl/SlotKt {
public static final fun slot (I)Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;
public static final fun slot (II)Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/dsl/StaticPaneScope : com/github/stefvanschie/inventoryframework/pane/StaticPane {
public fun <init> (Lcom/github/stefvanschie/inventoryframework/pane/util/Slot;II)V
}

public final class dev/slne/surf/surfapi/bukkit/api/inventory/framework/InventoryFrameworkExtensions {
public static final fun getOutlineItem (Lme/devnatan/inventoryframework/View;)Lorg/bukkit/inventory/ItemStack;

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API surface change removes multiple Bukkit inventory GUI-related public types (SinglePlayerGui, SurfGui, etc.), which looks unrelated to this PR’s stated purpose (Sponge config serializers). If intentional, it should be called out explicitly in the PR description/changelog (breaking change); if not intentional, the API dump likely needs to be regenerated/fixed so it matches the intended public API.

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +54
fun unregisterSerializer(clazz: Class<*>) {
_classSerializers.remove(clazz)
}

fun registerTypeTokenSerializer(typeToken: TypeToken<*>, serializer: TypeSerializer<*>) {
_typeTokenSerializers[typeToken] = serializer
}

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unregisterSerializer(clazz) is ambiguous now that there are two registries (class-based and TypeToken-based). For symmetry with registerClassSerializer(...) and clarity for API consumers, consider renaming this to unregisterClassSerializer(...) (and keeping unregisterTypeTokenSerializer(...) as-is).

Copilot uses AI. Check for mistakes.
Comment on lines 25 to +33
/**
* Serializers for Sponge configurations, including support for Adventure [Component] and other types.
*/
object SpongeConfigSerializers {
abstract class SpongeConfigSerializers {
private val _typeTokenSerializers = mutableObject2ObjectMapOf<TypeToken<*>, TypeSerializer<*>>()
val typeTokenSerializers get() = _typeTokenSerializers.freeze()

private val _classSerializers = mutableObject2ObjectMapOf<Class<*>, TypeSerializer<*>>()
val classSerializers get() = _classSerializers.freeze()

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing SpongeConfigSerializers from a Kotlin object with mutable SERIALIZERS to an abstract class loaded via requiredService() is a breaking public API change (source + binary). Make sure this is intentional and that downstream consumers have a clear migration path (e.g., release notes and version bump consistent with your compatibility policy).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: blocked Issue or Request is waiting on some other issue or change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants