more cleanup, send entire sonic data each frame instead of diffs
This commit is contained in:
parent
419e97af23
commit
e33275e65d
|
@ -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 => ()
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -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>{
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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()?)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue