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-trait",
"chrono",
"clap",
"num_cpus",
"rst-core",
"systemstat",

@ -21,8 +21,8 @@ pub fn parse(settings: &mut GameSettings) {
)
.arg(
Arg::with_name("assets")
.required(true)
.takes_value(true)
.default_value("./assets/raw")
.help("Specify the path to load assets from"),
)
.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::{
event::{EventHandler, MouseButton},
graphics::{self, Color},
@ -10,12 +12,14 @@ pub struct EditorState {
settings: GameSettings,
input: InputArbiter,
vp: Viewport,
btn: Button,
btn: EventId,
btn2: EventId,
}
impl EditorState {
pub fn new(settings: GameSettings, assets: Assets) -> Self {
info!("Initialising map editor state");
Self {
assets,
settings,
@ -26,7 +30,15 @@ impl EditorState {
(250.0, 125.0).into(),
Some("Create Node".into()),
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(())
}
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<()> {
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15));
self.btn.draw(ctx)?;
graphics::present(ctx)
Ok(())
}
}

@ -1,17 +1,73 @@
use ggez::{
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> {
layers: Vec<Box<dyn EventHandler>>,
pub type EventId = usize;
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,
}
impl<L: EventHandler> EventLayer<L> {
pub fn new(render: L) -> Self {
let layer_rx = unsafe { rx.take().expect("Call event::setup() first!") };
Self {
layers: vec![],
layers: BTreeMap::new(),
layer_rx,
render,
}
}
@ -19,38 +75,59 @@ impl<L: EventHandler> EventLayer<L> {
impl<L: EventHandler> EventHandler for EventLayer<L> {
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
.iter_mut()
.map(|l| l.update(ctx))
.map(|(_, l)| l.update(ctx))
.collect::<GameResult<Vec<()>>>()?;
// Update the renderer last
self.render.update(ctx)?;
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15));
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) {
self.layers
.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<_>>();
}
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))
.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))
.map(|(_, l)| l.mouse_motion_event(ctx, x, y, dx, dy))
.collect::<Vec<_>>();
}
@ -69,7 +146,7 @@ impl<L: EventHandler> EventHandler for EventLayer<L> {
) {
self.layers
.iter_mut()
.map(|l| l.key_down_event(ctx, keycode, keymods, repeat))
.map(|(_, l)| l.key_down_event(ctx, keycode, keymods, repeat))
.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) {
self.layers
.iter_mut()
.map(|l| l.key_up_event(ctx, keycode, keymods))
.map(|(_, l)| l.key_up_event(ctx, keycode, keymods))
.collect::<Vec<_>>();
}
@ -86,7 +163,7 @@ impl<L: EventHandler> EventHandler for EventLayer<L> {
fn text_input_event(&mut self, ctx: &mut Context, character: char) {
self.layers
.iter_mut()
.map(|l| l.text_input_event(ctx, character))
.map(|(_, l)| l.text_input_event(ctx, character))
.collect::<Vec<_>>();
}
}

@ -23,9 +23,9 @@ mod ui;
mod viewport;
mod window;
use crate::{assets::Assets, window::Window};
pub(crate) use editor::*;
pub(crate) use event::*;
#[allow(unused)]
pub(crate) use settings::{GameSettings, GraphicsSettings, WindowSettings};
pub(crate) use state::*;
@ -41,28 +41,30 @@ async fn main() {
log::initialise();
// Initialise window context
let mut window = window::create(&settings);
let mut win = window::create(&settings);
// Load assets tree
let assets =
assets::load_tree(window.ctx(), &settings).unwrap_or_else(|e| fatal!("LoadError: {}!", e));
let assets = assets::load_tree(win.ctx(), &settings)
.unwrap_or_else(|e| fatal!("Asset tree failed to load: {}!", e));
// Either create client state or editor state
if settings.editor {
let state = EditorState::new(settings, assets);
// Event system setup
event::setup();
// Initialise the viewport first!
// state.viewport().init(window.ctx());
match settings.editor {
true => run_editor(win, settings, assets),
false => run_game(win, settings, assets),
}
}
// Window goes brrrr
window.run(state)
} else {
let mut state = ClientState::new(settings, assets);
fn run_editor(win: Window, settings: GameSettings, assets: Assets) {
let state = EventLayer::new(EditorState::new(settings, assets));
win.run(state);
}
// Initialise the viewport first!
state.viewport().init(window.ctx());
fn run_game(mut win: Window, settings: GameSettings, assets: Assets) {
let mut state = ClientState::new(settings, assets);
state.viewport().init(win.ctx());
// Window goes brrrr
window.run(state)
}
let mut layer = EventLayer::new(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::{
event::{EventHandler, MouseButton},
@ -38,13 +38,16 @@ impl Button {
}
/// 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
}
/// Create a button with text which auto-infers its required size
pub fn auto(pos: Pos, text: String, color: impl Into<Color>) -> Self {
todo!()
/// Register the button with the event handler
pub fn register(self) -> EventId {
let (btn_id, diff) = HandlerDiff::add(self);
get_tx().send(diff).unwrap();
btn_id
}
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<()> {
let mut mb = MeshBuilder::new();
let bounds = Rect {

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

@ -36,31 +36,33 @@ pub struct MapLoader {
impl MapLoader {
pub fn load_path(path: PathBuf) -> Self {
Self {
root: path.clone(),
inner: fs::read_dir(&path)
.unwrap()
.filter_map(|map| {
let map = map.unwrap();
let name = map.file_name().into_string().unwrap();
info!("Loading map path: {}", path.to_str().unwrap());
let root = path.clone();
let inner = fs::read_dir(&path)
.unwrap()
.filter_map(|map| {
let map = map.unwrap();
let name = map.file_name().into_string().unwrap();
if map.path().is_dir() {
warn!("Directories in map path will be ignored: {}!", name);
None
} else {
let np = map.path().with_extension("");
let name = np.file_name().unwrap().to_str().unwrap();
if map.path().is_dir() {
warn!("Directories in map path will be ignored: {}!", name);
None
} else {
let np = map.path().with_extension("");
let name = np.file_name().unwrap().to_str().unwrap();
debug!("Loading map {}", name);
let mut c = String::new();
let mut f = File::open(map.path()).unwrap();
f.read_to_string(&mut c).unwrap();
debug!("Loading map {}", name);
let mut c = String::new();
let mut f = File::open(map.path()).unwrap();
f.read_to_string(&mut c).unwrap();
Some((name.into(), serde_yaml::from_str(&c).unwrap()))
}
})
.collect(),
}
Some((name.into(), serde_yaml::from_str(&c).unwrap()))
}
})
.collect();
info!("Loading complete!");
Self { root, inner }
}
/// 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-trait = "0.1"
clap = "2.0"
chrono = { version = "0.4", features = ["serde"] }
tracing = "0.1"
tracing-subscriber = "0.2"

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

Loading…
Cancel
Save