build: switch to the OneLiteFeather minestom-extensions fork - #207
Merged
Conversation
TheMeinerLP
force-pushed
the
build/buildsrc-conventions
branch
from
August 27, 2026 20:03
c9a0860 to
00dfaed
Compare
TheMeinerLP
force-pushed
the
build/minestom-extensions
branch
from
August 27, 2026 20:04
33bf01e to
e22c1ca
Compare
dev.hollowcube:minestom-ce-extensions is archived and resolves extension dependencies through a Kotlin class (net.minestom.dependencies.maven. MavenRepository). That forced two workarounds Titan carried in comments: bundling kotlin-stdlib-jdk8 into the fat jar, and routing resolution through the reposilite JitPack proxy for com.github.Minestom: DependencyGetter. net.onelitefeather:minestom-extensions 2.2.0 keeps the same packages (net.hollowcube.minestom.extensions, net.minestom.server.extensions) but resolves through Maven Resolver, so both workarounds are gone: - kotlin-stdlib-jdk8 dropped from :app and from the version catalog - the JitPack proxy repository replaced by the credential-free OneLiteFeatherReleases repository the fork is published to. Verified with a cold Gradle user home: all 65 modules resolve without it, com.github.CloudNetService.cloud-command-framework included (it comes from repository.derklaro.dev). The fork also offers ExtensionBootstrap.init(Auth), added upstream for exactly this case. Titan's Velocity path no longer has to reach for getDeclaredConstructor(MinecraftServer.class) + setAccessible(true) - the reflection hack listed as open point 1 in the OLF Minestom project standard is gone. :bridge now generates extension.json from @ExtensionInfo instead of keeping a hand-written file plus a ReplaceTokens filter for @Version@. The generated descriptor carries the same name, entrypoint, version, authors and dependencies; only key order and whitespace differ. The annotation has source retention, so the bridge jar holds exactly the same entries as before. Verified: 56 tests, 0 failures (unchanged). The Velocity branch was smoke tested against the real fat jar with -Dminestom.velocity.secret set; it gets past ExtensionBootstrap and LuckPerms and stops at the same missing worlds/ directory as the pre-change jar does in the same run. Fat jar shrinks from 43.7 MB to 40.8 MB (25650 to 23719 entries): the old DependencyGetter dragged in shrinkwrap-resolver, arquillian-spacelift, jsoup and a large commons/plexus tree; Maven Resolver replaces them with aether plus httpclient. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QtbnMbAj6m2q3vrDYFizDr
Titan shipped without an SLF4J binding. slf4j-api arrived transitively
through Minestom, no provider was ever declared, and the fat jars answered
every log call with "No SLF4J providers were found" and dropped it. On top
of that, Minestom's default ExceptionManager handler is
Throwable::printStackTrace, so a listener that threw left a bare stack
trace on stdout and nothing else. A production lobby was effectively
running blind.
Logging
- logback-classic as runtimeOnly in :app and :setup, slf4j-api declared
explicitly where code compiles against it
- one logback.xml in :common, so both fat jars get the same configuration
without copying it
- TitanObservability.installExceptionHandler() replaces Minestom's
printStackTrace default, so exceptions reach the log like everything else
Sentry
- optional, exactly as Sturnus does it: no TITAN_SENTRY_DSN means
Sentry.init is never called and the process behaves as it does today.
One jar serves operators with and without a Sentry instance.
- release comes from the jar's Implementation-Version manifest attribute
(added in titan.java-conventions), so an issue points at a deploy
- environment from TITAN_SENTRY_ENVIRONMENT
- reporting has exactly one entry point, the logback appender at ERROR.
No second path that could double-report or drift out of sync.
Player attribution
EventNodeImpl catches what a listener throws and hands it to the exception
manager one frame up, on the same thread. TitanObservability.guard() sits
inside that frame and records the failing event's player, which the handler
puts into the MDC as player.uuid / player.name. Recording happens in a
catch block only - a listener that returns normally pays for an entered try
and nothing else, which matters because the guarded set includes
PlayerMoveEvent and PlayerPacketEvent.
sendDefaultPii stays false: the SDK's PII defaults are request headers and
IP addresses, which say nothing about a Minestom crash. The player identity
that does is attached deliberately.
Verified against the real fat jar. Without a DSN:
INFO n.o.t.c.o.TitanObservability - Sentry reporting disabled - ...
INFO luckperms - Loading configuration...
ERROR n.o.t.c.o.TitanObservability - Unhandled exception
java.nio.file.NoSuchFileException: worlds
With TITAN_SENTRY_DSN and TITAN_SENTRY_ENVIRONMENT set:
INFO n.o.t.c.o.TitanObservability - Sentry reporting enabled -
release 1.14.0, environment smoketest
Before this change the same run printed "No SLF4J providers were found"
and a bare stack trace.
The appender is declared with an empty DSN on purpose. It is constructed
when the first logger is created, necessarily before bootstrap() can call
Sentry.init, and an appender that finds no DSN then logs "DSN is required"
at WARN - which makes Logback dump its entire configuration status on every
start.
7 new tests in :common (63 total, 0 failures).
Claude-Session: https://claude.ai/code/session_01QtbnMbAj6m2q3vrDYFizDr
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
TheMeinerLP
force-pushed
the
build/minestom-extensions
branch
from
August 28, 2026 06:57
6b4c4e6 to
5512f2f
Compare
Contributor
Test results 66 files 66 suites 53s ⏱️ Results for commit 5512f2f. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebased onto
mainand retargeted: #206 is merged, so this PR no longer stacks onbuild/buildsrc-conventions. #208 was merged into this branch and therefore ships with it — the two commits below are the whole diff.build: switch to the OneLiteFeather minestom-extensions forkfeat: log through SLF4J and report errors to Sentry (#208)Why
dev.hollowcube:minestom-ce-extensionsis archived and resolves extension dependencies through a Kotlin class (net.minestom.dependencies.maven.MavenRepository). That forced two workarounds, both of which were carrying an explanatory comment in the build:kotlin-stdlib-jdk8into the fat jar, otherwiseNoClassDefFoundError: kotlin/jvm/internal/Intrinsicscom.github.Minestom:DependencyGetterthrough the reposilite JitPack proxyOn top of that,
TitanApplicationneeded a reflection hack becauseExtensionBootstrap.init()accepted noAuth.What
Switch to
net.onelitefeather:minestom-extensions2.2.0, the OneLiteFeather fork. Same packages (net.hollowcube.minestom.extensions,net.minestom.server.extensions), but resolution via Maven Resolver.Both workarounds are gone:
kotlin-stdlib-jdk8dropped from:appand from the version catalogOneLiteFeatherReleasesrepository that hosts the forkThe reflection hack is gone. The fork ships
ExtensionBootstrap.init(Auth)(minestom-extensions#7, release 2.2.0), added for exactly this case:That closes open item 1 of the OLF Minestom Project Standard.
:bridgenow generatesextension.jsonfrom@ExtensionInfoinstead of keeping it by hand (OLF-L5-01). The handwritten file and theReplaceTokensfilter for@version@are removed.Verification
Generated vs. handwritten
extension.json— identical content; only key order and whitespace differ:nameTitanCloudNetPermissionsTitanCloudNetPermissionsentrypointnet.onelitefeather.titan.bridge.TitanBridgePermissionExtensionversion1.14.01.14.0authors["OneLiteFeather"]["OneLiteFeather"]dependencies["CloudNet_Bridge"]["CloudNet_Bridge"]The bridge jar carries exactly the same entries as before —
@ExtensionInfohas source retention, so the annotation never reaches the jar.Cold Gradle cache (fresh
--gradle-user-home): all 65 modules resolve without the JitPack proxy, includingcom.github.CloudNetService.cloud-command-framework, which comes fromrepository.derklaro.dev.Velocity path against the real fat jar — the branch that previously needed reflection:
Gets past
ExtensionBootstrapand LuckPerms and stops atNoSuchFileException: worlds— the same point where the pre-change jar stops in an identical run (control run performed). NoNoClassDefFoundError.Tests: 63, 0 failures. (The count includes the 7 tests that came with #208.)
Side effect: the fat jar loses the Kotlin and Shrinkwrap trees
Measured against
main, both jars built from a cleanshadowJar:mainkotlin/**org/eclipse/aetherThe old
DependencyGetterpulled in shrinkwrap-resolver, arquillian-spacelift and jsoup; Maven Resolver replaces that with aether + httpclient.The extension switch on its own removed ~2.8 MB. The net figure is smaller because the Sentry and Logback dependencies from #208 add roughly 2 MB back — that is the cost of the observability change, not of this one.
Notes
build:, so this produces no changelog entry. If the loader switch should be visible to ops inCHANGELOG.md, say so and it becomes afeat:.SLF4J(W): No SLF4J providers were foundwarning noted during the original smoke test is fixed by feat: log through SLF4J and report errors to Sentry #208, which is part of this branch.MapProviderstill compiles with two removal warnings (GsonFileHandler,AnvilLoader(Path)), both pre-existing and unrelated to this change.