idk switching to bevy ecs again

This commit is contained in:
2024-06-13 00:54:52 -04:00
parent df4e433dcc
commit 24a7e299fa
20 changed files with 615 additions and 161 deletions

View File

@@ -1,9 +1,4 @@
use std::sync::Arc;
use winit::{
application::ApplicationHandler, event::WindowEvent, event_loop::ControlFlow,
window::WindowAttributes,
};
use winit::{application::ApplicationHandler, event::WindowEvent, event_loop::ControlFlow};
use super::Client;
@@ -24,13 +19,7 @@ impl ClientApp {
impl ApplicationHandler for ClientApp {
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
if self.client.is_none() {
let window = Arc::new(
event_loop
.create_window(WindowAttributes::default())
.expect("Failed to create window"),
);
let client = Client::new(window);
self.client = Some(client);
self.client = Some(Client::new(event_loop));
}
event_loop.set_control_flow(ControlFlow::Poll);
}
@@ -54,8 +43,6 @@ impl ApplicationHandler for ClientApp {
}
fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
if self.client().update() {
event_loop.exit();
}
self.client().update(event_loop);
}
}

View File

@@ -1,18 +1,18 @@
use std::ops::{Deref, DerefMut};
use evenio::component::Component;
use bevy_ecs::system::Resource;
use super::render::RendererChannel;
#[derive(Component)]
pub struct RenderComponent(pub RendererChannel);
impl Deref for RenderComponent {
#[derive(Resource)]
pub struct RenderResource(pub RendererChannel);
impl Deref for RenderResource {
type Target = RendererChannel;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RenderComponent {
impl DerefMut for RenderResource {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}

View File

@@ -4,9 +4,9 @@ use nalgebra::Rotation3;
use ndarray::Array3;
use winit::{dpi::PhysicalPosition, keyboard::KeyCode as Key, window::CursorGrabMode};
use crate::world::component::VoxelGrid;
use crate::world::component::{VoxelGrid, VoxelGridBundle};
use super::{render::voxel::VoxelColor, system::voxel_grid::SpawnVoxelGrid, Client};
use super::{render::voxel::VoxelColor, Client};
impl Client {
pub fn handle_input(&mut self, dt: &Duration) {
@@ -102,19 +102,18 @@ impl Client {
}
if state.camera != old_camera {
self.renderer
.send(super::render::RenderMessage::ViewUpdate(state.camera))
.expect("AAAAAAA");
.send(super::render::RenderMessage::ViewUpdate(state.camera));
}
// fun
if input.just_pressed(Key::KeyF) {
self.world.send(SpawnVoxelGrid {
pos: state.camera.pos + 135.0 * 2.0 * *state.camera.forward(),
orientation: state.camera.orientation,
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()
})),
})
});
}
}
}

View File

