Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive Serialize and Deserialize from BoostPad, CarInfo and GameState #11

Merged
merged 6 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exclude = [".git*", "CMake*", "collision_meshes", "rustfmt.toml", "*.py", "pytho
autocxx = "0.26.0"
cxx = { version = "1.0.83", features = ["c++20"] }
glam = { version = "0.25.0", optional = true }
serde = { version = "1.0.195", optional = true, features = ["derive"] }

[build-dependencies]
glob = "0.3.0"
Expand All @@ -28,6 +29,7 @@ default = ["debug_logging", "bin"]
debug_logging = []
glam = ["dep:glam"]
bin = []
serde_utils = ["serde"]

[target.'cfg(not(any(target_arch = "x86", target_arch = "x86_64")))'.dependencies]
# use glam with experimental support for portable SIMD when not running on x86
Expand All @@ -38,6 +40,7 @@ glam = { version = "0.25.0", optional = true, features = ["core-simd"] }
byteorder = "1.4.3"
ctrlc = "3.3.1"
rand = "0.8.5"
serde_json = "1.0.111"

[[example]]
name = "rlviser_socket"
Expand Down
15 changes: 15 additions & 0 deletions src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ use core::pin::Pin;
use cxx::UniquePtr;
use std::{error::Error, fmt};

#[cfg(feature = "serde_utils")]
use crate::serde_utils;
#[cfg(feature = "serde_utils")]
use serde::{Deserialize, Serialize};

impl fmt::Debug for GameMode {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -144,26 +149,35 @@ impl fmt::Debug for DemoMode {
}

#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde_utils", derive(Serialize, Deserialize))]
pub struct BoostPad {
pub is_big: bool,
pub position: Vec3,
#[cfg_attr(feature = "serde_utils", serde(with = "serde_utils::BoostPadStateDerive"))]
pub state: BoostPadState,
}

#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde_utils", derive(Serialize, Deserialize))]
pub struct CarInfo {
pub id: u32,
#[cfg_attr(feature = "serde_utils", serde(with = "serde_utils::TeamDerive"))]
pub team: Team,
#[cfg_attr(feature = "serde_utils", serde(with = "serde_utils::CarStateDerive"))]
pub state: CarState,
#[cfg_attr(feature = "serde_utils", serde(with = "serde_utils::CarConfigDerive"))]
pub config: CarConfig,
}

#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde_utils", derive(Serialize, Deserialize))]
pub struct GameState {
pub tick_rate: f32,
pub tick_count: u64,
#[cfg_attr(feature = "serde_utils", serde(with = "serde_utils::GameModeDerive"))]
pub game_mode: GameMode,
pub cars: Vec<CarInfo>,
#[cfg_attr(feature = "serde_utils", serde(with = "serde_utils::BallStateDerive"))]
pub ball: BallState,
pub pads: Vec<BoostPad>,
}
Expand Down Expand Up @@ -565,6 +579,7 @@ impl<const N: usize> LinearPieceCurve<N> {
}
}

#[cfg_attr(feature = "serde_utils", derive(Serialize, Deserialize))]
pub struct CarSpawnPos {
pub x: f32,
pub y: f32,
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
pub mod bytes;
#[cfg(feature = "glam")]
pub mod glam_ext;
#[cfg(feature = "serde_utils")]
mod serde_utils;
#[cfg(feature = "serde_utils")]
pub use serde;

pub mod consts;

Expand Down Expand Up @@ -460,8 +464,12 @@ pub mod sim {
}

pub mod math {
#[cfg(feature = "serde_utils")]
use serde::{Deserialize, Serialize};

#[repr(C, align(16))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde_utils", derive(Serialize, Deserialize))]
pub struct Vec3 {
pub x: f32,
pub y: f32,
Expand All @@ -478,6 +486,7 @@ pub mod math {

#[repr(C, align(16))]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde_utils", derive(Serialize, Deserialize))]
pub struct RotMat {
pub forward: Vec3,
pub right: Vec3,
Expand Down
155 changes: 155 additions & 0 deletions src/serde_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
pub use serde;

use serde::{Deserialize, Serialize};

use crate::{
math::{RotMat, Vec3},
sim::{
BallHitInfo, BallState, BoostPadState, CarConfig, CarControls, CarState, GameMode, HeatseekerInfo, Team,
WheelPairConfig,
},
};

// impl Serialize for Vec3 {
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
// where
// S: serde::Serializer {
// let mut s = serializer.serialize_struct("Vec3", 4)?;
// s.serialize_field("x", &self.x)?;
// s.serialize_field("y", &self.y)?;
// s.serialize_field("z", &self.z)?;
// s.serialize_field("_w", &self._w)?;
// s.end()
// }
// }

#[derive(Serialize, Deserialize)]
#[serde(remote = "BallHitInfo")]
pub struct BallHitInfoDerive {
is_valid: bool,
relative_pos_on_ball: Vec3,
ball_pos: Vec3,
extra_hit_vel: Vec3,
tick_count_when_hit: u64,
tick_count_when_extra_impulse_applied: u64,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "BoostPadState")]
pub struct BoostPadStateDerive {
is_active: bool,
cooldown: f32,
cur_locked_car_id: u32,
prev_locked_car_id: u32,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "Team")]
#[allow(clippy::upper_case_acronyms)]
pub enum TeamDerive {
BLUE,
ORANGE,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "GameMode")]
#[allow(clippy::upper_case_acronyms)]
pub enum GameModeDerive {
SOCCAR,
HOOPS,
HEATSEEKER,
SNOWDAY,
#[allow(non_camel_case_types)]
THE_VOID,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "CarControls")]
pub struct CarControlsDerive {
pub throttle: f32,
pub steer: f32,
pub pitch: f32,
pub yaw: f32,
pub roll: f32,
pub boost: bool,
pub jump: bool,
pub handbrake: bool,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "CarState")]
pub struct CarStateDerive {
update_counter: u64,
pos: Vec3,
rot_mat: RotMat,
vel: Vec3,
ang_vel: Vec3,
is_on_ground: bool,
has_jumped: bool,
has_double_jumped: bool,
has_flipped: bool,
last_rel_dodge_torque: Vec3,
jump_time: f32,
flip_time: f32,
is_flipping: bool,
is_jumping: bool,
air_time_since_jump: f32,
boost: f32,
time_spent_boosting: f32,
is_supersonic: bool,
supersonic_time: f32,
handbrake_val: f32,
is_auto_flipping: bool,
auto_flip_timer: f32,
auto_flip_torque_scale: f32,
has_contact: bool,
contact_normal: Vec3,
other_car_id: u32,
cooldown_timer: f32,
is_demoed: bool,
demo_respawn_timer: f32,
#[serde(with = "BallHitInfoDerive")]
ball_hit_info: BallHitInfo,
#[serde(with = "CarControlsDerive")]
last_controls: CarControls,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "WheelPairConfig")]
pub struct WheelPairConfigDerive {
wheel_radius: f32,
suspension_rest_length: f32,
connection_point_offset: Vec3,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "CarConfig")]
pub struct CarConfigDerive {
hitbox_size: Vec3,
hitbox_pos_offset: Vec3,
#[serde(with = "WheelPairConfigDerive")]
front_wheels: WheelPairConfig,
#[serde(with = "WheelPairConfigDerive")]
back_wheels: WheelPairConfig,
dodge_deadzone: f32,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "HeatseekerInfo")]
pub struct HeatseekerInfoDerive {
pub y_target_dir: f32,
pub cur_target_speed: f32,
pub time_since_hit: f32,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "BallState")]
pub struct BallStateDerive {
update_counter: u64,
pos: Vec3,
rot_mat: RotMat,
vel: Vec3,
ang_vel: Vec3,
#[serde(with = "HeatseekerInfoDerive")]
hs_info: HeatseekerInfo,
}
35 changes: 35 additions & 0 deletions tests/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,38 @@ fn demoed() {
// arena.pin_mut().step(15);
// assert!(DEMOED.load(Ordering::Relaxed));
// }

#[cfg(feature = "serde_utils")]
#[test]
fn game_state_serialize() {
use serde_json;

INIT.call_once(|| init(None));
let mut arena = Arena::default_standard();
let _ = arena.pin_mut().add_car(Team::ORANGE, CarConfig::breakout());
let _ = arena.pin_mut().add_car(Team::BLUE, CarConfig::hybrid());
arena.pin_mut().step(120);

let game_state = arena.pin_mut().get_game_state();
let json_state = serde_json::to_string(&game_state);
match json_state {
Ok(val) => println!("GOT JSON GAMESTATE:\n {val}"),
Err(e) => panic!("GOT ERROR IN GAMESTATE SERIALIZE: {e}"),
};

let car_info = game_state.cars[0];
let json_car_info = serde_json::to_string(&car_info);
match json_car_info {
Ok(val) => println!("GOT JSON CARINFO:\n {val}"),
Err(e) => panic!("GOT ERROR IN CARINFO SERIALIZE: {e}"),
};

let pad_state = game_state.pads[0];
let json_pad_state = serde_json::to_string(&pad_state);
match json_pad_state {
Ok(val) => println!("GOT JSON BOOSTPAD:\n {val}"),
Err(e) => panic!("GOT ERROR IN BOOSTPAD SERIALIZE: {e}"),
};

arena.pin_mut().reset_tick_count();
}
Loading