use self::map::Map; use crate::client::{helper::get_map_path, ClientMesgOut}; use gamenet::{ enums::{Emote, Team, Weapon}, SnapObj, }; use std::{collections::BTreeMap, fs::File}; pub mod map; pub use gamenet::enums; #[derive(Debug)] 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: i32, 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, } 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(), } } } pub struct World { pub map: Map, pub tees: BTreeMap, } impl World { pub fn new() -> Self { Self { map: Map::empty(), tees: BTreeMap::new(), } } pub fn update(&mut self, m: &ClientMesgOut) { match m { ClientMesgOut::MapChange { name, crc } => { let file = File::open(get_map_path(name.as_str(), *crc)).unwrap(); self.map = Map::load(file).unwrap(); } ClientMesgOut::Snaps(s) => { self.tees.clear(); for (id, o) in s { let e = self.tees.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); } 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.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_tee(&self) -> Option<&Tee> { self.tees.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() }