more cleanup, send entire sonic data each frame instead of diffs

This commit is contained in:
Vivian Lim 2020-03-16 01:01:29 -07:00
parent 419e97af23
commit e33275e65d
7 changed files with 90 additions and 31 deletions

View File

@ -181,7 +181,14 @@ impl MyEmulator {
match g.handle_inbound_messages() {
Ok(_) => (),
Err(e) => {
println!("Error while handling inbound messages");
println!("Error while handling inbound messages {}", e);
}
}
match g.update_state() {
Ok(_) => (),
Err(e) => {
println!("Error while updating pre-frame state {}", e);
}
}
},
@ -200,8 +207,10 @@ impl MyEmulator {
match &mut self.synced_game {
Some(g) => {
g.update_state();
g.send_state_messages();
match g.send_state_messages() {
Ok(_) => (),
Err(e) => println!("Error while sending messages post-frame {}", e)
}
},
None => ()
}

View File

@ -6,7 +6,7 @@ use failure::{Error, format_err};
pub trait SyncableGame {
// Update internal state based on tracked memory and the emulator
fn update_state(&mut self);
fn update_state(&mut self) -> Result<(), failure::Error>;
// Check for messages and handle them
fn handle_inbound_messages(&mut self) -> Result<(), failure::Error>;

View File

@ -1,20 +1,32 @@
use failure::{Error, format_err};
pub trait CopyFromMemory<T> {
fn copy_from_memory(&self) -> T;
fn write_back(&mut self, source: T);
fn copy_from_memory(&self) -> Result<T, Error>;
fn write_back(&mut self, source: T) -> Result<(), Error>;
}
impl CopyFromMemory<[u8; 2]> for &'static mut [u8] {
fn copy_from_memory(&self) -> [u8; 2] {
fn copy_from_memory(&self) -> Result<[u8; 2], Error> {
let mut result = [0, 0];
if self.len() != result.len() {
return Err(format_err!("Source ({}) and destination ({}) lengths differ", self.len(), result.len()));
}
for i in 0..result.len() {
result[i] = self[i];
}
result
Ok(result)
}
fn write_back(&mut self, source: [u8; 2]) {
fn write_back(&mut self, source: [u8; 2]) -> Result<(), Error> {
if source.len() != self.len() {
return Err(format_err!("Source ({}) and destination ({}) lengths differ", source.len(), self.len()));
}
for i in 0..source.len() {
self[i] = source[i];
}
Ok(())
}
}

View File

@ -40,12 +40,13 @@ struct BattleContext {
}
impl SyncableGame for SyncedPokemonRedBlue {
fn update_state(&mut self) {
fn update_state(&mut self) -> Result<(), failure::Error> {
let battle_context = BattleContext {
active_pokemon: num::FromPrimitive::from_u8(self.memory_handles.active_pokemon.slice[0xB]).unwrap_or(Pokemon::Unknown),
};
self.battle_context = battle_context;
Ok(())
}
fn send_state_messages(&mut self) -> Result<(), failure::Error>{

View File

@ -19,7 +19,7 @@ use std::result::Result;
pub struct SyncedSonic2 {
memory_handles: Sonic2MemoryHandles,
comms: Communication<Sonic2Message>
comms: Communication<Sonic2Message>,
}
#[derive(Serialize, Deserialize)]
@ -36,9 +36,9 @@ impl TryFrom<&mut Sonic2MemoryHandles> for Sonic2Message {
let global_game_state = src.global_game_state.get()?;
Ok(Sonic2Message {
sonic_pos: src.sonic_data.get_changes().expect("error getting changes"),
ctrl1_held_press: global_game_state.ctrl1_held_press.copy_from_memory(),
ctrl1_held_press_logical: global_game_state.ctrl1_held_press_logical.copy_from_memory(),
sonic_pos: src.sonic_data.get_tracked_data_if_changed()?,
ctrl1_held_press: global_game_state.ctrl1_held_press.copy_from_memory()?,
ctrl1_held_press_logical: global_game_state.ctrl1_held_press_logical.copy_from_memory()?,
})
}
}
@ -146,22 +146,23 @@ impl PlayerCharacterHandle {
impl SyncableGame for SyncedSonic2 {
fn update_state(&mut self) {
fn update_state(&mut self) -> Result<(), Error> {
//let game_state = self.memory_handles.global_game_state.get();
//let sonic_state = self.memory_handles.sonic_obj.get();
//let mut pos = self.memory_handles.sonic_pos2.get().unwrap();
//println!("game: {:?}, sonic: {:?}", game_state, sonic_state);
println!("sonic data: {:?}", self.memory_handles.sonic_data.handle.slice);
//println!("sonic data: {:?}", self.memory_handles.sonic_data.handle.slice);
let mut global_game_state = self.memory_handles.global_game_state.get().unwrap();
global_game_state.tails_control_counter.write_back([0x77, 0x77]); // force CPU tails to never take over
global_game_state.tails_respawn_counter.write_back([0x00, 0x00]); // force tails to never helicopter-respawn
let mut global_game_state = self.memory_handles.global_game_state.get()?;
global_game_state.tails_control_counter.write_back([0x77, 0x77])?; // force CPU tails to never take over
global_game_state.tails_respawn_counter.write_back([0x00, 0x00])?; // force tails to never helicopter-respawn
/*
if let Some(d) = &self.memory_handles.sonic_pos.slice {
writeln!("sonic pos: {:?}", d)
}*/
Ok(())
}
fn send_state_messages(&mut self) -> Result<(), failure::Error>{
@ -193,10 +194,10 @@ impl Sonic2MemoryHandles {
Ok(Sonic2MemoryHandles {
sonic_data: TrackedMemorySlice::create(
MemorySliceHandle::create(0xb000, 0x40, 0, memory_map)?,
vec![MemorySpan::ByAddress(0xb008..0xb01F),
//MemorySpan::ByAddress(0xb022..0xb024),
MemorySpan::ByAddress(0xb026..0xb03A),
MemorySpan::ByAddress(0xb03c..0xb03d)])?,
vec![MemorySpan::ByAddress(0xb008..0xb018),
MemorySpan::ByAddress(0xb022..0xb023),
MemorySpan::ByAddress(0xb028..0xb040)])?,
//MemorySpan::ByAddress(0xb028..0xb03d)])?,
tails_data: MemorySliceHandle::create(0xb040, 0x40, 0, memory_map)?,
sonic_obj: PlayerCharacterHandle::create(0xb000, memory_map)?,
global_game_state: GlobalGameHandle::create(memory_map)?,
@ -228,8 +229,8 @@ impl SyncedSonic2 {
*/
msg.sonic_pos.write_into(self.memory_handles.tails_data.slice);
global_game_state.ctrl2_held_press.write_back(msg.ctrl1_held_press);
global_game_state.ctrl2_held_press_logical.write_back(msg.ctrl1_held_press_logical);
global_game_state.ctrl2_held_press.write_back(msg.ctrl1_held_press)?;
global_game_state.ctrl2_held_press_logical.write_back(msg.ctrl1_held_press_logical)?;
Ok(())
}

View File

@ -1,7 +1,7 @@
use serde::{Serialize, Deserialize};
use std::ops::Range;
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct SparseVector<T: Clone> {
contents: Vec<(Range<usize>, Vec<T>)>,
pub length: usize,
@ -137,18 +137,29 @@ mod tests {
println!("{:?}", sparse);
assert_eq!((1..4, vec![2, 3, 4]), sparse.contents[0]);
assert_eq!((5..7, vec![6, 7]), sparse.contents[1]);
let mut destination = vec![1, 0, 0, 0, 5, 0, 0];
sparse.write_into(destination.as_mut());
assert_eq!(a, destination);
}
#[test]
fn partial_diff() {
let a = vec![1, 2, 3, 4, 5, 6, 7];
let b = vec![1, 0, 0, 0, 5, 0, 0];
let a = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
let b = vec![0, 1, 0, 0, 0, 5, 0, 0, 8, 9, 0, 0, 0, 13, 0];
let sparse = SparseVector::create_from_diff_in_spans(&a, &b, vec![(2..4), (6..7)]).expect("error during diffing");
let sparse = SparseVector::create_from_diff_in_spans(&a, &b, vec![(1..4), (6..9), (10..12), (14..15)]).expect("error during diffing");
println!("{:?}", sparse);
assert_eq!((2..4, vec![3, 4]), sparse.contents[0]);
assert_eq!((6..7, vec![7]), sparse.contents[1]);
assert_eq!((2..4, vec![2, 3]), sparse.contents[0]);
assert_eq!((6..8, vec![6, 7]), sparse.contents[1]);
assert_eq!((10..12, vec![10, 11]), sparse.contents[2]);
assert_eq!((14..15, vec![14]), sparse.contents[3]);
let expected = vec![0, 0, 2, 3, 0, 0, 6, 7, 0, 0, 10, 11, 0, 0, 14];
let mut destination = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
sparse.write_into(destination.as_mut());
assert_eq!(expected, destination);
}
}

View File

@ -34,4 +34,29 @@ impl TrackedMemorySlice {
self.remembered_state = self.handle.slice.into();
changes
}
pub fn has_changes(&mut self) -> bool {
for span in &self.tracked_spans {
for i in span.start..span.end {
if self.handle.slice[i] != self.remembered_state[i] {
self.remembered_state = self.handle.slice.into();
return true;
}
}
}
return false;
}
pub fn get_tracked_data(&mut self) -> Result<SparseVector<u8>, failure::Error>{
Ok(SparseVector::create_from(self.handle.slice, self.tracked_spans.clone()))
}
pub fn get_tracked_data_if_changed(&mut self) -> Result<SparseVector<u8>, failure::Error> {
if !self.has_changes() {
Ok(SparseVector::default())
}
else {
Ok(self.get_tracked_data()?)
}
}
}