aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-02-23 18:34:28 +0100
committermetamuffin <metamuffin@disroot.org>2025-02-23 18:34:28 +0100
commit57bb47ab1092dac7bffd707f35efa131b9bd99c3 (patch)
treecfc51622a0a0d324cc08fd849cc6ccf36b24f141
parentd4c9a59ed41c11bf3edccc37d531da46e4fcd218 (diff)
downloadtwclient-57bb47ab1092dac7bffd707f35efa131b9bd99c3.tar
twclient-57bb47ab1092dac7bffd707f35efa131b9bd99c3.tar.bz2
twclient-57bb47ab1092dac7bffd707f35efa131b9bd99c3.tar.zst
snaps from client are displayed but with timing issues
-rw-r--r--client/src/client.rs35
-rw-r--r--client/src/main.rs9
-rw-r--r--client/src/renderer.rs105
-rw-r--r--client/src/window.rs21
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<Self> {
- 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<L: Loop> Application<L> 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<L: Loop> Application<L> for ClientNetwork {
})
.collect::<Vec<_>>();
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<Client>,
+
device: Arc<Device>,
queue: Arc<Queue>,
window: &'a Window,
@@ -38,12 +49,20 @@ pub struct Renderer<'a> {
sprite_textures: SpriteTextures,
gpu_camera: Arc<GpuBuffer<Camera>>,
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<Self> {
- let texture_format = TextureFormat::Bgra8UnormSrgb;
+ pub fn new(window: &'a Window, client: Arc<Client>) -> Result<Self> {
+ 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<u32>) {
@@ -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<Arc<Client>>,
window: Option<(Window, Renderer<'static>)>,
}
impl WindowState {
- pub fn new() -> Self {
- Self { window: None }
+ pub fn new(client: Arc<Client>) -> 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();
}
_ => (),
}