Defer on-join player resets until after team-accept teleport#2979
Merged
tastybento merged 1 commit intoMay 18, 2026
Conversation
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>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
cleanPlayer/cleanJoiningPlayerfrom beforehomeTeleportAsyncto inside the.thenRun(...)callback inIslandTeamInviteAcceptCommand.acceptTeamInvite, so the inventory / XP / health / hunger / money resets configured byisland.reset.on-join.*(and on-leave) run after the player has been teleported to the island world, not before.CompletableFutureto 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) withisland.reset.on-join.inventory: true. BSkyBlock / AcidIsland / CaveBlock / Poseidon / StrangerRealms ship withfalseand don't trigger it.Root cause
worldwith real items./island team acceptcallscleanJoiningPlayer(user)synchronously —player.getInventory().clear()runs while the player is still in the non-BB world.homeTeleportAsyncthen teleports them to the island. The teleport eventually firesPlayerChangedWorldEvent.PlayerListener.onWorldEnterseesfrom = world, callsstoreInventory(player, world), and persists the now-empty inventory under that world's storage key.Fix
Defer the player-data resets until the teleport completes. This way
PlayerChangedWorldEventfires (and InvSwitcher saves the still-intact non-BB inventory) before anyclear()happens; the resets then run in the island world, which is the semantically correct place for on-join resets. ThegetIslands().removePlayer(...)call is logical island-state housekeeping and stays before the teleport;deleteIsland(...)was already insidethenRunand is now grouped withcleanPlayerthere for consistency.Test plan
./gradlew test --tests 'IslandTeamInviteAcceptCommandTest'— green, including the three pre-existing XP-reset tests that still verify resets occur (the mockedCompletableFuture.completedFuture(true)causesthenRunto fire synchronously)../gradlew test— full suite green.testAcceptTeamInvite_inventoryClearWaitsForTeleportuses an uncompleted future to assertinv.clear()/setLevel(0)/setExp(0F)/setTotalExperience(0)are not called before the teleport completes, then completes the future and asserts they are called after.on-join.inventory: true): player joins a team while standing inworld, returns toworldafter, items should remain.🤖 Generated with Claude Code