Refactored the Rust Snakebot codebase. (#7)

* Normal logging now logs to stdout;
  * Renamed Inbound::GameLinkEvent to Inbound::Gamelink;
  * Renamed the struct GameResultSnake to GameResult;
  * Added Inbound::GameResult;
* Rewrote the message handling to become more succinct;
* Turned the default_gamesettings function into a Default impl;
* Made the snake smaller and prettier;
* Replaced some direction checking code with less code;
* Added logging messages to all callbacks;
* Added as_movement_delta to the Direction impl;
* Added nice error messages to the message parsing;
* Moved some code in maputil to increase the DRY-factor.
This commit is contained in:
Rembane
2017-04-21 15:49:42 +02:00
committed by Martin Barksten
parent 435bd355d4
commit 061da11d43
6 changed files with 156 additions and 261 deletions

View File

@ -23,5 +23,5 @@ additive = false
[loggers.snake] [loggers.snake]
level = "debug" level = "debug"
appenders = [ "snake" ] appenders = [ "console" ]
additive = false additive = false

View File

@ -1,12 +1,13 @@
#![allow(non_snake_case)]
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate quick_error; #[macro_use] extern crate quick_error;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
extern crate clap; extern crate clap;
extern crate config; extern crate config;
extern crate log4rs; extern crate log4rs;
extern crate rustc_version; extern crate rustc_version;
extern crate serde; extern crate serde;
extern crate serde_json;
extern crate target_info; extern crate target_info;
extern crate ws; extern crate ws;
@ -17,7 +18,7 @@ mod structs;
mod util; mod util;
use clap::{ Arg, App }; use clap::{ Arg, App };
use messages::{ Inbound }; use messages::{ Inbound, Outbound, handle_inbound_msg, render_outbound_message };
use snake::{ Snake }; use snake::{ Snake };
use std::path::Path; use std::path::Path;
use std::string::{ String }; use std::string::{ String };
@ -74,9 +75,8 @@ struct Client {
fn route_msg(client: &mut Client, str_msg: &String) -> Result<(), ClientError> { fn route_msg(client: &mut Client, str_msg: &String) -> Result<(), ClientError> {
let snake = &mut client.snake; let snake = &mut client.snake;
let inbound_msg = try!(messages::parse_inbound_msg(str_msg));
match inbound_msg { match try!(handle_inbound_msg(str_msg)) {
Inbound::GameEnded(msg) => { Inbound::GameEnded(msg) => {
snake.on_game_ended(&msg); snake.on_game_ended(&msg);
if client.config.venue == "training" { if client.config.venue == "training" {
@ -88,10 +88,13 @@ fn route_msg(client: &mut Client, str_msg: &String) -> Result<(), ClientError> {
try!(client.out.close(ws::CloseCode::Normal)); try!(client.out.close(ws::CloseCode::Normal));
}, },
Inbound::MapUpdate(msg) => { Inbound::MapUpdate(msg) => {
let direction = maputil::direction_as_string(&snake.get_next_move(&msg)); let m = render_outbound_message(Outbound::RegisterMove {
let response = try!(messages::create_register_move_msg(direction, msg)); direction: snake.get_next_move(&msg),
debug!(target: LOG_TARGET, "Responding with RegisterMove {:?}", response); gameTick: msg.gameTick,
try!(client.out.send(response)); receivingPlayerId: msg.receivingPlayerId,
gameId: msg.gameId });
debug!(target: LOG_TARGET, "Responding with RegisterMove {:?}", m);
try!(client.out.send(m));
}, },
Inbound::SnakeDead(msg) => { Inbound::SnakeDead(msg) => {
snake.on_snake_dead(&msg); snake.on_snake_dead(&msg);
@ -104,9 +107,9 @@ fn route_msg(client: &mut Client, str_msg: &String) -> Result<(), ClientError> {
snake.on_player_registered(&msg); snake.on_player_registered(&msg);
if msg.gameMode == "TRAINING" { if msg.gameMode == "TRAINING" {
let response = try!(messages::create_start_game_msg()); let m = render_outbound_message(Outbound::StartGame);
debug!(target: LOG_TARGET, "Requesting a game start {:?}", response); debug!(target: LOG_TARGET, "Requesting a game start {:?}", m);
try!(client.out.send(response)); try!(client.out.send(m));
}; };
info!(target: LOG_TARGET, "Starting heart beat"); info!(target: LOG_TARGET, "Starting heart beat");
@ -119,9 +122,12 @@ fn route_msg(client: &mut Client, str_msg: &String) -> Result<(), ClientError> {
Inbound::HeartBeatResponse(_) => { Inbound::HeartBeatResponse(_) => {
// do nothing // do nothing
}, },
Inbound::GameLinkEvent(msg) => { Inbound::GameLink(msg) => {
info!(target: LOG_TARGET, "Watch game at {}", msg.url); info!(target: LOG_TARGET, "Watch game at {}", msg.url);
}, },
Inbound::GameResult(msg) => {
info!(target: LOG_TARGET, "We got some game result! {:?}", msg);
},
Inbound::UnrecognizedMessage => { Inbound::UnrecognizedMessage => {
error!(target: LOG_TARGET, "Received unrecognized message {:?}", str_msg); error!(target: LOG_TARGET, "Received unrecognized message {:?}", str_msg);
} }
@ -130,28 +136,17 @@ fn route_msg(client: &mut Client, str_msg: &String) -> Result<(), ClientError> {
Ok(()) Ok(())
} }
impl ws::Handler for Client { impl ws::Handler for Client {
fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> { fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
debug!(target: LOG_TARGET, "Connection to Websocket opened"); debug!(target: LOG_TARGET, "Connection to Websocket opened");
let m = render_outbound_message(Outbound::ClientInfo);
let client_info = messages::create_client_info_msg(); info!(target: LOG_TARGET, "Sending client info to server: {:?}", m);
if let Ok(message) = client_info { try!(self.out.send(m));
info!(target: LOG_TARGET, "Sending client info to server: {:?}", message); let msg = render_outbound_message(Outbound::RegisterPlayer {
try!(self.out.send(message)); playerName: self.config.snake_name.clone(),
} else { gameSettings: Default::default() });
error!(target: LOG_TARGET, "Unable to create client info message {:?}", client_info); info!(target: LOG_TARGET, "Registering player with message: {:?}", msg);
try!(self.out.close(ws::CloseCode::Error)); self.out.send(msg)
}
let parse_msg = messages::create_play_registration_msg(self.config.snake_name.clone());
if let Ok(response) = parse_msg {
info!(target: LOG_TARGET, "Registering player with message: {:?}", response);
self.out.send(response)
} else {
error!(target: LOG_TARGET, "Unable to create play registration message {:?}", parse_msg);
self.out.close(ws::CloseCode::Error)
}
} }
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> { fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
@ -251,16 +246,9 @@ fn do_heart_beat(id: String, out: Arc<ws::Sender>, done_receiver: mpsc::Receiver
} }
debug!(target: LOG_TARGET, "Sending heartbeat request"); debug!(target: LOG_TARGET, "Sending heartbeat request");
let send_result = out.send(render_outbound_message(Outbound::HeartBeat { receivingPlayerId: id.clone() }));
let id = id.clone(); if let Err(e) = send_result {
let parsed_msg = messages::create_heart_beat_msg(id); error!(target: LOG_TARGET, "Unable to send heartbeat, got error {:?}", e);
if let Ok(heart_beat) = parsed_msg {
let send_result = out.send(heart_beat);
if let Err(e) = send_result {
error!(target: LOG_TARGET, "Unable to send heartbeat, got error {:?}", e);
}
} else {
error!(target: LOG_TARGET, "Unable to parse heart beat message {:?}", parsed_msg);
} }
} }
} }

View File

@ -1,5 +1,6 @@
use structs::{ Map, SnakeInfo }; use structs::{ Map, SnakeInfo };
use util; use util;
use serde::ser::{ Serialize, Serializer };
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum Tile<'a> { pub enum Tile<'a> {
@ -11,7 +12,7 @@ pub enum Tile<'a> {
SnakeBody { coordinate: (i32,i32), snake: &'a SnakeInfo } SnakeBody { coordinate: (i32,i32), snake: &'a SnakeInfo }
} }
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
pub enum Direction { pub enum Direction {
Down, Down,
Up, Up,
@ -19,23 +20,27 @@ pub enum Direction {
Right Right
} }
pub fn direction_as_string(direction: &Direction) -> String { impl Serialize for Direction {
let s = match direction { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
&Direction::Down => "DOWN", where S: Serializer
&Direction::Up => "UP", {
&Direction::Left => "LEFT", serializer.serialize_str(match *self {
&Direction::Right => "RIGHT" Direction::Down => "DOWN",
}; Direction::Up => "UP",
Direction::Left => "LEFT",
String::from(s) Direction::Right => "RIGHT",
})
}
} }
pub fn direction_as_movement_delta(direction: &Direction) -> (i32,i32) { impl Direction {
match direction { pub fn as_movement_delta(&self) -> (i32,i32) {
&Direction::Down => (0, 1), match *self {
&Direction::Up => (0, -1), Direction::Down => ( 0, 1),
&Direction::Left => (-1, 0), Direction::Up => ( 0, -1),
&Direction::Right => (1, 0) Direction::Left => (-1, 0),
Direction::Right => ( 1, 0)
}
} }
} }
@ -83,7 +88,7 @@ impl Map {
} }
pub fn can_snake_move_in_direction(&self, snake: &SnakeInfo, direction: Direction) -> bool { pub fn can_snake_move_in_direction(&self, snake: &SnakeInfo, direction: Direction) -> bool {
let (xd,yd) = direction_as_movement_delta(&direction); let (xd,yd) = direction.as_movement_delta();
let (x,y) = util::translate_position(snake.positions[0], self.width); let (x,y) = util::translate_position(snake.positions[0], self.width);
self.is_tile_available_for_movement((x+xd,y+yd)) self.is_tile_available_for_movement((x+xd,y+yd))

View File

@ -1,40 +1,12 @@
use structs; use structs;
use serde_json::{ from_str, to_string, Error };
use target_info::Target; use target_info::Target;
use rustc_version; use rustc_version::{version};
use maputil::{Direction};
// Inbound use structs::{GameSettings};
pub const GAME_ENDED: &'static str = use serde_json::{ from_str, from_value, Error, Map, Value };
"se.cygni.snake.api.event.GameEndedEvent"; use std::iter::FromIterator;
pub const TOURNAMENT_ENDED: &'static str =
"se.cygni.snake.api.event.TournamentEndedEvent";
pub const MAP_UPDATE: &'static str =
"se.cygni.snake.api.event.MapUpdateEvent";
pub const SNAKE_DEAD: &'static str =
"se.cygni.snake.api.event.SnakeDeadEvent";
pub const GAME_STARTING: &'static str =
"se.cygni.snake.api.event.GameStartingEvent";
pub const PLAYER_REGISTERED: &'static str =
"se.cygni.snake.api.response.PlayerRegistered";
pub const INVALID_PLAYER_NAME: &'static str =
"se.cygni.snake.api.exception.InvalidPlayerName";
pub const HEART_BEAT_RESPONSE: &'static str =
"se.cygni.snake.api.response.HeartBeatResponse";
pub const GAME_LINK_EVENT: &'static str =
"se.cygni.snake.api.event.GameLinkEvent";
// Outbound
const REGISTER_PLAYER_MESSAGE_TYPE: &'static str =
"se.cygni.snake.api.request.RegisterPlayer";
const START_GAME: &'static str =
"se.cygni.snake.api.request.StartGame";
const REGISTER_MOVE: &'static str =
"se.cygni.snake.api.request.RegisterMove";
const HEART_BEAT_REQUEST: &'static str =
"se.cygni.snake.api.request.HeartBeatRequest";
const CLIENT_INFO: &'static str =
"se.cygni.snake.api.request.ClientInfo";
#[derive(Serialize, Deserialize, Debug)]
pub enum Inbound { pub enum Inbound {
GameEnded(structs::GameEnded), GameEnded(structs::GameEnded),
TournamentEnded(structs::TournamentEnded), TournamentEnded(structs::TournamentEnded),
@ -44,97 +16,73 @@ pub enum Inbound {
PlayerRegistered(structs::PlayerRegistered), PlayerRegistered(structs::PlayerRegistered),
InvalidPlayerName(structs::InvalidPlayerName), InvalidPlayerName(structs::InvalidPlayerName),
HeartBeatResponse(structs::HeartBeatResponse), HeartBeatResponse(structs::HeartBeatResponse),
GameLinkEvent(structs::GameLink), GameLink(structs::GameLink),
GameResult(structs::GameResult),
UnrecognizedMessage UnrecognizedMessage
} }
pub fn parse_inbound_msg(msg: &String) -> Result<Inbound, Error> { /// We turn the string into `Inbound` by converting the string into a
let msg: Inbound = /// JSON object, extracting the type-field from the object, and using the
if msg.contains(GAME_ENDED) { /// last part of the type-field to get the correct constructor in `Inbound`.
Inbound::GameEnded(try!(from_str(msg))) /// Then we let Serde do its magic and deserialize a constructed JSON object
} else if msg.contains(TOURNAMENT_ENDED) { /// with the constructor name as type. If the type has a Event suffix it is
Inbound::TournamentEnded(try!(from_str(msg))) /// removed since almost all `Inbound` messages are events.
} else if msg.contains(MAP_UPDATE) { ///
Inbound::MapUpdate(try!(from_str(msg))) /// Example:
} else if msg.contains(SNAKE_DEAD) { /// { type: "foo.bar.baz.GameResult", <Some JSON data> }
Inbound::SnakeDead(try!(from_str(msg))) /// ---------- This is the part we extract and hand to serde.
} else if msg.contains(GAME_STARTING) { /// Like this: {GameResult: <Some JSON data>}
Inbound::GameStarting(try!(from_str(msg))) ///
} else if msg.contains(PLAYER_REGISTERED) { pub fn handle_inbound_msg(s: &str) -> Result<Inbound, Error> {
Inbound::PlayerRegistered(try!(from_str(msg))) let mut json_value = from_str::<Value>(s)
} else if msg.contains(INVALID_PLAYER_NAME) { .expect(&format!("Couldn't parse string into JSON: {:?}", s));
Inbound::InvalidPlayerName(try!(from_str(msg))) let mut map = json_value.as_object_mut()
} else if msg.contains(HEART_BEAT_RESPONSE) { .expect(&format!("Couldn't parse string into JSON object: {:?}", s));
Inbound::HeartBeatResponse(try!(from_str(msg))) let type_value = map.remove("type").expect(&format!("Couldn't find key `type` in: {:?}", &map));
} else if msg.contains(GAME_LINK_EVENT) { let type_str = type_value.as_str().expect(&format!("Couldn't turn JSON Value into string: {:?}", &map));
Inbound::GameLinkEvent(try!(from_str(msg))) let typ = type_str.rsplit('.').next()
} else { .expect(&format!("The type parser needs a dot-separated string, this string lacks dots: {:?}", type_str))
Inbound::UnrecognizedMessage .replace("Event", "");
}; from_value(Value::Object(Map::from_iter(vec![(typ, Value::Object(map.clone()))])))
Ok(msg)
} }
pub enum Outbound {
pub fn create_play_registration_msg(name: String) -> Result<String, Error> { RegisterPlayer{playerName: String, gameSettings: GameSettings},
to_string(&structs::PlayRegistration { StartGame,
type_: String::from(REGISTER_PLAYER_MESSAGE_TYPE), RegisterMove{direction: Direction, gameTick: u32, receivingPlayerId: String, gameId: String},
playerName: name, HeartBeat{receivingPlayerId: String},
gameSettings: default_gamesettings() ClientInfo,
})
} }
pub fn create_start_game_msg() -> Result<String, Error> { pub fn render_outbound_message(msg: Outbound) -> String {
to_string(&structs::StartGame { (match msg {
type_: String::from(START_GAME) Outbound::RegisterPlayer {playerName, gameSettings} => json!({
}) "type": "se.cygni.snake.api.request.RegisterPlayer",
"playerName": playerName,
"gameSettings": gameSettings
}),
Outbound::StartGame => json!({
"type": "se.cygni.snake.api.request.StartGame",
}),
Outbound::RegisterMove {direction, gameTick, receivingPlayerId, gameId} => json!({
"type": "se.cygni.snake.api.request.RegisterMove",
"direction": direction,
"gameTick": gameTick,
"receivingPlayerId": receivingPlayerId,
"gameId": gameId,
}),
Outbound::HeartBeat {receivingPlayerId} => json!({
"type": "se.cygni.snake.api.request.HeartBeatRequest",
"receivingPlayerId": receivingPlayerId,
}),
Outbound::ClientInfo => json!({
"type": "se.cygni.snake.api.request.ClientInfo",
"language": "Rust",
"languageVersion": version().unwrap().to_string(),
"operatingSystem": Target::os(),
"operatingSystemVersion": "???",
"clientVersion": option_env!("CARGO_PKG_VERSION").unwrap_or("0.1337"),
}),
}).to_string()
} }
pub fn create_register_move_msg(direction: String, request: structs::MapUpdate) -> Result<String, Error> {
to_string(&structs::RegisterMove {
type_: String::from(REGISTER_MOVE),
direction: direction,
gameTick: request.gameTick,
receivingPlayerId: request.receivingPlayerId,
gameId: request.gameId
})
}
pub fn create_heart_beat_msg(id: String) -> Result<String, Error> {
to_string(&structs::HeartBeatRequest {
type_: String::from( HEART_BEAT_REQUEST ),
receivingPlayerId: id
})
}
pub fn create_client_info_msg() -> Result<String, Error> {
to_string(&structs::ClientInfo {
type_: String::from(CLIENT_INFO),
language: String::from("rust"),
languageVersion: format!("{}", rustc_version::version().unwrap()),
operatingSystem: String::from(Target::os()),
operatingSystemVersion: String::from(""),
clientVersion: String::from(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
})
}
pub fn default_gamesettings() -> structs::GameSettings {
structs::GameSettings {
maxNoofPlayers: 5,
startSnakeLength: 1,
timeInMsPerTick: 250,
obstaclesEnabled: true,
foodEnabled: true,
headToTailConsumes: true,
tailConsumeGrows: false,
addFoodLikelihood: 15,
removeFoodLikelihood: 5,
spontaneousGrowthEveryNWorldTick: 3,
trainingGame: false,
pointsPerLength: 1,
pointsPerFood: 2,
pointsPerCausedDeath: 5,
pointsPerNibble: 10,
noofRoundsTailProtectedAfterNibble: 3,
}
}

View File

@ -1,4 +1,4 @@
use structs::{ MapUpdate, GameEnded, TournamentEnded, SnakeDead, GameStarting, PlayerRegistered, InvalidPlayerName}; use structs::{ MapUpdate, GameEnded, TournamentEnded, SnakeDead, GameStarting, PlayerRegistered, InvalidPlayerName };
use maputil::{ Direction }; use maputil::{ Direction };
use util::{ translate_positions }; use util::{ translate_positions };
@ -10,28 +10,19 @@ impl Snake {
pub fn get_next_move(&self, msg: &MapUpdate) -> Direction { pub fn get_next_move(&self, msg: &MapUpdate) -> Direction {
debug!(target: LOG_TARGET, "Game map updated, tick: {}", msg.gameTick); debug!(target: LOG_TARGET, "Game map updated, tick: {}", msg.gameTick);
let ref map = msg.map; let map = &msg.map;
let player_id = &msg.receivingPlayerId; let snake = map.get_snake_by_id(&msg.receivingPlayerId).unwrap();
let snake = map.get_snake_by_id(player_id).unwrap();
debug!(target: LOG_TARGET, "Food can be found at {:?}", translate_positions(&map.foodPositions, map.width)); debug!(target: LOG_TARGET, "Food can be found at {:?}", translate_positions(&map.foodPositions, map.width));
debug!(target: LOG_TARGET, "My snake positions are {:?}", translate_positions(&snake.positions, map.width)); debug!(target: LOG_TARGET, "My snake positions are {:?}", translate_positions(&snake.positions, map.width));
for &d in [Direction::Down, Direction::Left, Direction::Right, Direction::Up].into_iter() {
let direction = if map.can_snake_move_in_direction(snake, Direction::Down) { if map.can_snake_move_in_direction(snake, d) {
Direction::Down debug!(target: LOG_TARGET, "Snake will move in direction {:?}", d);
} else if map.can_snake_move_in_direction(snake, Direction::Left) { return d;
Direction::Left }
} else if map.can_snake_move_in_direction(snake, Direction::Right) { }
Direction::Right debug!(target: LOG_TARGET, "Snake cannot but will move down.");
} else if map.can_snake_move_in_direction(snake, Direction::Up) { return Direction::Down;
Direction::Up
} else {
// this is bad
Direction::Down
};
debug!(target: LOG_TARGET, "Snake will move in direction {:?}", direction);
direction
} }
pub fn on_game_ended(&self, msg: &GameEnded) { pub fn on_game_ended(&self, msg: &GameEnded) {
@ -47,14 +38,14 @@ impl Snake {
} }
pub fn on_game_starting(&self, _: &GameStarting) { pub fn on_game_starting(&self, _: &GameStarting) {
debug!(target: LOG_TARGET, "All snakes are ready to rock. Game is starting.");
} }
pub fn on_player_registered(&self, _: &PlayerRegistered) { pub fn on_player_registered(&self, _: &PlayerRegistered) {
debug!(target: LOG_TARGET, "Player has been registered.");
} }
pub fn on_invalid_playername(&self, _: &InvalidPlayerName) { pub fn on_invalid_playername(&self, _: &InvalidPlayerName) {
debug!(target: LOG_TARGET, "Player name invalid.");
} }
} }

View File

@ -20,52 +20,31 @@ pub struct GameSettings {
pub noofRoundsTailProtectedAfterNibble: u32, pub noofRoundsTailProtectedAfterNibble: u32,
} }
#[derive(Serialize, Deserialize, Debug)] impl Default for GameSettings {
pub struct PlayRegistration { fn default() -> GameSettings {
#[serde(rename="type")] GameSettings {
pub type_: String, maxNoofPlayers: 5,
pub playerName: String, startSnakeLength: 1,
pub gameSettings: GameSettings, timeInMsPerTick: 250,
} obstaclesEnabled: true,
foodEnabled: true,
#[derive(Serialize, Deserialize, Debug)] headToTailConsumes: true,
pub struct ClientInfo { tailConsumeGrows: false,
#[serde(rename="type")] addFoodLikelihood: 15,
pub type_: String, removeFoodLikelihood: 5,
pub language: String, spontaneousGrowthEveryNWorldTick: 3,
pub languageVersion: String, trainingGame: false,
pub operatingSystem: String, pointsPerLength: 1,
pub operatingSystemVersion: String, pointsPerFood: 2,
pub clientVersion: String pointsPerCausedDeath: 5,
} pointsPerNibble: 10,
noofRoundsTailProtectedAfterNibble: 3,
#[derive(Serialize, Deserialize, Debug)] }
pub struct RegisterMove { }
#[serde(rename="type")]
pub type_: String,
pub direction: String,
pub gameTick: u32,
pub receivingPlayerId: String,
pub gameId: String
}
#[derive(Serialize, Deserialize, Debug)]
pub struct StartGame {
#[serde(rename="type")]
pub type_: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct HeartBeatRequest {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct PlayerRegistered { pub struct PlayerRegistered {
#[serde(rename="type")]
pub type_: String,
pub gameId: String, pub gameId: String,
pub gameMode: String, pub gameMode: String,
pub receivingPlayerId: String, pub receivingPlayerId: String,
@ -75,8 +54,6 @@ pub struct PlayerRegistered {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct MapUpdate { pub struct MapUpdate {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String, pub receivingPlayerId: String,
pub gameId: String, pub gameId: String,
pub gameTick: u32, pub gameTick: u32,
@ -85,15 +62,11 @@ pub struct MapUpdate {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct InvalidPlayerName { pub struct InvalidPlayerName {
#[serde(rename="type")]
pub type_: String,
pub reasonCode: u32, pub reasonCode: u32,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GameEnded { pub struct GameEnded {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String, pub receivingPlayerId: String,
pub playerWinnerId: String, pub playerWinnerId: String,
pub gameId: String, pub gameId: String,
@ -103,8 +76,6 @@ pub struct GameEnded {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SnakeDead { pub struct SnakeDead {
#[serde(rename="type")]
pub type_: String,
pub playerId: String, pub playerId: String,
pub x: u32, pub x: u32,
pub y: u32, pub y: u32,
@ -115,8 +86,6 @@ pub struct SnakeDead {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GameStarting { pub struct GameStarting {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String, pub receivingPlayerId: String,
pub gameId: String, pub gameId: String,
pub noofPlayers: u32, pub noofPlayers: u32,
@ -126,15 +95,11 @@ pub struct GameStarting {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct HeartBeatResponse { pub struct HeartBeatResponse {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String pub receivingPlayerId: String
} }
#[derive(Serialize, Deserialize, Debug, PartialEq)] #[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct GameLink { pub struct GameLink {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String, pub receivingPlayerId: String,
pub gameId: String, pub gameId: String,
pub url: String, pub url: String,
@ -142,18 +107,16 @@ pub struct GameLink {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct TournamentEnded { pub struct TournamentEnded {
#[serde(rename="type")]
pub type_: String,
pub receivingPlayerId: String, pub receivingPlayerId: String,
pub tournamentId: String, pub tournamentId: String,
pub tournamentName: String, pub tournamentName: String,
pub gameResult: Vec<GameResultSnake>, pub gameResult: Vec<GameResult>,
pub gameId: String, pub gameId: String,
pub playerWinnerId: String, pub playerWinnerId: String,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GameResultSnake { pub struct GameResult {
pub points: i32, pub points: i32,
pub playerId: String, pub playerId: String,
pub name: String pub name: String