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:
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
10
ui/model.go
10
ui/model.go
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user