aboutsummaryrefslogtreecommitdiff
path: root/games
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2021-02-21 21:13:56 +0100
committerKatharina Fey <kookie@spacekookie.de>2021-02-21 21:13:56 +0100
commit657fc50a071f8bb93a96b286c408dda105e9b580 (patch)
treeab5df68d5ff63aeff8423315f372ff65702c2032 /games
parent4aa0222a1fb78aa66e6efd1179a1901d728dbfb8 (diff)
rstnode: implement central event handling and handler layering
Diffstat (limited to 'games')
-rw-r--r--games/rstnode/Cargo.lock238
-rw-r--r--games/rstnode/Cargo.toml5
-rw-r--r--games/rstnode/rst-client/src/cli.rs7
-rw-r--r--games/rstnode/rst-client/src/editor/mod.rs6
-rw-r--r--games/rstnode/rst-client/src/event.rs92
-rw-r--r--games/rstnode/rst-client/src/graphics/entities/mod.rs4
-rw-r--r--games/rstnode/rst-client/src/input.rs69
-rw-r--r--games/rstnode/rst-client/src/input/arbiter.rs76
-rw-r--r--games/rstnode/rst-client/src/input/mod.rs75
-rw-r--r--games/rstnode/rst-client/src/input/traits.rs42
-rw-r--r--games/rstnode/rst-client/src/main.rs33
-rw-r--r--games/rstnode/rst-client/src/settings.rs2
-rw-r--r--games/rstnode/rst-client/src/state/if_impl.rs94
-rw-r--r--games/rstnode/rst-client/src/state/mod.rs17
-rw-r--r--games/rstnode/rst-client/src/viewport.rs20
-rw-r--r--games/rstnode/rst-client/src/window.rs6
-rw-r--r--games/rstnode/rst-core/src/data.rs17
17 files changed, 647 insertions, 156 deletions
diff --git a/games/rstnode/Cargo.lock b/games/rstnode/Cargo.lock
index 0247eaf0006f..33713c4b0971 100644
--- a/games/rstnode/Cargo.lock
+++ b/games/rstnode/Cargo.lock
@@ -1374,6 +1374,24 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1389,6 +1407,17 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2149,6 +2178,15 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2253,7 +2291,7 @@ dependencies = [
"cssparser",
"data-url",
"encoding",
- "float-cmp",
+ "float-cmp 0.8.0",
"gdk-pixbuf",
"gdk-pixbuf-sys",
"gio",
@@ -2301,6 +2339,13 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3197,10 +3242,16 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3711,6 +3762,22 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3754,6 +3821,15 @@ dependencies = [
]
[[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"
dependencies = [
@@ -3896,12 +3972,37 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4074,6 +4175,21 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4287,6 +4403,26 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4487,6 +4623,19 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4609,6 +4758,12 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3e7994fc4aed0ee366a4b0d01562c8a7cd5a5017088bceb6921b0c8c538f34e"
@@ -4640,6 +4795,24 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4649,6 +4822,18 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4713,6 +4898,33 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4947,6 +5159,16 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5097,6 +5319,18 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/games/rstnode/Cargo.toml b/games/rstnode/Cargo.toml
index 5dc3bd29c5f5..c1a9f145032c 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 b13697adb29a..dcc40b76726b 100644
--- a/games/rstnode/rst-client/src/cli.rs
+++ b/games/rstnode/rst-client/src/cli.rs
@@ -15,6 +15,11 @@ pub fn parse(settings: &mut GameSettings) {
.author("Bread Machine (Katharina Fey <kookie@spacekookie.de)")
.about("Main game client - consider running the game via the launcher instead")
.arg(
+ Arg::with_name("editor")
+ .help("Instead of running the main game screen, run the map editor instead")
+ .long("editor"),
+ )
+ .arg(
Arg::with_name("assets")
.required(true)
.takes_value(true)
@@ -54,4 +59,6 @@ pub fn parse(settings: &mut GameSettings) {
if matches.is_present("fullscreen") {
settings.window.window_mode = WindowMode::Fullscreen;
}
+
+ settings.editor = matches.is_present("editor");
}
diff --git a/games/rstnode/rst-client/src/editor/mod.rs b/games/rstnode/rst-client/src/editor/mod.rs
index ba7867017535..969ac27088ae 100644
--- a/games/rstnode/rst-client/src/editor/mod.rs
+++ b/games/rstnode/rst-client/src/editor/mod.rs
@@ -1,4 +1,4 @@
-use crate::{assets::Assets, input::InputHandle, ui::Button, viewport::Viewport, GameSettings};
+use crate::{assets::Assets, input::InputArbiter, ui::Button, viewport::Viewport, GameSettings};
use ggez::{
event::{EventHandler, MouseButton},
graphics::{self, Color},
@@ -8,7 +8,7 @@ use ggez::{
pub struct EditorState {
assets: Assets,
settings: GameSettings,
- input: InputHandle,
+ input: InputArbiter,
vp: Viewport,
btn: Button,
}
@@ -20,7 +20,7 @@ impl EditorState {
assets,
settings,
vp: Viewport::new(),
- input: InputHandle::new(),
+ input: InputArbiter::new(),
btn: Button::new(
(25.0, 25.0).into(),
(250.0, 125.0).into(),
diff --git a/games/rstnode/rst-client/src/event.rs b/games/rstnode/rst-client/src/event.rs
new file mode 100644
index 000000000000..54388bb8c438
--- /dev/null
+++ b/games/rstnode/rst-client/src/event.rs
@@ -0,0 +1,92 @@
+use ggez::{
+ event::{EventHandler, KeyCode, KeyMods, MouseButton},
+ Context, GameResult,
+};
+
+pub struct EventLayer<L: EventHandler> {
+ layers: Vec<Box<dyn EventHandler>>,
+ render: L,
+}
+
+impl<L: EventHandler> EventLayer<L> {
+ pub fn new(render: L) -> Self {
+ Self {
+ layers: vec![],
+ render,
+ }
+ }
+}
+
+impl<L: EventHandler> EventHandler for EventLayer<L> {
+ fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
+ self.layers
+ .iter_mut()
+ .map(|l| l.update(ctx))
+ .collect::<GameResult<Vec<()>>>()?;
+
+ 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::<Vec<_>>();
+ }
+
+ 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::<Vec<_>>();
+ }
+
+ 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::<Vec<_>>();
+ }
+
+ /// 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::<Vec<_>>();
+ }
+
+ /// 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::<Vec<_>>();
+ }
+
+ /// 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::<Vec<_>>();
+ }
+}
diff --git a/games/rstnode/rst-client/src/graphics/entities/mod.rs b/games/rstnode/rst-client/src/graphics/entities/mod.rs
index bb28fdd808d0..32fb400f55c9 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 83ae17286d61..000000000000
--- 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<Vector2>,
- /// 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 000000000000..19aeb5321a22
--- /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<Box<dyn InputDriver>>,
+}
+
+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 000000000000..18def89d1ec6
--- /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<Vector2>,
+// /// 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 000000000000..bd18a9927320
--- /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<EzBtn> 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 4159a37d1d4a..b0acb22e26d2 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 7fd0ba6881c1..e17dacca9716 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<PathBuf>,
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 38bac369d3cc..d3d33d5384f8 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<Self>, name: String, pw: String) -> Result<UserId, RegErr> {
- todo!()
- }
+// #[async_trait]
+// impl GameIf for ClientState {
+// async fn register(self: Arc<Self>, name: String, pw: String) -> Result<UserId, RegErr> {
+// todo!()
+// }
- async fn login(self: Arc<Self>, name: String, pw: String) -> Result<User, AuthErr> {
- todo!()
- }
+// async fn login(self: Arc<Self>, name: String, pw: String) -> Result<User, AuthErr> {
+// todo!()
+// }
- async fn logout(self: Arc<Self>, user: User) -> Result<(), AuthErr> {
- todo!()
- }
+// async fn logout(self: Arc<Self>, user: User) -> Result<(), AuthErr> {
+// todo!()
+// }
- async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> {
- todo!()
- }
+// async fn anonymous(self: Arc<Self>, name: String) -> Result<User, AuthErr> {
+// todo!()
+// }
- async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> {
- todo!()
- }
+// async fn join(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<Lobby, LobbyErr> {
+// todo!()
+// }
- async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> {
- todo!()
- }
+// async fn leave(self: Arc<Self>, user: User, lobby: LobbyId) -> Result<(), LobbyErr> {
+// todo!()
+// }
- async fn ready(
- self: Arc<Self>,
- user: User,
- lobby: LobbyId,
- ready: bool,
- ) -> Result<LobbyUpdate, LobbyErr> {
- todo!()
- }
+// async fn ready(
+// self: Arc<Self>,
+// user: User,
+// lobby: LobbyId,
+// ready: bool,
+// ) -> Result<LobbyUpdate, LobbyErr> {
+// todo!()
+// }
- async fn start_req(
- self: Arc<Self>,
- user: UserId,
- lobby: LobbyId,
- ) -> Result<DateTime<Utc>, LobbyErr> {
- todo!()
- }
+// async fn start_req(
+// self: Arc<Self>,
+// user: UserId,
+// lobby: LobbyId,
+// ) -> Result<DateTime<Utc>, LobbyErr> {
+// todo!()
+// }
- async fn perform_action(
- self: Arc<Self>,
- user: User,
- mtch: MatchId,
- act: Action,
- ) -> UpdateState {
- todo!()
- }
+// async fn perform_action(
+// self: Arc<Self>,
+// user: User,
+// mtch: MatchId,
+// act: Action,
+// ) -> UpdateState {
+// todo!()
+// }
- async fn leave_match(self: Arc<Self>, user: User, mtch: MatchId) -> Result<(), MatchErr> {
- todo!()
- }
-}
+// async fn leave_match(self: Arc<Self>, 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 cd030dcd5595..d6978fa211f8 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 017ba7d2a6e1..c573f675b975 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 3dcf375a9009..23a4ffd4e95f 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 2b7a13eb6377..86e5039e1c5d 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