rstnode: basic event loop usage (prototype)

wip/yesman
Katharina Fey 3 years ago
parent c6e4921512
commit 3bfc345e55
Signed by: kookie
GPG Key ID: 90734A9E619C8A6C
  1. 1
      games/rstnode/Cargo.lock
  2. 2
      games/rstnode/rst-client/src/cli.rs
  3. 28
      games/rstnode/rst-client/src/editor/mod.rs
  4. 101
      games/rstnode/rst-client/src/event.rs
  5. 38
      games/rstnode/rst-client/src/main.rs
  6. 20
      games/rstnode/rst-client/src/ui/button.rs
  7. 3
      games/rstnode/rst-core/src/lib.rs
  8. 46
      games/rstnode/rst-core/src/loader.rs
  9. 18
      games/rstnode/rst-core/src/mapstore.rs
  10. 1
      games/rstnode/rst-server/Cargo.toml
  11. 8
      games/rstnode/rst-server/src/main.rs

@ -3878,6 +3878,7 @@ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
"chrono", "chrono",
"clap",
"num_cpus", "num_cpus",
"rst-core", "rst-core",
"systemstat", "systemstat",

@ -21,8 +21,8 @@ pub fn parse(settings: &mut GameSettings) {
) )
.arg( .arg(
Arg::with_name("assets") Arg::with_name("assets")
.required(true)
.takes_value(true) .takes_value(true)
.default_value("./assets/raw")
.help("Specify the path to load assets from"), .help("Specify the path to load assets from"),
) )
.arg( .arg(

@ -1,4 +1,6 @@
use crate::{assets::Assets, input::InputArbiter, ui::Button, viewport::Viewport, GameSettings}; use crate::{
assets::Assets, input::InputArbiter, ui::Button, viewport::Viewport, EventId, GameSettings,
};
use ggez::{ use ggez::{
event::{EventHandler, MouseButton}, event::{EventHandler, MouseButton},
graphics::{self, Color}, graphics::{self, Color},
@ -10,12 +12,14 @@ pub struct EditorState {
settings: GameSettings, settings: GameSettings,
input: InputArbiter, input: InputArbiter,
vp: Viewport, vp: Viewport,
btn: Button, btn: EventId,
btn2: EventId,
} }
impl EditorState { impl EditorState {
pub fn new(settings: GameSettings, assets: Assets) -> Self { pub fn new(settings: GameSettings, assets: Assets) -> Self {
info!("Initialising map editor state"); info!("Initialising map editor state");
Self { Self {
assets, assets,
settings, settings,
@ -26,7 +30,15 @@ impl EditorState {
(250.0, 125.0).into(), (250.0, 125.0).into(),
Some("Create Node".into()), Some("Create Node".into()),
Color::from_rgb(50, 50, 50), Color::from_rgb(50, 50, 50),
), )
.register(),
btn2: Button::new(
(300.0, 25.0).into(),
(250.0, 125.0).into(),
Some("Destroy Node".into()),
Color::from_rgb(50, 50, 50),
)
.register(),
} }
} }
} }
@ -36,15 +48,7 @@ impl EventHandler for EditorState {
Ok(()) Ok(())
} }
fn mouse_button_down_event(&mut self, ctx: &mut Context, btn: MouseButton, x: f32, y: f32) {
self.btn.mouse_button_down_event(ctx, btn, x, y)
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15)); Ok(())
self.btn.draw(ctx)?;
graphics::present(ctx)
} }
} }

