state stuff

This commit is contained in:
Robin Appelman 2019-12-22 22:05:16 +01:00
commit 5031746e8b
2 changed files with 166 additions and 12 deletions

View file

@ -1,26 +1,39 @@
use tf_demo_parser::demo::parser::gamestateanalyser::GameStateAnalyser; #![feature(const_generics)]
use tf_demo_parser::{Demo, DemoParser, ParseError}; #![macro_use]
use wasm_bindgen::__rt::std::time::Instant;
use wasm_bindgen::prelude::*;
use web_sys::console;
#[wasm_bindgen] use crate::state::ParsedDemo;
pub fn parse_demo(buffer: &[u8]) -> Result<(), JsValue> { use tf_demo_parser::demo::parser::gamestateanalyser::{GameState, GameStateAnalyser};
let buffer = buffer.to_vec(); use tf_demo_parser::{Demo, DemoParser, ParseError};
parse_demo_inner(buffer).map_err(|e| e.to_string().into()) use wasm_bindgen::prelude::*;
mod state;
macro_rules! log {
($($arg:tt)*) => (web_sys::console::log_1(&JsValue::from(format!($($arg)*))))
} }
pub fn parse_demo_inner(buffer: Vec<u8>) -> Result<(), ParseError> { #[wasm_bindgen]
console::log_1(&JsValue::from_str(&format!("len: {}", buffer.len()))); pub fn parse_demo(buffer: Box<[u8]>) -> Result<(), JsValue> {
let buffer = buffer.into_vec();
let parsed = parse_demo_inner(buffer).map_err(|e| JsValue::from(e.to_string()))?;
log!("{:?}", parsed.players[2].get(10));
Ok(())
}
pub fn parse_demo_inner(buffer: Vec<u8>) -> Result<ParsedDemo, ParseError> {
let demo = Demo::new(buffer); let demo = Demo::new(buffer);
let parser = DemoParser::new_with_analyser(demo.get_stream(), GameStateAnalyser::default()); let parser = DemoParser::new_with_analyser(demo.get_stream(), GameStateAnalyser::default());
let (header, mut ticker) = parser.ticker()?; let (header, mut ticker) = parser.ticker()?;
let mut parsed_demo = ParsedDemo::new();
while ticker.tick()? { while ticker.tick()? {
// noop parsed_demo.push_state(ticker.state());
} }
console::log_1(&JsValue::from_str(&format!("{:?}", header))); Ok(parsed_demo)
Ok(())
} }
// This is like the `main` function, except for JavaScript. // This is like the `main` function, except for JavaScript.
@ -32,7 +45,7 @@ pub fn main_js() -> Result<(), JsValue> {
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
// Your code goes here! // Your code goes here!
console::log_1(&JsValue::from_str("Hello world!")); log!("Hello world!");
Ok(()) Ok(())
} }

141
src/state.rs Normal file
View file

@ -0,0 +1,141 @@
use std::ops::Index;
use tf_demo_parser::demo::parser::gamestateanalyser::{Class, GameState, Team};
use tf_demo_parser::demo::vector::VectorXY;
macro_rules! log {
($($arg:tt)*) => (web_sys::console::log_1(&wasm_bindgen::prelude::JsValue::from(format!($($arg)*))))
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Angle(u16);
impl From<f32> for Angle {
fn from(val: f32) -> Self {
Angle(val.rem_euclid(360.0) as u16)
}
}
impl From<Angle> for u16 {
fn from(val: Angle) -> Self {
val.0
}
}
#[derive(Debug, Clone, Default)]
pub struct ParsedDemo {
tick: usize,
pub players: Vec<ParsedPlayer>,
}
impl ParsedDemo {
pub fn new() -> Self {
Self::default()
}
pub fn push_state(&mut self, game_state: &GameState) {
for (index, player) in game_state.players.iter().enumerate() {
if let None = self.players.get(index) {
let mut new_player = ParsedPlayer::default();
// backfill with defaults
new_player.resize(self.tick);
self.players.push(new_player)
};
let parsed_player = &mut self.players[index];
parsed_player.push(
self.tick,
player.position.into(),
player.view_angle.into(),
player.health,
player.team,
player.class,
);
}
self.tick += 1;
}
}
#[derive(Debug, Default, Clone)]
pub struct ParsedPlayer {
position: Vec<VectorXY>,
angle: SparseVec<Angle, 1>,
health: SparseVec<u16, 4>,
team: SparseVec<Team, 128>,
class: SparseVec<Class, 128>,
}
#[derive(Debug, Default, Clone)]
pub struct PlayerState {
position: VectorXY,
angle: Angle,
health: u16,
team: Team,
class: Class,
}
impl ParsedPlayer {
fn push(
&mut self,
index: usize,
position: VectorXY,
angle: Angle,
health: u16,
team: Team,
class: Class,
) {
debug_assert!(self.position.len() == index);
self.position.push(position);
self.angle.push_index(index, angle);
self.health.push_index(index, health);
self.team.push_index(index, team);
self.class.push_index(index, class);
}
fn resize(&mut self, size: usize) {
self.position.resize_with(size, || VectorXY::default());
self.angle.resize(size);
self.health.resize(size);
self.team.resize(size);
self.class.resize(size);
}
pub fn len(&self) -> usize {
self.position.len()
}
pub fn get(&self, index: usize) -> PlayerState {
PlayerState {
position: self.position[index],
angle: self.angle[index],
health: self.health[index],
team: self.team[index],
class: self.class[index],
}
}
}
#[derive(Debug, Default, Clone)]
pub struct SparseVec<T: Default, const N: usize> {
inner: Vec<T>,
}
impl<T: Default, const N: usize> SparseVec<T, N> {
fn push_index(&mut self, index: usize, val: T) {
if index % N == 0 {
self.inner.push(val)
}
}
fn resize(&mut self, size: usize) {
self.inner.resize_with(size / N, Default::default)
}
}
impl<T: Default, const N: usize> Index<usize> for SparseVec<T, N> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.inner.index(index / N)
}
}