diff --git a/Cargo.toml b/Cargo.toml index 360ef3d..54d443d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,56 +1,57 @@ -[package] -name = "training_modpack" -version = "4.0.0" -authors = ["jugeeya "] -edition = "2018" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" } -skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", branch = "no-cache" } -skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" } -bitflags = "1.2.1" -parking_lot = { version = "0.12.0", features = ["nightly"] } -lazy_static = "1.4.0" -owo-colors = "2.1.0" -once_cell = "1.12.0" -ramhorns = "0.12.0" -paste = "1.0" -num = "0.4.0" -num-derive = "0.3" -num-traits = "0.2" -wsl = "0.1.0" -strum = "0.21.0" -strum_macros = "0.21.0" -minreq = { version = "2", features = ["https-native", "json-using-serde"] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -toml = "0.5.9" -training_mod_consts = { path = "training_mod_consts" } -training_mod_tui = { path = "training_mod_tui" } -native-tls = { version = "0.2.11", features = ["vendored"] } - -[patch.crates-io] -native-tls = { git = "https://github.com/skyline-rs/rust-native-tls", rev = "f202fca" } -nnsdk = { git = "https://github.com/ultimate-research/nnsdk-rs" } - -[profile.dev] -panic = "abort" - -[profile.release] -panic = "abort" -lto = true - -[package.metadata.skyline] -titleid = "01006A800016E000" -plugin-dependencies = [ - { name = "libnro_hook.nro", url = "https://github.com/ultimate-research/nro-hook-plugin/releases/download/v0.4.0/libnro_hook.nro" }, - { name = "libparam_hook.nro", url = "https://github.com/ultimate-research/params-hook-plugin/releases/download/v0.1.1/libparam_hook.nro" }, - { name = "libnn_hid_hook.nro", url = "https://github.com/jugeeya/nn-hid-hook/releases/download/beta/libnn_hid_hook.nro" } -] - -[features] -outside_training_mode = [] -web_session_single_thread = [] +[package] +name = "training_modpack" +version = "4.0.0" +authors = ["jugeeya "] +edition = "2018" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +skyline = { git = "https://github.com/ultimate-research/skyline-rs.git" } +skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", branch = "no-cache" } +skyline-web = { git = "https://github.com/skyline-rs/skyline-web.git" } +bitflags = "1.2.1" +parking_lot = { version = "0.12.0", features = ["nightly"] } +lazy_static = "1.4.0" +owo-colors = "2.1.0" +once_cell = "1.12.0" +ramhorns = "0.12.0" +paste = "1.0" +num = "0.4.0" +num-derive = "0.3" +num-traits = "0.2" +wsl = "0.1.0" +strum = "0.21.0" +strum_macros = "0.21.0" +minreq = { version = "2", features = ["https-native", "json-using-serde"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +toml = "0.5.9" +training_mod_consts = { path = "training_mod_consts" } +training_mod_tui = { path = "training_mod_tui" } +native-tls = { version = "0.2.11", features = ["vendored"] } +log = "0.4.17" + +[patch.crates-io] +native-tls = { git = "https://github.com/skyline-rs/rust-native-tls", rev = "f202fca" } +nnsdk = { git = "https://github.com/ultimate-research/nnsdk-rs" } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +lto = true + +[package.metadata.skyline] +titleid = "01006A800016E000" +plugin-dependencies = [ + { name = "libnro_hook.nro", url = "https://github.com/ultimate-research/nro-hook-plugin/releases/download/v0.4.0/libnro_hook.nro" }, + { name = "libparam_hook.nro", url = "https://github.com/ultimate-research/params-hook-plugin/releases/download/v0.1.1/libparam_hook.nro" }, + { name = "libnn_hid_hook.nro", url = "https://github.com/jugeeya/nn-hid-hook/releases/download/beta/libnn_hid_hook.nro" } +] + +[features] +outside_training_mode = [] +web_session_single_thread = [] diff --git a/src/common/button_config.rs b/src/common/button_config.rs index 3a7c13a..97be9b2 100644 --- a/src/common/button_config.rs +++ b/src/common/button_config.rs @@ -61,7 +61,7 @@ struct TopLevelBtnComboConfig { } pub fn validate_config(data: &str) -> bool { - let conf: TopLevelBtnComboConfig = toml::from_str(data).unwrap(); + let conf: TopLevelBtnComboConfig = toml::from_str(data).expect("Custom button config has invalid schema"); let conf = conf.button_config; let configs = [conf.open_menu, conf.save_state, conf.load_state]; let bad_keys = configs @@ -117,7 +117,7 @@ pub fn save_all_btn_config_from_defaults() { } pub fn save_all_btn_config_from_toml(data: &str) { - let conf: TopLevelBtnComboConfig = toml::from_str(data).unwrap(); + let conf: TopLevelBtnComboConfig = toml::from_str(data).expect("Could not parse button config"); unsafe { // This println is necessary. Why?....... println!("{:?}", &conf.button_config.load_state.press); diff --git a/src/common/menu.rs b/src/common/menu.rs index 15b2d0b..5fc35e9 100644 --- a/src/common/menu.rs +++ b/src/common/menu.rs @@ -1,6 +1,7 @@ use crate::common::*; use crate::events::{Event, EVENT_QUEUE}; use crate::training::frame_counter; +use crate::logging::*; use ramhorns::Template; use skyline::info::get_program_id; @@ -57,11 +58,7 @@ pub unsafe fn write_menu() { .join(format!("{program_id:016X}")) .join(format!("manual_html/html-document/{htdocs_dir}.htdocs/")) .join("training_menu.html"); - - let write_resp = fs::write(menu_html_path, data); - if write_resp.is_err() { - println!("Error!: {}", write_resp.err().unwrap()); - } + fs::write(menu_html_path, data).expect("Failed to write menu HTML file"); } const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.json"; @@ -69,7 +66,7 @@ const MENU_CONF_PATH: &str = "sd:/TrainingModpack/training_modpack_menu.json"; pub unsafe fn set_menu_from_json(message: &str) { let web_response = serde_json::from_str::(message); let tui_response = serde_json::from_str::(message); - println!("Received menu message: {message}"); + info!("Received menu message: {message}"); if let Ok(message_json) = web_response { // Includes both MENU and DEFAULTS_MENU // From Web Applet @@ -79,7 +76,7 @@ pub unsafe fn set_menu_from_json(message: &str) { MENU_CONF_PATH, serde_json::to_string_pretty(&message_json).unwrap(), ) - .expect("Failed to write menu settings file"); + .expect("Failed to write menu settings file from web response"); } else if let Ok(message_json) = tui_response { // Only includes MENU // From TUI @@ -90,7 +87,7 @@ pub unsafe fn set_menu_from_json(message: &str) { defaults_menu: DEFAULTS_MENU, }; std::fs::write(MENU_CONF_PATH, serde_json::to_string_pretty(&conf).unwrap()) - .expect("Failed to write menu settings file"); + .expect("Failed to write menu settings file from quick menu response"); } else { skyline::error::show_error( 0x70, @@ -348,10 +345,10 @@ pub unsafe fn quick_menu_loop() { static mut WEB_MENU_ACTIVE: bool = false; unsafe fn spawn_web_session(session: WebSession) { - println!("[Training Modpack] Opening menu session..."); + info!("Opening menu session..."); let loaded_msg = session.recv(); - println!( - "[Training Modpack] Received loaded message from web: {}", + info!( + "Received loaded message from web: {}", &loaded_msg ); let message_send = MenuJsonStruct { @@ -360,7 +357,7 @@ unsafe fn spawn_web_session(session: WebSession) { }; session.send_json(&message_send); let message_recv = session.recv(); - println!("[Training Modpack] Tearing down Training Modpack menu session"); + info!("Tearing down Training Modpack menu session"); session.exit(); session.wait_for_exit(); set_menu_from_json(&message_recv); @@ -399,7 +396,7 @@ pub unsafe fn web_session_loop() { // Starting a new session causes some ingame lag. // Investigate whether we can minimize this lag by // waiting until the player is idle or using CPU boost mode - println!("[Training Modpack] Starting new menu session..."); + info!("Starting new menu session..."); web_session = Some(new_web_session(true)); } } else { @@ -407,7 +404,7 @@ pub unsafe fn web_session_loop() { // This will avoid conflicts with other web plugins, and helps with stability. // Having the session open too long, especially if the switch has been put to sleep, can cause freezes if let Some(web_session_to_kill) = web_session { - println!("[Training Modpack] Tearing down Training Modpack menu session"); + info!("Tearing down Training Modpack menu session"); web_session_to_kill.exit(); web_session_to_kill.wait_for_exit(); } diff --git a/src/common/release.rs b/src/common/release.rs index 6258af8..6929ee1 100644 --- a/src/common/release.rs +++ b/src/common/release.rs @@ -1,5 +1,6 @@ use skyline_web::DialogOk; use std::fs; +use crate::logging::*; pub const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION_FILE_PATH: &str = "sd:/TrainingModpack/version.txt"; @@ -44,9 +45,9 @@ pub fn version_check() { ) ); // Remove old menu selections, silently ignoring errors (i.e. if the file doesn't exist) - fs::remove_file("sd:/TrainingModpack/training_modpack_menu.conf").unwrap(); - fs::remove_file("sd:/TrainingModpack/training_modpack_menu.json").unwrap(); - fs::remove_file("sd:/TrainingModpack/training_modpack_menu_defaults.conf").unwrap(); + fs::remove_file("sd:/TrainingModpack/training_modpack_menu.conf").unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu.conf")); + fs::remove_file("sd:/TrainingModpack/training_modpack_menu.json").unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu.json")); + fs::remove_file("sd:/TrainingModpack/training_modpack_menu_defaults.conf").unwrap_or_else(|_| error!("Couldn't remove training_modpack_menu_defaults.conf")); record_current_version(VERSION_FILE_PATH); } VersionCheck::NoFile => { diff --git a/src/hazard_manager/mod.rs b/src/hazard_manager/mod.rs index 78998c9..21972b2 100644 --- a/src/hazard_manager/mod.rs +++ b/src/hazard_manager/mod.rs @@ -2,6 +2,7 @@ #![allow(unused_assignments)] #![allow(unused_variables)] use crate::common::consts::*; +use crate::logging::*; use skyline::error::show_error; use skyline::hook; use skyline::hooks::A64InlineHook; @@ -127,7 +128,7 @@ unsafe fn validate_hazards_addrs() -> std::result::Result<(), ()> { } pub fn hazard_manager() { - println!("[Training Modpack] Applying hazard control mods."); + info!("Applying hazard control mods."); unsafe { if let Ok(()) = validate_hazards_addrs() { HAZARD_FLAG_ADDRESS = get_hazard_flag_address() as *mut u8; diff --git a/src/hitbox_visualizer/mod.rs b/src/hitbox_visualizer/mod.rs index 75f1b3a..4150e6e 100644 --- a/src/hitbox_visualizer/mod.rs +++ b/src/hitbox_visualizer/mod.rs @@ -1,4 +1,5 @@ use crate::common::{consts::*, *}; +use crate::logging::*; use smash::app::{self, lua_bind::*, sv_animcmd, sv_system}; use smash::lib::{lua_const::*, L2CAgent, L2CValue}; use smash::phx::{Hash40, Vector3f}; @@ -369,6 +370,6 @@ unsafe fn mod_handle_handle_set_rebound( } pub fn hitbox_visualization() { - println!("[Training Modpack] Applying hitbox visualization mods."); + info!("Applying hitbox visualization mods."); skyline::install_hooks!(handle_attack, handle_catch, handle_set_rebound); } diff --git a/src/lib.rs b/src/lib.rs index 5d4b92a..6f18d48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ mod training; #[cfg(test)] mod test; +mod logging; use crate::common::*; use crate::events::{Event, EVENT_QUEUE}; @@ -34,8 +35,8 @@ use std::fs; use crate::menu::quick_menu_loop; #[cfg(feature = "web_session_preload")] use crate::menu::web_session_loop; -use owo_colors::OwoColorize; use training_mod_consts::{MenuJsonStruct, OnOff}; +use crate::logging::*; fn nro_main(nro: &NroInfo<'_>) { if nro.module.isLoaded { @@ -70,21 +71,16 @@ pub fn main() { }, }; - let err_msg = format!("thread has panicked at '{msg}', {location}"); + let err_msg = format!("SSBU Training Modpack has panicked at '{msg}', {location}"); skyline::error::show_error( 69, - "Skyline plugin has panicked! Please open the details and send a screenshot to the developer, then close the game.\n", + "SSBU Training Modpack has panicked! Please open the details and send a screenshot to the developer, then close the game.\n", err_msg.as_str(), ); })); + init_logger().unwrap(); - macro_rules! log { - ($($arg:tt)*) => { - println!("{}{}", "[Training Modpack] ".green(), format!($($arg)*)); - }; - } - - log!("Initialized."); + info!("Initialized."); unsafe { EVENT_QUEUE.push(Event::smash_open()); } @@ -102,46 +98,43 @@ pub fn main() { let ovl_path = "sd:/switch/.overlays/ovlTrainingModpack.ovl"; if fs::metadata(ovl_path).is_ok() { - log!("Removing ovlTrainingModpack.ovl..."); - fs::remove_file(ovl_path).unwrap(); + warn!("Removing ovlTrainingModpack.ovl..."); + fs::remove_file(ovl_path).expect(&format!("Could not remove {}", ovl_path)); } - log!("Performing version check..."); + info!("Performing version check..."); release::version_check(); let menu_conf_path = "sd:/TrainingModpack/training_modpack_menu.json"; - log!("Checking for previous menu in training_modpack_menu.json..."); + info!("Checking for previous menu in training_modpack_menu.json..."); if fs::metadata(menu_conf_path).is_ok() { - let menu_conf = fs::read_to_string(menu_conf_path).unwrap(); + let menu_conf = fs::read_to_string(menu_conf_path).expect(&format!("Could not remove {}", menu_conf_path)); if let Ok(menu_conf_json) = serde_json::from_str::(&menu_conf) { unsafe { MENU = menu_conf_json.menu; DEFAULTS_MENU = menu_conf_json.defaults_menu; - log!("Previous menu found. Loading..."); + info!("Previous menu found. Loading..."); } - } else if menu_conf.starts_with("http://localhost") { - log!("Previous menu found, with URL schema. Deleting..."); - fs::remove_file(menu_conf_path).expect("Could not delete menu conf file!"); } else { - log!("Previous menu found but is invalid. Deleting..."); - fs::remove_file(menu_conf_path).expect("Could not delete menu conf file!"); + warn!("Previous menu found but is invalid. Deleting..."); + fs::remove_file(menu_conf_path).expect(&format!("{} has invalid schema but could not be deleted!", menu_conf_path)); } } else { - log!("No previous menu file found."); + info!("No previous menu file found."); } let combo_path = "sd:/TrainingModpack/training_modpack.toml"; - log!("Checking for previous button combo settings in training_modpack.toml..."); + info!("Checking for previous button combo settings in training_modpack.toml..."); if fs::metadata(combo_path).is_ok() { - log!("Previous button combo settings found. Loading..."); - let combo_conf = fs::read_to_string(combo_path).unwrap(); + info!("Previous button combo settings found. Loading..."); + let combo_conf = fs::read_to_string(combo_path).expect(&format!("Could not read {}", combo_path)); if button_config::validate_config(&combo_conf) { button_config::save_all_btn_config_from_toml(&combo_conf); } else { button_config::save_all_btn_config_from_defaults(); } } else { - log!("No previous button combo file found. Creating..."); + info!("No previous button combo file found. Creating..."); fs::write(combo_path, button_config::DEFAULT_BTN_CONFIG) .expect("Failed to write button config conf file"); button_config::save_all_btn_config_from_defaults(); @@ -166,7 +159,7 @@ pub fn main() { ); let url = format!("{host}{path}"); - minreq::post(url).with_json(&event).unwrap().send().ok(); + minreq::post(url).with_json(&event).expect("Failed to send info to firebase").send().ok(); } } }); diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..adc74c8 --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,50 @@ +pub use log::{error, info, warn}; +use log::{Level, LevelFilter, Metadata, Record, SetLoggerError}; +use owo_colors::OwoColorize; + +struct TrainingModpackLogger; + +impl log::Log for TrainingModpackLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Info + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + match record.level() { + Level::Error => { + println!( + "[TrainingModpack] [{}] {}", + record.level().red(), + record.args() + ); + } + Level::Warn => { + println!( + "[TrainingModpack] [{}] {}", + record.level().yellow(), + record.args() + ); + } + Level::Info => { + println!( + "[TrainingModpack] [{}] {}", + record.level().cyan(), + record.args() + ); + } + _ => { + println!("[TrainingModpack] [{}] {}", record.level(), record.args()); + } + }; + } + } + + fn flush(&self) {} +} + +static LOGGER: TrainingModpackLogger = TrainingModpackLogger; + +pub fn init_logger() -> Result<(), SetLoggerError> { + log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info)) +} diff --git a/src/training/mod.rs b/src/training/mod.rs index 7dbcd7d..8dfac10 100644 --- a/src/training/mod.rs +++ b/src/training/mod.rs @@ -3,6 +3,7 @@ use crate::common::{ }; use crate::hitbox_visualizer; use crate::training::character_specific::items; +use crate::logging::*; use skyline::hooks::{getRegionAddress, InlineCtx, Region}; use skyline::nn::hid::*; use skyline::nn::ro::LookupSymbol; @@ -476,7 +477,7 @@ extern "C" { } pub fn training_mods() { - println!("[Training Modpack] Applying training mods."); + info!("Applying training mods."); // Input Recording/Delay unsafe {