Skip to content

Fix stale-message risk in async chat handling and shared-state bug in IslandChatCommand#61

Merged
tastybento merged 3 commits into
developfrom
copilot/fix-repeating-message
Jul 3, 2026
Merged

Fix stale-message risk in async chat handling and shared-state bug in IslandChatCommand#61
tastybento merged 3 commits into
developfrom
copilot/fix-repeating-message

Conversation

Copilot AI commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Island/team chat could repeat a previously sent message instead of the current one — reported specifically with OneBlock's /ob chat, where every message after the first kept echoing the first message's text.

Root cause

The classic trigger for this bug is deferring AsyncPlayerChatEvent#getMessage() to a scheduled task (e.g. Bukkit.getScheduler().runTask(...)) instead of reading it synchronously in the handler. By the time the deferred task runs, the message content can no longer be trusted to reflect the current chat event. ChatListener.onChat() already captures the message value up front before dispatching work to the main thread via callSyncMethod, which is the correct pattern — but this path had no test coverage, since existing tests only exercised the synchronous (isAsynchronous() == false) branch.

Changes

  • Test coverage for the async code path: added regression tests that drive onChat through the actual async branch with a stubbed scheduler, sending two consecutive messages ("aaaa" then "test") and asserting each is delivered with its own content rather than the previous one, for both island chat and team chat.
  • Fixed shared mutable state in IslandChatCommand: the resolved Island was cached on an instance field set in canExecute() and read in execute(). Since command instances are shared singletons across all players (not per-invocation), this risks one player's island leaking into another player's execute() call. Sibling commands (IslandTeamChatCommand, IslandTeamMuteCommand) avoid this by recomputing what they need directly inside execute(); IslandChatCommand now follows the same pattern:
@Override
public boolean canExecute(User user, String label, List<String> args) {
    return this.getIslands().getIslandAt(user.getLocation()).isPresent();
}

@Override
public boolean execute(User user, String label, List<String> args) {
    Island island = this.getIslands().getIslandAt(user.getLocation()).orElse(null);
    if (island == null) {
        return false;
    }
    // ... rest of execute logic uses the freshly resolved island
}

Copilot AI linked an issue Jul 3, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix repeating message in oneblock chat Fix stale-message risk in async chat handling and shared-state bug in IslandChatCommand Jul 3, 2026
Copilot AI requested a review from tastybento July 3, 2026 17:17
@tastybento tastybento marked this pull request as ready for review July 3, 2026 17:29
@tastybento tastybento merged commit 8dc3228 into develop Jul 3, 2026
1 check passed
@tastybento tastybento deleted the copilot/fix-repeating-message branch July 3, 2026 20:30
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.

Repeating message

2 participants