Migrate to v0.11.0 of Dragonfly #88

Merged
smell-of-curry merged 2 commits from v0.11.0-migration into main 2026-07-13 14:30:59 +00:00
smell-of-curry commented 2026-07-13 01:24:29 +00:00 (Migrated from github.com)
  • New Features

    • Added configurable interactive NPCs with custom skins, equipment, movement, and vulnerability settings.
    • Improved NPC animations and interactions across different viewing layers.
    • Added safer handling for console commands that do not have a world-attached source.
  • Bug Fixes

  • Reliability

    • Leaderboard updates now save asynchronously and flush cleanly during shutdown.
    • Release builds now include automated quality and test checks.
* **New Features** * Added configurable interactive NPCs with custom skins, equipment, movement, and vulnerability settings. * Improved NPC animations and interactions across different viewing layers. * Added safer handling for console commands that do not have a world-attached source. * **Bug Fixes** * Updated parkour locations and leaderboard markers across multiple worlds. * Improved countdowns, moderation effects, rank updates, and player-session handling. * Prevented closed worlds from being incorrectly reported as stalled. * https://github.com/smell-of-curry/pokebedrock-hub/issues/86 * https://github.com/smell-of-curry/pokebedrock-hub/issues/85 * **Reliability** * Leaderboard updates now save asynchronously and flush cleanly during shutdown. * Release builds now include automated quality and test checks.
coderabbitai[bot] commented 2026-07-13 01:24:50 +00:00 (Migrated from github.com)

Review Change Stack

Warning

Review limit reached

@smell-of-curry, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d334c81f-40a4-4eb7-a6c3-987f3e7a4a46

📥 Commits

Reviewing files that changed from the base of the PR and between 260e1bb378 and 8fd91c3167.

📒 Files selected for processing (12)
  • .cursor/rules/no-blocking-io-in-execworld.mdc
  • pokebedrock/hider/hider_test.go
  • pokebedrock/moderation/service.go
  • pokebedrock/moderation/service_test.go
  • pokebedrock/parkour/leaderboard.go
  • pokebedrock/parkour/leaderboard_test.go
  • pokebedrock/parkour/manager.go
  • pokebedrock/pokebedrock.go
  • pokebedrock/slapper/slapper.go
  • pokebedrock/srv/config.go
  • pokebedrock/srv/config_test.go
  • pokebedrock/srv/manager.go
📝 Walkthrough

Walkthrough

The PR updates world-owner execution patterns, adds NPC and skin-loading infrastructure, refactors slapper and parkour lifecycles, removes obsolete APIs, adds release checks, and updates server parkour coordinates.

Changes

World-owner execution and asynchronous player flows

Layer / File(s) Summary
Execution and player callbacks
.cursor/rules/*, pokebedrock/form/*, pokebedrock/session/*, pokebedrock/handler/*, pokebedrock/moderation/*
Blocking I/O guidance, player data capture, moderation queues, infliction loading, and rank updates now use world-owner-safe callback patterns.
World lifecycle and monitoring
pokebedrock/pokebedrock.go, pokebedrock/hider/*, pokebedrock/watchdog/*
World initialization, player acceptance, visibility handling, watchdog probing, and shutdown use updated transaction and task behavior.

NPC and slapper asset pipeline

Layer / File(s) Summary
NPC and skin infrastructure
pokebedrock/npc/*
NPC settings, creation, interaction handlers, model parsing, texture parsing, and skin assembly are added.
Slapper loading and integration
pokebedrock/slapper/*, pokebedrock/pokebedrock.go, go.mod, .golangci.yml
Slapper assets load with errors and fallback support before transaction-bound spawning and registration; the previous external NPC dependency is removed.

Parkour transaction and persistence flow

Layer / File(s) Summary
Leaderboard and manager lifecycle
pokebedrock/parkour/leaderboard.go, pokebedrock/parkour/manager.go, pokebedrock/command/parkour_reset.go
Leaderboard snapshots are persisted asynchronously, parkour operations accept transactions, and manager shutdown flushes pending saves.
Countdown scheduling
pokebedrock/parkour/session.go
Countdowns use cancellable scheduled tasks and generation checks.
Server locations
resources/servers/*.json
Parkour NPC, leaderboard, start, and end coordinates are updated.

API cleanup and release validation

Layer / File(s) Summary
API cleanup
pokebedrock/queue/manager.go, pokebedrock/rank/service.go, pokebedrock/moderation/service.go, pokebedrock/kit/lobby.go
Deprecated transfer, queue-loading, player-role, and player-infliction helpers are removed or replaced with direct state handling and XUID-based APIs.
Release and configuration updates
.github/workflows/release.yml, config.example.toml, pokebedrock/config.go
Release jobs run go vet ./... and go test ./...; watchdog configuration comments are updated for world-owner task semantics.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: glancist

🚥 Pre-merge checks | 4 | 1

Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title accurately summarizes the main dependency upgrade in the pull request.
Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v0.11.0-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

<!-- This is an auto-generated comment: summarize by coderabbit.ai --> <!-- review_stack_entry_start --> [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/smell-of-curry/pokebedrock-hub/pull/88?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- This is an auto-generated comment: rate limited by coderabbit.ai --> > [!WARNING] > ## Review limit reached > > `@smell-of-curry`, you've reached your PR review limit, so we couldn't start this review. > > **Next review available in:** **32 minutes** > > Enable **[usage-based reviews](https://app.coderabbit.ai/settings/billing?tab=usage&orgId=622c78ce-9e11-4f9b-9f86-5799be0786e4)** in Billing to review now. Otherwise, wait until the next included review is available. > You're only billed for reviews past your plan's rate limits ($0.25/file). > > <details> > <summary>How can I continue?</summary> > > After more reviews become available, a review can be triggered using the `@coderabbitai review` command as a PR comment. Alternatively, push new commits to this PR. > > To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. > > </details> > > > <details> > <summary>How do review limits work?</summary> > > CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. > > For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. > > Please refer [docs](https://docs.coderabbit.ai/management/plans#rate-limits) for additional details. > > </details> > > <details> > <summary>Review details</summary> > > <details> > <summary>⚙️ Run configuration</summary> > > **Configuration used**: defaults > > **Review profile**: CHILL > > **Plan**: Pro > > **Run ID**: `d334c81f-40a4-4eb7-a6c3-987f3e7a4a46` > > </details> > > <details> > <summary>📥 Commits</summary> > > Reviewing files that changed from the base of the PR and between 260e1bb37886443271c563be827a0f963fb9174b and 8fd91c3167b76d33591acf084b916584b2009374. > > </details> > > <details> > <summary>📒 Files selected for processing (12)</summary> > > * `.cursor/rules/no-blocking-io-in-execworld.mdc` > * `pokebedrock/hider/hider_test.go` > * `pokebedrock/moderation/service.go` > * `pokebedrock/moderation/service_test.go` > * `pokebedrock/parkour/leaderboard.go` > * `pokebedrock/parkour/leaderboard_test.go` > * `pokebedrock/parkour/manager.go` > * `pokebedrock/pokebedrock.go` > * `pokebedrock/slapper/slapper.go` > * `pokebedrock/srv/config.go` > * `pokebedrock/srv/config_test.go` > * `pokebedrock/srv/manager.go` > > </details> > > </details> <!-- end of auto-generated comment: rate limited by coderabbit.ai --> <!-- walkthrough_start --> <details> <summary>📝 Walkthrough</summary> ## Walkthrough The PR updates world-owner execution patterns, adds NPC and skin-loading infrastructure, refactors slapper and parkour lifecycles, removes obsolete APIs, adds release checks, and updates server parkour coordinates. ### Changes **World-owner execution and asynchronous player flows** |Layer / File(s)|Summary| |---|---| |**Execution and player callbacks** <br> `.cursor/rules/*`, `pokebedrock/form/*`, `pokebedrock/session/*`, `pokebedrock/handler/*`, `pokebedrock/moderation/*`|Blocking I/O guidance, player data capture, moderation queues, infliction loading, and rank updates now use world-owner-safe callback patterns.| |**World lifecycle and monitoring** <br> `pokebedrock/pokebedrock.go`, `pokebedrock/hider/*`, `pokebedrock/watchdog/*`|World initialization, player acceptance, visibility handling, watchdog probing, and shutdown use updated transaction and task behavior.| **NPC and slapper asset pipeline** |Layer / File(s)|Summary| |---|---| |**NPC and skin infrastructure** <br> `pokebedrock/npc/*`|NPC settings, creation, interaction handlers, model parsing, texture parsing, and skin assembly are added.| |**Slapper loading and integration** <br> `pokebedrock/slapper/*`, `pokebedrock/pokebedrock.go`, `go.mod`, `.golangci.yml`|Slapper assets load with errors and fallback support before transaction-bound spawning and registration; the previous external NPC dependency is removed.| **Parkour transaction and persistence flow** |Layer / File(s)|Summary| |---|---| |**Leaderboard and manager lifecycle** <br> `pokebedrock/parkour/leaderboard.go`, `pokebedrock/parkour/manager.go`, `pokebedrock/command/parkour_reset.go`|Leaderboard snapshots are persisted asynchronously, parkour operations accept transactions, and manager shutdown flushes pending saves.| |**Countdown scheduling** <br> `pokebedrock/parkour/session.go`|Countdowns use cancellable scheduled tasks and generation checks.| |**Server locations** <br> `resources/servers/*.json`|Parkour NPC, leaderboard, start, and end coordinates are updated.| **API cleanup and release validation** |Layer / File(s)|Summary| |---|---| |**API cleanup** <br> `pokebedrock/queue/manager.go`, `pokebedrock/rank/service.go`, `pokebedrock/moderation/service.go`, `pokebedrock/kit/lobby.go`|Deprecated transfer, queue-loading, player-role, and player-infliction helpers are removed or replaced with direct state handling and XUID-based APIs.| |**Release and configuration updates** <br> `.github/workflows/release.yml`, `config.example.toml`, `pokebedrock/config.go`|Release jobs run `go vet ./...` and `go test ./...`; watchdog configuration comments are updated for world-owner task semantics.| **Estimated code review effort:** 4 (Complex) | ~60 minutes **Possibly related PRs** - [smell-of-curry/pokebedrock-hub#45](https://github.com/smell-of-curry/pokebedrock-hub/pull/45): Touches the same parkour manager, leaderboard, session, and reset-command implementation. - [smell-of-curry/pokebedrock-hub#70](https://github.com/smell-of-curry/pokebedrock-hub/pull/70): Overlaps the moderation and infliction execution-flow changes. **Suggested reviewers:** `glancist` </details> <!-- walkthrough_end --> <!-- pre_merge_checks_walkthrough_start --> <details> <summary>🚥 Pre-merge checks | ✅ 4 | ❌ 1</summary> ### ❌ Failed checks (1 warning) | Check name | Status | Explanation | Resolution | | :----------------: | :--------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- | | Docstring Coverage | ⚠️ Warning | Docstring coverage is 53.13% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. | <details> <summary>✅ Passed checks (4 passed)</summary> | Check name | Status | Explanation | | :------------------------: | :------- | :------------------------------------------------------------------------------- | | Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. | | Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. | | Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. | | Title check | ✅ Passed | The title accurately summarizes the main dependency upgrade in the pull request. | </details> </details> <!-- pre_merge_checks_walkthrough_end --> <!-- finishing_touch_checkbox_start --> <details> <summary>✨ Finishing Touches</summary> <details> <summary>🧪 Generate unit tests (beta)</summary> - [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Create PR with unit tests - [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} --> Commit unit tests in branch `v0.11.0-migration` </details> </details> <!-- finishing_touch_checkbox_end --> <!-- tips_start --> --- Thanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=smell-of-curry/pokebedrock-hub&utm_content=88)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. <details> <summary>❤️ Share</summary> - [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai) - [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai) - [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai) - [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code) </details> <sub>Comment `@coderabbitai help` to get the list of available commands.</sub> <!-- tips_end -->
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-13 01:45:59 +00:00
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 6

🧹 Nitpick comments (3)
pokebedrock/slapper/slapper.go (1)

48-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fallback logic is sound; consider logging the fallback.

The retry-to-"black" logic correctly avoids infinite recursion (conf.Identifier == "black" guard) and errors.Is(err, os.ErrNotExist) correctly unwraps through the %w-wrapped chain from preloadSkin/FindFileInPack. One nit: when falling back, the original failure reason is silently discarded — a log/warning noting the fallback would help operators notice missing assets in production.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/slapper/slapper.go` around lines 48 - 67, Add a warning log in
NewSlapper immediately before retrying preloadSkin with the "black" asset,
including conf.Identifier and the original preloadSkin error; keep the existing
fallback conditions and retry behavior unchanged.
pokebedrock/pokebedrock.go (1)

421-424: 🩺 Stability & Availability | 🔵 Trivial | Quick win

Consider a bounded context for the startup world.Call.

context.Background() has no timeout, so if the owner is ever stuck at this point in startup, loadServers() (and thus Start()) hangs indefinitely with no watchdog protection yet running (loadWatchdog runs later in handleWorld). A bounded context would fail fast instead of hanging server startup silently.

⏱️ Proposed bounded-context fix
-	_, err = world.Call(context.Background(), w, func(tx *world.Tx) (struct{}, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	_, err = world.Call(ctx, w, func(tx *world.Tx) (struct{}, error) {
 		slapper.SummonAll(loadedSlappers, tx)
 		return struct{}{}, nil
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/pokebedrock.go` around lines 421 - 424, Update the startup
world.Call in loadServers to use a bounded context with an appropriate timeout
instead of context.Background(). Ensure the timeout error propagates through the
existing err handling so Start() fails promptly if slapper.SummonAll or the
world operation hangs.
pokebedrock/parkour/leaderboard.go (1)

97-104: 🩺 Stability & Availability | 🔵 Trivial | Quick win

Silently swallowed disk write errors.

saveLoop discards errors from os.MkdirAll/os.WriteFile, so persistent write failures (disk full, permissions) go unnoticed and leaderboard data can silently fail to persist across restarts.

♻️ Log write failures
 func (l *leaderboard) saveLoop() {
 	defer close(l.saveDone)
 	for data := range l.saveCh {
-		_ = os.MkdirAll(filepath.Dir(l.path), os.ModePerm)
-		_ = os.WriteFile(l.path, data, os.ModePerm)
+		if err := os.MkdirAll(filepath.Dir(l.path), os.ModePerm); err != nil {
+			log.Printf("parkour: failed to create leaderboard dir %s: %v", filepath.Dir(l.path), err)
+			continue
+		}
+		if err := os.WriteFile(l.path, data, os.ModePerm); err != nil {
+			log.Printf("parkour: failed to write leaderboard %s: %v", l.path, err)
+		}
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/parkour/leaderboard.go` around lines 97 - 104, Update
leaderboard.saveLoop to log failures from both os.MkdirAll and os.WriteFile
instead of discarding their errors. Include the relevant path and error details
in the existing logging mechanism while preserving the queued snapshot
processing and saveDone shutdown behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.cursor/rules/no-blocking-io-in-execworld.mdc:
- Around line 42-54: Make the “GOOD” example self-contained by defining p and
handle within an explicit player.Do callback, or clearly state that they are
supplied by an existing callback. Ensure XUID and handle are captured on-owner
before launching the goroutine, while preserving the off-thread I/O and re-entry
through player.Do.

In `@pokebedrock/hider/hider_test.go`:
- Around line 11-20: The TestExemptedPlayersSkipsServerWithoutSlapper test
leaves its server in the global registry through srv.Register. Add and use a
test cleanup/reset mechanism for the srv registry, preferably via t.Cleanup, so
the registered “missing-slapper” server is removed after the test and cannot
affect later tests.

In `@pokebedrock/moderation/service.go`:
- Around line 392-408: Update SendDetailsOf to extract the player IP with
net.SplitHostPort instead of splitting p.Addr().String() on colons, preserving
correct handling for both IPv4 and bracketed IPv6 addresses before populating
PlayerDetails.IP.

In `@pokebedrock/parkour/manager.go`:
- Around line 62-72: Update the world.Call invocation in NewManager to use a
bounded, cancellable context instead of context.Background(), ensuring the
startup transaction returns when the timeout expires while preserving the
existing error logging and initialization flow.

In `@pokebedrock/queue/manager.go`:
- Around line 261-269: Update the transfer flow around Player.Transfer so the
destination address is resolved before the world transaction callback runs,
preferably when the transfer server configuration is loaded, and reuse the
resolved endpoint during transfer. Avoid calling transferServer.Address() or any
synchronous DNS/lookup operation inside this callback while preserving the
existing failure and queue-reinsert behavior.
- Around line 261-269: The transfer result handling in the queue-processing flow
around transferPlayer.Transfer must distinguish cancellation from successful
transfers. When HandleTransfer cancels and Transfer returns nil, requeue
toTransfer and avoid updating authentication; only execute the existing success
behavior for an actual completed transfer, while preserving the current error
requeue path.

---

Nitpick comments:
In `@pokebedrock/parkour/leaderboard.go`:
- Around line 97-104: Update leaderboard.saveLoop to log failures from both
os.MkdirAll and os.WriteFile instead of discarding their errors. Include the
relevant path and error details in the existing logging mechanism while
preserving the queued snapshot processing and saveDone shutdown behavior.

In `@pokebedrock/pokebedrock.go`:
- Around line 421-424: Update the startup world.Call in loadServers to use a
bounded context with an appropriate timeout instead of context.Background().
Ensure the timeout error propagates through the existing err handling so Start()
fails promptly if slapper.SummonAll or the world operation hangs.

In `@pokebedrock/slapper/slapper.go`:
- Around line 48-67: Add a warning log in NewSlapper immediately before retrying
preloadSkin with the "black" asset, including conf.Identifier and the original
preloadSkin error; keep the existing fallback conditions and retry behavior
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3a26861c-ddfe-4f6e-833d-182487df310b

📥 Commits

Reviewing files that changed from the base of the PR and between 0a4483e3ca and 260e1bb378.

Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (44)
  • .cursor/rules/no-blocking-io-in-execworld.mdc
  • .github/workflows/release.yml
  • .golangci.yml
  • config.example.toml
  • go.mod
  • pokebedrock/command/list.go
  • pokebedrock/command/parkour_reset.go
  • pokebedrock/config.go
  • pokebedrock/form/moderate.go
  • pokebedrock/handler/player.go
  • pokebedrock/hider/hider.go
  • pokebedrock/hider/hider_test.go
  • pokebedrock/kit/lobby.go
  • pokebedrock/moderation/service.go
  • pokebedrock/npc/handler.go
  • pokebedrock/npc/npc.go
  • pokebedrock/npc/settings.go
  • pokebedrock/npc/skin.go
  • pokebedrock/npc/skin_test.go
  • pokebedrock/parkour/leaderboard.go
  • pokebedrock/parkour/leaderboard_test.go
  • pokebedrock/parkour/manager.go
  • pokebedrock/parkour/session.go
  • pokebedrock/pokebedrock.go
  • pokebedrock/queue/manager.go
  • pokebedrock/rank/service.go
  • pokebedrock/session/inflictions.go
  • pokebedrock/session/ranks.go
  • pokebedrock/slapper/manager.go
  • pokebedrock/slapper/slapper.go
  • pokebedrock/slapper/slapper_test.go
  • pokebedrock/slapper/util.go
  • pokebedrock/watchdog/watchdog.go
  • pokebedrock/watchdog/watchdog_test.go
  • resources/servers/black.json
  • resources/servers/diamond.json
  • resources/servers/gold.json
  • resources/servers/moon.json
  • resources/servers/pearl.json
  • resources/servers/ruby.json
  • resources/servers/sapphire.json
  • resources/servers/silver.json
  • resources/servers/sun.json
  • resources/servers/white.json
💤 Files with no reviewable changes (3)
  • pokebedrock/slapper/util.go
  • pokebedrock/rank/service.go
  • .golangci.yml
**Actionable comments posted: 6** <details> <summary>🧹 Nitpick comments (3)</summary><blockquote> <details> <summary>pokebedrock/slapper/slapper.go (1)</summary><blockquote> `48-67`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Fallback logic is sound; consider logging the fallback.** The retry-to-"black" logic correctly avoids infinite recursion (`conf.Identifier == "black"` guard) and `errors.Is(err, os.ErrNotExist)` correctly unwraps through the `%w`-wrapped chain from `preloadSkin`/`FindFileInPack`. One nit: when falling back, the original failure reason is silently discarded — a `log`/warning noting the fallback would help operators notice missing assets in production. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/slapper/slapper.go` around lines 48 - 67, Add a warning log in NewSlapper immediately before retrying preloadSkin with the "black" asset, including conf.Identifier and the original preloadSkin error; keep the existing fallback conditions and retry behavior unchanged. ``` </details> <!-- cr-comment:v1:43b4631a27d306eb6c439258 --> </blockquote></details> <details> <summary>pokebedrock/pokebedrock.go (1)</summary><blockquote> `421-424`: _🩺 Stability & Availability_ | _🔵 Trivial_ | _⚡ Quick win_ **Consider a bounded context for the startup `world.Call`.** `context.Background()` has no timeout, so if the owner is ever stuck at this point in startup, `loadServers()` (and thus `Start()`) hangs indefinitely with no watchdog protection yet running (`loadWatchdog` runs later in `handleWorld`). A bounded context would fail fast instead of hanging server startup silently. <details> <summary>⏱️ Proposed bounded-context fix</summary> ```diff - _, err = world.Call(context.Background(), w, func(tx *world.Tx) (struct{}, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + _, err = world.Call(ctx, w, func(tx *world.Tx) (struct{}, error) { slapper.SummonAll(loadedSlappers, tx) return struct{}{}, nil }) ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/pokebedrock.go` around lines 421 - 424, Update the startup world.Call in loadServers to use a bounded context with an appropriate timeout instead of context.Background(). Ensure the timeout error propagates through the existing err handling so Start() fails promptly if slapper.SummonAll or the world operation hangs. ``` </details> <!-- cr-comment:v1:275e6fa5fc2ad2b8289958f3 --> </blockquote></details> <details> <summary>pokebedrock/parkour/leaderboard.go (1)</summary><blockquote> `97-104`: _🩺 Stability & Availability_ | _🔵 Trivial_ | _⚡ Quick win_ **Silently swallowed disk write errors.** `saveLoop` discards errors from `os.MkdirAll`/`os.WriteFile`, so persistent write failures (disk full, permissions) go unnoticed and leaderboard data can silently fail to persist across restarts. <details> <summary>♻️ Log write failures</summary> ```diff func (l *leaderboard) saveLoop() { defer close(l.saveDone) for data := range l.saveCh { - _ = os.MkdirAll(filepath.Dir(l.path), os.ModePerm) - _ = os.WriteFile(l.path, data, os.ModePerm) + if err := os.MkdirAll(filepath.Dir(l.path), os.ModePerm); err != nil { + log.Printf("parkour: failed to create leaderboard dir %s: %v", filepath.Dir(l.path), err) + continue + } + if err := os.WriteFile(l.path, data, os.ModePerm); err != nil { + log.Printf("parkour: failed to write leaderboard %s: %v", l.path, err) + } } } ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/parkour/leaderboard.go` around lines 97 - 104, Update leaderboard.saveLoop to log failures from both os.MkdirAll and os.WriteFile instead of discarding their errors. Include the relevant path and error details in the existing logging mechanism while preserving the queued snapshot processing and saveDone shutdown behavior. ``` </details> <!-- cr-comment:v1:b4697701727081cfb8a2fb26 --> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Inline comments: In @.cursor/rules/no-blocking-io-in-execworld.mdc: - Around line 42-54: Make the “GOOD” example self-contained by defining p and handle within an explicit player.Do callback, or clearly state that they are supplied by an existing callback. Ensure XUID and handle are captured on-owner before launching the goroutine, while preserving the off-thread I/O and re-entry through player.Do. In `@pokebedrock/hider/hider_test.go`: - Around line 11-20: The TestExemptedPlayersSkipsServerWithoutSlapper test leaves its server in the global registry through srv.Register. Add and use a test cleanup/reset mechanism for the srv registry, preferably via t.Cleanup, so the registered “missing-slapper” server is removed after the test and cannot affect later tests. In `@pokebedrock/moderation/service.go`: - Around line 392-408: Update SendDetailsOf to extract the player IP with net.SplitHostPort instead of splitting p.Addr().String() on colons, preserving correct handling for both IPv4 and bracketed IPv6 addresses before populating PlayerDetails.IP. In `@pokebedrock/parkour/manager.go`: - Around line 62-72: Update the world.Call invocation in NewManager to use a bounded, cancellable context instead of context.Background(), ensuring the startup transaction returns when the timeout expires while preserving the existing error logging and initialization flow. In `@pokebedrock/queue/manager.go`: - Around line 261-269: Update the transfer flow around Player.Transfer so the destination address is resolved before the world transaction callback runs, preferably when the transfer server configuration is loaded, and reuse the resolved endpoint during transfer. Avoid calling transferServer.Address() or any synchronous DNS/lookup operation inside this callback while preserving the existing failure and queue-reinsert behavior. - Around line 261-269: The transfer result handling in the queue-processing flow around transferPlayer.Transfer must distinguish cancellation from successful transfers. When HandleTransfer cancels and Transfer returns nil, requeue toTransfer and avoid updating authentication; only execute the existing success behavior for an actual completed transfer, while preserving the current error requeue path. --- Nitpick comments: In `@pokebedrock/parkour/leaderboard.go`: - Around line 97-104: Update leaderboard.saveLoop to log failures from both os.MkdirAll and os.WriteFile instead of discarding their errors. Include the relevant path and error details in the existing logging mechanism while preserving the queued snapshot processing and saveDone shutdown behavior. In `@pokebedrock/pokebedrock.go`: - Around line 421-424: Update the startup world.Call in loadServers to use a bounded context with an appropriate timeout instead of context.Background(). Ensure the timeout error propagates through the existing err handling so Start() fails promptly if slapper.SummonAll or the world operation hangs. In `@pokebedrock/slapper/slapper.go`: - Around line 48-67: Add a warning log in NewSlapper immediately before retrying preloadSkin with the "black" asset, including conf.Identifier and the original preloadSkin error; keep the existing fallback conditions and retry behavior unchanged. ``` </details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro **Run ID**: `3a26861c-ddfe-4f6e-833d-182487df310b` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 0a4483e3caabb8266e5a5b608e926057a549789a and 260e1bb37886443271c563be827a0f963fb9174b. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `go.sum` is excluded by `!**/*.sum` </details> <details> <summary>📒 Files selected for processing (44)</summary> * `.cursor/rules/no-blocking-io-in-execworld.mdc` * `.github/workflows/release.yml` * `.golangci.yml` * `config.example.toml` * `go.mod` * `pokebedrock/command/list.go` * `pokebedrock/command/parkour_reset.go` * `pokebedrock/config.go` * `pokebedrock/form/moderate.go` * `pokebedrock/handler/player.go` * `pokebedrock/hider/hider.go` * `pokebedrock/hider/hider_test.go` * `pokebedrock/kit/lobby.go` * `pokebedrock/moderation/service.go` * `pokebedrock/npc/handler.go` * `pokebedrock/npc/npc.go` * `pokebedrock/npc/settings.go` * `pokebedrock/npc/skin.go` * `pokebedrock/npc/skin_test.go` * `pokebedrock/parkour/leaderboard.go` * `pokebedrock/parkour/leaderboard_test.go` * `pokebedrock/parkour/manager.go` * `pokebedrock/parkour/session.go` * `pokebedrock/pokebedrock.go` * `pokebedrock/queue/manager.go` * `pokebedrock/rank/service.go` * `pokebedrock/session/inflictions.go` * `pokebedrock/session/ranks.go` * `pokebedrock/slapper/manager.go` * `pokebedrock/slapper/slapper.go` * `pokebedrock/slapper/slapper_test.go` * `pokebedrock/slapper/util.go` * `pokebedrock/watchdog/watchdog.go` * `pokebedrock/watchdog/watchdog_test.go` * `resources/servers/black.json` * `resources/servers/diamond.json` * `resources/servers/gold.json` * `resources/servers/moon.json` * `resources/servers/pearl.json` * `resources/servers/ruby.json` * `resources/servers/sapphire.json` * `resources/servers/silver.json` * `resources/servers/sun.json` * `resources/servers/white.json` </details> <details> <summary>💤 Files with no reviewable changes (3)</summary> * pokebedrock/slapper/util.go * pokebedrock/rank/service.go * .golangci.yml </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
@ -86,7 +87,6 @@ func (k Kick) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) {
## Reference implementations
- `pokebedrock/session/ranks.go` (`rankWorker`) — HTTP runs on the worker
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:45:58 +00:00

🎯 Functional Correctness | 🟡 Minor | Quick win

Make the “GOOD” example self-contained.

Lines 43-44 use p and handle without defining them, so the example does not show how data is captured on-owner and cannot be copied as written. Wrap the capture in an explicit player.Do callback or state that these values come from an existing callback.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.cursor/rules/no-blocking-io-in-execworld.mdc around lines 42 - 54, Make the
“GOOD” example self-contained by defining p and handle within an explicit
player.Do callback, or clearly state that they are supplied by an existing
callback. Ensure XUID and handle are captured on-owner before launching the
goroutine, while preserving the off-thread I/O and re-entry through player.Do.

Addressed in commit 8fd91c3

_🎯 Functional Correctness_ | _🟡 Minor_ | _⚡ Quick win_ **Make the “GOOD” example self-contained.** Lines 43-44 use `p` and `handle` without defining them, so the example does not show how data is captured on-owner and cannot be copied as written. Wrap the capture in an explicit `player.Do` callback or state that these values come from an existing callback. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.cursor/rules/no-blocking-io-in-execworld.mdc around lines 42 - 54, Make the “GOOD” example self-contained by defining p and handle within an explicit player.Do callback, or clearly state that they are supplied by an existing callback. Ensure XUID and handle are captured on-owner before launching the goroutine, while preserving the off-thread I/O and re-entry through player.Do. ``` </details> <!-- fingerprinting:phantom:poseidon:luna --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:45674da2a7de1712eb2e262b --> <!-- This is an auto-generated reply by CodeRabbit --> ✅ Addressed in commit 8fd91c3
@ -0,0 +21,4 @@
if handles := NewManager().exemptedPlayers(); len(handles) != 0 {
t.Fatalf("expected no exempted handles, got %d", len(handles))
}
}
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:45:58 +00:00

