Add initial JSON events
This commit is contained in:
parent
138a91e57d
commit
1c60039ed9
6 changed files with 137 additions and 32 deletions
15
PROTOCOL.md
15
PROTOCOL.md
|
@ -10,12 +10,17 @@ Log in to bgammon. A random username is assigned when none is provided.
|
|||
|
||||
This must be the first command sent when a client connects to bgammon.
|
||||
|
||||
### `json [on/off]`
|
||||
### `loginjson [username] [password]`
|
||||
|
||||
Log in to bgammon and enable JSON formatted responses.
|
||||
|
||||
All client applications should use the `loginjson` command to log in, as JSON
|
||||
formatted responses are more easily parsed by computers.
|
||||
|
||||
### `json <on/off>`
|
||||
|
||||
Turn JSON formatted messages on or off. JSON messages are not sent by default.
|
||||
|
||||
Graphical clients should send the `json on` command immediately after sending `login`.
|
||||
|
||||
### `help [command]`
|
||||
|
||||
Request help for all commands, or optionally a specific command.
|
||||
|
@ -24,11 +29,11 @@ Request help for all commands, or optionally a specific command.
|
|||
|
||||
List all games.
|
||||
|
||||
### `create [public/private] [password]`
|
||||
### `create <public/private> [password]`
|
||||
|
||||
List all games.
|
||||
|
||||
### `join [id] [password]`
|
||||
### `join <id> [password]`
|
||||
|
||||
Join game.
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
|
@ -94,6 +94,17 @@ func (g *serverGame) sendBoard(client *serverClient) {
|
|||
}
|
||||
}
|
||||
|
||||
func (g *serverGame) playerCount() int {
|
||||
c := 0
|
||||
if g.client1 != nil {
|
||||
c++
|
||||
}
|
||||
if g.client2 != nil {
|
||||
c++
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (g *serverGame) eachClient(f func(client *serverClient)) {
|
||||
if g.client1 != nil {
|
||||
f(g.client1)
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
|
@ -184,7 +185,7 @@ COMMANDS:
|
|||
|
||||
// Require users to send login command first.
|
||||
if cmd.client.account == -1 {
|
||||
if keyword == bgammon.CommandLogin || keyword == "l" {
|
||||
if keyword == bgammon.CommandLogin || keyword == bgammon.CommandLoginJSON || keyword == "l" || keyword == "lj" {
|
||||
var username []byte
|
||||
var password []byte
|
||||
switch len(params) {
|
||||
|
@ -204,6 +205,10 @@ COMMANDS:
|
|||
}
|
||||
cmd.client.name = username
|
||||
|
||||
if keyword == bgammon.CommandLoginJSON || keyword == "lj" {
|
||||
cmd.client.json = true
|
||||
}
|
||||
|
||||
s.sendWelcome(cmd.client)
|
||||
|
||||
log.Printf("login as %s - %s", username, password)
|
||||
|
@ -215,6 +220,13 @@ COMMANDS:
|
|||
}
|
||||
|
||||
clientGame := s.gameByClient(cmd.client)
|
||||
clientNumber := 0
|
||||
if clientGame != nil {
|
||||
clientNumber = 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
clientNumber = 2
|
||||
}
|
||||
}
|
||||
|
||||
switch keyword {
|
||||
case bgammon.CommandHelp, "h":
|
||||
|
@ -256,6 +268,23 @@ COMMANDS:
|
|||
}
|
||||
opponent.events <- []byte(fmt.Sprintf("say %s %s", cmd.client.name, bytes.Join(params, []byte(" "))))
|
||||
case bgammon.CommandList, "ls":
|
||||
if cmd.client.json {
|
||||
ev := bgammon.EventList{}
|
||||
for _, g := range s.games {
|
||||
ev.Games = append(ev.Games, bgammon.GameListing{
|
||||
ID: g.id,
|
||||
Password: len(g.password) != 0,
|
||||
Players: g.playerCount(),
|
||||
Name: string(g.name),
|
||||
})
|
||||
}
|
||||
buf, err := json.Marshal(ev)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cmd.client.events <- buf
|
||||
continue
|
||||
}
|
||||
cmd.client.events <- []byte("liststart Games list:")
|
||||
players := 0
|
||||
password := 0
|
||||
|
@ -357,18 +386,14 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
playerNumber := 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
playerNumber = 2
|
||||
}
|
||||
if !clientGame.roll(playerNumber) {
|
||||
if !clientGame.roll(clientNumber) {
|
||||
cmd.client.events <- []byte("notice It is not your turn to roll.")
|
||||
continue
|
||||
}
|
||||
clientGame.eachClient(func(client *serverClient) {
|
||||
roll1 := 0
|
||||
roll2 := 0
|
||||
if playerNumber == 1 {
|
||||
if clientNumber == 1 {
|
||||
roll1 = clientGame.Roll1
|
||||
} else {
|
||||
roll2 = clientGame.Roll2
|
||||
|
@ -391,11 +416,7 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
playerNumber := 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
playerNumber = 2
|
||||
}
|
||||
if clientGame.Turn != playerNumber {
|
||||
if clientGame.Turn != clientNumber {
|
||||
cmd.client.events <- []byte("failedmove It is not your turn to move.")
|
||||
continue
|
||||
}
|
||||
|
@ -432,7 +453,7 @@ COMMANDS:
|
|||
}
|
||||
|
||||
originalFrom, originalTo := from, to
|
||||
from, to = bgammon.FlipSpace(from, playerNumber), bgammon.FlipSpace(to, playerNumber)
|
||||
from, to = bgammon.FlipSpace(from, clientNumber), bgammon.FlipSpace(to, clientNumber)
|
||||
|
||||
legalMoves := gameCopy.LegalMoves()
|
||||
var found bool
|
||||
|
@ -443,7 +464,7 @@ COMMANDS:
|
|||
}
|
||||
}
|
||||
if !found {
|
||||
log.Printf("available legal moves: %s", bgammon.FormatMoves(legalMoves, playerNumber))
|
||||
log.Printf("available legal moves: %s", bgammon.FormatMoves(legalMoves, clientNumber))
|
||||
cmd.client.events <- []byte(fmt.Sprintf("failedmove %d/%d Illegal move.", originalFrom, originalTo))
|
||||
continue COMMANDS
|
||||
}
|
||||
|
@ -487,12 +508,7 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
playerNumber := 1
|
||||
if clientGame.client2 == cmd.client {
|
||||
playerNumber = 2
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader(clientGame.BoardState(playerNumber)))
|
||||
scanner := bufio.NewScanner(bytes.NewReader(clientGame.BoardState(clientNumber)))
|
||||
for scanner.Scan() {
|
||||
cmd.client.events <- append([]byte("notice "), scanner.Bytes()...)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ type Command string
|
|||
|
||||
const (
|
||||
CommandLogin = "login" // Log in with username and password, or as a guest.
|
||||
CommandLoginJSON = "loginjson" // Log in with username and password, or as a guest, and enable JSON messages.
|
||||
CommandHelp = "help" // Print help information.
|
||||
CommandJSON = "json" // Enable or disable JSON formatted messages.
|
||||
CommandSay = "say" // Send chat message.
|
||||
|
@ -20,3 +21,10 @@ const (
|
|||
CommandBoard = "board" // Print current board state in human-readable form.
|
||||
CommandDisconnect = "disconnect" // Disconnect from server.
|
||||
)
|
||||
|
||||
type EventType string
|
||||
|
||||
const (
|
||||
EventTypeWelcome = "welcome"
|
||||
EventTypeJoined = "joined"
|
||||
)
|
||||
|
|
74
event.go
74
event.go
|
@ -1,8 +1,78 @@
|
|||
package bgammon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// events are always received FROM the server
|
||||
|
||||
type Event struct {
|
||||
Player int
|
||||
Command
|
||||
Type string
|
||||
Player string
|
||||
}
|
||||
|
||||
type EventWelcome struct {
|
||||
PlayerName string
|
||||
Clients int
|
||||
Games int
|
||||
}
|
||||
|
||||
type EventJoined struct {
|
||||
GameID int
|
||||
PlayerName string
|
||||
}
|
||||
|
||||
type GameListing struct {
|
||||
ID int
|
||||
Password bool
|
||||
Players int
|
||||
Name string
|
||||
}
|
||||
|
||||
type EventList struct {
|
||||
Games []GameListing
|
||||
}
|
||||
|
||||
type EventSay struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
type EventBoard struct {
|
||||
GameState
|
||||
}
|
||||
|
||||
type EventRoll struct {
|
||||
Roll1 int
|
||||
Roll2 int
|
||||
}
|
||||
|
||||
type EventMove struct {
|
||||
Moves [][]int
|
||||
}
|
||||
|
||||
func DecodeEvent(message []byte) (interface{}, error) {
|
||||
e := &Event{}
|
||||
err := json.Unmarshal(message, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch e.Type {
|
||||
case EventTypeWelcome:
|
||||
ev := &EventWelcome{}
|
||||
err = json.Unmarshal(message, ev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ev, nil
|
||||
case EventTypeJoined:
|
||||
ev := &EventJoined{}
|
||||
err = json.Unmarshal(message, ev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ev, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("failed to decode event: unknown event type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue