Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions src/main/java/com/wasteofplastic/invswitcher/Store.java
Original file line number Diff line number Diff line change
Expand Up @@ -304,16 +304,22 @@ public void getInventory(Player player, World world, Island island) {
}

private void setHeath(InventoryStorage store, Player player, String overworldName) {
// Health
double health = store.getHealth().getOrDefault(overworldName,
player.getAttribute(Attribute.MAX_HEALTH).getValue());

AttributeInstance attr = player.getAttribute(Attribute.MAX_HEALTH);
if (attr != null && health > attr.getValue()) {
health = attr.getValue();
}
if (health < 0D) {
health = 0D;
double maxHealth = (attr != null) ? attr.getValue() : 20D;

// Health
double health = store.getHealth().getOrDefault(overworldName, maxHealth);

if (health > maxHealth) {
health = maxHealth;
}
// Never load a fatal health value. A stored value of 0 (or less) only arises when the
// player's state was captured mid-death (e.g. when they died on another island). Applying
// it to a live player would kill them again the moment they load the world, causing an
// endless respawn/death loop (issue #56). Restore full health instead, matching vanilla
// respawn behaviour.
if (health <= 0D) {
health = maxHealth;
}
player.setHealth(health);

Expand Down
23 changes: 23 additions & 0 deletions src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,29 @@ void testGetInventory() {
verify(player).setTotalExperience(0);
}

/**
* Issue #56: a stored health of 0 is only ever captured when the player's state is saved
* mid-death (e.g. per-island health enabled and the player died on another island). Loading
* that value into a live player would kill them the instant they enter the world, causing an
* endless respawn/death loop. Loading must restore full health instead of applying 0.
*/
@Test
void testGetInventoryNeverLoadsFatalHealth() {
sets.setStatistics(false);
sets.setAdvancements(false);

// Simulate the player's state being captured mid-death with 0 health
when(player.getHealth()).thenReturn(0D);
try (MockedStatic<Bukkit> mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
s.storeInventory(player, world);
}

// Re-entering the world must restore full health (max = 18), never the fatal stored 0
s.getInventory(player, world);
verify(player).setHealth(18D);
verify(player, never()).setHealth(0D);
}

/**
* Test that advancement grants during {@link Store#getInventory} do not modify the player's
* experience points. Some advancements reward XP when their criteria are awarded; the store
Expand Down
Loading