Commit 1fcfe6c8 authored by ceddral's avatar ceddral
Browse files

context: add Unregister

use to keep track of:
present players and order in lobby
connection status in game
parent 60956f99
......@@ -71,6 +71,10 @@ func (m *GameMenu) Redraw(s GameState) {
v.DrawTextClearLine(fg, bg, buf, 0, line)
maxlen := len(buf)
line++
if p.lostConnection {
v.DrawTextClearLine(fg, bg, []byte("!!disconnected!!"), 0, line)
goto next
}
buf = buf[:0]
for t := Token(0); t < tMax; t++ {
count := p.tokens[t]
......@@ -87,6 +91,7 @@ func (m *GameMenu) Redraw(s GameState) {
}
v.DrawTextClearLine(fg, bg, []byte("/c"), maxlen + 1, line - 1)
v.DrawTextClearLine(fg, bg, []byte("\\C"), maxlen + 1, line)
next:
line += 2
p = p.next
}
......@@ -109,6 +114,7 @@ type GamePlayer struct {
boardMode PieceMode
next *GamePlayer
score int
lostConnection bool
}
type Token int
......@@ -317,6 +323,7 @@ func NewGame(pns []string, extensions []string) (g *Game) {
boardy: -10,
boardMode: PMPlayers,
score: 0,
lostConnection: false,
}
p.menu = GameMenu{p}
g.players[name] = p
......@@ -362,23 +369,35 @@ func NewGame(pns []string, extensions []string) (g *Game) {
g.board = NewBoard(g)
// select first player
g.broadcastState(NewStatePlacePiece(g, g.players[pns[0]]))
agent := g.players[pns[0]]
g.broadcastState(NewStatePlacePiece(g, agent))
for _, p := range g.players {
go g.Loop(p)
go g.Loop(p, &StateInit{g, agent})
}
return
}
func (g *Game) Register(p *Player) {
func (g *Game) Register(glp *Player) {
g.Lock()
err := p.scr.Redraw()
p := g.players[glp.name]
p.lostConnection = false
err := glp.scr.Redraw()
if err != nil {
log.Println(err)
}
log.Printf("Player >%s< reconnected\n", p.name)
g.Unlock()
g.broadcastState(nil)
}
func (g *Game) Unregister(name string) {
g.Lock()
p := g.players[name]
p.lostConnection = true
g.Unlock()
g.broadcastState(nil)
}
func (g *Game) Resize(w, h int, glp *Player) {
......@@ -392,14 +411,17 @@ func (g *Game) Redraw(glp *Player) {
p.inputEvent<-[]byte{byte(keyRedraw)}
}
func (g *Game) Loop(p *GamePlayer) {
state := GameState(&StateInit{})
func (g *Game) Loop(p *GamePlayer, initState GameState) {
state := initState
fullRedraw := false
var err error
for {
log.Println("Game Player Loop:", p.name)
select {
case state = <-p.gameEvent:
case newState := <-p.gameEvent:
if newState != nil {
state = newState
}
log.Println("State:", state)
if state.getAgent() == p {
state.agentTransition(p)
......@@ -469,10 +491,13 @@ func anyStateAnyRoleAction(s GameState, p *GamePlayer, key Key) bool {
return true
}
type StateInit struct{}
type StateInit struct{
g *Game
agent *GamePlayer
}
func (s *StateInit) getAgent() *GamePlayer { return nil }
func (s *StateInit) getGame() *Game { return nil }
func (s *StateInit) getAgent() *GamePlayer { return s.agent }
func (s *StateInit) getGame() *Game { return s.g }
func (s *StateInit) String() string { return "StateInit" }
func (s *StateInit) agentTransition(p *GamePlayer) {}
func (s *StateInit) patientTransition(p *GamePlayer) {}
......
......@@ -17,12 +17,14 @@ type GameLobbyPlayer struct {
type GameLobby struct {
lock *sync.Mutex
players map[string]*GameLobbyPlayer
playerOrder []string
}
func NewGameLobby() (gl *GameLobby) {
return &GameLobby{
lock: &sync.Mutex{},
players: make(map[string]*GameLobbyPlayer),
playerOrder: make([]string, 0),
}
}
......@@ -36,6 +38,7 @@ func (gl *GameLobby) Unlock() {
func (gl *GameLobby) Register(glp *Player) {
gl.Lock()
gl.unregisterUnlocked(glp.name)
p := &GameLobbyPlayer{
name: glp.name,
scr: glp.scr,
......@@ -44,17 +47,37 @@ func (gl *GameLobby) Register(glp *Player) {
lobbyEvent: make(chan struct{}, 50),
inputEvent: glp.inputEvent,
}
if pOld, ok := gl.players[glp.name]; ok {
pOld.lobbyKill <- struct{}{} // trigger loop termination
close(pOld.lobbyEvent)
pOld.lobbyKill <- struct{}{} // await loop termination
}
gl.players[glp.name] = p
gl.playerOrder = append(gl.playerOrder, p.name)
gl.Unlock()
go gl.Loop(p)
gl.Update()
}
func (gl *GameLobby) Unregister(name string) {
gl.Lock()
gl.unregisterUnlocked(name)
gl.Unlock()
}
func (gl *GameLobby) unregisterUnlocked(name string) {
p, ok := gl.players[name]
if !ok {
return
}
p.lobbyKill <- struct{}{} // trigger loop termination
close(p.lobbyEvent)
p.lobbyKill <- struct{}{} // await loop termination
delete(gl.players, name)
for i, namei := range gl.playerOrder {
if namei != name {
continue
}
copy(gl.playerOrder[i:], gl.playerOrder[i+1:])
gl.playerOrder = gl.playerOrder[:len(gl.playerOrder) - 1]
}
}
func (gl *GameLobby) Resize(w, h int, glp *Player) {
p := gl.players[glp.name]
p.lobbyv.Resize(w, h)
......@@ -76,17 +99,12 @@ func (gl *GameLobby) Update() {
}
func (gl *GameLobby) StartGame() {
ps := make([]string, 0)
gl.Lock()
for name, p := range gl.players {
p.lobbyKill <- struct{}{} // trigger termination
close(p.lobbyEvent)
ps = append(ps, name)
}
for _, p := range gl.players {
p.lobbyKill <- struct{}{} // await termination
ps := make([]string, len(gl.playerOrder))
copy(ps, gl.playerOrder)
for name := range gl.players {
gl.unregisterUnlocked(name)
}
gl.players = make(map[string]*GameLobbyPlayer)
gl.Unlock()
NewGame(ps, []string{"base", "ext1"})
}
......@@ -120,7 +138,7 @@ func (p *GameLobbyPlayer) Redraw(gl *GameLobby) {
line := 0
fg := tg.ColorDefault
bg := tg.ColorDefault
for name := range gl.players {
for _, name := range gl.playerOrder {
v.DrawTextClearLine(fg, bg, []byte(name), 0, line)
line++
}
......
......@@ -11,6 +11,7 @@ import (
type Context interface {
Register(*Player)
Unregister(string)
Resize(int, int, *Player)
Redraw(*Player)
Lock()
......@@ -95,6 +96,17 @@ func NewPlayer(conn net.Conn) (p *Player) {
return p
}
func (p *Player) Close() {
p.inputKill <- struct{}{}
p.conn.Close()
p.windowSizeLoopKill <- struct{}{}
p.windowSizeLoopKill <- struct{}{}
close(p.connClosed)
close(p.inputKill)
close(p.inputEvent)
close(p.windowSizeLoopKill)
}
func StopTimer(t *time.Timer) {
if !t.Stop() {
select {
......@@ -127,6 +139,9 @@ func (p *Player) inputLoop() {
continue
}
p.connClosed <- struct{}{}
gs.Lock()
p.context.Unregister(p.name)
gs.Unlock()
// await termination, to unblock a reconnect
<-p.inputKill
return
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment