aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2021-02-07 16:44:44 +0100
committerKatharina Fey <kookie@spacekookie.de>2021-02-07 16:44:44 +0100
commit79c8b9ab441493e3b3a37a59263f66896c9c90b3 (patch)
treeca111686fa202369a5730ff8151480b04e391cbb
parentf5b36ff6b99256030201c878608a07d163b4c802 (diff)
rstnode: basic asset loading and prototype sprite rendering
* restructure assets directory * implement asset loading and dynamic conversion to sprites * reload sprites with unique URIs to load at runtime * provide an updated renderer API to give access to client state * use new APIs to draw a single node frame on screen * use colour APIs to dynamically change node frame colour
-rw-r--r--games/rstnode/Cargo.lock92
-rw-r--r--games/rstnode/assets/raw/frame/frame_l.pngbin0 -> 11582 bytes
-rw-r--r--games/rstnode/assets/raw/frame/frame_l.svg (renamed from games/rstnode/assets/raw/frame_l.svg)0
-rw-r--r--games/rstnode/assets/raw/frame/frame_m.pngbin0 -> 9175 bytes
-rw-r--r--games/rstnode/assets/raw/frame/frame_m.svg (renamed from games/rstnode/assets/raw/frame_m.svg)0
-rw-r--r--games/rstnode/assets/raw/frame/frame_s.pngbin0 -> 8749 bytes
-rw-r--r--games/rstnode/assets/raw/frame/frame_s.svg (renamed from games/rstnode/assets/raw/frame_s.svg)0
-rw-r--r--games/rstnode/assets/raw/frame/frame_xl.pngbin0 -> 13187 bytes
-rw-r--r--games/rstnode/assets/raw/frame/frame_xl.svg (renamed from games/rstnode/assets/raw/frame_xl.svg)0
-rw-r--r--games/rstnode/assets/raw/relay/relay1.pngbin0 -> 4632 bytes
-rw-r--r--games/rstnode/assets/raw/relay/relay1.svg (renamed from games/rstnode/assets/raw/relay1.svg)0
-rw-r--r--games/rstnode/rst-client/Cargo.toml11
-rw-r--r--games/rstnode/rst-client/src/assets.rs138
-rw-r--r--games/rstnode/rst-client/src/cli.rs56
-rw-r--r--games/rstnode/rst-client/src/error.rs24
-rw-r--r--games/rstnode/rst-client/src/graphics/entities/mod.rs18
-rw-r--r--games/rstnode/rst-client/src/graphics/mod.rs18
-rw-r--r--games/rstnode/rst-client/src/log.rs43
-rw-r--r--games/rstnode/rst-client/src/main.rs25
-rw-r--r--games/rstnode/rst-client/src/settings.rs7
-rw-r--r--games/rstnode/rst-client/src/state.rs20
-rw-r--r--games/rstnode/rst-client/src/window.rs24
22 files changed, 451 insertions, 25 deletions
diff --git a/games/rstnode/Cargo.lock b/games/rstnode/Cargo.lock
index 60e7e3d404b2..81e017cbd207 100644
--- a/games/rstnode/Cargo.lock
+++ b/games/rstnode/Cargo.lock
@@ -97,6 +97,15 @@ dependencies = [
]
[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
name = "approx"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -515,7 +524,7 @@ version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
- "ansi_term",
+ "ansi_term 0.11.0",
"atty",
"bitflags",
"strsim 0.8.0",
@@ -2363,6 +2372,15 @@ dependencies = [
]
[[package]]
+name = "matchers"
+version = "0.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
name = "matches"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3549,6 +3567,16 @@ dependencies = [
]
[[package]]
+name = "regex-automata"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
+dependencies = [
+ "byteorder",
+ "regex-syntax",
+]
+
+[[package]]
name = "regex-syntax"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3638,6 +3666,10 @@ dependencies = [
"librsvg",
"mint",
"rst-core",
+ "svg",
+ "tempfile",
+ "tracing",
+ "tracing-subscriber",
]
[[package]]
@@ -3847,6 +3879,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]]
+name = "sharded-slab"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
name = "shared_library"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4091,6 +4132,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]]
+name = "svg"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcbef9cf3cf75dd7772fb1f40dd6d90278a5263454db94ee399500ee9918aaa7"
+
+[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4330,6 +4377,49 @@ dependencies = [
]
[[package]]
+name = "tracing-log"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9"
+dependencies = [
+ "lazy_static",
+ "log",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-serde"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
+dependencies = [
+ "serde",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1fa8f0c8f4c594e4fc9debc1990deab13238077271ba84dd853d54902ee3401"
+dependencies = [
+ "ansi_term 0.12.1",
+ "chrono",
+ "lazy_static",
+ "matchers",
+ "regex",
+ "serde",
+ "serde_json",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+ "tracing-serde",
+]
+
+[[package]]
name = "ttf-parser"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/games/rstnode/assets/raw/frame/frame_l.png b/games/rstnode/assets/raw/frame/frame_l.png
new file mode 100644
index 000000000000..f37386dca351
--- /dev/null
+++ b/games/rstnode/assets/raw/frame/frame_l.png
Binary files differ
diff --git a/games/rstnode/assets/raw/frame_l.svg b/games/rstnode/assets/raw/frame/frame_l.svg
index bb1b26ddb95e..bb1b26ddb95e 100644
--- a/games/rstnode/assets/raw/frame_l.svg
+++ b/games/rstnode/assets/raw/frame/frame_l.svg
diff --git a/games/rstnode/assets/raw/frame/frame_m.png b/games/rstnode/assets/raw/frame/frame_m.png
new file mode 100644
index 000000000000..02afae96ac20
--- /dev/null
+++ b/games/rstnode/assets/raw/frame/frame_m.png
Binary files differ
diff --git a/games/rstnode/assets/raw/frame_m.svg b/games/rstnode/assets/raw/frame/frame_m.svg
index 3938a558997c..3938a558997c 100644
--- a/games/rstnode/assets/raw/frame_m.svg
+++ b/games/rstnode/assets/raw/frame/frame_m.svg
diff --git a/games/rstnode/assets/raw/frame/frame_s.png b/games/rstnode/assets/raw/frame/frame_s.png
new file mode 100644
index 000000000000..6fc0133acbcb
--- /dev/null
+++ b/games/rstnode/assets/raw/frame/frame_s.png
Binary files differ
diff --git a/games/rstnode/assets/raw/frame_s.svg b/games/rstnode/assets/raw/frame/frame_s.svg
index 0a9a51c4464d..0a9a51c4464d 100644
--- a/games/rstnode/assets/raw/frame_s.svg
+++ b/games/rstnode/assets/raw/frame/frame_s.svg
diff --git a/games/rstnode/assets/raw/frame/frame_xl.png b/games/rstnode/assets/raw/frame/frame_xl.png
new file mode 100644
index 000000000000..6ec3a513d05d
--- /dev/null
+++ b/games/rstnode/assets/raw/frame/frame_xl.png
Binary files differ
diff --git a/games/rstnode/assets/raw/frame_xl.svg b/games/rstnode/assets/raw/frame/frame_xl.svg
index cfc7a3df2277..cfc7a3df2277 100644
--- a/games/rstnode/assets/raw/frame_xl.svg
+++ b/games/rstnode/assets/raw/frame/frame_xl.svg
diff --git a/games/rstnode/assets/raw/relay/relay1.png b/games/rstnode/assets/raw/relay/relay1.png
new file mode 100644
index 000000000000..0c66135130f4
--- /dev/null
+++ b/games/rstnode/assets/raw/relay/relay1.png
Binary files differ
diff --git a/games/rstnode/assets/raw/relay1.svg b/games/rstnode/assets/raw/relay/relay1.svg
index c8809bf08123..c8809bf08123 100644
--- a/games/rstnode/assets/raw/relay1.svg
+++ b/games/rstnode/assets/raw/relay/relay1.svg
diff --git a/games/rstnode/rst-client/Cargo.toml b/games/rstnode/rst-client/Cargo.toml
index 929f7550bbef..7b5155f8108c 100644
--- a/games/rstnode/rst-client/Cargo.toml
+++ b/games/rstnode/rst-client/Cargo.toml
@@ -9,8 +9,13 @@ authors = ["Bread Machine", "Katharina Fey <kookie@spacekookie.de>"]
[dependencies]
rst-core = { path = "../rst-core" }
-clap = "2.0"
+cairo-rs = { version="0.8.0", features=["v1_16", "png", "svg"] }
+librsvg = { git = "https://gitlab.gnome.org/GNOME/librsvg.git", rev = "d34f570f" }
ggez = "0.6.0-rc0"
mint = "0.5" # Required because ggez is trash
-librsvg = { git = "https://gitlab.gnome.org/GNOME/librsvg.git", rev = "d34f570f" }
-cairo-rs = { version="0.8.0", features=["v1_16", "png", "svg"] } \ No newline at end of file
+svg = "0.9"
+
+clap = "2.0"
+tracing = "0.1"
+tracing-subscriber = "0.2"
+tempfile = "*" \ No newline at end of file
diff --git a/games/rstnode/rst-client/src/assets.rs b/games/rstnode/rst-client/src/assets.rs
index 7e368b8d4c16..d1ccdaf875ed 100644
--- a/games/rstnode/rst-client/src/assets.rs
+++ b/games/rstnode/rst-client/src/assets.rs
@@ -1,5 +1,19 @@
+use crate::{error::LoadError, GameSettings};
+use cairo::{Context, Format, ImageSurface, Rectangle};
use ggez::graphics::Image;
-use std::{collections::BTreeMap, path::Path};
+use librsvg::{CairoRenderer, Loader};
+use std::{
+ collections::BTreeMap,
+ error::Error,
+ ffi::OsStr,
+ fs::{read_dir, File},
+ io::BufWriter,
+ io::Read,
+ path::{Path, PathBuf},
+};
+use tempfile::tempdir;
+
+pub type Result<T> = std::result::Result<T, LoadError>;
/// Construct a `node` prefixed URI
pub fn node(tt: &str) -> URI {
@@ -24,21 +38,137 @@ impl From<String> for URI {
}
/// Asset loader
+#[derive(Debug)]
pub struct Assets {
inner: BTreeMap<URI, Image>,
}
impl Assets {
- pub fn load(p: &Path) -> Self {
+ fn new() -> Self {
Self {
inner: Default::default(),
}
}
+
+ pub fn find<U: Into<URI>>(&self, u: U) -> Option<Image> {
+ self.inner.get(&u.into()).map(|i| i.clone())
+ }
+
+ /// Load an asset directory path
+ fn load_tree(&mut self, ctx: &mut ggez::Context, tmpdir: &Path, p: &Path) -> Result<()> {
+ let err: LoadError = p.to_str().unwrap().into();
+
+ read_dir(p)
+ .map_err(|_| err)?
+ .map(|e| {
+ let e = e.unwrap();
+ let p = e.path();
+
+ let ext = OsStr::new("svg");
+
+ if p.is_dir() {
+ debug!(
+ "Entering directory {}",
+ p.file_name().unwrap().to_str().unwrap()
+ );
+ self.load_tree(ctx, tmpdir, p.as_path())?;
+ } else if p.extension() == Some(ext) {
+ let png = load_svg(tmpdir, p.as_path())?;
+
+ let basepath = p.with_extension("");
+
+ let uri_cat = p.parent().unwrap().file_name().unwrap().to_str().unwrap();
+ let name = basepath.file_name().unwrap().to_str().unwrap();
+ let uri = format!("{}/{}", uri_cat, name);
+ let path_str = png.as_path().to_str().unwrap();
+
+ let mut content = vec![];
+ let mut f = File::open(png.as_path()).map_err(|_| {
+ LoadError::from(format!("No such file: {}", path_str).as_str())
+ })?;
+
+ f.read_to_end(&mut content).map_err(|e| {
+ LoadError::from(
+ format!("Read error for {}: {}", path_str, e.to_string()).as_str(),
+ )
+ })?;
+
+ self.inner.insert(
+ uri.into(),
+ Image::from_bytes(ctx, content.as_slice()).map_err(|e| {
+ LoadError::from(
+ format!("Read error for {}: {}", path_str, e.to_string()).as_str(),
+ )
+ })?,
+ );
+ }
+
+ Ok(())
+ })
+ .fold(Ok(()), |acc, res| match (acc, res) {
+ (Ok(_), Ok(_)) => Ok(()),
+ (Ok(_), Err(e)) => Err(e),
+ (Err(e), _) => Err(e),
+ })
+ }
}
+/// Load all game assets into the game
+///
+/// This function performs three main steps.
+///
+/// 1. Check that the provided path is a directory
+/// 2. Recursively load Directories and files and call
+/// [`load_svg`](self::load_svg) on each `.svg` file
+/// 3. Re-load newly converted assets into [`Assets`](self::Assets)
+pub fn load_tree(ctx: &mut ggez::Context, settings: &GameSettings) -> Result<Assets> {
+ let path = match settings.assets.clone() {
+ Some(s) => Ok(s),
+ None => Err(LoadError::from("No assets path set!")),
+ }?;
+
+ debug!(
+ "Starting assets loading harness on {}",
+ path.to_str().unwrap()
+ );
+
+ let tmpdir = tempdir().unwrap();
+ let mut assets = Assets::new();
+ assets.load_tree(ctx, tmpdir.path(), path.as_path())?;
+ info!("Asset loading complete!");
+ Ok(assets)
+}
/// A utility function to take an SVG and render it to a raster image
/// according to a render spec
-fn load_svg(p: &Path) -> () {
-
+pub fn load_svg(tmpdir: &Path, p: &Path) -> Result<PathBuf> {
+ let err: LoadError = p.to_str().unwrap().into();
+
+ let handle = Loader::new().read_path(p).map_err(|_| err.clone())?;
+ let renderer = CairoRenderer::new(&handle);
+
+ let surf = ImageSurface::create(Format::ARgb32, 256, 256).map_err(|_| err.clone())?;
+ let cr = Context::new(&surf);
+
+ renderer
+ .render_document(
+ &cr,
+ &Rectangle {
+ x: 0.0,
+ y: 0.0,
+ width: 256.0,
+ height: 256.0,
+ },
+ )
+ .map_err(|_| err.clone())?;
+
+ let png = p.with_extension("png");
+ let name = png
+ .file_name()
+ .map_or_else(|| Err(err.clone()), |name| Ok(name))?;
+
+ let out = tmpdir.join(name.clone());
+ let mut file = BufWriter::new(File::create(out.clone()).map_err(|_| err.clone())?);
+ surf.write_to_png(&mut file).map_err(|_| err.clone())?;
+ Ok(out.to_path_buf())
}
diff --git a/games/rstnode/rst-client/src/cli.rs b/games/rstnode/rst-client/src/cli.rs
index b8a93b237a7b..b13697adb29a 100644
--- a/games/rstnode/rst-client/src/cli.rs
+++ b/games/rstnode/rst-client/src/cli.rs
@@ -1 +1,57 @@
//! Handle user CLI inputs
+
+use crate::{
+ constants::{NAME, VERSION},
+ settings::WindowMode,
+ GameSettings,
+};
+use clap::{App, Arg};
+use std::path::PathBuf;
+
+/// Run CLI parser and parse options into GameSettings structure
+pub fn parse(settings: &mut GameSettings) {
+ let app = App::new(NAME)
+ .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("assets")
+ .required(true)
+ .takes_value(true)
+ .help("Specify the path to load assets from"),
+ )
+ .arg(
+ Arg::with_name("width")
+ .short("w")
+ .takes_value(true)
+ .help("Set the desired game window width"),
+ )
+ .arg(
+ Arg::with_name("height")
+ .short("h")
+ .takes_value(true)
+ .help("Set the desired game window height"),
+ )
+ .arg(
+ Arg::with_name("fullscreen")
+ .short("f")
+ .help("Specify if the game should run full screen"),
+ );
+
+ let matches = app.get_matches();
+ if let Some(assets) = matches.value_of("assets") {
+ settings.assets = Some(PathBuf::new().join(assets));
+ }
+
+ if let Some(width) = matches.value_of("width") {
+ settings.window.width = str::parse(width).unwrap();
+ }
+
+ if let Some(height) = matches.value_of("height") {
+ settings.window.height = str::parse(height).unwrap();
+ }
+
+ if matches.is_present("fullscreen") {
+ settings.window.window_mode = WindowMode::Fullscreen;
+ }
+}
diff --git a/games/rstnode/rst-client/src/error.rs b/games/rstnode/rst-client/src/error.rs
new file mode 100644
index 000000000000..08266bd5e591
--- /dev/null
+++ b/games/rstnode/rst-client/src/error.rs
@@ -0,0 +1,24 @@
+//! Various errors that can occur
+
+use std::{
+ error::Error,
+ fmt::{self, Display, Formatter},
+};
+
+/// Error loading an asset
+#[derive(Clone, Debug)]
+pub struct LoadError(String);
+
+impl<'s> From<&'s str> for LoadError {
+ fn from(s: &'s str) -> Self {
+ Self(s.into())
+ }
+}
+
+impl Display for LoadError {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl Error for LoadError {}
diff --git a/games/rstnode/rst-client/src/graphics/entities/mod.rs b/games/rstnode/rst-client/src/graphics/entities/mod.rs
index d3536d4f5fc2..17f26a8e5a70 100644
--- a/games/rstnode/rst-client/src/graphics/entities/mod.rs
+++ b/games/rstnode/rst-client/src/graphics/entities/mod.rs
@@ -22,20 +22,28 @@ pub struct NodeRndr {
pub inner: Arc<Node>,
}
-impl EventHandler for NodeRndr {
- fn update(&mut self, _: &mut Context) -> GameResult<()> {
+impl Renderer for NodeRndr {
+ fn update(&mut self, _: &mut ClientState, _: &mut Context) -> GameResult<()> {
Ok(())
}
- fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
+ fn draw(&self, s: &ClientState, ctx: &mut Context) -> GameResult<()> {
+ let frame = s.assets().find("frame/frame_s").unwrap();
+
+ frame.draw(
+ ctx,
+ DrawParam::new().dest([256.0, 256.0]).color(graphics::RED),
+ )?;
+
let circ = Mesh::new_circle(
ctx,
DrawMode::fill(),
Point2::from(&self.loc),
- 128.0,
+ 64.0,
0.1,
graphics::WHITE,
- ).unwrap();
+ )
+ .unwrap();
circ.draw(ctx, DrawParam::new()).unwrap();
Ok(())
diff --git a/games/rstnode/rst-client/src/graphics/mod.rs b/games/rstnode/rst-client/src/graphics/mod.rs
index 8118207d70af..095e66f1ad1f 100644
--- a/games/rstnode/rst-client/src/graphics/mod.rs
+++ b/games/rstnode/rst-client/src/graphics/mod.rs
@@ -8,9 +8,25 @@
pub mod entities;
pub mod ui;
+use crate::state::ClientState;
+use ggez::{Context, GameResult};
+
/// A utility module to include everything required to implement a
/// graphics entity
pub(self) mod prelude {
- pub use ggez::{event::EventHandler, graphics::{self, Drawable, DrawParam, Mesh, DrawMode}, Context, GameResult};
+ pub use ggez::{
+ event::EventHandler,
+ graphics::{self, DrawMode, DrawParam, Drawable, Mesh},
+ Context, GameResult,
+ };
pub use mint::Point2;
+
+ pub use super::Renderer;
+ pub use crate::state::ClientState;
+}
+
+/// A rendering trait which is given graphics context, and game state
+pub trait Renderer {
+ fn update(&mut self, _state: &mut ClientState, _ctx: &mut Context) -> GameResult<()>;
+ fn draw(&self, _state: &ClientState, _ctx: &mut Context) -> GameResult<()>;
}
diff --git a/games/rstnode/rst-client/src/log.rs b/games/rstnode/rst-client/src/log.rs
new file mode 100644
index 000000000000..f1c346ae343a
--- /dev/null
+++ b/games/rstnode/rst-client/src/log.rs
@@ -0,0 +1,43 @@
+//! Logging specifics
+
+const BANNER: &'static str = "
+██████╗ ███████╗████████╗ ███╗ ██╗ ██████╗ ██████╗ ███████╗
+██╔══██╗██╔════╝╚══██╔══╝ ████╗ ██║██╔═══██╗██╔══██╗██╔════╝
+██████╔╝███████╗ ██║ ██╔██╗ ██║██║ ██║██║ ██║█████╗
+██╔══██╗╚════██║ ██║ ██║╚██╗██║██║ ██║██║ ██║██╔══╝
+██║ ██║███████║ ██║ ██║ ╚████║╚██████╔╝██████╔╝███████╗
+╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═════╝ ╚══════╝";
+
+use tracing_subscriber::{filter::LevelFilter, fmt, EnvFilter};
+
+pub(crate) fn initialise() {
+ let filter = EnvFilter::try_from_env("RST_LOG")
+ .unwrap_or_default()
+ .add_directive(LevelFilter::DEBUG.into())
+ .add_directive("async_std=error".parse().unwrap())
+ .add_directive("gfx_device_gl=error".parse().unwrap())
+ .add_directive("ggez=error".parse().unwrap())
+ .add_directive("selectors=error".parse().unwrap())
+ .add_directive("gilrs=error".parse().unwrap())
+ .add_directive("mio=error".parse().unwrap());
+
+ // Initialise the logger
+ fmt().with_env_filter(filter).init();
+ info!("Initialising...");
+ info!("{}", BANNER);
+ info!("Platform: unknown");
+ info!("GPU Driver: unknown");
+ info!("Version: {}", crate::constants::VERSION);
+}
+
+#[macro_export]
+macro_rules! fatal {
+ () => {
+ error!("Unknown failure!");
+ std::process::exit(2)
+ };
+ ($($arg:tt)*) => ({
+ error!($($arg)*);
+ std::process::exit(2)
+ })
+}
diff --git a/games/rstnode/rst-client/src/main.rs b/games/rstnode/rst-client/src/main.rs
index 57a686a19d74..b86ee341075e 100644
--- a/games/rstnode/rst-client/src/main.rs
+++ b/games/rstnode/rst-client/src/main.rs
@@ -1,10 +1,15 @@
//! RST Node game client
+#[macro_use]
+extern crate tracing;
+
mod assets;
mod cli;
mod constants;
mod ctx;
+mod error;
mod graphics;
+mod log;
mod settings;
mod state;
mod window;
@@ -14,8 +19,22 @@ pub(crate) use settings::{GameSettings, GraphicsSettings, WindowSettings};
pub(crate) use state::*;
fn main() {
- let settings = settings::default();
+ // Initialise logging mechanism
+ log::initialise();
+
+ // Initialise default game settings
+ let mut settings = settings::default();
+
+ // Parse commandline arguments
+ cli::parse(&mut settings);
+
+ // Initialise window context
+ let mut window = window::create(&settings);
+
+ // Load assets tree
+ let assets =
+ assets::load_tree(window.ctx(), &settings).unwrap_or_else(|e| fatal!("LoadError: {}!", e));
+ let state = ClientState::new(settings, assets);
- let state = ClientState::new(&settings);
- window::run(&settings, state)
+ window.run(state)
}
diff --git a/games/rstnode/rst-client/src/settings.rs b/games/rstnode/rst-client/src/settings.rs
index a339c4106da5..cb44eacca3a3 100644
--- a/games/rstnode/rst-client/src/settings.rs
+++ b/games/rstnode/rst-client/src/settings.rs
@@ -1,16 +1,18 @@
//! Configuration structures for the game client
use ggez::conf::{FullscreenType, NumSamples};
+use std::path::PathBuf;
pub fn default() -> GameSettings {
GameSettings {
+ assets: None,
window: WindowSettings {
width: 1280,
height: 720,
window_mode: WindowMode::Windowed,
},
graphics: GraphicsSettings {
- samples: Samples(16),
+ samples: Samples(8),
vsync: true,
},
}
@@ -18,6 +20,7 @@ pub fn default() -> GameSettings {
/// Complete tree of basic game client settings
pub struct GameSettings {
+ pub assets: Option<PathBuf>,
pub window: WindowSettings,
pub graphics: GraphicsSettings,
}
@@ -45,7 +48,7 @@ impl<'s> From<&'s Samples> for NumSamples {
2 => Self::Two,
4 => Self::Four,
8 => Self::Eight,
- 16 => Self::Sixteen,
+ // 16 => Self::Sixteen, // currently broken
_ => panic!("Invalid multisampling value: {}", s.0),
}
}
diff --git a/games/rstnode/rst-client/src/state.rs b/games/rstnode/rst-client/src/state.rs
index c55dc2faa6d6..6b7312f13d7f 100644
--- a/games/rstnode/rst-client/src/state.rs
+++ b/games/rstnode/rst-client/src/state.rs
@@ -1,7 +1,11 @@
//! Game client state handling
use crate::{
- graphics::entities::{Coordinates, NodeRndr},
+ assets::Assets,
+ graphics::{
+ entities::{Coordinates, NodeRndr},
+ Renderer,
+ },
GameSettings,
};
use ggez::{event::EventHandler, graphics, Context, GameResult};
@@ -9,12 +13,18 @@ use rst_core::data::{Node, Owner, Upgrade};
use std::sync::Arc;
pub struct ClientState {
+ assets: Assets,
+ settings: GameSettings,
+
+ // Game state
node: NodeRndr,
}
impl ClientState {
- pub fn new(_settings: &GameSettings) -> Self {
+ pub fn new(settings: GameSettings, assets: Assets) -> Self {
Self {
+ assets,
+ settings,
node: NodeRndr {
loc: Coordinates(250.0, 250.0),
inner: Arc::new(Node {
@@ -30,6 +40,10 @@ impl ClientState {
},
}
}
+
+ pub fn assets(&self) -> &Assets {
+ &self.assets
+ }
}
impl EventHandler for ClientState {
@@ -41,7 +55,7 @@ impl EventHandler for ClientState {
graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15));
// Render the node
- self.node.draw(ctx).unwrap();
+ self.node.draw(&self, ctx).unwrap();
graphics::present(ctx)
}
diff --git a/games/rstnode/rst-client/src/window.rs b/games/rstnode/rst-client/src/window.rs
index ad58c38e0ffb..3dcf375a9009 100644
--- a/games/rstnode/rst-client/src/window.rs
+++ b/games/rstnode/rst-client/src/window.rs
@@ -1,10 +1,28 @@
//! Basic window setup code
use crate::{ctx, state::ClientState, GameSettings};
-use ggez::event;
+use ggez::{
+ event::{self, EventLoop},
+ Context,
+};
+
+pub struct Window {
+ ctx: Context,
+ eloop: EventLoop<()>,
+}
+
+impl Window {
+ pub fn ctx(&mut self) -> &mut Context {
+ &mut self.ctx
+ }
+
+ pub fn run(self, state: ClientState) -> ! {
+ event::run(self.ctx, self.eloop, state)
+ }
+}
/// Start the main event loop with game settings and state
-pub fn run(settings: &GameSettings, state: ClientState) -> ! {
+pub fn create(settings: &GameSettings) -> Window {
let (ctx, eloop) = ctx::build(settings).build().unwrap();
- event::run(ctx, eloop, state)
+ Window { ctx, eloop }
}