Handle multiple games by reading their metadata
This commit is contained in:
parent
ccc3f16491
commit
6889711f5b
|
@ -8,6 +8,11 @@ dependencies = [
|
|||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.13"
|
||||
|
@ -204,6 +209,7 @@ dependencies = [
|
|||
name = "ferretro-synced"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ascii 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1353,6 +1359,7 @@ dependencies = [
|
|||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum ascii 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
|
||||
|
|
|
@ -21,5 +21,6 @@ serde = { version = "1.0.104", features = ["derive"] }
|
|||
serde_bytes = "0.11"
|
||||
serde_json = "1.0.44"
|
||||
websocket = "0.24.0"
|
||||
ascii = "1.0.0"
|
||||
|
||||
[dev-dependencies]
|
|
@ -6,6 +6,7 @@ use ferretro::retro::wrapper::LibretroWrapper;
|
|||
|
||||
use crate::sync::game::{SyncableGame, KnownGames, read_game_name, create_game};
|
||||
use crate::emulator::libretro_memory_map::LibRetroMemoryMap;
|
||||
use crate::emulator::metadata_reader::{GameInfo, get_game_info};
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io::Read;
|
||||
|
@ -30,6 +31,7 @@ pub struct MyEmulator {
|
|||
|
||||
sys_info: SystemInfo,
|
||||
av_info: SystemAvInfo,
|
||||
pub game_info: Option<GameInfo>,
|
||||
|
||||
sdl_context: sdl2::Sdl,
|
||||
|
||||
|
@ -129,6 +131,7 @@ impl MyEmulator {
|
|||
preferred_pad: None,
|
||||
av_info,
|
||||
sys_info,
|
||||
game_info: None,
|
||||
sdl_context,
|
||||
canvas,
|
||||
pixel_format,
|
||||
|
@ -208,17 +211,31 @@ impl MyEmulator {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load_game(&self, rom: impl AsRef<Path>) {
|
||||
pub fn load_game(&mut self, rom: impl AsRef<Path>) {
|
||||
let path = rom.as_ref();
|
||||
let mut data = None;
|
||||
let mut v = Vec::new();
|
||||
if !self.sys_info.need_fullpath {
|
||||
if let Ok(mut f) = std::fs::File::open(path) {
|
||||
if f.read_to_end(&mut v).is_ok() {
|
||||
data = Some(v.as_ref());
|
||||
}
|
||||
|
||||
if let Ok(mut f) = std::fs::File::open(path) {
|
||||
if f.read_to_end(&mut v).is_ok() {
|
||||
data = Some(v.as_ref());
|
||||
|
||||
let library_name = unsafe { CStr::from_ptr(self.sys_info.library_name) }.to_string_lossy();
|
||||
|
||||
self.game_info = match get_game_info(library_name.as_ref(), v.as_ref()) {
|
||||
Ok(game_info) => Some(game_info),
|
||||
Err(e) => {
|
||||
println!("Couldn't get game metadata: {:?}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if self.sys_info.need_fullpath { // this core will load the rom itself, so don't pass it data
|
||||
data = None
|
||||
}
|
||||
|
||||
self.retro
|
||||
.load_game(Some(path), data, None)
|
||||
.unwrap();
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
use ascii::AsAsciiStr;
|
||||
|
||||
pub enum GamePlatform {
|
||||
GameBoyColor,
|
||||
SuperNintendo,
|
||||
Genesis
|
||||
}
|
||||
|
||||
pub struct GameInfo {
|
||||
pub platform: GamePlatform,
|
||||
pub core_name: String,
|
||||
pub game_name: String,
|
||||
}
|
||||
|
||||
fn core_to_platform(core_name: &str) -> GamePlatform {
|
||||
match core_name.to_lowercase().as_str() {
|
||||
"gambatte" => GamePlatform::GameBoyColor,
|
||||
"bsnes" => GamePlatform::SuperNintendo,
|
||||
"genesis plus gx" => GamePlatform::Genesis,
|
||||
"higan (super famicom accuracy)" => GamePlatform::SuperNintendo,
|
||||
_ => panic!(format!("unknown core {}", core_name))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_game_info(core_name: &str, data: &[u8]) -> Result<GameInfo, failure::Error> {
|
||||
let platform = core_to_platform(&core_name);
|
||||
|
||||
let game_name = match &platform {
|
||||
GamePlatform::GameBoyColor => data.slice_ascii(0x134..0x143)?.to_string()
|
||||
.trim_end_matches("\0").to_string(), // remove nulls at end
|
||||
|
||||
GamePlatform::SuperNintendo => data.slice_ascii(0x7fc0..0x7fd5)?.to_string()
|
||||
.trim_end_matches("\0").to_string(), // remove nulls at end
|
||||
|
||||
GamePlatform::Genesis => data.slice_ascii(0x120..0x150)?.to_string()
|
||||
.split(" ")
|
||||
.filter(|w| w.len() > 0)
|
||||
.collect::<Vec<&str>>()
|
||||
.join(" "), // remove duplicate spaces
|
||||
};
|
||||
|
||||
Ok(GameInfo {
|
||||
platform,
|
||||
core_name: String::from(core_name),
|
||||
game_name,
|
||||
})
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod emulator;
|
||||
pub mod libretro_memory_map;
|
||||
pub mod libretro_memory_map;
|
||||
pub mod metadata_reader;
|
36
src/main.rs
36
src/main.rs
|
@ -1,8 +1,10 @@
|
|||
#[macro_use] extern crate failure;
|
||||
extern crate crossbeam_channel;
|
||||
extern crate ferretro;
|
||||
extern crate sdl2;
|
||||
extern crate serde;
|
||||
extern crate serde_bytes;
|
||||
extern crate ascii;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -18,37 +20,45 @@ pub fn main() -> failure::Fallible<()> {
|
|||
emu.load_game(&opt.rom);
|
||||
|
||||
// memory map should be ready after init & loading game.
|
||||
let memory_map = emu.memory_map.as_ref().expect("Memory map was not set by emulator core, cannot continue.");
|
||||
//let memory_map = emu.memory_map.as_ref().expect("Memory map was not set by emulator core, cannot continue.");
|
||||
|
||||
match (&opt.state) {
|
||||
Some(s) => emu.load_state(s),
|
||||
None => ()
|
||||
}
|
||||
|
||||
let which_game = read_game_name("assume you can get it from emu".to_string());
|
||||
|
||||
let comms_settings = CommunicationSettings {
|
||||
connection: "ws://127.0.0.1:8765".to_string()
|
||||
};
|
||||
|
||||
match which_game {
|
||||
Some(which_game) => {
|
||||
let synced_game = create_game(which_game, comms_settings, &memory_map);
|
||||
|
||||
emu.begin_sync(synced_game);
|
||||
},
|
||||
None => {
|
||||
println!("Game is unknown, not syncing.")
|
||||
}
|
||||
|
||||
if let Err(e) = attempt_to_start_sync(&mut emu, comms_settings) {
|
||||
println!("Error trying to start sync: {:?}", e);
|
||||
}
|
||||
//let mut comms = Communication::new::<ferretro_synced::sync::pokemon_rb::Message>();
|
||||
|
||||
emu.run();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn attempt_to_start_sync(emu: &mut MyEmulator, comms_settings: CommunicationSettings) -> Result<(), failure::Error> {
|
||||
match &emu.game_info {
|
||||
Some(game_info) => match read_game_name(&game_info.game_name) {
|
||||
Some(which_game) => match &emu.memory_map {
|
||||
Some(memory_map) => {
|
||||
let synced_game = create_game(which_game, comms_settings, memory_map);
|
||||
emu.begin_sync(synced_game);
|
||||
Ok(())
|
||||
},
|
||||
None => Err(format_err!("Memory map has not been set"))
|
||||
},
|
||||
None => Err(format_err!("Unrecognized game {}", game_info.game_name))
|
||||
},
|
||||
None => Err(format_err!("Couldn't get game metadata"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
struct Opt {
|
||||
/// Core module to use.
|
||||
|
|
|
@ -17,8 +17,11 @@ pub enum KnownGames {
|
|||
PokemonRedBlue,
|
||||
}
|
||||
|
||||
pub fn read_game_name(name: String) -> Option<KnownGames> {
|
||||
Some(KnownGames::PokemonRedBlue) // todo: actually read the name of the game
|
||||
pub fn read_game_name(name: &str) -> Option<KnownGames> {
|
||||
match name {
|
||||
"POKEMON BLUE" => Some(KnownGames::PokemonRedBlue),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue