FFI for Pokemon Party, make Pokemon Party use interior mutability.

This commit is contained in:
Deukhoofd 2022-10-15 11:16:41 +02:00
parent c7b5bb7d12
commit 554a665b8f
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
5 changed files with 120 additions and 26 deletions

View File

@ -45,7 +45,7 @@ impl BattleParty {
} }
/// Gets a Pokemon at an index. /// Gets a Pokemon at an index.
pub fn get_pokemon(&self, index: usize) -> &Option<Arc<Pokemon>> { pub fn get_pokemon(&self, index: usize) -> Option<Arc<Pokemon>> {
self.party.at(index) self.party.at(index)
} }

View File

@ -1,13 +1,18 @@
use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock};
use std::sync::Arc; use std::sync::Arc;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::{ValueIdentifiable, ValueIdentifier};
/// A list of Pokemon belonging to a trainer. /// A list of Pokemon belonging to a trainer.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
pub struct PokemonParty { pub struct PokemonParty {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying list of Pokemon. /// The underlying list of Pokemon.
pokemon: Vec<Option<Arc<Pokemon>>>, pokemon: RwLock<Vec<Option<Arc<Pokemon>>>>,
} }
impl PokemonParty { impl PokemonParty {
@ -17,42 +22,50 @@ impl PokemonParty {
for _i in 0..size { for _i in 0..size {
pokemon.push(None); pokemon.push(None);
} }
Self { pokemon } Self {
identifier: Default::default(),
pokemon: RwLock::new(pokemon),
}
} }
/// Instantiates a party with a list. /// Instantiates a party with a list.
pub fn new_from_vec(pokemon: Vec<Option<Arc<Pokemon>>>) -> Self { pub fn new_from_vec(pokemon: Vec<Option<Arc<Pokemon>>>) -> Self {
Self { pokemon } Self {
identifier: Default::default(),
pokemon: RwLock::new(pokemon),
}
} }
/// Gets a Pokemon at an index in the party. /// Gets a Pokemon at an index in the party.
pub fn at(&self, index: usize) -> &Option<Arc<Pokemon>> { pub fn at(&self, index: usize) -> Option<Arc<Pokemon>> {
let opt = self.pokemon.get(index); let read_lock = self.pokemon.read();
let opt = read_lock.get(index);
if let Some(v) = opt { if let Some(v) = opt {
v v.clone()
} else { } else {
&None None
} }
} }
/// Swaps two Pokemon in the party around. /// Swaps two Pokemon in the party around.
pub fn switch(&mut self, a: usize, b: usize) { pub fn switch(&self, a: usize, b: usize) {
self.pokemon.swap(a, b); self.pokemon.write().swap(a, b);
} }
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon. /// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
pub fn swap_into(&mut self, index: usize, pokemon: Option<Arc<Pokemon>>) -> Option<Arc<Pokemon>> { pub fn swap_into(&self, index: usize, pokemon: Option<Arc<Pokemon>>) -> Option<Arc<Pokemon>> {
if index >= self.pokemon.len() { let mut party = self.pokemon.write();
if index >= party.len() {
return pokemon; return pokemon;
} }
let old = self.pokemon[index].as_ref().cloned(); let old = party[index].as_ref().cloned();
self.pokemon[index] = pokemon; party[index] = pokemon;
old old
} }
/// Whether or not the party still has Pokemon that can be used in battle. /// Whether or not the party still has Pokemon that can be used in battle.
pub fn has_usable_pokemon(&self) -> bool { pub fn has_usable_pokemon(&self) -> bool {
for pokemon in self.pokemon.iter().flatten() { for pokemon in self.pokemon.read().iter().flatten() {
if pokemon.is_usable() { if pokemon.is_usable() {
return true; return true;
} }
@ -62,30 +75,31 @@ impl PokemonParty {
/// Get the length of the underlying list of Pokemon. /// Get the length of the underlying list of Pokemon.
pub fn length(&self) -> usize { pub fn length(&self) -> usize {
self.pokemon.len() self.pokemon.read().len()
} }
/// Gets the underlying list of Pokemon. /// Gets the underlying list of Pokemon.
pub fn pokemon(&self) -> &Vec<Option<Arc<Pokemon>>> { pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<Option<Arc<Pokemon>>>> {
&self.pokemon self.pokemon.read()
} }
/// Makes sure there are no empty spots in the party anymore, leaving the length the same. /// Makes sure there are no empty spots in the party anymore, leaving the length the same.
pub fn pack_party(&mut self) { pub fn pack_party(&self) {
let mut first_empty = None; let mut first_empty = None;
let mut i = 0; let mut i = 0;
let mut party = self.pokemon.write();
loop { loop {
if self.pokemon[i].is_none() { if party[i].is_none() {
if first_empty.is_none() { if first_empty.is_none() {
first_empty = Some(i) first_empty = Some(i)
} }
} else if first_empty.is_some() { } else if first_empty.is_some() {
self.pokemon.swap(first_empty.unwrap(), i); party.swap(first_empty.unwrap(), i);
i = first_empty.unwrap(); i = first_empty.unwrap();
first_empty = None; first_empty = None;
} }
i += 1; i += 1;
if i >= self.pokemon.len() { if i >= party.len() {
break; break;
} }
} }
@ -93,7 +107,7 @@ impl PokemonParty {
/// Checks if the party contains a given pokemon. /// Checks if the party contains a given pokemon.
pub fn has_pokemon(&self, pokemon: &Pokemon) -> bool { pub fn has_pokemon(&self, pokemon: &Pokemon) -> bool {
for p in self.pokemon.iter().flatten() { for p in self.pokemon.read().iter().flatten() {
if std::ptr::eq(p.as_ref(), pokemon) { if std::ptr::eq(p.as_ref(), pokemon) {
return true; return true;
} }
@ -101,3 +115,9 @@ impl PokemonParty {
false false
} }
} }
impl ValueIdentifiable for PokemonParty {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -2,3 +2,5 @@
mod learned_move; mod learned_move;
/// The foreign function interface for a Pokemon. /// The foreign function interface for a Pokemon.
mod pokemon; mod pokemon;
/// The foreign function interface for a party of Pokemon.
mod pokemon_party;

View File

@ -0,0 +1,74 @@
use crate::dynamic_data::{Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer};
use std::sync::Arc;
/// Instantiates a party with a set size.
#[no_mangle]
extern "C" fn pokemon_party_new(capacity: usize) -> IdentifiablePointer<Arc<PokemonParty>> {
Arc::new(PokemonParty::new(capacity)).into()
}
/// Gets a Pokemon at an index in the party.
#[no_mangle]
extern "C" fn pokemon_party_at(
ptr: ExternPointer<Arc<PokemonParty>>,
index: usize,
) -> IdentifiablePointer<Arc<Pokemon>> {
if let Some(v) = ptr.as_ref().at(index) {
v.into()
} else {
IdentifiablePointer::none()
}
}
/// Gets a Pokemon at an index in the party.
#[no_mangle]
extern "C" fn pokemon_party_switch(ptr: ExternPointer<Arc<PokemonParty>>, a: usize, b: usize) {
ptr.as_ref().switch(a, b);
}
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
#[no_mangle]
extern "C" fn pokemon_party_swap_into(
ptr: ExternPointer<Arc<PokemonParty>>,
index: usize,
pokemon: ExternPointer<Arc<Pokemon>>,
) -> IdentifiablePointer<Arc<Pokemon>> {
let pokemon = if pokemon.ptr.is_null() {
None
} else {
Some(pokemon.as_ref().clone())
};
if let Some(v) = ptr.as_ref().swap_into(index, pokemon) {
v.into()
} else {
IdentifiablePointer::none()
}
}
/// Whether or not the party still has Pokemon that can be used in battle.
#[no_mangle]
extern "C" fn pokemon_party_has_usable_pokemon(ptr: ExternPointer<Arc<PokemonParty>>) -> u8 {
u8::from(ptr.as_ref().has_usable_pokemon())
}
/// Get the length of the underlying list of Pokemon.
#[no_mangle]
extern "C" fn pokemon_party_length(ptr: ExternPointer<Arc<PokemonParty>>) -> usize {
ptr.as_ref().length()
}
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
#[no_mangle]
extern "C" fn pokemon_party_pack_party(ptr: ExternPointer<Arc<PokemonParty>>) {
ptr.as_ref().pack_party()
}
/// Checks if the party contains a given pokemon.
#[no_mangle]
extern "C" fn pokemon_party_has_pokemon(
ptr: ExternPointer<Arc<PokemonParty>>,
pokemon: ExternPointer<Arc<Pokemon>>,
) -> u8 {
u8::from(ptr.as_ref().has_pokemon(pokemon.as_ref()))
}

View File

@ -34,9 +34,7 @@ impl TestStep {
pub fn execute(&self, battle: &mut Battle) { pub fn execute(&self, battle: &mut Battle) {
match self { match self {
TestStep::SetPokemon { place, from_party } => { TestStep::SetPokemon { place, from_party } => {
let p = battle.parties()[from_party[0] as usize] let p = battle.parties()[from_party[0] as usize].get_pokemon(from_party[1] as usize);
.get_pokemon(from_party[1] as usize)
.clone();
battle.sides_mut()[place[0] as usize].set_pokemon(place[1], p); battle.sides_mut()[place[0] as usize].set_pokemon(place[1], p);
} }
TestStep::SetMoveChoice { TestStep::SetMoveChoice {