@ -1,17 +1,73 @@
use ggez::{ use ggez::{
event::{EventHandler, KeyCode, KeyMods, MouseButton}, event::{EventHandler, KeyCode, KeyMods, MouseButton},
Context, GameResult, graphics, Context, GameResult,
}; };
use std::collections::BTreeMap;
use std::sync::{
atomic::{AtomicUsize, Ordering},
mpsc::{channel, Receiver, Sender},
};
static ID_CTR: AtomicUsize = AtomicUsize::new(0);
static mut tx: Option<Sender<HandlerDiff>> = None;
static mut rx: Option<Receiver<HandlerDiff>> = None;
#[inline(always)]
pub fn get_tx() -> Sender<HandlerDiff> {
unsafe { tx.as_ref() }.expect("Call event::setup() first!").clone()
}
/// Must absolutely call this function before using the event system!
pub fn setup() {
let (tx_, rx_) = channel();
unsafe { tx = Some(tx_) };
unsafe { rx = Some(rx_) };
}
pub struct EventLayer<L: EventHandler> { pub type EventId = usize;
layers: Vec<Box<dyn EventHandler>>,
pub fn new_id() -> EventId {
ID_CTR.fetch_add(1, Ordering::Relaxed)
}
pub type BoxedHandler = Box<dyn EventHandler + 'static>;
pub enum HandlerDiff {
Add { id: usize, inner: BoxedHandler },
Remove(usize),
}
impl HandlerDiff {
pub fn add(inner: impl EventHandler + 'static) -> (usize, Self) {
let id = new_id();
(
id,
Self::Add {
id,
inner: Box::new(inner),
},
)
}
pub fn remove(id: usize) -> Self {
Self::Remove(id)
}
}
pub struct EventLayer<L> {
layers: BTreeMap<usize, BoxedHandler>,
layer_rx: Receiver<HandlerDiff>,
render: L, render: L,
} }
impl<L: EventHandler> EventLayer<L> { impl<L: EventHandler> EventLayer<L> {
pub fn new(render: L) -> Self { pub fn new(render: L) -> Self {
let layer_rx = unsafe { rx.take().expect("Call event::setup() first!") };
Self { Self {
layers: vec![], layers: BTreeMap::new(),
layer_rx,
render, render,
} }
} }
@ -19,38 +75,59 @@ impl<L: EventHandler> EventLayer<L> {
impl<L: EventHandler> EventHandler for EventLayer<L> { impl<L: EventHandler> EventHandler for EventLayer<L> {
fn update(&mut self, ctx: &mut Context) -> GameResult<()> { fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
// Add all new layers to the update stack
while let Ok(l) = self.layer_rx.try_recv() {
match l {
HandlerDiff::Add { id, inner } => {
self.layers.insert(id, inner);
}
HandlerDiff::Remove(ref id) => {
self.layers.remove(id);
}
}
}
// Then update all the layers
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.update(ctx)) .map(|(_, l)| l.update(ctx))
.collect::<GameResult<Vec<()>>>()?; .collect::<GameResult<Vec<()>>>()?;
// Update the renderer last
self.render.update(ctx)?; self.render.update(ctx)?;
Ok(()) Ok(())
} }
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15));
self.render.draw(ctx)?; self.render.draw(ctx)?;
Ok(())
self.layers
.iter_mut()
.map(|(_, l)| l.draw(ctx))
.collect::<Vec<_>>();
graphics::present(ctx)
} }
fn mouse_button_down_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) { fn mouse_button_down_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) {
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.mouse_button_down_event(ctx, button, x, y)) .map(|(_, l)| l.mouse_button_down_event(ctx, button, x, y))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
fn mouse_button_up_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) { fn mouse_button_up_event(&mut self, ctx: &mut Context, button: MouseButton, x: f32, y: f32) {
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.mouse_button_up_event(ctx, button, x, y)) .map(|(_, l)| l.mouse_button_up_event(ctx, button, x, y))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
fn mouse_motion_event(&mut self, ctx: &mut Context, x: f32, y: f32, dx: f32, dy: f32) { fn mouse_motion_event(&mut self, ctx: &mut Context, x: f32, y: f32, dx: f32, dy: f32) {
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.mouse_motion_event(ctx, x, y, dx, dy)) .map(|(_, l)| l.mouse_motion_event(ctx, x, y, dx, dy))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
@ -69,7 +146,7 @@ impl<L: EventHandler> EventHandler for EventLayer<L> {
) { ) {
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.key_down_event(ctx, keycode, keymods, repeat)) .map(|(_, l)| l.key_down_event(ctx, keycode, keymods, repeat))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
@ -77,7 +154,7 @@ impl<L: EventHandler> EventHandler for EventLayer<L> {
fn key_up_event(&mut self, ctx: &mut Context, keycode: KeyCode, keymods: KeyMods) { fn key_up_event(&mut self, ctx: &mut Context, keycode: KeyCode, keymods: KeyMods) {
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.key_up_event(ctx, keycode, keymods)) .map(|(_, l)| l.key_up_event(ctx, keycode, keymods))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
@ -86,7 +163,7 @@ impl<L: EventHandler> EventHandler for EventLayer<L> {
fn text_input_event(&mut self, ctx: &mut Context, character: char) { fn text_input_event(&mut self, ctx: &mut Context, character: char) {
self.layers self.layers
.iter_mut() .iter_mut()
.map(|l| l.text_input_event(ctx, character)) .map(|(_, l)| l.text_input_event(ctx, character))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
} }

@ -23,9 +23,9 @@ mod ui;
mod viewport; mod viewport;
mod window; mod window;
use crate::{assets::Assets, window::Window};
pub(crate) use editor::*; pub(crate) use editor::*;
pub(crate) use event::*; pub(crate) use event::*;
#[allow(unused)]
pub(crate) use settings::{GameSettings, GraphicsSettings, WindowSettings}; pub(crate) use settings::{GameSettings, GraphicsSettings, WindowSettings};
pub(crate) use state::*; pub(crate) use state::*;
@ -41,28 +41,30 @@ async fn main() {
log::initialise(); log::initialise();
// Initialise window context // Initialise window context
let mut window = window::create(&settings); let mut win = window::create(&settings);
// Load assets tree // Load assets tree
let assets = let assets = assets::load_tree(win.ctx(), &settings)
assets::load_tree(window.ctx(), &settings).unwrap_or_else(|e| fatal!("LoadError: {}!", e)); .unwrap_or_else(|e| fatal!("Asset tree failed to load: {}!", e));
// Either create client state or editor state // Event system setup
if settings.editor { event::setup();
let state = EditorState::new(settings, assets);
// Initialise the viewport first! match settings.editor {
// state.viewport().init(window.ctx()); true => run_editor(win, settings, assets),
false => run_game(win, settings, assets),
}
}
// Window goes brrrr fn run_editor(win: Window, settings: GameSettings, assets: Assets) {
window.run(state) let state = EventLayer::new(EditorState::new(settings, assets));
} else { win.run(state);
let mut state = ClientState::new(settings, assets); }
// Initialise the viewport first! fn run_game(mut win: Window, settings: GameSettings, assets: Assets) {
state.viewport().init(window.ctx()); let mut state = ClientState::new(settings, assets);
state.viewport().init(win.ctx());
// Window goes brrrr let mut layer = EventLayer::new(state);
window.run(state) win.run(layer)
}
} }

@ -1,4 +1,4 @@
use crate::color::ColorUtils; use crate::{color::ColorUtils, get_tx, EventId, HandlerDiff};
use ggez::graphics::{self, Align, Color, DrawMode, DrawParam, Drawable, MeshBuilder, Rect, Text}; use ggez::graphics::{self, Align, Color, DrawMode, DrawParam, Drawable, MeshBuilder, Rect, Text};
use ggez::{ use ggez::{
event::{EventHandler, MouseButton}, event::{EventHandler, MouseButton},
@ -38,13 +38,16 @@ impl Button {
} }
/// Register an on-click listening closure /// Register an on-click listening closure
pub fn on_click<C: FnMut() -> () + 'static>(&mut self, btn: MouseButton, cb: C) { pub fn on_click<C: FnMut() -> () + 'static>(mut self, btn: MouseButton, cb: C) -> Self {
self.cbs.insert(btn, Box::new(cb)); self.cbs.insert(btn, Box::new(cb));
self
} }
/// Create a button with text which auto-infers its required size /// Register the button with the event handler
pub fn auto(pos: Pos, text: String, color: impl Into<Color>) -> Self { pub fn register(self) -> EventId {
todo!() let (btn_id, diff) = HandlerDiff::add(self);
get_tx().send(diff).unwrap();
btn_id
} }
fn boundry_check(&self, x: f32, y: f32) -> bool { fn boundry_check(&self, x: f32, y: f32) -> bool {
@ -70,6 +73,13 @@ impl EventHandler for Button {
} }
} }
fn mouse_button_up_event(&mut self, _ctx: &mut Context, btn: MouseButton, x: f32, y: f32) {
if self.boundry_check(x, y) {
trace!("Releasing button state");
std::mem::swap(&mut self.color_base, &mut self.color_trim);
}
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
let mut mb = MeshBuilder::new(); let mut mb = MeshBuilder::new();
let bounds = Rect { let bounds = Rect {

@ -30,16 +30,15 @@ pub use _if::GameIf;
mod _match; mod _match;
pub use _match::Match; pub use _match::Match;
pub mod loader;
pub mod config; pub mod config;
pub mod data; pub mod data;
pub mod error; pub mod error;
pub mod gens; pub mod gens;
pub mod io; pub mod io;
pub mod loader;
pub mod lobby; pub mod lobby;
pub mod mailbox; pub mod mailbox;
pub mod map; pub mod map;
pub mod mapstore;
pub mod net; pub mod net;
pub mod server; pub mod server;
pub mod stats; pub mod stats;

@ -36,31 +36,33 @@ pub struct MapLoader {
impl MapLoader { impl MapLoader {
pub fn load_path(path: PathBuf) -> Self { pub fn load_path(path: PathBuf) -> Self {
Self { info!("Loading map path: {}", path.to_str().unwrap());
root: path.clone(), let root = path.clone();
inner: fs::read_dir(&path) let inner = fs::read_dir(&path)
.unwrap() .unwrap()
.filter_map(|map| { .filter_map(|map| {
let map = map.unwrap(); let map = map.unwrap();
let name = map.file_name().into_string().unwrap(); let name = map.file_name().into_string().unwrap();
if map.path().is_dir() { if map.path().is_dir() {
warn!("Directories in map path will be ignored: {}!", name); warn!("Directories in map path will be ignored: {}!", name);
None None
} else { } else {
let np = map.path().with_extension(""); let np = map.path().with_extension("");
let name = np.file_name().unwrap().to_str().unwrap(); let name = np.file_name().unwrap().to_str().unwrap();
debug!("Loading map {}", name); debug!("Loading map {}", name);
let mut c = String::new(); let mut c = String::new();
let mut f = File::open(map.path()).unwrap(); let mut f = File::open(map.path()).unwrap();
f.read_to_string(&mut c).unwrap(); f.read_to_string(&mut c).unwrap();
Some((name.into(), serde_yaml::from_str(&c).unwrap())) Some((name.into(), serde_yaml::from_str(&c).unwrap()))
} }
}) })
.collect(), .collect();
}
info!("Loading complete!");
Self { root, inner }
} }
/// Save all maps that are present currently /// Save all maps that are present currently

@ -1,18 +0,0 @@
//! Map store
use crate::config::MapCfg;
use std::{collections::BTreeMap, fs, path::Path};
#[deprecated]
pub struct MapStore {
configs: BTreeMap<String, MapCfg>,
}
impl MapStore {
/// Load a set of map configs
pub fn load_path(&mut self, path: &Path) {
fs::read_dir(&path).unwrap().for_each(|d| {
let name = d.unwrap().file_name().into_string().unwrap();
});
}
}

@ -11,6 +11,7 @@ rst-core = { path = "../rst-core" }
async-std = { version = "1.0", features = ["unstable", "attributes"] } async-std = { version = "1.0", features = ["unstable", "attributes"] }
async-trait = "0.1" async-trait = "0.1"
clap = "2.0"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = "0.2" tracing-subscriber = "0.2"

@ -6,16 +6,20 @@
#[macro_use] #[macro_use]
extern crate tracing; extern crate tracing;
pub(crate) mod loader; pub(crate) mod cli;
pub(crate) mod constants; pub(crate) mod constants;
pub(crate) mod loader;
pub(crate) mod log; pub(crate) mod log;
use rst_core::net::Endpoint; use rst_core::{loader::MapLoader, net::Endpoint};
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
log::initialise(); log::initialise();
let map_path = cli::parse();
let maps = MapLoader::load_path(map_path);
let addr = format!("{}:{}", constants::DEFAULT_BIND, constants::DEFAULT_PORT); let addr = format!("{}:{}", constants::DEFAULT_BIND, constants::DEFAULT_PORT);
let serv = Endpoint::new(addr.as_str()).await; let serv = Endpoint::new(addr.as_str()).await;
// serv.listen().await; // serv.listen().await;

Loading…
Cancel
Save