Document player stats persistence

This commit is contained in:
2026-05-18 19:13:59 -07:00
parent 1e0d326657
commit 82f60f480b
3 changed files with 69 additions and 1 deletions
+4 -1
View File
@@ -737,7 +737,10 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
backwards-compatible `PlayerId` plus `FAgrarianSavedPlayerIdentity`, prefer a
valid `APlayerState` network ID when available, and retain safe display/pawn
metadata without storing credentials.
- [ ] Save player stats.
- [x] Save player stats. Player save records capture
`FAgrarianSavedPlayer::Survival`, including health, stamina, exhaustion,
hunger, thirst, body temperature, injury, bleeding, sprain, sickness, death
state, and death reason, then restore through `ApplySavedState`.
- [ ] Save long-term character care history placeholders without applying aging gameplay yet.
- [ ] Save player inventory.
- [x] Save placed structures.
+7
View File
@@ -409,6 +409,13 @@ identity block also records the display player name, raw network ID, whether
the network ID was used, and the last known pawn name. It deliberately does not
store passwords, tokens, emails, or platform credentials.
Player stats are stored through `FAgrarianSavedPlayer::Survival`, which captures
the replicated `FAgrarianSurvivalSnapshot`. The MVP stat save includes health,
stamina, exhaustion, hunger, thirst, body temperature, generic injury,
bleeding, sprain, sickness, death state, and death reason. Loading applies the
snapshot through `UAgrarianSurvivalComponent::ApplySavedState`, keeping clamping
and replicated change notifications inside the survival component.
## Testing Gates
Minimum persistence smoke test:
@@ -0,0 +1,58 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
EXPECTED = {
ROOT / "Source" / "AgrarianGame" / "AgrarianTypes.h": [
"struct FAgrarianSurvivalSnapshot",
"float Health = 100.0f;",
"float Stamina = 100.0f;",
"float Exhaustion = 0.0f;",
"float Hunger = 100.0f;",
"float Thirst = 100.0f;",
"float BodyTemperature = 37.0f;",
"float InjurySeverity = 0.0f;",
"float BleedingSeverity = 0.0f;",
"float SprainSeverity = 0.0f;",
"float SicknessSeverity = 0.0f;",
"bool bIsDead = false;",
"FName LastDeathReason = NAME_None;",
],
ROOT / "Source" / "AgrarianGame" / "AgrarianSaveGame.h": [
"FAgrarianSurvivalSnapshot Survival;",
],
ROOT / "Source" / "AgrarianGame" / "AgrarianPersistenceSubsystem.cpp": [
"SavedPlayer.Survival = SurvivalComponent->Survival;",
"SurvivalComponent->ApplySavedState(SavedPlayer->Survival, SavedPlayer->CareHistory);",
],
ROOT / "Docs" / "PersistenceDesignDocument.md": [
"`FAgrarianSavedPlayer::Survival`",
"The MVP stat save includes health",
"bleeding, sprain, sickness, death state, and death reason",
"`UAgrarianSurvivalComponent::ApplySavedState`",
],
ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md": [
"[x] Save player stats.",
"`FAgrarianSavedPlayer::Survival`",
"state, and death reason",
],
}
def main() -> None:
missing = []
for path, snippets in EXPECTED.items():
text = path.read_text(encoding="utf-8")
for snippet in snippets:
if snippet not in text:
missing.append(f"{path.relative_to(ROOT)}: {snippet}")
if missing:
raise RuntimeError("Player stats persistence verification failed: " + "; ".join(missing))
print("PASS: player stats persist through the saved survival snapshot.")
if __name__ == "__main__":
main()