parent
d0f8b45b0f
commit
28ba643bf9
3 changed files with 72 additions and 32 deletions
|
@ -16,6 +16,7 @@ type serverGame struct {
|
|||
password []byte
|
||||
client1 *serverClient
|
||||
client2 *serverClient
|
||||
spectators []*serverClient
|
||||
allowed1 []byte
|
||||
allowed2 []byte
|
||||
rematch int
|
||||
|
@ -79,6 +80,9 @@ func (g *serverGame) sendBoard(client *serverClient) {
|
|||
Available: g.LegalMoves(false),
|
||||
},
|
||||
}
|
||||
if g.client1 != client && g.client2 != client {
|
||||
ev.Spectating = true
|
||||
}
|
||||
|
||||
// Reverse spaces for white.
|
||||
if client.playerNumber == 2 {
|
||||
|
@ -160,11 +164,33 @@ func (g *serverGame) eachClient(f func(client *serverClient)) {
|
|||
if g.client2 != nil {
|
||||
f(g.client2)
|
||||
}
|
||||
for _, spectator := range g.spectators {
|
||||
f(spectator)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *serverGame) addClient(client *serverClient) (bool, string) {
|
||||
func (g *serverGame) addClient(client *serverClient) (spectator bool) {
|
||||
if g.allowed1 != nil && !bytes.Equal(client.name, g.allowed1) && !bytes.Equal(client.name, g.allowed2) {
|
||||
return false, "Match has already started."
|
||||
spectator = true
|
||||
} else if g.client1 != nil && g.client2 != nil {
|
||||
spectator = true
|
||||
}
|
||||
if spectator {
|
||||
for _, spec := range g.spectators {
|
||||
if spec == client {
|
||||
return true
|
||||
}
|
||||
}
|
||||
client.playerNumber = 1
|
||||
g.spectators = append(g.spectators, client)
|
||||
ev := &bgammon.EventJoined{
|
||||
GameID: g.id,
|
||||
PlayerNumber: 1,
|
||||
}
|
||||
ev.Player = string(client.name)
|
||||
client.sendEvent(ev)
|
||||
g.sendBoard(client)
|
||||
return spectator
|
||||
}
|
||||
|
||||
var playerNumber int
|
||||
|
@ -201,8 +227,6 @@ func (g *serverGame) addClient(client *serverClient) (bool, string) {
|
|||
}
|
||||
}()
|
||||
switch {
|
||||
case g.client1 != nil && g.client2 != nil:
|
||||
// Do not assign player number.
|
||||
case g.client1 != nil:
|
||||
g.client2 = client
|
||||
g.Player2.Name = string(client.name)
|
||||
|
@ -226,13 +250,7 @@ func (g *serverGame) addClient(client *serverClient) (bool, string) {
|
|||
playerNumber = 2
|
||||
}
|
||||
}
|
||||
|
||||
ok := playerNumber != 0
|
||||
var reason string
|
||||
if !ok {
|
||||
reason = "Match is full."
|
||||
}
|
||||
return ok, reason
|
||||
return spectator
|
||||
}
|
||||
|
||||
func (g *serverGame) removeClient(client *serverClient) {
|
||||
|
@ -275,6 +293,22 @@ func (g *serverGame) removeClient(client *serverClient) {
|
|||
g.Player2.Name = ""
|
||||
playerNumber = 2
|
||||
default:
|
||||
for i, spectator := range g.spectators {
|
||||
if spectator == client {
|
||||
g.spectators = append(g.spectators[:i], g.spectators[i+1:]...)
|
||||
|
||||
ev := &bgammon.EventLeft{}
|
||||
ev.Player = string(client.name)
|
||||
|
||||
client.sendEvent(ev)
|
||||
if !client.json {
|
||||
g.sendBoard(client)
|
||||
}
|
||||
|
||||
client.playerNumber = 0
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -334,6 +334,11 @@ func (s *server) gameByClient(c *serverClient) *serverGame {
|
|||
if g.client1 == c || g.client2 == c {
|
||||
return g
|
||||
}
|
||||
for _, spec := range g.spectators {
|
||||
if spec == c {
|
||||
return g
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -440,10 +445,8 @@ COMMANDS:
|
|||
rejoin = g.rejoin2
|
||||
}
|
||||
if rejoin {
|
||||
ok, _ := g.addClient(cmd.client)
|
||||
if ok {
|
||||
cmd.client.sendNotice(fmt.Sprintf("Rejoined match: %s", g.name))
|
||||
}
|
||||
g.addClient(cmd.client)
|
||||
cmd.client.sendNotice(fmt.Sprintf("Rejoined match: %s", g.name))
|
||||
}
|
||||
}
|
||||
s.gamesLock.RUnlock()
|
||||
|
@ -455,6 +458,15 @@ COMMANDS:
|
|||
}
|
||||
|
||||
clientGame := s.gameByClient(cmd.client)
|
||||
if clientGame != nil && clientGame.client1 != cmd.client && clientGame.client2 != cmd.client {
|
||||
switch keyword {
|
||||
case bgammon.CommandHelp, "h", bgammon.CommandJSON, bgammon.CommandList, "ls", bgammon.CommandBoard, "b", bgammon.CommandLeave, "l", bgammon.CommandDisconnect, bgammon.CommandPong:
|
||||
// These commands are allowed to be used by spectators.
|
||||
default:
|
||||
cmd.client.sendNotice("Command ignored: You are spectating this match.")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
switch keyword {
|
||||
case bgammon.CommandHelp, "h":
|
||||
|
@ -573,10 +585,7 @@ COMMANDS:
|
|||
g.name = gameName
|
||||
g.Points = points
|
||||
g.password = gamePassword
|
||||
ok, reason := g.addClient(cmd.client)
|
||||
if !ok {
|
||||
log.Panicf("failed to add client to newly created game %+v %+v: %s", g, cmd.client, reason)
|
||||
}
|
||||
g.addClient(cmd.client)
|
||||
|
||||
s.gamesLock.Lock()
|
||||
s.games = append(s.games, g)
|
||||
|
@ -651,15 +660,11 @@ COMMANDS:
|
|||
s.gamesLock.Unlock()
|
||||
continue COMMANDS
|
||||
}
|
||||
ok, reason := g.addClient(cmd.client)
|
||||
spectator := g.addClient(cmd.client)
|
||||
s.gamesLock.Unlock()
|
||||
|
||||
if !ok {
|
||||
cmd.client.sendEvent(&bgammon.EventFailedJoin{
|
||||
Reason: reason,
|
||||
})
|
||||
} else {
|
||||
cmd.client.sendNotice(fmt.Sprintf("Joined match: %s", g.name))
|
||||
cmd.client.sendNotice(fmt.Sprintf("Joined match: %s", g.name))
|
||||
if spectator {
|
||||
cmd.client.sendNotice("You are spectating this match. Chat messages are not relayed.")
|
||||
}
|
||||
continue COMMANDS
|
||||
}
|
||||
|
|
11
gamestate.go
11
gamestate.go
|
@ -8,6 +8,7 @@ type GameState struct {
|
|||
*Game
|
||||
PlayerNumber int
|
||||
Available [][]int // Legal moves.
|
||||
Spectating bool
|
||||
}
|
||||
|
||||
func (g *GameState) OpponentPlayer() Player {
|
||||
|
@ -75,7 +76,7 @@ func (g *GameState) Pips(player int) int {
|
|||
|
||||
// MayDouble returns whether the player may send the 'double' command.
|
||||
func (g *GameState) MayDouble() bool {
|
||||
if g.Winner != 0 {
|
||||
if g.Spectating || g.Winner != 0 {
|
||||
return false
|
||||
}
|
||||
return g.Points != 1 && g.Turn != 0 && g.Turn == g.PlayerNumber && g.Roll1 == 0 && !g.DoubleOffered && (g.DoublePlayer == 0 || g.DoublePlayer == g.PlayerNumber)
|
||||
|
@ -83,7 +84,7 @@ func (g *GameState) MayDouble() bool {
|
|||
|
||||
// MayRoll returns whether the player may send the 'roll' command.
|
||||
func (g *GameState) MayRoll() bool {
|
||||
if g.Winner != 0 || g.DoubleOffered {
|
||||
if g.Spectating || g.Winner != 0 || g.DoubleOffered {
|
||||
return false
|
||||
}
|
||||
switch g.Turn {
|
||||
|
@ -106,7 +107,7 @@ func (g *GameState) MayRoll() bool {
|
|||
|
||||
// MayOK returns whether the player may send the 'ok' command.
|
||||
func (g *GameState) MayOK() bool {
|
||||
if g.Winner != 0 {
|
||||
if g.Spectating || g.Winner != 0 {
|
||||
return false
|
||||
} else if g.Turn != 0 && g.Turn != g.PlayerNumber && g.DoubleOffered {
|
||||
return true
|
||||
|
@ -116,7 +117,7 @@ func (g *GameState) MayOK() bool {
|
|||
|
||||
// MayResign returns whether the player may send the 'resign' command.
|
||||
func (g *GameState) MayResign() bool {
|
||||
if g.Winner != 0 {
|
||||
if g.Spectating || g.Winner != 0 {
|
||||
return false
|
||||
}
|
||||
return g.Turn != 0 && g.Turn != g.PlayerNumber && g.DoubleOffered
|
||||
|
@ -124,7 +125,7 @@ func (g *GameState) MayResign() bool {
|
|||
|
||||
// MayReset returns whether the player may send the 'reset' command.
|
||||
func (g *GameState) MayReset() bool {
|
||||
if g.Winner != 0 {
|
||||
if g.Spectating || g.Winner != 0 {
|
||||
return false
|
||||
}
|
||||
return g.Turn != 0 && g.Turn == g.PlayerNumber && len(g.Moves) > 0
|
||||
|
|
Loading…
Reference in a new issue