@@ -2,7 +2,6 @@ mod app;
mod camera;
mod component;
mod handle_input;
mod init;
mod input;
pub mod render;
mod rsc;
@@ -10,15 +9,20 @@ mod state;
mod system;
pub use app::*;
use component::RenderComponent;
use evenio::world::World;
use init::init_world;
use bevy_ecs::{system::SystemId, world::World};
use component::RenderResource;
use render::{RenderMessage, RendererChannel};
pub use state::*;
use system::voxel_grid::update_renderer;
use crate::{server::Server, sync::ServerHandle, world::generation::generate};
use self::{input::Input, render::Renderer, ClientState};
use std::{sync::Arc, thread::JoinHandle, time::Instant};
use winit::{event::WindowEvent, window::Window};
use winit::{
event::WindowEvent,
window::{Window, WindowAttributes},
};
pub struct Client {
window: Arc<Window>,
@@ -31,19 +35,26 @@ pub struct Client {
grabbed_cursor: bool,
keep_cursor: bool,
world: World,
server: ServerHandle,
bruh: SystemId,
}
impl Client {
pub fn new(window: Arc<Window>) -> Self {
pub fn new(event_loop: &winit::event_loop::ActiveEventLoop) -> Self {
let mut world = World::new();
let window = Arc::new(
event_loop
.create_window(WindowAttributes::default())
.expect("Failed to create window"),
);
let (render_channel, render_handle) = Renderer::spawn(window.clone());
let e = world.spawn();
world.insert(e, RenderComponent(render_channel.clone()));
world.add_handler(system::voxel_grid::handle_create_grid);
world.insert_resource(RenderResource(render_channel.clone()));
let bruh = world.register_system(update_renderer);
init_world(&mut world);
let state = ClientState::new();
let server = Server::spawn();
generate(&mut world);
Self {
window,
@@ -56,10 +67,12 @@ impl Client {
grabbed_cursor: false,
keep_cursor: false,
world,
server,
bruh,
}
}
pub fn update(&mut self) -> bool {
pub fn update(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
let now = Instant::now();
let dt = now - self.prev_update;
self.prev_update = now;
@@ -67,8 +80,12 @@ impl Client {
self.handle_input(&dt);
self.input.end();
self.recv();
self.world.run_system(self.bruh).expect("WHAT");
self.world.clear_trackers();
if self.exit {
let _ = self.renderer.send(RenderMessage::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
@@ -76,21 +93,19 @@ impl Client {
.expect("uh oh")
.join()
.expect("bruh");
event_loop.exit();
}
self.exit
}
pub fn recv(&mut self) {
for msg in self.server.recv() {}
}
pub fn window_event(&mut self, event: WindowEvent) {
match event {
WindowEvent::CloseRequested => self.exit = true,
WindowEvent::Resized(size) => self
.renderer
.send(RenderMessage::Resize(size))
.expect("render broke"),
WindowEvent::RedrawRequested => self
.renderer
.send(RenderMessage::Draw)
.expect("render broke"),
WindowEvent::Resized(size) => self.renderer.send(RenderMessage::Resize(size)),
WindowEvent::RedrawRequested => self.renderer.send(RenderMessage::Draw),
WindowEvent::CursorLeft { .. } => {
self.input.clear();
}

View File

@@ -17,6 +17,7 @@ pub struct Renderer<'a> {
surface: wgpu::Surface<'a>,
device: wgpu::Device,
queue: wgpu::Queue,
encoder: wgpu::CommandEncoder,
config: wgpu::SurfaceConfiguration,
staging_belt: wgpu::util::StagingBelt,
voxel_pipeline: VoxelPipeline,
@@ -96,6 +97,7 @@ impl<'a> Renderer<'a> {
voxel_pipeline: VoxelPipeline::new(&device, &config.format),
staging_belt,
surface,
encoder: Self::create_encoder(&device),
device,
config,
queue,
@@ -105,15 +107,14 @@ impl<'a> Renderer<'a> {
}
}
fn create_encoder(&mut self) -> wgpu::CommandEncoder {
self.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
})
fn create_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder {
device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
})
}
pub fn draw(&mut self, encoder: &mut wgpu::CommandEncoder) {
let mut encoder = std::mem::replace(encoder, self.create_encoder());
pub fn draw(&mut self) {
let mut encoder = std::mem::replace(&mut self.encoder, Self::create_encoder(&self.device));
let output = self.surface.get_current_texture().unwrap();
let view = output
.texture
@@ -146,7 +147,7 @@ impl<'a> Renderer<'a> {
self.staging_belt.recall();
}
pub fn resize(&mut self, size: PhysicalSize<u32>, encoder: &mut wgpu::CommandEncoder) {
pub fn resize(&mut self, size: PhysicalSize<u32>) {
self.size = Vector2::new(size.width, size.height);
self.config.width = size.width;
self.config.height = size.height;
@@ -156,7 +157,7 @@ impl<'a> Renderer<'a> {
self.voxel_pipeline.update_view(
&self.device,
encoder,
&mut self.encoder,
&mut self.staging_belt,
self.size,
&self.camera,

View File

@@ -12,7 +12,7 @@ use std::{
};
use winit::{dpi::PhysicalSize, window::Window};
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum RenderMessage {
Resize(PhysicalSize<u32>),
Draw,
@@ -21,9 +21,7 @@ pub enum RenderMessage {
Exit,
}
pub type RendererChannel = Sender<RenderMessage>;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct CreateVoxelGrid {
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
@@ -46,7 +44,7 @@ impl Renderer<'_> {
.create_surface(window)
.expect("Could not create window surface!");
(
s,
RendererChannel(s),
std::thread::spawn(move || {
Self::new(instance, surface, size).start(&mut r);
}),
@@ -54,25 +52,24 @@ impl Renderer<'_> {
}
pub fn start(&mut self, reciever: &mut Receiver<RenderMessage>) {
let mut encoder = self.create_encoder();
let mut new_camera = false;
'main: loop {
let now = Instant::now();
while let Ok(msg) = reciever.try_recv() {
for msg in reciever.try_iter() {
match msg {
RenderMessage::CreateVoxelGrid(desc) => {
self.voxel_pipeline.add_group(
&self.device,
&mut encoder,
&mut self.encoder,
&mut self.staging_belt,
desc,
);
}
RenderMessage::Draw => {
self.draw(&mut encoder);
self.draw();
}
RenderMessage::Resize(size) => {
self.resize(size, &mut encoder);
self.resize(size);
}
RenderMessage::Exit => {
break 'main;
@@ -88,15 +85,24 @@ impl Renderer<'_> {
if new_camera {
self.voxel_pipeline.update_view(
&self.device,
&mut encoder,
&mut self.encoder,
&mut self.staging_belt,
self.size,
&self.camera,
);
new_camera = false;
}
self.draw(&mut encoder);
self.draw();
}
}
}
}
#[derive(Clone)]
pub struct RendererChannel(Sender<RenderMessage>);
impl RendererChannel {
pub fn send(&self, msg: RenderMessage) {
// TODO: handle this properly
self.0.send(msg).expect("Failed to send renderer message");
}
}

View File

@@ -1,49 +1,36 @@
use evenio::{
event::{EventMut, GlobalEvent, Insert, ReceiverMut, Sender, Spawn},
fetch::Single,
use bevy_ecs::{
query::{Changed, Or},
system::{Query, Res},
};
use nalgebra::{Rotation3, Vector3};
use nalgebra::Vector3;
use ndarray::Axis;
use crate::{
client::{
component::RenderComponent,
component::RenderResource,
render::{CreateVoxelGrid, RenderMessage},
},
world::component::{Orientation, Pos, VoxelGrid},
};
#[derive(GlobalEvent)]
pub struct SpawnVoxelGrid {
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
pub grid: VoxelGrid,
}
pub fn handle_create_grid(
r: ReceiverMut<SpawnVoxelGrid>,
renderer: Single<&RenderComponent>,
mut s: Sender<(Spawn, Insert<Pos>, Insert<Orientation>, Insert<VoxelGrid>)>,
pub fn update_renderer(
query: Query<
(&Pos, &Orientation, &VoxelGrid),
Or<(Changed<Pos>, Changed<Orientation>, Changed<VoxelGrid>)>,
>,
renderer: Res<RenderResource>,
) {
let SpawnVoxelGrid {
pos,
orientation,
grid,
} = EventMut::take(r.event);
renderer
.send(RenderMessage::CreateVoxelGrid(CreateVoxelGrid {
pos,
orientation,
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(),
}))
.expect("render broke");
let e = s.spawn();
s.insert(e, Pos(pos));
s.insert(e, Orientation(orientation));
s.insert(e, grid);
}));
}
}

View File

@@ -1,9 +1,13 @@
#![allow(clippy::type_complexity)]
use client::ClientApp;
use winit::event_loop::EventLoop;
mod client;
mod util;
mod world;
mod server;
mod sync;
fn main() {
let event_loop = EventLoop::new().expect("Failed to create event loop");

52
src/server/mod.rs Normal file
View File

@@ -0,0 +1,52 @@
mod rsc;
use crate::{
sync::{client_server_channel, ClientHandle, ServerHandle},
world::generation::generate,
};
use bevy_ecs::world::World;
use rsc::UPDATE_TIME;
use std::time::{Duration, Instant};
pub struct Server {
update_time: Duration,
target: Instant,
client: ClientHandle,
world: World,
}
impl Server {
pub fn new(ch: ClientHandle) -> Self {
Self {
client: ch,
world: World::new(),
target: Instant::now(),
update_time: UPDATE_TIME,
}
}
pub fn spawn() -> ServerHandle {
let (ch, sh) = client_server_channel();
std::thread::spawn(|| {
Self::new(ch).run();
});
sh
}
pub fn run(&mut self) {
generate(&mut self.world);
loop {
self.recv();
let now = Instant::now();
if now >= self.target {
self.target += self.update_time;
}
}
}
pub fn recv(&mut self) {
for msg in self.client.recv() {
}
}
}

4
src/server/rsc.rs Normal file
View File

@@ -0,0 +1,4 @@
use std::time::Duration;
pub const UPS: u32 = 60;
pub const UPDATE_TIME: Duration = Duration::from_millis(1000 / UPS as u64);

48
src/sync/mod.rs Normal file
View File

@@ -0,0 +1,48 @@
use std::sync::mpsc::{channel, Receiver, Sender, TryIter};
use bevy_ecs::{
component::{Component, TableStorage},
entity::Entity,
};
pub enum ServerMessage {}
pub enum ClientMessage {
LoadWorld(Vec<(Entity, Vec<Box<dyn Component<Storage = TableStorage>>>)>),
}
pub struct ServerHandle {
send: Sender<ServerMessage>,
recv: Receiver<ClientMessage>,
}
impl ServerHandle {
pub fn send(&self, msg: ServerMessage) {
self.send.send(msg).expect("BOOOOOO");
}
pub fn recv(&self) -> TryIter<ClientMessage> {
self.recv.try_iter()
}
}
pub struct ClientHandle {
send: Sender<ClientMessage>,
recv: Receiver<ServerMessage>,
}
impl ClientHandle {
pub fn send(&self, msg: ClientMessage) {
self.send.send(msg).expect("YOU HAVE FAILED THE MISSION");
}
pub fn recv(&self) -> TryIter<ServerMessage> {
self.recv.try_iter()
}
}
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)
}

View File

@@ -1,14 +1,15 @@
use std::ops::{Deref, DerefMut, Range};
use std::ops::Range;
use evenio::component::Component;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{bundle::Bundle, component::Component};
use nalgebra::{Rotation3, Vector3};
use ndarray::{Array3, ArrayBase, Dim, SliceArg};
use crate::client::render::voxel::VoxelColor;
#[derive(Debug, Component, Default)]
#[derive(Debug, Component, Default, Deref, DerefMut)]
pub struct Pos(pub Vector3<f32>);
#[derive(Debug, Component, Default)]
#[derive(Debug, Component, Default, Deref, DerefMut)]
pub struct Orientation(pub Rotation3<f32>);
pub type VoxelGrid = TrackedGrid<VoxelColor>;
@@ -61,31 +62,14 @@ impl From<Rotation3<f32>> for Orientation {
}
}
// reref boilerplate :pensive:
#[derive(Bundle)]
pub struct VoxelGridBundle {
pub pos: Pos,
pub orientation: Orientation,
pub grid: VoxelGrid,
}
impl Deref for Pos {
type Target = Vector3<f32>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Pos {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Deref for Orientation {
type Target = Rotation3<f32>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Orientation {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> Deref for TrackedGrid<T> {
impl<T> std::ops::Deref for TrackedGrid<T> {
type Target = Array3<T>;
fn deref(&self) -> &Self::Target {
&self.data

View File

@@ -0,0 +1,64 @@
use std::{ops::Deref, sync::mpsc::{channel, Receiver, Sender}};
pub type EntityID = usize;
pub struct Component<T> {
id: EntityID,
val: T,
}
impl<T> Deref for Component<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.val
}
}
pub struct ComponentVec<T> {
vec: Vec<Component<T>>,
changes: Vec<EntityID>,
}
impl<'a, T> IntoIterator for &'a ComponentVec<T> {
type Item = &'a Component<T>;
type IntoIter = std::slice::Iter<'a, Component<T>>;
fn into_iter(self) -> Self::IntoIter {
(&self.vec).into_iter()
}
}
pub struct ComponentMut<'a, T> {
cmp: &'a Component<T>,
send: Sender<EntityID>,
}
pub struct ComponentMutIter<'a, T> {
iter: std::slice::IterMut<'a, Component<T>>,
recv: Receiver<EntityID>,
send: Sender<EntityID>,
i: usize,
}
impl<'a, T> Iterator for ComponentMutIter<'a, T> {
type Item = ComponentMut<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|c| ComponentMut {
cmp: c,
send: self.send.clone(),
})
}
}
impl<'a, T> IntoIterator for &'a mut ComponentVec<T> {
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,
}
}
}

5
src/world/ecs/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
mod component;
mod world;
pub use component::*;
pub use world::*;

8
src/world/ecs/world.rs Normal file
View File

@@ -0,0 +1,8 @@
pub struct World {
}
impl World {
pub fn new() -> Self {
Self {}
}
}

11
src/world/event.rs Normal file
View File

@@ -0,0 +1,11 @@
use nalgebra::{Rotation3, Vector3};
use super::component::VoxelGrid;
#[derive(GlobalEvent)]
pub struct SpawnVoxelGrid {
pub pos: Vector3<f32>,
pub orientation: Rotation3<f32>,
pub grid: VoxelGrid,
}

View File

@@ -1,17 +1,17 @@
use crate::world::component::VoxelGrid;
use evenio::world::World;
use bevy_ecs::world::World;
use nalgebra::{Rotation3, UnitVector3, Vector3};
use ndarray::Array3;
use crate::client::render::voxel::VoxelColor;
use super::system::voxel_grid::SpawnVoxelGrid;
use super::component::VoxelGridBundle;
pub fn init_world(world: &mut World) {
pub fn generate(world: &mut World) {
let dim = (15, 10, 10);
world.send(SpawnVoxelGrid {
pos: Vector3::new(0.0, 0.0, 20.0),
orientation: Rotation3::from_axis_angle(&Vector3::y_axis(), 0.5),
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)| {
if x == z && x == y {
VoxelColor::white()
@@ -36,9 +36,9 @@ pub fn init_world(world: &mut World) {
});
let dim = (1000, 2, 1000);
world.send(SpawnVoxelGrid {
pos: Vector3::new(0.0, -2.1, 0.0),
orientation: Rotation3::identity(),
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)| {
if y == 0 {
VoxelColor::random()
@@ -56,13 +56,14 @@ pub fn init_world(world: &mut World) {
});
let dim = (3, 3, 3);
world.send(SpawnVoxelGrid {
pos: Vector3::new(0.0, 0.0, 16.5),
orientation: Rotation3::from_axis_angle(&Vector3::y_axis(), std::f32::consts::PI / 4.0)
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(
&UnitVector3::new_normalize(Vector3::new(1.0, 0.0, 1.0)),
std::f32::consts::PI / 4.0,
),
))
.into(),
grid: VoxelGrid::new(Array3::from_shape_fn(dim, |(..)| VoxelColor {
r: 255,
g: 0,

View File

@@ -1 +1,2 @@
pub mod component;
pub mod generation;