use std::{collections::BTreeMap, f32::consts::PI}; use super::helper::Color; use crate::client::ClientMesgOut; use gamenet::{ enums::{Emote, Team, Weapon}, SnapObj, }; pub struct Tees { pub inner: BTreeMap, } pub struct Tee { pub name: String, pub skin: String, pub clan: String, pub local: bool, pub latency: i32, pub score: i32, pub team: Team, pub weapon: Weapon, pub armor: i32, pub ammo: i32, pub emote: Emote, pub attack_tick: i32, pub tick: i32, pub angle: f32, pub x: i32, pub y: i32, pub vel_x: i32, pub vel_y: i32, pub hook_x: i32, pub hook_y: i32, pub hook_dx: i32, pub hook_dy: i32, pub hook_player: i32, pub hook_state: i32, pub color_feet: Color, pub color_body: Color, pub use_custom_colors: bool, pub country: i32, } impl Default for Tee { fn default() -> Self { Self { x: Default::default(), y: Default::default(), local: false, team: Team::Spectators, latency: Default::default(), score: Default::default(), weapon: Weapon::Shotgun, armor: Default::default(), ammo: Default::default(), attack_tick: Default::default(), emote: Emote::Normal, tick: Default::default(), angle: Default::default(), vel_x: Default::default(), vel_y: Default::default(), hook_x: Default::default(), hook_y: Default::default(), hook_dx: Default::default(), hook_dy: Default::default(), hook_player: Default::default(), hook_state: Default::default(), name: Default::default(), skin: Default::default(), clan: Default::default(), color_feet: Color { a: 0, b: 0, g: 0, r: 0, }, color_body: Color { a: 0, b: 0, g: 0, r: 0, }, use_custom_colors: Default::default(), country: Default::default(), } } } impl Tees { pub fn new() -> Self { Self { inner: BTreeMap::new(), } } pub fn update(&mut self, m: &ClientMesgOut) { match m { ClientMesgOut::Snaps(s) => { self.inner.clear(); for (id, o) in s { let e = self.inner.entry(*id).or_default(); match o { SnapObj::ClientInfo(o) => { e.name = i32_to_string(o.name); e.skin = i32_to_string(o.skin); e.clan = i32_to_string(o.clan); e.color_feet = unsafe { std::mem::transmute(o.color_feet) }; e.color_body = unsafe { std::mem::transmute(o.color_body) }; e.use_custom_colors = o.use_custom_color != 0 } SnapObj::PlayerInfo(o) => { e.local = o.local == 1; e.team = o.team; e.latency = o.latency; e.score = o.score; } SnapObj::Character(c) => { e.ammo = c.ammo_count; e.weapon = c.weapon; e.emote = c.emote; e.attack_tick = c.attack_tick; e.x = c.character_core.x; e.y = c.character_core.y; e.angle = c.character_core.angle as f32 / 1600.0 * 2.0 * PI; e.vel_x = c.character_core.vel_x; e.vel_y = c.character_core.vel_y; e.tick = c.character_core.tick; e.hook_x = c.character_core.hook_x; e.hook_y = c.character_core.hook_y; e.hook_player = c.character_core.hooked_player; e.hook_dx = c.character_core.hook_dx; e.hook_dy = c.character_core.hook_dy; e.hook_state = c.character_core.hook_state; } _ => (), } } } _ => {} } } pub fn local(&self) -> Option<&Tee> { self.inner.values().find(|e| e.local) } } fn i32_to_string(k: [i32; S]) -> String { let mut bytes = vec![]; for i in 0..S { bytes.push(((((k[i]) >> 24) & 0xff) - 128) as u8); bytes.push(((((k[i]) >> 16) & 0xff) - 128) as u8); bytes.push(((((k[i]) >> 8) & 0xff) - 128) as u8); bytes.push((((k[i]) & 0xff) - 128) as u8); } let len = bytes.iter().position(|e| *e == 0).unwrap_or(S); while bytes.len() > len { bytes.pop(); } String::from_utf8(bytes).unwrap() }