Skip to content

✨ feat(minestom): add server lifecycle, surf player and runtime plugin downloads - #448

Merged
twisti-dev merged 1 commit into
version/26.3from
feat/minestom-server-lifecycle
Oct 17, 2026
Merged

twisti-dev merged 1 commit into
version/26.3from
feat/minestom-server-lifecycle

Conversation

@twisti-dev

Copy link
Copy Markdown
Member
  • enable features and plugins synchronously in surfMinestomServer, before the server accepts players; a failing enable fails the start and rolls back
  • refuse a shutdown from the starting thread and fail the start when another thread requests one
  • add SurfMinestomServer.stop(), which stops Minestom, the api and then the onShutdown actions once, lets concurrent callers wait and refuses tick threads
  • add builder onShutdown actions and a JVM shutdown hook installed after a successful start
  • set minestom.shutdown-on-signal=false in the bootstrap unless it is given with -D
  • add SurfMinestomPlayer with the Adventure permission pointer, vanilla-like game mode switches, signed chat sessions in player list entries and shared viewable rules
  • add builder playerFactory; ConnectionManagerMixin rejects other player providers while the api runs, and a provider set before the start fails it outside of tests
  • add PlayerVisibility.isManaged and Provider.manages for the viewable rule of managed players
  • add withPlugins { requireAll }, which also counts unreadable plugin descriptions, and create plugins/ before a plugin is constructed
  • start the console reader on the first tick and stop the server from its default onShutdown
  • add downloadSurfModules and the shaded configuration to the minestom-server Gradle plugin
  • let SurfMixinAgent read the server jar reported by the bootstrap, so it works when surf-api modules are downloaded
  • use stop() in the example server and log from an onShutdown action
  • bump version to 3.49.0 and the Gradle plugin to 2.5.0

…n downloads

- enable features and plugins synchronously in surfMinestomServer, before the server accepts
  players; a failing enable fails the start and rolls back
- refuse a shutdown from the starting thread and fail the start when another thread requests one
- add SurfMinestomServer.stop(), which stops Minestom, the api and then the onShutdown actions
  once, lets concurrent callers wait and refuses tick threads
- add builder onShutdown actions and a JVM shutdown hook installed after a successful start
- set minestom.shutdown-on-signal=false in the bootstrap unless it is given with -D
- add SurfMinestomPlayer with the Adventure permission pointer, vanilla-like game mode switches,
  signed chat sessions in player list entries and shared viewable rules
- add builder playerFactory; ConnectionManagerMixin rejects other player providers while the api
  runs, and a provider set before the start fails it outside of tests
- add PlayerVisibility.isManaged and Provider.manages for the viewable rule of managed players
- add withPlugins { requireAll }, which also counts unreadable plugin descriptions, and create
  plugins/<id> before a plugin is constructed
- start the console reader on the first tick and stop the server from its default onShutdown
- add downloadSurfModules and the shaded configuration to the minestom-server Gradle plugin
- let SurfMixinAgent read the server jar reported by the bootstrap, so it works when surf-api
  modules are downloaded
- use stop() in the example server and log from an onShutdown action
- bump version to 3.49.0 and the Gradle plugin to 2.5.0
@twisti-dev twisti-dev self-assigned this Oct 17, 2026
Copilot AI balanced review requested due to automatic review settings October 17, 2026 11:43

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T11:49:08.798192Z 217ef7d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@twisti-dev
twisti-dev merged commit 14afc3b into version/26.3 Oct 17, 2026
7 checks passed
@twisti-dev
twisti-dev deleted the feat/minestom-server-lifecycle branch October 17, 2026 11:43

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 217ef7d820

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +180 to +182
for (action in builder.shutdownActions) {
try {
action()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Invoke shutdown actions for every Minestom stop

These callbacks run only when callers use SurfMinestomServer.stop(). If existing server code calls MinecraftServer.stopCleanly() directly, Minestom invokes the registered ::shutdown task and disables the API, but this loop is never reached, so documented shutdown work such as flushing databases is silently skipped. Register an idempotent action runner in the Minestom shutdown path as well.

Useful? React with 👍 / 👎.

start()
}

SchedulerManager.scheduleNextTick(console::start)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Cancel the pending console start when disabling

If a later feature fails during synchronous enable, or the API is shut down before the first tick, teardown calls ConsoleFeature.disable() but leaves this scheduled task active. A subsequent retry followed by the first server tick starts the stale console alongside the new one, causing multiple threads to read the same terminal and allowing the stale shutdown handler to stop the replacement runtime. Retain the scheduled task and cancel it during disable, or guard the callback against a disabled feature.

Useful? React with 👍 / 👎.


// Requested by another thread, which waits for the lock and then finds the api
// torn down
check(!runtime.shutdownRequested.get()) { "The surf api was shut down while it started" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Close the shutdown-request race at startup completion

If another thread enters shutdown() immediately after this final flag read but before surfMinestomServer returns, it sets shutdownRequested, waits for the lifecycle lock, and tears the runtime down; the starting thread never observes that request and returns normally with an already-disabled API. This contradicts the documented guarantee that a shutdown requested while startup is in progress fails the start, so the transition to the started state and the request check need to be linearized with shutdown().

Useful? React with 👍 / 👎.

)
}

Runtime.getRuntime().addShutdownHook(Thread(::stop, "surf-minestom-shutdown"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid retaining one shutdown hook per restarted runtime

In production, shutdown() clears current and permits a new runtime to start, but this hook is never removed or shared. After such a restart, JVM shutdown launches both hooks concurrently; their independent stopping flags allow both runtimes to call MinecraftServer.stopCleanly() at the same time, recreating the concurrent-stop condition warned about above and also retaining every old runtime and its shutdown actions until process exit. Use one process-wide hook or unregister the old runtime's hook when it is replaced.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants