ubered status

This commit is contained in:
Robin Appelman 2025-06-26 00:42:43 +02:00
commit 32cb59264f
5 changed files with 45 additions and 56 deletions

7
Cargo.lock generated
View file

@ -541,12 +541,15 @@ dependencies = [
[[package]] [[package]]
name = "tf-demo-parser" name = "tf-demo-parser"
version = "0.5.1" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecbf06f08d668b350dce132a30888848306aebbf498fa6a5212ff65ba0a85dd2"
dependencies = [ dependencies = [
"bitbuffer", "bitbuffer",
"enumflags2", "enumflags2",
"fnv", "fnv",
"itertools", "itertools",
"log",
"main_error", "main_error",
"num-traits 0.2.19", "num-traits 0.2.19",
"num_enum", "num_enum",
@ -561,7 +564,7 @@ dependencies = [
[[package]] [[package]]
name = "tf-demos-viewer" name = "tf-demos-viewer"
version = "0.2.1" version = "0.2.2"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"serde", "serde",

View file

@ -1,7 +1,7 @@
[package] [package]
name = "tf-demos-viewer" name = "tf-demos-viewer"
description = "JS bindings for demo parser" description = "JS bindings for demo parser"
version = "0.2.1" version = "0.2.2"
authors = ["Robin Appelman <robin@icewind.nl>"] authors = ["Robin Appelman <robin@icewind.nl>"]
categories = ["wasm"] categories = ["wasm"]
edition = "2021" edition = "2021"
@ -26,7 +26,7 @@ wasm-bindgen = "0.2.96"
wee_alloc = { version = "0.4.2", optional = true } wee_alloc = { version = "0.4.2", optional = true }
web-sys = { version = "0.3.22", features = ["console"] } web-sys = { version = "0.3.22", features = ["console"] }
js-sys = "0.3.22" js-sys = "0.3.22"
tf-demo-parser = { version = "0.5.1", path = "../tf-demo-parser" } tf-demo-parser = "0.6.2"
serde = { version = "1.0.215", features = ["derive"] } serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0.133" serde_json = "1.0.133"

8
flake.lock generated
View file

@ -33,16 +33,16 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1732923073, "lastModified": 1750880979,
"narHash": "sha256-OxrZizAeWllfavAj73qRlZirc7ig4gZdm2U+hgdAHk0=", "narHash": "sha256-pzGtNlk34NLBylIgARHjUNjOhfwa0RmqdWZ2ZOFj0OU=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d20209c9cb07495799ae423a305e31ef40d25edb", "rev": "b639654086cba4ddd4ecb889a3c44635c89aa83f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "id": "nixpkgs",
"ref": "release-24.11", "ref": "release-25.05",
"type": "indirect" "type": "indirect"
} }
}, },

View file

@ -2,7 +2,7 @@
inputs = { inputs = {
utils.url = "github:numtide/flake-utils"; utils.url = "github:numtide/flake-utils";
naersk.url = "github:nix-community/naersk"; naersk.url = "github:nix-community/naersk";
nixpkgs.url = "nixpkgs/release-24.11"; nixpkgs.url = "nixpkgs/release-25.05";
rust-overlay.url = "github:oxalica/rust-overlay"; rust-overlay.url = "github:oxalica/rust-overlay";
}; };

View file

@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tf_demo_parser::demo::data::game_state::{Projectile, ProjectileType}; use tf_demo_parser::demo::data::game_state::{PlayerCondition, Projectile, ProjectileType};
use tf_demo_parser::demo::data::DemoTick; use tf_demo_parser::demo::data::DemoTick;
use tf_demo_parser::demo::gamevent::GameEvent; use tf_demo_parser::demo::gamevent::GameEvent;
use tf_demo_parser::demo::header::Header; use tf_demo_parser::demo::header::Header;
@ -74,6 +74,7 @@ impl ParsedDemo {
team: player.team, team: player.team,
class: player.class, class: player.class,
charge: player.charge, charge: player.charge,
ubered: player.has_condition(PlayerCondition::Invulnerable),
}; };
if self.players.get(index).is_none() { if self.players.get(index).is_none() {
@ -164,6 +165,7 @@ pub struct PlayerState {
team: Team, team: Team,
class: Class, class: Class,
charge: u8, charge: u8,
ubered: bool,
} }
impl PlayerState { impl PlayerState {
@ -182,9 +184,12 @@ impl PlayerState {
let y = pack_f32(self.position.y, world.boundary_min.y, world.boundary_max.y).to_le_bytes(); let y = pack_f32(self.position.y, world.boundary_min.y, world.boundary_max.y).to_le_bytes();
// 2 bits for team // 2 bits for team
// 4 bits for class // 4 bits for class
// 10 bits for health // 9 bits for health
let team_class_health = // 1 bit for ubered
((self.team as u16) << 14) + ((self.class as u16) << 10) + self.health; let team_class_health = ((self.team as u16) << 14)
+ ((self.class as u16) << 10)
+ (self.health << 1)
+ (self.ubered as u16);
let combined_bytes = team_class_health.to_le_bytes(); let combined_bytes = team_class_health.to_le_bytes();
[ [
@ -217,7 +222,8 @@ impl PlayerState {
world.boundary_max.y, world.boundary_max.y,
); );
let team_class_health = u16::from_le_bytes([bytes[4], bytes[5]]); let team_class_health = u16::from_le_bytes([bytes[4], bytes[5]]);
let health = team_class_health & 1023; let ubered = (team_class_health & 1) == 1;
let health = (team_class_health >> 1) & 511;
let angle = Angle(bytes[6]); let angle = Angle(bytes[6]);
let team = Team::new(team_class_health >> 14); let team = Team::new(team_class_health >> 14);
let class = Class::new((team_class_health >> 10) & 15); let class = Class::new((team_class_health >> 10) & 15);
@ -230,26 +236,31 @@ impl PlayerState {
team, team,
class, class,
charge, charge,
ubered,
} }
} }
} }
#[cfg(test)]
fn get_world() -> World {
use tf_demo_parser::demo::vector::Vector;
let mut world = World::default();
world.boundary_max = Vector {
x: 10000.0,
y: 10000.0,
z: 100.0,
};
world.boundary_min = Vector {
x: -10000.0,
y: -10000.0,
z: -100.0,
};
world
}
#[test] #[test]
fn test_player_packing() { fn test_player_packing() {
use tf_demo_parser::demo::vector::Vector; let world = get_world();
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 { let input = PlayerState {
position: VectorXY { position: VectorXY {
@ -261,6 +272,7 @@ fn test_player_packing() {
team: Team::Blue, team: Team::Blue,
class: Class::Demoman, class: Class::Demoman,
charge: 7, charge: 7,
ubered: false,
}; };
let bytes = input.pack(&world); let bytes = input.pack(&world);
@ -436,20 +448,7 @@ impl BuildingState {
#[test] #[test]
fn test_building_packing() { fn test_building_packing() {
use tf_demo_parser::demo::vector::Vector; let world = get_world();
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 = BuildingState { let input = BuildingState {
position: VectorXY { position: VectorXY {
@ -545,20 +544,7 @@ impl ProjectileState {
#[test] #[test]
fn test_projectile_packing() { fn test_projectile_packing() {
use tf_demo_parser::demo::vector::Vector; let world = get_world();
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 = ProjectileState { let input = ProjectileState {
position: VectorXY { position: VectorXY {