Skip to content

Scope addon-created BlueMap marker sets to their own worlds - #3041

Merged
tastybento merged 1 commit into
developfrom
fix/bluemap-addon-markerset-world-scope
Jul 26, 2026
Merged

Scope addon-created BlueMap marker sets to their own worlds#3041
tastybento merged 1 commit into
developfrom
fix/bluemap-addon-markerset-world-scope

Conversation

@tastybento

Copy link
Copy Markdown
Member

Problem

BlueMapHook.createMarkerSet() attached every new marker set to every map on the server:

api.getMaps().forEach(map -> map.getMarkerSets().put(id, markerSet));

populateAll() did the same again after a BlueMap reload, and removeMarkerSet() had the matching fan-out. So an addon registering a warps marker set for one game mode put that set in the sidebar of every other game mode's map, and of any non-BentoBox world's map as well. A set created but never populated was listed on every map while permanently empty.

Island marker sets were never affected — registerGameMode() already scopes those to the game mode's own overworld/nether/end.

Fix

MapHook#createMarkerSet(id, label) has no world parameter, so there is nothing to scope by at creation time. The worlds are instead learned lazily from the markers themselves:

  • addPointMarker / addAreaMarker / addPolygonMarker record the world they were handed and attach the set to just that world's maps.
  • populateAll() replays the recorded worlds after a BlueMap reload instead of hitting api.getMaps().
  • removeMarkerSet() detaches from only the worlds the set was attached to.

A set with no markers yet is now attached nowhere, which is also the more useful behaviour.

Also in here

createMarkerSet() and removeMarkerSet() dereferenced the api field unconditionally, so an addon calling either before BlueMap finished loading — or during a /bluemap reload, when the hook nulls api in its onDisable callback — got an NPE. Both now guard, as does addMarkerSetToWorld.

getBlueMapAPI() was annotated @NonNull but returns null in exactly those two windows. It is now @Nullable with the windows documented; the old annotation told null-analysis to skip the check callers actually needed. Annotation-only change, so binary compatibility is unaffected.

Testing

8 new tests in BlueMapHookTest, including the direct regression test (testAddPointMarkerDoesNotAttachSetToUnrelatedWorld: two worlds with their own maps, marker added in one, assert the other's map stays clean), reload re-attachment, detach-on-remove, and the API-not-loaded path.

Full suite: 3374 tests, 0 failures.

Version

None needed — buildVersion is already 3.21.1 and 3.21.0 is the latest release, so this lands in the pending version.

Context

Spotted while investigating an admin's BlueMap report on Discord. It is not the cause of that report — that one is looking like an nginx gzip_static always / webroot issue on their side — but it is a real defect in the same code.

🤖 Generated with Claude Code

https://claude.ai/code/session_016pHWC6XapJj5gRtsFr74Tf

createMarkerSet() attached the new set to every map on the server via
api.getMaps(), and populateAll() re-attached it to every map again after a
BlueMap reload. An addon registering, say, a warps marker set for one game
mode put that set on the sidebar of every other game mode's map, and of any
non-BentoBox world's map too. removeMarkerSet() had the same fan-out.

MapHook#createMarkerSet carries no world, so the set's worlds are now learned
lazily from the markers themselves: addPointMarker/addAreaMarker/addPolygonMarker
record the world they were given and attach the set to just that world's maps.
populateAll() replays the recorded worlds after a BlueMap reload, and
removeMarkerSet() detaches from only those worlds.

A set with no markers yet is no longer attached anywhere, which is also the
more useful behaviour - an empty set was previously listed on every map.

Island marker sets are unaffected; registerGameMode() already scoped them to
the game mode's own worlds.

Also guards the api field before use. createMarkerSet() and removeMarkerSet()
dereferenced it unconditionally, so an addon calling either before BlueMap had
loaded, or while it was reloading, hit an NPE. getBlueMapAPI() is annotated
@nullable for the same reason - it was marked @nonnull but returns null in both
those windows, which suppressed the null checks callers needed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016pHWC6XapJj5gRtsFr74Tf
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a86dfff into develop Jul 26, 2026
3 checks passed
@tastybento
tastybento deleted the fix/bluemap-addon-markerset-world-scope branch July 26, 2026 19:29
@tastybento tastybento mentioned this pull request Jul 27, 2026
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.

1 participant