🩺 Stability & Availability | 🟡 Minor | Quick win

🧩 Analysis chain

🏁 Script executed:

rg -n 'func Register|func Unregister|srv.Register' pokebedrock/srv pokebedrock/hider

Repository: smell-of-curry/pokebedrock-hub

Length of output: 291


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline pokebedrock/srv/manager.go --view expanded || true
printf '\n--- manager.go ---\n'
cat -n pokebedrock/srv/manager.go

printf '\n--- registry-related references ---\n'
rg -n 'Register\(|Unregister\(|Reset\(|servers|registry|NewServer\(' pokebedrock/srv pokebedrock -g '!**/*_test.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 6341


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '%s\n' '--- hider_test.go ---'
cat -n pokebedrock/hider/hider_test.go | sed -n '1,120p'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 780


Clean up the test server registration
srv.Register(...) writes to the package-global registry in pokebedrock/srv/manager.go, and there’s no unregister/reset path. Add a test cleanup/reset helper or isolate the registry so this test doesn’t leak state into later ones.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/hider/hider_test.go` around lines 11 - 20, The
TestExemptedPlayersSkipsServerWithoutSlapper test leaves its server in the
global registry through srv.Register. Add and use a test cleanup/reset mechanism
for the srv registry, preferably via t.Cleanup, so the registered
“missing-slapper” server is removed after the test and cannot affect later
tests.

Addressed in commit 8fd91c3

_🩺 Stability & Availability_ | _🟡 Minor_ | _⚡ Quick win_ <details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell rg -n 'func Register|func Unregister|srv.Register' pokebedrock/srv pokebedrock/hider ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 291 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail ast-grep outline pokebedrock/srv/manager.go --view expanded || true printf '\n--- manager.go ---\n' cat -n pokebedrock/srv/manager.go printf '\n--- registry-related references ---\n' rg -n 'Register\(|Unregister\(|Reset\(|servers|registry|NewServer\(' pokebedrock/srv pokebedrock -g '!**/*_test.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 6341 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail printf '%s\n' '--- hider_test.go ---' cat -n pokebedrock/hider/hider_test.go | sed -n '1,120p' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 780 --- </details> **Clean up the test server registration** `srv.Register(...)` writes to the package-global registry in `pokebedrock/srv/manager.go`, and there’s no unregister/reset path. Add a test cleanup/reset helper or isolate the registry so this test doesn’t leak state into later ones. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/hider/hider_test.go` around lines 11 - 20, The TestExemptedPlayersSkipsServerWithoutSlapper test leaves its server in the global registry through srv.Register. Add and use a test cleanup/reset mechanism for the srv registry, preferably via t.Cleanup, so the registered “missing-slapper” server is removed after the test and cannot affect later tests. ``` </details> <!-- fingerprinting:phantom:poseidon:luna --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:82ac39fa276ea5e005f348ec --> <!-- This is an auto-generated reply by CodeRabbit --> ✅ Addressed in commit 8fd91c3
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:45:58 +00:00

🗄️ Data Integrity & Integration | 🟡 Minor | Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant file and nearby definitions.
git ls-files 'pokebedrock/**/service.go' 'pokebedrock/**/**/*.go' | sed -n '1,200p'
printf '\n--- moderation/service.go excerpt ---\n'
sed -n '1,260p' pokebedrock/moderation/service.go
printf '\n--- moderation/service.go later excerpt ---\n'
sed -n '260,460p' pokebedrock/moderation/service.go

# Find the player.Addr() type/source and any other IP extraction uses.
printf '\n--- player.Addr references ---\n'
rg -n 'Addr\(\)|SplitHostPort|strings\.Split\(p\.Addr\(\)\.String\(\), ":"\)' pokebedrock -g '*.go'

# Inspect the player package/type definitions if present.
fd -a 'player' pokebedrock
rg -n 'type .*Player|func \(.*\) Addr\(' pokebedrock -g '*.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 11380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- moderation/model.go ---\n'
sed -n '1,220p' pokebedrock/moderation/model.go

printf '\n--- IP-related uses across moderation ---\n'
rg -n '\bIP\b|Addr\(\)\.String\(\)|SplitHostPort|strings\.Split' pokebedrock/moderation -g '*.go'

printf '\n--- dragonfly/player Addr docs in module cache if available ---\n'
go env GOPATH GOMODCACHE 2>/dev/null || true

Repository: smell-of-curry/pokebedrock-hub

Length of output: 3243


🏁 Script executed:

#!/bin/bash
set -euo pipefail

MODCACHE="$(go env GOMODCACHE)"
printf 'Module cache: %s\n' "$MODCACHE"

# Find Dragonfly player address implementation / docs.
rg -n 'func \(.*\) Addr\(|type .*Addr|String\(\) string|host:port|\[::1\]|SplitHostPort' \
  "$MODCACHE"/github.com/df-mc/dragonfly* \
  -g '*.go' -g '*.md' -g '*.txt' | sed -n '1,220p'

# Narrow search for player.Player and Addr method.
fd -a 'player' "$MODCACHE"/github.com/df-mc/dragonfly* | sed -n '1,120p'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 20013


🏁 Script executed:

#!/bin/bash
set -euo pipefail

MODCACHE="$(go env GOMODCACHE)"

printf '\n--- dragonfly server/player/player.go (Addr implementation) ---\n'
sed -n '150,220p' "$MODCACHE"/github.com/df-mc/dragonfly@v0.11.0/server/player/player.go

printf '\n--- dragonfly server/session/session.go (Addr implementation) ---\n'
sed -n '330,390p' "$MODCACHE"/github.com/df-mc/dragonfly@v0.11.0/server/session/session.go

printf '\n--- small Go probe for Split vs SplitHostPort ---\n'
cat <<'EOF' >/tmp/ip_probe.go
package main

import (
	"fmt"
	"net"
	"strings"
)

func main() {
	samples := []string{
		"127.0.0.1:19132",
		"[::1]:19132",
		"::1:19132",
		"localhost:19132",
	}
	for _, s := range samples {
		fmt.Printf("%q -> Split[0]=%q\n", s, strings.Split(s, ":")[0])
		host, port, err := net.SplitHostPort(s)
		fmt.Printf("   SplitHostPort host=%q port=%q err=%v\n", host, port, err)
	}
}
EOF
go run /tmp/ip_probe.go

Repository: smell-of-curry/pokebedrock-hub

Length of output: 5287


Use net.SplitHostPort for the player IP. strings.Split(p.Addr().String(), ":")[0] breaks on bracketed IPv6 addresses like [::1]:19132 and sends a malformed ip value to the moderation API. net.SplitHostPort handles both IPv4 and IPv6.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/moderation/service.go` around lines 392 - 408, Update
SendDetailsOf to extract the player IP with net.SplitHostPort instead of
splitting p.Addr().String() on colons, preserving correct handling for both IPv4
and bracketed IPv6 addresses before populating PlayerDetails.IP.

