mirror of
https://codeberg.org/demostf/tf-demos-viewer.git
synced 2026-06-03 18:14:11 +02:00
playerstate packing
This commit is contained in:
parent
8c8e1c2f2e
commit
707695b45d
1 changed files with 114 additions and 17 deletions
131
src/state.rs
131
src/state.rs
|
|
@ -1,20 +1,21 @@
|
|||
use std::ops::Index;
|
||||
use tf_demo_parser::demo::parser::gamestateanalyser::{Class, GameState, Team};
|
||||
use tf_demo_parser::demo::vector::VectorXY;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use tf_demo_parser::demo::parser::gamestateanalyser::{Class, GameState, Team, World};
|
||||
use tf_demo_parser::demo::vector::{Vector, VectorXY};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Angle(u16);
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||
pub struct Angle(u8);
|
||||
|
||||
impl From<f32> for Angle {
|
||||
fn from(val: f32) -> Self {
|
||||
Angle(val.rem_euclid(360.0) as u16)
|
||||
let ratio = val.rem_euclid(360.0) / 360.0;
|
||||
Angle((ratio * u8::max_value() as f32) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Angle> for u16 {
|
||||
impl From<Angle> for f32 {
|
||||
fn from(val: Angle) -> Self {
|
||||
val.0
|
||||
let ratio = val.0 as f32 / u8::max_value() as f32;
|
||||
ratio * 360.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +59,111 @@ impl ParsedDemo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct PlayerState {
|
||||
position: VectorXY,
|
||||
angle: Angle,
|
||||
health: u16,
|
||||
team: Team,
|
||||
class: Class,
|
||||
}
|
||||
|
||||
impl PlayerState {
|
||||
pub fn pack(&self, world: &World) -> [u8; 8] {
|
||||
// for the purpose of viewing the demo in the browser we dont really need high accuracy for
|
||||
// position or angle, so we save a bunch of space by truncating those down to half the number
|
||||
// of bits
|
||||
fn pack_f32(val: f32, min: f32, max: f32) -> u16 {
|
||||
let ratio = (val - min) / (max - min);
|
||||
(ratio * u16::max_value() as f32) as u16
|
||||
}
|
||||
|
||||
let x = pack_f32(self.position.x, world.boundary_min.x, world.boundary_max.x).to_le_bytes();
|
||||
let y = pack_f32(self.position.y, world.boundary_min.y, world.boundary_max.y).to_le_bytes();
|
||||
let team_and_class = ((self.team as u8) << 4) + self.class as u8;
|
||||
let health_bytes = self.health.to_le_bytes();
|
||||
|
||||
[
|
||||
x[0],
|
||||
x[1],
|
||||
y[0],
|
||||
y[1],
|
||||
health_bytes[0],
|
||||
health_bytes[1],
|
||||
self.angle.0,
|
||||
team_and_class,
|
||||
]
|
||||
}
|
||||
|
||||
pub fn unpack(bytes: [u8; 8], world: &World) -> Self {
|
||||
fn unpack_f32(val: u16, min: f32, max: f32) -> f32 {
|
||||
let ratio = val as f32 / (u16::max_value() as f32);
|
||||
ratio * (max - min) + min
|
||||
}
|
||||
|
||||
let x = unpack_f32(
|
||||
u16::from_le_bytes([bytes[0], bytes[1]]),
|
||||
world.boundary_min.x,
|
||||
world.boundary_max.x,
|
||||
);
|
||||
let y = unpack_f32(
|
||||
u16::from_le_bytes([bytes[2], bytes[3]]),
|
||||
world.boundary_min.y,
|
||||
world.boundary_max.y,
|
||||
);
|
||||
let health = u16::from_le_bytes([bytes[4], bytes[5]]);
|
||||
let angle = Angle(bytes[6]);
|
||||
let team = Team::new(bytes[7] >> 4);
|
||||
let class = Class::new(bytes[7] & 15);
|
||||
|
||||
PlayerState {
|
||||
position: VectorXY { x, y },
|
||||
angle,
|
||||
health,
|
||||
team,
|
||||
class,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_packing() {
|
||||
let world = World {
|
||||
boundary_max: Vector {
|
||||
x: 10000.0,
|
||||
y: 10000.0,
|
||||
z: 100.0,
|
||||
},
|
||||
boundary_min: Vector {
|
||||
x: -10000.0,
|
||||
y: -10000.0,
|
||||
z: -100.0,
|
||||
},
|
||||
};
|
||||
|
||||
let input = PlayerState {
|
||||
position: VectorXY {
|
||||
x: 100.0,
|
||||
y: -5000.0,
|
||||
},
|
||||
angle: Angle::from(213.0),
|
||||
health: 250,
|
||||
team: Team::Blue,
|
||||
class: Class::Demoman,
|
||||
};
|
||||
|
||||
let bytes = input.pack(&world);
|
||||
|
||||
let unpacked = PlayerState::unpack(bytes, &world);
|
||||
assert_eq!(input.angle, unpacked.angle);
|
||||
assert_eq!(input.health, unpacked.health);
|
||||
assert_eq!(input.class, unpacked.class);
|
||||
assert_eq!(input.team, unpacked.team);
|
||||
|
||||
assert!(f32::abs(input.position.x - unpacked.position.x) < 0.5);
|
||||
assert!(f32::abs(input.position.y - unpacked.position.y) < 0.5);
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ParsedPlayer {
|
||||
position: Vec<VectorXY>,
|
||||
|
|
@ -67,15 +173,6 @@ pub struct ParsedPlayer {
|
|||
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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue