Skip to content

Fix Dead process - added dead transaction and refactored as state mac… - #39

Draft
nightNR wants to merge 1 commit into
mtwango:dark-paradisefrom
nightNR:dark-paradise
Draft

Fix Dead process - added dead transaction and refactored as state mac…#39
nightNR wants to merge 1 commit into
mtwango:dark-paradisefrom
nightNR:dark-paradise

Conversation

@nightNR

@nightNR nightNR commented Aug 11, 2026

Copy link
Copy Markdown

Make character death a resumable state machine to ensure idempotency and retryability

Description

This PR fixes an issue where a character—particularly a summoned NPC such as Blade Spirit—could remain in the world with 0 HP while being impossible to kill or
dispel.

The original death process set STATF_DEAD before completing all cleanup operations. If an exception occurred afterward, the periodic tick caught it and
rescheduled the character. Subsequent ticks skipped Death() because STATF_DEAD was already set, leaving a permanently inconsistent character that could still
occupy summon/follower slots.

This PR refactors character death into a resumable transaction with explicit phases. Completed phases are recorded, internal cleanup operations can be retried,
and irreversible callbacks are protected against duplicate execution.

The implementation includes:

  • Persistent death transaction state for save/load recovery
  • Idempotent continuation from the last completed phase
  • At-most-once execution of triggers, penalties, and notifications
  • Retry with backoff for failed internal cleanup
  • Emergency finalization for repeatedly failing non-bonded NPCs
  • Protection for players and bonded pets from forced deletion
  • Reentrancy protection for recursive Death() calls
  • Legacy recovery for dead non-bonded NPCs without transaction state
  • Prevention of sector sleep from suspending an active death transaction
  • Structured diagnostic logging with transaction, phase, character, location, sector, and corpse information
  • Test-only fault injection at death phase boundaries

———

Type of Change

  • Bug fix
  • New feature
  • Performance improvement
  • Refactoring
  • Documentation update
  • Build / CI change
  • Other

———

Related Issues

No related issue or pull request is currently linked.

———

Testing

  • Tested on a clean SphereServer instance with latest ScriptPack
  • No regressions in existing functionality
  • Added or updated tests

Added isolated tests covering:

  • Death transaction lifecycle
  • At-most-once callback dispatch
  • Retry and emergency-finalization behavior
  • Player and bonded-pet protection
  • Fault injection before and after phase boundaries
  • Reentrancy protection
  • Legacy zombie-NPC recovery

Test result:

8 test cases passed
66 assertions passed

The changed production translation units compile successfully. A complete server build is currently blocked by a pre-existing unrelated C4706 warning treated
as an error in CCChampion.cpp.

A full runtime Blade Spirit test with the latest ScriptPack has therefore not yet been completed.

———

Checklist

  • Changed code compiles successfully
  • Changes follow the project's coding style
  • No unrelated code was modified
  • Documentation provided through code comments and diagnostic logs
  • This PR does not introduce breaking script API changes

———

Additional Notes

Active death transactions remain tickable even when their sector is sleeping. Recovery therefore does not depend on a player keeping the current or adjacent
sector awake.

Script callbacks and other irreversible side effects use at-most-once semantics. Internal cleanup phases are retried until successful. After repeated failures,
non-bonded NPCs enter emergency finalization so they cannot remain permanently in the world or occupy follower slots.

The transaction is serialized as DEATHTXN while active. Completed player and bonded-pet deaths do not retain transaction state. Legacy dead non-bonded NPCs
without this state enter conservative recovery without replaying kill, loot, or corpse triggers.

@nightNR

nightNR commented Aug 12, 2026

Copy link
Copy Markdown
Author

Podla vsetkeho bug suvisi s tym, kedy sa characteru setne STATF_DEAD flag ak niektory z krokov po nom skonci vynimkou, tak char zostane v stave ze uz ho scheduler nepusti do CCHar:Dead()
if ( IsStatFlag(STATF_DEAD) ) return DeathRequestResult::AlreadyDead;
lenze nezbehol zvysok procesu takze char zostane v blbom stave kedy nevie zomriet

najjednoduchsie by bolo STATF_DEAD setnut az na konci ale to by v pripade vynimky dovolilo zbehnut Death viac krat, a tak by mohlo docahdzat trebarz k zdvojovaniu lootu..

V tejto prerabke je to prerobene na tranzakciu ktora si znaci kazdy bod processu ktory dokazal dobehnut.. ak niektory nedobehne, dovoli retry ale len bodov ktore mozu byt zopakovane alebo neboli skoncene. Mal by par krat skusit retry a potom zalogovat vyunimku a ticho skoncit...

Neviem to rozumne vyskusat kedze neviem uplne dany stav nasimulovat.. + takze by to chcelo skor otestovat v zivej situacii

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