commit d52bc7b646a0274c231e1d6182a5073246ab7b33 Author: Filipe Rodrigues Date: Sun Apr 26 09:32:44 2020 +0100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96d8802 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +.vscode +resources/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..83dc176 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,539 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "ascii" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109" +dependencies = [ + "serde", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +dependencies = [ + "num-integer", + "num-traits", + "time", +] + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "dcb" +version = "0.1.0" +dependencies = [ + "arrayref", + "ascii", + "byteorder", + "derive_more", + "err-impl", + "log", + "serde", +] + +[[package]] +name = "dcb-extract" +version = "0.1.0" +dependencies = [ + "clap", + "dcb", + "derive_more", + "err-backtrace", + "err-ext", + "err-panic", + "log", + "serde_yaml", + "simplelog", + "string-err", +] + +[[package]] +name = "derive_more" +version = "0.99.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +dependencies = [ + "cfg-if", + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dtoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" + +[[package]] +name = "err-backtrace" +version = "0.1.0" + +[[package]] +name = "err-ext" +version = "0.1.0" + +[[package]] +name = "err-impl" +version = "0.1.0" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "err-panic" +version = "0.1.0" +dependencies = [ + "string-err", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" + +[[package]] +name = "linked-hash-map" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "syn-mid", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "redox_users" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "rust-argon2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "serde" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + +[[package]] +name = "simplelog" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcacac97349a890d437921dfb23cbec52ab5b4752551cb637df2721371acd467" +dependencies = [ + "chrono", + "log", + "term", +] + +[[package]] +name = "string-err" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb6c5ccd2a653178945caa695062379fa26812f1e63584111ac8fff988358d1" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +dependencies = [ + "dirs", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" + +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..da7ffa3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "dcb-extract" +version = "0.1.0" +authors = ["Filipe Rodrigues "] +edition = "2018" + +[dependencies] + +# Dcb +dcb = { path = "../dcb" } + +# Cmd +clap = "2.33" + +# Logging +log = "0.4" +simplelog = "0.7" + +# Error handling +string-err = "0.1" +err-backtrace = { path = "../err-backtrace" } +err-panic = { path = "../err-panic", features = ["string-err-ext"] } +err-ext = { path = "../err-ext" } +derive_more = "0.99" + + +# Serde +serde_yaml = "0.8" + +# Build dependencies in release mode +[profile.dev.package."*"] +opt-level = 2 +[profile.dev.package.dcb] # Except dcb +opt-level = 0 + diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..24b38b4 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,72 @@ +//! Cli manager for the extractor + +// Filesystem +use std::path::{Path, PathBuf}; + +// Clap +use clap::{Arg as ClapArg, App as ClapApp}; + +// Errors +use err_panic::ErrorExtPanic; + + +/// All of the data received form the command line +/// +/// # Public fields +/// All fields are public as this type has no invariants. +pub struct CliData +{ + /// The input filename + pub input_filename: PathBuf, + + /// The output directory + pub output_dir: PathBuf, +} + +impl CliData +{ + /// Constructs all of the cli data given and returns it + pub fn new() -> Self + { + // Get all matches from cli + let matches = ClapApp::new("Dcb Extractor") + .version("0.0") + .author("Filipe [...] <[...]@gmail.com>") + .about("Extracts all data from a Digimon Digital Card Battle `.bin` game file") + .arg( ClapArg::with_name("INPUT") + .help("Sets the input game file to use") + .required(true) + .index(1) + ) + .arg( ClapArg::with_name("OUTPUT") + .help("Sets the output directory to use") + .short("o") + .long("output") + .takes_value(true) + .required(false) + ) + .get_matches(); + + // Get the input filename + // Note: required + let input_filename = matches.value_of("INPUT") + .map(Path::new) + .map(Path::to_path_buf) + .panic_msg("Unable to get required argument `INPUT`"); + + // Try to get the output + let output_dir = match matches.value_of("OUTPUT") { + Some(output) => PathBuf::from(output), + None => input_filename + .parent() + .unwrap_or_else(|| Path::new(".")) + .to_path_buf() + }; + + // Return the cli data + Self { + input_filename, + output_dir, + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b972b6c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,127 @@ +//! Data extractor +//! +//! # Details +//! Extracts data from the game file to several other files, that can be +//! edited and then used by `Patcher` to modify the game file. +//! +//! # Syntax +//! The executable may be called as `./dcb-extractor {-o }` +//! +//! Use the command `./dcb-extractor --help` for more information. +//! +//! # Data extracted +//! Currently only the following is extracted: +//! - Card table +//! - Deck table (partial) + +// Features +#![feature( + box_syntax, + backtrace, + panic_info_message, +)] + +// Lints +#![warn( + clippy::restriction, + clippy::pedantic, + clippy::nursery, +)] +#![allow( + clippy::implicit_return, // We prefer implicit returns where possible + clippy::module_name_repetitions, // This happens often due to separating things into modules finely + clippy::wildcard_enum_match_arm, // We only use wildcards when we truly only care about some variants + clippy::result_expect_used, + clippy::option_expect_used, // We use expect when there is no alternative. + clippy::used_underscore_binding, // Useful for macros and such +)] + +// Modules +mod cli; +mod panic; + +// Exports +use cli::CliData; + +// Dcb +use dcb::{ + GameFile, + game::{ + card::Table as CardTable + }, + //game::deck::Table as DeckTable, +}; + +// Errors +use err_ext::ErrorExt; +use err_panic::ErrorExtPanic; +use err_backtrace::ErrBacktraceExt; + +fn main() { + // Initialize the logger and set the panic handler + init_logger(); + std::panic::set_hook(box panic::log_handler); + + // Get all data from cli + let CliData{ input_filename, output_dir } = CliData::new(); + + let cur_working_dir = std::env::current_dir().expect("No cwd"); + log::info!("cwd: {}", cur_working_dir.display()); + + // Open the game file + let input_file = std::fs::File::open(&input_filename) + .panic_err_msg("Unable to open input file"); + let mut game_file = GameFile::from_reader(input_file) + .panic_err_msg("Unable to parse input file as dcb"); + + // Get the cards table + let cards_table = CardTable::deserialize(&mut game_file) + .panic_err_msg("Unable to create cards table"); + let cards_table_yaml = serde_yaml::to_string(&cards_table) + .panic_err_msg("Unable to serialize cards table"); + log::info!("Extracted {} cards", cards_table.card_count()); + + /* + // Get the decks table + let decks_table = DeckTable::new(&mut game_file) + .panic_err_msg("Unable to create decks table"); + let decks_table_yaml = serde_yaml::to_string(&decks_table) + .panic_err_msg("Unable to serialize decks table"); + log::info!("Extracted {} decks", "[Unknown]"); + */ + + // And output everything to the files + let cards_table_output_filename = output_dir.join("cards.yaml"); + std::fs::write(&cards_table_output_filename, cards_table_yaml) + .map_err(|err| log::warn!("Unable to write output file {}:\n{}", cards_table_output_filename.display(), err.err_backtrace() )) + .ignore(); + /* + let decks_table_output_filename = output_dir.join("decks.yaml"); + std::fs::write(output_dir.join("decks.yaml"), decks_table_yaml) + .map_err(|err| log::warn!("Unable to write output file {}:\n{}", decks_table_output_filename.display(), err.err_backtrace() )) + .ignore(); + */ +} + +/// Initializes the global logger +fn init_logger() { + use simplelog::{CombinedLogger, SharedLogger, TermLogger, WriteLogger, Config, TerminalMode}; + use log::LevelFilter::{Info, Trace}; + use std::convert::identity; + /// The type of logger required to pass to `CombinedLogger::init` + type BoxedLogger = Box; + + // All loggers to try and initialize + let loggers: Vec< Option > = vec![ + TermLogger ::new(Info, Config::default(), TerminalMode::Mixed) + .map(|logger| BoxedLogger::from(logger)), + std::fs::File::create("latest.log").ok() + .map(|file| WriteLogger::new(Trace, Config::default(), file)) + .map(|logger| BoxedLogger::from(logger)) + ]; + + // Filter all logger that actually work and initialize them + CombinedLogger::init( + loggers.into_iter().filter_map(identity).collect() + ).ignore_with_err(|_| log::warn!("Logger was already initialized at the start of the program")); +} diff --git a/src/panic.rs b/src/panic.rs new file mode 100644 index 0000000..595c8ef --- /dev/null +++ b/src/panic.rs @@ -0,0 +1,31 @@ +//! Panic handlers for this application + +// Std +use std::{ + error::Error, + backtrace::{Backtrace, BacktraceStatus}, +}; +// Error backtrace +use err_backtrace::ErrBacktraceExt; + +/// Panic handler based on logging to the current initialization +pub fn log_handler(info: &std::panic::PanicInfo) { + // Log that this thread has panicked + log::error!("Thread \"{}\" panicked", std::thread::current().name().unwrap_or("[Unknown]")); + + // Log any message that came with the panic + log::info!("Panic message: {}", info.message().unwrap_or( &format_args!("None") )); + + // Print an error backtrace if we found any + if let Some(err) = info.payload().downcast_ref::< Box >() { + log::info!("Error backtrace:\n{}", err.err_backtrace()); + } + + // And print a backtrace of where this panic occured. + let backtrace = Backtrace::force_capture(); + if backtrace.status() == BacktraceStatus::Captured { + log::info!("Backtrace:\n{}", backtrace); + } else { + log::info!("Unable to get backtrace: {}", backtrace); + } +}