* 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 colourwip/yesman
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
@ -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; |
||||
} |
||||
} |
||||
|
@ -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 {} |
@ -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) |
||||
}) |
||||
} |
@ -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 } |
||||
} |
||||
|