Skip to content

Commit dce266e

Browse files
fix: add manual META-INF/services files for NmsProvider ServiceLoader registration
The @autoservice KSP processor may not always generate the service file correctly (e.g. due to paperweight dev bundle resolution issues). Adding manual service files ensures V1_21_11NmsProvider and V26_1NmsProvider are always discoverable by ServiceLoader at runtime. Also makes ServiceLoader iteration robust against class loading failures and updates the NMS template generator to auto-generate service files. Agent-Logs-Url: https://github.com/SLNE-Development/surf-api/sessions/1c421ac7-9194-4697-91fd-1373913d3900 Co-authored-by: TheBjoRedCraft <143264463+TheBjoRedCraft@users.noreply.github.com>
1 parent 64eb38b commit dce266e

4 files changed

Lines changed: 50 additions & 4 deletions

File tree

surf-api-generator/src/main/kotlin/dev/slne/surf/api/gen/nms/NmsTemplateGenerator.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,35 @@ class NmsTemplateGenerator(
7474
generated++
7575
}
7676

77+
// Generate META-INF/services file for ServiceLoader registration
78+
generateServiceFile(repoRoot, target)
79+
7780
println("Generated $generated files for ${target.versionId} in ${targetSourceRoot.toAbsolutePath()}")
7881
return generated
7982
}
8083

84+
/**
85+
* Generates the META-INF/services file for ServiceLoader registration.
86+
* This ensures the NmsProvider implementation is discoverable at runtime,
87+
* regardless of whether KSP annotation processing runs successfully.
88+
*/
89+
private fun generateServiceFile(repoRoot: Path, target: NmsVersionConfig) {
90+
val serviceDir = repoRoot.resolve(target.sourceModulePath)
91+
.resolve("src/main/resources/META-INF/services")
92+
serviceDir.createDirectories()
93+
94+
// Derive the provider class name from the reference module's NmsProvider
95+
val referenceProviderPackage = "dev.slne.surf.api.paper.server.nms.$referenceVersionId"
96+
val referenceProviderClass = "${referenceClassPrefix}NmsProvider"
97+
val targetProviderPackage = "dev.slne.surf.api.paper.server.nms.${target.versionId}"
98+
val targetProviderClass = "${target.classPrefix}NmsProvider"
99+
100+
val serviceFile = serviceDir.resolve("dev.slne.surf.api.paper.nms.common.NmsProvider")
101+
serviceFile.writeText("$targetProviderPackage.$targetProviderClass\n")
102+
103+
println("Generated service file for ${target.versionId}: $targetProviderPackage.$targetProviderClass")
104+
}
105+
81106
/**
82107
* Transforms a relative path from the reference module to the target module.
83108
* Replaces the reference package directory segments with target ones.

surf-api-paper/surf-api-paper-nms/surf-api-paper-nms-common/src/main/kotlin/dev/slne/surf/api/paper/nms/common/NmsProvider.kt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,29 @@ interface NmsProvider {
9898
*/
9999
val current: NmsProvider by lazy {
100100
val version = NmsVersion.current
101-
val providers = java.util.ServiceLoader.load(
101+
val serviceLoader = java.util.ServiceLoader.load(
102102
NmsProvider::class.java,
103103
NmsProvider::class.java.classLoader
104-
).toList()
104+
)
105+
106+
// Iterate safely — skip providers whose classes can't be loaded
107+
// (e.g. version-specific NMS classes not present on this server)
108+
val providers = buildList {
109+
val iterator = serviceLoader.iterator()
110+
while (iterator.hasNext()) {
111+
try {
112+
add(iterator.next())
113+
} catch (e: java.util.ServiceConfigurationError) {
114+
log.atWarning().withCause(e).log("Skipping NmsProvider that failed to load")
115+
}
116+
}
117+
}
105118

106119
log.atInfo().log("Looking for NmsProvider with version: %s", version)
107-
log.atInfo().log("Available NmsProviders: %s", providers.map { "${it.version.name} (${it.version.versionPrefix})" }.joinToString(", "))
120+
log.atInfo().log(
121+
"Available NmsProviders: %s",
122+
providers.joinToString(", ") { "${it.version.name} (${it.version.versionPrefix})" }
123+
)
108124

109125
val matched = providers.firstOrNull { it.version == version }
110126
if (matched != null) {
@@ -113,7 +129,10 @@ interface NmsProvider {
113129
} else {
114130
log.atWarning().log("No exact match for NmsProvider version %s, using fallback", version)
115131
val fallback = providers.maxByOrNull { it.version.versionPrefix }
116-
?: error("No NmsProvider implementations found")
132+
?: error(
133+
"No NmsProvider implementations found for version $version. " +
134+
"Ensure the correct NMS module is included in the classpath."
135+
)
117136
log.atWarning().log("Selected fallback NmsProvider: %s", fallback.version.name)
118137
fallback
119138
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dev.slne.surf.api.paper.server.nms.v1_21_11.V1_21_11NmsProvider
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dev.slne.surf.api.paper.server.nms.v26_1.V26_1NmsProvider

0 commit comments

Comments
 (0)