Set up the desktop wrapper

This commit is contained in:
Evan Pratten 2022-03-17 10:22:07 -04:00
parent ec19b22107
commit 9b9bff120a
6 changed files with 155 additions and 4 deletions

View File

@ -5,5 +5,17 @@ version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
game_logic = { version = "*", path = "../game_logic" }
tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] }
fern = { version = "0.6", features = ["colored"] }
thiserror = "1.0.30"
profiling = { version = "1.0.5", features = ["profile-with-puffin"] }
chrono = "0.4.19"
log = "0.4.14"
clap = { version = "3.1.6", features = ["derive"] }
puffin_http = "0.10.0"
puffin = "0.13.1"
[dependencies]
[dev-dependencies]
puffin_viewer = "0.11.0"

View File

@ -0,0 +1,11 @@
//! This module contains some code for handling CLI flags
use clap::Parser;
/// Ludum Dare 50 game
#[derive(Parser, Debug)]
#[clap( version, about, long_about = None)]
pub struct Args {
/// Use verbose logging
#[clap(short, long)]
pub verbose: bool,
}

View File

@ -0,0 +1,18 @@
//! This module handles enabling the remote-attach profiler when running in debug mode.
/// When in debug mode, this will set up profiling. (note: this will cause very slight lag)
#[must_use]
pub fn init_profiling() -> Option<puffin_http::Server> {
if cfg!(debug_assertions) {
// Enable the puffin HTTP service
let server =
puffin_http::Server::new(&format!("0.0.0.0:{}", puffin_http::DEFAULT_PORT)).unwrap();
// Enable puffin itself
puffin::set_scopes_on(true);
Some(server)
} else {
None
}
}

View File

@ -0,0 +1,76 @@
//! This module contains some bootstrapping code for setting up logging.
use std::env::temp_dir;
use chrono::Utc;
use fern::colors::ColoredLevelConfig;
use log::LevelFilter;
use thiserror::Error;
/// Error definitions for setting up the logging system
#[derive(Error, Debug)]
pub enum LoggingSystemInitError {
/// Error caused by a failure to set the global logger
#[error(transparent)]
SetLoggerError(#[from] log::SetLoggerError),
/// Error caused by a failure to open the filesystem log location
#[error(transparent)]
IoError(#[from] std::io::Error),
}
/// Sets up global logging for an application
#[profiling::function]
pub fn init_logging_system(
tool_name: &str,
log_level: Option<LevelFilter>,
) -> Result<(), LoggingSystemInitError> {
// Set up coloring system for STDIO logs
let stdio_colors = ColoredLevelConfig::default();
// Set up a dispatcher for STDIO
// This will skip over un-needed verbosity
log::trace!("Setting up STDIO logging");
let stdio_dispatch = fern::Dispatch::new()
.format(move |out, message, record| {
out.finish(format_args!(
"{}: {}",
stdio_colors.color(record.level()),
message
))
})
.level(log_level.unwrap_or(LevelFilter::Info))
.chain(std::io::stdout());
// Determine where to write the logfile
let log_file_path = temp_dir().join(format!("{}.{}.log", tool_name, Utc::now().timestamp()));
log::info!(
"A verbose copy of the application log will be written to: {}",
log_file_path.display()
);
// Set up a dispatcher for the logfile
log::trace!("Setting up file logging");
let fs_dispatch = fern::Dispatch::new()
// Perform allocation-free log formatting
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}][{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record.level(),
message
))
})
.level(LevelFilter::Debug)
.chain(fern::log_file(log_file_path)?);
// Combine and apply the dispatchers
log::trace!("Setting up global logger");
fern::Dispatch::new()
.chain(stdio_dispatch)
.chain(fs_dispatch)
.apply()?;
Ok(())
}

View File

@ -1,4 +1,35 @@
//! # This file is probably not what you are looking for.
//!
//! In order to keep compile times reasonable, this crate is split into a `bin` and `lib` part, this being `bin`.
//! All this crate is designed to do is bootstrap the game, and call `game_logic::entrypoint()` to *actually* start the game.
fn main(){
}
use clap::StructOpt;
use log::LevelFilter;
mod cli;
mod logging;
mod debug_profiling;
#[tokio::main]
async fn main() {
// Set up CLI args
let args = cli::Args::parse();
// Enable profiling
let _profile_handle = debug_profiling::init_profiling();
// Set up logging
logging::init_logging_system(
"ldjam50",
match args.verbose {
true => Some(LevelFilter::Debug),
false => None,
},
)
.expect("Failed to initialize logging system");
// Start the game
log::info!("Starting game");
game_logic::entrypoint().await;
log::info!("Goodbye!");
}

View File

@ -0,0 +1,3 @@
/// This is the game logic entrypoint. Despite being async,
/// this is expected to block the main thread for rendering and stuff.
pub async fn entrypoint() {}