Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

348 linhas
8.1KB

  1. package botserv
  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 (c *Controller) 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 := c.Games.get(gid.Id)
  132. if game == nil {
  133. var err error
  134. game, err = NewGame(
  135. gid.Id,
  136. float32(c.Conf.Width),
  137. float32(c.Conf.Height),
  138. c.Conf.Obstacles,
  139. c.Conf.Tick,
  140. c.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. c.Games.add(game)
  150. }
  151. player_id := c.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. reqEncs := []string{}
  178. err = websocket.JSON.Receive(ws, &reqEncs)
  179. if err != nil {
  180. log.Printf("%s %s unable to parse requested encodings", gid.Id, player_id)
  181. websocket.JSON.Send(ws, NewFailure("encoding recieve error"))
  182. return
  183. }
  184. prefEncs := []string{
  185. "gob",
  186. "json",
  187. }
  188. var encoding string
  189. encodingLoops:
  190. for _, prefEnc := range prefEncs {
  191. for _, reqEnc := range reqEncs {
  192. if reqEnc == prefEnc {
  193. encoding = prefEnc
  194. log.Println("selected following encoding:", encoding)
  195. break encodingLoops
  196. }
  197. }
  198. }
  199. if encoding == "" {
  200. log.Printf("%s %s unable to negociate encoding", gid.Id, player_id)
  201. websocket.JSON.Send(
  202. ws,
  203. NewFailure("no overlap on supported encodings; I suggest using json"),
  204. )
  205. return
  206. }
  207. gameParam := game.gameParam()
  208. gp := struct {
  209. GameParam
  210. Encoding string `json:"encoding"`
  211. }{
  212. GameParam: *gameParam,
  213. Encoding: encoding,
  214. }
  215. err = websocket.JSON.Send(ws, gp)
  216. if err != nil {
  217. log.Printf("%s %s game param send error", gid.Id, player_id)
  218. websocket.JSON.Send(ws, NewFailure("game param send error"))
  219. return
  220. } else {
  221. log.Printf("%s -> %s: sent %+v", gid.Id, player_id, gameParam)
  222. }
  223. switch clientid.Type {
  224. case "robot":
  225. var conf ClientConfig
  226. for {
  227. log.Printf("%s Waiting for client to send conf ...", player_id)
  228. err = websocket.JSON.Receive(ws, &conf)
  229. log.Printf("%s: conf received: %s", player_id, conf.ID)
  230. if err != nil {
  231. log.Printf("%s %s config parse error", gid.Id, player_id)
  232. websocket.JSON.Send(ws, NewFailure("config parse error"))
  233. return
  234. }
  235. // TODO: verify conf's type
  236. if conf.Valid(game.maxPoints) {
  237. log.Printf("%s -> %s: valid client config", gid.Id, player_id)
  238. _ = websocket.JSON.Send(ws, NewHandshake(player_id, true))
  239. break
  240. } else {
  241. log.Printf("%s: Config is INVALID, abort", player_id)
  242. _ = websocket.JSON.Send(ws, NewFailure("invalid config"))
  243. return
  244. }
  245. }
  246. p := NewPlayer(player_id, ws, game.bw, encoding)
  247. log.Printf("%s: made a player: %s", gid.Id, p.Id)
  248. convertedStats := map[string]Stats{}
  249. for name, stats := range conf.Stats {
  250. dstat := DeriveStats(stats)
  251. convertedStats[name] = dstat
  252. r := Robot{
  253. Stats: dstat,
  254. Id: c.Idg.Hash(),
  255. Name: name,
  256. Health: 10,
  257. Heading: v.Vector2d{1, 0},
  258. Scanners: make([]Scanner, 0)}
  259. r.Health = r.Stats.Hp
  260. log.Printf("%s: adding robot: %s", p.Id, r.Id)
  261. r.reset(game)
  262. p.Robots = append(p.Robots, &r)
  263. }
  264. statsPayload := struct {
  265. Stats map[string]Stats `json:"stats"`
  266. Type string `json:"type"`
  267. }{
  268. Stats: convertedStats,
  269. Type: "stats",
  270. }
  271. err = websocket.JSON.Send(ws, &statsPayload)
  272. if err != nil {
  273. log.Printf("error sending convertedStats to client: %s", err)
  274. websocket.JSON.Send(ws, NewFailure("protocol error: convertedStats"))
  275. return
  276. } else {
  277. log.Printf("%s -> %s: sent stats payload", gid.Id, p.Id)
  278. }
  279. log.Printf("%s, %s: about to register this player", gid.Id, p.Id)
  280. game.register <- p
  281. log.Printf("%s, %s: registered player", gid.Id, p.Id)
  282. defer func() {
  283. log.Printf("%s, %s: about to unregister this player", gid.Id, p.Id)
  284. game.unregister <- p
  285. log.Printf("%s, %s: unregistered player", gid.Id, p.Id)
  286. }()
  287. go p.sender()
  288. log.Printf("%s -> %s: p.sender went", gid.Id, p.Id)
  289. p.recv()
  290. log.Printf(
  291. "%s (player): %v (robot) has been disconnected from %s (game)",
  292. p.Id,
  293. p.Robots[0].Id,
  294. gid.Id,
  295. )
  296. case "spectator":
  297. s := NewSpectator(player_id, ws, game.bw, encoding)
  298. log.Printf("%s, %s: about to register this spectator", gid.Id, s.Id)
  299. game.sregister <- s
  300. log.Printf("%s, %s: registered spectator", gid.Id, s.Id)
  301. defer func() {
  302. log.Printf("%s, %s: about to unregister this spectator", gid.Id, s.Id)
  303. game.sunregister <- s
  304. log.Printf("%s, %s: unregistered spectator", gid.Id, s.Id)
  305. }()
  306. go s.sender()
  307. log.Printf("%s -> %s: s.sender went", gid.Id, s.Id)
  308. s.recv()
  309. log.Printf("game %s: spectator %+v has been disconnected from this game", gid.Id, s)
  310. }
  311. }