Skip to content

Defer on-join player resets until after team-accept teleport#2979

Merged
tastybento merged 1 commit into
developfrom
fix/team-accept-clear-inventory-after-teleport
May 18, 2026
Merged

Defer on-join player resets until after team-accept teleport#2979
tastybento merged 1 commit into
developfrom
fix/team-accept-clear-inventory-after-teleport

Conversation

@tastybento
Copy link
Copy Markdown
Member

Summary

  • Move cleanPlayer / cleanJoiningPlayer from before homeTeleportAsync to inside the .thenRun(...) callback in IslandTeamInviteAcceptCommand.acceptTeamInvite, so the inventory / XP / health / hunger / money resets configured by island.reset.on-join.* (and on-leave) run after the player has been teleported to the island world, not before.
  • Adds a regression test that uses an uncompleted CompletableFuture to assert no resets fire until the teleport completes.

The bug

Reported via InvSwitcher: a player standing in a non-BentoBox world with items, who accepts an invite into an AOneBlock or Boxed team island, returns to find their non-BentoBox-world inventory empty. The pattern only shows up in those two game modes because they're the ones that ship (Boxed 3.3.0) or commonly default (AOneBlock, via the Java field default true) with island.reset.on-join.inventory: true. BSkyBlock / AcidIsland / CaveBlock / Poseidon / StrangerRealms ship with false and don't trigger it.

Root cause

  1. Player stands in non-BB world world with real items.
  2. /island team accept calls cleanJoiningPlayer(user) synchronously — player.getInventory().clear() runs while the player is still in the non-BB world.
  3. homeTeleportAsync then teleports them to the island. The teleport eventually fires PlayerChangedWorldEvent.
  4. InvSwitcher's PlayerListener.onWorldEnter sees from = world, calls storeInventory(player, world), and persists the now-empty inventory under that world's storage key.
  5. When the player later returns to a non-BB world, InvSwitcher loads the empty inventory it just saved. Their items are gone.

Fix

Defer the player-data resets until the teleport completes. This way PlayerChangedWorldEvent fires (and InvSwitcher saves the still-intact non-BB inventory) before any clear() happens; the resets then run in the island world, which is the semantically correct place for on-join resets. The getIslands().removePlayer(...) call is logical island-state housekeeping and stays before the teleport; deleteIsland(...) was already inside thenRun and is now grouped with cleanPlayer there for consistency.

Test plan

  • ./gradlew test --tests 'IslandTeamInviteAcceptCommandTest' — green, including the three pre-existing XP-reset tests that still verify resets occur (the mocked CompletableFuture.completedFuture(true) causes thenRun to fire synchronously).
  • ./gradlew test — full suite green.
  • New testAcceptTeamInvite_inventoryClearWaitsForTeleport uses an uncompleted future to assert inv.clear() / setLevel(0) / setExp(0F) / setTotalExperience(0) are not called before the teleport completes, then completes the future and asserts they are called after.
  • Manual reproduction with InvSwitcher 1.17.1, AOneBlock 1.25.0, Boxed 3.3.0 (both with on-join.inventory: true): player joins a team while standing in world, returns to world after, items should remain.

🤖 Generated with Claude Code

When a player accepts a team invite while standing in a non-BentoBox
world, IslandTeamInviteAcceptCommand previously ran cleanPlayer /
cleanJoiningPlayer synchronously before homeTeleportAsync. That clears
inventory, ender chest, XP, etc. while the player is still in the
previous world. Plugins that save per-world inventories on
PlayerChangedWorldEvent (e.g. InvSwitcher) then see and persist the
post-clear empty inventory as the previous world's stored state,
permanently overwriting the player's real items in that world.

Move the cleanPlayer / cleanJoiningPlayer calls into the
homeTeleportAsync().thenRun() block so the resets fire after the
teleport, in the island world. The disallow-team-member-islands branch
still removes the player from their old islands before teleport (this
is logical island state, not player data) and now deletes those islands
inside thenRun alongside cleanPlayer for consistency.

Adds a regression test that completes the teleport future manually and
verifies inventory.clear() and the XP resets do not fire until the
teleport future completes.

Reported via InvSwitcher: inventory in non-BentoBox worlds is emptied
after accepting an AOneBlock / Boxed team invite (game modes whose
shipped or user-edited config sets on-join.inventory: true).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

@tastybento tastybento merged commit df53ae6 into develop May 18, 2026
3 checks passed
@tastybento tastybento deleted the fix/team-accept-clear-inventory-after-teleport branch May 18, 2026 13:56
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