233 lines
4.8 KiB
Go
233 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"code.google.com/p/go.net/websocket"
|
|
"log"
|
|
)
|
|
|
|
// < the name of the game we want to join
|
|
type GameID struct {
|
|
Id string `json:"id"`
|
|
}
|
|
|
|
// > identify
|
|
type PlayerID struct {
|
|
Type string `json:"type"`
|
|
Hash string `json:"id"`
|
|
Failure
|
|
}
|
|
|
|
func NewPlayerID(id string) *PlayerID {
|
|
return &PlayerID{
|
|
Type: "idreq",
|
|
Hash: id,
|
|
}
|
|
}
|
|
|
|
// < [robot | spectator], name, client-type, game ID
|
|
type ClientID struct {
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
Useragent string `json:"useragent"`
|
|
}
|
|
|
|
func (c *ClientID) Valid() (bool, string) {
|
|
switch c.Type {
|
|
case "robot", "spectator":
|
|
return true, ""
|
|
}
|
|
return false, "usergent must be 'robot' or 'spectator'"
|
|
}
|
|
|
|
type ClientConfig struct {
|
|
ID string `json:"id"`
|
|
Stats map[string]StatsRequest `json:"stats"`
|
|
}
|
|
|
|
func (config ClientConfig) Valid() bool {
|
|
total := 0
|
|
for _, s := range config.Stats {
|
|
total += (s.Speed +
|
|
s.Hp +
|
|
s.WeaponRadius +
|
|
s.ScannerRadius +
|
|
s.Acceleration +
|
|
s.TurnSpeed +
|
|
s.FireRate +
|
|
s.WeaponDamage +
|
|
s.WeaponSpeed)
|
|
}
|
|
|
|
// allowing for 50 pts in every category
|
|
if total > 500 {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
type BoardSize struct {
|
|
Width float32 `json:"width"`
|
|
Height float32 `json:"height"`
|
|
}
|
|
|
|
type GameParam struct {
|
|
BoardSize BoardSize `json:"boardsize"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
// > [OK | FULL | NOT AUTH], board size, game params
|
|
func NewGameParam(w, h float32) *GameParam {
|
|
return &GameParam{
|
|
BoardSize: BoardSize{
|
|
Width: w,
|
|
Height: h,
|
|
},
|
|
Type: "gameparam",
|
|
}
|
|
}
|
|
|
|
type Handshake struct {
|
|
ID string `json:"id"`
|
|
Success bool `json:"success"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
func NewHandshake(id string, success bool) *Handshake {
|
|
return &Handshake{
|
|
ID: id,
|
|
Success: success,
|
|
Type: "handshake",
|
|
}
|
|
}
|
|
|
|
type Failure struct {
|
|
Reason string `json:"reason"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
func NewFailure(reason string) *Failure {
|
|
return &Failure{
|
|
Reason: reason,
|
|
Type: "failure",
|
|
}
|
|
}
|
|
|
|
func addPlayer(ws *websocket.Conn) {
|
|
var gid GameID
|
|
err := websocket.JSON.Receive(ws, &gid)
|
|
if err != nil {
|
|
log.Println("problem parsing the requested game id")
|
|
return
|
|
}
|
|
|
|
game := games.get(gid.Id)
|
|
if game == nil {
|
|
force := *debug
|
|
if force {
|
|
game = NewGame(gid.Id, float32(*width), float32(*height))
|
|
go game.run()
|
|
games.add(game)
|
|
} else {
|
|
log.Printf("ERROR: game '%s' not found", gid.Id)
|
|
websocket.JSON.Send(ws, NewFailure("game 404"))
|
|
return
|
|
}
|
|
}
|
|
|
|
player_id := idg.Hash()
|
|
err = websocket.JSON.Send(ws, NewPlayerID(player_id))
|
|
if err != nil {
|
|
log.Printf("game %s: unable to send player_id to player %s", gid.Id, player_id)
|
|
websocket.JSON.Send(ws, NewFailure("send error"))
|
|
return
|
|
}
|
|
|
|
var clientid ClientID
|
|
err = websocket.JSON.Receive(ws, &clientid)
|
|
if err != nil {
|
|
log.Printf("unable to parse ClientID: gid: %s, player: %s", gid.Id, player_id)
|
|
websocket.JSON.Send(ws, NewFailure("parse error"))
|
|
return
|
|
}
|
|
if v, msg := clientid.Valid(); !v {
|
|
log.Printf("clientid is invalid: %+v", clientid)
|
|
websocket.JSON.Send(
|
|
ws,
|
|
NewFailure(msg),
|
|
)
|
|
return
|
|
}
|
|
|
|
gameParam := NewGameParam(game.width, game.height)
|
|
err = websocket.JSON.Send(ws, gameParam)
|
|
if err != nil {
|
|
log.Printf("%s %s game param parse error", gid.Id, player_id)
|
|
websocket.JSON.Send(ws, NewFailure("game param parse error"))
|
|
return
|
|
}
|
|
|
|
switch clientid.Type {
|
|
case "robot":
|
|
var conf ClientConfig
|
|
for {
|
|
log.Printf("%s Waiting for client to send conf ...", player_id)
|
|
err = websocket.JSON.Receive(ws, &conf)
|
|
log.Printf("conf received: %+v", conf)
|
|
|
|
if err != nil {
|
|
log.Printf("%s %s config parse error", gid.Id, player_id)
|
|
websocket.JSON.Send(ws, NewFailure("config parse error"))
|
|
return
|
|
}
|
|
|
|
// TODO: verify conf's type
|
|
if conf.Valid() {
|
|
log.Printf("Config is Valid, continuing")
|
|
_ = websocket.JSON.Send(ws, NewHandshake(player_id, true))
|
|
break
|
|
} else {
|
|
log.Printf("Config is INVALID, abort")
|
|
_ = websocket.JSON.Send(ws, NewHandshake(player_id, false))
|
|
}
|
|
}
|
|
|
|
p := &player{
|
|
Robots: []*Robot{},
|
|
send: make(chan *Boardstate),
|
|
ws: ws,
|
|
}
|
|
|
|
for name, stats := range conf.Stats {
|
|
r := Robot{
|
|
Stats: DeriveStats(stats),
|
|
Id: idg.Hash(),
|
|
Name: name,
|
|
Health: 10,
|
|
Scanners: make([]Scanner, 0)}
|
|
r.Health = r.Stats.Hp
|
|
log.Printf("Adding Robot: %v", r)
|
|
r.reset(game)
|
|
p.Robots = append(p.Robots, &r)
|
|
}
|
|
|
|
game.register <- p
|
|
defer func() {
|
|
game.unregister <- p
|
|
}()
|
|
go p.sender()
|
|
p.recv()
|
|
log.Printf("game %s: player %v has been disconnected from this game\n", gid.Id, p.Robots[0].Id)
|
|
case "spectator":
|
|
s := &Spectator{
|
|
send: make(chan *Boardstate),
|
|
ws: ws,
|
|
}
|
|
game.sregister <- s
|
|
defer func() {
|
|
game.sunregister <- s
|
|
}()
|
|
s.sender()
|
|
log.Printf("game %s: spectator %+v has been disconnected from this game\n", s)
|
|
}
|
|
}
|