fix: stop combatLoop goroutine and remove lobby room on session exit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 10:56:23 +09:00
parent e8887cd69a
commit 46afd82060
3 changed files with 32 additions and 5 deletions

View File

@@ -67,6 +67,7 @@ type GameSession struct {
actions map[string]PlayerAction // playerName -> action actions map[string]PlayerAction // playerName -> action
actionCh chan playerActionMsg actionCh chan playerActionMsg
combatSignal chan struct{} combatSignal chan struct{}
done chan struct{}
} }
type playerActionMsg struct { type playerActionMsg struct {
@@ -82,6 +83,16 @@ func NewGameSession() *GameSession {
actions: make(map[string]PlayerAction), actions: make(map[string]PlayerAction),
actionCh: make(chan playerActionMsg, 4), actionCh: make(chan playerActionMsg, 4),
combatSignal: make(chan struct{}, 1), combatSignal: make(chan struct{}, 1),
done: make(chan struct{}),
}
}
func (s *GameSession) Stop() {
select {
case <-s.done:
// already stopped
default:
close(s.done)
} }
} }
@@ -102,6 +113,12 @@ func (s *GameSession) StartGame() {
// combatLoop continuously runs turns while in combat phase // combatLoop continuously runs turns while in combat phase
func (s *GameSession) combatLoop() { func (s *GameSession) combatLoop() {
for { for {
select {
case <-s.done:
return
default:
}
s.mu.Lock() s.mu.Lock()
phase := s.state.Phase phase := s.state.Phase
gameOver := s.state.GameOver gameOver := s.state.GameOver
@@ -112,13 +129,12 @@ func (s *GameSession) combatLoop() {
} }
if phase == PhaseCombat { if phase == PhaseCombat {
s.RunTurn() // blocks until all actions collected or timeout s.RunTurn()
} else { } else {
// Not in combat, wait for an action signal to avoid busy-spinning
// We'll just sleep briefly and re-check
select { select {
case <-s.combatSignal: case <-s.combatSignal:
// Room entered, combat may have started case <-s.done:
return
} }
} }
} }

View File

@@ -41,6 +41,9 @@ func (s *GameSession) RunTurn() {
collected++ collected++
case <-timer.C: case <-timer.C:
goto resolve goto resolve
case <-s.done:
timer.Stop()
return
} }
} }
timer.Stop() timer.Stop()

View File

@@ -421,8 +421,16 @@ func (m Model) updateShop(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m Model) updateResult(msg tea.Msg) (tea.Model, tea.Cmd) { func (m Model) updateResult(msg tea.Msg) (tea.Model, tea.Cmd) {
if key, ok := msg.(tea.KeyMsg); ok { if key, ok := msg.(tea.KeyMsg); ok {
if isEnter(key) { if isEnter(key) {
m.screen = screenLobby if m.session != nil {
m.session.Stop()
m.session = nil
}
if m.lobby != nil && m.roomCode != "" {
m.lobby.RemoveRoom(m.roomCode)
}
m.roomCode = ""
m.rankingSaved = false m.rankingSaved = false
m.screen = screenLobby
m = m.withRefreshedLobby() m = m.withRefreshedLobby()
} else if isQuit(key) { } else if isQuit(key) {
return m, tea.Quit return m, tea.Quit