summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/download.rs58
-rw-r--r--client/src/main.rs11
-rw-r--r--client/src/network.rs55
-rw-r--r--client/src/part.rs36
-rw-r--r--client/src/renderer.rs2
-rw-r--r--client/src/state.rs33
-rw-r--r--client/src/window.rs36
7 files changed, 203 insertions, 28 deletions
diff --git a/client/src/download.rs b/client/src/download.rs
new file mode 100644
index 0000000..256c25c
--- /dev/null
+++ b/client/src/download.rs
@@ -0,0 +1,58 @@
+use anyhow::Result;
+use std::collections::HashSet;
+use weareshared::{
+ packets::{Packet, Resource},
+ store::{ResourceStore, sha256},
+};
+
+use crate::network::Network;
+
+pub struct Downloader {
+ have: HashSet<Resource>,
+ need: HashSet<Resource>,
+ pending: HashSet<Resource>,
+ store: ResourceStore,
+}
+
+impl Downloader {
+ pub fn new(store: ResourceStore) -> Self {
+ Self {
+ have: HashSet::new(),
+ need: HashSet::new(),
+ pending: HashSet::new(),
+ store,
+ }
+ }
+ pub fn try_get(&mut self, hash: Resource) -> Result<Option<Vec<u8>>> {
+ if self.have.contains(&hash) {
+ self.store.get(hash)
+ } else {
+ self.need.insert(hash);
+ Ok(None)
+ }
+ }
+ pub fn packet(&mut self, p: &Packet) -> Result<()> {
+ match p {
+ Packet::RespondResource(d) => {
+ let key = Resource(sha256(&d));
+ self.store.set(&d)?;
+ self.need.remove(&key);
+ self.pending.remove(&key);
+ self.have.insert(key);
+ }
+ _ => (),
+ }
+ Ok(())
+ }
+ pub fn update(&mut self, network: &mut Network) {
+ let mut new_pending = Vec::new();
+ for n in self.need.difference(&self.pending) {
+ network
+ .packet_send
+ .send(Packet::RequestResource(*n))
+ .unwrap();
+ new_pending.push(*n);
+ }
+ self.pending.extend(new_pending);
+ }
+}
diff --git a/client/src/main.rs b/client/src/main.rs
index 543db6d..b90d26b 100644
--- a/client/src/main.rs
+++ b/client/src/main.rs
@@ -1,9 +1,13 @@
+pub mod download;
+pub mod network;
+pub mod part;
pub mod renderer;
+pub mod state;
pub mod window;
-pub mod part;
use anyhow::Result;
use clap::Parser;
+use log::info;
use std::net::{SocketAddr, TcpStream};
use window::WindowState;
use winit::event_loop::EventLoop;
@@ -17,10 +21,11 @@ fn main() -> Result<()> {
env_logger::init_from_env("LOG");
let args = Args::parse();
+ info!("connecting...");
let sock = TcpStream::connect(args.address)?;
-
+ info!("connection established");
let evloop = EventLoop::new()?;
- evloop.run_app(&mut WindowState::new())?;
+ evloop.run_app(&mut WindowState::new(sock))?;
Ok(())
}
diff --git a/client/src/network.rs b/client/src/network.rs
new file mode 100644
index 0000000..0fd5f08
--- /dev/null
+++ b/client/src/network.rs
@@ -0,0 +1,55 @@
+use std::{
+ io::{BufReader, BufWriter},
+ net::TcpStream,
+ sync::mpsc::{Receiver, Sender, channel},
+ thread::spawn,
+};
+
+use anyhow::Result;
+use log::{debug, info, warn};
+use weareshared::packets::Packet;
+
+pub struct Network {
+ pub packet_recv: Receiver<Packet>,
+ pub packet_send: Sender<Packet>,
+}
+impl Network {
+ pub fn new(sock: TcpStream) -> Self {
+ info!("starting network threads");
+ let (packet_send, rx) = channel();
+ let (tx, packet_recv) = channel();
+
+ let sock2 = sock.try_clone().unwrap();
+ spawn(move || {
+ if let Err(e) = handle_conn_read(sock, tx) {
+ warn!("read thread: {e:?}")
+ }
+ });
+ spawn(move || {
+ if let Err(e) = handle_conn_write(sock2, rx) {
+ warn!("write thread: {e:?}")
+ }
+ });
+ Self {
+ packet_recv,
+ packet_send,
+ }
+ }
+}
+
+fn handle_conn_read(sock: TcpStream, tx: Sender<Packet>) -> Result<()> {
+ let mut sock = BufReader::new(sock);
+ loop {
+ let packet = Packet::deserialize(&mut sock)?;
+ debug!("<- {packet:?}");
+ tx.send(packet)?;
+ }
+}
+fn handle_conn_write(sock: TcpStream, rx: Receiver<Packet>) -> Result<()> {
+ let mut sock = BufWriter::new(sock);
+ for packet in rx {
+ debug!("-> {packet:?}");
+ packet.serialize(&mut sock)?;
+ }
+ Ok(())
+}
diff --git a/client/src/part.rs b/client/src/part.rs
index 15835d0..0ad714a 100644
--- a/client/src/part.rs
+++ b/client/src/part.rs
@@ -1,8 +1,6 @@
+use crate::download::Downloader;
use anyhow::Result;
-use weareshared::{
- packets::Resource,
- resources::{Indecies, Part, VertexAttributes},
-};
+use weareshared::resources::{Indecies, Part, VertexAttributes};
use wgpu::{
BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Buffer, BufferUsages,
ColorTargetState, ColorWrites, CommandEncoder, Device, FragmentState, FrontFace, IndexFormat,
@@ -28,16 +26,25 @@ pub struct PartData {
}
impl PartData {
- pub fn update(&mut self, hash: Resource, data: &[u8]) -> Result<bool> {
- if Some(hash) == self.target.index {
- self.index = Some(Indecies::deserialize(data)?)
+ pub fn update(&mut self, dls: &mut Downloader) -> Result<bool> {
+ let mut ready = true;
+ if self.index.is_none() {
+ ready = false;
+ if let Some(hash) = self.target.index {
+ if let Some(data) = dls.try_get(hash)? {
+ self.index = Some(Indecies::deserialize(data.as_slice())?)
+ }
+ }
}
- for (thash, tdata) in self.target.vertex.iter().zip(self.vertex.iter_mut()) {
- if hash == *thash {
- *tdata = Some(VertexAttributes::deserialize(data)?)
+ for (hash, slot) in self.target.vertex.iter().zip(self.vertex.iter_mut()) {
+ if slot.is_none() {
+ ready = false;
+ if let Some(data) = dls.try_get(*hash)? {
+ *slot = Some(VertexAttributes::deserialize(data.as_slice())?)
+ }
}
}
- Ok(self.vertex.iter().all(|v| v.is_some()) && self.index.is_some())
+ Ok(ready)
}
}
@@ -45,11 +52,10 @@ impl RenderPart {
pub fn new(device: Device, data: PartData, format: TextureFormat) -> Self {
let mut vertex = Vec::new();
let mut index = Vec::new();
- let attrs = data.vertex.unwrap();
for i in 0..data.vertex[0].as_ref().unwrap().0.len() {
- vertex.extend(attrs[0].0[i].to_le_bytes());
- vertex.extend(attrs[1].0[i].to_le_bytes());
- vertex.extend(attrs[2].0[i].to_le_bytes());
+ vertex.extend(data.vertex[0].as_ref().unwrap().0[i].to_le_bytes());
+ vertex.extend(data.vertex[1].as_ref().unwrap().0[i].to_le_bytes());
+ vertex.extend(data.vertex[2].as_ref().unwrap().0[i].to_le_bytes());
}
let mut n_vertex = 0;
for ind in data.index.unwrap().0 {
diff --git a/client/src/renderer.rs b/client/src/renderer.rs
index b21c139..cc44446 100644
--- a/client/src/renderer.rs
+++ b/client/src/renderer.rs
@@ -1,4 +1,5 @@
use anyhow::{Result, anyhow};
+use log::info;
use pollster::FutureExt;
use wgpu::{
Backends, BindGroup, BindGroupDescriptor, BindGroupLayoutDescriptor, BlendState, Color,
@@ -22,6 +23,7 @@ pub struct Renderer<'a> {
}
impl<'a> Renderer<'a> {
pub fn new(window: &'a Window) -> Result<Self> {
+ info!("wgpu init");
let instance = Instance::new(InstanceDescriptor {
backends: Backends::all(),
..Default::default()
diff --git a/client/src/state.rs b/client/src/state.rs
new file mode 100644
index 0000000..ef68b85
--- /dev/null
+++ b/client/src/state.rs
@@ -0,0 +1,33 @@
+use crate::{download::Downloader, network::Network, renderer::Renderer};
+use anyhow::Result;
+use log::info;
+use std::net::TcpStream;
+use weareshared::{store::ResourceStore, tree::SceneTree};
+use winit::window::Window;
+
+pub struct State<'a> {
+ pub network: Network,
+ pub downloader: Downloader,
+ pub renderer: Renderer<'a>,
+ pub tree: SceneTree,
+}
+impl<'a> State<'a> {
+ pub fn new(conn: TcpStream, window: &'a Window) -> Result<State<'a>> {
+ info!("new state");
+ Ok(Self {
+ network: Network::new(conn),
+ tree: SceneTree::default(),
+ renderer: Renderer::new(window)?,
+ downloader: Downloader::new(ResourceStore::new_memory()),
+ })
+ }
+
+ pub fn update(&mut self) -> Result<()> {
+ for p in self.network.packet_recv.try_iter() {
+ self.downloader.packet(&p)?;
+ }
+ self.downloader.update(&mut self.network);
+
+ Ok(())
+ }
+}
diff --git a/client/src/window.rs b/client/src/window.rs
index 20300d5..5f2e7f8 100644
--- a/client/src/window.rs
+++ b/client/src/window.rs
@@ -1,4 +1,6 @@
-use crate::renderer::Renderer;
+use crate::state::State;
+use log::{info, warn};
+use std::net::TcpStream;
use winit::{
application::ApplicationHandler,
event::WindowEvent,
@@ -7,21 +9,28 @@ use winit::{
};
pub struct WindowState {
- window: Option<(Window, Renderer<'static>)>,
+ init: Option<TcpStream>,
+ window: Option<(Window, State<'static>)>,
}
impl WindowState {
- pub fn new() -> Self {
- Self { window: None }
+ pub fn new(init: TcpStream) -> Self {
+ Self {
+ window: None,
+ init: Some(init),
+ }
}
}
impl ApplicationHandler for WindowState {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
+ info!("app resumed");
let win = event_loop
.create_window(WindowAttributes::default().with_maximized(true))
.unwrap();
- let ren = Renderer::new(unsafe { std::mem::transmute::<&Window, &'static Window>(&win) })
- .unwrap();
- self.window = Some((win, ren))
+ let sta = State::new(self.init.take().unwrap(), unsafe {
+ std::mem::transmute::<&Window, &'static Window>(&win)
+ })
+ .unwrap();
+ self.window = Some((win, sta))
}
fn window_event(
&mut self,
@@ -29,12 +38,12 @@ impl ApplicationHandler for WindowState {
_window_id: WindowId,
event: WindowEvent,
) {
- if let Some((_win, ren)) = &mut self.window {
+ if let Some((_win, sta)) = &mut self.window {
match event {
WindowEvent::Resized(size) => {
- ren.resize(size.width, size.height);
+ sta.renderer.resize(size.width, size.height);
}
- WindowEvent::RedrawRequested => ren.draw().unwrap(),
+ WindowEvent::RedrawRequested => sta.renderer.draw().unwrap(),
WindowEvent::CloseRequested => {
event_loop.exit();
}
@@ -42,4 +51,11 @@ impl ApplicationHandler for WindowState {
}
}
}
+ fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
+ if let Some((_win, sta)) = &mut self.window {
+ if let Err(e) = sta.update() {
+ warn!("update failed: {e}")
+ }
+ }
+ }
}