319 lines
8.0 KiB
Rust
319 lines
8.0 KiB
Rust
use std::default::Default;
|
|
use std::fmt::Display;
|
|
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 {
|
|
memory_handles: PokemonRedBlueMemoryHandles<'static>,
|
|
battle_context: BattleContext,
|
|
comms: Communication<PokemonRedBlueMessage>
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct PokemonRedBlueMessage {
|
|
active_pkmn: Option<Vec<u8>>
|
|
}
|
|
|
|
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 PokemonRedBlueMemoryHandles<'a> {
|
|
active_pokemon: MemorySliceHandle<'a>,
|
|
player_and_party: MemorySliceHandle<'a>,
|
|
pokemon_out: MemorySliceHandle<'a>,
|
|
}
|
|
|
|
struct BattleContext {
|
|
active_pokemon: Pokemon,
|
|
}
|
|
|
|
impl SyncableGame for SyncedPokemonRedBlue {
|
|
fn update_state(&mut self) {
|
|
let battle_context = BattleContext {
|
|
active_pokemon: match &self.memory_handles.active_pokemon.slice {
|
|
Some(d) => num::FromPrimitive::from_u8(d[0xB]).unwrap_or(Pokemon::Unknown),
|
|
None => Pokemon::Unknown
|
|
}
|
|
};
|
|
|
|
self.battle_context = battle_context;
|
|
}
|
|
|
|
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(())
|
|
}
|
|
}
|
|
|
|
fn handle_inbound_messages(&mut self) -> Result<(), failure::Error>{
|
|
let in_msg = self.comms.try_recv()?;
|
|
self.handle_message(in_msg)
|
|
}
|
|
}
|
|
|
|
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),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for BattleContext {
|
|
fn default() -> Self {
|
|
BattleContext {
|
|
active_pokemon: Pokemon::Rhydon
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for SyncedPokemonRedBlue {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "active: pk {:?}", &self.battle_context.active_pokemon)
|
|
}
|
|
}
|
|
|
|
impl SyncedPokemonRedBlue {
|
|
pub fn create(comms_settings: CommunicationSettings, memory_map: &LibRetroMemoryMap) -> Self {
|
|
SyncedPokemonRedBlue {
|
|
memory_handles: PokemonRedBlueMemoryHandles::create(memory_map),
|
|
battle_context: BattleContext::default(),
|
|
comms: Communication::new(comms_settings),
|
|
}
|
|
}
|
|
|
|
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."));
|
|
}
|
|
|
|
let mut index: usize = 0;
|
|
for value in src.into_iter(){
|
|
target_slice[index] = value;
|
|
index += 1;
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
None => Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(FromPrimitive, ToPrimitive, Debug)]
|
|
enum Pokemon {
|
|
Unknown = 0x0,
|
|
Abra = 0x94,
|
|
Aerodactyl = 0xAB,
|
|
Alakazam = 0x95,
|
|
Arbok = 0x2D,
|
|
Arcanine = 0x14,
|
|
Articuno = 0x4A,
|
|
Beedrill = 0x72,
|
|
Bellsprout = 0xBC,
|
|
Blastoise = 0x1C,
|
|
Bulbasaur = 0x99,
|
|
Butterfree = 0x7D,
|
|
Caterpie = 0x7B,
|
|
Chansey = 0x28,
|
|
Charizard = 0xB4,
|
|
Charmander = 0xB0,
|
|
Charmeleon = 0xB2,
|
|
Clefable = 0x8E,
|
|
Clefairy = 0x04,
|
|
Cloyster = 0x8B,
|
|
Cubone = 0x11,
|
|
Dewgong = 0x78,
|
|
Diglett = 0x3B,
|
|
Ditto = 0x4C,
|
|
Dodrio = 0x74,
|
|
Doduo = 0x46,
|
|
Dragonair = 0x59,
|
|
Dragonite = 0x42,
|
|
Dratini = 0x58,
|
|
Drowzee = 0x30,
|
|
Dugtrio = 0x76,
|
|
Eevee = 0x66,
|
|
Ekans = 0x6C,
|
|
Electabuzz = 0x35,
|
|
Electrode = 0x8D,
|
|
Exeggcute = 0x0C,
|
|
Exeggutor = 0x0A,
|
|
Farfetchd = 0x40,
|
|
Fearow = 0x23,
|
|
Flareon = 0x67,
|
|
Gastly = 0x19,
|
|
Gengar = 0x0E,
|
|
Geodude = 0xA9,
|
|
Gloom = 0xBA,
|
|
Golbat = 0x82,
|
|
Goldeen = 0x9D,
|
|
Golduck = 0x80,
|
|
Golem = 0x31,
|
|
Graveler = 0x27,
|
|
Grimer = 0x0D,
|
|
Growlithe = 0x21,
|
|
Gyarados = 0x16,
|
|
Haunter = 0x93,
|
|
Hitmonchan = 0x2C,
|
|
Hitmonlee = 0x2B,
|
|
Horsea = 0x5C,
|
|
Hypno = 0x81,
|
|
Ivysaur = 0x09,
|
|
Jigglypuff = 0x64,
|
|
Jolteon = 0x68,
|
|
Jynx = 0x48,
|
|
Kabuto = 0x5A,
|
|
Kabutops = 0x5B,
|
|
Kadabra = 0x26,
|
|
Kakuna = 0x71,
|
|
Kangaskhan = 0x02,
|
|
Kingler = 0x8A,
|
|
Koffing = 0x37,
|
|
Krabby = 0x4E,
|
|
Lapras = 0x13,
|
|
Lickitung = 0x0B,
|
|
Machamp = 0x7E,
|
|
Machoke = 0x29,
|
|
Machop = 0x6A,
|
|
Magikarp = 0x85,
|
|
Magmar = 0x33,
|
|
Magnemite = 0xAD,
|
|
Magneton = 0x36,
|
|
Mankey = 0x39,
|
|
Marowak = 0x91,
|
|
Meowth = 0x4D,
|
|
Metapod = 0x7C,
|
|
Mew = 0x15,
|
|
Mewtwo = 0x83,
|
|
Moltres = 0x49,
|
|
MrMime = 0x2A,
|
|
Muk = 0x88,
|
|
Nidoking = 0x07,
|
|
Nidoqueen = 0x10,
|
|
NidoranF = 0x0F,
|
|
NidoranM = 0x03,
|
|
Nidorino = 0xA7,
|
|
Nidorina = 0xA8,
|
|
Ninetales = 0x53,
|
|
Oddish = 0xB9,
|
|
Omanyte = 0x62,
|
|
Omastar = 0x63,
|
|
Onix = 0x22,
|
|
Paras = 0x6D,
|
|
Parasect = 0x2E,
|
|
Persian = 0x90,
|
|
Pidgeot = 0x97,
|
|
Pidgeotto = 0x96,
|
|
Pidgey = 0x24,
|
|
Pikachu = 0x54,
|
|
Pinsir = 0x1D,
|
|
Poliwag = 0x47,
|
|
Poliwhirl = 0x6E,
|
|
Poliwrath = 0x6F,
|
|
Ponyta = 0xA3,
|
|
Porygon = 0xAA,
|
|
Primeape = 0x75,
|
|
Psyduck = 0x2F,
|
|
Raichu = 0x55,
|
|
Rapidash = 0xA4,
|
|
Raticate = 0xA6,
|
|
Rattata = 0xA5,
|
|
Rhydon = 0x01,
|
|
Rhyhorn = 0x12,
|
|
Sandshrew = 0x60,
|
|
Sandslash = 0x61,
|
|
Scyther = 0x1A,
|
|
Seadra = 0x5D,
|
|
Seaking = 0x9E,
|
|
Seel = 0x3A,
|
|
Shellder = 0x17,
|
|
Slowbro = 0x08,
|
|
Slowpoke = 0x25,
|
|
Snorlax = 0x84,
|
|
Spearow = 0x05,
|
|
Squirtle = 0xB1,
|
|
Starmie = 0x98,
|
|
Staryu = 0x1B,
|
|
Tangela = 0x1E,
|
|
Tauros = 0x3C,
|
|
Tentacool = 0x18,
|
|
Tentacruel = 0x9B,
|
|
Vaporeon = 0x69,
|
|
Venomoth = 0x77,
|
|
Venonat = 0x41,
|
|
Venusaur = 0x9A,
|
|
Victreebell = 0xBE,
|
|
Vileplume = 0xBB,
|
|
Voltorb = 0x06,
|
|
Vulpix = 0x52,
|
|
Wartortle = 0xB3,
|
|
Weedle = 0x70,
|
|
Weepinbell = 0xBD,
|
|
Weezing = 0x8F,
|
|
Wigglytuff = 0x65,
|
|
Zapdos = 0x4B,
|
|
Zubat = 0x6B,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use serde_json;
|
|
|
|
fn build_message(em: &MemorySliceHandle) -> PokemonRedBlueMessage {
|
|
PokemonRedBlueMessage {
|
|
active_pkmn: match &em.slice {
|
|
Some(m) => Some(m.to_vec()),
|
|
None => None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn serde_mem() -> Result<(), String> {
|
|
let mut data: [u8; 5] = [1, 2, 3, 4, 5];
|
|
let b: &mut [u8] = &mut data;
|
|
let slice = MemorySliceHandle {
|
|
offset: 0,
|
|
length: 0,
|
|
bank_switch: 0,
|
|
slice: Some(b),
|
|
last_read_value: None
|
|
};
|
|
|
|
let message = build_message(&slice);
|
|
|
|
let serialized = serde_json::to_string(&message).unwrap();
|
|
|
|
println!("serialized data: {}", serialized);
|
|
|
|
let deserialized: PokemonRedBlueMessage = serde_json::from_str(&serialized).unwrap();
|
|
|
|
assert_eq!(deserialized.active_pkmn.unwrap()[0], data[0]);
|
|
Ok(())
|
|
}
|
|
|
|
} |