You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
5.6 KiB

7 years ago
7 years ago
  1. package main
  2. import (
  3. "log"
  4. v "bitbucket.org/hackerbots/vector"
  5. "code.google.com/p/go.net/websocket"
  6. )
  7. // < the name of the game we want to join
  8. type GameID struct {
  9. Id string `json:"id"`
  10. }
  11. // > identify
  12. type PlayerID struct {
  13. Type string `json:"type"`
  14. Hash string `json:"id"`
  15. Failure
  16. }
  17. func NewPlayerID(id string) *PlayerID {
  18. return &PlayerID{
  19. Type: "idreq",
  20. Hash: id,
  21. }
  22. }
  23. // < [robot | spectator], name, client-type, game ID
  24. type ClientID struct {
  25. Type string `json:"type"`
  26. Name string `json:"name"`
  27. Useragent string `json:"useragent"`
  28. }
  29. func (c *ClientID) Valid() (bool, string) {
  30. switch c.Type {
  31. case "robot", "spectator":
  32. return true, ""
  33. }
  34. return false, "usergent must be 'robot' or 'spectator'"
  35. }
  36. type ClientConfig struct {
  37. ID string `json:"id"`
  38. Stats map[string]StatsRequest `json:"stats"`
  39. }
  40. func (config ClientConfig) Valid(max int) bool {
  41. total := 0
  42. for _, s := range config.Stats {
  43. total += (s.Speed +
  44. s.Hp +
  45. s.WeaponRadius +
  46. s.ScannerRadius +
  47. s.Acceleration +
  48. s.TurnSpeed +
  49. s.FireRate +
  50. s.WeaponDamage +
  51. s.WeaponSpeed)
  52. }
  53. if total > max {
  54. return false
  55. }
  56. return true
  57. }
  58. type BoardSize struct {
  59. Width float32 `json:"width"`
  60. Height float32 `json:"height"`
  61. }
  62. type GameParam struct {
  63. // TODO: should have information about max points in here
  64. BoardSize BoardSize `json:"boardsize"`
  65. MaxPoints int `json:"max_points"`
  66. Type string `json:"type"`
  67. }
  68. // > [OK | FULL | NOT AUTH], board size, game params
  69. type Handshake struct {
  70. ID string `json:"id"`
  71. Success bool `json:"success"`
  72. Type string `json:"type"`
  73. }
  74. func NewHandshake(id string, success bool) *Handshake {
  75. return &Handshake{
  76. ID: id,
  77. Success: success,
  78. Type: "handshake",
  79. }
  80. }
  81. type Message interface {
  82. }
  83. type Boardstate struct {
  84. MyRobots []Robot `json:"my_robots"`
  85. OtherRobots []OtherRobot `json:"robots"`
  86. Projectiles []Projectile `json:"projectiles"`
  87. Splosions []Splosion `json:"splosions"`
  88. Objects [][4]int `json:"objects"`
  89. Type string `json:"type"`
  90. Turn int `json:"turn"`
  91. AllBots []BotHealth `json:"all_bots"`
  92. Messages []string `json:"messages"`
  93. }
  94. func NewBoardstate() *Boardstate {
  95. return &Boardstate{
  96. MyRobots: []Robot{},
  97. OtherRobots: []OtherRobot{},
  98. Projectiles: []Projectile{},
  99. Splosions: []Splosion{},
  100. AllBots: []BotHealth{},
  101. Type: "boardstate",
  102. }
  103. }
  104. type GameOver struct {
  105. Winners []string `json:"winners"`
  106. Type string `json:"type"`
  107. }
  108. func NewGameOver() *GameOver {
  109. return &GameOver{
  110. Type: "gameover",
  111. Winners: make([]string, 0),
  112. }
  113. }
  114. type Failure struct {
  115. Reason string `json:"reason"`
  116. Type string `json:"type"`
  117. }
  118. func NewFailure(reason string) *Failure {
  119. return &Failure{
  120. Reason: reason,
  121. Type: "failure",
  122. }
  123. }
  124. func addPlayer(ws *websocket.Conn) {
  125. var gid GameID
  126. err := websocket.JSON.Receive(ws, &gid)
  127. if err != nil {
  128. log.Println("problem parsing the requested game id")
  129. return
  130. }
  131. game := games.get(gid.Id)
  132. if game == nil {
  133. game = NewGame(
  134. gid.Id,
  135. float32(conf.Width),
  136. float32(conf.Height),
  137. conf.Obstacles,
  138. conf.Tick,
  139. conf.MaxPoints,
  140. "",
  141. )
  142. go game.run()
  143. games.add(game)
  144. }
  145. player_id := idg.Hash()
  146. err = websocket.JSON.Send(ws, NewPlayerID(player_id))
  147. if err != nil {
  148. log.Printf("game %s: unable to send player_id to player %s", gid.Id, player_id)
  149. websocket.JSON.Send(ws, NewFailure("send error"))
  150. return
  151. }
  152. var clientid ClientID
  153. err = websocket.JSON.Receive(ws, &clientid)
  154. if err != nil {
  155. log.Printf("unable to parse ClientID: gid: %s, player: %s", gid.Id, player_id)
  156. websocket.JSON.Send(ws, NewFailure("parse error"))
  157. return
  158. }
  159. if v, msg := clientid.Valid(); !v {
  160. log.Printf("clientid is invalid: %+v", clientid)
  161. websocket.JSON.Send(
  162. ws,
  163. NewFailure(msg),
  164. )
  165. return
  166. }
  167. gameParam := game.gameParam()
  168. err = websocket.JSON.Send(ws, gameParam)
  169. if err != nil {
  170. log.Printf("%s %s game param parse error", gid.Id, player_id)
  171. websocket.JSON.Send(ws, NewFailure("game param parse error"))
  172. return
  173. }
  174. switch clientid.Type {
  175. case "robot":
  176. var conf ClientConfig
  177. for {
  178. log.Printf("%s Waiting for client to send conf ...", player_id)
  179. err = websocket.JSON.Receive(ws, &conf)
  180. log.Printf("%s: conf received: %+v", player_id, conf)
  181. if err != nil {
  182. log.Printf("%s %s config parse error", gid.Id, player_id)
  183. websocket.JSON.Send(ws, NewFailure("config parse error"))
  184. return
  185. }
  186. // TODO: verify conf's type
  187. if conf.Valid(game.maxPoints) {
  188. log.Printf("Config is Valid, continuing")
  189. _ = websocket.JSON.Send(ws, NewHandshake(player_id, true))
  190. break
  191. } else {
  192. log.Printf("Config is INVALID, abort")
  193. _ = websocket.JSON.Send(ws, NewHandshake(player_id, false))
  194. }
  195. }
  196. p := &player{
  197. Robots: []*Robot{},
  198. send: make(chan Message),
  199. ws: ws,
  200. Id: idg.Hash(),
  201. }
  202. for name, stats := range conf.Stats {
  203. r := Robot{
  204. Stats: DeriveStats(stats),
  205. Id: idg.Hash(),
  206. Name: name,
  207. Health: 10,
  208. Heading: v.Vector2d{1, 0},
  209. Scanners: make([]Scanner, 0)}
  210. r.Health = r.Stats.Hp
  211. log.Printf("%s: adding robot: %s", p.Id, r.Id)
  212. r.reset(game)
  213. p.Robots = append(p.Robots, &r)
  214. }
  215. game.register <- p
  216. defer func() {
  217. game.unregister <- p
  218. }()
  219. go p.sender()
  220. p.recv()
  221. log.Printf(
  222. "%s (player): %v (robot) has been disconnected from %s (game)",
  223. p.Id,
  224. p.Robots[0].Id,
  225. gid.Id,
  226. )
  227. case "spectator":
  228. s := &Spectator{
  229. send: make(chan Message),
  230. ws: ws,
  231. }
  232. game.sregister <- s
  233. defer func() {
  234. game.sunregister <- s
  235. }()
  236. s.sender()
  237. log.Printf("game %s: spectator %+v has been disconnected from this game\n", s)
  238. }
  239. }