From 024a73e9575980b40c93d5f60c0e4e3f8e54187c Mon Sep 17 00:00:00 2001 From: metamuffin Date: Thu, 9 Jun 2022 14:39:44 +0200 Subject: player names --- client/src/world/mod.rs | 36 ++++++++++++++++++++++------ renderer/src/main.rs | 25 ++++---------------- renderer/src/map.rs | 62 ++++++++++++++++++++++++++++++++++++++----------- renderer/src/tee.rs | 46 ++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 renderer/src/tee.rs diff --git a/client/src/world/mod.rs b/client/src/world/mod.rs index ae985a6..bbc505c 100644 --- a/client/src/world/mod.rs +++ b/client/src/world/mod.rs @@ -1,10 +1,9 @@ +use self::map::Map; +use crate::client::{helper::get_map_path, ClientMesgOut}; use gamenet::{ enums::{Emote, Team, Weapon}, SnapObj, }; - -use self::map::Map; -use crate::client::{helper::get_map_path, ClientMesgOut}; use std::{collections::BTreeMap, fs::File}; pub mod map; @@ -13,6 +12,10 @@ 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, @@ -62,6 +65,9 @@ impl Default for Tee { hook_dy: Default::default(), hook_player: Default::default(), hook_state: Default::default(), + name: Default::default(), + skin: Default::default(), + clan: Default::default(), } } } @@ -88,19 +94,20 @@ impl World { ClientMesgOut::Snaps(s) => { self.tees.clear(); for (id, o) in s { + let e = self.tees.entry(*id).or_default(); match o { - SnapObj::ClientInfo(_o) => { - // TODO + 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) => { - let e = self.tees.entry(*id).or_default(); e.local = o.local == 1; e.team = o.team; e.latency = o.latency; e.score = o.score; } SnapObj::Character(c) => { - let e = self.tees.entry(*id).or_default(); e.ammo = c.ammo_count; e.weapon = c.weapon; e.emote = c.emote; @@ -130,3 +137,18 @@ impl World { 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() +} diff --git a/renderer/src/main.rs b/renderer/src/main.rs index d4ee57d..63396cc 100644 --- a/renderer/src/main.rs +++ b/renderer/src/main.rs @@ -1,4 +1,5 @@ pub mod map; +pub mod tee; use glutin::{ event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, @@ -20,6 +21,7 @@ use std::{ collections::HashSet, convert::TryInto, net::IpAddr, process::exit, str::FromStr, sync::atomic::Ordering, thread, time::Duration, }; +use tee::TeeRenderer; use twclient::{ client::{Client, ClientConfig, ClientInterface, ClientMesgIn, PlayerInput}, world::World, @@ -111,6 +113,7 @@ fn main() { let mut renderer = Renderer { client_interface, + tee_renderer: TeeRenderer::new(), map_renderer: MapRenderer::new(), world: World::new(), input: PlayerInput::default(), @@ -206,6 +209,7 @@ fn main() { pub struct Renderer { client_interface: ClientInterface, map_renderer: MapRenderer, + tee_renderer: TeeRenderer, world: World, input: PlayerInput, } @@ -231,26 +235,7 @@ impl Renderer { canvas.translate((-center.0 as f32, -center.1 as f32)); self.map_renderer.draw(&self.world, canvas); - - let tee_paint = Paint::new( - Color4f { - a: 1.0, - r: 0.2, - g: 0.0, - b: 0.2, - }, - &ColorSpace::new_srgb(), - ); - for t in self.world.tees.values() { - canvas.draw_circle( - Point { - x: t.x as f32, - y: t.y as f32, - }, - 16.0, - &tee_paint, - ); - } + self.tee_renderer.draw(&self.world, canvas); canvas.restore(); } diff --git a/renderer/src/map.rs b/renderer/src/map.rs index 8ce932f..f7672c1 100644 --- a/renderer/src/map.rs +++ b/renderer/src/map.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use log::{info, warn}; use skia_safe::{ - canvas::SrcRectConstraint, BlendMode, Canvas, Color4f, ColorSpace, ISize, Image, Paint, Rect, + canvas::SrcRectConstraint, BlendMode, Canvas, Color4f, ColorSpace, ISize, Image, Matrix, Paint, + Rect, }; use twclient::world::{ map::{format, TILE_NUM}, @@ -51,6 +52,7 @@ impl MapRenderer { } pub fn draw(&mut self, world: &World, canvas: &mut Canvas) { + let rot90 = Matrix::rotate_deg(90.0); let mut grid_paint = Paint::new( Color4f { a: 1.0, @@ -89,22 +91,14 @@ impl MapRenderer { let layer_x = layer_x.try_into().unwrap_or(0); let layer_y = layer_y.try_into().unwrap_or(0); - let tile_rect = Rect { - top: layer_y as f32 * TILE_SIZE, - left: layer_x as f32 * TILE_SIZE, - bottom: layer_y as f32 * TILE_SIZE + TILE_SIZE, - right: layer_x as f32 * TILE_SIZE + TILE_SIZE, - }; - // canvas.draw_rect(tile_rect, &grid_paint); - let tile = match l.tiles.get((layer_y, layer_x)) { Some(t) => t, None => continue, }; - let _rotate = tile.flags & format::TILEFLAG_ROTATE != 0; - let _vflip = tile.flags & format::TILEFLAG_VFLIP != 0; - let _hflip = tile.flags & format::TILEFLAG_HFLIP != 0; + let rotate = tile.flags & format::TILEFLAG_ROTATE != 0; + let vflip = tile.flags & format::TILEFLAG_VFLIP != 0; + let hflip = tile.flags & format::TILEFLAG_HFLIP != 0; let tile_x = tile.index as u32 % TILE_NUM; let tile_y = tile.index as u32 / TILE_NUM; @@ -112,6 +106,21 @@ impl MapRenderer { continue; } + canvas.save(); + canvas.translate(( + (layer_x as f32 + 0.5) * TILE_SIZE, + (layer_y as f32 + 0.5) * TILE_SIZE, + )); + if rotate { + canvas.concat(&rot90); + } + if vflip { + canvas.scale((-1.0, 1.0)); + } + if hflip { + canvas.scale((1.0, -1.0)); + } + const TL: u32 = 64; canvas.draw_image_rect( tileset, @@ -124,9 +133,36 @@ impl MapRenderer { }, SrcRectConstraint::Strict, )), - tile_rect, + Rect { + top: -TILE_SIZE / 2.0, + bottom: TILE_SIZE / 2.0, + left: -TILE_SIZE / 2.0, + right: TILE_SIZE / 2.0, + }, &layer_tint, ); + + // if hflip { + // canvas.draw_rect( + // Rect { + // top: -TILE_SIZE / 2.0, + // bottom: TILE_SIZE / 2.0, + // left: -TILE_SIZE / 2.0, + // right: TILE_SIZE / 2.0, + // }, + // &Paint::new( + // Color4f { + // a: 0.5, + // b: 1.0, + // g: 0.0, + // r: 1.0, + // }, + // &ColorSpace::new_srgb(), + // ), + // ); + // } + + canvas.restore(); } } } diff --git a/renderer/src/tee.rs b/renderer/src/tee.rs new file mode 100644 index 0000000..98ac218 --- /dev/null +++ b/renderer/src/tee.rs @@ -0,0 +1,46 @@ +use skia_safe::{Canvas, Color4f, ColorSpace, Font, Paint, Point}; +use twclient::world::World; + +const TEE_RADIUS: f32 = 16.0; + +pub struct TeeRenderer {} + +impl TeeRenderer { + pub fn new() -> Self { + Self {} + } + + pub fn draw(&mut self, world: &World, canvas: &mut Canvas) { + let tee_paint = Paint::new( + Color4f { + a: 1.0, + r: 0.2, + g: 0.0, + b: 0.2, + }, + &ColorSpace::new_srgb(), + ); + let name_paint = Paint::new( + Color4f { + a: 1.0, + r: 1.0, + g: 1.0, + b: 0.0, + }, + &ColorSpace::new_srgb(), + ); + for t in world.tees.values() { + let origin = Point { + x: t.x as f32, + y: t.y as f32, + }; + canvas.draw_circle(origin, TEE_RADIUS, &tee_paint); + canvas.draw_str( + t.name.as_str(), + (origin.x, origin.y - 20.0), + &Font::default(), + &name_paint, + ); + } + } +} -- cgit v1.2.3-70-g09d2