diff --git a/Cargo.lock b/Cargo.lock index be99c8c..b48f8a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1127,6 +1127,16 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + [[package]] name = "cursor-icon" version = "1.1.0" @@ -1150,6 +1160,7 @@ version = "0.1.0" dependencies = [ "bevy", "bevy_eventwork", + "ctrlc", "itermore", "rand", "serde", @@ -1817,6 +1828,18 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + [[package]] name = "nonmax" version = "0.5.5" diff --git a/Cargo.toml b/Cargo.toml index 7da5471..881af12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ bevy = { version = "0.14.2", default-features = false, features = [ "multi_threaded", ] } bevy_eventwork = "0.9.0" +ctrlc = "3.4.5" itermore = { version = "0.7.1", features = ["array_chunks"] } rand = "0.8.5" serde = { version = "1.0.215", features = ["derive"] } diff --git a/src/lib_client/input.rs b/src/lib_client/input.rs index 85da48c..7bf4ade 100644 --- a/src/lib_client/input.rs +++ b/src/lib_client/input.rs @@ -1,16 +1,11 @@ -use bevy_eventwork::{tcp::TcpProvider, ConnectionId, Network}; +use bevy_eventwork::{tcp::TcpProvider, Network}; use std::{ - io::{stdin, stdout, Stdout}, + io::{stdin, stdout}, process, sync::{mpsc, Arc, Mutex}, - thread::{self, JoinHandle}, -}; -use termion::{ - cursor::{self, HideCursor}, - event::Key, - input::TermRead, - raw::{IntoRawMode, RawTerminal}, + thread, }; +use termion::{clear, cursor, event::Key, input::TermRead, raw::IntoRawMode}; use bevy::prelude::*; @@ -22,7 +17,7 @@ pub struct InputPlugin; impl Plugin for InputPlugin { fn build(&self, app: &mut App) { - let (rec, _thread) = spawn_reader(); + let rec = spawn_reader(); let rec = Arc::new(Mutex::new(rec)); app.insert_resource(InputReceiver(rec)) .add_event::() @@ -37,23 +32,36 @@ pub struct InputReceiver(Arc>>); #[derive(Debug, Event)] pub struct KeyEvent(Key); -fn spawn_reader() -> (mpsc::Receiver, JoinHandle<()>) { +fn spawn_reader() -> mpsc::Receiver { let (tx, rx) = mpsc::channel(); - let thread = thread::spawn(move || { - let stdout = stdout().into_raw_mode().unwrap(); + + let (exit_tx, exit_rx) = mpsc::channel(); + thread::spawn(move || { + let raw_mode = stdout().into_raw_mode().unwrap(); println!("{}", cursor::Hide); + exit_rx.recv().ok(); + drop(raw_mode); + println!("{}{}", cursor::Restore, clear::All); + process::exit(0); + }); + + let exit_tx_ = exit_tx.clone(); + ctrlc::set_handler(move || { + exit_tx_.send(()).ok(); + }) + .unwrap(); + + thread::spawn(move || { let mut keys = stdin().keys(); while let Some(Ok(key)) = keys.next() { if key == Key::Esc { - println!("exitting."); - println!("{}", cursor::Restore); - drop(stdout); - process::exit(0); + exit_tx.send(()).ok(); } tx.send(key).ok(); } }); - (rx, thread) + + rx } fn try_read_keys(receiver: Res, mut writer: EventWriter) { diff --git a/src/lib_server/display.rs b/src/lib_server/display.rs index 902815d..eca1bba 100644 --- a/src/lib_server/display.rs +++ b/src/lib_server/display.rs @@ -3,7 +3,7 @@ use bevy::{prelude::*, utils::hashbrown::HashSet}; use bevy_eventwork::{tcp::TcpProvider, ConnectionId, Network}; use super::{ - physics::{update_physics_collisions, Pos}, + physics::{self, Pos}, player::Player, }; @@ -13,7 +13,7 @@ impl Plugin for DisplayPlugin { fn build(&self, app: &mut App) { app.add_event::() // .add_systems(Update, rerender_players) - .add_systems(Update, on_updates.after(update_physics_collisions)); + .add_systems(Update, on_updates.after(physics::update_physics_pos)); } } @@ -35,8 +35,8 @@ fn on_updates( let mut to_render = HashSet::new(); for RenderUpdate(event_pos) in updates.read() { for (Player(connection_id), player_pos) in &players { - if player_pos.pos().distance_squared(*event_pos) <= RENDER_DISTANCE_SQ { - to_render.insert((*connection_id, player_pos.pos())); + if player_pos.0.distance_squared(*event_pos) <= RENDER_DISTANCE_SQ { + to_render.insert((*connection_id, player_pos.0)); } } } @@ -54,14 +54,14 @@ fn render( ) { let updates = displayables .iter() - .filter(|(pos, _)| pos.pos().distance_squared(player_pos) <= RENDER_DISTANCE_SQ) - .map(|(pos, Display(display))| (pos.pos() - player_pos, *display)) + .filter(|(pos, _)| pos.0.distance_squared(player_pos) <= RENDER_DISTANCE_SQ) + .map(|(pos, Display(display))| (pos.0 - player_pos, *display)) .collect(); net.send_message(id, MapUpdates(updates)).ok(); } fn rerender_players(players: Query<&Pos, With>, mut writer: EventWriter) { for Pos(pos) in &players { - writer.send(RenderUpdate(pos.as_ivec2())); + writer.send(RenderUpdate(*pos)); } } diff --git a/src/lib_server/generation.rs b/src/lib_server/generation.rs index d423fc4..610f3ea 100644 --- a/src/lib_server/generation.rs +++ b/src/lib_server/generation.rs @@ -1,41 +1,94 @@ use bevy::{prelude::*, utils::HashSet}; -use super::physics::Pos; +use super::{ + display::RenderUpdate, + map::{self, spawn_block}, + physics::Pos, +}; pub struct GenerationPlugin; impl Plugin for GenerationPlugin { fn build(&self, app: &mut bevy::prelude::App) { app.insert_resource(GeneratedRegistry::default()) - // .add_systems(schedule, systems) - ; + .add_systems(Update, chunk_loading); } } -fn chunk_loading(cmd: &mut Commands, loaders: Query<&Pos, With>, reg: ResMut) { - for pos in &loaders { - chunks_surrounding(&pos.pos()); +fn chunk_loading( + mut cmd: Commands, + loaders: Query<&Pos, With>, + mut reg: ResMut, + mut updater: EventWriter, +) { + for loader in &loaders { + for pos in chunks_surrounding(&loader.0, GEN_DISTANCE) { + reg.load_chunk(&mut cmd, &mut updater, pos); + } } } +const GEN_DISTANCE: i32 = 1; const CHUNK_WIDTH: i32 = 8; -fn chunks_surrounding(pos: &IVec2) -> Vec { - todo!() -} - -fn snap(value: i32, increment: i32) -> i32 { - todo!() +fn chunks_surrounding(pos: &IVec2, radius: i32) -> Vec { + let center_chunk = pos.div_euclid(IVec2::splat(CHUNK_WIDTH)); + (-radius..=radius) + .flat_map(move |x| (-radius..=radius).map(move |y| center_chunk + IVec2::new(x, y))) + .collect() } #[test] -fn test_snap() { - // assert_eq!(); +fn test_euclid() { + assert_eq!((5_i32).div_euclid(2), 2); + assert_eq!((4_i32).div_euclid(2), 2); + assert_eq!((3_i32).div_euclid(2), 1); + assert_eq!((2_i32).div_euclid(2), 1); + assert_eq!((1_i32).div_euclid(2), 0); + assert_eq!((0_i32).div_euclid(2), 0); + assert_eq!((-1_i32).div_euclid(2), -1); + assert_eq!((-2_i32).div_euclid(2), -1); + assert_eq!((-3_i32).div_euclid(2), -2); + assert_eq!((-4_i32).div_euclid(2), -2); + assert_eq!((-5_i32).div_euclid(2), -3); +} + +#[test] +fn test_snap_mod() { + assert_eq!((5_i32).rem_euclid(2), 1); + assert_eq!((4_i32).rem_euclid(2), 0); + assert_eq!((3_i32).rem_euclid(2), 1); + assert_eq!((2_i32).rem_euclid(2), 0); + assert_eq!((1_i32).rem_euclid(2), 1); + assert_eq!((0_i32).rem_euclid(2), 0); + assert_eq!((-1_i32).rem_euclid(2), 1); + assert_eq!((-2_i32).rem_euclid(2), 0); + assert_eq!((-3_i32).rem_euclid(2), 1); + assert_eq!((-4_i32).rem_euclid(2), 0); + assert_eq!((-5_i32).rem_euclid(2), 1); } #[derive(Debug, Resource, Default)] pub struct GeneratedRegistry(HashSet); +impl GeneratedRegistry { + pub fn load_chunk(&mut self, cmd: &mut Commands, rerender: &mut EventWriter, chunk: IVec2) { + if self.0.contains(&chunk) { + return; + } + + println!("Loading chunk indexed at position {chunk:?}."); + let from = chunk * CHUNK_WIDTH; + let to = from + IVec2::splat(CHUNK_WIDTH); + for (pos, spawnable) in generate(from, to) { + match spawnable { + Spawnable::Block(display, mass) => spawn_block(cmd, rerender, pos, display, mass), + } + } + self.0.insert(chunk); + } +} + #[derive(Debug, Component)] pub struct Loader; @@ -44,3 +97,19 @@ pub struct Generated; #[derive(Debug, Component)] pub struct Chunk(IVec2); + +enum Spawnable { + Block((char, char), usize), +} + +fn generate(from: IVec2, _to: IVec2) -> Vec<(IVec2, Spawnable)> { + let structure = " +XX XX + +XX XX +"; + map::str_to_struct(structure) + .into_iter() + .map(|(pos, display, mass)| (pos + from, Spawnable::Block(display, mass))) + .collect() +} diff --git a/src/lib_server/map.rs b/src/lib_server/map.rs index d3cd8fb..63cad9b 100644 --- a/src/lib_server/map.rs +++ b/src/lib_server/map.rs @@ -4,15 +4,22 @@ use bevy::prelude::*; use itermore::IterArrayChunks; use super::{ - display::Display, - physics::{Mass, Pos}, + display::{Display, RenderUpdate}, + physics::{Forces, Mass, Pos}, }; -fn spawn_block(cmd: &mut Commands, pos: IVec2, display: (char, char), mass: usize) { - cmd.spawn((Pos(pos.as_vec2()), Mass(mass), Display(display))); +pub fn spawn_block( + cmd: &mut Commands, + rerender: &mut EventWriter, + pos: IVec2, + display: (char, char), + mass: usize, +) { + cmd.spawn((Forces::zero(), Pos(pos), Mass(mass), Display(display))); + rerender.send(RenderUpdate(pos)); } -fn str_to_struct(text: &str) -> Vec<(IVec2, (char, char), usize)> { +pub fn str_to_struct(text: &str) -> Vec<(IVec2, (char, char), usize)> { text.lines() .enumerate() .flat_map(|(y, line)| { @@ -25,17 +32,17 @@ fn str_to_struct(text: &str) -> Vec<(IVec2, (char, char), usize)> { .collect() } -fn mass_of(tiles: (char, char)) -> usize { +pub fn mass_of(tiles: (char, char)) -> usize { match tiles { ('#', '#') => 100, ('X', 'X') => 10, - ('[', ']') => 5, - ('(', ')') => 1, + ('[', ']') => 8, + ('(', ')') => 5, _ => 20, } } -pub fn spawn_debug_map(mut cmd: Commands) { +pub fn spawn_debug_map(mut cmd: Commands, mut rerender: EventWriter) { let raw = " () @@ -49,6 +56,6 @@ pub fn spawn_debug_map(mut cmd: Commands) { "; for (pos, display, mass) in str_to_struct(raw) { - spawn_block(&mut cmd, pos, display, mass); + spawn_block(&mut cmd, &mut rerender, pos, display, mass); } } diff --git a/src/lib_server/metrics.rs b/src/lib_server/metrics.rs index 02a47c2..f434a3c 100644 --- a/src/lib_server/metrics.rs +++ b/src/lib_server/metrics.rs @@ -16,12 +16,12 @@ impl Plugin for MetricsPlugin { } } -fn show_metrics(time: Res