Phase 19: wire save_on_death + save_on_respawn (dead config) to fix keep-charm edge cases
User report: Twilight Forest 'Charm of Keeping' + ReviveMe interaction loses
inventory over multiple deaths. Analysis concludes this is a Twilight/ReviveMe
event-priority interaction, not a PlayerSync bug — but two dead config options
hid admin-facing levers that help mitigate the case.
(1) save_on_death was declared in JdbcConfig but NEVER read in code. The death
snapshot ran unconditionally. Now gated: setting save_on_death=false
disables the LivingDeathEvent-driven pre-drop snapshot. The normal
onPlayerLogout save still fires on disconnect, so nothing is lost — but
admins diagnosing a keeping-charm interaction can quickly turn off the
aggressive death snapshot to rule PlayerSync in or out.
(2) save_on_respawn was also declared but never read. Added a new
@SubscribeEvent PlayerEvent.PlayerRespawnEvent handler that calls
snapshotAndQueueSave(player, 'RESPAWN') after the respawn completes.
This captures the post-death state AFTER keeping-charms / Corail
Tombstone / similar mods have restored their preserved items, so
PlayerSync's DB row reflects the actual post-respawn inventory rather
than the pre-drop snapshot from onPlayerDeath.
Excludes end-portal exit (isEndConquered) since that's not a death
respawn — no need to overwrite.
Combined effect: if a player dies, charm-keeps items, respawns, the DB
ends up with:
t=0 death snapshot (pre-drop, full inventory)
t=X respawn snapshot (post-drop, kept items + whatever charm restored)
The respawn snapshot overwrites the death one by virtue of running later.
A disconnect between t=0 and t=X still saves via onPlayerLogout anyway,
so no loss window opens.
No change to the duplication-safety guarantees from Phases 15-18:
onPlayerDeath still checks event.isCanceled() for ReviveMe, the RESPAWN
snapshot goes through the normal snapshotAndQueueSave pipeline with all
the P0-a/b/c guards and the 2-phase-commit logout_started_at tracking.
Answer to the user's question: the keep-charm inventory loss is
overwhelmingly likely to be a ReviveMe x Twilight Forest event-priority
bug outside PlayerSync's control, but this commit exposes two levers
(save_on_death, save_on_respawn) that let admins test whether PlayerSync
is contributing — setting save_on_death=false should make the symptom
unchanged if the root cause is external.
This commit is contained in:
parent
6c986faa3f
commit
be816cb359
|
|
@ -1136,6 +1136,32 @@ public class VanillaSync {
|
|||
snapshotAndQueueSave(event.getEntity(), "SaveToFile");
|
||||
}
|
||||
|
||||
/**
|
||||
* PHASE 19: optional save on respawn — gated by {@code save_on_respawn}.
|
||||
* Runs AFTER the respawn is complete so the snapshot captures the final
|
||||
* post-death inventory (vanilla drops + whatever keeping-charms preserved).
|
||||
* This OVERWRITES the pre-death snapshot taken in onPlayerDeath with the
|
||||
* correct authoritative state, so the next restore sees the real inventory.
|
||||
*
|
||||
* <p>Essential when mods like Twilight Forest's Charm of Keeping or
|
||||
* Corail Tombstone restore items on respawn — without this event,
|
||||
* PlayerSync's DB row stays at the pre-death snapshot until the next
|
||||
* auto-save, and a quick disconnect loses the keep-charm state.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
|
||||
try {
|
||||
if (!JdbcConfig.SAVE_ON_RESPAWN.get()) return;
|
||||
if (event.isEndConquered()) return; // End-portal exit, not a death respawn
|
||||
Player player = event.getEntity();
|
||||
SyncLogger.playerEvent(player.getUUID().toString(), "RESPAWN",
|
||||
"Snapshot post-respawn inventory (keeping-charm / tombstone mods)");
|
||||
snapshotAndQueueSave(player, "RESPAWN");
|
||||
} catch (Exception e) {
|
||||
PlayerSync.LOGGER.warn("[respawn-save] trigger failed: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 4: optional save on dimension change — gated by
|
||||
* {@code save_on_dimension_change} config. Protects against mid-teleport
|
||||
|
|
@ -2372,9 +2398,20 @@ public class VanillaSync {
|
|||
// Always cache curios on death (API returns empty for dead players later)
|
||||
CuriosCache.tryStoreCuriosToCache(player);
|
||||
|
||||
// PHASE 19: honour save_on_death config. Keeping-charm / death-drop-replacement
|
||||
// mods (Twilight Forest Charm of Keeping, Corail Tombstone items, etc.) run
|
||||
// their own event handlers during LivingDeathEvent. When their priority is
|
||||
// higher than ours (LOW), they've already moved items out of the drops list
|
||||
// — our snapshot at this point captures the post-keep inventory, which is
|
||||
// usually the desired behaviour.
|
||||
// If admins diagnose a keeping-charm interaction, setting save_on_death=false
|
||||
// disables this snapshot entirely; the normal onPlayerLogout save still fires
|
||||
// on disconnect and captures the post-respawn state.
|
||||
if (!JdbcConfig.SAVE_ON_DEATH.get()) return;
|
||||
|
||||
// Immediately save ALL player data on death (snapshot + async).
|
||||
// LivingDeathEvent fires BEFORE items are dropped, so the snapshot captures
|
||||
// the full pre-death inventory including backpack contents.
|
||||
// LivingDeathEvent fires BEFORE vanilla items are dropped, so the snapshot
|
||||
// captures whatever keeping-charms have already reserved + the rest.
|
||||
// This protects against: server crash after death, network disconnect before
|
||||
// onPlayerLogout fires, or any scenario where the logout handler is skipped.
|
||||
// The normal logout save will overwrite this with the final post-death state.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user