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.

308 lines
7.2 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, "useragent 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. var err error
  134. game, err = NewGame(
  135. gid.Id,
  136. float32(conf.Width),
  137. float32(conf.Height),
  138. conf.Obstacles,
  139. conf.Tick,
  140. conf.MaxPoints,
  141. "",
  142. )
  143. if err != nil {
  144. log.Printf("problem creating game: %s", gid.Id)
  145. websocket.JSON.Send(ws, NewFailure("game creation error"))
  146. return
  147. }
  148. go game.run()
  149. games.add(game)
  150. }
  151. player_id := idg.Hash()
  152. err = websocket.JSON.Send(ws, NewPlayerID(player_id))
  153. if err != nil {
  154. log.Printf("game %s: unable to send player_id to player %s", gid.Id, player_id)
  155. websocket.JSON.Send(ws, NewFailure("send error"))
  156. return
  157. } else {
  158. log.Printf("game %s: sent player id: %s", gid.Id, player_id)
  159. }
  160. var clientid ClientID
  161. err = websocket.JSON.Receive(ws, &clientid)
  162. if err != nil {
  163. log.Printf("unable to parse ClientID: gid: %s, player: %s", gid.Id, player_id)
  164. websocket.JSON.Send(ws, NewFailure("parse error"))
  165. return
  166. } else {
  167. log.Printf("game %s: recieved: %+v", gid.Id, clientid)
  168. }
  169. if v, msg := clientid.Valid(); !v {
  170. log.Printf("clientid is invalid: %+v", clientid)
  171. websocket.JSON.Send(
  172. ws,
  173. NewFailure(msg),
  174. )
  175. return
  176. }
  177. gameParam := game.gameParam()
  178. err = websocket.JSON.Send(ws, gameParam)
  179. if err != nil {
  180. log.Printf("%s %s game param parse error", gid.Id, player_id)
  181. websocket.JSON.Send(ws, NewFailure("game param parse error"))
  182. return
  183. } else {
  184. log.Printf("%s -> %s: sent %+v", gid.Id, player_id, gameParam)
  185. }
  186. switch clientid.Type {
  187. case "robot":
  188. var conf ClientConfig
  189. for {
  190. log.Printf("%s Waiting for client to send conf ...", player_id)
  191. err = websocket.JSON.Receive(ws, &conf)
  192. log.Printf("%s: conf received: %s", player_id, conf.ID)
  193. if err != nil {
  194. log.Printf("%s %s config parse error", gid.Id, player_id)
  195. websocket.JSON.Send(ws, NewFailure("config parse error"))
  196. return
  197. }
  198. // TODO: verify conf's type
  199. if conf.Valid(game.maxPoints) {
  200. log.Printf("%s -> %s: valid client config", gid.Id, player_id)
  201. _ = websocket.JSON.Send(ws, NewHandshake(player_id, true))
  202. break
  203. } else {
  204. log.Printf("%s: Config is INVALID, abort", player_id)
  205. _ = websocket.JSON.Send(ws, NewFailure("invalid config"))
  206. return
  207. }
  208. }
  209. p := NewPlayer(player_id, ws, game.bw)
  210. log.Printf("%s: made a player: %s", gid.Id, p.Id)
  211. convertedStats := map[string]Stats{}
  212. for name, stats := range conf.Stats {
  213. dstat := DeriveStats(stats)
  214. convertedStats[name] = dstat
  215. r := Robot{
  216. Stats: dstat,
  217. Id: idg.Hash(),
  218. Name: name,
  219. Health: 10,
  220. Heading: v.Vector2d{1, 0},
  221. Scanners: make([]Scanner, 0)}
  222. r.Health = r.Stats.Hp
  223. log.Printf("%s: adding robot: %s", p.Id, r.Id)
  224. r.reset(game)
  225. p.Robots = append(p.Robots, &r)
  226. }
  227. statsPayload := struct {
  228. Stats map[string]Stats `json:"stats"`
  229. Type string `json:"type"`
  230. }{
  231. Stats: convertedStats,
  232. Type: "stats",
  233. }
  234. err = websocket.JSON.Send(ws, &statsPayload)
  235. if err != nil {
  236. log.Printf("error sending convertedStats to client: %s", err)
  237. websocket.JSON.Send(ws, NewFailure("protocol error: convertedStats"))
  238. return
  239. } else {
  240. log.Printf("%s -> %s: sent stats payload", gid.Id, p.Id)
  241. }
  242. log.Printf("%s, %s: about to register this player", gid.Id, p.Id)
  243. game.register <- p
  244. log.Printf("%s, %s: registered player", gid.Id, p.Id)
  245. defer func() {
  246. log.Printf("%s, %s: about to unregister this player", gid.Id, p.Id)
  247. game.unregister <- p
  248. log.Printf("%s, %s: unregistered player", gid.Id, p.Id)
  249. }()
  250. go p.sender()
  251. log.Printf("%s -> %s: p.sender went", gid.Id, p.Id)
  252. p.recv()
  253. log.Printf(
  254. "%s (player): %v (robot) has been disconnected from %s (game)",
  255. p.Id,
  256. p.Robots[0].Id,
  257. gid.Id,
  258. )
  259. case "spectator":
  260. s := NewSpectator(player_id, ws, game.bw)
  261. log.Printf("%s, %s: about to register this spectator", gid.Id, s.Id)
  262. game.sregister <- s
  263. log.Printf("%s, %s: registered spectator", gid.Id, s.Id)
  264. defer func() {
  265. log.Printf("%s, %s: about to unregister this spectator", gid.Id, s.Id)
  266. game.sunregister <- s
  267. log.Printf("%s, %s: unregistered spectator", gid.Id, s.Id)
  268. }()
  269. go s.sender()
  270. log.Printf("%s -> %s: s.sender went", gid.Id, s.Id)
  271. s.recv()
  272. log.Printf("game %s: spectator %+v has been disconnected from this game", gid.Id, s)
  273. }
  274. }