Addressed in commit 8fd91c3

_🗄️ Data Integrity & Integration_ | _🟡 Minor_ | _⚡ Quick win_ <details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail # Inspect the relevant file and nearby definitions. git ls-files 'pokebedrock/**/service.go' 'pokebedrock/**/**/*.go' | sed -n '1,200p' printf '\n--- moderation/service.go excerpt ---\n' sed -n '1,260p' pokebedrock/moderation/service.go printf '\n--- moderation/service.go later excerpt ---\n' sed -n '260,460p' pokebedrock/moderation/service.go # Find the player.Addr() type/source and any other IP extraction uses. printf '\n--- player.Addr references ---\n' rg -n 'Addr\(\)|SplitHostPort|strings\.Split\(p\.Addr\(\)\.String\(\), ":"\)' pokebedrock -g '*.go' # Inspect the player package/type definitions if present. fd -a 'player' pokebedrock rg -n 'type .*Player|func \(.*\) Addr\(' pokebedrock -g '*.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 11380 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail printf '\n--- moderation/model.go ---\n' sed -n '1,220p' pokebedrock/moderation/model.go printf '\n--- IP-related uses across moderation ---\n' rg -n '\bIP\b|Addr\(\)\.String\(\)|SplitHostPort|strings\.Split' pokebedrock/moderation -g '*.go' printf '\n--- dragonfly/player Addr docs in module cache if available ---\n' go env GOPATH GOMODCACHE 2>/dev/null || true ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 3243 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail MODCACHE="$(go env GOMODCACHE)" printf 'Module cache: %s\n' "$MODCACHE" # Find Dragonfly player address implementation / docs. rg -n 'func \(.*\) Addr\(|type .*Addr|String\(\) string|host:port|\[::1\]|SplitHostPort' \ "$MODCACHE"/github.com/df-mc/dragonfly* \ -g '*.go' -g '*.md' -g '*.txt' | sed -n '1,220p' # Narrow search for player.Player and Addr method. fd -a 'player' "$MODCACHE"/github.com/df-mc/dragonfly* | sed -n '1,120p' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 20013 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail MODCACHE="$(go env GOMODCACHE)" printf '\n--- dragonfly server/player/player.go (Addr implementation) ---\n' sed -n '150,220p' "$MODCACHE"/github.com/df-mc/dragonfly@v0.11.0/server/player/player.go printf '\n--- dragonfly server/session/session.go (Addr implementation) ---\n' sed -n '330,390p' "$MODCACHE"/github.com/df-mc/dragonfly@v0.11.0/server/session/session.go printf '\n--- small Go probe for Split vs SplitHostPort ---\n' cat <<'EOF' >/tmp/ip_probe.go package main import ( "fmt" "net" "strings" ) func main() { samples := []string{ "127.0.0.1:19132", "[::1]:19132", "::1:19132", "localhost:19132", } for _, s := range samples { fmt.Printf("%q -> Split[0]=%q\n", s, strings.Split(s, ":")[0]) host, port, err := net.SplitHostPort(s) fmt.Printf(" SplitHostPort host=%q port=%q err=%v\n", host, port, err) } } EOF go run /tmp/ip_probe.go ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 5287 --- </details> **Use `net.SplitHostPort` for the player IP.** `strings.Split(p.Addr().String(), ":")[0]` breaks on bracketed IPv6 addresses like `[::1]:19132` and sends a malformed `ip` value to the moderation API. `net.SplitHostPort` handles both IPv4 and IPv6. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/moderation/service.go` around lines 392 - 408, Update SendDetailsOf to extract the player IP with net.SplitHostPort instead of splitting p.Addr().String() on colons, preserving correct handling for both IPv4 and bracketed IPv6 addresses before populating PlayerDetails.IP. ``` </details> <!-- fingerprinting:phantom:medusa:beignet --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:450b483e075abc0fd86dbfb1 --> <!-- This is an auto-generated reply by CodeRabbit --> ✅ Addressed in commit 8fd91c3
@ -57,41 +59,48 @@ func NewManager(log *slog.Logger, w *world.World, cfg Config) *Manager {
for _, course := range cfg.Courses {
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:45:58 +00:00

🩺 Stability & Availability | 🟠 Major | Quick win

Blocking world.Call during startup has no timeout.

world.Call(context.Background(), w, ...) will block NewManager indefinitely if the world owner never processes the transaction (e.g., world already shutting down or stalled). Since this runs on what's presumably a request/startup thread (not a world-owner callback), it should carry a bounded context so a stuck owner can't hang server initialization forever.

🛡️ Suggested fix
-	if _, err := world.Call(context.Background(), w, func(tx *world.Tx) (struct{}, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+	if _, err := world.Call(ctx, w, func(tx *world.Tx) (struct{}, error) {
 		m.spawnNPCs(tx)
 		m.spawnLeaderboardTexts(tx)
 		return struct{}{}, nil
 	}); err != nil {
 		log.Error("parkour entities could not be spawned", "error", err)
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if _, err := world.Call(ctx, w, func(tx *world.Tx) (struct{}, error) {
		m.spawnNPCs(tx)
		m.spawnLeaderboardTexts(tx)
		return struct{}{}, nil
	}); err != nil {
		log.Error("parkour entities could not be spawned", "error", err)
	}

	globalManager = m
	return m
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/parkour/manager.go` around lines 62 - 72, Update the world.Call
invocation in NewManager to use a bounded, cancellable context instead of
context.Background(), ensuring the startup transaction returns when the timeout
expires while preserving the existing error logging and initialization flow.

Confirmed as addressed by @smell-of-curry

_🩺 Stability & Availability_ | _🟠 Major_ | _⚡ Quick win_ **Blocking `world.Call` during startup has no timeout.** `world.Call(context.Background(), w, ...)` will block `NewManager` indefinitely if the world owner never processes the transaction (e.g., world already shutting down or stalled). Since this runs on what's presumably a request/startup thread (not a world-owner callback), it should carry a bounded context so a stuck owner can't hang server initialization forever. <details> <summary>🛡️ Suggested fix</summary> ```diff - if _, err := world.Call(context.Background(), w, func(tx *world.Tx) (struct{}, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if _, err := world.Call(ctx, w, func(tx *world.Tx) (struct{}, error) { m.spawnNPCs(tx) m.spawnLeaderboardTexts(tx) return struct{}{}, nil }); err != nil { log.Error("parkour entities could not be spawned", "error", err) } ``` </details> <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if _, err := world.Call(ctx, w, func(tx *world.Tx) (struct{}, error) { m.spawnNPCs(tx) m.spawnLeaderboardTexts(tx) return struct{}{}, nil }); err != nil { log.Error("parkour entities could not be spawned", "error", err) } globalManager = m return m } ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/parkour/manager.go` around lines 62 - 72, Update the world.Call invocation in NewManager to use a bounded, cancellable context instead of context.Background(), ensuring the startup transaction returns when the timeout expires while preserving the existing error logging and initialization flow. ``` </details> <!-- fingerprinting:phantom:poseidon:beignet --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:c09603b8b0d4f15ac16be670 --> <!-- This is an auto-generated reply by CodeRabbit --> ✅ Confirmed as addressed by @smell-of-curry <!-- This is an auto-generated comment by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:45:58 +00:00

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 3 'net\.ResolveUDPAddr|\.Address\(\)|\.Transfer\(' pokebedrock --glob '*.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 1539


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== manager.go context =="
sed -n '220,290p' pokebedrock/queue/manager.go

echo
echo "== Dragonfly dependency version =="
sed -n '1,120p' go.mod

echo
echo "== Search for Update signature and world.Tx usage =="
rg -n -C 2 'func \(.*Manager.*Update|world\.Tx|type .*Manager' pokebedrock --glob '*.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 22229


🏁 Script executed:

#!/bin/bash
set -euo pipefail

moddir=$(go env GOPATH)/pkg/mod
echo "== possible dragonfly module paths =="
find "$moddir" -path '*github.com/df-mc/dragonfly*' -maxdepth 4 -type f \( -name 'player.go' -o -name '*.go' \) 2>/dev/null | head -n 50

echo
echo "== transfer implementation search =="
rg -n -C 4 'func \(.*Transfer|Transfer\(' "$moddir"/github.com/df-mc/dragonfly* --glob '*.go' 2>/dev/null | head -n 200

Repository: smell-of-curry/pokebedrock-hub

Length of output: 9739


Resolve the transfer address before Update pokebedrock/queue/manager.go:263Player.Transfer calls net.ResolveUDPAddr synchronously, so transferServer.Address() can block this *world.Tx callback on DNS/lookup work. Pre-resolve the endpoint when the server config is loaded, or use a non-resolving transfer path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/queue/manager.go` around lines 261 - 269, Update the transfer
flow around Player.Transfer so the destination address is resolved before the
world transaction callback runs, preferably when the transfer server
configuration is loaded, and reuse the resolved endpoint during transfer. Avoid
calling transferServer.Address() or any synchronous DNS/lookup operation inside
this callback while preserving the existing failure and queue-reinsert behavior.

Sources: Coding guidelines, MCP tools


🎯 Functional Correctness | 🟠 Major | Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 4 '\bHandleTransfer\b|\bTransfer\(' pokebedrock --glob '*.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 792


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant queue manager code in context.
sed -n '230,290p' pokebedrock/queue/manager.go

# Check the module dependency version for Dragonfly.
sed -n '1,220p' go.mod

# Look for any local references to transfer cancellation or requeue logic.
rg -n -C 3 'HandleTransfer|Transfer\(|requeue|queue entry|cancel' pokebedrock --glob '*.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 14635


🌐 Web query:

Dragonfly v0.11.0 player.Transfer HandleTransfer nil cancel semantics

💡 Result:

In the context of the Dragonfly project (specifically the Minecraft Bedrock Edition server software by df-mc), event handlers such as HandleTransfer use an event.Context to manage the lifecycle of an event [1][2]. When an event handler is triggered, it receives a context that provides the ability to cancel the event. Calling ctx.Cancel() on the provided *event.Context stops the associated action from occurring [1]. In Dragonfly's event handling system, this is the standard mechanism for preventing an action [1]. While some Go APIs use nil to represent a lack of context or a default state, HandleTransfer specifically expects a valid *event.Context (or equivalent context type) to function correctly [1][3]. Providing a nil context or attempting to interact with a null context in this handler is generally unsupported and will likely lead to a runtime panic when the server attempts to access the context's methods [1][2]. To cancel a transfer, you must use the Cancel() method on a non-nil context object provided by the event system [1]. If you are experiencing issues with transfer semantics in Dragonfly, ensure you are utilizing the event.Context provided by the function signature rather than passing nil [1]. If a transfer is not being cancelled as expected, confirm that the handler is correctly registered and that ctx.Cancel() is being invoked before the event completes [1].

Citations:


🌐 Web query:

df-mc/dragonfly v0.11.0 player.Transfer HandleTransfer return nil canceled source

💡 Result:

In the Dragonfly server software for Minecraft: Bedrock Edition, event cancellation is handled consistently across its player.Handler interface [1]. When a handler method, such as a hypothetical transfer-related event, receives a *event.Context or similar context type, you can cancel the action by calling ctx.Cancel() [1][2]. Dragonfly does not typically use a "return nil" pattern to indicate cancellation in its event handler signatures [1][2]; instead, the idiomatic approach is to use the context provided as an argument to the method [1][3]. If you are encountering a situation where you intend to cancel a player transfer, you must: 1. Ensure your handler method accepts the appropriate context (e.g., *player.Context or *event.Context) [1][3]. 2. Invoke ctx.Cancel() within the body of that method to prevent the event from proceeding [1][2]. If you are referencing a specific API signature involving HandleTransfer, verify that the context object passed to your function supports the Cancel() method, as Dragonfly's event system is built upon this event.Context pattern [1][4]. Returning nil generally does not trigger cancellation in Dragonfly's event architecture [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "GOPATH=$(go env GOPATH)"
echo "GOMODCACHE=$(go env GOMODCACHE)"

# Find the Dragonfly module source if it exists in the cache.
fd -a 'player.go' "$(go env GOMODCACHE)" | rg '/github\.com/df-mc/dragonfly(@|/).*/player\.go$' || true
fd -a 'player.go' "$(go env GOPATH)/pkg/mod" | rg '/github\.com/df-mc/dragonfly(@|/).*/player\.go$' || true

# Search for transfer-related handlers and return semantics in the cached Dragonfly source.
rg -n -C 4 'HandleTransfer|func .*Transfer\(|Transfer\(' "$(go env GOMODCACHE)" --glob '*/github.com/df-mc/dragonfly*/**/*.go' || true

Repository: smell-of-curry/pokebedrock-hub

Length of output: 572


🏁 Script executed:

#!/bin/bash
set -euo pipefail

DRAGONFLY="/home/jailuser/go/pkg/mod/github.com/df-mc/dragonfly@v0.11.0"

# Map the relevant files first.
ast-grep outline "$DRAGONFLY/server/player/player.go" --view expanded || true
ast-grep outline "$DRAGONFLY/server/session/player.go" --view expanded || true

# Read the relevant sections with line numbers.
sed -n '1,260p' "$DRAGONFLY/server/player/player.go"
printf '\n--- session/player.go ---\n'
sed -n '1,260p' "$DRAGONFLY/server/session/player.go"

# Narrow searches for transfer and handler-related semantics.
rg -n -C 4 'HandleTransfer|Transfer\(|cancel|Cancelled|Err|nil' "$DRAGONFLY/server" --glob '*.go'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 50387


🏁 Script executed:

#!/bin/bash
set -euo pipefail

DRAGONFLY="/home/jailuser/go/pkg/mod/github.com/df-mc/dragonfly@v0.11.0"

# Find exact transfer-related symbols and print only the surrounding lines.
rg -n -C 8 'func .*Transfer\(|HandleTransfer|transfer' "$DRAGONFLY/server/player/player.go" "$DRAGONFLY/server/session/player.go" --glob '*.go' | sed -n '1,220p'

# Also inspect any event types tied to transfer handling.
rg -n -C 6 'type .*Transfer|HandleTransfer' "$DRAGONFLY/server" --glob '*.go' | sed -n '1,220p'

Repository: smell-of-curry/pokebedrock-hub

Length of output: 11598


Cancelled transfers still consume the queue entry pokebedrock/queue/manager.go:261-269
player.Transfer returns nil when HandleTransfer cancels, so this path treats a cancelled transfer as success: the entry is already removed, it is not requeued, and auth is updated. Requeue or gate the success branch on the cancellation case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pokebedrock/queue/manager.go` around lines 261 - 269, The transfer result
handling in the queue-processing flow around transferPlayer.Transfer must
distinguish cancellation from successful transfers. When HandleTransfer cancels
and Transfer returns nil, requeue toTransfer and avoid updating authentication;
only execute the existing success behavior for an actual completed transfer,
while preserving the current error requeue path.

Source: MCP tools

_🩺 Stability & Availability_ | _🟠 Major_ | _🏗️ Heavy lift_ <details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell #!/bin/bash rg -n -C 3 'net\.ResolveUDPAddr|\.Address\(\)|\.Transfer\(' pokebedrock --glob '*.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 1539 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail echo "== manager.go context ==" sed -n '220,290p' pokebedrock/queue/manager.go echo echo "== Dragonfly dependency version ==" sed -n '1,120p' go.mod echo echo "== Search for Update signature and world.Tx usage ==" rg -n -C 2 'func \(.*Manager.*Update|world\.Tx|type .*Manager' pokebedrock --glob '*.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 22229 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail moddir=$(go env GOPATH)/pkg/mod echo "== possible dragonfly module paths ==" find "$moddir" -path '*github.com/df-mc/dragonfly*' -maxdepth 4 -type f \( -name 'player.go' -o -name '*.go' \) 2>/dev/null | head -n 50 echo echo "== transfer implementation search ==" rg -n -C 4 'func \(.*Transfer|Transfer\(' "$moddir"/github.com/df-mc/dragonfly* --glob '*.go' 2>/dev/null | head -n 200 ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 9739 --- </details> **Resolve the transfer address before `Update`** `pokebedrock/queue/manager.go:263` — `Player.Transfer` calls `net.ResolveUDPAddr` synchronously, so `transferServer.Address()` can block this `*world.Tx` callback on DNS/lookup work. Pre-resolve the endpoint when the server config is loaded, or use a non-resolving transfer path. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/queue/manager.go` around lines 261 - 269, Update the transfer flow around Player.Transfer so the destination address is resolved before the world transaction callback runs, preferably when the transfer server configuration is loaded, and reuse the resolved endpoint during transfer. Avoid calling transferServer.Address() or any synchronous DNS/lookup operation inside this callback while preserving the existing failure and queue-reinsert behavior. ``` </details> <!-- fingerprinting:phantom:poseidon:luna --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:49a64ce92c67003dc6127627 --> _Sources: Coding guidelines, MCP tools_ --- _🎯 Functional Correctness_ | _🟠 Major_ | _⚡ Quick win_ <details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell #!/bin/bash rg -n -C 4 '\bHandleTransfer\b|\bTransfer\(' pokebedrock --glob '*.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 792 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail # Inspect the relevant queue manager code in context. sed -n '230,290p' pokebedrock/queue/manager.go # Check the module dependency version for Dragonfly. sed -n '1,220p' go.mod # Look for any local references to transfer cancellation or requeue logic. rg -n -C 3 'HandleTransfer|Transfer\(|requeue|queue entry|cancel' pokebedrock --glob '*.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 14635 --- 🌐 Web query: `Dragonfly v0.11.0 player.Transfer HandleTransfer nil cancel semantics` 💡 Result: In the context of the Dragonfly project (specifically the Minecraft Bedrock Edition server software by df-mc), event handlers such as `HandleTransfer` use an `event.Context` to manage the lifecycle of an event [1][2]. When an event handler is triggered, it receives a context that provides the ability to cancel the event. Calling `ctx.Cancel()` on the provided `*event.Context` stops the associated action from occurring [1]. In Dragonfly's event handling system, this is the standard mechanism for preventing an action [1]. While some Go APIs use `nil` to represent a lack of context or a default state, `HandleTransfer` specifically expects a valid `*event.Context` (or equivalent context type) to function correctly [1][3]. Providing a `nil` context or attempting to interact with a null context in this handler is generally unsupported and will likely lead to a runtime panic when the server attempts to access the context's methods [1][2]. To cancel a transfer, you must use the `Cancel()` method on a non-nil context object provided by the event system [1]. If you are experiencing issues with transfer semantics in Dragonfly, ensure you are utilizing the `event.Context` provided by the function signature rather than passing `nil` [1]. If a transfer is not being cancelled as expected, confirm that the handler is correctly registered and that `ctx.Cancel()` is being invoked before the event completes [1]. Citations: - 1: https://github.com/df-mc/dragonfly/wiki/Event-Handlers - 2: https://p.rst.im/q/github.com/df-mc/dragonfly/wiki/World-Transactions - 3: https://pkg.go.dev/github.com/oriumgames/bevi-df/dragonfly --- 🌐 Web query: `df-mc/dragonfly v0.11.0 player.Transfer HandleTransfer return nil canceled source` 💡 Result: In the Dragonfly server software for Minecraft: Bedrock Edition, event cancellation is handled consistently across its `player.Handler` interface [1]. When a handler method, such as a hypothetical transfer-related event, receives a `*event.Context` or similar context type, you can cancel the action by calling `ctx.Cancel()` [1][2]. Dragonfly does not typically use a "return nil" pattern to indicate cancellation in its event handler signatures [1][2]; instead, the idiomatic approach is to use the context provided as an argument to the method [1][3]. If you are encountering a situation where you intend to cancel a player transfer, you must: 1. Ensure your handler method accepts the appropriate context (e.g., `*player.Context` or `*event.Context`) [1][3]. 2. Invoke `ctx.Cancel()` within the body of that method to prevent the event from proceeding [1][2]. If you are referencing a specific API signature involving `HandleTransfer`, verify that the context object passed to your function supports the `Cancel()` method, as Dragonfly's event system is built upon this `event.Context` pattern [1][4]. Returning `nil` generally does not trigger cancellation in Dragonfly's event architecture [1]. Citations: - 1: https://github.com/df-mc/dragonfly/wiki/Event-Handlers - 2: https://pkg.go.dev/github.com/ahnsunggwan45/df-plugin - 3: https://p.rst.im/q/github.com/df-mc/dragonfly/wiki/World-Transactions - 4: https://pkg.go.dev/github.com/oriumgames/bevi-df/dragonfly --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail echo "GOPATH=$(go env GOPATH)" echo "GOMODCACHE=$(go env GOMODCACHE)" # Find the Dragonfly module source if it exists in the cache. fd -a 'player.go' "$(go env GOMODCACHE)" | rg '/github\.com/df-mc/dragonfly(@|/).*/player\.go$' || true fd -a 'player.go' "$(go env GOPATH)/pkg/mod" | rg '/github\.com/df-mc/dragonfly(@|/).*/player\.go$' || true # Search for transfer-related handlers and return semantics in the cached Dragonfly source. rg -n -C 4 'HandleTransfer|func .*Transfer\(|Transfer\(' "$(go env GOMODCACHE)" --glob '*/github.com/df-mc/dragonfly*/**/*.go' || true ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 572 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail DRAGONFLY="/home/jailuser/go/pkg/mod/github.com/df-mc/dragonfly@v0.11.0" # Map the relevant files first. ast-grep outline "$DRAGONFLY/server/player/player.go" --view expanded || true ast-grep outline "$DRAGONFLY/server/session/player.go" --view expanded || true # Read the relevant sections with line numbers. sed -n '1,260p' "$DRAGONFLY/server/player/player.go" printf '\n--- session/player.go ---\n' sed -n '1,260p' "$DRAGONFLY/server/session/player.go" # Narrow searches for transfer and handler-related semantics. rg -n -C 4 'HandleTransfer|Transfer\(|cancel|Cancelled|Err|nil' "$DRAGONFLY/server" --glob '*.go' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 50387 --- 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail DRAGONFLY="/home/jailuser/go/pkg/mod/github.com/df-mc/dragonfly@v0.11.0" # Find exact transfer-related symbols and print only the surrounding lines. rg -n -C 8 'func .*Transfer\(|HandleTransfer|transfer' "$DRAGONFLY/server/player/player.go" "$DRAGONFLY/server/session/player.go" --glob '*.go' | sed -n '1,220p' # Also inspect any event types tied to transfer handling. rg -n -C 6 'type .*Transfer|HandleTransfer' "$DRAGONFLY/server" --glob '*.go' | sed -n '1,220p' ``` Repository: smell-of-curry/pokebedrock-hub Length of output: 11598 --- </details> **Cancelled transfers still consume the queue entry** `pokebedrock/queue/manager.go:261-269` `player.Transfer` returns `nil` when `HandleTransfer` cancels, so this path treats a cancelled transfer as success: the entry is already removed, it is not requeued, and auth is updated. Requeue or gate the success branch on the cancellation case. <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pokebedrock/queue/manager.go` around lines 261 - 269, The transfer result handling in the queue-processing flow around transferPlayer.Transfer must distinguish cancellation from successful transfers. When HandleTransfer cancels and Transfer returns nil, requeue toTransfer and avoid updating authentication; only execute the existing success behavior for an actual completed transfer, while preserving the current error requeue path. ``` </details> <!-- fingerprinting:phantom:poseidon:luna --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:bf2c76d617006f833c770031 --> _Source: MCP tools_ <!-- This is an auto-generated reply by CodeRabbit -->
smell-of-curry (Migrated from github.com) reviewed 2026-07-13 01:53:02 +00:00
@ -0,0 +21,4 @@
if handles := NewManager().exemptedPlayers(); len(handles) != 0 {
t.Fatalf("expected no exempted handles, got %d", len(handles))
}
}
smell-of-curry (Migrated from github.com) commented 2026-07-13 01:53:02 +00:00

Fixed in 8fd91c3. Added srv.Unregister and registered t.Cleanup so this test cannot leak its server into later tests.

Fixed in 8fd91c3. Added srv.Unregister and registered t.Cleanup so this test cannot leak its server into later tests.
smell-of-curry (Migrated from github.com) reviewed 2026-07-13 01:53:02 +00:00
@ -86,7 +87,6 @@ func (k Kick) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) {
## Reference implementations
- `pokebedrock/session/ranks.go` (`rankWorker`) — HTTP runs on the worker
smell-of-curry (Migrated from github.com) commented 2026-07-13 01:53:02 +00:00

Fixed in 8fd91c3. The example now explicitly states that it runs inside an existing owner callback where p is defined.

Fixed in 8fd91c3. The example now explicitly states that it runs inside an existing owner callback where p is defined.
smell-of-curry (Migrated from github.com) reviewed 2026-07-13 01:53:02 +00:00
smell-of-curry (Migrated from github.com) commented 2026-07-13 01:53:02 +00:00

Fixed in 8fd91c3. Player addresses now use net.SplitHostPort, with IPv4 and bracketed IPv6 regression coverage.

Fixed in 8fd91c3. Player addresses now use net.SplitHostPort, with IPv4 and bracketed IPv6 regression coverage.
smell-of-curry (Migrated from github.com) reviewed 2026-07-13 01:53:02 +00:00
smell-of-curry (Migrated from github.com) commented 2026-07-13 01:53:02 +00:00

Address-resolution concern fixed in 8fd91c3: server endpoints are resolved and canonicalized during config loading, off the world owner. The cancellation concern does not apply to this hub: PlayerHandler embeds NopHandler and does not override HandleTransfer, so no current path cancels Transfer.

Address-resolution concern fixed in 8fd91c3: server endpoints are resolved and canonicalized during config loading, off the world owner. The cancellation concern does not apply to this hub: PlayerHandler embeds NopHandler and does not override HandleTransfer, so no current path cancels Transfer.
smell-of-curry (Migrated from github.com) reviewed 2026-07-13 01:53:02 +00:00
@ -57,41 +59,48 @@ func NewManager(log *slog.Logger, w *world.World, cfg Config) *Manager {
for _, course := range cfg.Courses {
smell-of-curry (Migrated from github.com) commented 2026-07-13 01:53:02 +00:00

Fixed in 8fd91c3. NewManager now receives a caller-bounded context using the configured world-owner timeout.

Fixed in 8fd91c3. NewManager now receives a caller-bounded context using the configured world-owner timeout.
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-13 01:53:16 +00:00
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:53:16 +00:00

@smell-of-curry, thanks for confirming — glad the fix and regression tests are in. Closing this one out.

(=^・ω・^=)

`@smell-of-curry`, thanks for confirming — glad the fix and regression tests are in. Closing this one out. (=^・ω・^=) <!-- <review_comment_addressed> --> <!-- This is an auto-generated reply by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-13 01:53:17 +00:00
@ -0,0 +21,4 @@
if handles := NewManager().exemptedPlayers(); len(handles) != 0 {
t.Fatalf("expected no exempted handles, got %d", len(handles))
}
}
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:53:16 +00:00

@smell-of-curry, thanks for confirming — that resolves the leaked global registry state concern. 🐇

`@smell-of-curry`, thanks for confirming — that resolves the leaked global registry state concern. 🐇✨ <!-- <review_comment_addressed> --> <!-- This is an auto-generated reply by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-13 01:53:18 +00:00
@ -57,41 +59,48 @@ func NewManager(log *slog.Logger, w *world.World, cfg Config) *Manager {
for _, course := range cfg.Courses {
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:53:18 +00:00

@smell-of-curry, thanks for confirming! Using a caller-bounded context tied to the configured world-owner timeout is a solid approach — it ensures the timeout stays consistent with the rest of the watchdog/world-owner timeout configuration rather than a hardcoded value. Appreciate the quick fix.

`@smell-of-curry`, thanks for confirming! Using a caller-bounded context tied to the configured world-owner timeout is a solid approach — it ensures the timeout stays consistent with the rest of the watchdog/world-owner timeout configuration rather than a hardcoded value. Appreciate the quick fix. <!-- <review_comment_addressed> --> <!-- This is an auto-generated reply by CodeRabbit -->
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-13 01:53:25 +00:00
@ -86,7 +87,6 @@ func (k Kick) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) {
## Reference implementations
- `pokebedrock/session/ranks.go` (`rankWorker`) — HTTP runs on the worker
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:53:25 +00:00

@smell-of-curry, confirmed — the updated example now clearly states it runs inside an existing owner callback where p and handle are already defined, which resolves the ambiguity. Thanks for the quick fix!

`@smell-of-curry`, confirmed — the updated example now clearly states it runs inside an existing owner callback where `p` and `handle` are already defined, which resolves the ambiguity. Thanks for the quick fix! <!-- <review_comment_addressed> --> <!-- This is an auto-generated reply by CodeRabbit -->
smell-of-curry commented 2026-07-13 01:53:34 +00:00 (Migrated from github.com)

Addressed the review-body nitpicks in 8fd91c3: slapper fallback now logs the original missing-asset error, loadServers uses the configured bounded world-owner timeout, and leaderboard save failures are logged. Full tests, vet, build, module verification, and diff checks pass.

Addressed the review-body nitpicks in 8fd91c3: slapper fallback now logs the original missing-asset error, loadServers uses the configured bounded world-owner timeout, and leaderboard save failures are logged. Full tests, vet, build, module verification, and diff checks pass.
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-13 01:54:13 +00:00
coderabbitai[bot] (Migrated from github.com) commented 2026-07-13 01:54:13 +00:00
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
git log --oneline -1 8fd91c3 2>/dev/null || true
git show 8fd91c3 --stat 2>/dev/null || true
echo "---diff---"
git show 8fd91c3 2>/dev/null | head -300
echo "---HandleTransfer search---"
rg -n 'HandleTransfer|NopHandler' pokebedrock --glob '*.go'

Length of output: 12663


@smell-of-curry, confirmed both points:

  1. Address resolution — commit 8fd91c3 updates parseConfig in pokebedrock/srv/config.go to call net.ResolveUDPAddr("udp", cfg.Address) and store the canonicalized address back into cfg.Address at config-load time, with a new test (TestParseConfigRejectsInvalidAddress) covering invalid addresses. This moves the resolution off the world owner, so Manager.Update's world.Tx callback no longer performs a blocking DNS lookup. Good fix.

  2. Cancellation concern — verified that PlayerHandler (pokebedrock/handler/player.go) embeds player.NopHandler and there's no HandleTransfer override anywhere in the codebase (checked npc/handler.go and handler/inventory.go too, neither is relevant here). Since nothing cancels the transfer, Transfer won't return nil due to cancellation in this hub today. Agreed this doesn't currently apply.

Thanks for the clarification on both.


🧬 Code Graph Analysis Results

Relevant snippets

pokebedrock/locale/locale.go (lines 61-63)

func Translate(key string, args ...any) string {
	return text.Colourf("%s", TranslateL(language.English, key, args...))
}

pokebedrock/authentication/factory.go (lines 60-68)

func (f *Factory) Set(name, xuid string, duration time.Duration) {
	f.mu.Lock()
	defer f.mu.Unlock()
	f.data[xuid] = PlayerIdentity{
		DisplayName: name,
		XUID:        xuid,
		Expiration:  time.Now().Add(duration),
	}
}

pokebedrock/authentication/factory.go (lines 21-23)

func GlobalFactory() *Factory {
	return globalFactory
}

pokebedrock/authentication/factory.go (lines 80-84)

func (f *Factory) Remove(xuid string) {
	f.mu.Lock()
	defer f.mu.Unlock()
	delete(f.data, xuid)
}

pokebedrock/authentication/factory.go (line 14)

DefaultAuthDuration = 5 * time.Minute

pokebedrock/internal/constants.go (line 15)

ProcessingBatchSize = 20
<details> <summary>🧩 Analysis chain</summary> 🏁 Script executed: ```shell #!/bin/bash set -euo pipefail git log --oneline -1 8fd91c3 2>/dev/null || true git show 8fd91c3 --stat 2>/dev/null || true echo "---diff---" git show 8fd91c3 2>/dev/null | head -300 echo "---HandleTransfer search---" rg -n 'HandleTransfer|NopHandler' pokebedrock --glob '*.go' ``` Length of output: 12663 --- </details> `@smell-of-curry`, confirmed both points: 1. **Address resolution** — commit 8fd91c3 updates `parseConfig` in `pokebedrock/srv/config.go` to call `net.ResolveUDPAddr("udp", cfg.Address)` and store the canonicalized address back into `cfg.Address` at config-load time, with a new test (`TestParseConfigRejectsInvalidAddress`) covering invalid addresses. This moves the resolution off the world owner, so `Manager.Update`'s `world.Tx` callback no longer performs a blocking DNS lookup. Good fix. 2. **Cancellation concern** — verified that `PlayerHandler` (`pokebedrock/handler/player.go`) embeds `player.NopHandler` and there's no `HandleTransfer` override anywhere in the codebase (checked `npc/handler.go` and `handler/inventory.go` too, neither is relevant here). Since nothing cancels the transfer, `Transfer` won't return `nil` due to cancellation in this hub today. Agreed this doesn't currently apply. Thanks for the clarification on both. <!-- <review_comment_withdrawn> --> --- <details> <summary>🧬 Code Graph Analysis Results</summary> ### Relevant snippets #### `pokebedrock/locale/locale.go` (lines 61-63) ```go func Translate(key string, args ...any) string { return text.Colourf("%s", TranslateL(language.English, key, args...)) } ``` #### `pokebedrock/authentication/factory.go` (lines 60-68) ```go func (f *Factory) Set(name, xuid string, duration time.Duration) { f.mu.Lock() defer f.mu.Unlock() f.data[xuid] = PlayerIdentity{ DisplayName: name, XUID: xuid, Expiration: time.Now().Add(duration), } } ``` #### `pokebedrock/authentication/factory.go` (lines 21-23) ```go func GlobalFactory() *Factory { return globalFactory } ``` #### `pokebedrock/authentication/factory.go` (lines 80-84) ```go func (f *Factory) Remove(xuid string) { f.mu.Lock() defer f.mu.Unlock() delete(f.data, xuid) } ``` #### `pokebedrock/authentication/factory.go` (line 14) ```go DefaultAuthDuration = 5 * time.Minute ``` #### `pokebedrock/internal/constants.go` (line 15) ```go ProcessingBatchSize = 20 ``` </details> <!-- This is an auto-generated reply by CodeRabbit -->
Sign in to join this conversation.
No description provided.