diff options
Diffstat (limited to 'internal/game/casino.go')
| -rw-r--r-- | internal/game/casino.go | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/internal/game/casino.go b/internal/game/casino.go index 9af9156..f9eb771 100644 --- a/internal/game/casino.go +++ b/internal/game/casino.go @@ -99,7 +99,28 @@ func (w casinoWallet) payCreditsFlagged(amount int, refund bool) error { rec, err := w.g.Economy.startKind("payout", refund, w.p, 0, amount, creditsBefore, creditsAfter, chipsBefore, chipsBefore) if err != nil { - return casino.ErrWalletPersistence + // The journal is unavailable (persistent append failure). Last + // resort: pay through the character file only. The save below is + // the commit point — the money is durable even without a journal + // record, so the settlement may be announced as paid. The stake + // resolution evidence (ResolveStakes) keeps recovery from treating + // the round as unresolved; without a payout record, an open wager + // can no longer be distinguished from a lost one, so the balance + // itself is the only record of what happened. + if capErr != nil { + return capErr + } + w.p.Credits = creditsAfter + if serr := w.g.AccountStore.SaveCharacter(w.p); serr != nil { + w.p.Credits = creditsBefore + return casino.ErrWalletPersistence + } + kind := "settlement" + if refund { + kind = "refund" + } + fmt.Fprintf(os.Stderr, "economy: %s payout of %d credits for %s could not be journaled; the character file is the only durable record\n", kind, amount, w.p.Name) + return nil } if capErr != nil { return capErr @@ -129,9 +150,28 @@ func (w casinoWallet) payCreditsFlagged(amount int, refund bool) error { // ResolveStakes marks every outstanding stake for the player settled: the // round resolved (won, lost, pushed, or forfeited), so startup recovery -// must no longer refund it. +// must no longer refund it. When the journal cannot persist the settled +// markers, the record IDs are recorded in the character file as durable +// resolution evidence (player.Player.ResolvedStakes) so recovery still +// honors the resolution instead of refunding an already-resolved round. func (w casinoWallet) ResolveStakes() { - w.g.Economy.ResolveStakes(economyKey(w.p)) + unresolved := w.g.Economy.ResolveStakes(economyKey(w.p)) + if len(unresolved) == 0 { + return + } + changed := false + for _, rec := range unresolved { + if !resolvedStakeRecorded(w.p, rec.ID) { + w.p.ResolvedStakes = append(w.p.ResolvedStakes, rec.ID) + changed = true + } + } + if !changed { + return + } + if err := w.g.AccountStore.SaveCharacter(w.p); err != nil { + fmt.Fprintf(os.Stderr, "casino resolve stakes: evidence save for %s: %v\n", w.p.Name, err) + } } // RefundOutstanding returns every outstanding stake to the player: chips |
