rstnode: implement central event handling and handler layering

wip/yesman
Katharina Fey 3 years ago
parent 4aa0222a1f
commit 657fc50a07
Signed by: kookie
GPG Key ID: 90734A9E619C8A6C
  1. 238
      games/rstnode/Cargo.lock
  2. 5
      games/rstnode/Cargo.toml
  3. 7
      games/rstnode/rst-client/src/cli.rs
  4. 6
      games/rstnode/rst-client/src/editor/mod.rs
  5. 92
      games/rstnode/rst-client/src/event.rs
  6. 4
      games/rstnode/rst-client/src/graphics/entities/mod.rs
  7. 69
      games/rstnode/rst-client/src/input.rs
  8. 76
      games/rstnode/rst-client/src/input/arbiter.rs
  9. 75
      games/rstnode/rst-client/src/input/mod.rs
  10. 42
      games/rstnode/rst-client/src/input/traits.rs
  11. 33
      games/rstnode/rst-client/src/main.rs
  12. 2
      games/rstnode/rst-client/src/settings.rs
  13. 94
      games/rstnode/rst-client/src/state/if_impl.rs
  14. 17
      games/rstnode/rst-client/src/state/mod.rs
  15. 20
      games/rstnode/rst-client/src/viewport.rs
  16. 6
      games/rstnode/rst-client/src/window.rs
  17. 17
      games/rstnode/rst-core/src/data.rs

@ -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"

@ -7,7 +7,10 @@ members = [
"rst-server",
# Utility libraries
"async-quic"
"async-quic",
# Initial set of little engine crates
"little-assets"
]
# [profile.release.overrides."*"]

@ -14,6 +14,11 @@ pub fn parse(settings: &mut GameSettings) {
.version(VERSION)
.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)
@ -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");
}

@ -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(),

@ -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<_>>();
}
}

@ -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),

@ -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!");
}
}

@ -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) {}
}

@ -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!");
// }
// }

@ -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) {}
}

@ -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)
}
}

@ -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,

@ -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!()
// }
// }

@ -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<()> {

@ -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(())

@ -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)
}
}

@ -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

Loading…
Cancel
Save