From 57bb47ab1092dac7bffd707f35efa131b9bd99c3 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sun, 23 Feb 2025 18:34:28 +0100 Subject: snaps from client are displayed but with timing issues --- client/src/client.rs | 35 +++++++++++------ client/src/main.rs | 9 +++-- client/src/renderer.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++---- client/src/window.rs | 21 +++++++--- 4 files changed, 141 insertions(+), 29 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index 9f23c41..3ebccca 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -21,26 +21,37 @@ use std::{ io::Write, net::{IpAddr, Ipv4Addr}, path::PathBuf, + sync::mpsc::{Receiver, Sender, channel}, + thread::spawn, }; use twsnap::{Snap, SnapObj}; -pub struct Client {} +pub struct Client { + pub incoming: Receiver<(i32, Snap)>, +} impl Client { pub fn new() -> Result { - let mut sloop = SocketLoop::client(); - sloop.connect(Addr { - ip: IpAddr::V4(Ipv4Addr::LOCALHOST), - port: 8303, - }); - sloop.run(ClientNetwork { - state: NetworkState::New, + let (incoming_tx, incoming_rx) = channel(); + spawn(move || { + let mut sloop = SocketLoop::client(); + sloop.connect(Addr { + ip: IpAddr::V4(Ipv4Addr::LOCALHOST), + port: 8303, + }); + sloop.run(ClientNetwork { + state: NetworkState::New, + events: incoming_tx, + }); }); - Ok(Self {}) + Ok(Self { + incoming: incoming_rx, + }) } } pub struct ClientNetwork { state: NetworkState, + events: Sender<(i32, Snap)>, } enum NetworkState { New, @@ -117,8 +128,8 @@ impl Application for ClientNetwork { country: -1, skin: b"limekittygirl", use_custom_color: true, - color_body: 0xFF00FF, - color_feet: 0x550055, + color_body: 0xFF00FFFFu32 as i32, + color_feet: 0x550055FFu32 as i32, }); self.state = NetworkState::Ingame { snap: Snap::default(), @@ -146,7 +157,7 @@ impl Application for ClientNetwork { }) .collect::>(); snap.process_next(objs.iter()); - debug!("{snap:#?}"); + self.events.send((p.tick, snap.clone())).unwrap(); } } } diff --git a/client/src/main.rs b/client/src/main.rs index 5a52620..55969a4 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,20 +1,21 @@ +#![feature(random)] use anyhow::Result; use client::Client; +use std::sync::Arc; use window::WindowState; use winit::event_loop::EventLoop; pub mod client; pub mod renderer; -pub mod window; pub mod skin_manager; +pub mod window; fn main() -> Result<()> { env_logger::init_from_env("LOG"); - // Client::new()?; - + let client = Arc::new(Client::new().unwrap()); let evloop = EventLoop::new()?; - evloop.run_app(&mut WindowState::new())?; + evloop.run_app(&mut WindowState::new(client))?; Ok(()) } diff --git a/client/src/renderer.rs b/client/src/renderer.rs index b213307..57e0fc4 100644 --- a/client/src/renderer.rs +++ b/client/src/renderer.rs @@ -1,17 +1,26 @@ -use crate::skin_manager::{SkinManager, init_sprite_textures}; +use crate::{ + client::Client, + skin_manager::{SkinManager, init_sprite_textures}, +}; use anyhow::{Result, anyhow}; use log::warn; use pollster::FutureExt; -use std::{sync::Arc, time::Instant}; +use std::{mem::swap, random::random, sync::Arc, time::Instant}; +use twgame::Map; use twgpu::{ Camera, GpuCamera, TwRenderPass, blit::Blit, buffer::GpuBuffer, map::{GpuMapData, GpuMapRender, GpuMapStatic}, - sprites::{ParticleData, ParticleGroup, SpriteTextures, SpritesData, SpritesStatic}, + shared::{Clock, Rng}, + sprites::{ + ParticleData, ParticleGroup, SpriteRenderContext, SpriteTextures, SpritesData, + SpritesStatic, TeeStorage, + }, textures::Samplers, }; use twmap::TwMap; +use twsnap::Snap; use vek::Vec2; use wgpu::{ Backends, Color, CommandEncoderDescriptor, Device, DeviceDescriptor, Features, Instance, @@ -22,6 +31,8 @@ use wgpu::{ use winit::{dpi::PhysicalSize, window::Window}; pub struct Renderer<'a> { + client: Arc, + device: Arc, queue: Arc, window: &'a Window, @@ -38,12 +49,20 @@ pub struct Renderer<'a> { sprite_textures: SpriteTextures, gpu_camera: Arc>, start: Instant, + rng: Rng, need_reconfigure: bool, + clock: Clock, + map: Map, + from_snap: Snap, + to_snap: Snap, + tees: TeeStorage, + clock_set: bool, + local_time_offset: i64, } impl<'a> Renderer<'a> { - pub fn new(window: &'a Window) -> Result { - let texture_format = TextureFormat::Bgra8UnormSrgb; + pub fn new(window: &'a Window, client: Arc) -> Result { + let texture_format = TextureFormat::Bgra8Unorm; let instance = Instance::new(InstanceDescriptor { backends: Backends::all(), @@ -83,7 +102,8 @@ impl<'a> Renderer<'a> { twmap.load()?; let samplers = Arc::new(Samplers::new(&device)); - let camera = Camera::new(1.); + let mut camera = Camera::new(1.); + camera.position = Vec2 { x: 33., y: 84. }; let gpu_camera = Arc::new(GpuCamera::upload(&camera, &device)); let map_static = GpuMapStatic::new(texture_format, &device); @@ -100,12 +120,16 @@ impl<'a> Renderer<'a> { let skin_manager = SkinManager::new(blit, &mut sprite_textures, device.clone(), queue.clone()); - let surface_configuration = surface + let mut surface_configuration = surface .get_default_config(&adapter, 256, 256) .ok_or(anyhow!("no surface config"))?; + surface_configuration.format = texture_format; // surface_configuration.format.remove_srgb_suffix(); + surface.configure(&device, &surface_configuration); + let map = Map::try_from(&mut twmap).map_err(|e| anyhow!("{e}"))?; + Ok(Self { start: Instant::now(), map_data, @@ -123,7 +147,16 @@ impl<'a> Renderer<'a> { skin_manager, sprites_data, sprite_textures, + clock: Clock::default(), + from_snap: Snap::default(), + to_snap: Snap::default(), + map, + local_time_offset: 0, + clock_set: false, + tees: TeeStorage::default(), + rng: Rng::new(random()), need_reconfigure: false, + client, }) } pub fn resize(&mut self, size: PhysicalSize) { @@ -150,13 +183,70 @@ impl<'a> Renderer<'a> { } let time = self.start.elapsed().as_micros() as i64; + let local_tick = (time + self.local_time_offset) as f64 / 1_000_000. * 50. + 1.; let size = Vec2::new( self.surface_configuration.width, self.surface_configuration.height, ); + + if self.clock_set { + self.clock.update(local_tick); + } + + for (player_id, player) in self.from_snap.players.iter() { + if player.local { + if let Some(tees) = self.tees.lerp_tee( + player_id, + &self.clock, + &self.from_snap, + &self.to_snap, + &self.map, + ) { + self.camera.position = self.clock.lerp_tee_vec(tees, |tee| tee.pos); + } + } + } + + { + let process = if let Ok((new_tick, new_snap)) = self.client.incoming.try_recv() { + eprintln!("{new_tick} {}", new_snap.players.len()); + if self.clock_set { + self.clock.next_tick(new_tick); + } else { + self.clock = Clock::new(new_tick); + self.clock_set = true; + } + self.local_time_offset = new_tick as i64 * 20_000 - time; + self.skin_manager.queue_snap_skins(&new_snap); + swap(&mut self.from_snap, &mut self.to_snap); + self.to_snap = new_snap; + true + } else { + false + }; + let mut ctx = SpriteRenderContext { + clock: &self.clock, + from_snap: &self.from_snap, + to_snap: &self.to_snap, + tees: &mut self.tees, + map: &self.map, + particles: &mut self.particle_data, + textures: &self.sprite_textures, + rng: &mut self.rng, + }; + if process { + ctx.process_events(); + } + self.sprites_data.clear(); + ctx.generate_all_sprites(&mut self.sprites_data); + } + self.map_data .update(&self.twmap, &self.camera, size, time, time, &self.queue); self.gpu_camera.update(&self.camera, &self.queue); + self.skin_manager.poll_queued(&mut self.sprite_textures); + self.sprites_data.upload(&self.device, &self.queue); + self.particle_data.upload(&self.device, &self.queue); let target_view = target .texture @@ -218,6 +308,7 @@ impl<'a> Renderer<'a> { .poll(MaintainBase::WaitForSubmissionIndex(submission)); target.present(); + self.window.request_redraw(); Ok(()) } diff --git a/client/src/window.rs b/client/src/window.rs index 0bcac6a..a7e1859 100644 --- a/client/src/window.rs +++ b/client/src/window.rs @@ -1,4 +1,6 @@ -use crate::renderer::Renderer; +use std::sync::Arc; + +use crate::{client::Client, renderer::Renderer}; use log::warn; use winit::{ application::ApplicationHandler, @@ -8,12 +10,16 @@ use winit::{ }; pub struct WindowState { + temp_client: Option>, window: Option<(Window, Renderer<'static>)>, } impl WindowState { - pub fn new() -> Self { - Self { window: None } + pub fn new(client: Arc) -> Self { + Self { + window: None, + temp_client: Some(client), + } } } impl ApplicationHandler for WindowState { @@ -21,7 +27,11 @@ impl ApplicationHandler for WindowState { let window = event_loop .create_window(WindowAttributes::default().with_maximized(true)) .unwrap(); - let renderer = Renderer::new(unsafe { std::mem::transmute(&window) }).unwrap(); + let renderer = Renderer::new( + unsafe { std::mem::transmute(&window) }, + self.temp_client.take().unwrap(), + ) + .unwrap(); self.window = Some((window, renderer)) } @@ -31,7 +41,7 @@ impl ApplicationHandler for WindowState { _window_id: WindowId, event: WindowEvent, ) { - if let Some((win, ren)) = &mut self.window { + if let Some((_win, ren)) = &mut self.window { match event { WindowEvent::CloseRequested => { event_loop.exit(); @@ -43,7 +53,6 @@ impl ApplicationHandler for WindowState { if let Err(e) = ren.redraw() { warn!("{e:?}") } - win.request_redraw(); } _ => (), } -- cgit v1.2.3-70-g09d2