diff options
| author | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-09-18 05:31:09 -0400 |
| commit | 153acb7f644d755c45533b7c5311e3ffa47e8973 (patch) | |
| tree | 7645e6f7b65bc3830b078e3b9336d2e6b199d584 /internal/game/core_login_char.go | |
| parent | 87d08f0151e643951769e323995f1c5ed89ee200 (diff) | |
| download | thehouseoficarus-153acb7f644d755c45533b7c5311e3ffa47e8973.tar.gz | |
fix: harden engine across casino, economy, concurrency, security, and content
Diffstat (limited to 'internal/game/core_login_char.go')
| -rw-r--r-- | internal/game/core_login_char.go | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/internal/game/core_login_char.go b/internal/game/core_login_char.go index 0f57d3c..3a2e324 100644 --- a/internal/game/core_login_char.go +++ b/internal/game/core_login_char.go @@ -9,6 +9,10 @@ import ( ) func (g *Game) handleNewCharName(sess *net.Session, input string) { + if sess.Account == nil { + g.resetToAccountName(sess) + return + } name := strings.TrimSpace(input) if sess.PendingChar == "connect" && len(sess.Account.Characters) > 0 { @@ -62,6 +66,10 @@ func (g *Game) handleNewCharName(sess *net.Session, input string) { } func (g *Game) connectCharacter(sess *net.Session, name string) { + if sess.Account == nil { + g.resetToAccountName(sess) + return + } // This whole function runs as one owner step (invoked from session // input): membership validation, the online check, registry // publication, and room entry are serialized against every other @@ -139,6 +147,10 @@ func (g *Game) connectCharacter(sess *net.Session, name string) { } func (g *Game) handleRenameChar(sess *net.Session, input string) { + if sess.Account == nil { + g.resetToAccountName(sess) + return + } name := strings.TrimSpace(input) if idx, err := parseChoiceIndex(name); err == nil && idx > 0 && idx <= len(sess.Account.Characters) { sess.PendingChar = sess.Account.Characters[idx-1] @@ -168,13 +180,32 @@ func (g *Game) handleRenameChar(sess *net.Session, input string) { // through a live session. Menu operations that rename or delete character // files must refuse while the character is online, otherwise the in-memory // player later overwrites or resurrects the moved/removed file. +// +// The lookup is case-insensitive: loggedInChars is keyed by the canonical +// on-disk character name, but callers pass names taken from hand-editable +// account files and admin file paths ("ALICE"), and character names keep the +// case their owner chose. Character identity in this game is otherwise +// case-insensitive (see isMemberOf), so liveness must be too - an exact-match +// lookup lets an online character's file be edited or deleted. func (g *Game) characterOnline(name string) bool { g.charsMu.Lock() defer g.charsMu.Unlock() - return g.loggedInChars[name] != nil + if g.loggedInChars[name] != nil { + return true + } + for logged, sess := range g.loggedInChars { + if sess != nil && strings.EqualFold(logged, name) { + return true + } + } + return false } func (g *Game) handleRenameCharName(sess *net.Session, input string) { + if sess.Account == nil { + g.resetToAccountName(sess) + return + } newName := strings.TrimSpace(input) oldName := sess.PendingChar if newName == "" { @@ -239,6 +270,10 @@ func (g *Game) showDeleteConfirm(sess *net.Session) { } func (g *Game) handleDeleteChar(sess *net.Session, input string) { + if sess.Account == nil { + g.resetToAccountName(sess) + return + } if sess.PendingChar == "" { name := strings.TrimSpace(input) if idx, err := parseChoiceIndex(name); err == nil && idx > 0 && idx <= len(sess.Account.Characters) { |
