diff --git a/games/rstnode/Cargo.lock b/games/rstnode/Cargo.lock index 0247eaf0006..33713c4b097 100644 --- a/games/rstnode/Cargo.lock +++ b/games/rstnode/Cargo.lock @@ -1373,6 +1373,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "flate2" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +dependencies = [ + "cfg-if 1.0.0", + "crc32fast", + "libc", + "miniz_oxide 0.4.3", +] + +[[package]] +name = "float-cmp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e" + [[package]] name = "float-cmp" version = "0.8.0" @@ -1388,6 +1406,17 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fontdb" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428948a0f39fb83fe55991d4423e35a793cdbb0322ebe23853f6024124a330d7" +dependencies = [ + "log", + "memmap2", + "ttf-parser 0.9.0", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -2148,6 +2177,15 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kurbo" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cb54cd28cb3d2e964d9444ca185676a94fd9b7cce5f02b22c717947ed8e9a2" +dependencies = [ + "arrayvec", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -2253,7 +2291,7 @@ dependencies = [ "cssparser", "data-url", "encoding", - "float-cmp", + "float-cmp 0.8.0", "gdk-pixbuf", "gdk-pixbuf-sys", "gio", @@ -2300,6 +2338,13 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +[[package]] +name = "little-assets" +version = "0.1.0" +dependencies = [ + "resvg", +] + [[package]] name = "locale_config" version = "0.3.0" @@ -3197,9 +3242,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" dependencies = [ - "siphasher", + "siphasher 0.3.3", ] +[[package]] +name = "pico-args" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1" + [[package]] name = "pin-project" version = "0.4.27" @@ -3710,6 +3761,22 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "resvg" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cf6c4710bcfa7c15a73be647ec7af799500f30c3eecde2060568f3e44c09a52" +dependencies = [ + "jpeg-decoder", + "log", + "pico-args", + "png", + "rgb", + "svgfilters", + "tiny-skia", + "usvg", +] + [[package]] name = "rgb" version = "0.8.25" @@ -3753,6 +3820,15 @@ dependencies = [ "minimp3", ] +[[package]] +name = "roxmltree" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf7d7b1ea646d380d0e8153158063a6da7efe30ddbf3184042848e3f8a6f671" +dependencies = [ + "xmlparser", +] + [[package]] name = "rst-core" version = "0.0.0" @@ -3895,12 +3971,37 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rustybuzz" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab463a295d00f3692e0974a0bfd83c7a9bcd119e27e07c2beecdb1b44a09d10" +dependencies = [ + "bitflags", + "bytemuck", + "smallvec", + "ttf-parser 0.9.0", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-general-category", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "safe_arch" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -4073,6 +4174,21 @@ dependencies = [ "paste", ] +[[package]] +name = "simplecss" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "596554e63596d556a0dbd681416342ca61c75f1a45203201e7e77d3fa2fa9014" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" + [[package]] name = "siphasher" version = "0.3.3" @@ -4286,6 +4402,26 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbef9cf3cf75dd7772fb1f40dd6d90278a5263454db94ee399500ee9918aaa7" +[[package]] +name = "svgfilters" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3016b3217b82ea3bb7cd3b773030222c6acca46c52ef4e64b4e716bd4b25090e" +dependencies = [ + "float-cmp 0.5.3", + "rgb", +] + +[[package]] +name = "svgtypes" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c536faaff1a10837cfe373142583f6e27d81e96beba339147e77b67c9f260ff" +dependencies = [ + "float-cmp 0.5.3", + "siphasher 0.2.3", +] + [[package]] name = "syn" version = "0.15.44" @@ -4486,6 +4622,19 @@ dependencies = [ "syn 1.0.60", ] +[[package]] +name = "tiny-skia" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60736037f43b891718dd2120a096157a188177b8b222adb72bd19e415223ec72" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "png", + "wide", +] + [[package]] name = "tinyvec" version = "0.3.4" @@ -4607,6 +4756,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +[[package]] +name = "ttf-parser" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ddb402ac6c2af6f7a2844243887631c4e94b51585b229fcfddb43958cd55ca" + [[package]] name = "ttf-parser" version = "0.11.0" @@ -4639,6 +4794,24 @@ dependencies = [ "matches", ] +[[package]] +name = "unicode-bidi-mirroring" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" + +[[package]] +name = "unicode-ccc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28ae07c514c335bbd0251147bb1de333e28ebc8f57d792014f919ed212d119f6" + +[[package]] +name = "unicode-general-category" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9af028e052a610d99e066b33304625dea9613170a2563314490a4e6ec5cf7f" + [[package]] name = "unicode-normalization" version = "0.1.17" @@ -4648,6 +4821,18 @@ dependencies = [ "tinyvec 1.1.1", ] +[[package]] +name = "unicode-script" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79bf4d5fc96546fdb73f9827097810bbda93b11a6770ff3a54e1f445d4135787" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-width" version = "0.1.8" @@ -4712,6 +4897,33 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "usvg" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49cf4a80e688e21577387cf750f0d6c18cd0dfc524ba9cf3ef7e01eae5301288" +dependencies = [ + "base64 0.13.0", + "data-url", + "flate2", + "fontdb", + "kurbo", + "log", + "memmap2", + "pico-args", + "rctree", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher 0.2.3", + "svgtypes", + "ttf-parser 0.9.0", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + [[package]] name = "utf-8" version = "0.7.5" @@ -4946,6 +5158,16 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a32b378380f4e9869b22f0b5177c68a5519f03b3454fde0b291455ddbae266c" +[[package]] +name = "wide" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c51f160ef6333906fad7d31a2010d449148dd1a26bc377e0a1ace2cc9e1e1ee" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.2.8" @@ -5096,6 +5318,18 @@ dependencies = [ "time 0.1.43", ] +[[package]] +name = "xmlparser" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/games/rstnode/Cargo.toml b/games/rstnode/Cargo.toml index 5dc3bd29c5f..c1a9f145032 100644 --- a/games/rstnode/Cargo.toml +++ b/games/rstnode/Cargo.toml @@ -7,7 +7,10 @@ members = [ "rst-server", # Utility libraries - "async-quic" + "async-quic", + + # Initial set of little engine crates + "little-assets" ] # [profile.release.overrides."*"] diff --git a/games/rstnode/rst-client/src/cli.rs b/games/rstnode/rst-client/src/cli.rs index b13697adb29..dcc40b76726 100644 --- a/games/rstnode/rst-client/src/cli.rs +++ b/games/rstnode/rst-client/src/cli.rs @@ -14,6 +14,11 @@ pub fn parse(settings: &mut GameSettings) { .version(VERSION) .author("Bread Machine (Katharina Fey { + layers: Vec>, + render: L, +} + +impl EventLayer { + pub fn new(render: L) -> Self { + Self { + layers: vec![], + render, + } + } +} + +impl EventHandler for EventLayer { + fn update(&mut self, ctx: &mut Context) -> GameResult<()> { + self.layers + .iter_mut() + .map(|l| l.update(ctx)) + .collect::>>()?; + + self.render.update(ctx)?; + Ok(()) + } + + fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { + self.render.draw(ctx)?; + Ok(()) + } + + fn mouse_button_down_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) { + self.layers + .iter_mut() + .map(|l| l.mouse_button_down_event(ctx, button, x, y)) + .collect::>(); + } + + fn mouse_button_up_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) { + self.layers + .iter_mut() + .map(|l| l.mouse_button_up_event(ctx, button, x, y)) + .collect::>(); + } + + fn mouse_motion_event(&mut self, ctx: &mut Context, x: f32, y: f32, dx: f32, dy: f32) { + self.layers + .iter_mut() + .map(|l| l.mouse_motion_event(ctx, x, y, dx, dy)) + .collect::>(); + } + + /// A keyboard button was pressed. + /// + /// The default implementation of this will call `ggez::event::quit()` + /// when the escape key is pressed. If you override this with + /// your own event handler you have to re-implment that + /// functionality yourself. + fn key_down_event( + &mut self, + ctx: &mut Context, + keycode: KeyCode, + keymods: KeyMods, + repeat: bool, + ) { + self.layers + .iter_mut() + .map(|l| l.key_down_event(ctx, keycode, keymods, repeat)) + .collect::>(); + } + + /// A keyboard button was released. + fn key_up_event(&mut self, ctx: &mut Context, keycode: KeyCode, keymods: KeyMods) { + self.layers + .iter_mut() + .map(|l| l.key_up_event(ctx, keycode, keymods)) + .collect::>(); + } + + /// A unicode character was received, usually from keyboard input. + /// This is the intended way of facilitating text input. + fn text_input_event(&mut self, ctx: &mut Context, character: char) { + self.layers + .iter_mut() + .map(|l| l.text_input_event(ctx, character)) + .collect::>(); + } +} diff --git a/games/rstnode/rst-client/src/graphics/entities/mod.rs b/games/rstnode/rst-client/src/graphics/entities/mod.rs index bb28fdd808d..32fb400f55c 100644 --- a/games/rstnode/rst-client/src/graphics/entities/mod.rs +++ b/games/rstnode/rst-client/src/graphics/entities/mod.rs @@ -27,8 +27,8 @@ impl Renderer for NodeRndr { let frame = s.assets().find("frame/frame_s").unwrap(); let icon = s.assets().find("relay/relay1").unwrap(); - let x = self.loc.0 - frame.width() as f32; - let y = self.loc.1 - frame.height() as f32; + let x = self.inner.pos.x - frame.width() as f32; + let y = self.inner.pos.y - frame.height() as f32; let color = match self.inner.owner { Owner::Player(ref p) => color::to(p.color), diff --git a/games/rstnode/rst-client/src/input.rs b/games/rstnode/rst-client/src/input.rs deleted file mode 100644 index 83ae17286d6..00000000000 --- a/games/rstnode/rst-client/src/input.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Advanced input handler - -use crate::{graphics::Vector2, viewport::Viewport}; -use ggez::{ - event::EventHandler, - input::mouse::{self, MouseButton}, - Context, GameResult, -}; - -pub struct InputHandle { - /// The mouse position on the viewport - pub mouse_pos: Vector2, - /// Whether the left mouse button is pressed this frame - pub left_pressed: bool, - /// Whether the middle mouse button is pressed this frame - pub middle_pressed: bool, - /// Whether the right mouse button is pressed this frame - pub right_pressed: bool, - /// Set when pressing left mouse and unset when releasing it - pub drag_point: Option, - /// Get the scroll-wheel position this frame - pub scroll_offset: f32, -} - -impl InputHandle { - pub fn new() -> Self { - Self { - mouse_pos: Vector2::new(0.0, 0.0), - left_pressed: false, - middle_pressed: false, - right_pressed: false, - drag_point: None, - scroll_offset: 1.0, - } - } - - /// Get the unprojected mouse coordinates - pub fn unproject(&self, vp: &Viewport) -> Vector2 { - // self.mouse_pos.clone() - vp.start().clone() - - todo!() - } -} - -impl EventHandler for InputHandle { - fn update(&mut self, ctx: &mut Context) -> GameResult<()> { - self.mouse_pos = mouse::position(&ctx).into(); - self.left_pressed = mouse::button_pressed(ctx, MouseButton::Left); - self.middle_pressed = mouse::button_pressed(ctx, MouseButton::Middle); - self.right_pressed = mouse::button_pressed(ctx, MouseButton::Right); - - // Only set the drag_point once and unset when we release Left button - if self.middle_pressed && self.drag_point.is_none() { - self.drag_point = Some(self.mouse_pos.clone()); - } else if !self.middle_pressed { - self.drag_point = None; - } - - Ok(()) - } - - fn mouse_wheel_event(&mut self, _ctx: &mut Context, _: f32, y: f32) { - self.scroll_offset -= y * 0.25; - } - - fn draw(&mut self, _: &mut Context) -> GameResult<()> { - panic!("Don't draw the input handle!"); - } -} diff --git a/games/rstnode/rst-client/src/input/arbiter.rs b/games/rstnode/rst-client/src/input/arbiter.rs new file mode 100644 index 00000000000..19aeb5321a2 --- /dev/null +++ b/games/rstnode/rst-client/src/input/arbiter.rs @@ -0,0 +1,76 @@ +use super::{InputDriver, MouseButton}; +use ggez::{ + event::{EventHandler, KeyCode, KeyMods, MouseButton as EzBtn}, + Context, GameResult, +}; + +/// Incoming event handler core component +/// +/// An input event handler component that receives events from APIs +/// and maps them onto an input subscriber collection. Events can be +/// consumed, or passed through priority trees. +pub struct InputArbiter { + map: Vec>, +} + +impl InputArbiter { + pub fn new() -> Self { + Self { map: vec![] } + } + + /// Add a new input handler subscription + pub(crate) fn add_handler(&mut self, dri: impl InputDriver + 'static) { + self.map.push(Box::new(dri)); + } +} + +/// Implement the ggez event trait for the input arbiter. These +/// function calls map onto a little-input system which maps them +/// across event handlers. An event handler is attached to a UI +/// element, which was subscribed to a partical type and scope. +impl EventHandler for InputArbiter { + fn draw(&mut self, _: &mut Context) -> GameResult<()> { + Ok(()) + } + + fn update(&mut self, _: &mut Context) -> GameResult<()> { + Ok(()) + } + + fn mouse_button_down_event(&mut self, _: &mut Context, button: EzBtn, x: f32, y: f32) { + self.map.iter_mut().for_each(|dri| { + // TODO: add drag event handling + dri.mouse_down(x, y, button.into()); + }); + } + + fn mouse_button_up_event(&mut self, _: &mut Context, button: EzBtn, x: f32, y: f32) { + self.map.iter_mut().for_each(|dri| { + dri.mouse_up(x, y, button.into()); + }); + } + + fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {} + + /// A keyboard button was pressed. + /// + /// The default implementation of this will call `ggez::event::quit()` + /// when the escape key is pressed. If you override this with + /// your own event handler you have to re-implment that + /// functionality yourself. + fn key_down_event( + &mut self, + ctx: &mut Context, + keycode: KeyCode, + _keymods: KeyMods, + _repeat: bool, + ) { + } + + /// A keyboard button was released. + fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {} + + /// A unicode character was received, usually from keyboard input. + /// This is the intended way of facilitating text input. + fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {} +} diff --git a/games/rstnode/rst-client/src/input/mod.rs b/games/rstnode/rst-client/src/input/mod.rs new file mode 100644 index 00000000000..18def89d1ec --- /dev/null +++ b/games/rstnode/rst-client/src/input/mod.rs @@ -0,0 +1,75 @@ +//! Advanced input handler + +mod arbiter; +pub use arbiter::*; +mod traits; +pub use traits::*; + + +// use crate::{graphics::Vector2, viewport::Viewport}; +// use ggez::{ +// event::EventHandler, +// input::mouse::{self, MouseButton}, +// Context, GameResult, +// }; + +// pub struct InputHandle { +// /// The mouse position on the viewport +// pub mouse_pos: Vector2, +// /// Whether the left mouse button is pressed this frame +// pub left_pressed: bool, +// /// Whether the middle mouse button is pressed this frame +// pub middle_pressed: bool, +// /// Whether the right mouse button is pressed this frame +// pub right_pressed: bool, +// /// Set when pressing left mouse and unset when releasing it +// pub drag_point: Option, +// /// Get the scroll-wheel position this frame +// pub scroll_offset: f32, +// } + +// impl InputHandle { +// pub fn new() -> Self { +// Self { +// mouse_pos: Vector2::new(0.0, 0.0), +// left_pressed: false, +// middle_pressed: false, +// right_pressed: false, +// drag_point: None, +// scroll_offset: 1.0, +// } +// } + +// /// Get the unprojected mouse coordinates +// pub fn unproject(&self, vp: &Viewport) -> Vector2 { +// // self.mouse_pos.clone() - vp.start().clone() + +// todo!() +// } +// } + +// impl EventHandler for InputHandle { +// fn update(&mut self, ctx: &mut Context) -> GameResult<()> { +// self.mouse_pos = mouse::position(&ctx).into(); +// self.left_pressed = mouse::button_pressed(ctx, MouseButton::Left); +// self.middle_pressed = mouse::button_pressed(ctx, MouseButton::Middle); +// self.right_pressed = mouse::button_pressed(ctx, MouseButton::Right); + +// // Only set the drag_point once and unset when we release Left button +// if self.middle_pressed && self.drag_point.is_none() { +// self.drag_point = Some(self.mouse_pos.clone()); +// } else if !self.middle_pressed { +// self.drag_point = None; +// } + +// Ok(()) +// } + +// fn mouse_wheel_event(&mut self, _ctx: &mut Context, _: f32, y: f32) { +// self.scroll_offset -= y * 0.25; +// } + +// fn draw(&mut self, _: &mut Context) -> GameResult<()> { +// panic!("Don't draw the input handle!"); +// } +// } diff --git a/games/rstnode/rst-client/src/input/traits.rs b/games/rstnode/rst-client/src/input/traits.rs new file mode 100644 index 00000000000..bd18a992732 --- /dev/null +++ b/games/rstnode/rst-client/src/input/traits.rs @@ -0,0 +1,42 @@ +use ggez::event::MouseButton as EzBtn; + +/// Encodes a mouse button +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum MouseButton { + /// Left mouse + Left, + /// Right mouse + Right, + /// Middle mouse (or wheel) + Middle, + /// Additional mouse key-codes + Other(u16), +} + +impl From for MouseButton { + fn from(btn: EzBtn) -> Self { + match btn { + EzBtn::Left => Self::Left, + EzBtn::Right => Self::Right, + EzBtn::Middle => Self::Middle, + EzBtn::Other(c) => Self::Other(c), + } + } +} + +/// A trait that represents an input event loop connection +/// +/// Because `little-input` can be built built against different game +/// framework backends (ggez, ...), this trait abstracts over these +/// different APIs with this trait. This trait is implemented between +/// ggez and the `little-input` event arbiter. +pub trait InputDriver { + /// Mouse button pressed events + fn mouse_down(&mut self, x: f32, y: f32, btn: MouseButton) {} + /// Mouse button released events + fn mouse_up(&mut self, x: f32, y: f32, btn: MouseButton) {} + /// Mouse wheel response + fn scroll(&mut self, f: f32) {} + /// Mouse drag events (toggled by mouse_down events) + fn mouse_drag(&mut self, x: f32, y: f32, btn: MouseButton) {} +} diff --git a/games/rstnode/rst-client/src/main.rs b/games/rstnode/rst-client/src/main.rs index 4159a37d1d4..b0acb22e26d 100644 --- a/games/rstnode/rst-client/src/main.rs +++ b/games/rstnode/rst-client/src/main.rs @@ -11,30 +11,35 @@ mod cli; mod color; mod constants; mod ctx; +mod editor; mod error; +mod event; mod graphics; mod input; mod log; mod settings; mod state; +mod ui; mod viewport; mod window; +pub(crate) use editor::*; +pub(crate) use event::*; #[allow(unused)] pub(crate) use settings::{GameSettings, GraphicsSettings, WindowSettings}; pub(crate) use state::*; #[async_std::main] async fn main() { - // Initialise logging mechanism - log::initialise(); - // Initialise default game settings let mut settings = settings::default(); // Parse commandline arguments cli::parse(&mut settings); + // Initialise logging mechanism + log::initialise(); + // Initialise window context let mut window = window::create(&settings); @@ -42,12 +47,22 @@ async fn main() { let assets = assets::load_tree(window.ctx(), &settings).unwrap_or_else(|e| fatal!("LoadError: {}!", e)); - // Create the client state - let mut state = ClientState::new(settings, assets); + // Either create client state or editor state + if settings.editor { + let state = EditorState::new(settings, assets); + + // Initialise the viewport first! + // state.viewport().init(window.ctx()); + + // Window goes brrrr + window.run(state) + } else { + let mut state = ClientState::new(settings, assets); - // Initialise the viewport first! - state.viewport().init(window.ctx()); + // Initialise the viewport first! + state.viewport().init(window.ctx()); - // Window goes brrrr - window.run(state) + // Window goes brrrr + window.run(state) + } } diff --git a/games/rstnode/rst-client/src/settings.rs b/games/rstnode/rst-client/src/settings.rs index 7fd0ba6881c..e17dacca971 100644 --- a/games/rstnode/rst-client/src/settings.rs +++ b/games/rstnode/rst-client/src/settings.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; pub fn default() -> GameSettings { GameSettings { + editor: false, assets: None, window: WindowSettings { width: 1280, @@ -20,6 +21,7 @@ pub fn default() -> GameSettings { /// Complete tree of basic game client settings pub struct GameSettings { + pub editor: bool, pub assets: Option, pub window: WindowSettings, pub graphics: GraphicsSettings, diff --git a/games/rstnode/rst-client/src/state/if_impl.rs b/games/rstnode/rst-client/src/state/if_impl.rs index 38bac369d3c..d3d33d5384f 100644 --- a/games/rstnode/rst-client/src/state/if_impl.rs +++ b/games/rstnode/rst-client/src/state/if_impl.rs @@ -12,59 +12,59 @@ use rst_core::{ }; use std::sync::Arc; -#[async_trait] -impl GameIf for ClientState { - async fn register(self: Arc, name: String, pw: String) -> Result { - todo!() - } +// #[async_trait] +// impl GameIf for ClientState { +// async fn register(self: Arc, name: String, pw: String) -> Result { +// todo!() +// } - async fn login(self: Arc, name: String, pw: String) -> Result { - todo!() - } +// async fn login(self: Arc, name: String, pw: String) -> Result { +// todo!() +// } - async fn logout(self: Arc, user: User) -> Result<(), AuthErr> { - todo!() - } +// async fn logout(self: Arc, user: User) -> Result<(), AuthErr> { +// todo!() +// } - async fn anonymous(self: Arc, name: String) -> Result { - todo!() - } +// async fn anonymous(self: Arc, name: String) -> Result { +// todo!() +// } - async fn join(self: Arc, user: User, lobby: LobbyId) -> Result { - todo!() - } +// async fn join(self: Arc, user: User, lobby: LobbyId) -> Result { +// todo!() +// } - async fn leave(self: Arc, user: User, lobby: LobbyId) -> Result<(), LobbyErr> { - todo!() - } +// async fn leave(self: Arc, user: User, lobby: LobbyId) -> Result<(), LobbyErr> { +// todo!() +// } - async fn ready( - self: Arc, - user: User, - lobby: LobbyId, - ready: bool, - ) -> Result { - todo!() - } +// async fn ready( +// self: Arc, +// user: User, +// lobby: LobbyId, +// ready: bool, +// ) -> Result { +// todo!() +// } - async fn start_req( - self: Arc, - user: UserId, - lobby: LobbyId, - ) -> Result, LobbyErr> { - todo!() - } +// async fn start_req( +// self: Arc, +// user: UserId, +// lobby: LobbyId, +// ) -> Result, LobbyErr> { +// todo!() +// } - async fn perform_action( - self: Arc, - user: User, - mtch: MatchId, - act: Action, - ) -> UpdateState { - todo!() - } +// async fn perform_action( +// self: Arc, +// user: User, +// mtch: MatchId, +// act: Action, +// ) -> UpdateState { +// todo!() +// } - async fn leave_match(self: Arc, user: User, mtch: MatchId) -> Result<(), MatchErr> { - todo!() - } -} +// async fn leave_match(self: Arc, user: User, mtch: MatchId) -> Result<(), MatchErr> { +// todo!() +// } +// } diff --git a/games/rstnode/rst-client/src/state/mod.rs b/games/rstnode/rst-client/src/state/mod.rs index cd030dcd559..d6978fa211f 100644 --- a/games/rstnode/rst-client/src/state/mod.rs +++ b/games/rstnode/rst-client/src/state/mod.rs @@ -11,13 +11,13 @@ use crate::{ entities::{Coordinates, NodeRndr}, Renderer, }, - input::InputHandle, + input::InputArbiter, viewport::Viewport, GameSettings, }; use ggez::{event::EventHandler, graphics, Context, GameResult}; use rst_core::{ - data::{Color, Level, Link, Node, Owner, Player, Position, Upgrade}, + data::{Color, Level, Link, Node, Owner, Player, Pos, Upgrade}, io::Io, }; use std::sync::Arc; @@ -25,7 +25,7 @@ use std::sync::Arc; pub struct ClientState { assets: Assets, settings: GameSettings, - input: InputHandle, + input: InputArbiter, vp: Viewport, // Game state @@ -36,6 +36,7 @@ pub struct ClientState { impl ClientState { pub fn new(settings: GameSettings, assets: Assets) -> Self { + info!("Initialising game client state"); let link = Arc::new(Link { id: 0, a: 0, @@ -49,11 +50,11 @@ impl ClientState { assets, settings, vp: Viewport::new(), - input: InputHandle::new(), + input: InputArbiter::new(), node1: NodeRndr { inner: Arc::new(Node { id: 0, - pos: Position { x: 512.0, y: 512.0 }, + pos: Pos { x: 512.0, y: 512.0 }, health: 100.into(), max_health: 100.into(), owner: Owner::Player(Player { @@ -72,7 +73,7 @@ impl ClientState { node2: NodeRndr { inner: Arc::new(Node { id: 0, - pos: Position { x: 128.0, y: 128.0 }, + pos: Pos { x: 128.0, y: 128.0 }, health: 100.into(), max_health: 100.into(), owner: Owner::Neutral, @@ -113,8 +114,8 @@ impl EventHandler for ClientState { fn mouse_wheel_event(&mut self, ctx: &mut Context, x: f32, y: f32) { self.input.mouse_wheel_event(ctx, x, y); - let zoom = self.input.scroll_offset; - self.viewport().zoom(zoom); + // let zoom = self.input.scroll_offset; + // self.viewport().zoom(zoom); } fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { diff --git a/games/rstnode/rst-client/src/viewport.rs b/games/rstnode/rst-client/src/viewport.rs index 017ba7d2a6e..c573f675b97 100644 --- a/games/rstnode/rst-client/src/viewport.rs +++ b/games/rstnode/rst-client/src/viewport.rs @@ -1,6 +1,6 @@ //! Viewport utilities -use crate::{graphics::Vector2, input::InputHandle}; +use crate::{graphics::Vector2, input::InputArbiter}; use ggez::{ error::GameResult, graphics::{self, Rect}, @@ -46,16 +46,16 @@ impl Viewport { } /// Apply changes from the input handle to the viewport - pub fn apply(&mut self, _: &mut Context, input: &InputHandle) -> GameResult<()> { + pub fn apply(&mut self, _: &mut Context, input: &InputArbiter) -> GameResult<()> { - // Move the viewport around - if input.middle_pressed { - let drag = input.drag_point.as_ref().unwrap().clone(); - let pos = input.mouse_pos.clone(); - self.start = self.prev_start + (drag - pos); - } else { - self.prev_start = self.start; - } + // // Move the viewport around + // if input.middle_pressed { + // let drag = input.drag_point.as_ref().unwrap().clone(); + // let pos = input.mouse_pos.clone(); + // self.start = self.prev_start + (drag - pos); + // } else { + // self.prev_start = self.start; + // } // Compute the scroll level Ok(()) diff --git a/games/rstnode/rst-client/src/window.rs b/games/rstnode/rst-client/src/window.rs index 3dcf375a900..23a4ffd4e95 100644 --- a/games/rstnode/rst-client/src/window.rs +++ b/games/rstnode/rst-client/src/window.rs @@ -2,7 +2,7 @@ use crate::{ctx, state::ClientState, GameSettings}; use ggez::{ - event::{self, EventLoop}, + event::{self, EventHandler, EventLoop}, Context, }; @@ -15,8 +15,8 @@ impl Window { pub fn ctx(&mut self) -> &mut Context { &mut self.ctx } - - pub fn run(self, state: ClientState) -> ! { + + pub fn run(self, state: impl EventHandler + 'static) -> ! { event::run(self.ctx, self.eloop, state) } } diff --git a/games/rstnode/rst-core/src/data.rs b/games/rstnode/rst-core/src/data.rs index 2b7a13eb637..86e5039e1c5 100644 --- a/games/rstnode/rst-core/src/data.rs +++ b/games/rstnode/rst-core/src/data.rs @@ -14,12 +14,25 @@ use std::{ pub type NodeId = usize; +/// An x/y position in the game #[derive(Serialize, Deserialize)] -pub struct Position { +pub struct Pos { pub x: f32, pub y: f32, } +impl Pos { + pub fn xy(x: f32, y: f32) -> Self { + Self { x, y } + } +} + +impl From<(f32, f32)> for Pos { + fn from((x, y): (f32, f32)) -> Self { + Self { x, y } + } +} + /// A node is a computer on the network graph /// /// It's owned by a player, and has some upgrade state, as well as @@ -29,7 +42,7 @@ pub struct Node { /// Each node has a unique ID by which it's addressed pub id: NodeId, /// The position of this node on the map - pub pos: Position, + pub pos: Pos, /// The current health pub health: AtomicU32, /// The max health