- package main
-
- import (
- "log"
-
- v "bitbucket.org/hackerbots/vector"
- "code.google.com/p/go.net/websocket"
- )
-
- // < 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(max int) 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)
- }
- if total > max {
- return false
- }
- return true
- }
-
- type BoardSize struct {
- Width float32 `json:"width"`
- Height float32 `json:"height"`
- }
-
- type GameParam struct {
- // TODO: should have information about max points in here
- BoardSize BoardSize `json:"boardsize"`
- MaxPoints int `json:"max_points"`
- Type string `json:"type"`
- }
-
- // > [OK | FULL | NOT AUTH], board size, game params
-
- 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 Message interface {
- }
-
- type Boardstate struct {
- MyRobots []Robot `json:"my_robots"`
- OtherRobots []OtherRobot `json:"robots"`
- Projectiles []Projectile `json:"projectiles"`
- Splosions []Splosion `json:"splosions"`
- Objects [][4]int `json:"objects"`
- Type string `json:"type"`
- Turn int `json:"turn"`
- AllBots []BotHealth `json:"all_bots"`
- Messages []string `json:"messages"`
- }
-
- func NewBoardstate() *Boardstate {
- return &Boardstate{
- MyRobots: []Robot{},
- OtherRobots: []OtherRobot{},
- Projectiles: []Projectile{},
- Splosions: []Splosion{},
- AllBots: []BotHealth{},
- Type: "boardstate",
- }
- }
-
- type GameOver struct {
- Winners []string `json:"winners"`
- Type string `json:"type"`
- }
-
- func NewGameOver() *GameOver {
- return &GameOver{
- Type: "gameover",
- Winners: make([]string, 0),
- }
- }
-
- 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 {
- game = NewGame(
- gid.Id,
- float32(conf.Width),
- float32(conf.Height),
- conf.Obstacles,
- conf.Tick,
- conf.MaxPoints,
- "",
- )
- go game.run()
- games.add(game)
- }
-
- 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 := game.gameParam()
- 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("%s: conf received: %+v", player_id, 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(game.maxPoints) {
- 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 Message),
- ws: ws,
- Id: idg.Hash(),
- }
-
- for name, stats := range conf.Stats {
- r := Robot{
- Stats: DeriveStats(stats),
- Id: idg.Hash(),
- Name: name,
- Health: 10,
- Heading: v.Vector2d{1, 0},
- Scanners: make([]Scanner, 0)}
- r.Health = r.Stats.Hp
- log.Printf("%s: adding robot: %s", p.Id, r.Id)
- r.reset(game)
- p.Robots = append(p.Robots, &r)
- }
-
- game.register <- p
-
- defer func() {
- game.unregister <- p
- }()
- go p.sender()
- p.recv()
- log.Printf(
- "%s (player): %v (robot) has been disconnected from %s (game)",
- p.Id,
- p.Robots[0].Id,
- gid.Id,
- )
- case "spectator":
- s := &Spectator{
- send: make(chan Message),
- 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)
- }
- }
|