diff options
| author | historia <[not public]> | 2026-09-15 15:35:52 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-15 15:35:52 -0400 |
| commit | 0b0b25222b3131ada79ff78c28eb8bf07d977deb (patch) | |
| tree | 2ceaef5203595044f66a8f00064cd8e017f8f48d /internal/player | |
| parent | 396c3facb8287b9a34076cae8f3d7b300d366d99 (diff) | |
| download | thehouseoficarus-0b0b25222b3131ada79ff78c28eb8bf07d977deb.tar.gz | |
feat: single-owner game state, transactional lifecycle, durable money on server stop
Diffstat (limited to 'internal/player')
| -rw-r--r-- | internal/player/player.go | 5 | ||||
| -rw-r--r-- | internal/player/store.go | 32 |
2 files changed, 26 insertions, 11 deletions
diff --git a/internal/player/player.go b/internal/player/player.go index 81ef056..ae147b2 100644 --- a/internal/player/player.go +++ b/internal/player/player.go @@ -159,6 +159,11 @@ func GetOptionDef(name string) *OptionDef { type Player struct { Name string `yaml:"name"` + // ID is a stable identifier assigned at creation. Filenames are + // renameable; the ID is not, so cached references authorize by ID. + ID string `yaml:"id,omitempty"` + // Account is the owning account name (case-canonical at write time). + Account string `yaml:"account,omitempty"` Skills map[SkillName]int `yaml:"skills"` Inventory map[int]*InventorySlot `yaml:"inventory"` Bank map[int]*InventorySlot `yaml:"bank"` diff --git a/internal/player/store.go b/internal/player/store.go index d0dbd0f..d461485 100644 --- a/internal/player/store.go +++ b/internal/player/store.go @@ -37,12 +37,17 @@ func (s *AccountStore) LoadAccount(name string) (*Account, error) { } func (s *AccountStore) SaveAccount(acc *Account) error { - path := s.AccountPath(acc.Name) - data, err := yaml.Marshal(acc) + data, err := s.MarshalAccount(acc) if err != nil { return err } - return persistence.WriteFile(path, data, 0600) + return persistence.WriteFile(s.AccountPath(acc.Name), data, 0600) +} + +// MarshalAccount serializes an account; callers that own the account (the +// game owner, or transaction code holding it) may use this directly. +func (s *AccountStore) MarshalAccount(acc *Account) ([]byte, error) { + return yaml.Marshal(acc) } func (s *AccountStore) AccountExists(name string) bool { @@ -103,9 +108,18 @@ func (s *AccountStore) LoadCharacter(name string) (*Player, error) { } func (s *AccountStore) SaveCharacter(p *Player) error { - path := s.CharPath(p.Name) - // Serialize a value copy so saving god-mode stats never temporarily - // changes the live player. The caller still owns all referenced maps. + data, err := s.MarshalCharacter(p) + if err != nil { + return err + } + return persistence.WriteFile(s.CharPath(p.Name), data, 0600) +} + +// MarshalCharacter serializes a character for a same-directory temporary +// atomic write. It serializes a value snapshot so saving god-mode stats +// never temporarily changes the live player; the caller still owns all +// referenced maps (serialize on the owner goroutine). +func (s *AccountStore) MarshalCharacter(p *Player) ([]byte, error) { snapshot := *p if snapshot.GodMode && snapshot.GodBackup != nil { snapshot.Skills = snapshot.GodBackup @@ -113,11 +127,7 @@ func (s *AccountStore) SaveCharacter(p *Player) error { snapshot.HP = snapshot.MaxHP() } } - data, err := yaml.Marshal(&snapshot) - if err != nil { - return err - } - return persistence.WriteFile(path, data, 0600) + return yaml.Marshal(&snapshot) } func (s *AccountStore) CharacterExists(name string) bool { |
