wip- big refactoring to generalize games
This commit is contained in:
parent
2b5f05deb4
commit
6d66f5e80b
|
@ -14,7 +14,7 @@
|
|||
"cwd": "${workspaceFolder}",
|
||||
"environment": [{
|
||||
"name": "RUST_BACKTRACE",
|
||||
"value": "1"
|
||||
"value": "full"
|
||||
}],
|
||||
"externalConsole": false,
|
||||
},
|
||||
|
|
|
@ -4,8 +4,7 @@ use ferretro::retro::constants::{InputIndex, JoypadButton, AnalogAxis, DeviceTyp
|
|||
use ferretro::retro::wrapped_types::{ControllerDescription2, InputDescriptor2, InputDeviceId, SubsystemInfo2, Variable2};
|
||||
use ferretro::retro::wrapper::LibretroWrapper;
|
||||
|
||||
use ferretro_synced::sync::memory_rw::ReadWriteMemoryMap;
|
||||
use ferretro_synced::sync::pokemon_rb::SyncedPokemonRedBlue;
|
||||
use crate::sync::game::{SyncableGame, KnownGames, read_game_name, create_game};
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::io::Read;
|
||||
|
@ -48,8 +47,8 @@ pub struct MyEmulator {
|
|||
gamepads: Vec<GameController>,
|
||||
pressed_keys: Vec<Keycode>,
|
||||
|
||||
// memory
|
||||
synced_pokemonrb: SyncedPokemonRedBlue,
|
||||
pub memory_map: Option<MemoryMap>,
|
||||
synced_game: Option<Box<dyn SyncableGame>>,
|
||||
}
|
||||
|
||||
impl MyEmulator {
|
||||
|
@ -116,8 +115,11 @@ impl MyEmulator {
|
|||
|
||||
let pressed_keys = Vec::new();
|
||||
|
||||
/*
|
||||
let memory_map = std::default::Default::default();
|
||||
let which_game = read_game_name("whatever");
|
||||
let synced_pokemonrb = SyncedPokemonRedBlue::create(memory_map);
|
||||
*/
|
||||
|
||||
let emu = MyEmulator {
|
||||
retro,
|
||||
|
@ -136,7 +138,8 @@ impl MyEmulator {
|
|||
gamepad_subsys,
|
||||
gamepads,
|
||||
pressed_keys,
|
||||
synced_pokemonrb,
|
||||
memory_map: None,
|
||||
synced_game: None,
|
||||
};
|
||||
let mut pin_emu = Box::pin(emu);
|
||||
retro::wrapper::set_handler(pin_emu.as_mut());
|
||||
|
@ -144,9 +147,12 @@ impl MyEmulator {
|
|||
pin_emu
|
||||
}
|
||||
|
||||
pub fn begin_sync(&mut self, synced_game: Box<dyn SyncableGame>){
|
||||
self.synced_game = Some(synced_game);
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
self.audio_device.resume();
|
||||
self.synced_pokemonrb.start_comms();
|
||||
let mut event_pump = self.sdl_context.event_pump().unwrap();
|
||||
'running: loop {
|
||||
let frame_begin = Instant::now();
|
||||
|
@ -164,6 +170,18 @@ impl MyEmulator {
|
|||
|
||||
self.update_key_state(&event_pump.keyboard_state());
|
||||
|
||||
match &mut self.synced_game {
|
||||
Some(g) => {
|
||||
match g.handle_inbound_messages() {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("Error while handling inbound messages: {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
None => ()
|
||||
}
|
||||
|
||||
// The rest of the game loop goes here...
|
||||
self.retro.run();
|
||||
self.canvas.present();
|
||||
|
@ -174,9 +192,13 @@ impl MyEmulator {
|
|||
spf = 1.0 / 60.0;
|
||||
}
|
||||
|
||||
self.synced_pokemonrb.handle_inbound_msgs();
|
||||
|
||||
self.synced_pokemonrb.update_from_mem();
|
||||
match &mut self.synced_game {
|
||||
Some(g) => {
|
||||
g.update_state();
|
||||
g.send_state_messages();
|
||||
},
|
||||
None => ()
|
||||
}
|
||||
//println!("{}", self.synced_pokemonrb);
|
||||
|
||||
Duration::from_secs_f64(spf)
|
||||
|
@ -410,7 +432,7 @@ impl retro::wrapper::Handler for MyEmulator {
|
|||
}
|
||||
|
||||
fn set_memory_maps(&mut self, memory_map: MemoryMap) -> bool {
|
||||
self.synced_pokemonrb.libretro_set_memory_maps(memory_map);
|
||||
self.memory_map = Some(memory_map);
|
||||
true
|
||||
}
|
||||
}
|
|
@ -1,13 +1,11 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::default::Default;
|
||||
use ferretro::retro::ffi::{MemoryMap};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ReadWriteMemoryMap {
|
||||
regions: Vec<MemoryRegion>,
|
||||
pub struct LibRetroMemoryMap {
|
||||
regions: Vec<LibRetroMemoryRegion>,
|
||||
}
|
||||
|
||||
impl ReadWriteMemoryMap {
|
||||
impl LibRetroMemoryMap {
|
||||
pub fn get_slice_from_region(&self, offset: usize, length: usize, bank_switch: usize) -> Option<&'static mut [u8]> {
|
||||
match self.find_bank(offset, length, bank_switch) {
|
||||
Some(ptr) => Some(unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, length) }),
|
||||
|
@ -36,8 +34,8 @@ impl ReadWriteMemoryMap {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn libretro_set_memory_maps(&mut self, memory_map: MemoryMap) {
|
||||
let mut regions: Vec<MemoryRegion> = Vec::new();
|
||||
pub fn create(memory_map: &MemoryMap) -> Self {
|
||||
let mut regions: Vec<LibRetroMemoryRegion> = Vec::new();
|
||||
let num_descriptors = isize::try_from(memory_map.num_descriptors).unwrap();
|
||||
for i in 0..num_descriptors {
|
||||
let region = unsafe { &*memory_map.descriptors.offset(i) };
|
||||
|
@ -48,18 +46,20 @@ impl ReadWriteMemoryMap {
|
|||
println!("truncating memory region {:x} from size {:x} to {:x} banks of size {:x}", region.start, region.len, region.len/length, length)
|
||||
}
|
||||
|
||||
regions.push(MemoryRegion {
|
||||
regions.push(LibRetroMemoryRegion {
|
||||
start: region.start,
|
||||
end: region.start + length,
|
||||
pointer: region.ptr,
|
||||
})
|
||||
}
|
||||
|
||||
self.regions = regions;
|
||||
LibRetroMemoryMap {
|
||||
regions: regions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MemoryRegion {
|
||||
struct LibRetroMemoryRegion {
|
||||
start: usize,
|
||||
end: usize,
|
||||
pointer: *const std::ffi::c_void,
|
|
@ -0,0 +1,2 @@
|
|||
pub mod emulator;
|
||||
pub mod libretro_memory_map;
|
|
@ -4,4 +4,5 @@ extern crate num;
|
|||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
|
||||
pub mod sync;
|
||||
pub mod sync;
|
||||
pub mod emulator;
|
28
src/main.rs
28
src/main.rs
|
@ -7,18 +7,42 @@ extern crate serde_bytes;
|
|||
use structopt::StructOpt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
mod emulator;
|
||||
use emulator::MyEmulator;
|
||||
use ferretro_synced::emulator::emulator::MyEmulator;
|
||||
use ferretro_synced::emulator::libretro_memory_map::LibRetroMemoryMap;
|
||||
use ferretro_synced::sync::game::{SyncableGame, KnownGames, read_game_name, create_game};
|
||||
use ferretro_synced::sync::comms::CommunicationSettings;
|
||||
|
||||
pub fn main() -> failure::Fallible<()> {
|
||||
let opt: Opt = Opt::from_args();
|
||||
let mut emu = MyEmulator::new(&opt.core, &opt.system);
|
||||
emu.load_game(&opt.rom);
|
||||
|
||||
// memory map should be ready after init & loading game.
|
||||
let ffi_memory_map = emu.memory_map.as_ref().expect("Memory map was not set by emulator core, cannot continue.");
|
||||
let memory_map = LibRetroMemoryMap::create(ffi_memory_map);
|
||||
|
||||
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.")
|
||||
}
|
||||
|
||||
}
|
||||
//let mut comms = Communication::new::<ferretro_synced::sync::pokemon_rb::Message>();
|
||||
|
||||
emu.run();
|
||||
|
|
|
@ -20,15 +20,19 @@ pub struct Communication<T> {
|
|||
outbound_thread: JoinHandle<Result<(), failure::Error>>,
|
||||
}
|
||||
|
||||
pub struct CommunicationSettings {
|
||||
pub connection: String
|
||||
}
|
||||
|
||||
impl<T> Communication<T> where T: std::marker::Send, T: Serialize, T: DeserializeOwned, T: 'static {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(settings: CommunicationSettings) -> Self {
|
||||
let (tx, from_main): (Sender<OwnedMessage>, Receiver<OwnedMessage>) = mpsc::channel();
|
||||
let (to_main, rx): (Sender<T>, Receiver<T>) = mpsc::channel();
|
||||
|
||||
// transmitter for ping and close messages
|
||||
let tx_1 = tx.clone();
|
||||
|
||||
let ws_client = ClientBuilder::new(CONNECTION)
|
||||
let ws_client = ClientBuilder::new(settings.connection.as_str())
|
||||
.unwrap()
|
||||
.add_protocol("rust-websocket")
|
||||
.connect_insecure()
|
||||
|
@ -124,9 +128,4 @@ impl<T> Communication<T> where T: std::marker::Send, T: Serialize, T: Deserializ
|
|||
pub fn try_recv(&mut self) -> Result<T, std::sync::mpsc::TryRecvError> {
|
||||
self.rx.try_recv()
|
||||
}
|
||||
}
|
||||
|
||||
struct WebsocketClient<T> {
|
||||
thread_tx: Sender<T>,
|
||||
thread_rx: Receiver<T>,
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use crate::sync::pokemon_rb::SyncedPokemonRedBlue;
|
||||
use crate::sync::comms::CommunicationSettings;
|
||||
use crate::emulator::libretro_memory_map::LibRetroMemoryMap;
|
||||
|
||||
pub trait SyncableGame {
|
||||
// Update internal state based on tracked memory and the emulator
|
||||
fn update_state(&mut self);
|
||||
|
||||
// Check for messages and handle them
|
||||
fn handle_inbound_messages(&mut self) -> Result<(), failure::Error>;
|
||||
|
||||
// Check for messages and handle them
|
||||
fn send_state_messages(&mut self) -> Result<(), failure::Error>;
|
||||
}
|
||||
|
||||
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 create_game(which_game: KnownGames, comms_settings: CommunicationSettings, memory_map: &LibRetroMemoryMap) -> Box<dyn SyncableGame> {
|
||||
match which_game {
|
||||
KnownGames::PokemonRedBlue => Box::from(SyncedPokemonRedBlue::create(comms_settings, memory_map))
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
use crate::emulator::libretro_memory_map::LibRetroMemoryMap;
|
||||
|
||||
pub struct MemorySliceHandle<'a> {
|
||||
pub offset: usize,
|
||||
pub length: usize,
|
||||
pub bank_switch: usize,
|
||||
pub slice: Option<&'a mut [u8]>,
|
||||
pub last_read_value: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl MemorySliceHandle<'_> {
|
||||
pub fn create(offset: usize, length: usize, bank_switch: usize, memory_map: &LibRetroMemoryMap) -> Self {
|
||||
let slice = memory_map.get_slice_from_region(offset, length, bank_switch);
|
||||
|
||||
MemorySliceHandle {
|
||||
offset: offset,
|
||||
length: length,
|
||||
bank_switch: bank_switch,
|
||||
slice,
|
||||
last_read_value: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_copy_if_changed_since_last_read(&mut self) -> Option<Vec<u8>> {
|
||||
match &mut self.slice {
|
||||
None => None,
|
||||
Some(data) => match &mut self.last_read_value {
|
||||
None => {
|
||||
// last read value isn't allocated yet
|
||||
let last = data.to_vec();
|
||||
self.last_read_value = Some(last);
|
||||
self.last_read_value.clone()
|
||||
},
|
||||
Some(last) => {
|
||||
let mut index: usize = 0;
|
||||
let mut any_changes = false;
|
||||
|
||||
for value in data.into_iter() {
|
||||
if last[index] != *value {
|
||||
last[index] = *value;
|
||||
any_changes = true;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if any_changes {
|
||||
return Some(last.clone());
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod pokemon_rb;
|
||||
pub mod memory_rw;
|
||||
pub mod comms;
|
||||
pub mod comms;
|
||||
pub mod memory_slice_handle;
|
||||
pub mod game;
|
|
@ -1,181 +1,77 @@
|
|||
use std::default::Default;
|
||||
use std::fmt::Display;
|
||||
use crate::sync::memory_rw::ReadWriteMemoryMap;
|
||||
use crate::emulator::libretro_memory_map::LibRetroMemoryMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use ferretro::retro::wrapper::LibretroWrapper; // want LibretroWrapper.api : LibretroApi.get_memory()
|
||||
use crate::num::ToPrimitive;
|
||||
use crate::sync::comms::Communication;
|
||||
use crate::sync::comms::CommunicationSettings;
|
||||
use crate::sync::memory_slice_handle::MemorySliceHandle;
|
||||
use crate::sync::game::SyncableGame;
|
||||
|
||||
pub struct SyncedPokemonRedBlue {
|
||||
raw: Raw<'static>,
|
||||
memory_handles: PokemonRedBlueMemoryHandles<'static>,
|
||||
battle_context: BattleContext,
|
||||
comms: Option<Communication<Message>>
|
||||
comms: Communication<PokemonRedBlueMessage>
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Message {
|
||||
pub struct PokemonRedBlueMessage {
|
||||
active_pkmn: Option<Vec<u8>>
|
||||
}
|
||||
|
||||
impl From<&mut Raw<'_>> for Message {
|
||||
fn from(src: &mut Raw) -> Self {
|
||||
Message {
|
||||
active_pkmn: src.active_pokemon_raw.get_copy_if_changed_since_last_read()
|
||||
impl From<&mut PokemonRedBlueMemoryHandles<'_>> for PokemonRedBlueMessage {
|
||||
fn from(src: &mut PokemonRedBlueMemoryHandles) -> Self {
|
||||
PokemonRedBlueMessage {
|
||||
active_pkmn: src.active_pokemon.get_copy_if_changed_since_last_read()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct Raw<'a> {
|
||||
active_pokemon_raw: EmulatorMemory<'a>,
|
||||
player_and_party: EmulatorMemory<'a>,
|
||||
pokemon_out: EmulatorMemory<'a>,
|
||||
pub memory_map: ReadWriteMemoryMap,
|
||||
}
|
||||
|
||||
struct EmulatorMemory<'a> {
|
||||
offset: usize,
|
||||
length: usize,
|
||||
bank_switch: usize,
|
||||
pub slice: Option<&'a mut [u8]>,
|
||||
last_read_value: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl EmulatorMemory<'_> {
|
||||
pub fn update_slice(&mut self, map: &ReadWriteMemoryMap) {
|
||||
self.slice = map.get_slice_from_region(self.offset, self.length, self.bank_switch);
|
||||
}
|
||||
|
||||
pub fn get_copy_if_changed_since_last_read(&mut self) -> Option<Vec<u8>> {
|
||||
match &mut self.slice {
|
||||
None => None,
|
||||
Some(data) => match &mut self.last_read_value {
|
||||
None => {
|
||||
// last read value isn't allocated yet
|
||||
let mut last = vec![0; data.len()];
|
||||
last.copy_from_slice(data);
|
||||
self.last_read_value = Some(last);
|
||||
self.last_read_value.clone()
|
||||
},
|
||||
Some(last) => {
|
||||
let mut index: usize = 0;
|
||||
let mut any_changes = false;
|
||||
|
||||
for value in data.into_iter() {
|
||||
if last[index] != *value {
|
||||
last[index] = *value;
|
||||
any_changes = true;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if any_changes {
|
||||
return Some(last.clone());
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
struct PokemonRedBlueMemoryHandles<'a> {
|
||||
active_pokemon: MemorySliceHandle<'a>,
|
||||
player_and_party: MemorySliceHandle<'a>,
|
||||
pokemon_out: MemorySliceHandle<'a>,
|
||||
}
|
||||
|
||||
struct BattleContext {
|
||||
active_pokemon: Pokemon,
|
||||
}
|
||||
|
||||
|
||||
impl SyncedPokemonRedBlue {
|
||||
pub fn update_from_mem(&mut self) {
|
||||
impl SyncableGame for SyncedPokemonRedBlue {
|
||||
fn update_state(&mut self) {
|
||||
let battle_context = BattleContext {
|
||||
active_pokemon: match &self.raw.active_pokemon_raw.slice {
|
||||
active_pokemon: match &self.memory_handles.active_pokemon.slice {
|
||||
Some(d) => num::FromPrimitive::from_u8(d[0xB]).unwrap_or(Pokemon::Unknown),
|
||||
None => Pokemon::Unknown
|
||||
}
|
||||
};
|
||||
|
||||
// test to see that we can indeed write back to the slice
|
||||
// match self.raw.active_pokemon_raw.get_slice(mem){
|
||||
// Some(s) => {
|
||||
// s[0xD] = 69
|
||||
// },
|
||||
// _ => ()
|
||||
// }
|
||||
|
||||
self.battle_context = battle_context;
|
||||
}
|
||||
|
||||
let message: Message = (&mut self.raw).into();
|
||||
|
||||
match &mut self.comms {
|
||||
Some(comms) => {
|
||||
comms.send(message);
|
||||
},
|
||||
None => ()
|
||||
fn send_state_messages(&mut self) -> Result<(), failure::Error>{
|
||||
let message: PokemonRedBlueMessage = (&mut self.memory_handles).into();
|
||||
if !message.active_pkmn.is_none() {
|
||||
self.comms.send(message)
|
||||
}
|
||||
else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_inbound_msgs(&mut self) -> Result<(), failure::Error>{
|
||||
let in_msg = self.comms.as_mut().ok_or(failure::err_msg("comms doesn't exist, can't handle inbound msgs"))?.try_recv()?;
|
||||
fn handle_inbound_messages(&mut self) -> Result<(), failure::Error>{
|
||||
let in_msg = self.comms.try_recv()?;
|
||||
self.handle_message(in_msg)
|
||||
}
|
||||
|
||||
fn handle_message(&mut self, msg: Message) -> Result<(), failure::Error> {
|
||||
match msg.active_pkmn {
|
||||
Some(src) => {
|
||||
println!("message contains a new active pokemon. data: {:?}", &src);
|
||||
let target_slice = self.raw.active_pokemon_raw.slice.as_mut().ok_or(failure::err_msg("can't write message back to None memory slice"))?;
|
||||
if src.len() != target_slice.len() {
|
||||
return Err(failure::err_msg("message size and slice size differ."));
|
||||
}
|
||||
|
||||
let mut index: usize = 0;
|
||||
for value in src.into_iter(){
|
||||
target_slice[index] = value;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
||||
None => Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// pub fn get_message<'a>(&self) -> Message {
|
||||
// Message {
|
||||
// active_pkmn: Box::from(&self.raw.active_pokemon_raw.clone())
|
||||
// }
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
impl Raw<'_> {
|
||||
pub fn create(map: ReadWriteMemoryMap) -> Self {
|
||||
Raw {
|
||||
active_pokemon_raw: EmulatorMemory {
|
||||
offset: 0xd009,
|
||||
length: 0x27,
|
||||
bank_switch: 0,
|
||||
slice: None,
|
||||
last_read_value: None,
|
||||
},
|
||||
player_and_party: EmulatorMemory {
|
||||
offset: 0xd158,
|
||||
length: 0x19e,
|
||||
bank_switch: 0,
|
||||
slice: None,
|
||||
last_read_value: None,
|
||||
},
|
||||
pokemon_out: EmulatorMemory {
|
||||
offset: 0xcc2f,
|
||||
length: 0x1,
|
||||
bank_switch: 0,
|
||||
slice: None,
|
||||
last_read_value: None,
|
||||
},
|
||||
memory_map: map
|
||||
impl PokemonRedBlueMemoryHandles<'_> {
|
||||
pub fn create(memory_map: &LibRetroMemoryMap) -> Self {
|
||||
PokemonRedBlueMemoryHandles {
|
||||
active_pokemon: MemorySliceHandle::create(0xd009, 0x27, 0, memory_map),
|
||||
player_and_party: MemorySliceHandle::create(0xd158, 0x19e, 0, memory_map),
|
||||
pokemon_out: MemorySliceHandle::create(0xcc2f, 0x1, 0, memory_map),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,31 +91,34 @@ impl Display for SyncedPokemonRedBlue {
|
|||
}
|
||||
|
||||
impl SyncedPokemonRedBlue {
|
||||
pub fn create(map: ReadWriteMemoryMap) -> Self {
|
||||
pub fn create(comms_settings: CommunicationSettings, memory_map: &LibRetroMemoryMap) -> Self {
|
||||
SyncedPokemonRedBlue {
|
||||
raw: Raw::create(map),
|
||||
memory_handles: PokemonRedBlueMemoryHandles::create(memory_map),
|
||||
battle_context: BattleContext::default(),
|
||||
comms: None,
|
||||
comms: Communication::new(comms_settings),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn libretro_set_memory_maps(&mut self, libretro_memory_map: ferretro::retro::ffi::MemoryMap) {
|
||||
self.raw.libretro_set_memory_maps(libretro_memory_map)
|
||||
}
|
||||
fn handle_message(&mut self, msg: PokemonRedBlueMessage) -> Result<(), failure::Error> {
|
||||
match msg.active_pkmn {
|
||||
Some(src) => {
|
||||
println!("message contains a new active pokemon. data: {:?}", &src);
|
||||
let target_slice = self.memory_handles.active_pokemon.slice.as_mut().ok_or(failure::err_msg("can't write message back to None memory slice"))?;
|
||||
if src.len() != target_slice.len() {
|
||||
return Err(failure::err_msg("message size and slice size differ."));
|
||||
}
|
||||
|
||||
pub fn start_comms(&mut self) {
|
||||
self.comms = Some(Communication::new());
|
||||
}
|
||||
}
|
||||
let mut index: usize = 0;
|
||||
for value in src.into_iter(){
|
||||
target_slice[index] = value;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
impl Raw<'_> {
|
||||
pub fn libretro_set_memory_maps(&mut self, libretro_memory_map: ferretro::retro::ffi::MemoryMap) {
|
||||
self.memory_map.libretro_set_memory_maps(libretro_memory_map);
|
||||
Ok(())
|
||||
|
||||
// update our slices
|
||||
self.active_pokemon_raw.update_slice(&self.memory_map);
|
||||
self.player_and_party.update_slice(&self.memory_map);
|
||||
self.pokemon_out.update_slice(&self.memory_map);
|
||||
}
|
||||
None => Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,8 +283,8 @@ mod tests {
|
|||
use super::*;
|
||||
use serde_json;
|
||||
|
||||
fn build_message(em: &EmulatorMemory) -> Message {
|
||||
Message {
|
||||
fn build_message(em: &MemorySliceHandle) -> PokemonRedBlueMessage {
|
||||
PokemonRedBlueMessage {
|
||||
active_pkmn: match &em.slice {
|
||||
Some(m) => Some(m.to_vec()),
|
||||
None => None
|
||||
|
@ -397,11 +296,12 @@ mod tests {
|
|||
fn serde_mem() -> Result<(), String> {
|
||||
let mut data: [u8; 5] = [1, 2, 3, 4, 5];
|
||||
let b: &mut [u8] = &mut data;
|
||||
let slice = EmulatorMemory {
|
||||
let slice = MemorySliceHandle {
|
||||
offset: 0,
|
||||
length: 0,
|
||||
bank_switch: 0,
|
||||
slice: Some(b),
|
||||
last_read_value: None
|
||||
};
|
||||
|
||||
let message = build_message(&slice);
|
||||
|
@ -410,7 +310,7 @@ mod tests {
|
|||
|
||||
println!("serialized data: {}", serialized);
|
||||
|
||||
let deserialized: Message = serde_json::from_str(&serialized).unwrap();
|
||||
let deserialized: PokemonRedBlueMessage = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
assert_eq!(deserialized.active_pkmn.unwrap()[0], data[0]);
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in New Issue