diff --git a/src/client/app.rs b/src/client/app.rs index faaa487..feee38c 100644 --- a/src/client/app.rs +++ b/src/client/app.rs @@ -2,12 +2,12 @@ use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::Con use super::Client; -pub struct ClientApp { - client: Option, +pub struct ClientApp<'a> { + client: Option>, } -impl ClientApp { - fn client(&mut self) -> &mut Client { +impl <'a> ClientApp<'a> { + fn client(&mut self) -> &mut Client<'a> { self.client.as_mut().expect("bruh") } @@ -16,7 +16,7 @@ impl ClientApp { } } -impl ApplicationHandler for ClientApp { +impl ApplicationHandler for ClientApp<'_> { fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { if self.client.is_none() { self.client = Some(Client::new(event_loop)); diff --git a/src/client/component.rs b/src/client/component.rs index 8d0beac..64031d3 100644 --- a/src/client/component.rs +++ b/src/client/component.rs @@ -1,19 +1,7 @@ -use std::ops::{Deref, DerefMut}; - +use bevy_derive::{Deref, DerefMut}; use bevy_ecs::system::Resource; -use super::render::RendererChannel; +use super::render::RenderCommand; -#[derive(Resource)] -pub struct RenderResource(pub RendererChannel); -impl Deref for RenderResource { - type Target = RendererChannel; - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for RenderResource { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +#[derive(Resource, Deref, DerefMut, Default)] +pub struct RenderCommands(pub Vec); diff --git a/src/client/handle_input.rs b/src/client/handle_input.rs index 96bcf75..edad11e 100644 --- a/src/client/handle_input.rs +++ b/src/client/handle_input.rs @@ -4,11 +4,14 @@ use nalgebra::Rotation3; use ndarray::Array3; use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode}; -use crate::world::component::{VoxelGrid, VoxelGridBundle}; +use crate::{ + sync::ServerMessage, + world::component::{VoxelGrid, VoxelGridBundle}, +}; use super::{render::voxel::VoxelColor, Client}; -impl Client { +impl Client<'_> { pub fn handle_input(&mut self, dt: &Duration) { let dt = dt.as_secs_f32(); let Client { @@ -101,19 +104,24 @@ impl Client { state.camera.pos += *state.camera.down() * move_dist; } if state.camera != old_camera { - self.renderer - .send(super::render::RenderMessage::ViewUpdate(state.camera)); + self.render_commands + .push(super::render::RenderCommand::ViewUpdate(state.camera)); } // fun if input.just_pressed(Key::KeyF) { - self.world.spawn(VoxelGridBundle { - pos: (state.camera.pos + 135.0 * 2.0 * *state.camera.forward()).into(), - orientation: state.camera.orientation.into(), - grid: VoxelGrid::new(Array3::from_shape_fn((135, 135, 135), |(..)| { - VoxelColor::white() - })), - }); + self.server + .send(ServerMessage::SpawnVoxelGrid(VoxelGridBundle { + pos: (state.camera.pos + 135.0 * 2.0 * *state.camera.forward()).into(), + orientation: state.camera.orientation.into(), + grid: VoxelGrid::new(Array3::from_shape_fn((135, 135, 135), |(x, y, z)| { + if x == 0 || y == 0 || z == 0 || x == 134 || y == 134 || z == 134 { + VoxelColor::white() + } else { + VoxelColor::none() + } + })), + })); } } } diff --git a/src/client/mod.rs b/src/client/mod.rs index 6dea929..0c3f708 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -9,26 +9,30 @@ mod state; mod system; pub use app::*; -use bevy_ecs::{system::SystemId, world::World}; -use component::RenderResource; -use render::{RenderMessage, RendererChannel}; +use bevy_ecs::{entity::Entity, system::SystemId, world::World}; +use component::RenderCommands; +use render::RenderCommand; +use rsc::FRAME_TIME; pub use state::*; -use system::voxel_grid::update_renderer; +use system::render::add_grid; -use crate::{server::Server, sync::ServerHandle, world::generation::generate}; +use crate::{ + server::Server, + sync::{ClientMessage, ServerHandle, ServerMessage}, +}; use self::{input::Input, render::Renderer, ClientState}; -use std::{sync::Arc, thread::JoinHandle, time::Instant}; +use std::{collections::HashMap, sync::Arc, time::{Duration, Instant}}; use winit::{ event::WindowEvent, window::{Window, WindowAttributes}, }; -pub struct Client { +pub struct Client<'a> { window: Arc, state: ClientState, - render_handle: Option>, - renderer: RendererChannel, + renderer: Renderer<'a>, + render_commands: Vec, exit: bool, input: Input, prev_update: Instant, @@ -36,10 +40,18 @@ pub struct Client { keep_cursor: bool, world: World, server: ServerHandle, - bruh: SystemId, + server_id_map: HashMap, + systems: ClientSystems, + target: Instant, + frame_time: Duration, } -impl Client { +pub struct ClientSystems { + render_add_grid: SystemId, + render_update_transform: SystemId, +} + +impl Client<'_> { pub fn new(event_loop: &winit::event_loop::ActiveEventLoop) -> Self { let mut world = World::new(); let window = Arc::new( @@ -48,27 +60,32 @@ impl Client { .expect("Failed to create window"), ); - let (render_channel, render_handle) = Renderer::spawn(window.clone()); - world.insert_resource(RenderResource(render_channel.clone())); - let bruh = world.register_system(update_renderer); + let renderer = Renderer::spawn(window.clone()); + world.insert_resource(RenderCommands(Vec::new())); let state = ClientState::new(); - let server = Server::spawn(); - generate(&mut world); + let server = ServerHandle::spawn(Server::start); + server.send(ServerMessage::LoadWorld); Self { window, exit: false, - render_handle: Some(render_handle), - renderer: render_channel, + renderer, + render_commands: Vec::new(), state, input: Input::new(), prev_update: Instant::now(), grabbed_cursor: false, keep_cursor: false, + systems: ClientSystems { + render_add_grid: world.register_system(add_grid), + render_update_transform: world.register_system(system::render::update_transform), + }, world, server, - bruh, + server_id_map: HashMap::new(), + target: Instant::now(), + frame_time: FRAME_TIME, } } @@ -81,31 +98,51 @@ impl Client { self.input.end(); self.recv(); - self.world.run_system(self.bruh).expect("WHAT"); + self.world + .run_system(self.systems.render_add_grid) + .expect("WHAT v2"); + self.world + .run_system(self.systems.render_update_transform) + .expect("WHAT"); self.world.clear_trackers(); + if now >= self.target { + self.target += self.frame_time; + let mut commands = std::mem::take(&mut self.render_commands); + let world_cmds = std::mem::take(&mut self.world.resource_mut::().0); + commands.extend(world_cmds); + self.renderer.handle_commands(commands); + self.renderer.draw(); + } + if self.exit { - self.renderer.send(RenderMessage::Exit); - // you know I'd like to do a timeout here... - // only because I have an NVIDIA GPU HELP - self.render_handle - .take() - .expect("uh oh") - .join() - .expect("bruh"); + self.server.send(ServerMessage::Stop); + self.server.join(); event_loop.exit(); } } pub fn recv(&mut self) { - for msg in self.server.recv() {} + for msg in self.server.recv() { + match msg { + ClientMessage::SpawnVoxelGrid(entity, grid) => { + let cid = self.world.spawn(grid).id(); + self.server_id_map.insert(entity, cid); + } + ClientMessage::PosUpdate(e, pos) => { + if let Some(id) = self.server_id_map.get(&e) { + self.world.entity_mut(*id).insert(pos); + } + } + } + } } pub fn window_event(&mut self, event: WindowEvent) { match event { WindowEvent::CloseRequested => self.exit = true, - WindowEvent::Resized(size) => self.renderer.send(RenderMessage::Resize(size)), - WindowEvent::RedrawRequested => self.renderer.send(RenderMessage::Draw), + WindowEvent::Resized(size) => self.renderer.resize(size), + WindowEvent::RedrawRequested => self.renderer.draw(), WindowEvent::CursorLeft { .. } => { self.input.clear(); } diff --git a/src/client/render/command.rs b/src/client/render/command.rs new file mode 100644 index 0000000..c8f846c --- /dev/null +++ b/src/client/render/command.rs @@ -0,0 +1,83 @@ +use crate::client::camera::Camera; + +use super::{voxel::VoxelColor, Renderer}; +use bevy_ecs::entity::Entity; +use nalgebra::{Rotation3, Vector3}; +use std::sync::Arc; +use winit::window::Window; + +#[derive(Debug, Clone)] +pub enum RenderCommand { + CreateVoxelGrid(CreateVoxelGrid), + UpdateGridTransform(UpdateGridTransform), + ViewUpdate(Camera), +} + +#[derive(Debug, Clone)] +pub struct CreateVoxelGrid { + pub id: Entity, + pub pos: Vector3, + pub orientation: Rotation3, + pub dimensions: Vector3, + pub grid: Vec, +} + +#[derive(Debug, Clone)] +pub struct UpdateGridTransform { + pub id: Entity, + pub pos: Vector3, + pub orientation: Rotation3, +} + +impl<'a> Renderer<'a> { + pub fn spawn(window: Arc) -> Renderer<'a> { + let size = window.inner_size(); + + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::PRIMARY, + ..Default::default() + }); + + let surface = instance + .create_surface(window) + .expect("Could not create window surface!"); + Self::new(instance, surface, size) + } + + pub fn handle_commands(&mut self, commands: Vec) { + let mut new_camera = false; + for cmd in commands { + match cmd { + RenderCommand::CreateVoxelGrid(desc) => { + self.voxel_pipeline.add_group( + &self.device, + &mut self.encoder, + &mut self.staging_belt, + desc, + ); + } + RenderCommand::ViewUpdate(camera) => { + new_camera = true; + self.camera = camera; + } + RenderCommand::UpdateGridTransform(update) => { + self.voxel_pipeline.update_transform( + &self.device, + &mut self.encoder, + &mut self.staging_belt, + update, + ); + } + } + } + if new_camera { + self.voxel_pipeline.update_view( + &self.device, + &mut self.encoder, + &mut self.staging_belt, + self.size, + &self.camera, + ); + } + } +} diff --git a/src/client/render/mod.rs b/src/client/render/mod.rs index e415ee4..cdd5b94 100644 --- a/src/client/render/mod.rs +++ b/src/client/render/mod.rs @@ -1,14 +1,13 @@ -mod thread; +mod command; mod util; pub mod voxel; -pub use thread::*; +pub use command::*; use super::camera::Camera; -use crate::client::rsc::{CLEAR_COLOR, FRAME_TIME}; +use crate::client::rsc::CLEAR_COLOR; use nalgebra::Vector2; use smaa::{SmaaMode, SmaaTarget}; -use std::time::{Duration, Instant}; use voxel::VoxelPipeline; use winit::dpi::PhysicalSize; @@ -23,9 +22,6 @@ pub struct Renderer<'a> { voxel_pipeline: VoxelPipeline, smaa_target: SmaaTarget, camera: Camera, - - frame_time: Duration, - target: Instant, } impl<'a> Renderer<'a> { @@ -102,8 +98,6 @@ impl<'a> Renderer<'a> { config, queue, smaa_target, - frame_time: FRAME_TIME, - target: Instant::now(), } } diff --git a/src/client/render/thread.rs b/src/client/render/thread.rs deleted file mode 100644 index df28958..0000000 --- a/src/client/render/thread.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::client::camera::Camera; - -use super::{voxel::VoxelColor, Renderer}; -use nalgebra::{Rotation3, Vector3}; -use std::{ - sync::{ - mpsc::{channel, Receiver, Sender}, - Arc, - }, - thread::JoinHandle, - time::Instant, -}; -use winit::{dpi::PhysicalSize, window::Window}; - -#[derive(Debug, Clone)] -pub enum RenderMessage { - Resize(PhysicalSize), - Draw, - CreateVoxelGrid(CreateVoxelGrid), - ViewUpdate(Camera), - Exit, -} - -#[derive(Debug, Clone)] -pub struct CreateVoxelGrid { - pub pos: Vector3, - pub orientation: Rotation3, - pub dimensions: Vector3, - pub grid: Vec, -} - -impl Renderer<'_> { - pub fn spawn(window: Arc) -> (RendererChannel, JoinHandle<()>) { - let (s, mut r) = channel(); - - let size = window.inner_size(); - - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { - backends: wgpu::Backends::PRIMARY, - ..Default::default() - }); - - let surface = instance - .create_surface(window) - .expect("Could not create window surface!"); - ( - RendererChannel(s), - std::thread::spawn(move || { - Self::new(instance, surface, size).start(&mut r); - }), - ) - } - - pub fn start(&mut self, reciever: &mut Receiver) { - let mut new_camera = false; - 'main: loop { - let now = Instant::now(); - for msg in reciever.try_iter() { - match msg { - RenderMessage::CreateVoxelGrid(desc) => { - self.voxel_pipeline.add_group( - &self.device, - &mut self.encoder, - &mut self.staging_belt, - desc, - ); - } - RenderMessage::Draw => { - self.draw(); - } - RenderMessage::Resize(size) => { - self.resize(size); - } - RenderMessage::Exit => { - break 'main; - } - RenderMessage::ViewUpdate(camera) => { - new_camera = true; - self.camera = camera; - } - } - } - if now >= self.target { - self.target = now + self.frame_time; - if new_camera { - self.voxel_pipeline.update_view( - &self.device, - &mut self.encoder, - &mut self.staging_belt, - self.size, - &self.camera, - ); - new_camera = false; - } - self.draw(); - } - } - } -} - -#[derive(Clone)] -pub struct RendererChannel(Sender); -impl RendererChannel { - pub fn send(&self, msg: RenderMessage) { - // TODO: handle this properly - self.0.send(msg).expect("Failed to send renderer message"); - } -} diff --git a/src/client/render/voxel/mod.rs b/src/client/render/voxel/mod.rs index 329954e..82a2a5d 100644 --- a/src/client/render/voxel/mod.rs +++ b/src/client/render/voxel/mod.rs @@ -4,11 +4,15 @@ mod group; mod light; mod view; +use std::collections::HashMap; + +use bevy_ecs::entity::Entity; pub use color::*; use light::GlobalLight; use nalgebra::{Projective3, Transform3, Translation3, Vector2, Vector3}; +use super::UpdateGridTransform; use crate::client::{ camera::Camera, render::{ @@ -16,6 +20,7 @@ use crate::client::{ CreateVoxelGrid, }, }; + use {group::VoxelGroup, view::View}; pub struct VoxelPipeline { @@ -26,6 +31,7 @@ pub struct VoxelPipeline { voxel_groups: Storage, voxels: Storage, global_lights: Storage, + id_map: HashMap, } impl VoxelPipeline { @@ -123,6 +129,7 @@ impl VoxelPipeline { voxels, voxel_groups, global_lights, + id_map: HashMap::new(), } } @@ -132,6 +139,7 @@ impl VoxelPipeline { encoder: &mut wgpu::CommandEncoder, belt: &mut wgpu::util::StagingBelt, CreateVoxelGrid { + id, pos, orientation, dimensions, @@ -139,6 +147,7 @@ impl VoxelPipeline { }: CreateVoxelGrid, ) { let offset = self.voxels.len(); + let updates = [ArrBufUpdate { offset, data: &grid, @@ -160,10 +169,13 @@ impl VoxelPipeline { offset: self.voxel_groups.len(), data: &[group], }]; - let size = self.voxel_groups.len() + 1; + let i = self.voxel_groups.len(); + let size = i + 1; self.voxel_groups .update(device, encoder, belt, size, &updates); + self.id_map.insert(id, (i, group)); + self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &self.bind_group_layout, entries: &[ @@ -176,6 +188,30 @@ impl VoxelPipeline { }); } + pub fn update_transform( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, + update: UpdateGridTransform, + ) { + if let Some((i, group)) = self.id_map.get_mut(&update.id) { + let proj = Projective3::identity() + * Translation3::from(update.pos) + * update.orientation + * Translation3::from(-group.dimensions.cast() / 2.0); + group.transform = proj; + group.transform_inv = proj.inverse(); + let updates = [ArrBufUpdate { + offset: *i, + data: &[*group], + }]; + let size = self.voxel_groups.len(); + self.voxel_groups + .update(device, encoder, belt, size, &updates); + } + } + pub fn update_view( &mut self, device: &wgpu::Device, diff --git a/src/client/system/mod.rs b/src/client/system/mod.rs index 8fef9bd..cf25e6c 100644 --- a/src/client/system/mod.rs +++ b/src/client/system/mod.rs @@ -1 +1 @@ -pub mod voxel_grid; +pub mod render; diff --git a/src/client/system/render.rs b/src/client/system/render.rs new file mode 100644 index 0000000..c2b0448 --- /dev/null +++ b/src/client/system/render.rs @@ -0,0 +1,50 @@ +use bevy_ecs::{ + entity::Entity, + query::{Added, Changed, Or}, + system::{Query, ResMut}, +}; +use nalgebra::Vector3; +use ndarray::Axis; + +use crate::{ + client::{ + component::RenderCommands, + render::{CreateVoxelGrid, RenderCommand, UpdateGridTransform}, + }, + world::component::{Orientation, Pos, VoxelGrid}, +}; + +pub fn add_grid( + query: Query< + (Entity, &Pos, &Orientation, &VoxelGrid), + Or<(Added, Added, Added)>, + >, + mut renderer: ResMut, +) { + for (id, pos, orientation, grid) in query.iter() { + renderer.push(RenderCommand::CreateVoxelGrid(CreateVoxelGrid { + id, + pos: **pos, + orientation: **orientation, + dimensions: Vector3::new( + grid.len_of(Axis(0)), + grid.len_of(Axis(1)), + grid.len_of(Axis(2)), + ), + grid: grid.iter().cloned().collect(), + })); + } +} + +pub fn update_transform( + query: Query<(Entity, &Pos, &Orientation), Or<(Changed, Changed)>>, + mut renderer: ResMut, +) { + for (id, pos, orientation) in query.iter() { + renderer.push(RenderCommand::UpdateGridTransform(UpdateGridTransform { + id, + pos: **pos, + orientation: **orientation, + })); + } +} diff --git a/src/client/system/voxel_grid.rs b/src/client/system/voxel_grid.rs deleted file mode 100644 index 54ac218..0000000 --- a/src/client/system/voxel_grid.rs +++ /dev/null @@ -1,36 +0,0 @@ -use bevy_ecs::{ - query::{Changed, Or}, - system::{Query, Res}, -}; -use nalgebra::Vector3; -use ndarray::Axis; - -use crate::{ - client::{ - component::RenderResource, - render::{CreateVoxelGrid, RenderMessage}, - }, - world::component::{Orientation, Pos, VoxelGrid}, -}; - -pub fn update_renderer( - query: Query< - (&Pos, &Orientation, &VoxelGrid), - Or<(Changed, Changed, Changed)>, - >, - renderer: Res, -) { - for (pos, orientation, grid) in query.iter() { - println!("YAY"); - renderer.send(RenderMessage::CreateVoxelGrid(CreateVoxelGrid { - pos: **pos, - orientation: **orientation, - dimensions: Vector3::new( - grid.len_of(Axis(0)), - grid.len_of(Axis(1)), - grid.len_of(Axis(2)), - ), - grid: grid.iter().cloned().collect(), - })); - } -} diff --git a/src/main.rs b/src/main.rs index e58210d..02e6d0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ use client::ClientApp; use winit::event_loop::EventLoop; mod client; -mod util; mod world; mod server; mod sync; diff --git a/src/server/mod.rs b/src/server/mod.rs index 3180939..c9c496a 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,36 +1,57 @@ mod rsc; +mod system; use crate::{ - sync::{client_server_channel, ClientHandle, ServerHandle}, - world::generation::generate, + sync::{ClientChannel, ClientMessage, ClientSender, ServerMessage}, + world::{ + component::{Orientation, Pos, Synced, VoxelGrid, VoxelGridBundle}, + generation::generate, + }, }; -use bevy_ecs::world::World; +use bevy_ecs::{entity::Entity, query::With, system::SystemId, world::World}; use rsc::UPDATE_TIME; use std::time::{Duration, Instant}; pub struct Server { update_time: Duration, target: Instant, - client: ClientHandle, + client: ClientChannel, world: World, + systems: ServerSystems, + mov: Vec, + stop: bool, +} + +pub struct ServerSystems { + sync_pos: SystemId, +} + +impl ServerSystems { + pub fn new(world: &mut World) -> Self { + Self { + sync_pos: world.register_system(system::sync::pos), + } + } } impl Server { - pub fn new(ch: ClientHandle) -> Self { + pub fn new(client: ClientChannel) -> Self { + let mut world = World::new(); + world.insert_resource(ClientSender(client.sender())); + let systems = ServerSystems::new(&mut world); Self { - client: ch, - world: World::new(), + client, + world, + systems, target: Instant::now(), update_time: UPDATE_TIME, + mov: Vec::new(), + stop: false, } } - pub fn spawn() -> ServerHandle { - let (ch, sh) = client_server_channel(); - std::thread::spawn(|| { - Self::new(ch).run(); - }); - sh + pub fn start(ch: ClientChannel) { + Self::new(ch).run(); } pub fn run(&mut self) { @@ -40,13 +61,49 @@ impl Server { let now = Instant::now(); if now >= self.target { self.target += self.update_time; + let mut q = self.world.query::<(Entity, &mut Pos)>(); + for (e, mut p) in q.iter_mut(&mut self.world) { + if self.mov.contains(&e) { + p.x += 0.1; + } + } + self.world.run_system(self.systems.sync_pos).unwrap(); + self.world.clear_trackers(); + } + if self.stop { + break; } } } pub fn recv(&mut self) { for msg in self.client.recv() { - + match msg { + ServerMessage::LoadWorld => { + let mut q = self + .world + .query_filtered::<(Entity, &Pos, &Orientation, &VoxelGrid), With>(); + // ePOG + for (e, p, o, g) in q.iter(&self.world) { + self.client.send(ClientMessage::SpawnVoxelGrid( + e, + VoxelGridBundle { + pos: *p, + orientation: *o, + grid: g.clone(), + }, + )) + } + } + ServerMessage::SpawnVoxelGrid(grid) => { + let e = self.world.spawn((grid.clone(), Synced)).id(); + self.mov.push(e); + self.client.send(ClientMessage::SpawnVoxelGrid(e, grid)); + } + ServerMessage::Stop => { + self.stop = true; + } + } } } } diff --git a/src/server/system/mod.rs b/src/server/system/mod.rs new file mode 100644 index 0000000..d086d5b --- /dev/null +++ b/src/server/system/mod.rs @@ -0,0 +1 @@ +pub mod sync; diff --git a/src/server/system/sync.rs b/src/server/system/sync.rs new file mode 100644 index 0000000..0533f84 --- /dev/null +++ b/src/server/system/sync.rs @@ -0,0 +1,9 @@ +use bevy_ecs::{entity::Entity, query::Changed, system::{Query, Res}}; + +use crate::{sync::{ClientMessage, ClientSender}, world::component::{Pos, Synced}}; + +pub fn pos(query: Query<(Entity, &Synced, &Pos), Changed>, client: Res) { + for (e, _, pos) in query.iter() { + client.send(ClientMessage::PosUpdate(e, *pos)); + } +} diff --git a/src/sync/mod.rs b/src/sync/mod.rs index ff06898..abfdfe5 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -1,48 +1,28 @@ -use std::sync::mpsc::{channel, Receiver, Sender, TryIter}; +pub mod thread; -use bevy_ecs::{ - component::{Component, TableStorage}, - entity::Entity, -}; +use crate::world::component::{Pos, VoxelGridBundle}; +use bevy_ecs::{entity::Entity, system::Resource}; +use std::sync::mpsc::Sender; +use thread::{ThreadChannel, ThreadHandle}; -pub enum ServerMessage {} +pub enum ServerMessage { + Stop, + LoadWorld, + SpawnVoxelGrid(VoxelGridBundle), +} pub enum ClientMessage { - LoadWorld(Vec<(Entity, Vec>>)>), + SpawnVoxelGrid(Entity, VoxelGridBundle), + PosUpdate(Entity, Pos), } -pub struct ServerHandle { - send: Sender, - recv: Receiver, -} +pub type ClientChannel = ThreadChannel; +pub type ServerHandle = ThreadHandle; -impl ServerHandle { - pub fn send(&self, msg: ServerMessage) { - self.send.send(msg).expect("BOOOOOO"); - } - pub fn recv(&self) -> TryIter { - self.recv.try_iter() - } -} - -pub struct ClientHandle { - send: Sender, - recv: Receiver, -} - -impl ClientHandle { +#[derive(Resource, Clone)] +pub struct ClientSender(pub Sender); +impl ClientSender { pub fn send(&self, msg: ClientMessage) { - self.send.send(msg).expect("YOU HAVE FAILED THE MISSION"); - } - pub fn recv(&self) -> TryIter { - self.recv.try_iter() + self.0.send(msg).expect("YOU HAVE FAILED THE MISSION"); } } - -pub fn client_server_channel() -> (ClientHandle, ServerHandle) { - let (cs, sr) = channel(); - let (ss, cr) = channel(); - let sh = ServerHandle { send: ss, recv: sr }; - let ch = ClientHandle { send: cs, recv: cr }; - (ch, sh) -} diff --git a/src/sync/thread.rs b/src/sync/thread.rs new file mode 100644 index 0000000..be89537 --- /dev/null +++ b/src/sync/thread.rs @@ -0,0 +1,53 @@ +use std::{ + sync::mpsc::{channel, Receiver, Sender, TryIter}, + thread::JoinHandle, +}; + +pub struct ThreadHandle { + pub channel: ThreadChannel, + pub handle: Option>, +} + +impl ThreadHandle { + pub fn send(&self, msg: SendMsg) { + self.channel.send(msg); + } + pub fn recv(&self) -> TryIter { + self.channel.recv() + } + pub fn join(&mut self) { + self.handle.take().map(|h| h.join()); + } + pub fn spawn) + Send + 'static>(f: F) -> Self { + let (hs, tr) = channel(); + let (ts, hr) = channel(); + + let th = ThreadChannel { send: ts, recv: tr }; + let run = || { + f(th); + }; + let handle = std::thread::spawn(run); + ThreadHandle { + channel: ThreadChannel { send: hs, recv: hr }, + handle: Some(handle), + } + } +} + +pub struct ThreadChannel { + send: Sender, + recv: Receiver, +} + +impl ThreadChannel { + pub fn sender(&self) -> Sender { + self.send.clone() + } + pub fn send(&self, msg: SendMsg) { + // TODO: handle this properly + self.send.send(msg).expect("Failed to send message"); + } + pub fn recv(&self) -> TryIter { + self.recv.try_iter() + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index 7e7b477..0000000 --- a/src/util/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod swap_buf; diff --git a/src/util/swap_buf.rs b/src/util/swap_buf.rs deleted file mode 100644 index f909a0f..0000000 --- a/src/util/swap_buf.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::ops::{Deref, DerefMut, Add}; - -pub struct SwapBuffer { - read: Vec, - write: Vec, - modify: Vec, -} - -impl> SwapBuffer { - pub fn new(size: usize) -> Self { - Self { - read: vec![T::default(); size], - write: vec![T::default(); size], - modify: vec![T::default(); size], - } - } - - pub fn swap(&mut self) { - std::mem::swap(&mut self.read, &mut self.write); - for (m, r) in self.modify.iter_mut().zip(&mut self.read) { - *r = *r + *m; - *m = T::default(); - } - } - - pub fn rwm(&mut self) -> (&mut Vec, &mut Vec, &mut Vec) { - (&mut self.read, &mut self.write, &mut self.modify) - } -} - -impl Deref for SwapBuffer { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.read - } -} - -impl DerefMut for SwapBuffer { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.read - } -} - diff --git a/src/world/component.rs b/src/world/component.rs index cf110ee..229a7ef 100644 --- a/src/world/component.rs +++ b/src/world/component.rs @@ -7,9 +7,12 @@ use ndarray::{Array3, ArrayBase, Dim, SliceArg}; use crate::client::render::voxel::VoxelColor; -#[derive(Debug, Component, Default, Deref, DerefMut)] +#[derive(Debug, Clone, Copy, Component, Default)] +pub struct Synced; + +#[derive(Debug, Clone, Copy, Component, Default, Deref, DerefMut)] pub struct Pos(pub Vector3); -#[derive(Debug, Component, Default, Deref, DerefMut)] +#[derive(Debug, Clone, Copy, Component, Default, Deref, DerefMut)] pub struct Orientation(pub Rotation3); pub type VoxelGrid = TrackedGrid; @@ -62,7 +65,7 @@ impl From> for Orientation { } } -#[derive(Bundle)] +#[derive(Bundle, Clone)] pub struct VoxelGridBundle { pub pos: Pos, pub orientation: Orientation, diff --git a/src/world/ecs/component.rs b/src/world/ecs/component.rs deleted file mode 100644 index 7e5fe6e..0000000 --- a/src/world/ecs/component.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::{ops::Deref, sync::mpsc::{channel, Receiver, Sender}}; - -pub type EntityID = usize; - -pub struct Component { - id: EntityID, - val: T, -} - -impl Deref for Component { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.val - } -} - -pub struct ComponentVec { - vec: Vec>, - changes: Vec, -} - -impl<'a, T> IntoIterator for &'a ComponentVec { - type Item = &'a Component; - type IntoIter = std::slice::Iter<'a, Component>; - fn into_iter(self) -> Self::IntoIter { - (&self.vec).into_iter() - } -} - -pub struct ComponentMut<'a, T> { - cmp: &'a Component, - send: Sender, -} - -pub struct ComponentMutIter<'a, T> { - iter: std::slice::IterMut<'a, Component>, - recv: Receiver, - send: Sender, - i: usize, -} - -impl<'a, T> Iterator for ComponentMutIter<'a, T> { - type Item = ComponentMut<'a, T>; - fn next(&mut self) -> Option { - self.iter.next().map(|c| ComponentMut { - cmp: c, - send: self.send.clone(), - }) - } -} - -impl<'a, T> IntoIterator for &'a mut ComponentVec { - type Item = ComponentMut<'a, T>; - type IntoIter = ComponentMutIter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - let (send, recv) = channel(); - ComponentMutIter { - iter: (&mut self.vec).into_iter(), - recv, - send, - i: 0, - } - } -} diff --git a/src/world/ecs/mod.rs b/src/world/ecs/mod.rs deleted file mode 100644 index 9db673f..0000000 --- a/src/world/ecs/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod component; -mod world; -pub use component::*; -pub use world::*; - diff --git a/src/world/ecs/world.rs b/src/world/ecs/world.rs deleted file mode 100644 index 8f22384..0000000 --- a/src/world/ecs/world.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub struct World { -} - -impl World { - pub fn new() -> Self { - Self {} - } -} diff --git a/src/world/event.rs b/src/world/event.rs deleted file mode 100644 index 6c8534c..0000000 --- a/src/world/event.rs +++ /dev/null @@ -1,11 +0,0 @@ -use nalgebra::{Rotation3, Vector3}; - -use super::component::VoxelGrid; - -#[derive(GlobalEvent)] -pub struct SpawnVoxelGrid { - pub pos: Vector3, - pub orientation: Rotation3, - pub grid: VoxelGrid, -} - diff --git a/src/world/generation/mod.rs b/src/world/generation/mod.rs index 3b4e8b1..5ea038c 100644 --- a/src/world/generation/mod.rs +++ b/src/world/generation/mod.rs @@ -5,11 +5,11 @@ use ndarray::Array3; use crate::client::render::voxel::VoxelColor; -use super::component::VoxelGridBundle; +use super::component::{Synced, VoxelGridBundle}; pub fn generate(world: &mut World) { let dim = (15, 10, 10); - world.spawn(VoxelGridBundle { + world.spawn((VoxelGridBundle { pos: Vector3::new(0.0, 0.0, 20.0).into(), orientation: Rotation3::from_axis_angle(&Vector3::y_axis(), 0.5).into(), grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| { @@ -33,10 +33,10 @@ pub fn generate(world: &mut World) { VoxelColor::none() } })), - }); + }, Synced)); let dim = (1000, 2, 1000); - world.spawn(VoxelGridBundle { + world.spawn((VoxelGridBundle { pos: Vector3::new(0.0, -2.1, 0.0).into(), orientation: Rotation3::identity().into(), grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(x, y, z)| { @@ -53,10 +53,10 @@ pub fn generate(world: &mut World) { VoxelColor::none() } })), - }); + }, Synced)); let dim = (3, 3, 3); - world.spawn(VoxelGridBundle { + world.spawn((VoxelGridBundle { pos: Vector3::new(0.0, 0.0, 16.5).into(), orientation: (Rotation3::from_axis_angle(&Vector3::y_axis(), std::f32::consts::PI / 4.0) * Rotation3::from_axis_angle( @@ -70,5 +70,5 @@ pub fn generate(world: &mut World) { b: 255, a: 255, })), - }); + }, Synced)); }