FFI for Pokemon Party, make Pokemon Party use interior mutability.
This commit is contained in:
parent
c7b5bb7d12
commit
554a665b8f
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()))
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue