diff --git a/ferretro_components/examples/multifunction_emulator.rs b/ferretro_components/examples/multifunction_emulator.rs index e3b18eb..f3ea608 100644 --- a/ferretro_components/examples/multifunction_emulator.rs +++ b/ferretro_components/examples/multifunction_emulator.rs @@ -35,7 +35,10 @@ struct Opt { /// Disable OpenGL context creation. #[structopt(long)] no_opengl: bool, - /// Trace all API calls. + /// Print core-provided system information to stderr. + #[structopt(long)] + sys_info: bool, + /// Trace all API calls to stderr. #[structopt(long)] trace_api: bool, } @@ -51,6 +54,10 @@ pub fn main() -> Result<(), Box> { stderr_log.prefix = "{log} ".to_string(); emu.register_component(stderr_log)?; + let mut stderr_msg = StderrMessageComponent::default(); + stderr_msg.prefix = "{message} ".to_string(); + emu.register_component(stderr_msg)?; + if opt.trace_api { emu.register_component(StderrCallTraceComponent { prefix: "{trace} ".to_string() })?; } @@ -94,6 +101,19 @@ pub fn main() -> Result<(), Box> { emu.register_component(LocalFileSaveComponent::default())?; + if opt.sys_info { + emu.register_component(StderrSysInfoLogComponent::default())?; + } + + let mut variables = VariableStoreComponent::default(); + // TODO: load a config file specified on the CLI + variables.insert("mgba_skip_bios", "ON"); + variables.insert("gpsp_drc", "enabled"); + variables.insert("gpsp_frameskip", "auto"); + variables.insert("gpsp_frame_mixing", "enabled"); + variables.insert("gpsp_save_method", "libretro"); + emu.register_component(variables)?; + emu.init()?; emu.load_game(&opt.rom)?; if let Some(state) = opt.state { diff --git a/ferretro_components/src/provided/stdlib/mod.rs b/ferretro_components/src/provided/stdlib/mod.rs index 364b8b8..bc502b0 100644 --- a/ferretro_components/src/provided/stdlib/mod.rs +++ b/ferretro_components/src/provided/stdlib/mod.rs @@ -4,7 +4,7 @@ mod camera; mod fps; mod input; -mod logs; +mod print; mod memory; mod paths; mod saves; @@ -13,9 +13,7 @@ mod variables; pub use camera::CameraInfoComponent; pub use fps::SleepFramerateLimitComponent; pub use input::StatefulInputComponent; -pub use logs::StderrCallTraceComponent; -pub use logs::StderrLogComponent; -pub use logs::StderrSysInfoLogComponent; pub use paths::PathBufComponent; +pub use print::*; pub use saves::LocalFileSaveComponent; pub use variables::VariableStoreComponent; diff --git a/ferretro_components/src/provided/stdlib/print/log.rs b/ferretro_components/src/provided/stdlib/print/log.rs new file mode 100644 index 0000000..fd4b32f --- /dev/null +++ b/ferretro_components/src/provided/stdlib/print/log.rs @@ -0,0 +1,28 @@ +use crate::prelude::*; + +/// Write's the core's own log statements to stderr. +pub struct StderrLogComponent { + /// May be set to add a prefix to each logged line. + pub prefix: String, + /// The most verbose log level that should be printed. + pub level: ferretro_base::retro::ffi::LogLevel, +} + +impl Default for StderrLogComponent { + fn default() -> Self { + StderrLogComponent { + prefix: String::new(), + level: ferretro_base::retro::ffi::LogLevel::Info, + } + } +} + +impl RetroComponent for StderrLogComponent {} + +impl RetroCallbacks for StderrLogComponent { + fn log_print(&mut self, level: ferretro_base::retro::ffi::LogLevel, msg: &str) { + if level >= self.level { + eprint!("{}[{:?}] {}", self.prefix, level, msg); + } + } +} diff --git a/ferretro_components/src/provided/stdlib/print/message.rs b/ferretro_components/src/provided/stdlib/print/message.rs new file mode 100644 index 0000000..fc6e90a --- /dev/null +++ b/ferretro_components/src/provided/stdlib/print/message.rs @@ -0,0 +1,27 @@ +use std::ffi::CStr; +use ferretro_base::retro::ffi::Message; +use crate::prelude::*; + +/// Write's the core's "temporary" messages to stderr. +pub struct StderrMessageComponent { + /// May be set to add a prefix to each logged line. + pub prefix: String, +} + +impl Default for StderrMessageComponent { + fn default() -> Self { + StderrMessageComponent { + prefix: String::new(), + } + } +} + +impl RetroComponent for StderrMessageComponent {} + +impl RetroCallbacks for StderrMessageComponent { + fn set_message(&mut self, message: &Message) -> Option { + let cstr = unsafe { CStr::from_ptr(message.msg) }; + eprintln!("{}", cstr.to_string_lossy()); + Some(true) + } +} diff --git a/ferretro_components/src/provided/stdlib/print/mod.rs b/ferretro_components/src/provided/stdlib/print/mod.rs new file mode 100644 index 0000000..a76035e --- /dev/null +++ b/ferretro_components/src/provided/stdlib/print/mod.rs @@ -0,0 +1,9 @@ +mod log; +mod message; +mod sysinfo; +mod trace; + +pub use log::StderrLogComponent; +pub use message::StderrMessageComponent; +pub use sysinfo::StderrSysInfoLogComponent; +pub use trace::StderrCallTraceComponent; diff --git a/ferretro_components/src/provided/stdlib/print/sysinfo.rs b/ferretro_components/src/provided/stdlib/print/sysinfo.rs new file mode 100644 index 0000000..85e4fbc --- /dev/null +++ b/ferretro_components/src/provided/stdlib/print/sysinfo.rs @@ -0,0 +1,55 @@ +use std::path::Path; +use crate::prelude::*; + +/// Writes all the input descriptors, variables, and subsystem information to stderr as they are +/// provided by the core. +#[derive(Default)] +pub struct StderrSysInfoLogComponent { + /// May be set to add a prefix to each logged line. + pub prefix: String, +} + +impl RetroComponent for StderrSysInfoLogComponent { + fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> crate::base::Result<()> { + self.set_system_av_info(&retro.get_system_av_info()); + Ok(()) + } +} + +impl RetroCallbacks for StderrSysInfoLogComponent { + fn set_memory_maps(&mut self, memory_map: &MemoryMap) -> Option { + eprintln!("{}{:?}", self.prefix, memory_map); + Some(true) + } + + fn set_geometry(&mut self, game_geometry: &GameGeometry) -> Option { + eprintln!("{}{:?}", self.prefix, game_geometry); + Some(true) + } + + fn set_system_av_info(&mut self, system_av_info: &SystemAvInfo) -> Option { + eprintln!("{}{:?}", self.prefix, system_av_info); + Some(true) + } + + fn set_input_descriptors(&mut self, descriptors: &[InputDescriptor2]) -> Option { + for id in descriptors { + eprintln!("{}{:?}", self.prefix, id); + } + Some(true) + } + + fn set_variables(&mut self, variables: &[Variable2]) -> Option { + for v in variables { + eprintln!("{}{:?}", self.prefix, v); + } + Some(true) + } + + fn set_subsystem_info(&mut self, subsystem_info: &[SubsystemInfo2]) -> Option { + for s in subsystem_info { + eprintln!("{}{:?}", self.prefix, s); + } + Some(true) + } +} diff --git a/ferretro_components/src/provided/stdlib/logs.rs b/ferretro_components/src/provided/stdlib/print/trace.rs similarity index 75% rename from ferretro_components/src/provided/stdlib/logs.rs rename to ferretro_components/src/provided/stdlib/print/trace.rs index f919b25..23093ce 100644 --- a/ferretro_components/src/provided/stdlib/logs.rs +++ b/ferretro_components/src/provided/stdlib/print/trace.rs @@ -5,67 +5,7 @@ use ferretro_base::retro::ffi::{Message, Language}; use std::os::raw::c_uint; use std::path::PathBuf; -/// Write's the core's own log statements to stderr. -pub struct StderrLogComponent { - /// May be set to add a prefix to each logged line. - pub prefix: String, - /// The most verbose log level that should be printed. - pub level: ferretro_base::retro::ffi::LogLevel, -} - -impl Default for StderrLogComponent { - fn default() -> Self { - StderrLogComponent { - prefix: String::new(), - level: ferretro_base::retro::ffi::LogLevel::Info, - } - } -} - -impl RetroComponent for StderrLogComponent {} - -impl RetroCallbacks for StderrLogComponent { - fn log_print(&mut self, level: ferretro_base::retro::ffi::LogLevel, msg: &str) { - if level >= self.level { - eprint!("{}[{:?}] {}", self.prefix, level, msg); - } - } -} - -/// Writes all the input descriptors, variables, and subsystem information to stderr as they are -/// provided by the core. -#[derive(Default)] -pub struct StderrSysInfoLogComponent { - /// May be set to add a prefix to each logged line. - pub prefix: String, -} - -impl RetroComponent for StderrSysInfoLogComponent {} - -impl RetroCallbacks for StderrSysInfoLogComponent { - fn set_input_descriptors(&mut self, descriptors: &[InputDescriptor2]) -> Option { - for id in descriptors { - eprintln!("{}{:?}", self.prefix, id); - } - Some(true) - } - - fn set_variables(&mut self, variables: &[Variable2]) -> Option { - for v in variables { - eprintln!("{}{:?}", self.prefix, v); - } - Some(true) - } - - fn set_subsystem_info(&mut self, subsystem_info: &[SubsystemInfo2]) -> Option { - for s in subsystem_info { - eprintln!("{}{:?}", self.prefix, s); - } - Some(true) - } -} - -/// Trace-logs every callback call made and their arguments to stderr. +/// Trace-print every callback call made and their arguments to stderr. #[derive(Default)] pub struct StderrCallTraceComponent { /// May be set to add a prefix to each logged line. diff --git a/ferretro_components/src/provided/stdlib/saves.rs b/ferretro_components/src/provided/stdlib/saves.rs index dc23cb5..589c827 100644 --- a/ferretro_components/src/provided/stdlib/saves.rs +++ b/ferretro_components/src/provided/stdlib/saves.rs @@ -13,7 +13,7 @@ pub struct LocalFileSaveComponent { impl LocalFileSaveComponent { fn save_path(&self) -> PathBuf { - self.rom_path.with_extension(".sav") + self.rom_path.with_extension("sav") } } @@ -22,7 +22,7 @@ impl RetroComponent for LocalFileSaveComponent { self.rom_path = rom.to_path_buf(); let save = self.save_path(); if save.is_file() { - File::open(save)?.read(retro.mut_memory(MEMORY_SAVE_RAM))?; + File::open(&save)?.read(retro.mut_memory(MEMORY_SAVE_RAM))?; } self.initial_sram = retro.get_memory(MEMORY_SAVE_RAM).to_vec(); Ok(()) @@ -32,8 +32,13 @@ impl RetroComponent for LocalFileSaveComponent { let final_sram = retro.get_memory(MEMORY_SAVE_RAM); if &self.initial_sram != final_sram { let save = self.save_path(); - if let Ok(mut f) = File::create(save) { - let _ = f.write(final_sram); + match File::create(&save) { + Ok(mut f) => if let Err(e) = f.write(final_sram) { + eprintln!("Couldn't write save to {:?}: {:?}", save, e); + } + Err(e) => { + eprintln!("Couldn't (over)write {:?}: {:?}", save, e); + } } } }