diff options
| author | historia <[not public]> | 2026-09-18 17:48:26 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 17:48:26 -0400 |
| commit | 8fe9e3c3fef0049df82281a62afe35dda516dfe2 (patch) | |
| tree | dd269f2c0710f334e19f00a191260ebc46284a90 /internal/game/game.go | |
| parent | 194164a77eb4f2479b94c19e6f0e1278ab608781 (diff) | |
| download | thehouseoficarus-8fe9e3c3fef0049df82281a62afe35dda516dfe2.tar.gz | |
fix: close combat ghost, admin traversal, login throttle, journal double-pay, and quality/economy gaps
Diffstat (limited to 'internal/game/game.go')
| -rw-r--r-- | internal/game/game.go | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/internal/game/game.go b/internal/game/game.go index 5ad1033..af2ff66 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -110,6 +110,12 @@ type Game struct { // Economy is the durable money journal; see economy.go. Economy *economyJournal + // loginThrottle applies an escalating per-(account, IP) delay to failed + // interactive password attempts. Lazily created so Game literals built + // directly in tests work without it. + loginThrottleOnce sync.Once + loginThrottle *loginThrottle + // owner serializes all live-state mutations; see owner.go. owner *owner ownerStop sync.Once @@ -197,6 +203,13 @@ func (g *Game) SetHub(hub *net.Hub) { return } if p := sess.Player; p != nil { + // The session is leaving the world: end any live fight and + // cancel a running logout countdown first, so neither keeps + // acting on a detached session (ghost combat that saves over + // a reconnected character, or a duplicate logout that drops + // the reconnected session's registry entry). + g.stopCombat(p.Name) + g.cancelRest(p.Name) g.restoreGodPlayer(p) g.persistLockedOnDisconnect(p) g.saveCharacter(p) @@ -443,6 +456,12 @@ func (g *Game) HandleSession(sess *net.Session, input string) { g.handleDangerConfirm(sess, input) case net.StateUndigConfirm: g.handleUndigConfirm(sess, input) + default: + // A declared state with no handler would otherwise silently swallow + // every line. Re-prompt and log so a future menu flow cannot strand + // the player on a dead input state. + log.Printf("unhandled session state %v", sess.State()) + sess.WriteLine("Something went wrong; please try again.") } } |
