Complete refactor of the FFI to use handles instead of pointers.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2023-06-24 14:44:23 +02:00
parent 4c222cb753
commit 78bb91093b
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
76 changed files with 1510 additions and 1952 deletions

View File

@ -8,13 +8,10 @@ use crate::dynamic_data::Pokemon;
use crate::dynamic_data::ScriptContainer; use crate::dynamic_data::ScriptContainer;
use crate::dynamic_data::{LearnedMove, ScriptWrapper}; use crate::dynamic_data::{LearnedMove, ScriptWrapper};
use crate::dynamic_data::{ScriptSource, ScriptSourceData}; use crate::dynamic_data::{ScriptSource, ScriptSourceData};
use crate::{ValueIdentifiable, ValueIdentifier};
/// The data on a turn choice that should be contained in every turn choice, regardless of type. /// The data on a turn choice that should be contained in every turn choice, regardless of type.
#[derive(Debug)] #[derive(Debug)]
struct CommonChoiceData { struct CommonChoiceData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The user of the turn choice /// The user of the turn choice
user: Pokemon, user: Pokemon,
/// The speed of the user at the beginning of the turn. /// The speed of the user at the beginning of the turn.
@ -180,7 +177,6 @@ impl MoveChoice {
script: Default::default(), script: Default::default(),
priority: AtomicI8::new(0), priority: AtomicI8::new(0),
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
identifier: Default::default(),
user, user,
speed: AtomicU32::new(speed), speed: AtomicU32::new(speed),
random_value: AtomicU32::new(0), random_value: AtomicU32::new(0),
@ -253,7 +249,6 @@ impl ItemChoice {
let speed = user.boosted_stats().speed(); let speed = user.boosted_stats().speed();
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
identifier: Default::default(),
user, user,
speed: AtomicU32::new(speed), speed: AtomicU32::new(speed),
random_value: AtomicU32::new(0), random_value: AtomicU32::new(0),
@ -293,7 +288,6 @@ impl SwitchChoice {
let speed = user.boosted_stats().speed(); let speed = user.boosted_stats().speed();
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
identifier: Default::default(),
user, user,
speed: AtomicU32::new(speed), speed: AtomicU32::new(speed),
random_value: AtomicU32::new(0), random_value: AtomicU32::new(0),
@ -332,7 +326,6 @@ impl FleeChoice {
pub fn new(user: Pokemon) -> Self { pub fn new(user: Pokemon) -> Self {
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
identifier: Default::default(),
user, user,
speed: AtomicU32::new(0), speed: AtomicU32::new(0),
random_value: AtomicU32::new(0), random_value: AtomicU32::new(0),
@ -372,7 +365,6 @@ impl PassChoice {
let speed = user.boosted_stats().speed(); let speed = user.boosted_stats().speed();
Self { Self {
choice_data: Box::new(CommonChoiceData { choice_data: Box::new(CommonChoiceData {
identifier: Default::default(),
user, user,
speed: AtomicU32::new(speed), speed: AtomicU32::new(speed),
random_value: AtomicU32::new(0), random_value: AtomicU32::new(0),
@ -485,9 +477,3 @@ impl Ord for TurnChoice {
} }
} }
} }
impl ValueIdentifiable for TurnChoice {
fn value_identifier(&self) -> ValueIdentifier {
self.choice_data().identifier
}
}

View File

@ -1,7 +1,7 @@
use crate::dynamic_data::choices::TurnChoice; use crate::dynamic_data::choices::TurnChoice;
use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::script_handling::ScriptSource;
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::{script_hook, PkmnError, ValueIdentifiable, ValueIdentifier, VecExt}; use crate::{script_hook, PkmnError, VecExt};
use anyhow::Result; use anyhow::Result;
use anyhow_ext::anyhow; use anyhow_ext::anyhow;
use parking_lot::lock_api::MappedRwLockReadGuard; use parking_lot::lock_api::MappedRwLockReadGuard;
@ -17,8 +17,6 @@ use std::sync::Arc;
/// moves in Pokemon actively mess with this order. /// moves in Pokemon actively mess with this order.
#[derive(Debug)] #[derive(Debug)]
pub struct ChoiceQueue { pub struct ChoiceQueue {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get /// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get
/// executed. /// executed.
queue: RwLock<Vec<Option<Arc<TurnChoice>>>>, queue: RwLock<Vec<Option<Arc<TurnChoice>>>>,
@ -31,7 +29,6 @@ impl ChoiceQueue {
pub(crate) fn new(mut queue: Vec<Option<Arc<TurnChoice>>>) -> Self { pub(crate) fn new(mut queue: Vec<Option<Arc<TurnChoice>>>) -> Self {
queue.sort_unstable_by(|a, b| b.cmp(a)); queue.sort_unstable_by(|a, b| b.cmp(a));
Self { Self {
identifier: Default::default(),
queue: RwLock::new(queue), queue: RwLock::new(queue),
current: AtomicUsize::new(0), current: AtomicUsize::new(0),
} }
@ -107,7 +104,7 @@ impl ChoiceQueue {
// Find the index for the choice we want to move up. // Find the index for the choice we want to move up.
for index in self.current.load(Ordering::Relaxed)..queue_lock.len() { for index in self.current.load(Ordering::Relaxed)..queue_lock.len() {
if let Some(Some(choice)) = &queue_lock.get(index) { if let Some(Some(choice)) = &queue_lock.get(index) {
if pokemon.value_identifier() == choice.user().value_identifier() { if pokemon.eq(choice.user()) {
desired_index = Some(index); desired_index = Some(index);
break; break;
} }
@ -158,12 +155,6 @@ impl ChoiceQueue {
} }
} }
impl ValueIdentifiable for ChoiceQueue {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
@ -253,10 +244,7 @@ mod tests {
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))),
]); ]);
let inner_queue = queue.get_queue().unwrap(); let inner_queue = queue.get_queue().unwrap();
assert_eq!( assert_eq!(inner_queue[0].as_ref().unwrap().user().clone(), user1);
inner_queue[0].as_ref().unwrap().user().value_identifier(),
user1.value_identifier()
);
} }
#[test] #[test]
@ -283,15 +271,9 @@ mod tests {
]); ]);
user2.change_level_by(60).unwrap(); user2.change_level_by(60).unwrap();
assert_eq!( assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),);
user1.value_identifier(),
queue.peek().unwrap().unwrap().user().value_identifier()
);
queue.resort().unwrap(); queue.resort().unwrap();
assert_eq!( assert_eq!(user2, queue.peek().unwrap().unwrap().user().clone(),);
user2.value_identifier(),
queue.peek().unwrap().unwrap().user().value_identifier()
);
} }
#[test] #[test]
@ -303,20 +285,11 @@ mod tests {
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))),
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))),
]); ]);
assert_eq!( assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),);
user1.value_identifier(),
queue.peek().unwrap().unwrap().user().value_identifier()
);
assert!(queue.move_pokemon_choice_next(&user2).unwrap()); assert!(queue.move_pokemon_choice_next(&user2).unwrap());
assert_eq!( assert_eq!(user2, queue.dequeue().unwrap().unwrap().user().clone(),);
user2.value_identifier(), assert_eq!(user1, queue.dequeue().unwrap().unwrap().user().clone(),);
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
assert_eq!(
user1.value_identifier(),
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
} }
#[test] #[test]
@ -328,16 +301,10 @@ mod tests {
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))),
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))),
]); ]);
assert_eq!( assert_eq!(user2, queue.dequeue().unwrap().unwrap().user().clone(),);
user2.value_identifier(),
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
assert!(!queue.move_pokemon_choice_next(&user2).unwrap()); assert!(!queue.move_pokemon_choice_next(&user2).unwrap());
assert_eq!( assert_eq!(user1, queue.dequeue().unwrap().unwrap().user().clone(),);
user1.value_identifier(),
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
assert!(queue.peek().unwrap().is_none()) assert!(queue.peek().unwrap().is_none())
} }
@ -350,15 +317,9 @@ mod tests {
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))),
Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))),
]); ]);
assert_eq!( assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),);
user1.value_identifier(),
queue.peek().unwrap().unwrap().user().value_identifier()
);
assert!(queue.move_pokemon_choice_next(&user1).unwrap()); assert!(queue.move_pokemon_choice_next(&user1).unwrap());
assert_eq!( assert_eq!(user1, queue.peek().unwrap().unwrap().user().clone(),);
user1.value_identifier(),
queue.peek().unwrap().unwrap().user().value_identifier()
);
} }
#[test] #[test]
@ -382,27 +343,15 @@ mod tests {
Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[5].clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[5].clone())))),
Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[6].clone())))), Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[6].clone())))),
]); ]);
assert_eq!( assert_eq!(users[0], queue.peek().unwrap().unwrap().user().clone(),);
users[0].value_identifier(),
queue.peek().unwrap().unwrap().user().value_identifier()
);
assert!(queue.move_pokemon_choice_next(&users[4]).unwrap()); assert!(queue.move_pokemon_choice_next(&users[4]).unwrap());
assert_eq!( assert_eq!(users[4], queue.dequeue().unwrap().unwrap().user().clone(),);
users[4].value_identifier(),
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
for index in 0..4 { for index in 0..4 {
assert_eq!( assert_eq!(users[index], queue.dequeue().unwrap().unwrap().user().clone(),);
users[index].value_identifier(),
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
} }
for index in 5..7 { for index in 5..7 {
assert_eq!( assert_eq!(users[index], queue.dequeue().unwrap().unwrap().user().clone(),);
users[index].value_identifier(),
queue.dequeue().unwrap().unwrap().user().value_identifier()
);
} }
} }
} }

View File

@ -4,10 +4,9 @@ use std::fmt::Debug;
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::static_data::Statistic; use crate::static_data::Statistic;
use crate::static_data::StatisticSet; use crate::static_data::StatisticSet;
use crate::{ValueIdentifiable, ValueIdentifier};
/// A battle stat calculator is used to calculate stats for a Pokemon. /// A battle stat calculator is used to calculate stats for a Pokemon.
pub trait BattleStatCalculator: Debug + ValueIdentifiable { pub trait BattleStatCalculator: Debug {
/// Calculate all the flat stats of a Pokemon, disregarding stat boosts. /// Calculate all the flat stats of a Pokemon, disregarding stat boosts.
fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<u32>) -> Result<()>; fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<u32>) -> Result<()>;
/// Calculate a single flat stat of a Pokemon, disregarding stat boost /// Calculate a single flat stat of a Pokemon, disregarding stat boost
@ -20,10 +19,7 @@ pub trait BattleStatCalculator: Debug + ValueIdentifiable {
/// A basic implementation of the Gen 7 stat calculator. /// A basic implementation of the Gen 7 stat calculator.
#[derive(Debug)] #[derive(Debug)]
pub struct Gen7BattleStatCalculator { pub struct Gen7BattleStatCalculator {}
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
}
impl Default for Gen7BattleStatCalculator { impl Default for Gen7BattleStatCalculator {
fn default() -> Self { fn default() -> Self {
@ -34,9 +30,7 @@ impl Default for Gen7BattleStatCalculator {
impl Gen7BattleStatCalculator { impl Gen7BattleStatCalculator {
/// Creates a new Gen 7 battle stat calculator /// Creates a new Gen 7 battle stat calculator
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {}
identifier: Default::default(),
}
} }
/// The calculation used for health points. /// The calculation used for health points.
@ -141,11 +135,6 @@ impl BattleStatCalculator for Gen7BattleStatCalculator {
} }
} }
impl ValueIdentifiable for Gen7BattleStatCalculator {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
pub mod tests { pub mod tests {
@ -160,10 +149,5 @@ pub mod tests {
fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<u32>) -> Result<()>; fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<u32>) -> Result<()>;
fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> Result<u32>; fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> Result<u32>;
} }
impl ValueIdentifiable for BattleStatCalculator {
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -5,12 +5,12 @@ use std::sync::Arc;
use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::script_handling::ScriptSource;
use crate::dynamic_data::{Battle, Pokemon}; use crate::dynamic_data::{Battle, Pokemon};
use crate::dynamic_data::{ExecutingMove, HitData}; use crate::dynamic_data::{ExecutingMove, HitData};
use crate::script_hook;
use crate::static_data::{MoveCategory, Statistic}; use crate::static_data::{MoveCategory, Statistic};
use crate::{script_hook, ValueIdentifiable, ValueIdentifier};
/// A damage library holds the functions related to the calculation of damage. As this can change in /// A damage library holds the functions related to the calculation of damage. As this can change in
/// different generations and implementations, this is handled through a trait. /// different generations and implementations, this is handled through a trait.
pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { pub trait DamageLibrary: std::fmt::Debug {
/// Calculate the damage for a given hit on a Pokemon. /// Calculate the damage for a given hit on a Pokemon.
fn get_damage( fn get_damage(
&self, &self,
@ -42,8 +42,6 @@ pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable {
/// The implementation of a Damage Library for generation 7. /// The implementation of a Damage Library for generation 7.
#[derive(Debug)] #[derive(Debug)]
pub struct Gen7DamageLibrary { pub struct Gen7DamageLibrary {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// Defines whether or not a random damage modifier is applied to damage (0.85 - 1.00). /// Defines whether or not a random damage modifier is applied to damage (0.85 - 1.00).
has_randomness: bool, has_randomness: bool,
} }
@ -52,10 +50,7 @@ impl Gen7DamageLibrary {
/// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage /// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage
/// modifier (0.85x - 1.00x) is applied to the calculated damage. /// modifier (0.85x - 1.00x) is applied to the calculated damage.
pub fn new(has_randomness: bool) -> Self { pub fn new(has_randomness: bool) -> Self {
Self { Self { has_randomness }
identifier: Default::default(),
has_randomness,
}
} }
/// Calculates the modifier applied to damage from the statistics of the relevant Pokemon. /// Calculates the modifier applied to damage from the statistics of the relevant Pokemon.
@ -312,9 +307,3 @@ impl DamageLibrary for Gen7DamageLibrary {
}) })
} }
} }
impl ValueIdentifiable for Gen7DamageLibrary {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -10,11 +10,11 @@ use crate::dynamic_data::{ItemScript, ScriptResolver};
use crate::dynamic_data::{Script, ScriptOwnerData}; use crate::dynamic_data::{Script, ScriptOwnerData};
use crate::static_data::Item; use crate::static_data::Item;
use crate::static_data::StaticData; use crate::static_data::StaticData;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// The dynamic library stores a static data library, as well as holding different libraries and /// The dynamic library stores a static data library, as well as holding different libraries and
/// calculators that might be customized between different generations and implementations. /// calculators that might be customized between different generations and implementations.
pub trait DynamicLibrary: Debug + ValueIdentifiable { pub trait DynamicLibrary: Debug + Send + Sync {
/// The static data is the immutable storage data for this library. /// The static data is the immutable storage data for this library.
fn static_data(&self) -> &Arc<dyn StaticData>; fn static_data(&self) -> &Arc<dyn StaticData>;
/// The stat calculator deals with the calculation of flat and boosted stats, based on the /// The stat calculator deals with the calculation of flat and boosted stats, based on the
@ -39,13 +39,10 @@ pub trait DynamicLibrary: Debug + ValueIdentifiable {
/// shared between all different usages. /// shared between all different usages.
fn load_item_script(&self, _key: &Arc<dyn Item>) -> Result<Option<Arc<dyn ItemScript>>>; fn load_item_script(&self, _key: &Arc<dyn Item>) -> Result<Option<Arc<dyn ItemScript>>>;
} }
/// The dynamic library stores a static data library, as well as holding different libraries and /// The dynamic library stores a static data library, as well as holding different libraries and
/// calculators that might be customized between different generations and implementations. /// calculators that might be customized between different generations and implementations.
#[derive(Debug)] #[derive(Debug)]
pub struct DynamicLibraryImpl { pub struct DynamicLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The static data is the immutable storage data for this library. /// The static data is the immutable storage data for this library.
static_data: Arc<dyn StaticData>, static_data: Arc<dyn StaticData>,
/// The stat calculator deals with the calculation of flat and boosted stats, based on the /// The stat calculator deals with the calculation of flat and boosted stats, based on the
@ -58,9 +55,13 @@ pub struct DynamicLibraryImpl {
misc_library: Arc<dyn MiscLibrary>, misc_library: Arc<dyn MiscLibrary>,
/// The script resolver deals with how to resolve the scripts from specific unique key combinations. /// The script resolver deals with how to resolve the scripts from specific unique key combinations.
script_resolver: Box<dyn ScriptResolver>, script_resolver: Arc<dyn ScriptResolver>,
} }
unsafe impl Send for DynamicLibraryImpl {}
unsafe impl Sync for DynamicLibraryImpl {}
impl DynamicLibraryImpl { impl DynamicLibraryImpl {
/// Instantiates a new DynamicLibrary with given parameters. /// Instantiates a new DynamicLibrary with given parameters.
pub fn new( pub fn new(
@ -68,10 +69,9 @@ impl DynamicLibraryImpl {
stat_calculator: Arc<dyn BattleStatCalculator>, stat_calculator: Arc<dyn BattleStatCalculator>,
damage_calculator: Arc<dyn DamageLibrary>, damage_calculator: Arc<dyn DamageLibrary>,
misc_library: Arc<dyn MiscLibrary>, misc_library: Arc<dyn MiscLibrary>,
script_resolver: Box<dyn ScriptResolver>, script_resolver: Arc<dyn ScriptResolver>,
) -> Self { ) -> Self {
Self { Self {
identifier: Default::default(),
static_data, static_data,
stat_calculator, stat_calculator,
damage_calculator, damage_calculator,
@ -120,12 +120,6 @@ impl DynamicLibrary for DynamicLibraryImpl {
} }
} }
impl ValueIdentifiable for DynamicLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
pub mod test { pub mod test {
@ -138,6 +132,10 @@ pub mod test {
mockall::mock! { mockall::mock! {
#[derive(Debug)] #[derive(Debug)]
pub DynamicLibrary{} pub DynamicLibrary{}
unsafe impl Send for DynamicLibrary{}
unsafe impl Sync for DynamicLibrary{}
impl DynamicLibrary for DynamicLibrary { impl DynamicLibrary for DynamicLibrary {
fn static_data(&self) -> &Arc<dyn StaticData>; fn static_data(&self) -> &Arc<dyn StaticData>;
fn stat_calculator(&self) -> &Arc<dyn BattleStatCalculator>; fn stat_calculator(&self) -> &Arc<dyn BattleStatCalculator>;
@ -151,23 +149,15 @@ pub mod test {
) -> Result<Option<Arc<dyn Script>>>; ) -> Result<Option<Arc<dyn Script>>>;
fn load_item_script(&self, _key: &Arc<dyn Item>) -> Result<Option<Arc<dyn ItemScript>>>; fn load_item_script(&self, _key: &Arc<dyn Item>) -> Result<Option<Arc<dyn ItemScript>>>;
} }
impl ValueIdentifiable for DynamicLibrary{
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
pub fn build() -> DynamicLibraryImpl { pub fn build() -> DynamicLibraryImpl {
DynamicLibraryImpl { DynamicLibraryImpl {
identifier: Default::default(),
static_data: Arc::new(crate::static_data::libraries::static_data::test::build()), static_data: Arc::new(crate::static_data::libraries::static_data::test::build()),
stat_calculator: Arc::new(Gen7BattleStatCalculator::new()), stat_calculator: Arc::new(Gen7BattleStatCalculator::new()),
damage_calculator: Arc::new(Gen7DamageLibrary::new(false)), damage_calculator: Arc::new(Gen7DamageLibrary::new(false)),
misc_library: Arc::new(Gen7MiscLibrary::new()), misc_library: Arc::new(Gen7MiscLibrary::new()),
script_resolver: Box::new(EmptyScriptResolver { script_resolver: Arc::new(EmptyScriptResolver {}),
identifier: Default::default(),
}),
} }
} }
} }

View File

@ -7,10 +7,10 @@ use crate::dynamic_data::choices::{MoveChoice, TurnChoice};
use crate::dynamic_data::Pokemon; use crate::dynamic_data::Pokemon;
use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
use crate::static_data::{MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffectImpl}; use crate::static_data::{MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffectImpl};
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// The misc library holds several misc functions required for the battle to run. /// The misc library holds several misc functions required for the battle to run.
pub trait MiscLibrary: Debug + ValueIdentifiable { pub trait MiscLibrary: Debug {
/// Returns whether or not a Pokemon is allowed to flee or switch out. /// Returns whether or not a Pokemon is allowed to flee or switch out.
fn can_flee(&self, choice: &TurnChoice) -> bool; fn can_flee(&self, choice: &TurnChoice) -> bool;
/// Returns the move we need to use if we can't use another move. Typically Struggle. /// Returns the move we need to use if we can't use another move. Typically Struggle.
@ -22,8 +22,6 @@ pub trait MiscLibrary: Debug + ValueIdentifiable {
/// A gen 7 implementation for the MiscLibrary. /// A gen 7 implementation for the MiscLibrary.
#[derive(Debug)] #[derive(Debug)]
pub struct Gen7MiscLibrary { pub struct Gen7MiscLibrary {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The learned move data for struggle. /// The learned move data for struggle.
struggle_learned_move: Arc<LearnedMove>, struggle_learned_move: Arc<LearnedMove>,
} }
@ -40,7 +38,7 @@ impl Gen7MiscLibrary {
255, 255,
MoveTarget::Any, MoveTarget::Any,
0, 0,
Some(Box::new(SecondaryEffectImpl::new( Some(Arc::new(SecondaryEffectImpl::new(
-1.0, -1.0,
StringKey::new("struggle"), StringKey::new("struggle"),
vec![], vec![],
@ -48,10 +46,7 @@ impl Gen7MiscLibrary {
HashSet::new(), HashSet::new(),
)); ));
let struggle_learned_move = Arc::new(LearnedMove::new(struggle_data, MoveLearnMethod::Unknown)); let struggle_learned_move = Arc::new(LearnedMove::new(struggle_data, MoveLearnMethod::Unknown));
Self { Self { struggle_learned_move }
identifier: Default::default(),
struggle_learned_move,
}
} }
} }
@ -76,9 +71,3 @@ impl MiscLibrary for Gen7MiscLibrary {
)) ))
} }
} }
impl ValueIdentifiable for Gen7MiscLibrary {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -1,15 +1,16 @@
use anyhow::Result; use anyhow::Result;
use std::any::Any;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData}; use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData};
use crate::static_data::Item; use crate::static_data::Item;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// A script resolver deals with the resolving of scripts. These scripts are non-hardcoded /// A script resolver deals with the resolving of scripts. These scripts are non-hardcoded
/// implementations of different effects in Pokemon. This allows for things such as generational /// implementations of different effects in Pokemon. This allows for things such as generational
/// differences, and custom implementations. /// differences, and custom implementations.
pub trait ScriptResolver: Debug + ValueIdentifiable { pub trait ScriptResolver: Debug {
/// Loads a standard script with a given unique combination of category and key. If no script /// Loads a standard script with a given unique combination of category and key. If no script
/// can be created with this combination, returns None. /// can be created with this combination, returns None.
fn load_script( fn load_script(
@ -23,6 +24,8 @@ pub trait ScriptResolver: Debug + ValueIdentifiable {
/// combinations, returns None. Note that ItemScripts are immutable, as their script should be /// combinations, returns None. Note that ItemScripts are immutable, as their script should be
/// shared between all different usages. /// shared between all different usages.
fn load_item_script(&self, _key: &dyn Item) -> Result<Option<Arc<dyn ItemScript>>>; fn load_item_script(&self, _key: &dyn Item) -> Result<Option<Arc<dyn ItemScript>>>;
fn as_any(&self) -> &dyn std::any::Any;
} }
use std::fmt::Display; use std::fmt::Display;
@ -57,16 +60,7 @@ pub enum ScriptCategory {
/// A basic empty script resolver, that always returns None. /// A basic empty script resolver, that always returns None.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct EmptyScriptResolver { pub struct EmptyScriptResolver {}
/// A unique identifier so we know what value this is.
pub identifier: ValueIdentifier,
}
impl ValueIdentifiable for EmptyScriptResolver {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
impl ScriptResolver for EmptyScriptResolver { impl ScriptResolver for EmptyScriptResolver {
fn load_script( fn load_script(
@ -81,4 +75,8 @@ impl ScriptResolver for EmptyScriptResolver {
fn load_item_script(&self, _key: &dyn Item) -> Result<Option<Arc<dyn ItemScript>>> { fn load_item_script(&self, _key: &dyn Item) -> Result<Option<Arc<dyn ItemScript>>> {
Ok(None) Ok(None)
} }
fn as_any(&self) -> &dyn Any {
self
}
} }

View File

@ -21,13 +21,11 @@ use crate::dynamic_data::VolatileScriptsOwner;
use crate::dynamic_data::{is_valid_target, ScriptWrapper}; use crate::dynamic_data::{is_valid_target, ScriptWrapper};
use crate::dynamic_data::{ChoiceQueue, ScriptContainer}; use crate::dynamic_data::{ChoiceQueue, ScriptContainer};
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData}; use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData};
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; use crate::{script_hook, PkmnError, StringKey, VecExt};
/// The data of a battle. /// The data of a battle.
#[derive(Debug)] #[derive(Debug)]
struct BattleData { struct BattleData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The library the battle uses for handling. /// The library the battle uses for handling.
library: Arc<dyn DynamicLibrary>, library: Arc<dyn DynamicLibrary>,
/// A list of all different parties in the battle. /// A list of all different parties in the battle.
@ -99,7 +97,6 @@ impl Battle {
} }
let battle = BattleData { let battle = BattleData {
identifier: Default::default(),
library, library,
parties, parties,
can_flee, can_flee,
@ -127,13 +124,6 @@ impl Battle {
battle battle
} }
/// Returns a weak reference to the battle.
pub fn weak(&self) -> WeakBattleReference {
WeakBattleReference {
data: Arc::downgrade(&self.data),
}
}
/// The library the battle uses for handling. /// The library the battle uses for handling.
pub fn library(&self) -> &Arc<dyn DynamicLibrary> { pub fn library(&self) -> &Arc<dyn DynamicLibrary> {
&self.data.library &self.data.library
@ -272,7 +262,7 @@ impl Battle {
} }
/// Try and set the choice for the battle. If the choice is not valid, this returns false. /// Try and set the choice for the battle. If the choice is not valid, this returns false.
pub fn try_set_choice(&self, choice: TurnChoice) -> Result<bool> { pub fn try_set_choice(&self, choice: Arc<TurnChoice>) -> Result<bool> {
if !self.can_use(&choice) { if !self.can_use(&choice) {
return Ok(false); return Ok(false);
} }
@ -380,6 +370,23 @@ impl Battle {
Ok(None) Ok(None)
} }
} }
/// Returns a weak reference to the battle.
pub fn weak(&self) -> WeakBattleReference {
WeakBattleReference {
data: Arc::downgrade(&self.data),
}
}
pub fn as_ptr(&self) -> *const c_void {
Arc::as_ptr(&self.data) as *const c_void
}
}
impl PartialEq for Battle {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.data, &other.data)
}
} }
impl WeakBattleReference { impl WeakBattleReference {
@ -437,12 +444,6 @@ impl ScriptSource for Battle {
} }
} }
impl ValueIdentifiable for Battle {
fn value_identifier(&self) -> ValueIdentifier {
self.data.identifier
}
}
/// The result of a battle. /// The result of a battle.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BattleResult { pub enum BattleResult {

View File

@ -3,14 +3,11 @@ use std::sync::Arc;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::models::pokemon_party::PokemonParty; use crate::dynamic_data::models::pokemon_party::PokemonParty;
use crate::{ValueIdentifiable, ValueIdentifier};
/// A battle party is a wrapper around a party, with the indices for which the party is responsible /// A battle party is a wrapper around a party, with the indices for which the party is responsible
/// on the field attached. /// on the field attached.
#[derive(Debug)] #[derive(Debug)]
pub struct BattleParty { pub struct BattleParty {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The party the BattleParty is holding. /// The party the BattleParty is holding.
party: Arc<PokemonParty>, party: Arc<PokemonParty>,
/// The indices for which the party is responsible, in the format (side, index) /// The indices for which the party is responsible, in the format (side, index)
@ -22,7 +19,6 @@ impl BattleParty {
/// for. /// for.
pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Result<Self> { pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Result<Self> {
Ok(Self { Ok(Self {
identifier: Default::default(),
party, party,
responsible_indices, responsible_indices,
}) })
@ -58,9 +54,3 @@ impl BattleParty {
&self.party &self.party
} }
} }
impl ValueIdentifiable for BattleParty {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -6,13 +6,11 @@ use crate::dynamic_data::models::executing_move::ExecutingMove;
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::script_handling::ScriptSource;
use crate::utils::Random; use crate::utils::Random;
use crate::{script_hook, PkmnError, ValueIdentifiable, ValueIdentifier}; use crate::{script_hook, PkmnError};
/// The RNG for a battle. /// The RNG for a battle.
#[derive(Default)] #[derive(Default)]
pub struct BattleRandom { pub struct BattleRandom {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The actual underlying RNG. This is in a mutex, so it is thread safe, and can be ran /// The actual underlying RNG. This is in a mutex, so it is thread safe, and can be ran
/// predictably, with guaranteed the same outputs. /// predictably, with guaranteed the same outputs.
random: Mutex<Random>, random: Mutex<Random>,
@ -22,7 +20,6 @@ impl BattleRandom {
/// Initializes a new RNG with a given seed. /// Initializes a new RNG with a given seed.
pub fn new_with_seed(seed: u128) -> Self { pub fn new_with_seed(seed: u128) -> Self {
BattleRandom { BattleRandom {
identifier: Default::default(),
random: Mutex::new(Random::new(seed)), random: Mutex::new(Random::new(seed)),
} }
} }
@ -104,8 +101,6 @@ impl Debug for BattleRandom {
impl Clone for BattleRandom { impl Clone for BattleRandom {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
identifier: Default::default(),
// As cloning when we can't get a lock on the randomness is completely impossible, we // As cloning when we can't get a lock on the randomness is completely impossible, we
// should unwrap here. // should unwrap here.
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -113,9 +108,3 @@ impl Clone for BattleRandom {
} }
} }
} }
impl ValueIdentifiable for BattleRandom {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -15,13 +15,11 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
use crate::dynamic_data::ScriptSet; use crate::dynamic_data::ScriptSet;
use crate::dynamic_data::VolatileScriptsOwner; use crate::dynamic_data::VolatileScriptsOwner;
use crate::dynamic_data::{Script, WeakBattleReference}; use crate::dynamic_data::{Script, WeakBattleReference};
use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; use crate::{script_hook, StringKey, VecExt};
/// The data that is stored for a battle side. /// The data that is stored for a battle side.
#[derive(Debug)] #[derive(Debug)]
struct BattleSideData { struct BattleSideData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The index of the side on the battle. /// The index of the side on the battle.
index: u8, index: u8,
/// The number of Pokemon that can be on the side. /// The number of Pokemon that can be on the side.
@ -47,7 +45,7 @@ struct BattleSideData {
} }
/// A side on a battle. /// A side on a battle.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct BattleSide { pub struct BattleSide {
/// The data that is stored for this side. /// The data that is stored for this side.
data: Arc<BattleSideData>, data: Arc<BattleSideData>,
@ -77,7 +75,6 @@ impl BattleSide {
Self { Self {
data: Arc::new(BattleSideData { data: Arc::new(BattleSideData {
identifier: Default::default(),
index, index,
pokemon_per_side, pokemon_per_side,
pokemon, pokemon,
@ -171,11 +168,11 @@ impl BattleSide {
} }
/// Sets a choice for a Pokemon on this side. /// Sets a choice for a Pokemon on this side.
pub(crate) fn set_choice(&self, choice: TurnChoice) -> Result<()> { pub(crate) fn set_choice(&self, choice: Arc<TurnChoice>) -> Result<()> {
for (index, pokemon_slot) in self.data.pokemon.read().iter().enumerate() { for (index, pokemon_slot) in self.data.pokemon.read().iter().enumerate() {
if let Some(pokemon) = pokemon_slot { if let Some(pokemon) = pokemon_slot {
if Pokemon::eq(pokemon, choice.user()) { if Pokemon::eq(pokemon, choice.user()) {
self.data.choices.write().get_mut_res(index)?.replace(choice.into()); self.data.choices.write().get_mut_res(index)?.replace(choice);
self.data.choices_set.fetch_add(1, Ordering::SeqCst); self.data.choices_set.fetch_add(1, Ordering::SeqCst);
return Ok(()); return Ok(());
} }
@ -337,7 +334,7 @@ impl BattleSide {
None => return Ok(false), None => return Ok(false),
}; };
// Don't allow swapping if different parties are responsible for the indices. // Don't allow swapping if different parties are responsible for the indices.
if party_a.value_identifier() != party_b.value_identifier() { if !Arc::ptr_eq(party_a, party_b) {
return Ok(false); return Ok(false);
} }
@ -356,6 +353,16 @@ impl BattleSide {
data: Arc::downgrade(&self.data), data: Arc::downgrade(&self.data),
} }
} }
pub fn as_ptr(&self) -> *const c_void {
Arc::as_ptr(&self.data) as *const c_void
}
}
impl PartialEq for BattleSide {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.data, &other.data)
}
} }
impl WeakBattleSideReference { impl WeakBattleSideReference {
@ -411,9 +418,3 @@ impl ScriptSource for BattleSide {
self.battle()?.collect_scripts(scripts) self.battle()?.collect_scripts(scripts)
} }
} }
impl ValueIdentifiable for BattleSide {
fn value_identifier(&self) -> ValueIdentifier {
self.data.identifier
}
}

View File

@ -12,13 +12,11 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
use crate::dynamic_data::ScriptContainer; use crate::dynamic_data::ScriptContainer;
use crate::dynamic_data::TargetList; use crate::dynamic_data::TargetList;
use crate::static_data::{MoveData, TypeIdentifier}; use crate::static_data::{MoveData, TypeIdentifier};
use crate::{PkmnError, ValueIdentifiable, ValueIdentifier}; use crate::PkmnError;
/// A hit data is the data for a single hit, on a single target. /// A hit data is the data for a single hit, on a single target.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct HitData { pub struct HitData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// Whether or not the hit is critical. /// Whether or not the hit is critical.
critical: AtomicBool, critical: AtomicBool,
/// The base power of the hit. /// The base power of the hit.
@ -89,8 +87,6 @@ impl HitData {
#[derive(Debug)] #[derive(Debug)]
pub struct ExecutingMove { pub struct ExecutingMove {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The number of hits this move has. /// The number of hits this move has.
number_of_hits: u8, number_of_hits: u8,
/// A list of hits for this move. For multi target multi hit moves, this stores the hits linearly, /// A list of hits for this move. For multi target multi hit moves, this stores the hits linearly,
@ -126,7 +122,6 @@ impl ExecutingMove {
hits.push(Arc::new(HitData::default())) hits.push(Arc::new(HitData::default()))
} }
Self { Self {
identifier: Default::default(),
number_of_hits, number_of_hits,
hits, hits,
user, user,
@ -238,15 +233,3 @@ impl ScriptSource for ExecutingMove {
Ok(()) Ok(())
} }
} }
impl ValueIdentifiable for ExecutingMove {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
impl ValueIdentifiable for HitData {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -2,14 +2,11 @@ use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc; use std::sync::Arc;
use crate::static_data::MoveData; use crate::static_data::MoveData;
use crate::{ValueIdentifiable, ValueIdentifier};
/// A learned move is the data attached to a Pokemon for a move it has learned. It has information /// A learned move is the data attached to a Pokemon for a move it has learned. It has information
/// such as the remaining amount of users, how it has been learned, etc. /// such as the remaining amount of users, how it has been learned, etc.
#[derive(Debug)] #[derive(Debug)]
pub struct LearnedMove { pub struct LearnedMove {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The immutable move information of the move. /// The immutable move information of the move.
move_data: Arc<dyn MoveData>, move_data: Arc<dyn MoveData>,
/// The maximal power points for this move. /// The maximal power points for this move.
@ -36,7 +33,6 @@ impl LearnedMove {
pub fn new(move_data: Arc<dyn MoveData>, learn_method: MoveLearnMethod) -> Self { pub fn new(move_data: Arc<dyn MoveData>, learn_method: MoveLearnMethod) -> Self {
let max_pp = move_data.base_usages(); let max_pp = move_data.base_usages();
Self { Self {
identifier: Default::default(),
move_data, move_data,
max_pp, max_pp,
remaining_pp: AtomicU8::new(max_pp), remaining_pp: AtomicU8::new(max_pp),
@ -92,12 +88,6 @@ impl LearnedMove {
} }
} }
impl ValueIdentifiable for LearnedMove {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
mod tests { mod tests {

View File

@ -26,13 +26,11 @@ use crate::static_data::TypeIdentifier;
use crate::static_data::{Ability, Statistic}; use crate::static_data::{Ability, Statistic};
use crate::static_data::{ClampedStatisticSet, StatisticSet}; use crate::static_data::{ClampedStatisticSet, StatisticSet};
use crate::utils::Random; use crate::utils::Random;
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; use crate::{script_hook, PkmnError, StringKey, VecExt};
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
/// The data of a Pokemon. /// The data of a Pokemon.
struct PokemonData { struct PokemonData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The library data of the Pokemon. /// The library data of the Pokemon.
library: Arc<dyn DynamicLibrary>, library: Arc<dyn DynamicLibrary>,
/// The species of the Pokemon. /// The species of the Pokemon.
@ -165,7 +163,6 @@ impl Pokemon {
.get_nature(nature) .get_nature(nature)
.ok_or(PkmnError::InvalidNatureName { nature: nature.clone() })?; .ok_or(PkmnError::InvalidNatureName { nature: nature.clone() })?;
let pokemon_data = PokemonData { let pokemon_data = PokemonData {
identifier: Default::default(),
library, library,
species: RwLock::new(species), species: RwLock::new(species),
form: RwLock::new(form.clone()), form: RwLock::new(form.clone()),
@ -546,7 +543,7 @@ impl Pokemon {
/// Change the form of the Pokemon. /// Change the form of the Pokemon.
pub fn change_form(&self, form: &Arc<dyn Form>) -> Result<()> { pub fn change_form(&self, form: &Arc<dyn Form>) -> Result<()> {
if self.form().value_identifier() == form.value_identifier() { if Arc::ptr_eq(&self.form(), form) {
return Ok(()); return Ok(());
} }
*self.data.form.write() = form.clone(); *self.data.form.write() = form.clone();
@ -818,6 +815,10 @@ impl Pokemon {
data: Arc::downgrade(&self.data), data: Arc::downgrade(&self.data),
} }
} }
pub fn as_ptr(&self) -> *const c_void {
Arc::as_ptr(&self.data) as *const c_void
}
} }
impl PartialEq for Pokemon { impl PartialEq for Pokemon {
@ -938,12 +939,6 @@ impl VolatileScriptsOwner for Pokemon {
} }
} }
impl ValueIdentifiable for Pokemon {
fn value_identifier(&self) -> ValueIdentifier {
self.data.identifier
}
}
/// A source of damage. This should be as unique as possible. /// A source of damage. This should be as unique as possible.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
#[repr(u8)] #[repr(u8)]

View File

@ -3,13 +3,11 @@ use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock}; use parking_lot::{RawRwLock, RwLock};
use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::models::pokemon::Pokemon;
use crate::{ValueIdentifiable, ValueIdentifier, VecExt}; use crate::VecExt;
/// A list of Pokemon belonging to a trainer. /// A list of Pokemon belonging to a trainer.
#[derive(Debug)] #[derive(Debug)]
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: RwLock<Vec<Option<Pokemon>>>, pokemon: RwLock<Vec<Option<Pokemon>>>,
} }
@ -22,7 +20,6 @@ impl PokemonParty {
pokemon.push(None); pokemon.push(None);
} }
Self { Self {
identifier: Default::default(),
pokemon: RwLock::new(pokemon), pokemon: RwLock::new(pokemon),
} }
} }
@ -30,7 +27,6 @@ impl PokemonParty {
/// Instantiates a party with a list. /// Instantiates a party with a list.
pub fn new_from_vec(pokemon: Vec<Option<Pokemon>>) -> Self { pub fn new_from_vec(pokemon: Vec<Option<Pokemon>>) -> Self {
Self { Self {
identifier: Default::default(),
pokemon: RwLock::new(pokemon), pokemon: RwLock::new(pokemon),
} }
} }
@ -118,9 +114,3 @@ impl PokemonParty {
false false
} }
} }
impl ValueIdentifiable for PokemonParty {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -1,105 +1,102 @@
use crate::dynamic_data::{FleeChoice, LearnedMove, MoveChoice, PassChoice, Pokemon, TurnChoice}; use crate::dynamic_data::{FleeChoice, LearnedMove, MoveChoice, PassChoice, Pokemon, TurnChoice};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use anyhow::anyhow; use anyhow::anyhow;
use std::ptr::drop_in_place; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
/// Disposes a turn choice.
#[no_mangle]
extern "C" fn turn_choice_drop(choice: OwnedPtr<TurnChoice>) {
unsafe { drop_in_place(choice) }
}
/// Get the user of the given choice. /// Get the user of the given choice.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_user(choice: ExternPointer<TurnChoice>) -> IdentifiablePointer<Pokemon> { extern "C" fn turn_choice_user(choice: FFIHandle<Arc<TurnChoice>>) -> FFIHandle<Pokemon> {
choice.as_ref().user().clone().into() FFIHandle::get_handle(choice.from_ffi_handle().user().clone().into())
} }
/// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon /// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon
/// at the start of the turn! /// at the start of the turn!
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_speed(choice: ExternPointer<TurnChoice>) -> u32 { extern "C" fn turn_choice_speed(choice: FFIHandle<Arc<TurnChoice>>) -> u32 {
choice.as_ref().speed() choice.from_ffi_handle().speed()
} }
/// Gets whether or not the choice has failed. If we notice this when we execute the choice, we /// Gets whether or not the choice has failed. If we notice this when we execute the choice, we
/// will not execute it. /// will not execute it.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_has_failed(choice: ExternPointer<TurnChoice>) -> u8 { extern "C" fn turn_choice_has_failed(choice: FFIHandle<Arc<TurnChoice>>) -> u8 {
u8::from(choice.as_ref().has_failed()) u8::from(choice.from_ffi_handle().has_failed())
} }
/// Fails the choice. This will prevent it from executing and run a specific fail handling during /// Fails the choice. This will prevent it from executing and run a specific fail handling during
/// execution. Note that this can not be undone. /// execution. Note that this can not be undone.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_fail(choice: ExternPointer<TurnChoice>) { extern "C" fn turn_choice_fail(choice: FFIHandle<Arc<TurnChoice>>) {
choice.as_ref().fail() choice.from_ffi_handle().fail()
} }
/// Creates a new Turn Choice with a move to use. /// Creates a new Turn Choice with a move to use.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_move_new( extern "C" fn turn_choice_move_new(
user: ExternPointer<Pokemon>, user: FFIHandle<Pokemon>,
learned_move: ExternPointer<Arc<LearnedMove>>, learned_move: FFIHandle<Arc<LearnedMove>>,
target_side: u8, target_side: u8,
target_index: u8, target_index: u8,
) -> IdentifiablePointer<TurnChoice> { ) -> FFIHandle<Arc<TurnChoice>> {
Box::new(TurnChoice::Move(MoveChoice::new( FFIHandle::get_handle(
user.as_ref().clone(), Arc::new(TurnChoice::Move(MoveChoice::new(
learned_move.as_ref().clone(), user.from_ffi_handle(),
target_side, learned_move.from_ffi_handle(),
target_index, target_side,
))) target_index,
.into() )))
.into(),
)
} }
/// The actual learned move on the Pokemon we use for this choice. /// The actual learned move on the Pokemon we use for this choice.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_move_learned_move( extern "C" fn turn_choice_move_learned_move(
choice: ExternPointer<TurnChoice>, choice: FFIHandle<Arc<TurnChoice>>,
) -> NativeResult<IdentifiablePointer<Arc<LearnedMove>>> { ) -> FFIResult<FFIHandle<Arc<LearnedMove>>> {
if let TurnChoice::Move(c) = choice.as_ref() { if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return NativeResult::ok(c.used_move().clone().into()); return FFIResult::ok(FFIHandle::get_handle(c.used_move().clone().into()));
} }
NativeResult::err(anyhow!("Turn choice was not a learned move")) FFIResult::err(anyhow!("Turn choice was not a learned move"))
} }
/// The target side the move is aimed at. /// The target side the move is aimed at.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_move_target_side(choice: ExternPointer<TurnChoice>) -> NativeResult<u8> { extern "C" fn turn_choice_move_target_side(choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<u8> {
if let TurnChoice::Move(c) = choice.as_ref() { if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return NativeResult::ok(c.target_side()); return FFIResult::ok(c.target_side());
} }
NativeResult::err(anyhow!("Turn choice was not a learned move")) FFIResult::err(anyhow!("Turn choice was not a learned move"))
} }
/// The Pokemon index on the side we're aiming at. /// The Pokemon index on the side we're aiming at.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_move_target_index(choice: ExternPointer<TurnChoice>) -> NativeResult<u8> { extern "C" fn turn_choice_move_target_index(choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<u8> {
if let TurnChoice::Move(c) = choice.as_ref() { if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return NativeResult::ok(c.target_index()); return FFIResult::ok(c.target_index());
} }
NativeResult::err(anyhow!("Turn choice was not a learned move")) FFIResult::err(anyhow!("Turn choice was not a learned move"))
} }
/// The priority of the move choice at the beginning of the turn. /// The priority of the move choice at the beginning of the turn.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_move_priority(choice: ExternPointer<TurnChoice>) -> NativeResult<i8> { extern "C" fn turn_choice_move_priority(choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<i8> {
if let TurnChoice::Move(c) = choice.as_ref() { if let TurnChoice::Move(c) = choice.from_ffi_handle().deref() {
return NativeResult::ok(c.priority()); return FFIResult::ok(c.priority());
} }
NativeResult::err(anyhow!("Turn choice was not a learned move")) FFIResult::err(anyhow!("Turn choice was not a learned move"))
} }
/// Creates a new Turn Choice for the user to flee. /// Creates a new Turn Choice for the user to flee.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_flee_new(user: ExternPointer<Pokemon>) -> IdentifiablePointer<TurnChoice> { extern "C" fn turn_choice_flee_new(user: FFIHandle<Pokemon>) -> FFIHandle<Arc<TurnChoice>> {
Box::new(TurnChoice::Flee(FleeChoice::new(user.as_ref().clone()))).into() FFIHandle::get_handle(Arc::new(TurnChoice::Flee(FleeChoice::new(user.from_ffi_handle()))).into())
} }
/// Creates a new Turn Choice for the user to pass the turn. /// Creates a new Turn Choice for the user to pass the turn.
#[no_mangle] #[no_mangle]
extern "C" fn turn_choice_pass_new(user: ExternPointer<Pokemon>) -> IdentifiablePointer<TurnChoice> { extern "C" fn turn_choice_pass_new(user: FFIHandle<Pokemon>) -> FFIHandle<Arc<TurnChoice>> {
Box::new(TurnChoice::Pass(PassChoice::new(user.as_ref().clone()))).into() FFIHandle::get_handle(Arc::new(TurnChoice::Pass(PassChoice::new(user.from_ffi_handle()))).into())
} }

View File

@ -1,63 +1,61 @@
use crate::dynamic_data::{BattleStatCalculator, Gen7BattleStatCalculator, Pokemon}; use crate::dynamic_data::{BattleStatCalculator, Gen7BattleStatCalculator, Pokemon};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ExternPointer, FFIResult};
use crate::static_data::{Statistic, StatisticSet}; use crate::static_data::{Statistic, StatisticSet};
use std::ptr::drop_in_place; use std::ops::Deref;
use std::sync::Arc;
/// Creates a new Gen 7 battle stat calculator /// Creates a new Gen 7 battle stat calculator
#[no_mangle] #[no_mangle]
extern "C" fn gen_7_battle_stat_calculator_new() -> IdentifiablePointer<Box<dyn BattleStatCalculator>> { extern "C" fn gen_7_battle_stat_calculator_new() -> FFIHandle<Arc<dyn BattleStatCalculator>> {
let v: Box<dyn BattleStatCalculator> = Box::new(Gen7BattleStatCalculator::new()); let v: Arc<dyn BattleStatCalculator> = Arc::new(Gen7BattleStatCalculator::new());
let id = v.value_identifier(); FFIHandle::get_handle(v.into())
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a battle stat calculator.
#[no_mangle]
extern "C" fn battle_stat_calculator_drop(ptr: OwnedPtr<Box<dyn BattleStatCalculator>>) {
unsafe { drop_in_place(ptr) };
} }
/// Calculate all the flat stats of a Pokemon, disregarding stat boosts. /// Calculate all the flat stats of a Pokemon, disregarding stat boosts.
#[no_mangle] #[no_mangle]
extern "C" fn battle_stat_calculator_calculate_flat_stats( extern "C" fn battle_stat_calculator_calculate_flat_stats(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>, ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>, pokemon: ExternPointer<Pokemon>,
mut stats: ExternPointer<Box<StatisticSet<u32>>>, stats: FFIHandle<Arc<StatisticSet<u32>>>,
) -> NativeResult<()> { ) -> FFIResult<()> {
ptr.as_ref() ptr.from_ffi_handle()
.calculate_flat_stats(pokemon.as_ref(), stats.as_mut()) .calculate_flat_stats(pokemon.as_ref(), stats.from_ffi_handle().deref())
.into() .into()
} }
/// Calculate a single flat stat of a Pokemon, disregarding stat boost /// Calculate a single flat stat of a Pokemon, disregarding stat boost
#[no_mangle] #[no_mangle]
extern "C" fn battle_stat_calculator_calculate_flat_stat( extern "C" fn battle_stat_calculator_calculate_flat_stat(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>, ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>, pokemon: FFIHandle<Pokemon>,
stat: Statistic, stat: Statistic,
) -> NativeResult<u32> { ) -> FFIResult<u32> {
ptr.as_ref().calculate_flat_stat(pokemon.as_ref(), stat).into() ptr.from_ffi_handle()
.calculate_flat_stat(&pokemon.from_ffi_handle(), stat)
.into()
} }
/// Calculate all the boosted stats of a Pokemon, including stat boosts. /// Calculate all the boosted stats of a Pokemon, including stat boosts.
#[no_mangle] #[no_mangle]
extern "C" fn battle_stat_calculator_calculate_boosted_stats( extern "C" fn battle_stat_calculator_calculate_boosted_stats(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>, ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>, pokemon: FFIHandle<Pokemon>,
mut stats: ExternPointer<Box<StatisticSet<u32>>>, stats: FFIHandle<Arc<StatisticSet<u32>>>,
) -> NativeResult<()> { ) -> FFIResult<()> {
ptr.as_ref() ptr.from_ffi_handle()
.calculate_boosted_stats(pokemon.as_ref(), stats.as_mut()) .calculate_boosted_stats(&pokemon.from_ffi_handle(), stats.from_ffi_handle().deref())
.into() .into()
} }
/// Calculate a single boosted stat of a Pokemon, including stat boosts. /// Calculate a single boosted stat of a Pokemon, including stat boosts.
#[no_mangle] #[no_mangle]
extern "C" fn battle_stat_calculator_calculate_boosted_stat( extern "C" fn battle_stat_calculator_calculate_boosted_stat(
ptr: ExternPointer<Box<dyn BattleStatCalculator>>, ptr: FFIHandle<Arc<dyn BattleStatCalculator>>,
pokemon: ExternPointer<Pokemon>, pokemon: FFIHandle<Pokemon>,
stat: Statistic, stat: Statistic,
) -> NativeResult<u32> { ) -> FFIResult<u32> {
ptr.as_ref().calculate_boosted_stat(pokemon.as_ref(), stat).into() ptr.from_ffi_handle()
.calculate_boosted_stat(&pokemon.from_ffi_handle(), stat)
.into()
} }

View File

@ -1,19 +1,11 @@
use crate::dynamic_data::{DamageLibrary, Gen7DamageLibrary}; use crate::dynamic_data::{DamageLibrary, Gen7DamageLibrary};
use crate::ffi::{IdentifiablePointer, OwnedPtr}; use crate::ffi::ffi_handle::FFIHandle;
use std::ptr::drop_in_place; use std::sync::Arc;
/// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage /// Creates a new generation 7 damage library. `has_randomness` defines whether a random damage
/// modifier (0.85x - 1.00x) is applied to the calculated damage. /// modifier (0.85x - 1.00x) is applied to the calculated damage.
#[no_mangle] #[no_mangle]
extern "C" fn gen_7_damage_library_new(has_randomness: u8) -> IdentifiablePointer<Box<dyn DamageLibrary>> { extern "C" fn gen_7_damage_library_new(has_randomness: u8) -> FFIHandle<Arc<dyn DamageLibrary>> {
let v: Box<dyn DamageLibrary> = Box::new(Gen7DamageLibrary::new(has_randomness == 1)); let v: Arc<dyn DamageLibrary> = Arc::new(Gen7DamageLibrary::new(has_randomness == 1));
let id = v.value_identifier(); FFIHandle::get_handle(v.into())
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a DamageLibrary.
#[no_mangle]
extern "C" fn damage_library_drop(ptr: OwnedPtr<Box<dyn DamageLibrary>>) {
unsafe { drop_in_place(ptr) };
} }

View File

@ -1,68 +1,59 @@
use crate::dynamic_data::{ use crate::dynamic_data::{
BattleStatCalculator, DamageLibrary, DynamicLibrary, DynamicLibraryImpl, MiscLibrary, ScriptResolver, BattleStatCalculator, DamageLibrary, DynamicLibrary, DynamicLibraryImpl, MiscLibrary, ScriptResolver,
}; };
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::static_data::StaticData; use crate::static_data::StaticData;
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new DynamicLibrary with given parameters. /// Instantiates a new DynamicLibrary with given parameters.
#[no_mangle] #[no_mangle]
extern "C" fn dynamic_library_new( extern "C" fn dynamic_library_new(
static_data: OwnedPtr<Arc<dyn StaticData>>, static_data: FFIHandle<Arc<dyn StaticData>>,
stat_calculator: OwnedPtr<Arc<dyn BattleStatCalculator>>, stat_calculator: FFIHandle<Arc<dyn BattleStatCalculator>>,
damage_library: OwnedPtr<Arc<dyn DamageLibrary>>, damage_library: FFIHandle<Arc<dyn DamageLibrary>>,
misc_library: OwnedPtr<Arc<dyn MiscLibrary>>, misc_library: FFIHandle<Arc<dyn MiscLibrary>>,
script_resolver: OwnedPtr<Box<dyn ScriptResolver>>, script_resolver: FFIHandle<Arc<dyn ScriptResolver>>,
) -> IdentifiablePointer<Arc<dyn DynamicLibrary>> { ) -> FFIHandle<Arc<dyn DynamicLibrary>> {
unsafe { let a: Arc<dyn DynamicLibrary> = Arc::new(DynamicLibraryImpl::new(
let a: Arc<dyn DynamicLibrary> = Arc::new(DynamicLibraryImpl::new( static_data.from_ffi_handle(),
static_data.read(), stat_calculator.from_ffi_handle(),
stat_calculator.read(), damage_library.from_ffi_handle(),
damage_library.read(), misc_library.from_ffi_handle(),
misc_library.read(), script_resolver.from_ffi_handle(),
*Box::from_raw(script_resolver), ));
)); FFIHandle::get_handle(a.into())
a.into()
}
}
/// Drops a dynamic library.
#[no_mangle]
extern "C" fn dynamic_library_drop(ptr: OwnedPtr<Arc<dyn DynamicLibrary>>) {
unsafe { drop_in_place(ptr) };
} }
/// The static data is the immutable storage data for this library. /// The static data is the immutable storage data for this library.
#[no_mangle] #[no_mangle]
extern "C" fn dynamic_library_get_static_data( extern "C" fn dynamic_library_get_static_data(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>, ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn StaticData>> { ) -> FFIHandle<Arc<dyn StaticData>> {
ptr.as_ref().static_data().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().static_data().clone().into())
} }
/// The stat calculator deals with the calculation of flat and boosted stats, based on the /// The stat calculator deals with the calculation of flat and boosted stats, based on the
/// Pokemons attributes. /// Pokemons attributes.
#[no_mangle] #[no_mangle]
extern "C" fn dynamic_library_get_stat_calculator( extern "C" fn dynamic_library_get_stat_calculator(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>, ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn BattleStatCalculator>> { ) -> FFIHandle<Arc<dyn BattleStatCalculator>> {
ptr.as_ref().stat_calculator().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().stat_calculator().clone().into())
} }
/// The damage calculator deals with the calculation of things relating to damage. /// The damage calculator deals with the calculation of things relating to damage.
#[no_mangle] #[no_mangle]
extern "C" fn dynamic_library_get_damage_calculator( extern "C" fn dynamic_library_get_damage_calculator(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>, ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn DamageLibrary>> { ) -> FFIHandle<Arc<dyn DamageLibrary>> {
ptr.as_ref().damage_calculator().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().damage_calculator().clone().into())
} }
/// The Misc Library holds minor functions that do not fall in any of the other libraries and /// The Misc Library holds minor functions that do not fall in any of the other libraries and
/// calculators. /// calculators.
#[no_mangle] #[no_mangle]
extern "C" fn dynamic_library_get_misc_library( extern "C" fn dynamic_library_get_misc_library(
ptr: ExternPointer<Arc<dyn DynamicLibrary>>, ptr: FFIHandle<Arc<dyn DynamicLibrary>>,
) -> IdentifiablePointer<Arc<dyn MiscLibrary>> { ) -> FFIHandle<Arc<dyn MiscLibrary>> {
ptr.as_ref().misc_library().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().misc_library().clone().into())
} }

View File

@ -1,18 +1,10 @@
use crate::dynamic_data::{Gen7MiscLibrary, MiscLibrary}; use crate::dynamic_data::{Gen7MiscLibrary, MiscLibrary};
use crate::ffi::{IdentifiablePointer, OwnedPtr}; use crate::ffi::ffi_handle::FFIHandle;
use std::ptr::drop_in_place; use std::sync::Arc;
/// Instantiates a new MiscLibrary. /// Instantiates a new MiscLibrary.
#[no_mangle] #[no_mangle]
extern "C" fn gen_7_misc_library_new() -> IdentifiablePointer<Box<dyn MiscLibrary>> { extern "C" fn gen_7_misc_library_new() -> FFIHandle<Arc<dyn MiscLibrary>> {
let v: Box<dyn MiscLibrary> = Box::new(Gen7MiscLibrary::new()); let v: Arc<dyn MiscLibrary> = Arc::new(Gen7MiscLibrary::new());
let id = v.value_identifier(); FFIHandle::get_handle(v.into())
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a MiscLibrary.
#[no_mangle]
extern "C" fn misc_library_drop(ptr: OwnedPtr<Box<dyn MiscLibrary>>) {
unsafe { drop_in_place(ptr) };
} }

View File

@ -1,49 +1,45 @@
use crate::dynamic_data::{EmptyScriptResolver, ScriptResolver}; use crate::dynamic_data::{EmptyScriptResolver, ScriptResolver};
use crate::ffi::{IdentifiablePointer, OwnedPtr}; use crate::ffi::ffi_handle::FFIHandle;
use std::ptr::drop_in_place; use std::sync::Arc;
/// Instantiates a basic empty script resolver, that always returns None. /// Instantiates a basic empty script resolver, that always returns None.
#[no_mangle] #[no_mangle]
extern "C" fn empty_script_resolver_new() -> IdentifiablePointer<Box<dyn ScriptResolver>> { extern "C" fn empty_script_resolver_new() -> FFIHandle<Arc<dyn ScriptResolver>> {
let v: Box<dyn ScriptResolver> = Box::new(EmptyScriptResolver { let v: Arc<dyn ScriptResolver> = Arc::new(EmptyScriptResolver {});
identifier: Default::default(), FFIHandle::get_handle(v.into())
});
let id = v.value_identifier();
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
}
/// Drops a script resolver.
#[no_mangle]
extern "C" fn script_resolver_drop(ptr: OwnedPtr<Box<dyn ScriptResolver>>) {
unsafe { drop_in_place(ptr) };
} }
/// Foreign function interfaces for the Webassembly script resolver. /// Foreign function interfaces for the Webassembly script resolver.
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
mod web_assembly_script_resolver { mod web_assembly_script_resolver {
use crate::dynamic_data::ScriptResolver; use crate::dynamic_data::ScriptResolver;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver; use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver;
use std::sync::Arc;
/// Instantiates a new WebAssemblyScriptResolver. /// Instantiates a new WebAssemblyScriptResolver.
#[no_mangle] #[no_mangle]
extern "C" fn webassembly_script_resolver_new() -> IdentifiablePointer<Box<dyn ScriptResolver>> { extern "C" fn webassembly_script_resolver_new() -> FFIHandle<Arc<dyn ScriptResolver>> {
let v: Box<dyn ScriptResolver> = WebAssemblyScriptResolver::new(); let v: Arc<dyn ScriptResolver> = WebAssemblyScriptResolver::new();
let id = v.value_identifier(); FFIHandle::get_handle(v.into())
let ptr = Box::into_raw(Box::new(v));
IdentifiablePointer::new(ptr, id)
} }
/// Load a compiled WASM module. /// Load a compiled WASM module.
#[no_mangle] #[no_mangle]
extern "C" fn webassembly_script_resolver_load_wasm_from_bytes( extern "C" fn webassembly_script_resolver_load_wasm_from_bytes(
mut ptr: ExternPointer<Box<WebAssemblyScriptResolver>>, ptr: FFIHandle<Arc<dyn ScriptResolver>>,
arr: *const u8, arr: *const u8,
len: usize, len: usize,
) -> NativeResult<()> { ) -> FFIResult<()> {
#[allow(clippy::unwrap_used)] // Unwrap used, but we know it cannot fail.
unsafe { unsafe {
ptr.as_mut() let script_resolver = ptr.from_ffi_handle();
let wasm_script_resolver = script_resolver
.as_any()
.downcast_ref::<WebAssemblyScriptResolver>()
.unwrap();
wasm_script_resolver
.load_wasm_from_bytes(std::slice::from_raw_parts(arr, len)) .load_wasm_from_bytes(std::slice::from_raw_parts(arr, len))
.into() .into()
} }
@ -51,9 +47,13 @@ mod web_assembly_script_resolver {
/// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver.
#[no_mangle] #[no_mangle]
extern "C" fn webassembly_script_resolver_finalize( #[allow(clippy::unwrap_used)] // Unwrap used, but we know it cannot fail.
mut ptr: ExternPointer<Box<WebAssemblyScriptResolver>>, extern "C" fn webassembly_script_resolver_finalize(ptr: FFIHandle<Arc<dyn ScriptResolver>>) -> FFIResult<()> {
) -> NativeResult<()> { let script_resolver = ptr.from_ffi_handle();
ptr.as_mut().finalize().into() let wasm_script_resolver = script_resolver
.as_any()
.downcast_ref::<WebAssemblyScriptResolver>()
.unwrap();
wasm_script_resolver.finalize().into()
} }
} }

View File

@ -2,16 +2,18 @@ use crate::dynamic_data::{
Battle, BattleParty, BattleRandom, BattleResult, BattleSide, DynamicLibrary, Pokemon, TurnChoice, Battle, BattleParty, BattleRandom, BattleResult, BattleSide, DynamicLibrary, Pokemon, TurnChoice,
}; };
use crate::ffi::dynamic_data::models::native_event_hook::NativeEventHook; use crate::ffi::dynamic_data::models::native_event_hook::NativeEventHook;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
/// Initializes a new battle. /// Initializes a new battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_new( extern "C" fn battle_new(
library: ExternPointer<Arc<dyn DynamicLibrary>>, library: FFIHandle<Arc<dyn DynamicLibrary>>,
parties: *const OwnedPtr<Arc<BattleParty>>, parties: *const FFIHandle<Arc<BattleParty>>,
parties_length: usize, parties_length: usize,
can_flee: u8, can_flee: u8,
number_of_sides: u8, number_of_sides: u8,
@ -19,11 +21,11 @@ extern "C" fn battle_new(
// NOTE: Split into two due to u128 not being ABI safe: https://github.com/rust-lang/rust/issues/54341 // NOTE: Split into two due to u128 not being ABI safe: https://github.com/rust-lang/rust/issues/54341
random_seed_1: u64, random_seed_1: u64,
random_seed_2: u64, random_seed_2: u64,
) -> IdentifiablePointer<Battle> { ) -> FFIHandle<Battle> {
let parties = unsafe { let parties = unsafe {
std::slice::from_raw_parts(parties, parties_length) std::slice::from_raw_parts(parties, parties_length)
.iter() .iter()
.map(|x| *Box::from_raw(*x)) .map(|x| x.from_ffi_handle())
.collect() .collect()
}; };
@ -34,99 +36,98 @@ extern "C" fn battle_new(
}; };
let random_seed = if random_seed == 0 { None } else { Some(random_seed) }; let random_seed = if random_seed == 0 { None } else { Some(random_seed) };
Battle::new( FFIHandle::get_handle(
library.as_ref().clone(), Battle::new(
parties, library.from_ffi_handle(),
can_flee == 1, parties,
number_of_sides, can_flee == 1,
pokemon_per_side, number_of_sides,
random_seed, pokemon_per_side,
random_seed,
)
.into(),
) )
.into()
} }
/// The library the battle uses for handling. /// The library the battle uses for handling.
#[no_mangle] #[no_mangle]
extern "C" fn battle_library(ptr: ExternPointer<Arc<Battle>>) -> IdentifiablePointer<Arc<dyn DynamicLibrary>> { extern "C" fn battle_library(ptr: FFIHandle<Battle>) -> FFIHandle<Arc<dyn DynamicLibrary>> {
ptr.as_ref().library().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().library().clone().into())
} }
/// The length of the list of all different parties in the battle. /// The length of the list of all different parties in the battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_parties_length(ptr: ExternPointer<Arc<Battle>>) -> usize { extern "C" fn battle_parties_length(ptr: FFIHandle<Battle>) -> usize {
ptr.as_ref().parties().len() ptr.from_ffi_handle().parties().len()
} }
/// Get a party in the battle. /// Get a party in the battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_parties_get( extern "C" fn battle_parties_get(ptr: FFIHandle<Battle>, index: usize) -> FFIHandle<Arc<BattleParty>> {
ptr: ExternPointer<Arc<Battle>>, if let Some(v) = ptr.from_ffi_handle().parties().get(index) {
index: usize, FFIHandle::get_handle(v.clone().into())
) -> IdentifiablePointer<Arc<BattleParty>> {
if let Some(v) = ptr.as_ref().parties().get(index) {
v.clone().into()
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Whether or not Pokemon can flee from the battle. /// Whether or not Pokemon can flee from the battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_can_flee(ptr: ExternPointer<Arc<Battle>>) -> u8 { extern "C" fn battle_can_flee(ptr: FFIHandle<Battle>) -> u8 {
u8::from(ptr.as_ref().can_flee()) u8::from(ptr.from_ffi_handle().can_flee())
} }
/// The number of sides in the battle. Typically 2. /// The number of sides in the battle. Typically 2.
#[no_mangle] #[no_mangle]
extern "C" fn battle_number_of_sides(ptr: ExternPointer<Arc<Battle>>) -> u8 { extern "C" fn battle_number_of_sides(ptr: FFIHandle<Battle>) -> u8 {
ptr.as_ref().number_of_sides() ptr.from_ffi_handle().number_of_sides()
} }
/// The number of Pokemon that can be on each side. /// The number of Pokemon that can be on each side.
#[no_mangle] #[no_mangle]
extern "C" fn battle_pokemon_per_side(ptr: ExternPointer<Arc<Battle>>) -> u8 { extern "C" fn battle_pokemon_per_side(ptr: FFIHandle<Battle>) -> u8 {
ptr.as_ref().pokemon_per_side() ptr.from_ffi_handle().pokemon_per_side()
} }
/// The length of the list of all different sides in the battle. /// The length of the list of all different sides in the battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_sides_length(ptr: ExternPointer<Arc<Battle>>) -> usize { extern "C" fn battle_sides_length(ptr: FFIHandle<Battle>) -> usize {
ptr.as_ref().sides().len() ptr.from_ffi_handle().sides().len()
} }
/// Get a side in the battle. /// Get a side in the battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_sides_get(ptr: ExternPointer<Arc<Battle>>, index: usize) -> IdentifiablePointer<BattleSide> { extern "C" fn battle_sides_get(ptr: FFIHandle<Battle>, index: usize) -> FFIHandle<BattleSide> {
if let Some(v) = ptr.as_ref().sides().get(index) { if let Some(v) = ptr.from_ffi_handle().sides().get(index) {
(v as *const BattleSide).into() FFIHandle::get_handle(v.clone().into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// The RNG used for the battle. /// The RNG used for the battle.
#[no_mangle] #[no_mangle]
extern "C" fn battle_random(ptr: ExternPointer<Arc<Battle>>) -> IdentifiablePointer<Arc<BattleRandom>> { extern "C" fn battle_random(ptr: FFIHandle<Battle>) -> FFIHandle<Arc<BattleRandom>> {
ptr.as_ref().random().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().random().clone().into())
} }
/// Whether or not the battle has ended. /// Whether or not the battle has ended.
#[no_mangle] #[no_mangle]
extern "C" fn battle_has_ended(ptr: ExternPointer<Arc<Battle>>) -> u8 { extern "C" fn battle_has_ended(ptr: FFIHandle<Battle>) -> u8 {
u8::from(ptr.as_ref().has_ended()) u8::from(ptr.from_ffi_handle().has_ended())
} }
/// Whether or not we have a conclusive winner /// Whether or not we have a conclusive winner
#[no_mangle] #[no_mangle]
extern "C" fn battle_has_conclusive_result(ptr: ExternPointer<Arc<Battle>>) -> u8 { extern "C" fn battle_has_conclusive_result(ptr: FFIHandle<Battle>) -> u8 {
u8::from(ptr.as_ref().result() != BattleResult::Inconclusive) u8::from(ptr.from_ffi_handle().result() != BattleResult::Inconclusive)
} }
/// If we have a conclusive winner, the side that has won. If we don't have a conclusive winner, this /// If we have a conclusive winner, the side that has won. If we don't have a conclusive winner, this
/// always returns 0. /// always returns 0.
#[no_mangle] #[no_mangle]
extern "C" fn battle_winning_side(ptr: ExternPointer<Arc<Battle>>) -> u8 { extern "C" fn battle_winning_side(ptr: FFIHandle<Battle>) -> u8 {
if let BattleResult::Conclusive(winner) = ptr.as_ref().result() { if let BattleResult::Conclusive(winner) = ptr.from_ffi_handle().result() {
winner winner
} else { } else {
0 0
@ -135,29 +136,29 @@ extern "C" fn battle_winning_side(ptr: ExternPointer<Arc<Battle>>) -> u8 {
/// Register a function to be triggered when an event in a battle occurs. /// Register a function to be triggered when an event in a battle occurs.
#[no_mangle] #[no_mangle]
extern "C" fn battle_register_event_hook(ptr: ExternPointer<Arc<Battle>>, f: NativeEventHook) { extern "C" fn battle_register_event_hook(ptr: FFIHandle<Battle>, f: NativeEventHook) {
ptr.as_ref().event_hook().register_listener(Box::new(f)) ptr.from_ffi_handle().event_hook().register_listener(Box::new(f))
} }
/// The index of the current turn. 0 until all choices /// The index of the current turn. 0 until all choices
#[no_mangle] #[no_mangle]
extern "C" fn battle_current_turn(ptr: ExternPointer<Arc<Battle>>) -> u32 { extern "C" fn battle_current_turn(ptr: FFIHandle<Battle>) -> u32 {
ptr.as_ref().current_turn() ptr.from_ffi_handle().current_turn()
} }
/// The time in nanoseconds the last turn took to run. Defaults to 0. /// The time in nanoseconds the last turn took to run. Defaults to 0.
#[no_mangle] #[no_mangle]
extern "C" fn battle_last_turn_time(ptr: ExternPointer<Arc<Battle>>) -> u64 { extern "C" fn battle_last_turn_time(ptr: FFIHandle<Battle>) -> u64 {
ptr.as_ref().last_turn_time() ptr.from_ffi_handle().last_turn_time()
} }
/// Get a Pokemon on the battlefield, on a specific side and an index on that side. /// Get a Pokemon on the battlefield, on a specific side and an index on that side.
#[no_mangle] #[no_mangle]
extern "C" fn battle_get_pokemon(ptr: ExternPointer<Arc<Battle>>, side: u8, index: u8) -> IdentifiablePointer<Pokemon> { extern "C" fn battle_get_pokemon(ptr: FFIHandle<Battle>, side: u8, index: u8) -> FFIHandle<Pokemon> {
if let Some(v) = ptr.as_ref().get_pokemon(side, index) { if let Some(v) = ptr.from_ffi_handle().get_pokemon(side, index) {
v.into() FFIHandle::get_handle(v.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
@ -165,47 +166,51 @@ extern "C" fn battle_get_pokemon(ptr: ExternPointer<Arc<Battle>>, side: u8, inde
/// for that slot, or a party is responsible, but has no remaining Pokemon to throw out anymore, /// for that slot, or a party is responsible, but has no remaining Pokemon to throw out anymore,
/// this returns false. /// this returns false.
#[no_mangle] #[no_mangle]
extern "C" fn battle_can_slot_be_filled(ptr: ExternPointer<Arc<Battle>>, side: u8, index: u8) -> u8 { extern "C" fn battle_can_slot_be_filled(ptr: FFIHandle<Battle>, side: u8, index: u8) -> u8 {
u8::from(ptr.as_ref().can_slot_be_filled(side, index)) u8::from(ptr.from_ffi_handle().can_slot_be_filled(side, index))
} }
/// Checks whether a choice is actually possible. /// Checks whether a choice is actually possible.
#[no_mangle] #[no_mangle]
extern "C" fn battle_can_use(ptr: ExternPointer<Arc<Battle>>, choice: ExternPointer<TurnChoice>) -> u8 { extern "C" fn battle_can_use(ptr: FFIHandle<Battle>, choice: FFIHandle<Arc<TurnChoice>>) -> u8 {
u8::from(ptr.as_ref().can_use(choice.as_ref())) u8::from(ptr.from_ffi_handle().can_use(choice.from_ffi_handle().deref()))
} }
/// Checks to see whether all Pokemon on the field have set their choices. If so, we then run /// Checks to see whether all Pokemon on the field have set their choices. If so, we then run
/// the turn. /// the turn.
#[no_mangle] #[no_mangle]
extern "C" fn battle_try_set_choice(ptr: ExternPointer<Arc<Battle>>, choice: OwnedPtr<TurnChoice>) -> NativeResult<u8> { extern "C" fn battle_try_set_choice(ptr: FFIHandle<Battle>, choice: FFIHandle<Arc<TurnChoice>>) -> FFIResult<u8> {
let choice = unsafe { choice.read() }; let choice = choice.from_ffi_handle();
let result = ptr.as_ref().try_set_choice(choice); let result = ptr.from_ffi_handle().try_set_choice(choice);
match result { match result {
Ok(b) => NativeResult::ok(u8::from(b)), Ok(b) => FFIResult::ok(u8::from(b)),
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }
/// Sets the current weather for the battle. If nullptr is passed, this clears the weather. /// Sets the current weather for the battle. If nullptr is passed, this clears the weather.
#[no_mangle] #[no_mangle]
extern "C" fn battle_set_weather(ptr: ExternPointer<Arc<Battle>>, weather: *const c_char) -> NativeResult<()> { extern "C" fn battle_set_weather(ptr: FFIHandle<Battle>, weather: *const c_char) -> FFIResult<()> {
if weather.is_null() { if weather.is_null() {
ptr.as_ref().set_weather(None).into() ptr.from_ffi_handle().set_weather(None).into()
} else { } else {
unsafe { ptr.as_ref().set_weather(Some(CStr::from_ptr(weather).into())).into() } unsafe {
ptr.from_ffi_handle()
.set_weather(Some(CStr::from_ptr(weather).into()))
.into()
}
} }
} }
/// Gets the current weather of the battle. If no weather is present, this returns nullptr. /// Gets the current weather of the battle. If no weather is present, this returns nullptr.
#[no_mangle] #[no_mangle]
extern "C" fn battle_weather_name(ptr: ExternPointer<Arc<Battle>>) -> NativeResult<*mut c_char> { extern "C" fn battle_weather_name(ptr: FFIHandle<Battle>) -> FFIResult<*mut c_char> {
match ptr.as_ref().weather_name() { match ptr.from_ffi_handle().weather_name() {
Ok(Some(w)) => match CString::new(w.str()) { Ok(Some(w)) => match CString::new(w.str()) {
Ok(s) => s.into_raw().into(), Ok(s) => s.into_raw().into(),
Err(e) => NativeResult::err(anyhow!("Failed to convert weather name to CString: {}", e)), Err(e) => FFIResult::err(anyhow!("Failed to convert weather name to CString: {}", e)),
}, },
Ok(None) => std::ptr::null_mut::<c_char>().into(), Ok(None) => std::ptr::null_mut::<c_char>().into(),
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }

View File

@ -1,5 +1,6 @@
use crate::dynamic_data::{BattleParty, Pokemon, PokemonParty}; use crate::dynamic_data::{BattleParty, Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::VecExt; use crate::VecExt;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use std::sync::Arc; use std::sync::Arc;
@ -8,12 +9,12 @@ use std::sync::Arc;
/// on the field attached. The indices are stored /// on the field attached. The indices are stored
#[no_mangle] #[no_mangle]
extern "C" fn battle_party_new( extern "C" fn battle_party_new(
party: ExternPointer<Arc<PokemonParty>>, party: FFIHandle<Arc<PokemonParty>>,
responsible_indices_ptr: *const u8, responsible_indices_ptr: *const u8,
responsible_indices_length: usize, responsible_indices_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<BattleParty>>> { ) -> FFIResult<FFIHandle<Arc<BattleParty>>> {
if responsible_indices_length % 2 != 0 { if responsible_indices_length % 2 != 0 {
return NativeResult::err(anyhow!("The length of responsible indices should be dividable by two")); return FFIResult::err(anyhow!("The length of responsible indices should be dividable by two"));
} }
let responsible_indices_slice = let responsible_indices_slice =
@ -31,43 +32,40 @@ extern "C" fn battle_party_new(
for i in 0..responsible_indices_length / 2 { for i in 0..responsible_indices_length / 2 {
match split(i) { match split(i) {
Ok(_) => (), Ok(_) => (),
Err(e) => return NativeResult::err(e), Err(e) => return FFIResult::err(e),
} }
} }
match BattleParty::new(party.as_ref().clone(), responsible_indices) { match BattleParty::new(party.from_ffi_handle(), responsible_indices) {
Ok(v) => NativeResult::ok(Arc::new(v).into()), Ok(v) => FFIResult::ok(FFIHandle::get_handle(Arc::new(v).into())),
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }
/// Checks whether the party is responsible for the given index. /// Checks whether the party is responsible for the given index.
#[no_mangle] #[no_mangle]
extern "C" fn battle_party_is_responsible_for_index(ptr: ExternPointer<Arc<BattleParty>>, side: u8, index: u8) -> u8 { extern "C" fn battle_party_is_responsible_for_index(ptr: FFIHandle<Arc<BattleParty>>, side: u8, index: u8) -> u8 {
u8::from(ptr.as_ref().is_responsible_for_index(side, index)) u8::from(ptr.from_ffi_handle().is_responsible_for_index(side, index))
} }
/// Whether or not the party has non fainted Pokemon that could be thrown out into the field. /// Whether or not the party has non fainted Pokemon that could be thrown out into the field.
#[no_mangle] #[no_mangle]
extern "C" fn battle_party_has_pokemon_not_in_field(ptr: ExternPointer<Arc<BattleParty>>) -> u8 { extern "C" fn battle_party_has_pokemon_not_in_field(ptr: FFIHandle<Arc<BattleParty>>) -> u8 {
u8::from(ptr.as_ref().has_pokemon_not_in_field()) u8::from(ptr.from_ffi_handle().has_pokemon_not_in_field())
} }
/// Gets a Pokemon at an index. /// Gets a Pokemon at an index.
#[no_mangle] #[no_mangle]
extern "C" fn battle_party_get_pokemon( extern "C" fn battle_party_get_pokemon(ptr: FFIHandle<Arc<BattleParty>>, index: usize) -> FFIHandle<Pokemon> {
ptr: ExternPointer<Arc<BattleParty>>, if let Some(v) = ptr.from_ffi_handle().get_pokemon(index) {
index: usize, FFIHandle::get_handle(v.into())
) -> IdentifiablePointer<Pokemon> {
if let Some(v) = ptr.as_ref().get_pokemon(index) {
v.into()
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Gets the underlying Pokemon Party /// Gets the underlying Pokemon Party
#[no_mangle] #[no_mangle]
extern "C" fn battle_party_party(ptr: ExternPointer<Arc<BattleParty>>) -> IdentifiablePointer<Arc<PokemonParty>> { extern "C" fn battle_party_party(ptr: FFIHandle<Arc<BattleParty>>) -> FFIHandle<Arc<PokemonParty>> {
ptr.as_ref().party().clone().into() FFIHandle::get_handle(ptr.from_ffi_handle().party().clone().into())
} }

View File

@ -1,5 +1,6 @@
use crate::dynamic_data::{Event, Pokemon}; use crate::dynamic_data::{Event, Pokemon};
use crate::ffi::{ExternPointer, IdentifiablePointer}; use crate::ffi::ExternPointer;
use crate::ffi::FFIHandle;
/// The kind of the event. /// The kind of the event.
#[no_mangle] #[no_mangle]
@ -66,13 +67,18 @@ event_ffi!(
/// The index of the Pokemon that got switched in/out on its side /// The index of the Pokemon that got switched in/out on its side
index: u8, index: u8,
/// The new Pokemon that will be on the spot. If none, the spot will be null. /// The new Pokemon that will be on the spot. If none, the spot will be null.
pokemon: IdentifiablePointer<Pokemon>, pokemon: FFIHandle<Pokemon>,
}, },
{ {
let pokemon_handle = match pokemon {
Some(pokemon) => FFIHandle::get_handle(pokemon.clone().into()),
None => FFIHandle::none(),
};
return SwitchData{ return SwitchData{
side_index: *side_index, side_index: *side_index,
index: *index, index: *index,
pokemon: pokemon.clone().into(), pokemon: pokemon_handle,
} }
} }
); );

View File

@ -1,66 +1,58 @@
use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; use crate::dynamic_data::{LearnedMove, MoveLearnMethod};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::MoveData; use crate::static_data::MoveData;
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiate a new learned move. /// Instantiate a new learned move.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_new( extern "C" fn learned_move_new(
move_data: ExternPointer<Arc<dyn MoveData>>, move_data: FFIHandle<Arc<dyn MoveData>>,
learn_method: MoveLearnMethod, learn_method: MoveLearnMethod,
) -> IdentifiablePointer<Arc<LearnedMove>> { ) -> FFIHandle<Arc<LearnedMove>> {
Arc::new(LearnedMove::new(move_data.as_ref().clone(), learn_method)).into() FFIHandle::get_handle(Arc::new(LearnedMove::new(move_data.from_ffi_handle().clone(), learn_method)).into())
}
/// Drops a learned move.
#[no_mangle]
extern "C" fn learned_move_drop(learned_move: OwnedPtr<Arc<LearnedMove>>) {
unsafe { drop_in_place(learned_move) }
} }
/// The immutable move information of the move. /// The immutable move information of the move.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_move_data( extern "C" fn learned_move_move_data(learned_move: FFIHandle<Arc<LearnedMove>>) -> FFIHandle<Arc<dyn MoveData>> {
learned_move: ExternPointer<Arc<LearnedMove>>, FFIHandle::get_handle(learned_move.from_ffi_handle().move_data().clone().into())
) -> IdentifiablePointer<Arc<dyn MoveData>> {
learned_move.as_ref().move_data().clone().into()
} }
/// The maximal power points for this move. /// The maximal power points for this move.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_max_pp(learned_move: ExternPointer<Arc<LearnedMove>>) -> u8 { extern "C" fn learned_move_max_pp(learned_move: FFIHandle<Arc<LearnedMove>>) -> u8 {
learned_move.as_ref().max_pp() learned_move.from_ffi_handle().max_pp()
} }
/// The amount of remaining power points. If this is 0, we can not use the move anymore. /// The amount of remaining power points. If this is 0, we can not use the move anymore.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_remaining_pp(learned_move: ExternPointer<Arc<LearnedMove>>) -> u8 { extern "C" fn learned_move_remaining_pp(learned_move: FFIHandle<Arc<LearnedMove>>) -> u8 {
learned_move.as_ref().remaining_pp() learned_move.from_ffi_handle().remaining_pp()
} }
/// The way the move was learned. /// The way the move was learned.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_learn_method(learned_move: ExternPointer<Arc<LearnedMove>>) -> MoveLearnMethod { extern "C" fn learned_move_learn_method(learned_move: FFIHandle<Arc<LearnedMove>>) -> MoveLearnMethod {
learned_move.as_ref().learn_method() learned_move.from_ffi_handle().learn_method()
} }
/// Try and reduce the PP by a certain amount. If the amount is higher than the current uses, /// Try and reduce the PP by a certain amount. If the amount is higher than the current uses,
/// return 0. Otherwise, reduce the PP, and return 1. /// return 0. Otherwise, reduce the PP, and return 1.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_try_use(learned_move: ExternPointer<Arc<LearnedMove>>, amount: u8) -> u8 { extern "C" fn learned_move_try_use(learned_move: FFIHandle<Arc<LearnedMove>>, amount: u8) -> u8 {
u8::from(learned_move.as_ref().try_use(amount)) u8::from(learned_move.from_ffi_handle().try_use(amount))
} }
/// Set the remaining PP to the max amount of PP. /// Set the remaining PP to the max amount of PP.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_restore_all_uses(learned_move: ExternPointer<Arc<LearnedMove>>) { extern "C" fn learned_move_restore_all_uses(learned_move: FFIHandle<Arc<LearnedMove>>) {
learned_move.as_ref().restore_all_uses(); learned_move.from_ffi_handle().restore_all_uses();
} }
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP. /// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
#[no_mangle] #[no_mangle]
extern "C" fn learned_move_restore_uses(learned_move: ExternPointer<Arc<LearnedMove>>, amount: u8) -> NativeResult<()> { extern "C" fn learned_move_restore_uses(learned_move: FFIHandle<Arc<LearnedMove>>, amount: u8) -> FFIResult<()> {
learned_move.as_ref().restore_uses(amount); learned_move.from_ffi_handle().restore_uses(amount);
NativeResult::ok(()) FFIResult::ok(())
} }

View File

@ -1,11 +1,10 @@
use crate::dynamic_data::Event; use crate::dynamic_data::Event;
use crate::ffi::BorrowedPtr;
/// Wrapper class for easier use of an external function pointer. /// Wrapper class for easier use of an external function pointer.
#[repr(C)] #[repr(C)]
pub(super) struct NativeEventHook { pub(super) struct NativeEventHook {
/// The actual C function to be called. /// The actual C function to be called.
f: extern "C" fn(BorrowedPtr<Event>), f: extern "C" fn(*const Event<'_>),
} }
impl NativeEventHook { impl NativeEventHook {

View File

@ -1,20 +1,21 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, LearnedMove, MoveLearnMethod, Pokemon}; use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, LearnedMove, MoveLearnMethod, Pokemon};
use crate::ffi::{ffi_arc_getter, ffi_vec_value_getters, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::{ use crate::static_data::{
Ability, AbilityIndex, Form, Gender, Item, Nature, Species, Statistic, StatisticSet, TypeIdentifier, Ability, AbilityIndex, Form, Gender, Item, Nature, Species, Statistic, StatisticSet, TypeIdentifier,
}; };
use crate::VecExt;
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new Pokemon. /// Instantiates a new Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_new( extern "C" fn pokemon_new(
library: ExternPointer<Arc<dyn DynamicLibrary>>, library: FFIHandle<Arc<dyn DynamicLibrary>>,
species: ExternPointer<Arc<dyn Species>>, species: FFIHandle<Arc<dyn Species>>,
form: ExternPointer<Arc<dyn Form>>, form: FFIHandle<Arc<dyn Form>>,
hidden_ability: u8, hidden_ability: u8,
ability_index: u8, ability_index: u8,
level: LevelInt, level: LevelInt,
@ -22,12 +23,12 @@ extern "C" fn pokemon_new(
gender: Gender, gender: Gender,
coloring: u8, coloring: u8,
nature: *const c_char, nature: *const c_char,
) -> NativeResult<IdentifiablePointer<Pokemon>> { ) -> FFIResult<FFIHandle<Pokemon>> {
let nature = unsafe { CStr::from_ptr(nature) }.into(); let nature = unsafe { CStr::from_ptr(nature) }.into();
let pokemon = Pokemon::new( let pokemon = Pokemon::new(
library.as_ref().clone(), library.from_ffi_handle(),
species.as_ref().clone(), species.from_ffi_handle(),
form.as_ref(), &form.from_ffi_handle(),
AbilityIndex { AbilityIndex {
hidden: hidden_ability == 1, hidden: hidden_ability == 1,
index: ability_index, index: ability_index,
@ -39,337 +40,373 @@ extern "C" fn pokemon_new(
&nature, &nature,
); );
match pokemon { match pokemon {
Ok(pokemon) => NativeResult::ok(pokemon.into()), Ok(pokemon) => FFIResult::ok(FFIHandle::get_handle(pokemon.into())),
Err(err) => NativeResult::err(err), Err(err) => FFIResult::err(err),
} }
} }
/// Drops an Arc reference held by the FFI.
#[no_mangle]
unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr<Pokemon>) {
drop_in_place(ptr);
}
/// The library data of the Pokemon. /// The library data of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_library(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn DynamicLibrary>> { extern "C" fn pokemon_library(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn DynamicLibrary>> {
ptr.as_ref().library().clone().into() FFIHandle::get_handle(handle.from_ffi_handle().library().clone().into())
} }
/// The species of the Pokemon. /// The species of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_species(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Species>> { extern "C" fn pokemon_species(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Species>> {
ptr.as_ref().species().into() FFIHandle::get_handle(handle.from_ffi_handle().species().into())
} }
/// The form of the Pokemon. /// The form of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_form(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Form>> { extern "C" fn pokemon_form(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Form>> {
ptr.as_ref().form().into() FFIHandle::get_handle(handle.from_ffi_handle().form().into())
} }
/// The species that should be displayed to the user. This handles stuff like the Illusion ability. /// The species that should be displayed to the user. This handles stuff like the Illusion ability.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_display_species(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Species>> { extern "C" fn pokemon_display_species(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Species>> {
ptr.as_ref().display_species().into() FFIHandle::get_handle(handle.from_ffi_handle().display_species().into())
} }
/// The form that should be displayed to the user. This handles stuff like the Illusion ability. /// The form that should be displayed to the user. This handles stuff like the Illusion ability.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_display_form(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Form>> { extern "C" fn pokemon_display_form(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Form>> {
ptr.as_ref().display_form().into() FFIHandle::get_handle(handle.from_ffi_handle().display_form().into())
} }
ffi_arc_getter!(Pokemon, level, LevelInt); #[no_mangle]
ffi_arc_getter!(Pokemon, experience, u32); extern "C" fn pokemon_level(handle: FFIHandle<Pokemon>) -> LevelInt {
ffi_arc_getter!(Pokemon, unique_identifier, u32); handle.from_ffi_handle().level()
ffi_arc_getter!(Pokemon, gender, Gender); }
ffi_arc_getter!(Pokemon, coloring, u8);
#[no_mangle]
extern "C" fn pokemon_experience(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().experience()
}
#[no_mangle]
extern "C" fn pokemon_unique_identifier(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().unique_identifier()
}
#[no_mangle]
extern "C" fn pokemon_gender(handle: FFIHandle<Pokemon>) -> Gender {
handle.from_ffi_handle().gender()
}
#[no_mangle]
extern "C" fn pokemon_coloring(handle: FFIHandle<Pokemon>) -> u8 {
handle.from_ffi_handle().coloring()
}
/// Gets the held item of a Pokemon /// Gets the held item of a Pokemon
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_held_item(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Item>> { extern "C" fn pokemon_held_item(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Item>> {
if let Some(v) = ptr.as_ref().held_item().read().as_ref() { if let Some(v) = handle.from_ffi_handle().held_item().read().as_ref() {
v.clone().into() FFIHandle::get_handle(v.clone().into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Checks whether the Pokemon is holding a specific item. /// Checks whether the Pokemon is holding a specific item.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_has_held_item(ptr: ExternPointer<Pokemon>, name: *const c_char) -> u8 { extern "C" fn pokemon_has_held_item(handle: FFIHandle<Pokemon>, name: *const c_char) -> u8 {
let name = unsafe { CStr::from_ptr(name) }.into(); let name = unsafe { CStr::from_ptr(name) }.into();
u8::from(ptr.as_ref().has_held_item(&name)) u8::from(handle.from_ffi_handle().has_held_item(&name))
} }
/// Changes the held item of the Pokemon. Returns the previously held item. /// Changes the held item of the Pokemon. Returns the previously held item.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_set_held_item( extern "C" fn pokemon_set_held_item(
ptr: ExternPointer<Pokemon>, handle: FFIHandle<Pokemon>,
item: ExternPointer<Arc<dyn Item>>, item: FFIHandle<Arc<dyn Item>>,
) -> IdentifiablePointer<Arc<dyn Item>> { ) -> FFIHandle<Arc<dyn Item>> {
if let Some(v) = ptr.as_ref().set_held_item(item.as_ref()) { if let Some(v) = handle.from_ffi_handle().set_held_item(&item.from_ffi_handle()) {
v.into() FFIHandle::get_handle(v.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Removes the held item from the Pokemon. Returns the previously held item. /// Removes the held item from the Pokemon. Returns the previously held item.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_remove_held_item(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Item>> { extern "C" fn pokemon_remove_held_item(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Item>> {
if let Some(v) = ptr.as_ref().remove_held_item() { if let Some(v) = handle.from_ffi_handle().remove_held_item() {
v.into() FFIHandle::get_handle(v.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Makes the Pokemon uses its held item. /// Makes the Pokemon uses its held item.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_consume_held_item(ptr: ExternPointer<Pokemon>) -> NativeResult<u8> { extern "C" fn pokemon_consume_held_item(handle: FFIHandle<Pokemon>) -> FFIResult<u8> {
match ptr.as_ref().consume_held_item() { match handle.from_ffi_handle().consume_held_item() {
Ok(v) => NativeResult::ok(u8::from(v)), Ok(v) => FFIResult::ok(u8::from(v)),
Err(err) => NativeResult::err(err), Err(err) => FFIResult::err(err),
} }
} }
ffi_arc_getter!(Pokemon, current_health, u32); #[no_mangle]
ffi_arc_getter!(Pokemon, max_health, u32); extern "C" fn pokemon_current_health(handle: FFIHandle<Pokemon>) -> u32 {
ffi_arc_getter!(Pokemon, weight, f32); handle.from_ffi_handle().current_health()
ffi_arc_getter!(Pokemon, height, f32); }
#[no_mangle]
extern "C" fn pokemon_max_health(handle: FFIHandle<Pokemon>) -> u32 {
handle.from_ffi_handle().max_health()
}
#[no_mangle]
extern "C" fn pokemon_weight(handle: FFIHandle<Pokemon>) -> f32 {
handle.from_ffi_handle().weight()
}
#[no_mangle]
extern "C" fn pokemon_height(handle: FFIHandle<Pokemon>) -> f32 {
handle.from_ffi_handle().height()
}
/// An optional nickname of the Pokemon. /// An optional nickname of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_nickname(ptr: ExternPointer<Pokemon>) -> NativeResult<*mut c_char> { extern "C" fn pokemon_nickname(handle: FFIHandle<Pokemon>) -> FFIResult<*mut c_char> {
let name = ptr.as_ref().nickname(); let form = handle.from_ffi_handle();
let name = form.nickname();
if let Some(v) = name { if let Some(v) = name {
match CString::new(v.as_str()) { match CString::new(v.as_str()) {
Ok(v) => NativeResult::ok(v.into_raw()), Ok(v) => FFIResult::ok(v.into_raw()),
Err(err) => NativeResult::err(anyhow!("Could not convert nickname to CString: {}", err)), Err(err) => FFIResult::err(anyhow!("Could not convert nickname to CString: {}", err)),
} }
} else { } else {
NativeResult::ok(std::ptr::null_mut()) FFIResult::ok(std::ptr::null_mut())
} }
} }
/// Whether the actual ability on the form is a hidden ability. /// Whether the actual ability on the form is a hidden ability.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_real_ability_is_hidden(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().real_ability().hidden) u8::from(handle.from_ffi_handle().real_ability().hidden)
} }
/// The index of the actual ability on the form. /// The index of the actual ability on the form.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_real_ability_index(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_real_ability_index(handle: FFIHandle<Pokemon>) -> u8 {
ptr.as_ref().real_ability().index handle.from_ffi_handle().real_ability().index
} }
ffi_vec_value_getters!(Pokemon, Pokemon, types, TypeIdentifier); #[no_mangle]
extern "C" fn pokemon_types_length(ptr: FFIHandle<Pokemon>) -> usize {
ptr.from_ffi_handle().types().len()
}
#[no_mangle]
extern "C" fn pokemon_types_get(ptr: FFIHandle<Pokemon>, index: usize) -> FFIResult<TypeIdentifier> {
match ptr.from_ffi_handle().types().get_res(index) {
Ok(v) => FFIResult::ok(*v),
Err(err) => FFIResult::err(err),
}
}
/// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get /// Gets a learned move of the Pokemon. Index should generally be below [`MAX_MOVES`], you will get
/// a null pointer otherwise. /// a null pointer otherwise.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_learned_move_get( extern "C" fn pokemon_learned_move_get(handle: FFIHandle<Pokemon>, index: usize) -> FFIHandle<Arc<LearnedMove>> {
ptr: ExternPointer<Pokemon>, if let Some(Some(v)) = handle.from_ffi_handle().learned_moves().read().get(index) {
index: usize, FFIHandle::get_handle(v.clone().into())
) -> IdentifiablePointer<Arc<LearnedMove>> {
if let Some(Some(v)) = ptr.as_ref().learned_moves().read().get(index) {
v.clone().into()
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// The stats of the Pokemon when disregarding any stat boosts. /// The stats of the Pokemon when disregarding any stat boosts.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_flat_stats(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<StatisticSet<u32>>> { extern "C" fn pokemon_flat_stats(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<StatisticSet<u32>>> {
ptr.as_ref().flat_stats().clone().into() FFIHandle::get_handle(handle.from_ffi_handle().flat_stats().clone().into())
} }
/// The stats of the Pokemon including the stat boosts. /// The stats of the Pokemon including the stat boosts.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_boosted_stats(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<StatisticSet<u32>>> { extern "C" fn pokemon_boosted_stats(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<StatisticSet<u32>>> {
ptr.as_ref().boosted_stats().clone().into() FFIHandle::get_handle(handle.from_ffi_handle().boosted_stats().clone().into())
} }
/// Get the stat boosts for a specific stat. /// Get the stat boosts for a specific stat.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer<Pokemon>, statistic: Statistic) -> i8 { extern "C" fn pokemon_get_stat_boost(handle: FFIHandle<Pokemon>, statistic: Statistic) -> i8 {
ptr.as_ref().stat_boost(statistic) handle.from_ffi_handle().stat_boost(statistic)
} }
/// Change a boosted stat by a certain amount. /// Change a boosted stat by a certain amount.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_change_stat_boost( extern "C" fn pokemon_change_stat_boost(
ptr: ExternPointer<Pokemon>, handle: FFIHandle<Pokemon>,
stat: Statistic, stat: Statistic,
diff_amount: i8, diff_amount: i8,
self_inflicted: u8, self_inflicted: u8,
) -> NativeResult<u8> { ) -> FFIResult<u8> {
match ptr.as_ref().change_stat_boost(stat, diff_amount, self_inflicted == 1) { match handle
Ok(v) => NativeResult::ok(u8::from(v)), .from_ffi_handle()
Err(e) => NativeResult::err(e), .change_stat_boost(stat, diff_amount, self_inflicted == 1)
{
Ok(v) => FFIResult::ok(u8::from(v)),
Err(e) => FFIResult::err(e),
} }
} }
/// Gets a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. /// Gets a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_get_individual_value(ptr: ExternPointer<Pokemon>, stat: Statistic) -> u8 { extern "C" fn pokemon_get_individual_value(handle: FFIHandle<Pokemon>, stat: Statistic) -> u8 {
ptr.as_ref().individual_values().get_stat(stat) handle.from_ffi_handle().individual_values().get_stat(stat)
} }
/// Modifies a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. /// Modifies a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_set_individual_value( extern "C" fn pokemon_set_individual_value(handle: FFIHandle<Pokemon>, stat: Statistic, value: u8) -> FFIResult<()> {
ptr: ExternPointer<Pokemon>, handle.from_ffi_handle().individual_values().set_stat(stat, value);
stat: Statistic, handle.from_ffi_handle().recalculate_flat_stats().into()
value: u8,
) -> NativeResult<()> {
ptr.as_ref().individual_values().set_stat(stat, value);
ptr.as_ref().recalculate_flat_stats().into()
} }
/// Gets a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. /// Gets a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_get_effort_value(ptr: ExternPointer<Pokemon>, stat: Statistic) -> u8 { extern "C" fn pokemon_get_effort_value(handle: FFIHandle<Pokemon>, stat: Statistic) -> u8 {
ptr.as_ref().effort_values().get_stat(stat) handle.from_ffi_handle().effort_values().get_stat(stat)
} }
/// Modifies a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. /// Modifies a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_set_effort_value(ptr: ExternPointer<Pokemon>, stat: Statistic, value: u8) -> NativeResult<()> { extern "C" fn pokemon_set_effort_value(handle: FFIHandle<Pokemon>, stat: Statistic, value: u8) -> FFIResult<()> {
ptr.as_ref().effort_values().set_stat(stat, value); handle.from_ffi_handle().effort_values().set_stat(stat, value);
ptr.as_ref().recalculate_flat_stats().into() handle.from_ffi_handle().recalculate_flat_stats().into()
} }
/// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this /// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this
/// returns null. /// returns null.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_get_battle(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Battle> { extern "C" fn pokemon_get_battle(handle: FFIHandle<Pokemon>) -> FFIHandle<Battle> {
if let Some(v) = ptr.as_ref().get_battle() { if let Some(v) = handle.from_ffi_handle().get_battle() {
v.into() FFIHandle::get_handle(v.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Get the index of the side of the battle the Pokemon is in. If the Pokemon /// Get the index of the side of the battle the Pokemon is in. If the Pokemon
/// is not on the battlefield, this always returns 0. /// is not on the battlefield, this always returns 0.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_get_battle_side_index(handle: FFIHandle<Pokemon>) -> u8 {
ptr.as_ref().get_battle_side_index().unwrap_or_default() handle.from_ffi_handle().get_battle_side_index().unwrap_or_default()
} }
/// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon /// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon
/// is not on the battlefield, this always returns 0. /// is not on the battlefield, this always returns 0.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_get_battle_index(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_get_battle_index(handle: FFIHandle<Pokemon>) -> u8 {
ptr.as_ref().get_battle_index().unwrap_or_default() handle.from_ffi_handle().get_battle_index().unwrap_or_default()
} }
/// Returns whether something overrides the ability. /// Returns whether something overrides the ability.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_is_ability_overriden(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_ability_overriden()) u8::from(handle.from_ffi_handle().is_ability_overriden())
} }
/// Returns the currently active ability. /// Returns the currently active ability.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_active_ability( extern "C" fn pokemon_active_ability(handle: FFIHandle<Pokemon>) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
ptr: ExternPointer<Pokemon>, match handle.from_ffi_handle().active_ability() {
) -> NativeResult<IdentifiablePointer<Arc<dyn Ability>>> { Ok(v) => FFIResult::ok(FFIHandle::get_handle(v.clone().into())),
match ptr.as_ref().active_ability() { Err(e) => FFIResult::err(e),
Ok(v) => NativeResult::ok(v.clone().into()),
Err(e) => NativeResult::err(e),
} }
} }
/// Whether or not the Pokemon is allowed to gain experience. /// Whether or not the Pokemon is allowed to gain experience.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_allowed_experience_gain(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().allowed_experience_gain()) u8::from(handle.from_ffi_handle().allowed_experience_gain())
} }
/// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon. /// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_nature(ptr: ExternPointer<Pokemon>) -> IdentifiablePointer<Arc<dyn Nature>> { extern "C" fn pokemon_nature(handle: FFIHandle<Pokemon>) -> FFIHandle<Arc<dyn Nature>> {
ptr.as_ref().nature().clone().into() FFIHandle::get_handle(handle.from_ffi_handle().nature().clone().into())
} }
/// Calculates the flat stats on the Pokemon. This should be called when for example the base /// Calculates the flat stats on the Pokemon. This should be called when for example the base
/// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted /// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted
/// stats, as those depend on the flat stats. /// stats, as those depend on the flat stats.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer<Pokemon>) -> NativeResult<()> { extern "C" fn pokemon_recalculate_flat_stats(handle: FFIHandle<Pokemon>) -> FFIResult<()> {
ptr.as_ref().recalculate_flat_stats().into() handle.from_ffi_handle().recalculate_flat_stats().into()
} }
/// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes. /// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer<Pokemon>) -> NativeResult<()> { extern "C" fn pokemon_recalculate_boosted_stats(handle: FFIHandle<Pokemon>) -> FFIResult<()> {
ptr.as_ref().recalculate_boosted_stats().into() handle.from_ffi_handle().recalculate_boosted_stats().into()
} }
/// Change the species of the Pokemon. /// Change the species of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_change_species( extern "C" fn pokemon_change_species(
ptr: ExternPointer<Pokemon>, handle: FFIHandle<Pokemon>,
species: ExternPointer<Arc<dyn Species>>, species: FFIHandle<Arc<dyn Species>>,
form: ExternPointer<Arc<dyn Form>>, form: FFIHandle<Arc<dyn Form>>,
) -> NativeResult<()> { ) -> FFIResult<()> {
ptr.as_ref() handle
.change_species(species.as_ref().clone(), form.as_ref().clone()) .from_ffi_handle()
.change_species(species.from_ffi_handle().clone(), form.from_ffi_handle().clone())
.into() .into()
} }
/// Change the form of the Pokemon. /// Change the form of the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_change_form(ptr: ExternPointer<Pokemon>, form: ExternPointer<Arc<dyn Form>>) -> NativeResult<()> { extern "C" fn pokemon_change_form(handle: FFIHandle<Pokemon>, form: FFIHandle<Arc<dyn Form>>) -> FFIResult<()> {
ptr.as_ref().change_form(form.as_ref()).into() handle.from_ffi_handle().change_form(&form.from_ffi_handle()).into()
} }
/// Whether or not the Pokemon is useable in a battle. /// Whether or not the Pokemon is useable in a battle.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_is_usable(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_is_usable(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_usable()) u8::from(handle.from_ffi_handle().is_usable())
} }
/// Returns whether the Pokemon is fainted. /// Returns whether the Pokemon is fainted.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_is_fainted(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_is_fainted(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_fainted()) u8::from(handle.from_ffi_handle().is_fainted())
} }
/// Whether or not the Pokemon is on the battlefield. /// Whether or not the Pokemon is on the battlefield.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_is_on_battlefield(handle: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().is_on_battlefield()) u8::from(handle.from_ffi_handle().is_on_battlefield())
} }
/// Damages the Pokemon by a certain amount of damage, from a damage source. /// Damages the Pokemon by a certain amount of damage, from a damage source.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_damage(ptr: ExternPointer<Pokemon>, damage: u32, source: DamageSource) -> NativeResult<()> { extern "C" fn pokemon_damage(handle: FFIHandle<Pokemon>, damage: u32, source: DamageSource) -> FFIResult<()> {
ptr.as_ref().damage(damage, source).into() handle.from_ffi_handle().damage(damage, source).into()
} }
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not /// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not
/// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false. /// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_heal(ptr: ExternPointer<Pokemon>, amount: u32, allow_revive: u8) -> bool { extern "C" fn pokemon_heal(handle: FFIHandle<Pokemon>, amount: u32, allow_revive: u8) -> bool {
ptr.as_ref().heal(amount, allow_revive == 1) handle.from_ffi_handle().heal(amount, allow_revive == 1)
} }
/// Learn a move. /// Learn a move.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_learn_move( extern "C" fn pokemon_learn_move(
ptr: ExternPointer<Pokemon>, handle: FFIHandle<Pokemon>,
move_name: *const c_char, move_name: *const c_char,
learn_method: MoveLearnMethod, learn_method: MoveLearnMethod,
) -> NativeResult<()> { ) -> FFIResult<()> {
unsafe { unsafe {
ptr.as_ref() handle
.from_ffi_handle()
.learn_move(&CStr::from_ptr(move_name).into(), learn_method) .learn_move(&CStr::from_ptr(move_name).into(), learn_method)
.into() .into()
} }
@ -377,6 +414,6 @@ extern "C" fn pokemon_learn_move(
/// Removes the current non-volatile status from the Pokemon. /// Removes the current non-volatile status from the Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_clear_status(ptr: ExternPointer<Pokemon>) { extern "C" fn pokemon_clear_status(handle: FFIHandle<Pokemon>) {
ptr.as_ref().clear_status() handle.from_ffi_handle().clear_status()
} }

View File

@ -1,68 +1,69 @@
use crate::dynamic_data::{Pokemon, PokemonParty}; use crate::dynamic_data::{Pokemon, PokemonParty};
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a party with a set size. /// Instantiates a party with a set size.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_new(capacity: usize) -> IdentifiablePointer<Arc<PokemonParty>> { extern "C" fn pokemon_party_new(capacity: usize) -> FFIHandle<Arc<PokemonParty>> {
Arc::new(PokemonParty::new(capacity)).into() FFIHandle::get_handle(Arc::new(PokemonParty::new(capacity)).into())
} }
/// Gets a Pokemon at an index in the party. /// Gets a Pokemon at an index in the party.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_at(ptr: ExternPointer<Arc<PokemonParty>>, index: usize) -> IdentifiablePointer<Pokemon> { extern "C" fn pokemon_party_at(ptr: FFIHandle<Arc<PokemonParty>>, index: usize) -> FFIHandle<Pokemon> {
if let Some(v) = ptr.as_ref().at(index) { if let Some(v) = ptr.from_ffi_handle().at(index) {
v.into() FFIHandle::get_handle(v.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Gets a Pokemon at an index in the party. /// Gets a Pokemon at an index in the party.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_switch(ptr: ExternPointer<Arc<PokemonParty>>, a: usize, b: usize) { extern "C" fn pokemon_party_switch(ptr: FFIHandle<Arc<PokemonParty>>, a: usize, b: usize) {
ptr.as_ref().switch(a, b); ptr.from_ffi_handle().switch(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.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_swap_into( extern "C" fn pokemon_party_swap_into(
ptr: ExternPointer<Arc<PokemonParty>>, ptr: FFIHandle<Arc<PokemonParty>>,
index: usize, index: usize,
pokemon: ExternPointer<Pokemon>, pokemon: FFIHandle<Pokemon>,
) -> NativeResult<IdentifiablePointer<Pokemon>> { ) -> FFIResult<FFIHandle<Pokemon>> {
let pokemon = if pokemon.ptr.is_null() { let pokemon = if pokemon.is_none() {
None None
} else { } else {
Some(pokemon.as_ref().clone()) Some(pokemon.from_ffi_handle())
}; };
match ptr.as_ref().swap_into(index, pokemon) { match ptr.from_ffi_handle().swap_into(index, pokemon) {
Ok(Some(v)) => NativeResult::ok(v.into()), Ok(Some(v)) => FFIResult::ok(FFIHandle::get_handle(v.into())),
Ok(None) => NativeResult::ok(IdentifiablePointer::none()), Ok(None) => FFIResult::ok(FFIHandle::none()),
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }
/// 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.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_has_usable_pokemon(ptr: ExternPointer<Arc<PokemonParty>>) -> u8 { extern "C" fn pokemon_party_has_usable_pokemon(ptr: FFIHandle<Arc<PokemonParty>>) -> u8 {
u8::from(ptr.as_ref().has_usable_pokemon()) u8::from(ptr.from_ffi_handle().has_usable_pokemon())
} }
/// Get the length of the underlying list of Pokemon. /// Get the length of the underlying list of Pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_length(ptr: ExternPointer<Arc<PokemonParty>>) -> usize { extern "C" fn pokemon_party_length(ptr: FFIHandle<Arc<PokemonParty>>) -> usize {
ptr.as_ref().length() ptr.from_ffi_handle().length()
} }
/// 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.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_pack_party(ptr: ExternPointer<Arc<PokemonParty>>) -> NativeResult<()> { extern "C" fn pokemon_party_pack_party(ptr: FFIHandle<Arc<PokemonParty>>) -> FFIResult<()> {
ptr.as_ref().pack_party().into() ptr.from_ffi_handle().pack_party().into()
} }
/// Checks if the party contains a given pokemon. /// Checks if the party contains a given pokemon.
#[no_mangle] #[no_mangle]
extern "C" fn pokemon_party_has_pokemon(ptr: ExternPointer<Arc<PokemonParty>>, pokemon: ExternPointer<Pokemon>) -> u8 { extern "C" fn pokemon_party_has_pokemon(ptr: FFIHandle<Arc<PokemonParty>>, pokemon: FFIHandle<Pokemon>) -> u8 {
u8::from(ptr.as_ref().has_pokemon(pokemon.as_ref())) u8::from(ptr.from_ffi_handle().has_pokemon(&pokemon.from_ffi_handle()))
} }

296
src/ffi/ffi_handle.rs Normal file
View File

@ -0,0 +1,296 @@
use crate::static_data::{
Ability, EffectParameter, Form, GrowthRate, Item, LearnableMoves, MoveData, Nature, SecondaryEffect, Species,
StaticStatisticSet, StatisticSet,
};
use anyhow::anyhow;
use hashbrown::HashMap;
use parking_lot::RwLock;
use std::hash::Hash;
use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, LazyLock};
#[repr(C)]
pub(super) struct FFIHandle<T> {
handle: usize,
_marker: std::marker::PhantomData<T>,
}
impl<T> Clone for FFIHandle<T> {
fn clone(&self) -> Self {
Self {
handle: self.handle,
_marker: std::marker::PhantomData,
}
}
}
impl<T> Copy for FFIHandle<T> {}
#[derive(Clone)]
pub(super) enum FFIObject {
Ability(Arc<dyn Ability>),
EffectParameter(Arc<EffectParameter>),
StatisticSetU8(Arc<StatisticSet<u8>>),
StatisticSetI8(Arc<StatisticSet<i8>>),
StatisticSetU32(Arc<StatisticSet<u32>>),
StaticStatisticSetU16(Arc<StaticStatisticSet<u16>>),
Form(Arc<dyn Form>),
LearnableMoves(Arc<dyn LearnableMoves>),
GrowthRate(Arc<dyn GrowthRate>),
Item(Arc<dyn Item>),
SecondaryEffect(Arc<dyn SecondaryEffect>),
MoveData(Arc<dyn MoveData>),
Nature(Arc<dyn Nature>),
Species(Arc<dyn Species>),
SpeciesLibrary(Arc<dyn crate::static_data::SpeciesLibrary>),
MoveLibrary(Arc<dyn crate::static_data::MoveLibrary>),
AbilityLibrary(Arc<dyn crate::static_data::AbilityLibrary>),
ItemLibrary(Arc<dyn crate::static_data::ItemLibrary>),
GrowthRateLibrary(Arc<dyn crate::static_data::GrowthRateLibrary>),
LibrarySettings(Arc<dyn crate::static_data::LibrarySettings>),
NatureLibrary(Arc<dyn crate::static_data::NatureLibrary>),
TypeLibrary(Arc<dyn crate::static_data::TypeLibrary>),
StaticData(Arc<dyn crate::static_data::StaticData>),
// DynamicData
TurnChoice(Arc<crate::dynamic_data::TurnChoice>),
Pokemon(crate::dynamic_data::Pokemon),
LearnedMove(Arc<crate::dynamic_data::LearnedMove>),
PokemonParty(Arc<crate::dynamic_data::PokemonParty>),
BattleParty(Arc<crate::dynamic_data::BattleParty>),
Battle(crate::dynamic_data::Battle),
BattleSide(crate::dynamic_data::BattleSide),
BattleRandom(Arc<crate::dynamic_data::BattleRandom>),
// DynamicLibrary
BattleStatCalculator(Arc<dyn crate::dynamic_data::BattleStatCalculator>),
DamageLibrary(Arc<dyn crate::dynamic_data::DamageLibrary>),
MiscLibrary(Arc<dyn crate::dynamic_data::MiscLibrary>),
ScriptResolver(Arc<dyn crate::dynamic_data::ScriptResolver>),
DynamicLibrary(Arc<dyn crate::dynamic_data::DynamicLibrary>),
}
unsafe impl Send for FFIObject {}
unsafe impl Sync for FFIObject {}
static NEXT_HANDLE: AtomicUsize = AtomicUsize::new(0);
static FFI_OBJECTS: LazyLock<RwLock<HashMap<usize, FFIObject>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
static FFI_OBJECTS_INVERSE: LazyLock<RwLock<HashMap<FFIObject, usize>>> = LazyLock::new(|| RwLock::new(HashMap::new()));
impl<T> FFIHandle<T> {
pub fn get_handle(o: FFIObject) -> Self {
if let Some(handle) = FFI_OBJECTS_INVERSE.read().get(&o) {
return Self {
handle: *handle,
_marker: std::marker::PhantomData,
};
}
let handle = NEXT_HANDLE.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
FFI_OBJECTS.write().insert(handle, o.clone());
FFI_OBJECTS_INVERSE.write().insert(o, handle);
Self {
handle,
_marker: std::marker::PhantomData,
}
}
pub fn none() -> Self {
Self {
handle: 0,
_marker: std::marker::PhantomData,
}
}
#[allow(clippy::unwrap_used)] // Unwrap used, as it is a potential security bug if this fails
pub fn resolve(&self) -> FFIObject {
FFI_OBJECTS
.read()
.get(&self.handle)
.ok_or(anyhow!("Unable to get handle"))
.unwrap()
.clone()
}
pub fn is_none(&self) -> bool {
self.handle == 0
}
}
#[allow(clippy::from_over_into)]
impl<T> Into<anyhow_ext::Result<FFIObject>> for FFIHandle<T> {
fn into(self) -> anyhow_ext::Result<FFIObject> {
Ok(FFI_OBJECTS
.read()
.get(&self.handle)
.ok_or(anyhow!("Unable to get handle"))?
.clone())
}
}
impl Eq for FFIObject {}
#[allow(clippy::wrong_self_convention)]
pub(super) trait FromFFIHandle<T> {
fn from_ffi_handle(&self) -> T;
fn from_ffi_handle_opt(&self) -> Option<T>;
}
impl Hash for FFIObject {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Ability(a) => Arc::as_ptr(a).hash(state),
Self::EffectParameter(a) => Arc::as_ptr(a).hash(state),
Self::StatisticSetU8(a) => Arc::as_ptr(a).hash(state),
Self::StatisticSetI8(a) => Arc::as_ptr(a).hash(state),
Self::StatisticSetU32(a) => Arc::as_ptr(a).hash(state),
Self::StaticStatisticSetU16(a) => Arc::as_ptr(a).hash(state),
Self::Form(a) => Arc::as_ptr(a).hash(state),
Self::LearnableMoves(a) => Arc::as_ptr(a).hash(state),
Self::GrowthRate(a) => Arc::as_ptr(a).hash(state),
Self::Item(a) => Arc::as_ptr(a).hash(state),
Self::SecondaryEffect(a) => Arc::as_ptr(a).hash(state),
Self::MoveData(a) => Arc::as_ptr(a).hash(state),
Self::Nature(a) => Arc::as_ptr(a).hash(state),
Self::Species(a) => Arc::as_ptr(a).hash(state),
Self::SpeciesLibrary(a) => Arc::as_ptr(a).hash(state),
Self::MoveLibrary(a) => Arc::as_ptr(a).hash(state),
Self::AbilityLibrary(a) => Arc::as_ptr(a).hash(state),
Self::ItemLibrary(a) => Arc::as_ptr(a).hash(state),
Self::GrowthRateLibrary(a) => Arc::as_ptr(a).hash(state),
Self::LibrarySettings(a) => Arc::as_ptr(a).hash(state),
Self::NatureLibrary(a) => Arc::as_ptr(a).hash(state),
Self::TypeLibrary(a) => Arc::as_ptr(a).hash(state),
Self::StaticData(a) => Arc::as_ptr(a).hash(state),
Self::TurnChoice(a) => Arc::as_ptr(a).hash(state),
Self::Pokemon(a) => a.as_ptr().hash(state),
Self::LearnedMove(a) => Arc::as_ptr(a).hash(state),
Self::PokemonParty(a) => Arc::as_ptr(a).hash(state),
Self::BattleParty(a) => Arc::as_ptr(a).hash(state),
Self::Battle(a) => a.as_ptr().hash(state),
Self::BattleSide(a) => a.as_ptr().hash(state),
Self::BattleRandom(a) => Arc::as_ptr(a).hash(state),
Self::BattleStatCalculator(a) => Arc::as_ptr(a).hash(state),
Self::DamageLibrary(a) => Arc::as_ptr(a).hash(state),
Self::MiscLibrary(a) => Arc::as_ptr(a).hash(state),
Self::ScriptResolver(a) => Arc::as_ptr(a).hash(state),
Self::DynamicLibrary(a) => Arc::as_ptr(a).hash(state),
}
}
}
impl PartialEq for FFIObject {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Ability(a), Self::Ability(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::EffectParameter(a), Self::EffectParameter(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StatisticSetU8(a), Self::StatisticSetU8(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StatisticSetI8(a), Self::StatisticSetI8(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StatisticSetU32(a), Self::StatisticSetU32(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StaticStatisticSetU16(a), Self::StaticStatisticSetU16(b)) => {
Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr()
}
(Self::Form(a), Self::Form(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::LearnableMoves(a), Self::LearnableMoves(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::GrowthRate(a), Self::GrowthRate(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Item(a), Self::Item(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::SecondaryEffect(a), Self::SecondaryEffect(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::MoveData(a), Self::MoveData(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Nature(a), Self::Nature(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Species(a), Self::Species(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::SpeciesLibrary(a), Self::SpeciesLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::MoveLibrary(a), Self::MoveLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::AbilityLibrary(a), Self::AbilityLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::ItemLibrary(a), Self::ItemLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::GrowthRateLibrary(a), Self::GrowthRateLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::LibrarySettings(a), Self::LibrarySettings(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::NatureLibrary(a), Self::NatureLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::TypeLibrary(a), Self::TypeLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::StaticData(a), Self::StaticData(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::TurnChoice(a), Self::TurnChoice(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Pokemon(a), Self::Pokemon(b)) => a.eq(b),
(Self::LearnedMove(a), Self::LearnedMove(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::PokemonParty(a), Self::PokemonParty(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::BattleParty(a), Self::BattleParty(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::Battle(a), Self::Battle(b)) => a.eq(b),
(Self::BattleSide(a), Self::BattleSide(b)) => a.eq(b),
(Self::BattleRandom(a), Self::BattleRandom(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::BattleStatCalculator(a), Self::BattleStatCalculator(b)) => {
Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr()
}
(Self::DamageLibrary(a), Self::DamageLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::MiscLibrary(a), Self::MiscLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::ScriptResolver(a), Self::ScriptResolver(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
(Self::DynamicLibrary(a), Self::DynamicLibrary(b)) => Arc::as_ptr(a).addr() == Arc::as_ptr(b).addr(),
_ => false,
}
}
}
macro_rules! ffi_obj_conversions {
($res_type:ty, $ffi_obj_name:ident) => {
impl From<$res_type> for FFIObject {
fn from(a: $res_type) -> Self {
Self::$ffi_obj_name(a)
}
}
impl FromFFIHandle<$res_type> for FFIHandle<$res_type> {
fn from_ffi_handle(&self) -> $res_type {
match self.resolve() {
FFIObject::$ffi_obj_name(a) => a.clone(),
_ => panic!("Invalid handle"),
}
}
fn from_ffi_handle_opt(&self) -> Option<$res_type> {
if (self.is_none()) {
return None;
}
match self.resolve() {
FFIObject::$ffi_obj_name(a) => Some(a.clone()),
_ => panic!("Invalid handle"),
}
}
}
};
}
ffi_obj_conversions!(Arc<dyn Ability>, Ability);
ffi_obj_conversions!(Arc<EffectParameter>, EffectParameter);
ffi_obj_conversions!(Arc<StatisticSet<i8>>, StatisticSetI8);
ffi_obj_conversions!(Arc<StatisticSet<u8>>, StatisticSetU8);
ffi_obj_conversions!(Arc<StatisticSet<u32>>, StatisticSetU32);
ffi_obj_conversions!(Arc<StaticStatisticSet<u16>>, StaticStatisticSetU16);
ffi_obj_conversions!(Arc<dyn Form>, Form);
ffi_obj_conversions!(Arc<dyn LearnableMoves>, LearnableMoves);
ffi_obj_conversions!(Arc<dyn GrowthRate>, GrowthRate);
ffi_obj_conversions!(Arc<dyn Item>, Item);
ffi_obj_conversions!(Arc<dyn SecondaryEffect>, SecondaryEffect);
ffi_obj_conversions!(Arc<dyn MoveData>, MoveData);
ffi_obj_conversions!(Arc<dyn Nature>, Nature);
ffi_obj_conversions!(Arc<dyn Species>, Species);
ffi_obj_conversions!(Arc<dyn crate::static_data::SpeciesLibrary>, SpeciesLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::MoveLibrary>, MoveLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::AbilityLibrary>, AbilityLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::ItemLibrary>, ItemLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::GrowthRateLibrary>, GrowthRateLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::LibrarySettings>, LibrarySettings);
ffi_obj_conversions!(Arc<dyn crate::static_data::NatureLibrary>, NatureLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::TypeLibrary>, TypeLibrary);
ffi_obj_conversions!(Arc<dyn crate::static_data::StaticData>, StaticData);
ffi_obj_conversions!(Arc<crate::dynamic_data::TurnChoice>, TurnChoice);
ffi_obj_conversions!(crate::dynamic_data::Pokemon, Pokemon);
ffi_obj_conversions!(Arc<crate::dynamic_data::LearnedMove>, LearnedMove);
ffi_obj_conversions!(Arc<crate::dynamic_data::PokemonParty>, PokemonParty);
ffi_obj_conversions!(Arc<crate::dynamic_data::BattleParty>, BattleParty);
ffi_obj_conversions!(crate::dynamic_data::Battle, Battle);
ffi_obj_conversions!(crate::dynamic_data::BattleSide, BattleSide);
ffi_obj_conversions!(Arc<crate::dynamic_data::BattleRandom>, BattleRandom);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::BattleStatCalculator>, BattleStatCalculator);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DamageLibrary>, DamageLibrary);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::MiscLibrary>, MiscLibrary);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::ScriptResolver>, ScriptResolver);
ffi_obj_conversions!(Arc<dyn crate::dynamic_data::DynamicLibrary>, DynamicLibrary);

View File

@ -1,68 +1,57 @@
/// The foreign function interfaces for the dynamic data /// The foreign function interfaces for the dynamic data
mod dynamic_data; mod dynamic_data;
mod ffi_handle;
/// The foreign function interfaces for that static data /// The foreign function interfaces for that static data
mod static_data; mod static_data;
pub(self) use ffi_handle::*;
/// Helper type for clearer functions. /// Helper type for clearer functions.
type OwnedPtr<T> = *mut T; type OwnedPtrString = *mut c_char;
/// Helper type for clearer functions. /// Helper type for clearer functions.
type BorrowedPtr<T> = *const T; type NonOwnedPtrString = *const c_char;
/// Generates a basic getter foreign function interface. /// Generates a basic getter foreign function interface.
macro_rules! ffi_arc_getter { macro_rules! ffi_handle_arc_dyn_getter {
( (
$type:ty, $func:ident, $returns: ty $type:ty, $func:ident, $returns: ty
) => { ) => {
paste::paste! { paste::paste! {
#[no_mangle] #[no_mangle]
extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer<Arc<$type>>) -> $returns { extern "C" fn [< $type:snake _ $func >](ptr: FFIHandle<Arc<dyn $type>>) -> $returns {
ptr.as_ref().$func() ptr.from_ffi_handle().$func()
}
}
};
}
/// Generates a basic getter foreign function interface.
macro_rules! ffi_arc_dyn_getter {
(
$type:ty, $func:ident, $returns: ty
) => {
paste::paste! {
#[no_mangle]
extern "C" fn [< $type:snake _ $func >](ptr: ExternPointer<Arc<dyn $type>>) -> $returns {
ptr.as_ref().$func()
} }
} }
}; };
} }
/// Generates a basic getter foreign function interface where the return type is a [`crate::StringKey`]. /// Generates a basic getter foreign function interface where the return type is a [`crate::StringKey`].
macro_rules! ffi_arc_stringkey_getter { macro_rules! ffi_handle_arc_stringkey_getter {
( (
$type:ty, $func:ident $type:ty, $func:ident
) => { ) => {
paste::paste! { paste::paste! {
#[no_mangle] #[no_mangle]
extern "C" fn [< $type:lower _ $func >](ptr: ExternPointer<Arc<dyn $type>>) -> OwnedPtr<c_char> { extern "C" fn [< $type:lower _ $func >](ptr: FFIHandle<Arc<dyn $type>>) -> NonOwnedPtrString {
std::ffi::CString::new(ptr.as_ref().$func().str()).unwrap().into_raw() std::ffi::CString::new(ptr.from_ffi_handle().$func().str()).unwrap().into_raw()
} }
} }
}; };
} }
/// Generates a foreign function interface for a vec. This generates a length function, and a getter. /// Generates a foreign function interface for a vec. This generates a length function, and a getter.
macro_rules! ffi_vec_value_getters { macro_rules! ffi_handle_vec_value_getters {
( (
$name:ident, $type:ty, $func:ident, $returns: ty $name:ident, $type:ty, $func:ident, $returns: ty
) => { ) => {
paste::paste! { paste::paste! {
#[no_mangle] #[no_mangle]
extern "C" fn [< $name:lower _ $func _length>](ptr: ExternPointer<Arc<$type>>) -> usize { extern "C" fn [< $name:lower _ $func _length>](ptr: FFIHandle<Arc<$type>>) -> usize {
ptr.as_ref().$func().len() ptr.from_ffi_handle().$func().len()
} }
#[no_mangle] #[no_mangle]
extern "C" fn [< $name:lower _ $func _get>](ptr: ExternPointer<Arc<$type>>, index: usize) -> $returns { extern "C" fn [< $name:lower _ $func _get>](ptr: FFIHandle<Arc<$type>>, index: usize) -> $returns {
*ptr.as_ref().$func().get(index).unwrap() *ptr.from_ffi_handle().$func().get(index).unwrap()
} }
} }
}; };
@ -70,33 +59,28 @@ macro_rules! ffi_vec_value_getters {
/// Generates a foreign function interface for a vec of [`crate::StringKey`]. This generates a /// Generates a foreign function interface for a vec of [`crate::StringKey`]. This generates a
/// length function, and a getter. /// length function, and a getter.
macro_rules! ffi_vec_stringkey_getters { macro_rules! ffi_handle_vec_stringkey_getters {
( (
$type:ty, $func:ident $type:ty, $func:ident
) => { ) => {
paste::paste! { paste::paste! {
#[no_mangle] #[no_mangle]
extern "C" fn [< $type:lower _ $func _length>](ptr: ExternPointer<Arc<dyn $type>>) -> usize { extern "C" fn [< $type:lower _ $func _length>](ptr: FFIHandle<Arc<dyn $type>>) -> usize {
ptr.as_ref().$func().len() ptr.from_ffi_handle().$func().len()
} }
#[no_mangle] #[no_mangle]
extern "C" fn [< $type:lower _ $func _get>](ptr: ExternPointer<Arc<dyn $type>>, index: usize) -> OwnedPtr<c_char> { extern "C" fn [< $type:lower _ $func _get>](ptr: FFIHandle<Arc<dyn $type>>, index: usize) -> OwnedPtrString {
CString::new(ptr.as_ref().$func().get(index).unwrap().str()).unwrap().into_raw() CString::new(ptr.from_ffi_handle().$func().get(index).unwrap().str()).unwrap().into_raw()
} }
} }
}; };
} }
use crate::dynamic_data::{Battle, Pokemon}; pub(self) use ffi_handle_arc_dyn_getter;
use crate::{ValueIdentifiable, ValueIdentifier}; pub(self) use ffi_handle_arc_stringkey_getter;
pub(self) use ffi_arc_dyn_getter; pub(self) use ffi_handle_vec_stringkey_getters;
pub(self) use ffi_arc_getter; pub(self) use ffi_handle_vec_value_getters;
pub(self) use ffi_arc_stringkey_getter;
pub(self) use ffi_vec_stringkey_getters;
pub(self) use ffi_vec_value_getters;
use std::ffi::{c_char, CString}; use std::ffi::{c_char, CString};
use std::mem::transmute;
use std::sync::Arc;
/// Helper utility class to wrap a pointer for extern functions. /// Helper utility class to wrap a pointer for extern functions.
#[repr(C)] #[repr(C)]
@ -115,184 +99,6 @@ impl<T: ?Sized> ExternPointer<T> {
.unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::<T>())) .unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::<T>()))
} }
} }
/// Get the internal pointer as mutable reference.
#[allow(clippy::panic)] // We currently allow this as these should never be null, but we might want to change this in the future.
pub(self) fn as_mut(&mut self) -> &mut T {
unsafe {
self.ptr
.as_mut()
.unwrap_or_else(|| panic!("Given pointer of type '{}' was null", std::any::type_name::<T>()))
}
}
}
/// Helper utility class to give both the pointer and identifier to a FFI.
#[repr(C)]
pub(self) struct IdentifiablePointer<T> {
/// The wrapped pointer.
pub ptr: *const T,
/// The identifier of the pointer.
pub id: usize,
}
impl<T> Clone for IdentifiablePointer<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
ptr: self.ptr,
}
}
}
impl<T> Copy for IdentifiablePointer<T> {}
impl<T> IdentifiablePointer<T> {
/// Creates a new IdentifiablePointer.
pub(self) fn new(ptr: *const T, id: ValueIdentifier) -> Self {
unsafe { Self { ptr, id: transmute(id) } }
}
}
impl<T> From<*mut T> for ExternPointer<T> {
fn from(ptr: *mut T) -> Self {
ExternPointer { ptr }
}
}
impl<T: ValueIdentifiable + ?Sized> From<Arc<T>> for IdentifiablePointer<Arc<T>> {
fn from(v: Arc<T>) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Arc<T>>> for IdentifiablePointer<Arc<T>> {
fn from(v: Option<Arc<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Box<T>> for IdentifiablePointer<Box<T>> {
fn from(v: &Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: v as *const Box<T>,
id,
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable + ?Sized> From<&Option<Box<T>>> for IdentifiablePointer<Box<T>> {
fn from(v: &Option<Box<T>>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
unsafe {
Self {
ptr: *Box::into_raw(Box::new(v as *const Box<T>)),
id,
}
}
} else {
IdentifiablePointer::none()
}
}
}
impl<T: ValueIdentifiable> From<Box<T>> for IdentifiablePointer<T> {
fn from(v: Box<T>) -> Self {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(v),
id,
}
}
}
impl<T: ValueIdentifiable> From<*const T> for IdentifiablePointer<T> {
#[allow(clippy::unwrap_used)] // We currently allow this as these should never be null, but we might want to change this in the future.
fn from(v: *const T) -> Self {
let id = unsafe { transmute(v.as_ref().unwrap().value_identifier()) };
Self { ptr: v, id }
}
}
impl From<Pokemon> for IdentifiablePointer<Pokemon> {
fn from(v: Pokemon) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl From<Option<Pokemon>> for IdentifiablePointer<Pokemon> {
fn from(v: Option<Pokemon>) -> Self {
if let Some(v) = v {
let id = unsafe { transmute(v.value_identifier()) };
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
} else {
IdentifiablePointer::none()
}
}
}
impl From<Battle> for IdentifiablePointer<Battle> {
fn from(v: Battle) -> Self {
let id = v.value_identifier().value();
Self {
ptr: Box::into_raw(Box::new(v)),
id,
}
}
}
impl<T> IdentifiablePointer<T> {
/// Returns an identifiable pointer with null as pointer, and 0 as identifier.
pub fn none() -> Self {
Self {
ptr: std::ptr::null(),
id: Default::default(),
}
}
} }
/// Helper utility class to give either the data or an error to a FFI. /// Helper utility class to give either the data or an error to a FFI.
@ -301,19 +107,19 @@ union ResultUnion<T: Copy> {
/// If the result is ok, this contains the value. /// If the result is ok, this contains the value.
ok: T, ok: T,
/// If the result is an error, this contains the error message. /// If the result is an error, this contains the error message.
err: OwnedPtr<c_char>, err: NonOwnedPtrString,
} }
/// The result of a FFI call that can either be an error or a value. /// The result of a FFI call that can either be an error or a value.
#[repr(C)] #[repr(C)]
pub struct NativeResult<T: Copy> { pub struct FFIResult<T: Copy> {
/// If the result is ok, this is 1, otherwise 0. /// If the result is ok, this is 1, otherwise 0.
ok: u8, ok: u8,
/// The value or error. /// The value or error.
value: ResultUnion<T>, value: ResultUnion<T>,
} }
impl<T: Copy> NativeResult<T> { impl<T: Copy> FFIResult<T> {
/// Creates a new NativeResult with the given value. /// Creates a new NativeResult with the given value.
pub fn ok(value: T) -> Self { pub fn ok(value: T) -> Self {
Self { Self {
@ -344,7 +150,7 @@ impl<T: Copy> NativeResult<T> {
} }
} }
impl<T: Copy> From<anyhow::Result<T>> for NativeResult<T> { impl<T: Copy> From<anyhow::Result<T>> for FFIResult<T> {
fn from(value: anyhow::Result<T>) -> Self { fn from(value: anyhow::Result<T>) -> Self {
match value { match value {
Ok(v) => Self::ok(v), Ok(v) => Self::ok(v),
@ -353,7 +159,7 @@ impl<T: Copy> From<anyhow::Result<T>> for NativeResult<T> {
} }
} }
impl<T: Copy> From<T> for NativeResult<T> { impl<T: Copy> From<T> for FFIResult<T> {
fn from(value: T) -> Self { fn from(value: T) -> Self {
Self::ok(value) Self::ok(value)
} }

View File

@ -1,9 +1,10 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::FFIHandle;
use crate::ffi::FromFFIHandle;
use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::{Ability, AbilityImpl, EffectParameter}; use crate::static_data::{Ability, AbilityImpl, EffectParameter};
use crate::StringKey; use crate::StringKey;
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new ability. /// Instantiates a new ability.
@ -11,67 +12,61 @@ use std::sync::Arc;
unsafe extern "C" fn ability_new( unsafe extern "C" fn ability_new(
name: *const c_char, name: *const c_char,
effect: *const c_char, effect: *const c_char,
parameters: *const OwnedPtr<Arc<EffectParameter>>, parameters: *const FFIHandle<Arc<EffectParameter>>,
parameters_length: usize, parameters_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Ability>>> { ) -> FFIResult<FFIHandle<Arc<dyn Ability>>> {
let parameters = std::slice::from_raw_parts(parameters, parameters_length); let parameters = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters_vec: Vec<Arc<EffectParameter>> = Vec::with_capacity(parameters_length); let mut parameters_vec: Vec<Arc<EffectParameter>> = Vec::with_capacity(parameters_length);
for parameter in parameters { for parameter in parameters {
parameters_vec.push(parameter.read()); parameters_vec.push(parameter.from_ffi_handle());
} }
let name: StringKey = match CStr::from_ptr(name).to_str() { let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(s) => s.into(), Ok(s) => s.into(),
Err(_) => return NativeResult::err(anyhow!("Failed to convert name to CStr")), Err(_) => return FFIResult::err(anyhow!("Failed to convert name to CStr")),
}; };
let effect: StringKey = match CStr::from_ptr(effect).to_str() { let effect: StringKey = match CStr::from_ptr(effect).to_str() {
Ok(s) => s.into(), Ok(s) => s.into(),
Err(_) => return NativeResult::err(anyhow!("Failed to convert effect to CStr")), Err(_) => return FFIResult::err(anyhow!("Failed to convert effect to CStr")),
}; };
let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec)); let arc: Arc<dyn Ability> = Arc::new(AbilityImpl::new(&name, &effect, parameters_vec));
NativeResult::ok(arc.into()) FFIResult::ok(FFIHandle::get_handle(arc.into()))
}
/// Drops a reference counted ability.
#[no_mangle]
unsafe extern "C" fn ability_drop(ptr: OwnedPtr<Arc<dyn Ability>>) {
drop_in_place(ptr)
} }
/// The name of the ability. /// The name of the ability.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn ability_name(ptr: ExternPointer<Arc<dyn Ability>>) -> NativeResult<OwnedPtr<c_char>> { unsafe extern "C" fn ability_name(handle: FFIHandle<Arc<dyn Ability>>) -> FFIResult<OwnedPtrString> {
match CString::new(ptr.as_ref().name().str()) { match CString::new(handle.from_ffi_handle().name().str()) {
Ok(s) => NativeResult::ok(s.into_raw()), Ok(s) => FFIResult::ok(s.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert name to CString")), Err(_) => FFIResult::err(anyhow!("Failed to convert name to CString")),
} }
} }
/// The name of the script effect of the ability. /// The name of the script effect of the ability.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn ability_effect(ptr: ExternPointer<Arc<dyn Ability>>) -> NativeResult<OwnedPtr<c_char>> { unsafe extern "C" fn ability_effect(ptr: FFIHandle<Arc<dyn Ability>>) -> FFIResult<OwnedPtrString> {
match CString::new(ptr.as_ref().effect().str()) { match CString::new(ptr.from_ffi_handle().effect().str()) {
Ok(s) => NativeResult::ok(s.into_raw()), Ok(s) => FFIResult::ok(s.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert effect to CString")), Err(_) => FFIResult::err(anyhow!("Failed to convert effect to CString")),
} }
} }
/// The length of the parameters for the script effect of the ability. /// The length of the parameters for the script effect of the ability.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn ability_parameter_length(ptr: ExternPointer<Arc<dyn Ability>>) -> usize { unsafe extern "C" fn ability_parameter_length(ptr: FFIHandle<Arc<dyn Ability>>) -> usize {
ptr.as_ref().parameters().len() ptr.from_ffi_handle().parameters().len()
} }
/// Gets a parameter for the script effect of the ability. /// Gets a parameter for the script effect of the ability.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn ability_parameter_get( unsafe extern "C" fn ability_parameter_get(
ptr: ExternPointer<Arc<dyn Ability>>, ptr: FFIHandle<Arc<dyn Ability>>,
index: usize, index: usize,
) -> IdentifiablePointer<Arc<EffectParameter>> { ) -> FFIHandle<Arc<EffectParameter>> {
if let Some(p) = ptr.as_ref().parameters().get(index) { if let Some(p) = ptr.from_ffi_handle().parameters().get(index) {
p.clone().into() FFIHandle::get_handle(p.clone().into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }

View File

@ -1,13 +1,13 @@
use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ use crate::ffi::{
ffi_arc_dyn_getter, ffi_vec_stringkey_getters, ffi_vec_value_getters, BorrowedPtr, ExternPointer, ffi_handle_arc_dyn_getter, ffi_handle_vec_stringkey_getters, ffi_handle_vec_value_getters, FFIResult,
IdentifiablePointer, NativeResult, OwnedPtr, NonOwnedPtrString, OwnedPtrString,
}; };
use crate::static_data::{Form, FormImpl, LearnableMoves, StaticStatisticSet, TypeIdentifier}; use crate::static_data::{Form, FormImpl, LearnableMoves, StaticStatisticSet, TypeIdentifier};
use crate::StringKey; use crate::StringKey;
use anyhow::anyhow; use anyhow::anyhow;
use hashbrown::HashSet; use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new form. /// Instantiates a new form.
@ -19,18 +19,18 @@ unsafe extern "C" fn form_new(
base_experience: u32, base_experience: u32,
types: *const TypeIdentifier, types: *const TypeIdentifier,
types_length: usize, types_length: usize,
base_stats: OwnedPtr<StaticStatisticSet<u16>>, base_stats: FFIHandle<Arc<StaticStatisticSet<u16>>>,
abilities: *const BorrowedPtr<c_char>, abilities: *const NonOwnedPtrString,
abilities_length: usize, abilities_length: usize,
hidden_abilities: *const BorrowedPtr<c_char>, hidden_abilities: *const NonOwnedPtrString,
hidden_abilities_length: usize, hidden_abilities_length: usize,
moves: OwnedPtr<Box<dyn LearnableMoves>>, moves: FFIHandle<Arc<dyn LearnableMoves>>,
flags: *const *const c_char, flags: *const *const c_char,
flags_length: usize, flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Form>>> { ) -> FFIResult<FFIHandle<Arc<dyn Form>>> {
let name: StringKey = match CStr::from_ptr(name).to_str() { let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(), Ok(name) => name.into(),
Err(_) => return NativeResult::err(anyhow!("Unable to convert name to string")), Err(_) => return FFIResult::err(anyhow!("Unable to convert name to string")),
}; };
let abilities = std::slice::from_raw_parts(abilities, abilities_length); let abilities = std::slice::from_raw_parts(abilities, abilities_length);
@ -49,7 +49,7 @@ unsafe extern "C" fn form_new(
for flag in flags { for flag in flags {
let flag = match CStr::from_ptr(*flag).to_str() { let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag, Ok(flag) => flag,
Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")), Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")),
}; };
flags_set.insert(flag.into()); flags_set.insert(flag.into());
} }
@ -60,57 +60,50 @@ unsafe extern "C" fn form_new(
weight, weight,
base_experience, base_experience,
std::slice::from_raw_parts(types, types_length).to_vec(), std::slice::from_raw_parts(types, types_length).to_vec(),
*Box::from_raw(base_stats), base_stats.from_ffi_handle(),
abilities_vec, abilities_vec,
hidden_abilities_vec, hidden_abilities_vec,
*Box::from_raw(moves), moves.from_ffi_handle(),
flags_set, flags_set,
)); ));
NativeResult::ok(a.into()) FFIResult::ok(FFIHandle::get_handle(a.into()))
}
/// Drops a reference count for a form.
#[no_mangle]
unsafe extern "C" fn form_drop(ptr: OwnedPtr<Arc<dyn Form>>) {
drop_in_place(ptr)
} }
/// The name of the form. /// The name of the form.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn form_name(ptr: ExternPointer<Arc<dyn Form>>) -> NativeResult<OwnedPtr<c_char>> { unsafe extern "C" fn form_name(ptr: FFIHandle<Arc<dyn Form>>) -> FFIResult<OwnedPtrString> {
let name = ptr.as_ref().name(); let obj = ptr.from_ffi_handle();
let name = obj.name();
match CString::new(name.str()) { match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()), Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), Err(_) => FFIResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())),
} }
} }
ffi_arc_dyn_getter!(Form, height, f32); ffi_handle_arc_dyn_getter!(Form, height, f32);
ffi_arc_dyn_getter!(Form, weight, f32); ffi_handle_arc_dyn_getter!(Form, weight, f32);
ffi_arc_dyn_getter!(Form, base_experience, u32); ffi_handle_arc_dyn_getter!(Form, base_experience, u32);
ffi_vec_value_getters!(Form, dyn Form, types, TypeIdentifier); ffi_handle_vec_value_getters!(Form, dyn Form, types, TypeIdentifier);
/// The inherent values of a form of species that are used for the stats of a Pokemon. /// The inherent values of a form of species that are used for the stats of a Pokemon.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn form_base_stats( unsafe extern "C" fn form_base_stats(ptr: FFIHandle<Arc<dyn Form>>) -> FFIHandle<Arc<StaticStatisticSet<u16>>> {
ptr: ExternPointer<Arc<dyn Form>>, FFIHandle::get_handle(ptr.from_ffi_handle().base_stats().clone().into())
) -> IdentifiablePointer<Arc<StaticStatisticSet<u16>>> {
ptr.as_ref().base_stats().clone().into()
} }
ffi_vec_stringkey_getters!(Form, abilities); ffi_handle_vec_stringkey_getters!(Form, abilities);
ffi_vec_stringkey_getters!(Form, hidden_abilities); ffi_handle_vec_stringkey_getters!(Form, hidden_abilities);
/// The moves a Pokemon with this form can learn. /// The moves a Pokemon with this form can learn.
#[no_mangle] #[no_mangle]
extern "C" fn form_moves(ptr: ExternPointer<Arc<dyn Form>>) -> BorrowedPtr<Box<dyn LearnableMoves>> { extern "C" fn form_moves(ptr: FFIHandle<Arc<dyn Form>>) -> FFIHandle<Arc<dyn LearnableMoves>> {
ptr.as_ref().moves() as *const Box<dyn LearnableMoves> FFIHandle::get_handle(ptr.from_ffi_handle().moves().clone().into())
} }
/// Check if the form has a specific flag set. /// Check if the form has a specific flag set.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn form_has_flag(ptr: ExternPointer<Arc<dyn Form>>, flag: *const c_char) -> u8 { unsafe extern "C" fn form_has_flag(ptr: FFIHandle<Arc<dyn Form>>, flag: *const c_char) -> u8 {
let flag = CStr::from_ptr(flag).into(); let flag = CStr::from_ptr(flag).into();
u8::from(ptr.as_ref().has_flag(&flag)) u8::from(ptr.from_ffi_handle().has_flag(&flag))
} }

View File

@ -1,33 +1,26 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::ffi::{ExternPointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::{GrowthRate, LookupGrowthRate}; use crate::static_data::{GrowthRate, LookupGrowthRate};
use std::ptr::drop_in_place; use std::sync::Arc;
/// Instantiates a new lookup growth rate. The experience array should be the amount of experience /// Instantiates a new lookup growth rate. The experience array should be the amount of experience
/// required per level, with the first element being the experience required for level 1 (generally 0). /// required per level, with the first element being the experience required for level 1 (generally 0).
#[no_mangle] #[no_mangle]
unsafe extern "C" fn growth_rate_lookup_new(array: *const u32, length: usize) -> OwnedPtr<Box<dyn GrowthRate>> { unsafe extern "C" fn growth_rate_lookup_new(array: *const u32, length: usize) -> FFIHandle<Arc<dyn GrowthRate>> {
let array = std::slice::from_raw_parts(array, length); let array = std::slice::from_raw_parts(array, length);
Box::into_raw(Box::new(Box::new(LookupGrowthRate::new(array.to_vec())))) let g: Arc<dyn GrowthRate> = Arc::new(LookupGrowthRate::new(array.to_vec()));
} FFIHandle::get_handle(g.into())
/// Drops the growth rate.
#[no_mangle]
unsafe extern "C" fn growth_rate_lookup_drop(ptr: OwnedPtr<Box<dyn GrowthRate>>) {
drop_in_place(ptr)
} }
/// Calculate the level something with this growth rate would have at a certain experience. /// Calculate the level something with this growth rate would have at a certain experience.
#[no_mangle] #[no_mangle]
extern "C" fn growth_rate_calculate_level(ptr: ExternPointer<Box<dyn GrowthRate>>, experience: u32) -> LevelInt { extern "C" fn growth_rate_calculate_level(ptr: FFIHandle<Arc<dyn GrowthRate>>, experience: u32) -> LevelInt {
ptr.as_ref().calculate_level(experience) ptr.from_ffi_handle().calculate_level(experience)
} }
/// Calculate the experience something with this growth rate would have at a certain level. /// Calculate the experience something with this growth rate would have at a certain level.
#[no_mangle] #[no_mangle]
extern "C" fn growth_rate_calculate_experience( extern "C" fn growth_rate_calculate_experience(ptr: FFIHandle<Arc<dyn GrowthRate>>, level: LevelInt) -> FFIResult<u32> {
ptr: ExternPointer<Box<dyn GrowthRate>>, ptr.from_ffi_handle().calculate_experience(level).into()
level: LevelInt,
) -> NativeResult<u32> {
ptr.as_ref().calculate_experience(level).into()
} }

View File

@ -1,10 +1,10 @@
use crate::ffi::{ffi_arc_dyn_getter, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ffi_handle_arc_dyn_getter, FFIResult, OwnedPtrString};
use crate::static_data::{BattleItemCategory, Item, ItemCategory, ItemImpl}; use crate::static_data::{BattleItemCategory, Item, ItemCategory, ItemImpl};
use crate::StringKey; use crate::StringKey;
use anyhow::anyhow; use anyhow::anyhow;
use hashbrown::HashSet; use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates an item. /// Instantiates an item.
@ -16,48 +16,43 @@ unsafe extern "C" fn item_new(
price: i32, price: i32,
flags: *const *const c_char, flags: *const *const c_char,
flags_length: usize, flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Item>>> { ) -> FFIResult<FFIHandle<Arc<dyn Item>>> {
let flags = std::slice::from_raw_parts(flags, flags_length); let flags = std::slice::from_raw_parts(flags, flags_length);
let name: StringKey = match CStr::from_ptr(name).to_str() { let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(), Ok(name) => name.into(),
Err(_) => return NativeResult::err(anyhow!("Unable to convert name to string")), Err(_) => return FFIResult::err(anyhow!("Unable to convert name to string")),
}; };
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length); let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
for flag in flags { for flag in flags {
let flag = match CStr::from_ptr(*flag).to_str() { let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag, Ok(flag) => flag,
Err(_) => return NativeResult::err(anyhow!("Unable to convert flag to string")), Err(_) => return FFIResult::err(anyhow!("Unable to convert flag to string")),
}; };
flags_set.insert(flag.into()); flags_set.insert(flag.into());
} }
let item: Arc<dyn Item> = Arc::new(ItemImpl::new(&name, category, battle_category, price, flags_set)); let item: Arc<dyn Item> = Arc::new(ItemImpl::new(&name, category, battle_category, price, flags_set));
NativeResult::ok(item.into()) FFIResult::ok(FFIHandle::get_handle(item.into()))
}
/// Drops a reference counted item.
#[no_mangle]
unsafe extern "C" fn item_drop(ptr: OwnedPtr<Arc<dyn Item>>) {
drop_in_place(ptr)
} }
/// The name of the item. /// The name of the item.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn item_name(ptr: ExternPointer<Arc<dyn Item>>) -> NativeResult<OwnedPtr<c_char>> { unsafe extern "C" fn item_name(ptr: FFIHandle<Arc<dyn Item>>) -> FFIResult<OwnedPtrString> {
let name = ptr.as_ref().name(); let item = ptr.from_ffi_handle();
let name = item.name();
match CString::new(name.str()) { match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()), Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())), Err(_) => FFIResult::err(anyhow!("Unable to convert name `{}` to CString", name.str())),
} }
} }
ffi_arc_dyn_getter!(Item, category, ItemCategory); ffi_handle_arc_dyn_getter!(Item, category, ItemCategory);
ffi_arc_dyn_getter!(Item, battle_category, BattleItemCategory); ffi_handle_arc_dyn_getter!(Item, battle_category, BattleItemCategory);
ffi_arc_dyn_getter!(Item, price, i32); ffi_handle_arc_dyn_getter!(Item, price, i32);
/// Checks whether the item has a specific flag. /// Checks whether the item has a specific flag.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn item_has_flag(ptr: ExternPointer<Arc<dyn Item>>, flag: *const c_char) -> u8 { unsafe extern "C" fn item_has_flag(ptr: FFIHandle<Arc<dyn Item>>, flag: *const c_char) -> u8 {
let flag = CStr::from_ptr(flag).into(); let flag = CStr::from_ptr(flag).into();
u8::from(ptr.as_ref().has_flag(&flag)) u8::from(ptr.from_ffi_handle().has_flag(&flag))
} }

View File

@ -1,29 +1,25 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::ffi::{BorrowedPtr, ExternPointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString};
use crate::static_data::{LearnableMoves, LearnableMovesImpl}; use crate::static_data::{LearnableMoves, LearnableMovesImpl};
use std::ffi::{c_char, CStr}; use std::ffi::CStr;
use std::ptr::drop_in_place; use std::sync::Arc;
/// Instantiates a new Learnable Moves. /// Instantiates a new Learnable Moves.
#[no_mangle] #[no_mangle]
extern "C" fn learnable_moves_new(max_level: LevelInt) -> OwnedPtr<Box<dyn LearnableMoves>> { extern "C" fn learnable_moves_new(max_level: LevelInt) -> FFIHandle<Arc<dyn LearnableMoves>> {
Box::into_raw(Box::new(Box::new(LearnableMovesImpl::new(max_level)))) let p: Arc<dyn LearnableMoves> = Arc::new(LearnableMovesImpl::new(max_level));
} FFIHandle::get_handle(p.into())
/// drops a learnablemoves struct.
#[no_mangle]
unsafe extern "C" fn learnable_moves_drop(ptr: OwnedPtr<Box<dyn LearnableMoves>>) {
drop_in_place(ptr)
} }
/// Adds a new level move the Pokemon can learn. /// Adds a new level move the Pokemon can learn.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn learnable_moves_add_level_move( unsafe extern "C" fn learnable_moves_add_level_move(
mut ptr: ExternPointer<Box<dyn LearnableMoves>>, ptr: FFIHandle<Arc<dyn LearnableMoves>>,
level: LevelInt, level: LevelInt,
move_name: BorrowedPtr<c_char>, move_name: NonOwnedPtrString,
) -> NativeResult<()> { ) -> FFIResult<()> {
ptr.as_mut() ptr.from_ffi_handle()
.add_level_move(level, &CStr::from_ptr(move_name).into()) .add_level_move(level, &CStr::from_ptr(move_name).into())
.into() .into()
} }

View File

@ -1,30 +1,25 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString};
use crate::static_data::{GrowthRate, GrowthRateLibrary, GrowthRateLibraryImpl}; use crate::static_data::{GrowthRate, GrowthRateLibrary, GrowthRateLibraryImpl};
use std::ffi::{c_char, CStr}; use std::ffi::CStr;
use std::ptr::drop_in_place; use std::sync::Arc;
/// Instantiates a new growth rate library with a capacity /// Instantiates a new growth rate library with a capacity
#[no_mangle] #[no_mangle]
extern "C" fn growth_rate_library_new(capacity: usize) -> IdentifiablePointer<Box<dyn GrowthRateLibrary>> { extern "C" fn growth_rate_library_new(capacity: usize) -> FFIHandle<Arc<dyn GrowthRateLibrary>> {
let b: Box<dyn GrowthRateLibrary> = Box::new(GrowthRateLibraryImpl::new(capacity)); let b: Arc<dyn GrowthRateLibrary> = Arc::new(GrowthRateLibraryImpl::new(capacity));
b.into() FFIHandle::get_handle(b.into())
}
/// Drops the growthrate library.
#[no_mangle]
unsafe extern "C" fn growth_rate_library_drop(ptr: OwnedPtr<Box<dyn GrowthRateLibrary>>) {
drop_in_place(ptr)
} }
/// Calculates the level for a given growth key name and a certain experience. /// Calculates the level for a given growth key name and a certain experience.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn growth_rate_library_calculate_level( unsafe extern "C" fn growth_rate_library_calculate_level(
ptr: ExternPointer<Box<dyn GrowthRateLibrary>>, ptr: FFIHandle<Arc<dyn GrowthRateLibrary>>,
growth_rate: BorrowedPtr<c_char>, growth_rate: NonOwnedPtrString,
experience: u32, experience: u32,
) -> NativeResult<LevelInt> { ) -> FFIResult<LevelInt> {
ptr.as_ref() ptr.from_ffi_handle()
.calculate_level(&CStr::from_ptr(growth_rate).into(), experience) .calculate_level(&CStr::from_ptr(growth_rate).into(), experience)
.into() .into()
} }
@ -32,11 +27,11 @@ unsafe extern "C" fn growth_rate_library_calculate_level(
/// Calculates the experience for a given growth key name and a certain level. /// Calculates the experience for a given growth key name and a certain level.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn growth_rate_library_calculate_experience( unsafe extern "C" fn growth_rate_library_calculate_experience(
ptr: ExternPointer<Box<dyn GrowthRateLibrary>>, ptr: FFIHandle<Arc<dyn GrowthRateLibrary>>,
growth_rate: BorrowedPtr<c_char>, growth_rate: NonOwnedPtrString,
level: LevelInt, level: LevelInt,
) -> NativeResult<u32> { ) -> FFIResult<u32> {
ptr.as_ref() ptr.from_ffi_handle()
.calculate_experience(&CStr::from_ptr(growth_rate).into(), level) .calculate_experience(&CStr::from_ptr(growth_rate).into(), level)
.into() .into()
} }
@ -44,10 +39,10 @@ unsafe extern "C" fn growth_rate_library_calculate_experience(
/// Adds a new growth rate with a name and value. /// Adds a new growth rate with a name and value.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn growth_rate_library_add_growth_rate( unsafe extern "C" fn growth_rate_library_add_growth_rate(
mut ptr: ExternPointer<Box<dyn GrowthRateLibrary>>, ptr: FFIHandle<Arc<dyn GrowthRateLibrary>>,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
growth_rate: OwnedPtr<Box<dyn GrowthRate>>, growth_rate: FFIHandle<Arc<dyn GrowthRate>>,
) { ) {
ptr.as_mut() ptr.from_ffi_handle()
.add_growth_rate(&CStr::from_ptr(name).into(), *Box::from_raw(growth_rate)); .add_growth_rate(&CStr::from_ptr(name).into(), growth_rate.from_ffi_handle());
} }

View File

@ -1,7 +1,8 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::FFIResult;
use crate::static_data::{LibrarySettings, LibrarySettingsImpl}; use crate::static_data::{LibrarySettings, LibrarySettingsImpl};
use std::ptr::drop_in_place; use std::sync::Arc;
/// Creates a new settings library. /// Creates a new settings library.
/// - `maximum_level` is the highest level a Pokemon can be. /// - `maximum_level` is the highest level a Pokemon can be.
@ -12,32 +13,26 @@ use std::ptr::drop_in_place;
extern "C" fn library_settings_new( extern "C" fn library_settings_new(
max_level: LevelInt, max_level: LevelInt,
shiny_rate: u32, shiny_rate: u32,
) -> NativeResult<IdentifiablePointer<Box<dyn LibrarySettings>>> { ) -> FFIResult<FFIHandle<Arc<dyn LibrarySettings>>> {
match LibrarySettingsImpl::new(max_level, shiny_rate) { match LibrarySettingsImpl::new(max_level, shiny_rate) {
Ok(settings) => { Ok(settings) => {
let b: Box<dyn LibrarySettings> = Box::new(settings); let b: Arc<dyn LibrarySettings> = Arc::new(settings);
let p: IdentifiablePointer<Box<dyn LibrarySettings>> = b.into(); let p: FFIHandle<Arc<dyn LibrarySettings>> = FFIHandle::get_handle(b.into());
p.into() FFIResult::ok(p)
} }
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }
/// Drop a library settings object.
#[no_mangle]
unsafe extern "C" fn library_settings_drop(ptr: OwnedPtr<Box<dyn LibrarySettings>>) {
drop_in_place(ptr)
}
/// The highest level a Pokemon can be. /// The highest level a Pokemon can be.
#[no_mangle] #[no_mangle]
extern "C" fn library_settings_maximum_level(ptr: ExternPointer<Box<dyn LibrarySettings>>) -> LevelInt { extern "C" fn library_settings_maximum_level(ptr: FFIHandle<Arc<dyn LibrarySettings>>) -> LevelInt {
ptr.as_ref().maximum_level() ptr.from_ffi_handle().maximum_level()
} }
/// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator /// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator
/// is 1. For example, if this is 1000, then the chance of a Pokemon being shiny is 1/1000. /// is 1. For example, if this is 1000, then the chance of a Pokemon being shiny is 1/1000.
#[no_mangle] #[no_mangle]
extern "C" fn library_settings_shiny_rate(ptr: ExternPointer<Box<dyn LibrarySettings>>) -> u32 { extern "C" fn library_settings_shiny_rate(ptr: FFIHandle<Arc<dyn LibrarySettings>>) -> u32 {
ptr.as_ref().shiny_rate() ptr.from_ffi_handle().shiny_rate()
} }

View File

@ -9,10 +9,10 @@ mod static_data;
/// The foreign function interface for the type library. /// The foreign function interface for the type library.
mod type_library; mod type_library;
use crate::ffi::{BorrowedPtr, IdentifiablePointer, OwnedPtr}; use crate::ffi::{FFIHandle, FromFFIHandle};
use crate::ffi::{NonOwnedPtrString, OwnedPtrString};
use crate::static_data::*; use crate::static_data::*;
use std::ffi::{c_char, CStr}; use std::ffi::CStr;
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Generates foreign function interfaces for a DataLibrary trait implementation. /// Generates foreign function interfaces for a DataLibrary trait implementation.
@ -20,42 +20,37 @@ macro_rules! library_interface {
($library_type_name:ident, $library_type:ty, $return_type:ty) => { ($library_type_name:ident, $library_type:ty, $return_type:ty) => {
paste::paste! { paste::paste! {
#[no_mangle] #[no_mangle]
extern "C" fn [< $library_type_name:snake _new >](capacity: usize) -> IdentifiablePointer<$library_type> { extern "C" fn [< $library_type_name:snake _new >](capacity: usize) -> FFIHandle<$library_type> {
let value: $library_type = Box::new([<$library_type_name Impl>]::new(capacity)); let value: $library_type = Arc::new([<$library_type_name Impl>]::new(capacity));
value.into() FFIHandle::get_handle(value.into())
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _drop >](ptr: OwnedPtr<$library_type>) { unsafe extern "C" fn [< $library_type_name:snake _add >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString, value: FFIHandle<Arc<$return_type>>) {
drop_in_place(ptr); let lib = ptr.from_ffi_handle();
lib.add(&CStr::from_ptr(key).into(), value.from_ffi_handle());
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _add >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr<c_char>, value: OwnedPtr<Arc<$return_type>>) { unsafe extern "C" fn [< $library_type_name:snake _remove >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString) {
let lib = ptr.as_mut().unwrap(); let lib = ptr.from_ffi_handle();
lib.add(&CStr::from_ptr(key).into(), *Box::from_raw(value));
}
#[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _remove >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr<c_char>) {
let lib = ptr.as_mut().unwrap();
lib.remove(&CStr::from_ptr(key).into()); lib.remove(&CStr::from_ptr(key).into());
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _get >](ptr: OwnedPtr<$library_type>, key: BorrowedPtr<c_char>) -> IdentifiablePointer<Arc<$return_type>> { unsafe extern "C" fn [< $library_type_name:snake _get >](ptr: FFIHandle<$library_type>, key: NonOwnedPtrString) -> FFIHandle<Arc<$return_type>> {
let lib = ptr.as_mut().unwrap(); let lib = ptr.from_ffi_handle();
let v = lib.get(&CStr::from_ptr(key).into()); let v = lib.get(&CStr::from_ptr(key).into());
if let Some(value) = v { if let Some(value) = v {
value.clone().into() FFIHandle::get_handle(value.clone().into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _get_key_by_index >](ptr: OwnedPtr<$library_type>, index: usize) -> OwnedPtr<c_char> { unsafe extern "C" fn [< $library_type_name:snake _get_key_by_index >](ptr: FFIHandle<$library_type>, index: usize) -> OwnedPtrString {
let lib = ptr.as_mut().unwrap(); let lib = ptr.from_ffi_handle();
let v = lib.get_key_by_index(index); let v = lib.get_key_by_index(index);
if let Some(value) = v { if let Some(value) = v {
std::ffi::CString::new(value.str()).unwrap().into_raw() std::ffi::CString::new(value.str()).unwrap().into_raw()
@ -65,15 +60,15 @@ macro_rules! library_interface {
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [< $library_type_name:snake _len >](ptr: OwnedPtr<$library_type>) -> usize { unsafe extern "C" fn [< $library_type_name:snake _len >](ptr: FFIHandle<$library_type>) -> usize {
let lib = ptr.as_mut().unwrap(); let lib = ptr.from_ffi_handle();
lib.len() lib.len()
} }
} }
}; };
} }
library_interface!(SpeciesLibrary, Box<dyn SpeciesLibrary>, dyn Species); library_interface!(SpeciesLibrary, Arc<dyn SpeciesLibrary>, dyn Species);
library_interface!(MoveLibrary, Box<dyn MoveLibrary>, dyn MoveData); library_interface!(MoveLibrary, Arc<dyn MoveLibrary>, dyn MoveData);
library_interface!(AbilityLibrary, Box<dyn AbilityLibrary>, dyn Ability); library_interface!(AbilityLibrary, Arc<dyn AbilityLibrary>, dyn Ability);
library_interface!(ItemLibrary, Box<dyn ItemLibrary>, dyn Item); library_interface!(ItemLibrary, Arc<dyn ItemLibrary>, dyn Item);

View File

@ -1,84 +1,79 @@
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString, OwnedPtrString};
use crate::static_data::{Nature, NatureLibrary, NatureLibraryImpl}; use crate::static_data::{Nature, NatureLibrary, NatureLibraryImpl};
use crate::{PkmnError, Random}; use crate::{PkmnError, Random};
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Creates a new nature library with a given capacity. /// Creates a new nature library with a given capacity.
#[no_mangle] #[no_mangle]
extern "C" fn nature_library_new(capacity: usize) -> IdentifiablePointer<Box<dyn NatureLibrary>> { extern "C" fn nature_library_new(capacity: usize) -> FFIHandle<Arc<dyn NatureLibrary>> {
let b: Box<dyn NatureLibrary> = Box::new(NatureLibraryImpl::new(capacity)); let b: Arc<dyn NatureLibrary> = Arc::new(NatureLibraryImpl::new(capacity));
b.into() FFIHandle::get_handle(b.into())
}
/// Drop a nature library.
#[no_mangle]
unsafe extern "C" fn nature_library_drop(ptr: OwnedPtr<Box<dyn NatureLibrary>>) {
drop_in_place(ptr);
} }
/// Adds a new nature with name to the library. /// Adds a new nature with name to the library.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn nature_library_load_nature( unsafe extern "C" fn nature_library_load_nature(
mut ptr: ExternPointer<Box<dyn NatureLibrary>>, ptr: FFIHandle<Arc<dyn NatureLibrary>>,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
nature: OwnedPtr<Arc<dyn Nature>>, nature: FFIHandle<Arc<dyn Nature>>,
) -> NativeResult<()> { ) -> FFIResult<()> {
let nature = nature.as_ref().ok_or(PkmnError::NullReference); let nature = nature.from_ffi_handle_opt().ok_or(PkmnError::NullReference);
match nature { match nature {
Ok(nature) => { Ok(nature) => {
ptr.as_mut().load_nature(CStr::from_ptr(name).into(), nature.clone()); ptr.from_ffi_handle()
NativeResult::ok(()) .load_nature(CStr::from_ptr(name).into(), nature.clone());
FFIResult::ok(())
} }
Err(e) => NativeResult::err(e.into()), Err(e) => FFIResult::err(e.into()),
} }
} }
/// Gets a nature by name. /// Gets a nature by name.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn nature_library_get_nature( unsafe extern "C" fn nature_library_get_nature(
ptr: ExternPointer<Box<dyn NatureLibrary>>, ptr: FFIHandle<Arc<dyn NatureLibrary>>,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
) -> IdentifiablePointer<Arc<dyn Nature>> { ) -> FFIHandle<Arc<dyn Nature>> {
if let Some(nature) = ptr.as_ref().get_nature(&CStr::from_ptr(name).into()) { if let Some(nature) = ptr.from_ffi_handle().get_nature(&CStr::from_ptr(name).into()) {
nature.into() FFIHandle::get_handle(nature.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Gets a random nature. /// Gets a random nature.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn nature_library_get_random_nature( unsafe extern "C" fn nature_library_get_random_nature(
ptr: ExternPointer<Box<dyn NatureLibrary>>, ptr: FFIHandle<Arc<dyn NatureLibrary>>,
seed: u64, seed: u64,
) -> NativeResult<IdentifiablePointer<Arc<dyn Nature>>> { ) -> FFIResult<FFIHandle<Arc<dyn Nature>>> {
let mut rand = Random::new(seed as u128); let mut rand = Random::new(seed as u128);
match ptr.as_ref().get_random_nature(&mut rand) { match ptr.from_ffi_handle().get_random_nature(&mut rand) {
Ok(nature) => NativeResult::ok(nature.into()), Ok(nature) => FFIResult::ok(FFIHandle::get_handle(nature.into())),
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }
/// Finds a nature name by nature. /// Finds a nature name by nature.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn nature_library_get_nature_name( unsafe extern "C" fn nature_library_get_nature_name(
ptr: ExternPointer<Box<dyn NatureLibrary>>, ptr: FFIHandle<Arc<dyn NatureLibrary>>,
nature: BorrowedPtr<Arc<dyn Nature>>, nature: FFIHandle<Arc<dyn Nature>>,
) -> NativeResult<OwnedPtr<c_char>> { ) -> FFIResult<OwnedPtrString> {
match nature.as_ref() { match nature.from_ffi_handle_opt() {
Some(nature) => { Some(nature) => {
let name = ptr.as_ref().get_nature_name(nature); let name = ptr.from_ffi_handle().get_nature_name(&nature);
match name { match name {
Ok(name) => match CString::new(name.str()) { Ok(name) => match CString::new(name.str()) {
Ok(cstr) => NativeResult::ok(cstr.into_raw()), Ok(cstr) => FFIResult::ok(cstr.into_raw()),
Err(_) => NativeResult::err(anyhow!("Failed to convert nature name to C string")), Err(_) => FFIResult::err(anyhow!("Failed to convert nature name to C string")),
}, },
Err(e) => NativeResult::err(e), Err(e) => FFIResult::err(e),
} }
} }
None => NativeResult::err(PkmnError::NullReference.into()), None => FFIResult::err(PkmnError::NullReference.into()),
} }
} }

View File

@ -1,102 +1,81 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::static_data::{ use crate::static_data::{
AbilityLibrary, GrowthRateLibrary, ItemLibrary, LibrarySettings, MoveLibrary, NatureLibrary, SpeciesLibrary, AbilityLibrary, GrowthRateLibrary, ItemLibrary, LibrarySettings, MoveLibrary, NatureLibrary, SpeciesLibrary,
StaticData, StaticDataImpl, TypeLibrary, StaticData, StaticDataImpl, TypeLibrary,
}; };
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new data collection. /// Instantiates a new data collection.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_new( unsafe extern "C" fn static_data_new(
settings: OwnedPtr<Arc<dyn LibrarySettings>>, settings: FFIHandle<Arc<dyn LibrarySettings>>,
species: OwnedPtr<Arc<dyn SpeciesLibrary>>, species: FFIHandle<Arc<dyn SpeciesLibrary>>,
moves: OwnedPtr<Arc<dyn MoveLibrary>>, moves: FFIHandle<Arc<dyn MoveLibrary>>,
items: OwnedPtr<Arc<dyn ItemLibrary>>, items: FFIHandle<Arc<dyn ItemLibrary>>,
growth_rates: OwnedPtr<Arc<dyn GrowthRateLibrary>>, growth_rates: FFIHandle<Arc<dyn GrowthRateLibrary>>,
types: OwnedPtr<Arc<dyn TypeLibrary>>, types: FFIHandle<Arc<dyn TypeLibrary>>,
natures: OwnedPtr<Arc<dyn NatureLibrary>>, natures: FFIHandle<Arc<dyn NatureLibrary>>,
abilities: OwnedPtr<Arc<dyn AbilityLibrary>>, abilities: FFIHandle<Arc<dyn AbilityLibrary>>,
) -> IdentifiablePointer<Arc<dyn StaticData>> { ) -> FFIHandle<Arc<dyn StaticData>> {
let b: Arc<dyn StaticData> = Arc::new(StaticDataImpl::new( let b: Arc<dyn StaticData> = Arc::new(StaticDataImpl::new(
settings.read(), settings.from_ffi_handle(),
species.read(), species.from_ffi_handle(),
moves.read(), moves.from_ffi_handle(),
items.read(), items.from_ffi_handle(),
growth_rates.read(), growth_rates.from_ffi_handle(),
types.read(), types.from_ffi_handle(),
natures.read(), natures.from_ffi_handle(),
abilities.read(), abilities.from_ffi_handle(),
)); ));
b.into() FFIHandle::get_handle(b.into())
}
/// Drop a static data.
#[no_mangle]
unsafe extern "C" fn static_data_drop(ptr: OwnedPtr<Box<dyn StaticData>>) {
drop_in_place(ptr)
} }
/// Several misc settings for the library. /// Several misc settings for the library.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_settings( unsafe extern "C" fn static_data_settings(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn LibrarySettings>> {
mut data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle(data.from_ffi_handle().settings().clone().into())
) -> IdentifiablePointer<Arc<dyn LibrarySettings>> {
data.as_mut().settings().clone().into()
} }
/// All data for Pokemon species. /// All data for Pokemon species.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_species( unsafe extern "C" fn static_data_species(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn SpeciesLibrary>> {
mut data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle(data.from_ffi_handle().species().clone().into())
) -> IdentifiablePointer<Arc<dyn SpeciesLibrary>> {
data.as_mut().species().clone().into()
} }
/// All data for the moves. /// All data for the moves.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_moves( unsafe extern "C" fn static_data_moves(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn MoveLibrary>> {
mut data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle(data.from_ffi_handle().moves().clone().into())
) -> IdentifiablePointer<Arc<dyn MoveLibrary>> {
data.as_mut().moves().clone().into()
} }
/// All data for the items. /// All data for the items.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_items( unsafe extern "C" fn static_data_items(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn ItemLibrary>> {
mut data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle((data.from_ffi_handle().items()).clone().into())
) -> IdentifiablePointer<Arc<dyn ItemLibrary>> {
(data.as_mut().items()).clone().into()
} }
/// All data for growth rates. /// All data for growth rates.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_growth_rates( unsafe extern "C" fn static_data_growth_rates(
mut data: ExternPointer<Arc<dyn StaticData>>, data: FFIHandle<Arc<dyn StaticData>>,
) -> IdentifiablePointer<Arc<dyn GrowthRateLibrary>> { ) -> FFIHandle<Arc<dyn GrowthRateLibrary>> {
data.as_mut().growth_rates().clone().into() FFIHandle::get_handle(data.from_ffi_handle().growth_rates().clone().into())
} }
/// All data related to types and type effectiveness. /// All data related to types and type effectiveness.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_types( unsafe extern "C" fn static_data_types(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn TypeLibrary>> {
mut data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle(data.from_ffi_handle().types().clone().into())
) -> IdentifiablePointer<Arc<dyn TypeLibrary>> {
data.as_mut().types().clone().into()
} }
/// All data related to natures. /// All data related to natures.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_natures( unsafe extern "C" fn static_data_natures(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn NatureLibrary>> {
data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle(data.from_ffi_handle().natures().clone().into())
) -> IdentifiablePointer<Arc<dyn NatureLibrary>> {
data.as_ref().natures().clone().into()
} }
/// All data related to abilities. /// All data related to abilities.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn static_data_abilities( unsafe extern "C" fn static_data_abilities(data: FFIHandle<Arc<dyn StaticData>>) -> FFIHandle<Arc<dyn AbilityLibrary>> {
mut data: ExternPointer<Arc<dyn StaticData>>, FFIHandle::get_handle((data.from_ffi_handle().abilities()).clone().into())
) -> IdentifiablePointer<Arc<dyn AbilityLibrary>> {
(data.as_mut().abilities()).clone().into()
} }

View File

@ -1,29 +1,24 @@
use crate::ffi::{BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{FFIResult, NonOwnedPtrString};
use crate::static_data::{TypeIdentifier, TypeLibrary, TypeLibraryImpl}; use crate::static_data::{TypeIdentifier, TypeLibrary, TypeLibraryImpl};
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place; use std::sync::Arc;
/// Instantiates a new type library with a specific capacity. /// Instantiates a new type library with a specific capacity.
#[no_mangle] #[no_mangle]
extern "C" fn type_library_new(capacity: usize) -> IdentifiablePointer<Box<dyn TypeLibrary>> { extern "C" fn type_library_new(capacity: usize) -> FFIHandle<Arc<dyn TypeLibrary>> {
let b: Box<dyn TypeLibrary> = Box::new(TypeLibraryImpl::new(capacity)); let b: Arc<dyn TypeLibrary> = Arc::new(TypeLibraryImpl::new(capacity));
b.into() FFIHandle::get_handle(b.into())
}
/// Drops a type library.
#[no_mangle]
unsafe extern "C" fn type_library_drop(ptr: OwnedPtr<Box<dyn TypeLibrary>>) {
drop_in_place(ptr);
} }
/// Gets the type identifier for a type with a name. /// Gets the type identifier for a type with a name.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn type_library_get_type_id( unsafe extern "C" fn type_library_get_type_id(
ptr: ExternPointer<Box<dyn TypeLibrary>>, ptr: FFIHandle<Arc<dyn TypeLibrary>>,
key: BorrowedPtr<c_char>, key: NonOwnedPtrString,
found: *mut bool, found: *mut bool,
) -> TypeIdentifier { ) -> TypeIdentifier {
if let Some(v) = ptr.as_ref().get_type_id(&CStr::from_ptr(key).into()) { if let Some(v) = ptr.from_ffi_handle().get_type_id(&CStr::from_ptr(key).into()) {
*found = true; *found = true;
v v
} else { } else {
@ -35,31 +30,33 @@ unsafe extern "C" fn type_library_get_type_id(
/// Gets the type name from the type identifier. /// Gets the type name from the type identifier.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn type_library_get_type_name( unsafe extern "C" fn type_library_get_type_name(
ptr: ExternPointer<Box<dyn TypeLibrary>>, ptr: FFIHandle<Arc<dyn TypeLibrary>>,
type_id: TypeIdentifier, type_id: TypeIdentifier,
found: *mut bool, found: *mut bool,
) -> NativeResult<*mut c_char> { ) -> FFIResult<*mut c_char> {
if let Some(v) = ptr.as_ref().get_type_name(type_id) { if let Some(v) = ptr.from_ffi_handle().get_type_name(type_id) {
*found = true; *found = true;
match CString::new(v.str()) { match CString::new(v.str()) {
Ok(v) => NativeResult::ok(v.into_raw()), Ok(v) => FFIResult::ok(v.into_raw()),
Err(e) => NativeResult::err(e.into()), Err(e) => FFIResult::err(e.into()),
} }
} else { } else {
*found = false; *found = false;
NativeResult::ok(std::ptr::null_mut()) FFIResult::ok(std::ptr::null_mut())
} }
} }
/// Gets the effectiveness for a single attacking type against a single defending type. /// Gets the effectiveness for a single attacking type against a single defending type.
#[no_mangle] #[no_mangle]
extern "C" fn type_library_get_single_effectiveness( extern "C" fn type_library_get_single_effectiveness(
ptr: ExternPointer<Box<dyn TypeLibrary>>, ptr: FFIHandle<Arc<dyn TypeLibrary>>,
attacking: TypeIdentifier, attacking: TypeIdentifier,
defending: TypeIdentifier, defending: TypeIdentifier,
) -> NativeResult<f32> { ) -> FFIResult<f32> {
ptr.as_ref().get_single_effectiveness(attacking, defending).into() ptr.from_ffi_handle()
.get_single_effectiveness(attacking, defending)
.into()
} }
/// Gets the effectiveness for a single attacking type against an amount of defending types. /// Gets the effectiveness for a single attacking type against an amount of defending types.
@ -67,33 +64,33 @@ extern "C" fn type_library_get_single_effectiveness(
/// and multiplying the results with each other. /// and multiplying the results with each other.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn type_library_get_effectiveness( unsafe extern "C" fn type_library_get_effectiveness(
ptr: ExternPointer<Box<dyn TypeLibrary>>, ptr: FFIHandle<Arc<dyn TypeLibrary>>,
attacking: TypeIdentifier, attacking: TypeIdentifier,
defending: OwnedPtr<TypeIdentifier>, defending: *const TypeIdentifier,
defending_length: usize, defending_length: usize,
) -> NativeResult<f32> { ) -> FFIResult<f32> {
let v = std::slice::from_raw_parts(defending, defending_length); let v = std::slice::from_raw_parts(defending, defending_length);
ptr.as_ref().get_effectiveness(attacking, v).into() ptr.from_ffi_handle().get_effectiveness(attacking, v).into()
} }
/// Registers a new type in the library. /// Registers a new type in the library.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn type_library_register_type( unsafe extern "C" fn type_library_register_type(
mut ptr: ExternPointer<Box<dyn TypeLibrary>>, ptr: FFIHandle<Arc<dyn TypeLibrary>>,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
) -> TypeIdentifier { ) -> TypeIdentifier {
ptr.as_mut().register_type(&CStr::from_ptr(name).into()) ptr.from_ffi_handle().register_type(&CStr::from_ptr(name).into())
} }
/// Sets the effectiveness for an attacking type against a defending type. /// Sets the effectiveness for an attacking type against a defending type.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn type_library_set_effectiveness( unsafe extern "C" fn type_library_set_effectiveness(
mut ptr: ExternPointer<Box<dyn TypeLibrary>>, ptr: FFIHandle<Arc<dyn TypeLibrary>>,
attacking: TypeIdentifier, attacking: TypeIdentifier,
defending: TypeIdentifier, defending: TypeIdentifier,
effectiveness: f32, effectiveness: f32,
) -> NativeResult<()> { ) -> FFIResult<()> {
ptr.as_mut() ptr.from_ffi_handle()
.set_effectiveness(attacking, defending, effectiveness) .set_effectiveness(attacking, defending, effectiveness)
.into() .into()
} }

View File

@ -1,9 +1,11 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FFIObject, FromFFIHandle};
use crate::ffi::{FFIResult, OwnedPtrString};
use crate::static_data::EffectParameter; use crate::static_data::EffectParameter;
use crate::{PkmnError, StringKey}; use crate::{PkmnError, StringKey};
use anyhow::anyhow; use anyhow::anyhow;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place; use std::ops::Deref;
use std::sync::Arc;
/// The Foreign Function Interface for abilities /// The Foreign Function Interface for abilities
mod ability; mod ability;
@ -28,94 +30,88 @@ mod statistic_set;
/// Instantiates an effect parameter with a boolean. /// Instantiates an effect parameter with a boolean.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_new_bool(value: u8) -> IdentifiablePointer<EffectParameter> { extern "C" fn effect_parameter_new_bool(value: u8) -> FFIHandle<Arc<EffectParameter>> {
Box::<EffectParameter>::new((value == 1).into()).into() FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value == 1))))
} }
/// Instantiates an effect parameter with an integer. /// Instantiates an effect parameter with an integer.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_new_int(value: i64) -> IdentifiablePointer<EffectParameter> { extern "C" fn effect_parameter_new_int(value: i64) -> FFIHandle<Arc<EffectParameter>> {
Box::<EffectParameter>::new(value.into()).into() FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value))))
} }
/// Instantiates an effect parameter with a float. /// Instantiates an effect parameter with a float.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_new_float(value: f32) -> IdentifiablePointer<EffectParameter> { extern "C" fn effect_parameter_new_float(value: f32) -> FFIHandle<Arc<EffectParameter>> {
Box::<EffectParameter>::new(value.into()).into() FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(EffectParameter::from(value))))
} }
/// Instantiates an effect parameter with a string. /// Instantiates an effect parameter with a string.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn effect_parameter_new_string( unsafe extern "C" fn effect_parameter_new_string(value: *const c_char) -> FFIResult<FFIHandle<Arc<EffectParameter>>> {
value: *const c_char,
) -> NativeResult<IdentifiablePointer<EffectParameter>> {
let sk: StringKey = match CStr::from_ptr(value).to_str() { let sk: StringKey = match CStr::from_ptr(value).to_str() {
Ok(sk) => sk.into(), Ok(sk) => sk.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
}; };
NativeResult::ok(Box::<EffectParameter>::new(sk.into()).into()) FFIResult::ok(FFIHandle::get_handle(FFIObject::EffectParameter(Arc::new(
} EffectParameter::from(sk),
))))
/// Drop an effect parameter.
#[no_mangle]
unsafe extern "C" fn effect_parameter_drop(ptr: OwnedPtr<EffectParameter>) {
drop_in_place(ptr)
} }
/// Get the type of an effect parameter. /// Get the type of an effect parameter.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_type(ptr: ExternPointer<EffectParameter>) -> u8 { extern "C" fn effect_parameter_get_type(ptr: FFIHandle<Arc<EffectParameter>>) -> u8 {
match ptr.as_ref() { match ptr.from_ffi_handle().deref() {
EffectParameter::Bool(_, _) => 0, EffectParameter::Bool(_) => 0,
EffectParameter::Int(_, _) => 1, EffectParameter::Int(_) => 1,
EffectParameter::Float(_, _) => 2, EffectParameter::Float(_) => 2,
EffectParameter::String(_, _) => 3, EffectParameter::String(_) => 3,
} }
} }
/// Get the boolean contained in the effect parameter, panics if the effect parameter is not a bool. /// Get the boolean contained in the effect parameter, panics if the effect parameter is not a bool.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_bool(ptr: ExternPointer<EffectParameter>) -> NativeResult<u8> { extern "C" fn effect_parameter_get_as_bool(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<u8> {
let p = ptr.as_ref(); let p = ptr.from_ffi_handle();
if let EffectParameter::Bool(_, b) = p { if let EffectParameter::Bool(b) = p.deref() {
NativeResult::ok(u8::from(*b)) FFIResult::ok(u8::from(*b))
} else { } else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected bool, was: {}", p))
} }
} }
/// Get the int contained in the effect parameter, panics if the effect parameter is not a int. /// Get the int contained in the effect parameter, panics if the effect parameter is not a int.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_int(ptr: ExternPointer<EffectParameter>) -> NativeResult<i64> { extern "C" fn effect_parameter_get_as_int(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<i64> {
let p = ptr.as_ref(); let p = ptr.from_ffi_handle();
if let EffectParameter::Int(_, b) = p { if let EffectParameter::Int(b) = p.deref() {
NativeResult::ok(*b) FFIResult::ok(*b)
} else { } else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected int, was: {}", p))
} }
} }
/// Get the float contained in the effect parameter, panics if the effect parameter is not a float. /// Get the float contained in the effect parameter, panics if the effect parameter is not a float.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_float(ptr: ExternPointer<EffectParameter>) -> NativeResult<f32> { extern "C" fn effect_parameter_get_as_float(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<f32> {
let p = ptr.as_ref(); let p = ptr.from_ffi_handle();
if let EffectParameter::Float(_, b) = p { if let EffectParameter::Float(b) = p.deref() {
NativeResult::ok(*b) FFIResult::ok(*b)
} else { } else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected float, was: {}", p))
} }
} }
/// Get the string contained in the effect parameter, panics if the effect parameter is not a string. /// Get the string contained in the effect parameter, panics if the effect parameter is not a string.
#[no_mangle] #[no_mangle]
extern "C" fn effect_parameter_get_as_string(ptr: ExternPointer<EffectParameter>) -> NativeResult<OwnedPtr<c_char>> { extern "C" fn effect_parameter_get_as_string(ptr: FFIHandle<Arc<EffectParameter>>) -> FFIResult<OwnedPtrString> {
let p = ptr.as_ref(); let p = ptr.from_ffi_handle();
if let EffectParameter::String(_, b) = p { if let EffectParameter::String(b) = p.deref() {
match CString::new(b.str().to_string()) { match CString::new(b.str().to_string()) {
Ok(cstr) => NativeResult::ok(cstr.into_raw()), Ok(cstr) => FFIResult::ok(cstr.into_raw()),
Err(_) => NativeResult::err(PkmnError::InvalidCString.into()), Err(_) => FFIResult::err(PkmnError::InvalidCString.into()),
} }
} else { } else {
NativeResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p)) FFIResult::err(anyhow!("Unexpected effect parameter. Expected string, was: {}", p))
} }
} }

View File

@ -1,4 +1,5 @@
use crate::ffi::{ffi_arc_dyn_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::ffi::{ffi_handle_arc_dyn_getter, ExternPointer, FFIResult, NonOwnedPtrString, OwnedPtrString};
use crate::static_data::{ use crate::static_data::{
EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl, EffectParameter, MoveCategory, MoveData, MoveDataImpl, MoveTarget, SecondaryEffect, SecondaryEffectImpl,
TypeIdentifier, TypeIdentifier,
@ -7,7 +8,6 @@ use crate::StringKey;
use anyhow::anyhow; use anyhow::anyhow;
use hashbrown::HashSet; use hashbrown::HashSet;
use std::ffi::{c_char, CStr, CString}; use std::ffi::{c_char, CStr, CString};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new move. /// Instantiates a new move.
@ -21,27 +21,27 @@ unsafe extern "C" fn move_data_new(
base_usages: u8, base_usages: u8,
target: MoveTarget, target: MoveTarget,
priority: i8, priority: i8,
secondary_effect: *mut Box<dyn SecondaryEffect>, secondary_effect: FFIHandle<Arc<dyn SecondaryEffect>>,
flags: *const *const c_char, flags: *const *const c_char,
flags_length: usize, flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn MoveData>>> { ) -> FFIResult<FFIHandle<Arc<dyn MoveData>>> {
let flags = std::slice::from_raw_parts(flags, flags_length); let flags = std::slice::from_raw_parts(flags, flags_length);
let name: StringKey = match CStr::from_ptr(name).to_str() { let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(), Ok(name) => name.into(),
Err(_) => return NativeResult::err_from_str("Unable to convert name to string"), Err(_) => return FFIResult::err_from_str("Unable to convert name to string"),
}; };
let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length); let mut flags_set: HashSet<StringKey> = HashSet::with_capacity(flags_length);
for flag in flags { for flag in flags {
let flag = match CStr::from_ptr(*flag).to_str() { let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag, Ok(flag) => flag,
Err(_) => return NativeResult::err_from_str("Unable to convert flag to string"), Err(_) => return FFIResult::err_from_str("Unable to convert flag to string"),
}; };
flags_set.insert(flag.into()); flags_set.insert(flag.into());
} }
let secondary_effect = if secondary_effect.is_null() { let secondary_effect = if secondary_effect.is_none() {
None None
} else { } else {
Some(*Box::from_raw(secondary_effect)) Some(secondary_effect.from_ffi_handle())
}; };
let a: Arc<dyn MoveData> = Arc::new(MoveDataImpl::new( let a: Arc<dyn MoveData> = Arc::new(MoveDataImpl::new(
&name, &name,
@ -55,39 +55,37 @@ unsafe extern "C" fn move_data_new(
secondary_effect, secondary_effect,
flags_set, flags_set,
)); ));
NativeResult::ok(a.into()) FFIResult::ok(FFIHandle::get_handle(a.into()))
}
/// Drops a reference counted move.
#[no_mangle]
unsafe extern "C" fn move_data_drop(ptr: OwnedPtr<Arc<dyn MoveData>>) {
drop_in_place(ptr)
} }
/// The name of the move. /// The name of the move.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn move_data_name(ptr: ExternPointer<Arc<dyn MoveData>>) -> NativeResult<OwnedPtr<c_char>> { unsafe extern "C" fn move_data_name(ptr: FFIHandle<Arc<dyn MoveData>>) -> FFIResult<OwnedPtrString> {
let name = ptr.as_ref().name(); let move_data = ptr.from_ffi_handle();
let name = move_data.name();
match CString::new(name.str()) { match CString::new(name.str()) {
Ok(name) => NativeResult::ok(name.into_raw()), Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => NativeResult::err_from_str("Unable to convert name to string"), Err(_) => FFIResult::err_from_str("Unable to convert name to string"),
} }
} }
ffi_arc_dyn_getter!(MoveData, move_type, TypeIdentifier); ffi_handle_arc_dyn_getter!(MoveData, move_type, TypeIdentifier);
ffi_arc_dyn_getter!(MoveData, category, MoveCategory); ffi_handle_arc_dyn_getter!(MoveData, category, MoveCategory);
ffi_arc_dyn_getter!(MoveData, base_power, u8); ffi_handle_arc_dyn_getter!(MoveData, base_power, u8);
ffi_arc_dyn_getter!(MoveData, accuracy, u8); ffi_handle_arc_dyn_getter!(MoveData, accuracy, u8);
ffi_arc_dyn_getter!(MoveData, base_usages, u8); ffi_handle_arc_dyn_getter!(MoveData, base_usages, u8);
ffi_arc_dyn_getter!(MoveData, target, MoveTarget); ffi_handle_arc_dyn_getter!(MoveData, target, MoveTarget);
ffi_arc_dyn_getter!(MoveData, priority, i8); ffi_handle_arc_dyn_getter!(MoveData, priority, i8);
/// The optional secondary effect the move has. /// The optional secondary effect the move has.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn move_data_secondary_effect( unsafe extern "C" fn move_data_secondary_effect(
ptr: ExternPointer<Arc<dyn MoveData>>, ptr: FFIHandle<Arc<dyn MoveData>>,
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> { ) -> FFIHandle<Arc<dyn SecondaryEffect>> {
ptr.as_ref().secondary_effect().into() match ptr.from_ffi_handle().secondary_effect() {
Some(secondary_effect) => FFIHandle::get_handle(secondary_effect.clone().into()),
None => FFIHandle::none(),
}
} }
/// Arbitrary flags that can be applied to the move. /// Arbitrary flags that can be applied to the move.
@ -101,28 +99,22 @@ unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer<Arc<dyn MoveData>>, f
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_new( unsafe extern "C" fn secondary_effect_new(
chance: f32, chance: f32,
effect_name: BorrowedPtr<c_char>, effect_name: NonOwnedPtrString,
parameters: *mut OwnedPtr<Arc<EffectParameter>>, parameters: *mut FFIHandle<Arc<EffectParameter>>,
parameters_length: usize, parameters_length: usize,
) -> IdentifiablePointer<Box<dyn SecondaryEffect>> { ) -> FFIHandle<Box<dyn SecondaryEffect>> {
let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length); let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length);
let mut parameters = Vec::with_capacity(parameters_length); let mut parameters = Vec::with_capacity(parameters_length);
for parameter in parameter_slice { for parameter in parameter_slice {
parameters.push(*Box::from_raw(*parameter)) parameters.push(parameter.from_ffi_handle())
} }
let b: Box<dyn SecondaryEffect> = Box::new(SecondaryEffectImpl::new( let b: Arc<dyn SecondaryEffect> = Arc::new(SecondaryEffectImpl::new(
chance, chance,
CStr::from_ptr(effect_name).into(), CStr::from_ptr(effect_name).into(),
parameters, parameters,
)); ));
b.into() FFIHandle::get_handle(b.into())
}
/// Drop a secondary effect.
#[no_mangle]
unsafe extern "C" fn secondary_effect_drop(ptr: OwnedPtr<Box<dyn SecondaryEffect>>) {
drop_in_place(ptr)
} }
/// The chance the effect triggers. /// The chance the effect triggers.
@ -135,10 +127,10 @@ unsafe extern "C" fn secondary_effect_chance(ptr: ExternPointer<Box<dyn Secondar
#[no_mangle] #[no_mangle]
unsafe extern "C" fn secondary_effect_effect_name( unsafe extern "C" fn secondary_effect_effect_name(
ptr: ExternPointer<Box<dyn SecondaryEffect>>, ptr: ExternPointer<Box<dyn SecondaryEffect>>,
) -> NativeResult<OwnedPtr<c_char>> { ) -> FFIResult<OwnedPtrString> {
match CString::new(ptr.as_ref().effect_name().str()) { match CString::new(ptr.as_ref().effect_name().str()) {
Ok(name) => NativeResult::ok(name.into_raw()), Ok(name) => FFIResult::ok(name.into_raw()),
Err(_) => NativeResult::err(anyhow!( Err(_) => FFIResult::err(anyhow!(
"Unable to convert effect name '{}' to CString", "Unable to convert effect name '{}' to CString",
ptr.as_ref().effect_name() ptr.as_ref().effect_name()
)), )),
@ -156,10 +148,10 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer<Box<dy
unsafe extern "C" fn secondary_effect_parameter_get( unsafe extern "C" fn secondary_effect_parameter_get(
ptr: ExternPointer<Box<dyn SecondaryEffect>>, ptr: ExternPointer<Box<dyn SecondaryEffect>>,
index: usize, index: usize,
) -> IdentifiablePointer<Arc<EffectParameter>> { ) -> FFIHandle<Arc<EffectParameter>> {
if let Some(v) = ptr.as_ref().parameters().get(index) { if let Some(v) = ptr.as_ref().parameters().get(index) {
v.clone().into() FFIHandle::get_handle(v.clone().into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }

View File

@ -1,6 +1,5 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::ffi::ffi_handle::{FFIHandle, FromFFIHandle};
use crate::static_data::{Nature, NatureImpl, Statistic}; use crate::static_data::{Nature, NatureImpl, Statistic};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Instantiates a new statistic. /// Instantiates a new statistic.
@ -10,32 +9,26 @@ extern "C" fn nature_new(
decrease_stat: Statistic, decrease_stat: Statistic,
increase_modifier: f32, increase_modifier: f32,
decrease_modifier: f32, decrease_modifier: f32,
) -> IdentifiablePointer<Arc<dyn Nature>> { ) -> FFIHandle<Arc<dyn Nature>> {
let arc: Arc<dyn Nature> = NatureImpl::new(increase_stat, decrease_stat, increase_modifier, decrease_modifier); let arc: Arc<dyn Nature> = NatureImpl::new(increase_stat, decrease_stat, increase_modifier, decrease_modifier);
arc.into() FFIHandle::get_handle(arc.into())
}
/// Reduce the reference count for a nature.
#[no_mangle]
unsafe extern "C" fn nature_drop(ptr: OwnedPtr<Arc<dyn Nature>>) {
drop_in_place(ptr)
} }
/// The stat that should receive the increased modifier. /// The stat that should receive the increased modifier.
#[no_mangle] #[no_mangle]
extern "C" fn nature_increased_stat(ptr: ExternPointer<Arc<dyn Nature>>) -> Statistic { extern "C" fn nature_increased_stat(ptr: FFIHandle<Arc<dyn Nature>>) -> Statistic {
ptr.as_ref().increased_stat() ptr.from_ffi_handle().increased_stat()
} }
/// The stat that should receive the decreased modifier. /// The stat that should receive the decreased modifier.
#[no_mangle] #[no_mangle]
extern "C" fn nature_decreased_stat(ptr: ExternPointer<Arc<dyn Nature>>) -> Statistic { extern "C" fn nature_decreased_stat(ptr: FFIHandle<Arc<dyn Nature>>) -> Statistic {
ptr.as_ref().decreased_stat() ptr.from_ffi_handle().decreased_stat()
} }
/// Calculates the modifier for a given stat. If it's the increased stat, returns the increased /// Calculates the modifier for a given stat. If it's the increased stat, returns the increased
/// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0 /// modifier, if it's the decreased stat, returns the decreased modifier. Otherwise returns 1.0
#[no_mangle] #[no_mangle]
extern "C" fn nature_get_stat_modifier(ptr: ExternPointer<Arc<dyn Nature>>, stat: Statistic) -> f32 { extern "C" fn nature_get_stat_modifier(ptr: FFIHandle<Arc<dyn Nature>>, stat: Statistic) -> f32 {
ptr.as_ref().get_stat_modifier(stat) ptr.from_ffi_handle().get_stat_modifier(stat)
} }

View File

@ -1,33 +1,32 @@
use crate::ffi::ffi_handle::FFIHandle;
use crate::ffi::{ use crate::ffi::{
ffi_arc_dyn_getter, ffi_arc_stringkey_getter, BorrowedPtr, ExternPointer, IdentifiablePointer, NativeResult, ffi_handle_arc_dyn_getter, ffi_handle_arc_stringkey_getter, FFIResult, FromFFIHandle, NonOwnedPtrString,
OwnedPtr,
}; };
use crate::static_data::{Form, Gender, Species, SpeciesImpl}; use crate::static_data::{Form, Gender, Species, SpeciesImpl};
use crate::{PkmnError, Random, StringKey}; use crate::{PkmnError, Random, StringKey};
use hashbrown::HashSet; use hashbrown::HashSet;
use std::ffi::{c_char, CStr}; use std::ffi::{c_char, CStr};
use std::ptr::drop_in_place;
use std::sync::Arc; use std::sync::Arc;
/// Creates a new species. /// Creates a new species.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn species_new( unsafe extern "C" fn species_new(
id: u16, id: u16,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
gender_rate: f32, gender_rate: f32,
growth_rate: BorrowedPtr<c_char>, growth_rate: NonOwnedPtrString,
capture_rate: u8, capture_rate: u8,
default_form: OwnedPtr<Arc<dyn Form>>, default_form: FFIHandle<Arc<dyn Form>>,
flags: *const *const c_char, flags: *const *const c_char,
flags_length: usize, flags_length: usize,
) -> NativeResult<IdentifiablePointer<Arc<dyn Species>>> { ) -> FFIResult<FFIHandle<Arc<dyn Species>>> {
let name: StringKey = match CStr::from_ptr(name).to_str() { let name: StringKey = match CStr::from_ptr(name).to_str() {
Ok(name) => name.into(), Ok(name) => name.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
}; };
let growth_rate: StringKey = match CStr::from_ptr(growth_rate).to_str() { let growth_rate: StringKey = match CStr::from_ptr(growth_rate).to_str() {
Ok(growth_rate) => growth_rate.into(), Ok(growth_rate) => growth_rate.into(),
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
}; };
let flags = std::slice::from_raw_parts(flags, flags_length); let flags = std::slice::from_raw_parts(flags, flags_length);
@ -35,13 +34,14 @@ unsafe extern "C" fn species_new(
for flag in flags { for flag in flags {
let flag = match CStr::from_ptr(*flag).to_str() { let flag = match CStr::from_ptr(*flag).to_str() {
Ok(flag) => flag, Ok(flag) => flag,
Err(_) => return NativeResult::err(PkmnError::InvalidCString.into()), Err(_) => return FFIResult::err(PkmnError::InvalidCString.into()),
}; };
flags_set.insert(flag.into()); flags_set.insert(flag.into());
} }
let default_form = match default_form.as_ref() { let default_form = if default_form.is_none() {
Some(default_form) => default_form, return FFIResult::err(PkmnError::NullReference.into());
None => return NativeResult::err(PkmnError::NullReference.into()), } else {
default_form.from_ffi_handle()
}; };
let a: Arc<dyn Species> = Arc::new(SpeciesImpl::new( let a: Arc<dyn Species> = Arc::new(SpeciesImpl::new(
@ -53,53 +53,48 @@ unsafe extern "C" fn species_new(
default_form.clone(), default_form.clone(),
flags_set, flags_set,
)); ));
NativeResult::ok(a.into()) FFIResult::ok(FFIHandle::get_handle(a.into()))
} }
/// Drop a reference to the species. ffi_handle_arc_dyn_getter!(Species, id, u16);
#[no_mangle] ffi_handle_arc_stringkey_getter!(Species, name);
unsafe extern "C" fn species_drop(ptr: OwnedPtr<Arc<dyn Species>>) { ffi_handle_arc_dyn_getter!(Species, gender_rate, f32);
drop_in_place(ptr); ffi_handle_arc_stringkey_getter!(Species, growth_rate);
} ffi_handle_arc_dyn_getter!(Species, capture_rate, u8);
ffi_arc_dyn_getter!(Species, id, u16);
ffi_arc_stringkey_getter!(Species, name);
ffi_arc_dyn_getter!(Species, gender_rate, f32);
ffi_arc_stringkey_getter!(Species, growth_rate);
ffi_arc_dyn_getter!(Species, capture_rate, u8);
/// Adds a new form to the species. /// Adds a new form to the species.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn species_add_form( unsafe extern "C" fn species_add_form(
mut species: ExternPointer<Arc<dyn Species>>, species: FFIHandle<Arc<dyn Species>>,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
form: OwnedPtr<Arc<dyn Form>>, form: FFIHandle<Arc<dyn Form>>,
) -> NativeResult<()> { ) -> FFIResult<()> {
let form = match form.as_ref() { let form = if form.is_none() {
Some(form) => form.clone(), return FFIResult::err(PkmnError::NullReference.into());
None => return NativeResult::err(PkmnError::NullReference.into()), } else {
form.from_ffi_handle()
}; };
species.as_mut().add_form(CStr::from_ptr(name).into(), form); species.from_ffi_handle().add_form(CStr::from_ptr(name).into(), form);
NativeResult::ok(()) FFIResult::ok(())
} }
/// Gets a form by name. /// Gets a form by name.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn species_get_form( unsafe extern "C" fn species_get_form(
species: ExternPointer<Arc<dyn Species>>, species: FFIHandle<Arc<dyn Species>>,
name: BorrowedPtr<c_char>, name: NonOwnedPtrString,
) -> IdentifiablePointer<Arc<dyn Form>> { ) -> FFIHandle<Arc<dyn Form>> {
let form = species.as_ref().get_form(&CStr::from_ptr(name).into()); let form = species.from_ffi_handle().get_form(&CStr::from_ptr(name).into());
if let Some(form) = form { if let Some(form) = form {
form.into() FFIHandle::get_handle(form.into())
} else { } else {
IdentifiablePointer::none() FFIHandle::none()
} }
} }
/// Gets a form by name. /// Gets a form by name.
#[no_mangle] #[no_mangle]
unsafe extern "C" fn species_get_random_gender(species: ExternPointer<Arc<dyn Species>>, seed: u64) -> Gender { unsafe extern "C" fn species_get_random_gender(species: FFIHandle<Arc<dyn Species>>, seed: u64) -> Gender {
let mut rand = Random::new(seed as u128); let mut rand = Random::new(seed as u128);
species.as_ref().get_random_gender(&mut rand) species.from_ffi_handle().get_random_gender(&mut rand)
} }

View File

@ -1,6 +1,7 @@
use crate::ffi::{ExternPointer, IdentifiablePointer, OwnedPtr}; use crate::ffi::FFIHandle;
use crate::ffi::FromFFIHandle;
use crate::static_data::{StaticStatisticSet, Statistic, StatisticSet}; use crate::static_data::{StaticStatisticSet, Statistic, StatisticSet};
use std::ptr::drop_in_place; use std::sync::Arc;
/// Basic foreign function interface for a statistic set. /// Basic foreign function interface for a statistic set.
macro_rules! statistic_set { macro_rules! statistic_set {
@ -15,40 +16,35 @@ extern "C" fn [<statistic_set_ $num_type _new>](
special_attack: $num_type, special_attack: $num_type,
special_defense: $num_type, special_defense: $num_type,
speed: $num_type, speed: $num_type,
) -> IdentifiablePointer<StatisticSet<$num_type>> { ) -> FFIHandle<Arc<StatisticSet<$num_type>>> {
Box::new(StatisticSet::new( FFIHandle::get_handle(Arc::new(StatisticSet::new(
hp, hp,
attack, attack,
defense, defense,
special_attack, special_attack,
special_defense, special_defense,
speed, speed,
)).into() )).into())
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [<statistic_set_ $num_type _drop>](ptr: OwnedPtr<StatisticSet<$num_type>>) { extern "C" fn [<statistic_set_ $num_type _get_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic) -> $num_type {
drop_in_place(ptr) ptr.from_ffi_handle().get_stat(stat)
} }
#[no_mangle] #[no_mangle]
extern "C" fn [<statistic_set_ $num_type _get_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic) -> $num_type { extern "C" fn [<statistic_set_ $num_type _set_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic, value: $num_type) {
ptr.as_ref().get_stat(stat) ptr.from_ffi_handle().set_stat(stat, value)
} }
#[no_mangle] #[no_mangle]
extern "C" fn [<statistic_set_ $num_type _set_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic, value: $num_type) { extern "C" fn [<statistic_set_ $num_type _increase_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic, value: $num_type) {
ptr.as_ref().set_stat(stat, value) ptr.from_ffi_handle().increase_stat(stat, value)
} }
#[no_mangle] #[no_mangle]
extern "C" fn [<statistic_set_ $num_type _increase_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic, value: $num_type) { extern "C" fn [<statistic_set_ $num_type _decrease_stat>](ptr: FFIHandle<Arc<StatisticSet<$num_type>>>, stat: Statistic, value: $num_type) {
ptr.as_ref().increase_stat(stat, value) ptr.from_ffi_handle().decrease_stat(stat, value)
}
#[no_mangle]
extern "C" fn [<statistic_set_ $num_type _decrease_stat>](ptr: ExternPointer<StatisticSet<$num_type>>, stat: Statistic, value: $num_type) {
ptr.as_ref().decrease_stat(stat, value)
} }
} }
@ -56,11 +52,11 @@ extern "C" fn [<statistic_set_ $num_type _decrease_stat>](ptr: ExternPointer<Sta
} }
statistic_set!(u8); statistic_set!(u8);
statistic_set!(u16); // statistic_set!(u16);
statistic_set!(u32); statistic_set!(u32);
statistic_set!(i8); statistic_set!(i8);
statistic_set!(i16); // statistic_set!(i16);
statistic_set!(i32); // statistic_set!(i32);
/// Basic foreign function interface for a static statistic set. /// Basic foreign function interface for a static statistic set.
macro_rules! static_statistic_set { macro_rules! static_statistic_set {
@ -75,34 +71,29 @@ extern "C" fn [<static_statistic_set_ $num_type _new>](
special_attack: $num_type, special_attack: $num_type,
special_defense: $num_type, special_defense: $num_type,
speed: $num_type, speed: $num_type,
) -> IdentifiablePointer<StaticStatisticSet<$num_type>> { ) -> FFIHandle<Arc<StaticStatisticSet<$num_type>>> {
Box::new(StaticStatisticSet::new( FFIHandle::get_handle(Arc::new(StaticStatisticSet::new(
hp, hp,
attack, attack,
defense, defense,
special_attack, special_attack,
special_defense, special_defense,
speed, speed,
)).into() )).into())
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn [<static_statistic_set_ $num_type _drop>](ptr: OwnedPtr<StaticStatisticSet<$num_type>>) { extern "C" fn [<static_statistic_set_ $num_type _get_stat>](ptr: FFIHandle<Arc<StaticStatisticSet<$num_type>>>, stat: Statistic) -> $num_type {
drop_in_place(ptr) ptr.from_ffi_handle().get_stat(stat)
}
#[no_mangle]
extern "C" fn [<static_statistic_set_ $num_type _get_stat>](ptr: ExternPointer<StaticStatisticSet<$num_type>>, stat: Statistic) -> $num_type {
ptr.as_ref().get_stat(stat)
} }
} }
}; };
} }
static_statistic_set!(u8); // static_statistic_set!(u8);
static_statistic_set!(u16); static_statistic_set!(u16);
static_statistic_set!(u32); // static_statistic_set!(u32);
static_statistic_set!(i8); // static_statistic_set!(i8);
static_statistic_set!(i16); // static_statistic_set!(i16);
static_statistic_set!(i32); // static_statistic_set!(i32);

View File

@ -7,8 +7,9 @@
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![allow(ambiguous_glob_reexports)] #![allow(ambiguous_glob_reexports)]
#![allow(hidden_glob_reexports)] #![allow(hidden_glob_reexports)]
#![deny(missing_docs)] // Documentation linters
#![deny(clippy::missing_docs_in_private_items)] // #![deny(missing_docs)]
// #![deny(clippy::missing_docs_in_private_items)]
// Linter rules to prevent panics // Linter rules to prevent panics
// Currently still a WIP to fix all of these // Currently still a WIP to fix all of these
#![deny(clippy::unwrap_used)] #![deny(clippy::unwrap_used)]

View File

@ -146,10 +146,10 @@ fn effect_parameter_get_type(
) -> WasmResult<u8> { ) -> WasmResult<u8> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
wasm_ok(match value.deref() { wasm_ok(match value.deref() {
EffectParameter::Bool(_, _) => 1, EffectParameter::Bool(_) => 1,
EffectParameter::Int(_, _) => 2, EffectParameter::Int(_) => 2,
EffectParameter::Float(_, _) => 3, EffectParameter::Float(_) => 3,
EffectParameter::String(_, _) => 4, EffectParameter::String(_) => 4,
}) })
} }
@ -160,7 +160,7 @@ fn effect_parameter_as_bool(
) -> WasmResult<u8> { ) -> WasmResult<u8> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::Bool(_, b) => wasm_ok(<u8 as From<bool>>::from(*b)), EffectParameter::Bool(b) => wasm_ok(<u8 as From<bool>>::from(*b)),
_ => wasm_err::<u8>(anyhow!("Unexpected parameter type. Expected bool, got {}", value), &env), _ => wasm_err::<u8>(anyhow!("Unexpected parameter type. Expected bool, got {}", value), &env),
} }
} }
@ -172,7 +172,7 @@ fn effect_parameter_as_int(
) -> WasmResult<i64> { ) -> WasmResult<i64> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::Int(_, i) => wasm_ok(*i), EffectParameter::Int(i) => wasm_ok(*i),
_ => wasm_err::<i64>(anyhow!("Unexpected parameter type. Expected int, got {}", value), &env), _ => wasm_err::<i64>(anyhow!("Unexpected parameter type. Expected int, got {}", value), &env),
} }
} }
@ -184,7 +184,7 @@ fn effect_parameter_as_float(
) -> WasmResult<f32> { ) -> WasmResult<f32> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::Float(_, f) => wasm_ok(*f), EffectParameter::Float(f) => wasm_ok(*f),
_ => wasm_err::<f32>( _ => wasm_err::<f32>(
anyhow!("Unexpected parameter type. Expected float, got {}", value), anyhow!("Unexpected parameter type. Expected float, got {}", value),
&env, &env,
@ -199,7 +199,7 @@ fn effect_parameter_as_string(
) -> WasmResult<ExternRef<StringKey>> { ) -> WasmResult<ExternRef<StringKey>> {
let value = get_value_arc!(parameter, env); let value = get_value_arc!(parameter, env);
match value.deref() { match value.deref() {
EffectParameter::String(_, s) => wasm_ok(ExternRef::<StringKey>::func_new(&env, s.clone().into())), EffectParameter::String(s) => wasm_ok(ExternRef::<StringKey>::func_new(&env, s.clone().into())),
_ => wasm_err::<ExternRef<StringKey>>( _ => wasm_err::<ExternRef<StringKey>>(
anyhow!("Unexpected parameter type. Expected string, got {}", value), anyhow!("Unexpected parameter type. Expected string, got {}", value),
&env, &env,

View File

@ -1,4 +1,3 @@
use crate::ValueIdentifiable;
use anyhow_ext::Result; use anyhow_ext::Result;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::transmute; use std::mem::transmute;
@ -41,7 +40,7 @@ impl<T: ?Sized> Default for ExternRef<T> {
} }
} }
impl<T: ValueIdentifiable + ?Sized> ExternRef<T> { impl<T: ?Sized> ExternRef<T> {
/// Instantiates a new ExternRef for a bit of data. If we already have made an Extern Ref for /// Instantiates a new ExternRef for a bit of data. If we already have made an Extern Ref for
/// this data and type, we use that instead. /// this data and type, we use that instead.
pub fn new(env: &WebAssemblyEnvironmentData, value: WasmObject) -> Self { pub fn new(env: &WebAssemblyEnvironmentData, value: WasmObject) -> Self {

View File

@ -1,3 +1,4 @@
use std::any::Any;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::mem::{align_of, forget, size_of}; use std::mem::{align_of, forget, size_of};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@ -19,19 +20,17 @@ use crate::script_implementations::wasm::script_function_cache::ScriptFunctionCa
use crate::script_implementations::wasm::temp_wasm_allocator::{AllocatedObject, TempWasmAllocator}; use crate::script_implementations::wasm::temp_wasm_allocator::{AllocatedObject, TempWasmAllocator};
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities; use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
use crate::static_data::Item; use crate::static_data::Item;
use crate::{ScriptCategory, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; use crate::{ScriptCategory, StringKey, VecExt};
/// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly. /// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly.
pub struct WebAssemblyScriptResolver { pub struct WebAssemblyScriptResolver {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The global state storage of WASM. /// The global state storage of WASM.
_store: *mut Store, _store: *mut Store,
/// The WASM modules we have loaded. /// The WASM modules we have loaded.
modules: Vec<Module>, modules: RwLock<Vec<Module>>,
/// Our currently loaded WASM instances. Empty until finalize() is called, after which the loaded modules get turned /// Our currently loaded WASM instances. Empty until finalize() is called, after which the loaded modules get turned
/// into actual instances. /// into actual instances.
instances: Vec<Instance>, instances: RwLock<Vec<Instance>>,
/// This is the WASM function to load a script. /// This is the WASM function to load a script.
load_script_fn: Option<TypedFunction<(u8, ExternRef<StringKey>), u32>>, load_script_fn: Option<TypedFunction<(u8, ExternRef<StringKey>), u32>>,
@ -51,7 +50,7 @@ struct ScriptCapabilitiesKey {
impl WebAssemblyScriptResolver { impl WebAssemblyScriptResolver {
/// Instantiates a new WebAssemblyScriptResolver. /// Instantiates a new WebAssemblyScriptResolver.
pub fn new() -> Box<WebAssemblyScriptResolver> { pub fn new() -> Arc<WebAssemblyScriptResolver> {
let compiler = wasmer::LLVM::default(); let compiler = wasmer::LLVM::default();
let mut features = Features::new(); let mut features = Features::new();
features.multi_value = true; features.multi_value = true;
@ -65,7 +64,6 @@ impl WebAssemblyScriptResolver {
environment.self_arc.write().replace(Arc::downgrade(&environment)); environment.self_arc.write().replace(Arc::downgrade(&environment));
let s = Self { let s = Self {
identifier: Default::default(),
_store: store_ptr, _store: store_ptr,
modules: Default::default(), modules: Default::default(),
instances: Default::default(), instances: Default::default(),
@ -73,7 +71,7 @@ impl WebAssemblyScriptResolver {
environment_data: environment, environment_data: environment,
}; };
Box::new(s) Arc::new(s)
} }
/// Get an immutable reference to the current WASM Store. /// Get an immutable reference to the current WASM Store.
@ -93,15 +91,15 @@ impl WebAssemblyScriptResolver {
} }
/// Load a compiled WASM module. /// Load a compiled WASM module.
pub fn load_wasm_from_bytes(&mut self, bytes: &[u8]) -> Result<()> { pub fn load_wasm_from_bytes(&self, bytes: &[u8]) -> Result<()> {
// FIXME: Error handling // FIXME: Error handling
let module = Module::new(&self.store_ref(), bytes)?; let module = Module::new(&self.store_ref(), bytes)?;
self.modules.push(module); self.modules.write().push(module);
Ok(()) Ok(())
} }
/// Tells the script resolver we're done loading wasm modules, and to finalize the resolver. /// Tells the script resolver we're done loading wasm modules, and to finalize the resolver.
pub fn finalize(&mut self) -> Result<()> { pub fn finalize(&self) -> Result<()> {
let mut imports = Imports::new(); let mut imports = Imports::new();
let env = FunctionEnv::new( let env = FunctionEnv::new(
@ -109,7 +107,8 @@ impl WebAssemblyScriptResolver {
WebAssemblyEnv::new(Arc::downgrade(&self.environment_data)), WebAssemblyEnv::new(Arc::downgrade(&self.environment_data)),
); );
register_webassembly_funcs(&mut imports, &mut self.store_mut(), &env); register_webassembly_funcs(&mut imports, &mut self.store_mut(), &env);
for module in &self.modules { let modules = self.modules.read();
for module in modules.iter() {
for import in module.imports() { for import in module.imports() {
if imports.get_export("env", import.name()).is_none() { if imports.get_export("env", import.name()).is_none() {
println!( println!(
@ -143,8 +142,12 @@ impl WebAssemblyScriptResolver {
if let Some(m) = &self.environment_data.memory.read().as_ref() { if let Some(m) = &self.environment_data.memory.read().as_ref() {
m.grow(&mut self.store_mut(), 32)?; m.grow(&mut self.store_mut(), 32)?;
} }
if let Some(f) = exported_functions.get::<StringKey>(&"load_script".into()) { unsafe {
self.load_script_fn = Some(f.typed(&self.store_ref())?) #[allow(clippy::unwrap_used)] // We know this is valid.
if let Some(f) = exported_functions.get::<StringKey>(&"load_script".into()) {
let self_mut = (self as *const Self as *mut Self).as_mut().unwrap();
self_mut.load_script_fn = Some(f.typed(&self.store_ref())?)
}
} }
if let Some(f) = exported_functions.get::<StringKey>(&"allocate_mem".into()) { if let Some(f) = exported_functions.get::<StringKey>(&"allocate_mem".into()) {
let _ = self let _ = self
@ -160,7 +163,7 @@ impl WebAssemblyScriptResolver {
.write() .write()
.insert(TempWasmAllocator::new(temp_memory_slab.0, temp_memory_slab.1)); .insert(TempWasmAllocator::new(temp_memory_slab.0, temp_memory_slab.1));
} }
self.instances.push(instance); self.instances.write().push(instance);
} }
Ok(()) Ok(())
} }
@ -171,12 +174,6 @@ impl WebAssemblyScriptResolver {
} }
} }
impl ValueIdentifiable for WebAssemblyScriptResolver {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
impl ScriptResolver for WebAssemblyScriptResolver { impl ScriptResolver for WebAssemblyScriptResolver {
fn load_script( fn load_script(
&self, &self,
@ -199,6 +196,10 @@ impl ScriptResolver for WebAssemblyScriptResolver {
fn load_item_script(&self, _key: &dyn Item) -> Result<Option<Arc<dyn ItemScript>>> { fn load_item_script(&self, _key: &dyn Item) -> Result<Option<Arc<dyn ItemScript>>> {
todo!() todo!()
} }
fn as_any(&self) -> &dyn Any {
self
}
} }
impl Debug for WebAssemblyScriptResolver { impl Debug for WebAssemblyScriptResolver {

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::fmt::Debug; use std::fmt::Debug;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// An item category defines which bag slot items are stored in. /// An item category defines which bag slot items are stored in.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -47,7 +47,7 @@ pub enum BattleItemCategory {
} }
/// An item is an object which the player can pick up, keep in their Bag, and use in some manner /// An item is an object which the player can pick up, keep in their Bag, and use in some manner
pub trait Item: ValueIdentifiable + Debug + Any { pub trait Item: Debug + Any {
/// The name of the item. /// The name of the item.
fn name(&self) -> &StringKey; fn name(&self) -> &StringKey;
/// Which bag slot items are stored in. /// Which bag slot items are stored in.
@ -66,8 +66,6 @@ pub trait Item: ValueIdentifiable + Debug + Any {
/// An item is an object which the player can pick up, keep in their Bag, and use in some manner /// An item is an object which the player can pick up, keep in their Bag, and use in some manner
#[derive(Debug)] #[derive(Debug)]
pub struct ItemImpl { pub struct ItemImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The name of the item. /// The name of the item.
name: StringKey, name: StringKey,
/// Which bag slot items are stored in. /// Which bag slot items are stored in.
@ -90,7 +88,6 @@ impl ItemImpl {
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
) -> ItemImpl { ) -> ItemImpl {
ItemImpl { ItemImpl {
identifier: Default::default(),
name: name.clone(), name: name.clone(),
category, category,
battle_category, battle_category,
@ -128,12 +125,6 @@ impl Item for ItemImpl {
} }
} }
impl ValueIdentifiable for ItemImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
pub(crate) mod tests { pub(crate) mod tests {
@ -150,10 +141,5 @@ pub(crate) mod tests {
fn flags(&self) -> &HashSet<StringKey>; fn flags(&self) -> &HashSet<StringKey>;
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
} }
impl ValueIdentifiable for Item {
fn value_identifier(&self) -> ValueIdentifier {
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -5,16 +5,14 @@ use indexmap::IndexMap;
use crate::static_data::Ability; use crate::static_data::Ability;
use crate::static_data::DataLibrary; use crate::static_data::DataLibrary;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// A storage for all abilities that can be used in this data library. /// A storage for all abilities that can be used in this data library.
pub trait AbilityLibrary: DataLibrary<dyn Ability> + ValueIdentifiable + Debug {} pub trait AbilityLibrary: DataLibrary<dyn Ability> + Debug {}
/// A storage for all abilities that can be used in this data library. /// A storage for all abilities that can be used in this data library.
#[derive(Debug)] #[derive(Debug)]
pub struct AbilityLibraryImpl { pub struct AbilityLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying map for the library. /// The underlying map for the library.
map: IndexMap<StringKey, Arc<dyn Ability>>, map: IndexMap<StringKey, Arc<dyn Ability>>,
} }
@ -23,7 +21,6 @@ impl AbilityLibraryImpl {
/// Instantiates a new ability library. /// Instantiates a new ability library.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(),
map: IndexMap::with_capacity(capacity), map: IndexMap::with_capacity(capacity),
} }
} }
@ -40,12 +37,6 @@ impl DataLibrary<dyn Ability> for AbilityLibraryImpl {
} }
} }
impl ValueIdentifiable for AbilityLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -57,7 +48,7 @@ pub mod tests {
use std::sync::Arc; use std::sync::Arc;
pub fn build() -> AbilityLibraryImpl { pub fn build() -> AbilityLibraryImpl {
let mut lib = AbilityLibraryImpl::new(1); let lib = AbilityLibraryImpl::new(1);
lib.add( lib.add(
&StringKey::new("test_ability"), &StringKey::new("test_ability"),
Arc::new(AbilityImpl::new( Arc::new(AbilityImpl::new(

View File

@ -15,13 +15,17 @@ pub trait DataLibrary<T: ?Sized> {
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<T>>; fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<T>>;
/// Adds a new value to the library. /// Adds a new value to the library.
fn add(&mut self, key: &StringKey, value: Arc<T>) { fn add(&self, key: &StringKey, value: Arc<T>) {
self.get_modify().insert(key.clone(), value); #[allow(clippy::unwrap_used)] // We know this cant fail.
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut() }.unwrap();
self_mut.get_modify().insert(key.clone(), value);
} }
/// Removes a value from the library. /// Removes a value from the library.
fn remove(&mut self, key: &StringKey) { fn remove(&self, key: &StringKey) {
self.get_modify().remove(key); #[allow(clippy::unwrap_used)] // We know this cant fail.
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut() }.unwrap();
self_mut.get_modify().remove(key);
} }
/// Gets a value from the library. /// Gets a value from the library.

View File

@ -1,37 +1,36 @@
use anyhow::Result; use anyhow::Result;
use std::fmt; use std::fmt;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use hashbrown::HashMap; use hashbrown::HashMap;
use parking_lot::RwLock;
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::static_data::GrowthRate; use crate::static_data::GrowthRate;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// A library to store all growth rates. /// A library to store all growth rates.
pub trait GrowthRateLibrary: Debug + ValueIdentifiable { pub trait GrowthRateLibrary: Debug {
/// Calculates the level for a given growth key name and a certain experience. /// Calculates the level for a given growth key name and a certain experience.
fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result<LevelInt>; fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result<LevelInt>;
/// Calculates the experience for a given growth key name and a certain level. /// Calculates the experience for a given growth key name and a certain level.
fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result<u32>; fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result<u32>;
/// Adds a new growth rate with a name and value. /// Adds a new growth rate with a name and value.
fn add_growth_rate(&mut self, key: &StringKey, value: Box<dyn GrowthRate>); fn add_growth_rate(&self, key: &StringKey, value: Arc<dyn GrowthRate>);
} }
/// A library to store all growth rates. /// A library to store all growth rates.
pub struct GrowthRateLibraryImpl { pub struct GrowthRateLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying data structure. /// The underlying data structure.
growth_rates: HashMap<StringKey, Box<dyn GrowthRate>>, growth_rates: RwLock<HashMap<StringKey, Arc<dyn GrowthRate>>>,
} }
impl GrowthRateLibraryImpl { impl GrowthRateLibraryImpl {
/// Instantiates a new growth rate library with a capacity. /// Instantiates a new growth rate library with a capacity.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(), growth_rates: RwLock::new(HashMap::with_capacity(capacity)),
growth_rates: HashMap::with_capacity(capacity),
} }
} }
} }
@ -41,6 +40,7 @@ impl GrowthRateLibrary for GrowthRateLibraryImpl {
fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result<LevelInt> { fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result<LevelInt> {
Ok(self Ok(self
.growth_rates .growth_rates
.read()
.get(growth_rate) .get(growth_rate)
.ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))? .ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))?
.calculate_level(experience)) .calculate_level(experience))
@ -48,20 +48,15 @@ impl GrowthRateLibrary for GrowthRateLibraryImpl {
/// Calculates the experience for a given growth key name and a certain level. /// Calculates the experience for a given growth key name and a certain level.
fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result<u32> { fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result<u32> {
self.growth_rates self.growth_rates
.read()
.get(growth_rate) .get(growth_rate)
.ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))? .ok_or_else(|| anyhow::anyhow!("No growth rate found with key {}", growth_rate.to_string()))?
.calculate_experience(level) .calculate_experience(level)
} }
/// Adds a new growth rate with a name and value. /// Adds a new growth rate with a name and value.
fn add_growth_rate(&mut self, key: &StringKey, value: Box<dyn GrowthRate>) { fn add_growth_rate(&self, key: &StringKey, value: Arc<dyn GrowthRate>) {
self.growth_rates.insert(key.clone(), value); self.growth_rates.write().insert(key.clone(), value);
}
}
impl ValueIdentifiable for GrowthRateLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
} }
} }
@ -87,7 +82,7 @@ pub mod tests {
let w = &mut lib; let w = &mut lib;
w.add_growth_rate( w.add_growth_rate(
&"test_growthrate".into(), &"test_growthrate".into(),
Box::new(LookupGrowthRate::new(vec![0, 5, 10, 100])), Arc::new(LookupGrowthRate::new(vec![0, 5, 10, 100])),
); );
// Drops borrow as mut // Drops borrow as mut
@ -100,12 +95,7 @@ pub mod tests {
impl GrowthRateLibrary for GrowthRateLibrary { impl GrowthRateLibrary for GrowthRateLibrary {
fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result<LevelInt>; fn calculate_level(&self, growth_rate: &StringKey, experience: u32) -> Result<LevelInt>;
fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result<u32>; fn calculate_experience(&self, growth_rate: &StringKey, level: LevelInt) -> Result<u32>;
fn add_growth_rate(&mut self, key: &StringKey, value: Box<dyn GrowthRate>); fn add_growth_rate(&self, key: &StringKey, value: Arc<dyn GrowthRate>);
}
impl ValueIdentifiable for GrowthRateLibrary {
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
} }
} }

View File

@ -5,16 +5,14 @@ use indexmap::IndexMap;
use crate::static_data::DataLibrary; use crate::static_data::DataLibrary;
use crate::static_data::Item; use crate::static_data::Item;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// A library to store all items. /// A library to store all items.
pub trait ItemLibrary: DataLibrary<dyn Item> + ValueIdentifiable + Debug {} pub trait ItemLibrary: DataLibrary<dyn Item> + Debug {}
/// A library to store all items. /// A library to store all items.
#[derive(Debug)] #[derive(Debug)]
pub struct ItemLibraryImpl { pub struct ItemLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying data structure. /// The underlying data structure.
map: IndexMap<StringKey, Arc<dyn Item>>, map: IndexMap<StringKey, Arc<dyn Item>>,
} }
@ -23,7 +21,6 @@ impl ItemLibraryImpl {
/// Instantiates a new Item Library. /// Instantiates a new Item Library.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(),
map: IndexMap::with_capacity(capacity), map: IndexMap::with_capacity(capacity),
} }
} }
@ -41,12 +38,6 @@ impl DataLibrary<dyn Item> for ItemLibraryImpl {
} }
} }
impl ValueIdentifiable for ItemLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use hashbrown::HashSet; use hashbrown::HashSet;

View File

@ -1,11 +1,10 @@
use crate::defines::LevelInt; use crate::defines::LevelInt;
use crate::{ValueIdentifiable, ValueIdentifier};
use anyhow::Result; use anyhow::Result;
use anyhow_ext::ensure; use anyhow_ext::ensure;
use std::fmt::Debug; use std::fmt::Debug;
/// This library holds several misc settings for the library. /// This library holds several misc settings for the library.
pub trait LibrarySettings: Debug + ValueIdentifiable { pub trait LibrarySettings: Debug {
/// The highest level a Pokemon can be. /// The highest level a Pokemon can be.
fn maximum_level(&self) -> LevelInt; fn maximum_level(&self) -> LevelInt;
@ -17,8 +16,6 @@ pub trait LibrarySettings: Debug + ValueIdentifiable {
/// This library holds several misc settings for the library. /// This library holds several misc settings for the library.
#[derive(Debug)] #[derive(Debug)]
pub struct LibrarySettingsImpl { pub struct LibrarySettingsImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The highest level a Pokemon can be. /// The highest level a Pokemon can be.
maximum_level: LevelInt, maximum_level: LevelInt,
/// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator /// The chance of a Pokemon being shiny, as the denominator of a fraction, where the nominator
@ -36,7 +33,6 @@ impl LibrarySettingsImpl {
ensure!(shiny_rate >= 1); ensure!(shiny_rate >= 1);
ensure!(maximum_level >= 1); ensure!(maximum_level >= 1);
Ok(Self { Ok(Self {
identifier: Default::default(),
maximum_level, maximum_level,
shiny_rate, shiny_rate,
}) })
@ -51,9 +47,3 @@ impl LibrarySettings for LibrarySettingsImpl {
self.shiny_rate self.shiny_rate
} }
} }
impl ValueIdentifiable for LibrarySettingsImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@ -5,16 +5,14 @@ use indexmap::IndexMap;
use crate::static_data::DataLibrary; use crate::static_data::DataLibrary;
use crate::static_data::MoveData; use crate::static_data::MoveData;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// A library to store all data for moves. /// A library to store all data for moves.
pub trait MoveLibrary: DataLibrary<dyn MoveData> + ValueIdentifiable + Debug {} pub trait MoveLibrary: DataLibrary<dyn MoveData> + Debug {}
/// A library to store all data for moves. /// A library to store all data for moves.
#[derive(Debug)] #[derive(Debug)]
pub struct MoveLibraryImpl { pub struct MoveLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying map. /// The underlying map.
map: IndexMap<StringKey, Arc<dyn MoveData>>, map: IndexMap<StringKey, Arc<dyn MoveData>>,
} }
@ -23,7 +21,6 @@ impl MoveLibraryImpl {
/// Instantiates a new Move Library. /// Instantiates a new Move Library.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(),
map: IndexMap::with_capacity(capacity), map: IndexMap::with_capacity(capacity),
} }
} }
@ -40,12 +37,6 @@ impl DataLibrary<dyn MoveData> for MoveLibraryImpl {
} }
} }
impl ValueIdentifiable for MoveLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use hashbrown::HashSet; use hashbrown::HashSet;

View File

@ -1,15 +1,16 @@
use crate::static_data::Nature; use crate::static_data::Nature;
use crate::{Random, StringKey, ValueIdentifiable, ValueIdentifier}; use crate::{Random, StringKey};
use anyhow::bail; use anyhow::bail;
use anyhow_ext::{ensure, Result}; use anyhow_ext::{ensure, Result};
use indexmap::IndexMap; use indexmap::IndexMap;
use parking_lot::RwLock;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
/// A library of all natures that can be used, stored by their names. /// A library of all natures that can be used, stored by their names.
pub trait NatureLibrary: Debug + ValueIdentifiable { pub trait NatureLibrary: Debug {
/// Adds a new nature with name to the library. /// Adds a new nature with name to the library.
fn load_nature(&mut self, name: StringKey, nature: Arc<dyn Nature>); fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>);
/// Gets a nature by name. /// Gets a nature by name.
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>>; fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>>;
/// Gets a random nature. /// Gets a random nature.
@ -21,38 +22,35 @@ pub trait NatureLibrary: Debug + ValueIdentifiable {
/// A library of all natures that can be used, stored by their names. /// A library of all natures that can be used, stored by their names.
#[derive(Debug)] #[derive(Debug)]
pub struct NatureLibraryImpl { pub struct NatureLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying data structure. /// The underlying data structure.
map: IndexMap<StringKey, Arc<dyn Nature>>, map: RwLock<IndexMap<StringKey, Arc<dyn Nature>>>,
} }
impl NatureLibraryImpl { impl NatureLibraryImpl {
/// Creates a new nature library with a given capacity. /// Creates a new nature library with a given capacity.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(), map: RwLock::new(IndexMap::with_capacity(capacity)),
map: IndexMap::with_capacity(capacity),
} }
} }
} }
impl NatureLibrary for NatureLibraryImpl { impl NatureLibrary for NatureLibraryImpl {
/// Adds a new nature with name to the library. /// Adds a new nature with name to the library.
fn load_nature(&mut self, name: StringKey, nature: Arc<dyn Nature>) { fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>) {
self.map.insert(name, nature); self.map.write().insert(name, nature);
} }
/// Gets a nature by name. /// Gets a nature by name.
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>> { fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>> {
self.map.get(key).cloned() self.map.read().get(key).cloned()
} }
fn get_random_nature(&self, rand: &mut Random) -> Result<Arc<dyn Nature>> { fn get_random_nature(&self, rand: &mut Random) -> Result<Arc<dyn Nature>> {
ensure!(!self.map.is_empty(), "No natures were loaded into the library."); let map = self.map.read();
let i = rand.get_between(0, self.map.len() as i32); ensure!(!map.is_empty(), "No natures were loaded into the library.");
Ok(self let i = rand.get_between(0, map.len() as i32);
.map Ok(map
.get_index(i as usize) .get_index(i as usize)
// this should never happen, but we'll check anyway. // this should never happen, but we'll check anyway.
.ok_or(anyhow_ext::anyhow!("Failed to get a random nature from the library."))? .ok_or(anyhow_ext::anyhow!("Failed to get a random nature from the library."))?
@ -62,10 +60,11 @@ impl NatureLibrary for NatureLibraryImpl {
/// Finds a nature name by nature. /// Finds a nature name by nature.
fn get_nature_name(&self, nature: &Arc<dyn Nature>) -> Result<StringKey> { fn get_nature_name(&self, nature: &Arc<dyn Nature>) -> Result<StringKey> {
for kv in &self.map { let read_lock = self.map.read();
for kv in read_lock.iter() {
// As natures can't be copied, and should always be the same reference as the value // As natures can't be copied, and should always be the same reference as the value
// in the map, we just compare by reference. // in the map, we just compare by reference.
if kv.1.value_identifier() == nature.value_identifier() { if Arc::ptr_eq(&kv.1, nature) {
return Ok(kv.0.clone()); return Ok(kv.0.clone());
} }
} }
@ -73,12 +72,6 @@ impl NatureLibrary for NatureLibraryImpl {
} }
} }
impl ValueIdentifiable for NatureLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -89,7 +82,7 @@ pub mod tests {
use crate::static_data::{NatureImpl, NatureLibrary, NatureLibraryImpl}; use crate::static_data::{NatureImpl, NatureLibrary, NatureLibraryImpl};
pub fn build() -> NatureLibraryImpl { pub fn build() -> NatureLibraryImpl {
let mut lib = NatureLibraryImpl::new(2); let lib = NatureLibraryImpl::new(2);
lib.load_nature( lib.load_nature(
"test_nature".into(), "test_nature".into(),
@ -103,21 +96,16 @@ pub mod tests {
#[derive(Debug)] #[derive(Debug)]
pub NatureLibrary{} pub NatureLibrary{}
impl NatureLibrary for NatureLibrary { impl NatureLibrary for NatureLibrary {
fn load_nature(&mut self, name: StringKey, nature: Arc<dyn Nature>); fn load_nature(&self, name: StringKey, nature: Arc<dyn Nature>);
fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>>; fn get_nature(&self, key: &StringKey) -> Option<Arc<dyn Nature>>;
fn get_nature_name(&self, nature: &Arc<dyn Nature>) -> Result<StringKey>; fn get_nature_name(&self, nature: &Arc<dyn Nature>) -> Result<StringKey>;
fn get_random_nature(&self, rand: &mut Random) -> Result<Arc<dyn Nature>>; fn get_random_nature(&self, rand: &mut Random) -> Result<Arc<dyn Nature>>;
} }
impl ValueIdentifiable for NatureLibrary {
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
#[test] #[test]
fn create_nature_library_insert_and_retrieve() { fn create_nature_library_insert_and_retrieve() {
let mut lib = NatureLibraryImpl::new(2); let lib = NatureLibraryImpl::new(2);
lib.load_nature( lib.load_nature(
"foo".into(), "foo".into(),
NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
@ -135,7 +123,7 @@ pub mod tests {
#[test] #[test]
fn create_nature_library_insert_and_get_name() { fn create_nature_library_insert_and_get_name() {
let mut lib = NatureLibraryImpl::new(2); let lib = NatureLibraryImpl::new(2);
lib.load_nature( lib.load_nature(
"foo".into(), "foo".into(),
NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),
@ -155,7 +143,7 @@ pub mod tests {
#[test] #[test]
fn create_nature_library_insert_single_and_retrieve_random() { fn create_nature_library_insert_single_and_retrieve_random() {
let mut lib = NatureLibraryImpl::new(2); let lib = NatureLibraryImpl::new(2);
lib.load_nature( lib.load_nature(
"foo".into(), "foo".into(),
NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9), NatureImpl::new(Statistic::HP, Statistic::Attack, 1.1, 0.9),

View File

@ -5,16 +5,14 @@ use indexmap::IndexMap;
use crate::static_data::DataLibrary; use crate::static_data::DataLibrary;
use crate::static_data::Species; use crate::static_data::Species;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// A library to store all data for Pokemon species. /// A library to store all data for Pokemon species.
pub trait SpeciesLibrary: DataLibrary<dyn Species> + ValueIdentifiable + Debug {} pub trait SpeciesLibrary: DataLibrary<dyn Species> + Debug {}
/// A library to store all data for Pokemon species. /// A library to store all data for Pokemon species.
#[derive(Debug)] #[derive(Debug)]
pub struct SpeciesLibraryImpl { pub struct SpeciesLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying map. /// The underlying map.
map: IndexMap<StringKey, Arc<dyn Species>>, map: IndexMap<StringKey, Arc<dyn Species>>,
} }
@ -23,7 +21,6 @@ impl SpeciesLibraryImpl {
/// Instantiates a new Species Library. /// Instantiates a new Species Library.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(),
map: IndexMap::with_capacity(capacity), map: IndexMap::with_capacity(capacity),
} }
} }
@ -40,12 +37,6 @@ impl DataLibrary<dyn Species> for SpeciesLibraryImpl {
} }
} }
impl ValueIdentifiable for SpeciesLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -65,11 +56,6 @@ pub mod tests {
fn map(&self) -> &IndexMap<StringKey, Arc<dyn Species>>; fn map(&self) -> &IndexMap<StringKey, Arc<dyn Species>>;
fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<dyn Species>>; fn get_modify(&mut self) -> &mut IndexMap<StringKey, Arc<dyn Species>>;
} }
impl ValueIdentifiable for SpeciesLibrary {
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
fn build_species() -> Arc<dyn Species> { fn build_species() -> Arc<dyn Species> {
@ -85,10 +71,10 @@ pub mod tests {
0.0, 0.0,
0, 0,
Vec::new(), Vec::new(),
StaticStatisticSet::new(10, 10, 10, 10, 10, 10), Arc::new(StaticStatisticSet::new(10, 10, 10, 10, 10, 10)),
Vec::new(), Vec::new(),
Vec::new(), Vec::new(),
Box::new(LearnableMovesImpl::new(100)), Arc::new(LearnableMovesImpl::new(100)),
HashSet::new(), HashSet::new(),
)), )),
HashSet::new(), HashSet::new(),

View File

@ -6,12 +6,11 @@ use crate::static_data::MoveLibrary;
use crate::static_data::NatureLibrary; use crate::static_data::NatureLibrary;
use crate::static_data::SpeciesLibrary; use crate::static_data::SpeciesLibrary;
use crate::static_data::TypeLibrary; use crate::static_data::TypeLibrary;
use crate::{ValueIdentifiable, ValueIdentifier};
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
/// The storage for all different libraries. /// The storage for all different libraries.
pub trait StaticData: Debug + ValueIdentifiable { pub trait StaticData: Debug {
/// Several misc settings for the library. /// Several misc settings for the library.
fn settings(&self) -> &Arc<dyn LibrarySettings>; fn settings(&self) -> &Arc<dyn LibrarySettings>;
/// All data for Pokemon species. /// All data for Pokemon species.
@ -34,8 +33,6 @@ pub trait StaticData: Debug + ValueIdentifiable {
/// The storage for all different libraries. /// The storage for all different libraries.
#[derive(Debug)] #[derive(Debug)]
pub struct StaticDataImpl { pub struct StaticDataImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// Several misc settings for the library. /// Several misc settings for the library.
settings: Arc<dyn LibrarySettings>, settings: Arc<dyn LibrarySettings>,
/// All data for Pokemon species. /// All data for Pokemon species.
@ -67,7 +64,6 @@ impl StaticDataImpl {
abilities: Arc<dyn AbilityLibrary>, abilities: Arc<dyn AbilityLibrary>,
) -> Self { ) -> Self {
Self { Self {
identifier: Default::default(),
settings, settings,
species, species,
moves, moves,
@ -116,12 +112,6 @@ impl StaticData for StaticDataImpl {
} }
} }
impl ValueIdentifiable for StaticDataImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -143,16 +133,10 @@ pub mod test {
fn natures(&self) -> &Arc<dyn NatureLibrary>; fn natures(&self) -> &Arc<dyn NatureLibrary>;
fn abilities(&self) -> &Arc<dyn AbilityLibrary>; fn abilities(&self) -> &Arc<dyn AbilityLibrary>;
} }
impl ValueIdentifiable for StaticData {
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
pub fn build() -> StaticDataImpl { pub fn build() -> StaticDataImpl {
StaticDataImpl { StaticDataImpl {
identifier: Default::default(),
settings: Arc::new(LibrarySettingsImpl::new(100, 100).unwrap()), settings: Arc::new(LibrarySettingsImpl::new(100, 100).unwrap()),
species: crate::static_data::libraries::species_library::tests::build(), species: crate::static_data::libraries::species_library::tests::build(),
moves: crate::static_data::libraries::move_library::tests::build(), moves: crate::static_data::libraries::move_library::tests::build(),

View File

@ -1,9 +1,10 @@
use anyhow_ext::Result; use anyhow_ext::Result;
use atomig::Atom; use atomig::Atom;
use hashbrown::HashMap; use hashbrown::HashMap;
use parking_lot::{RwLock, RwLockReadGuard};
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use crate::{PkmnError, StringKey, ValueIdentifiable, ValueIdentifier}; use crate::{PkmnError, StringKey};
/// A unique key that can be used to store a reference to a type. Opaque reference to a byte /// A unique key that can be used to store a reference to a type. Opaque reference to a byte
/// internally. /// internally.
@ -33,7 +34,7 @@ impl Display for TypeIdentifier {
} }
/// All data related to types and effectiveness. /// All data related to types and effectiveness.
pub trait TypeLibrary: Debug + ValueIdentifiable { pub trait TypeLibrary: Debug {
/// Gets the type identifier for a type with a name. /// Gets the type identifier for a type with a name.
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier>; fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier>;
@ -49,48 +50,56 @@ pub trait TypeLibrary: Debug + ValueIdentifiable {
fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result<f32>; fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result<f32>;
/// Registers a new type in the library. /// Registers a new type in the library.
fn register_type(&mut self, name: &StringKey) -> TypeIdentifier; fn register_type(&self, name: &StringKey) -> TypeIdentifier;
/// Sets the effectiveness for an attacking type against a defending type. /// Sets the effectiveness for an attacking type against a defending type.
fn set_effectiveness( fn set_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier, effectiveness: f32)
&mut self, -> Result<()>;
attacking: TypeIdentifier,
defending: TypeIdentifier,
effectiveness: f32,
) -> Result<()>;
} }
/// All data related to types and effectiveness. /// All data related to types and effectiveness.
#[derive(Debug)] #[derive(Debug)]
pub struct TypeLibraryImpl { pub struct TypeLibraryImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// A list of types /// A list of types
types: HashMap<StringKey, TypeIdentifier>, types: RwLock<HashMap<StringKey, TypeIdentifier>>,
/// The effectiveness of the different types against each other. /// The effectiveness of the different types against each other.
effectiveness: Vec<Vec<f32>>, effectiveness: RwLock<Vec<Vec<f32>>>,
} }
impl TypeLibraryImpl { impl TypeLibraryImpl {
/// Instantiates a new type library with a specific capacity. /// Instantiates a new type library with a specific capacity.
pub fn new(capacity: usize) -> Self { pub fn new(capacity: usize) -> Self {
Self { Self {
identifier: Default::default(), types: RwLock::new(HashMap::with_capacity(capacity)),
types: HashMap::with_capacity(capacity), effectiveness: RwLock::new(vec![]),
effectiveness: vec![],
} }
} }
} }
impl TypeLibraryImpl {
fn get_single_effectiveness_with_lock(
lock: &RwLockReadGuard<Vec<Vec<f32>>>,
attacking: TypeIdentifier,
defending: TypeIdentifier,
) -> Result<f32> {
Ok(*lock
.get((attacking.val - 1) as usize)
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
.get((defending.val - 1) as usize)
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })?)
}
}
impl TypeLibrary for TypeLibraryImpl { impl TypeLibrary for TypeLibraryImpl {
/// Gets the type identifier for a type with a name. /// Gets the type identifier for a type with a name.
fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> { fn get_type_id(&self, key: &StringKey) -> Option<TypeIdentifier> {
self.types.get(key).cloned() self.types.read().get(key).cloned()
} }
/// Gets the type name from the type identifier. /// Gets the type name from the type identifier.
fn get_type_name(&self, t: TypeIdentifier) -> Option<StringKey> { fn get_type_name(&self, t: TypeIdentifier) -> Option<StringKey> {
for kv in &self.types { let types = self.types.read();
for kv in types.iter() {
if *kv.1 == t { if *kv.1 == t {
return Some(kv.0.clone()); return Some(kv.0.clone());
} }
@ -100,12 +109,7 @@ impl TypeLibrary for TypeLibraryImpl {
/// Gets the effectiveness for a single attacking type against a single defending type. /// Gets the effectiveness for a single attacking type against a single defending type.
fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> Result<f32> { fn get_single_effectiveness(&self, attacking: TypeIdentifier, defending: TypeIdentifier) -> Result<f32> {
Ok(*self Self::get_single_effectiveness_with_lock(&self.effectiveness.read(), attacking, defending)
.effectiveness
.get((attacking.val - 1) as usize)
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
.get((defending.val - 1) as usize)
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: defending })?)
} }
/// Gets the effectiveness for a single attacking type against an amount of defending types. /// Gets the effectiveness for a single attacking type against an amount of defending types.
@ -113,20 +117,24 @@ impl TypeLibrary for TypeLibraryImpl {
/// multiplying the results with each other. /// multiplying the results with each other.
fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result<f32> { fn get_effectiveness(&self, attacking: TypeIdentifier, defending: &[TypeIdentifier]) -> Result<f32> {
let mut e = 1.0; let mut e = 1.0;
let lock = self.effectiveness.read();
for def in defending { for def in defending {
e *= self.get_single_effectiveness(attacking, *def)?; e *= Self::get_single_effectiveness_with_lock(&lock, attacking, *def)?;
} }
Ok(e) Ok(e)
} }
/// Registers a new type in the library. /// Registers a new type in the library.
fn register_type(&mut self, name: &StringKey) -> TypeIdentifier { fn register_type(&self, name: &StringKey) -> TypeIdentifier {
let mut types_write_lock = self.types.write();
let mut effectiveness_write_lock = self.effectiveness.write();
let id = TypeIdentifier { let id = TypeIdentifier {
val: (self.types.len() + 1) as u8, val: (types_write_lock.len() + 1) as u8,
}; };
self.types.insert(name.clone(), id); types_write_lock.insert(name.clone(), id);
self.effectiveness.resize((id.val) as usize, vec![]); effectiveness_write_lock.resize((id.val) as usize, vec![]);
for effectiveness in &mut self.effectiveness { for effectiveness in &mut effectiveness_write_lock.iter_mut() {
effectiveness.resize((id.val) as usize, 1.0) effectiveness.resize((id.val) as usize, 1.0)
} }
id id
@ -134,13 +142,14 @@ impl TypeLibrary for TypeLibraryImpl {
/// Sets the effectiveness for an attacking type against a defending type. /// Sets the effectiveness for an attacking type against a defending type.
fn set_effectiveness( fn set_effectiveness(
&mut self, &self,
attacking: TypeIdentifier, attacking: TypeIdentifier,
defending: TypeIdentifier, defending: TypeIdentifier,
effectiveness: f32, effectiveness: f32,
) -> Result<()> { ) -> Result<()> {
*self *self
.effectiveness .effectiveness
.write()
.get_mut((attacking.val - 1) as usize) .get_mut((attacking.val - 1) as usize)
.ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })? .ok_or(PkmnError::InvalidTypeIdentifier { type_id: attacking })?
.get_mut((defending.val - 1) as usize) .get_mut((defending.val - 1) as usize)
@ -149,12 +158,6 @@ impl TypeLibrary for TypeLibraryImpl {
} }
} }
impl ValueIdentifiable for TypeLibraryImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]

View File

@ -1,4 +1,4 @@
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
#[doc(inline)] #[doc(inline)]
pub use growth_rates::*; pub use growth_rates::*;
#[doc(inline)] #[doc(inline)]
@ -56,57 +56,46 @@ mod statistics;
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub enum EffectParameter { pub enum EffectParameter {
/// A boolean value. /// A boolean value.
Bool(ValueIdentifier, bool), Bool(bool),
/// An integer value. Stored as a 64 bit int to deal with potentially large numbers. /// An integer value. Stored as a 64 bit int to deal with potentially large numbers.
Int(ValueIdentifier, i64), Int(i64),
/// A float value. Stored as a 32 bit float. /// A float value. Stored as a 32 bit float.
Float(ValueIdentifier, f32), Float(f32),
/// A string value. /// A string value.
String(ValueIdentifier, StringKey), String(StringKey),
} }
impl From<bool> for EffectParameter { impl From<bool> for EffectParameter {
fn from(b: bool) -> Self { fn from(b: bool) -> Self {
EffectParameter::Bool(Default::default(), b) EffectParameter::Bool(b)
} }
} }
impl From<i64> for EffectParameter { impl From<i64> for EffectParameter {
fn from(i: i64) -> Self { fn from(i: i64) -> Self {
EffectParameter::Int(Default::default(), i) EffectParameter::Int(i)
} }
} }
impl From<f32> for EffectParameter { impl From<f32> for EffectParameter {
fn from(f: f32) -> Self { fn from(f: f32) -> Self {
EffectParameter::Float(Default::default(), f) EffectParameter::Float(f)
} }
} }
impl From<StringKey> for EffectParameter { impl From<StringKey> for EffectParameter {
fn from(s: StringKey) -> Self { fn from(s: StringKey) -> Self {
EffectParameter::String(Default::default(), s) EffectParameter::String(s)
} }
} }
impl Display for EffectParameter { impl Display for EffectParameter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
EffectParameter::Bool(_, v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")), EffectParameter::Bool(v) => f.write_fmt(format_args!("EffectParameter::Bool({v})")),
EffectParameter::Int(_, v) => f.write_fmt(format_args!("EffectParameter::Int({v})")), EffectParameter::Int(v) => f.write_fmt(format_args!("EffectParameter::Int({v})")),
EffectParameter::Float(_, v) => f.write_fmt(format_args!("EffectParameter::Float({v})")), EffectParameter::Float(v) => f.write_fmt(format_args!("EffectParameter::Float({v})")),
EffectParameter::String(_, v) => f.write_fmt(format_args!("EffectParameter::String({v})")), EffectParameter::String(v) => f.write_fmt(format_args!("EffectParameter::String({v})")),
}
}
}
impl ValueIdentifiable for EffectParameter {
fn value_identifier(&self) -> ValueIdentifier {
match self {
EffectParameter::Bool(i, _) => *i,
EffectParameter::Int(i, _) => *i,
EffectParameter::Float(i, _) => *i,
EffectParameter::String(i, _) => *i,
} }
} }
} }

View File

@ -2,9 +2,10 @@ use hashbrown::HashSet;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc;
use crate::static_data::{SecondaryEffect, TypeIdentifier}; use crate::static_data::{SecondaryEffect, TypeIdentifier};
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
/// The move category defines what global kind of move this move is. /// The move category defines what global kind of move this move is.
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -61,7 +62,7 @@ pub enum MoveTarget {
} }
/// A move is the skill Pokémon primarily use in battle. This is the data related to that. /// A move is the skill Pokémon primarily use in battle. This is the data related to that.
pub trait MoveData: Debug + ValueIdentifiable { pub trait MoveData: Debug {
/// The name of the move. /// The name of the move.
fn name(&self) -> &StringKey; fn name(&self) -> &StringKey;
/// The attacking type of the move. /// The attacking type of the move.
@ -82,7 +83,7 @@ pub trait MoveData: Debug + ValueIdentifiable {
fn priority(&self) -> i8; fn priority(&self) -> i8;
/// The optional secondary effect the move has. /// The optional secondary effect the move has.
fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>>; fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>>;
/// Arbitrary flags that can be applied to the move. /// Arbitrary flags that can be applied to the move.
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
@ -94,8 +95,6 @@ pub trait MoveData: Debug + ValueIdentifiable {
/// A move is the skill Pokémon primarily use in battle. This is the data related to that. /// A move is the skill Pokémon primarily use in battle. This is the data related to that.
#[derive(Debug)] #[derive(Debug)]
pub struct MoveDataImpl { pub struct MoveDataImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The name of the move. /// The name of the move.
name: StringKey, name: StringKey,
/// The attacking type of the move. /// The attacking type of the move.
@ -114,7 +113,7 @@ pub struct MoveDataImpl {
/// The priority of the move. A higher priority means the move should go before other moves. /// The priority of the move. A higher priority means the move should go before other moves.
priority: i8, priority: i8,
/// The optional secondary effect the move has. /// The optional secondary effect the move has.
secondary_effect: Option<Box<dyn SecondaryEffect>>, secondary_effect: Option<Arc<dyn SecondaryEffect>>,
/// Arbitrary flags that can be applied to the move. /// Arbitrary flags that can be applied to the move.
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
} }
@ -130,11 +129,10 @@ impl MoveDataImpl {
base_usages: u8, base_usages: u8,
target: MoveTarget, target: MoveTarget,
priority: i8, priority: i8,
secondary_effect: Option<Box<dyn SecondaryEffect>>, secondary_effect: Option<Arc<dyn SecondaryEffect>>,
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
) -> Self { ) -> Self {
Self { Self {
identifier: Default::default(),
name: name.clone(), name: name.clone(),
move_type, move_type,
category, category,
@ -186,7 +184,7 @@ impl MoveData for MoveDataImpl {
} }
/// The optional secondary effect the move has. /// The optional secondary effect the move has.
fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>> { fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>> {
&self.secondary_effect &self.secondary_effect
} }
@ -201,12 +199,6 @@ impl MoveData for MoveDataImpl {
} }
} }
impl ValueIdentifiable for MoveDataImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -225,14 +217,9 @@ pub(crate) mod tests {
fn base_usages(&self) -> u8; fn base_usages(&self) -> u8;
fn target(&self) -> MoveTarget; fn target(&self) -> MoveTarget;
fn priority(&self) -> i8; fn priority(&self) -> i8;
fn secondary_effect(&self) -> &Option<Box<dyn SecondaryEffect>>; fn secondary_effect(&self) -> &Option<Arc<dyn SecondaryEffect>>;
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
fn has_flag_by_hash(&self, key_hash: u32) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool;
} }
impl ValueIdentifiable for MoveData{
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -1,10 +1,10 @@
use crate::static_data::EffectParameter; use crate::static_data::EffectParameter;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
/// A secondary effect is an effect on a move that happens after it hits. /// A secondary effect is an effect on a move that happens after it hits.
pub trait SecondaryEffect: Debug + ValueIdentifiable { pub trait SecondaryEffect: Debug {
/// The chance in percentages that the effect triggers. -1 to make it always trigger. /// The chance in percentages that the effect triggers. -1 to make it always trigger.
fn chance(&self) -> f32; fn chance(&self) -> f32;
/// The name of the effect. /// The name of the effect.
@ -16,8 +16,6 @@ pub trait SecondaryEffect: Debug + ValueIdentifiable {
/// A secondary effect is an effect on a move that happens after it hits. /// A secondary effect is an effect on a move that happens after it hits.
#[derive(Debug)] #[derive(Debug)]
pub struct SecondaryEffectImpl { pub struct SecondaryEffectImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The chance in percentages that the effect triggers. -1 to make it always trigger. /// The chance in percentages that the effect triggers. -1 to make it always trigger.
chance: f32, chance: f32,
/// The name of the effect. /// The name of the effect.
@ -30,7 +28,6 @@ impl SecondaryEffectImpl {
/// Instantiates a new Secondary Effect. /// Instantiates a new Secondary Effect.
pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self { pub fn new(chance: f32, effect_name: StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self {
Self { Self {
identifier: Default::default(),
chance, chance,
effect_name, effect_name,
parameters, parameters,
@ -53,12 +50,6 @@ impl SecondaryEffect for SecondaryEffectImpl {
} }
} }
impl ValueIdentifiable for SecondaryEffectImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -77,11 +68,6 @@ pub(crate) mod tests {
fn effect_name(&self) -> &StringKey; fn effect_name(&self) -> &StringKey;
fn parameters(&self) -> &Vec<Arc<EffectParameter>>; fn parameters(&self) -> &Vec<Arc<EffectParameter>>;
} }
impl ValueIdentifiable for SecondaryEffect{
fn value_identifier(&self) -> ValueIdentifier{
ValueIdentifier::new(0)
}
}
} }
#[test] #[test]

View File

@ -1,11 +1,10 @@
use crate::static_data::Statistic; use crate::static_data::Statistic;
use crate::{ValueIdentifiable, ValueIdentifier};
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
/// A nature is an attribute on a Pokemon that modifies the effective base stats on a Pokemon. They /// A nature is an attribute on a Pokemon that modifies the effective base stats on a Pokemon. They
/// can have an increased statistic and a decreased statistic, or be neutral. /// can have an increased statistic and a decreased statistic, or be neutral.
pub trait Nature: ValueIdentifiable + Debug { pub trait Nature: Debug {
/// The stat that should receive the increased modifier. /// The stat that should receive the increased modifier.
fn increased_stat(&self) -> Statistic; fn increased_stat(&self) -> Statistic;
@ -27,8 +26,6 @@ pub trait Nature: ValueIdentifiable + Debug {
/// can have an increased statistic and a decreased statistic, or be neutral. /// can have an increased statistic and a decreased statistic, or be neutral.
#[derive(Debug)] #[derive(Debug)]
pub struct NatureImpl { pub struct NatureImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The stat that should receive the increased modifier. /// The stat that should receive the increased modifier.
increase_stat: Statistic, increase_stat: Statistic,
/// The stat that should receive the decreased modifier. /// The stat that should receive the decreased modifier.
@ -48,7 +45,6 @@ impl NatureImpl {
decrease_modifier: f32, decrease_modifier: f32,
) -> Arc<Self> { ) -> Arc<Self> {
Arc::new(Self { Arc::new(Self {
identifier: Default::default(),
increase_stat, increase_stat,
decrease_stat, decrease_stat,
increase_modifier, increase_modifier,
@ -89,12 +85,6 @@ impl Nature for NatureImpl {
} }
} }
impl ValueIdentifiable for NatureImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -111,10 +101,5 @@ pub(crate) mod tests {
fn decreased_modifier(&self) -> f32; fn decreased_modifier(&self) -> f32;
fn get_stat_modifier(&self, stat: Statistic) -> f32; fn get_stat_modifier(&self, stat: Statistic) -> f32;
} }
impl ValueIdentifiable for Nature {
fn value_identifier(&self) -> ValueIdentifier {
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -1,10 +1,10 @@
use crate::static_data::EffectParameter; use crate::static_data::EffectParameter;
use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use crate::StringKey;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc; use std::sync::Arc;
/// An ability is a passive effect in battle that is attached to a Pokemon. /// An ability is a passive effect in battle that is attached to a Pokemon.
pub trait Ability: Debug + ValueIdentifiable { pub trait Ability: Debug {
/// The name of the ability. /// The name of the ability.
fn name(&self) -> &StringKey; fn name(&self) -> &StringKey;
/// The name of the script effect of the ability. /// The name of the script effect of the ability.
@ -16,8 +16,6 @@ pub trait Ability: Debug + ValueIdentifiable {
/// An ability is a passive effect in battle that is attached to a Pokemon. /// An ability is a passive effect in battle that is attached to a Pokemon.
#[derive(Debug)] #[derive(Debug)]
pub struct AbilityImpl { pub struct AbilityImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The name of the ability. /// The name of the ability.
name: StringKey, name: StringKey,
/// The name of the script effect of the ability. /// The name of the script effect of the ability.
@ -30,7 +28,6 @@ impl AbilityImpl {
/// Instantiates a new ability. /// Instantiates a new ability.
pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self { pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec<Arc<EffectParameter>>) -> Self {
Self { Self {
identifier: Default::default(),
name: name.clone(), name: name.clone(),
effect: effect.clone(), effect: effect.clone(),
parameters, parameters,
@ -53,12 +50,6 @@ impl Ability for AbilityImpl {
} }
} }
impl ValueIdentifiable for AbilityImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
/// An ability index allows us to find an ability on a form. It combines a bool for whether the /// An ability index allows us to find an ability on a form. It combines a bool for whether the
/// ability is hidden or not, and then an index of the ability. /// ability is hidden or not, and then an index of the ability.
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -84,10 +75,5 @@ pub(crate) mod tests {
fn effect(&self) -> &StringKey; fn effect(&self) -> &StringKey;
fn parameters(&self) -> &Vec<Arc<EffectParameter>>; fn parameters(&self) -> &Vec<Arc<EffectParameter>>;
} }
impl ValueIdentifiable for Ability {
fn value_identifier(&self) -> ValueIdentifier {
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -7,12 +7,12 @@ use crate::static_data::Statistic;
use crate::static_data::TypeIdentifier; use crate::static_data::TypeIdentifier;
use crate::static_data::{Ability, StaticStatisticSet}; use crate::static_data::{Ability, StaticStatisticSet};
use crate::static_data::{AbilityIndex, LearnableMoves}; use crate::static_data::{AbilityIndex, LearnableMoves};
use crate::{Random, ValueIdentifiable, ValueIdentifier}; use crate::Random;
use crate::{StringKey, VecExt}; use crate::{StringKey, VecExt};
/// A form is a variant of a specific species. A species always has at least one form, but can have /// A form is a variant of a specific species. A species always has at least one form, but can have
/// many more. /// many more.
pub trait Form: ValueIdentifiable + Debug { pub trait Form: Debug {
/// The name of the form. /// The name of the form.
fn name(&self) -> &StringKey; fn name(&self) -> &StringKey;
/// The height of the form in meters. /// The height of the form in meters.
@ -31,7 +31,7 @@ pub trait Form: ValueIdentifiable + Debug {
fn hidden_abilities(&self) -> &Vec<StringKey>; fn hidden_abilities(&self) -> &Vec<StringKey>;
/// The moves a Pokemon with this form can learn. /// The moves a Pokemon with this form can learn.
fn moves(&self) -> &Box<dyn LearnableMoves>; fn moves(&self) -> &Arc<dyn LearnableMoves>;
/// Arbitrary flags can be set on a form for scripting use. /// Arbitrary flags can be set on a form for scripting use.
fn flags(&self) -> &HashSet<StringKey>; fn flags(&self) -> &HashSet<StringKey>;
@ -62,8 +62,6 @@ pub trait Form: ValueIdentifiable + Debug {
/// many more. /// many more.
#[derive(Debug)] #[derive(Debug)]
pub struct FormImpl { pub struct FormImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The name of the form. /// The name of the form.
name: StringKey, name: StringKey,
/// The height of the form in meters. /// The height of the form in meters.
@ -81,7 +79,7 @@ pub struct FormImpl {
/// The possible hidden abilities a Pokemon with this form can have. /// The possible hidden abilities a Pokemon with this form can have.
hidden_abilities: Vec<StringKey>, hidden_abilities: Vec<StringKey>,
/// The moves a Pokemon with this form can learn. /// The moves a Pokemon with this form can learn.
moves: Box<dyn LearnableMoves>, moves: Arc<dyn LearnableMoves>,
/// Arbitrary flags can be set on a form for scripting use. /// Arbitrary flags can be set on a form for scripting use.
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
} }
@ -94,20 +92,19 @@ impl FormImpl {
weight: f32, weight: f32,
base_experience: u32, base_experience: u32,
types: Vec<TypeIdentifier>, types: Vec<TypeIdentifier>,
base_stats: StaticStatisticSet<u16>, base_stats: Arc<StaticStatisticSet<u16>>,
abilities: Vec<StringKey>, abilities: Vec<StringKey>,
hidden_abilities: Vec<StringKey>, hidden_abilities: Vec<StringKey>,
moves: Box<dyn LearnableMoves>, moves: Arc<dyn LearnableMoves>,
flags: HashSet<StringKey>, flags: HashSet<StringKey>,
) -> Self { ) -> Self {
Self { Self {
identifier: Default::default(),
name: name.clone(), name: name.clone(),
height, height,
weight, weight,
base_experience, base_experience,
types, types,
base_stats: Arc::new(base_stats), base_stats,
abilities, abilities,
hidden_abilities, hidden_abilities,
moves, moves,
@ -151,7 +148,7 @@ impl Form for FormImpl {
} }
/// The moves a Pokemon with this form can learn. /// The moves a Pokemon with this form can learn.
fn moves(&self) -> &Box<dyn LearnableMoves> { fn moves(&self) -> &Arc<dyn LearnableMoves> {
&self.moves &self.moves
} }
/// Arbitrary flags can be set on a form for scripting use. /// Arbitrary flags can be set on a form for scripting use.
@ -222,12 +219,6 @@ impl Form for FormImpl {
} }
} }
impl ValueIdentifiable for FormImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -246,7 +237,7 @@ pub(crate) mod tests {
fn base_stats(&self) -> &Arc<StaticStatisticSet<u16>>; fn base_stats(&self) -> &Arc<StaticStatisticSet<u16>>;
fn abilities(&self) -> &Vec<StringKey>; fn abilities(&self) -> &Vec<StringKey>;
fn hidden_abilities(&self) -> &Vec<StringKey>; fn hidden_abilities(&self) -> &Vec<StringKey>;
fn moves(&self) -> &Box<dyn LearnableMoves>; fn moves(&self) -> &Arc<dyn LearnableMoves>;
fn flags(&self) -> &HashSet<StringKey>; fn flags(&self) -> &HashSet<StringKey>;
fn get_type(&self, index: usize) -> Result<TypeIdentifier>; fn get_type(&self, index: usize) -> Result<TypeIdentifier>;
fn get_base_stat(&self, stat: Statistic) -> u16; fn get_base_stat(&self, stat: Statistic) -> u16;
@ -257,10 +248,5 @@ pub(crate) mod tests {
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
fn has_flag_by_hash(&self, key_hash: u32) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool;
} }
impl ValueIdentifiable for Form {
fn value_identifier(&self) -> ValueIdentifier {
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -1,5 +1,6 @@
use anyhow_ext::Result; use anyhow_ext::Result;
use indexmap::IndexSet; use indexmap::IndexSet;
use parking_lot::RwLock;
use std::fmt::Debug; use std::fmt::Debug;
use crate::defines::LevelInt; use crate::defines::LevelInt;
@ -8,27 +9,27 @@ use crate::{StringKey, VecExt};
/// The storage of the moves a Pokemon can learn. /// The storage of the moves a Pokemon can learn.
pub trait LearnableMoves: Debug { pub trait LearnableMoves: Debug {
/// Adds a new level move the Pokemon can learn. /// Adds a new level move the Pokemon can learn.
fn add_level_move(&mut self, level: LevelInt, m: &StringKey) -> Result<()>; fn add_level_move(&self, level: LevelInt, m: &StringKey) -> Result<()>;
/// Gets all moves a Pokemon can learn when leveling up to a specific level. /// Gets all moves a Pokemon can learn when leveling up to a specific level.
fn get_learned_by_level(&self, level: LevelInt) -> Option<&Vec<StringKey>>; fn get_learned_by_level(&self, level: LevelInt) -> Option<Vec<StringKey>>;
/// Gets the distinct moves a Pokemon can learn through leveling up. /// Gets the distinct moves a Pokemon can learn through leveling up.
fn get_distinct_level_moves(&self) -> &IndexSet<StringKey>; fn get_distinct_level_moves(&self) -> IndexSet<StringKey>;
} }
/// The storage of the moves a Pokemon can learn. /// The storage of the moves a Pokemon can learn.
#[derive(PartialEq, Eq, Debug)] #[derive(Debug)]
pub struct LearnableMovesImpl { pub struct LearnableMovesImpl {
/// A map of the moves a Pokemon can learn per level. /// A map of the moves a Pokemon can learn per level.
learned_by_level: Vec<Vec<StringKey>>, learned_by_level: RwLock<Vec<Vec<StringKey>>>,
/// A list of the distinct moves a Pokemon can learn through leveling up. /// A list of the distinct moves a Pokemon can learn through leveling up.
distinct_level_moves: IndexSet<StringKey>, distinct_level_moves: RwLock<IndexSet<StringKey>>,
} }
impl LearnableMovesImpl { impl LearnableMovesImpl {
/// Instantiates a new Learnable Moves. /// Instantiates a new Learnable Moves.
pub fn new(max_level: LevelInt) -> Self { pub fn new(max_level: LevelInt) -> Self {
Self { Self {
learned_by_level: vec![Vec::new(); (max_level + 1) as usize], learned_by_level: RwLock::new(vec![Vec::new(); (max_level + 1) as usize]),
distinct_level_moves: Default::default(), distinct_level_moves: Default::default(),
} }
} }
@ -36,20 +37,23 @@ impl LearnableMovesImpl {
impl LearnableMoves for LearnableMovesImpl { impl LearnableMoves for LearnableMovesImpl {
/// Adds a new level move the Pokemon can learn. /// Adds a new level move the Pokemon can learn.
fn add_level_move(&mut self, level: LevelInt, m: &StringKey) -> Result<()> { fn add_level_move(&self, level: LevelInt, m: &StringKey) -> Result<()> {
self.learned_by_level.get_mut_res(level as usize)?.push(m.clone()); self.learned_by_level
self.distinct_level_moves.insert(m.clone()); .write()
.get_mut_res(level as usize)?
.push(m.clone());
self.distinct_level_moves.write().insert(m.clone());
Ok(()) Ok(())
} }
/// Gets all moves a Pokemon can learn when leveling up to a specific level. /// Gets all moves a Pokemon can learn when leveling up to a specific level.
fn get_learned_by_level(&self, level: LevelInt) -> Option<&Vec<StringKey>> { fn get_learned_by_level(&self, level: LevelInt) -> Option<Vec<StringKey>> {
self.learned_by_level.get(level as usize) self.learned_by_level.read().get(level as usize).cloned()
} }
/// Gets the distinct moves a Pokemon can learn through leveling up. /// Gets the distinct moves a Pokemon can learn through leveling up.
fn get_distinct_level_moves(&self) -> &IndexSet<StringKey> { fn get_distinct_level_moves(&self) -> IndexSet<StringKey> {
&self.distinct_level_moves self.distinct_level_moves.read().clone()
} }
} }
@ -61,7 +65,7 @@ pub(crate) mod tests {
#[test] #[test]
fn adds_level_moves() { fn adds_level_moves() {
let mut moves = LearnableMovesImpl::new(100); let moves = LearnableMovesImpl::new(100);
moves.add_level_move(1, &"foo".into()).unwrap(); moves.add_level_move(1, &"foo".into()).unwrap();
moves.add_level_move(1, &"bar".into()).unwrap(); moves.add_level_move(1, &"bar".into()).unwrap();
@ -73,7 +77,7 @@ pub(crate) mod tests {
#[test] #[test]
fn adds_two_same_moves_at_different_level() { fn adds_two_same_moves_at_different_level() {
let mut moves = LearnableMovesImpl::new(100); let moves = LearnableMovesImpl::new(100);
moves.add_level_move(1, &"foo".into()).unwrap(); moves.add_level_move(1, &"foo".into()).unwrap();
moves.add_level_move(5, &"foo".into()).unwrap(); moves.add_level_move(5, &"foo".into()).unwrap();

View File

@ -8,11 +8,11 @@ use parking_lot::{RawRwLock, RwLock};
use crate::static_data::Form; use crate::static_data::Form;
use crate::static_data::Gender; use crate::static_data::Gender;
use crate::Random;
use crate::StringKey; use crate::StringKey;
use crate::{Random, ValueIdentifiable, ValueIdentifier};
/// The data belonging to a Pokemon with certain characteristics. /// The data belonging to a Pokemon with certain characteristics.
pub trait Species: ValueIdentifiable + Debug { pub trait Species: Debug {
/// The national dex identifier of the Pokemon. /// The national dex identifier of the Pokemon.
fn id(&self) -> u16; fn id(&self) -> u16;
/// The name of the Pokemon. /// The name of the Pokemon.
@ -47,8 +47,6 @@ pub trait Species: ValueIdentifiable + Debug {
/// The data belonging to a Pokemon with certain characteristics. /// The data belonging to a Pokemon with certain characteristics.
#[derive(Debug)] #[derive(Debug)]
pub struct SpeciesImpl { pub struct SpeciesImpl {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The national dex identifier of the Pokemon. /// The national dex identifier of the Pokemon.
id: u16, id: u16,
/// The name of the Pokemon. /// The name of the Pokemon.
@ -88,7 +86,6 @@ impl SpeciesImpl {
let mut forms = HashMap::with_capacity(1); let mut forms = HashMap::with_capacity(1);
forms.insert_unique_unchecked(get_default_key(), default_form); forms.insert_unique_unchecked(get_default_key(), default_form);
Self { Self {
identifier: Default::default(),
id, id,
name: name.clone(), name: name.clone(),
gender_rate, gender_rate,
@ -176,12 +173,6 @@ impl Species for SpeciesImpl {
} }
} }
impl ValueIdentifiable for SpeciesImpl {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
#[allow(clippy::indexing_slicing)] #[allow(clippy::indexing_slicing)]
#[allow(clippy::unwrap_used)] #[allow(clippy::unwrap_used)]
@ -207,10 +198,5 @@ pub(crate) mod tests {
fn has_flag(&self, key: &StringKey) -> bool; fn has_flag(&self, key: &StringKey) -> bool;
fn has_flag_by_hash(&self, key_hash: u32) -> bool; fn has_flag_by_hash(&self, key_hash: u32) -> bool;
} }
impl ValueIdentifiable for Species {
fn value_identifier(&self) -> ValueIdentifier {
ValueIdentifier::new(0)
}
}
} }
} }

View File

@ -1,6 +1,5 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use crate::{ValueIdentifiable, ValueIdentifier};
use atomig::impls::{PrimitiveAtom, PrimitiveAtomInteger}; use atomig::impls::{PrimitiveAtom, PrimitiveAtomInteger};
use atomig::{Atom, AtomInteger, Atomic}; use atomig::{Atom, AtomInteger, Atomic};
use num_traits::{clamp, NumCast, PrimInt}; use num_traits::{clamp, NumCast, PrimInt};
@ -20,8 +19,6 @@ where
<T as Atom>::Repr: PrimitiveAtomInteger, <T as Atom>::Repr: PrimitiveAtomInteger,
T: AtomInteger, T: AtomInteger,
{ {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The health point stat value. /// The health point stat value.
hp: Atomic<T>, hp: Atomic<T>,
/// The physical attack stat value. /// The physical attack stat value.
@ -47,7 +44,6 @@ where
/// Creates a new statistic set with given stats. /// Creates a new statistic set with given stats.
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
Self { Self {
identifier: Default::default(),
hp: Atomic::<T>::new(hp), hp: Atomic::<T>::new(hp),
attack: Atomic::<T>::new(attack), attack: Atomic::<T>::new(attack),
defense: Atomic::<T>::new(defense), defense: Atomic::<T>::new(defense),
@ -131,19 +127,6 @@ where
} }
} }
impl<T> ValueIdentifiable for StatisticSet<T>
where
T: PrimitiveAtom,
T: Atom,
T: PrimitiveAtomInteger,
<T as Atom>::Repr: PrimitiveAtomInteger,
T: AtomInteger,
{
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
/// A collection of statistics that can not be modified after creation. /// A collection of statistics that can not be modified after creation.
/// ///
/// As no modifications happen, this struct does not use atomics. /// As no modifications happen, this struct does not use atomics.
@ -152,8 +135,6 @@ pub struct StaticStatisticSet<T>
where where
T: PrimInt, T: PrimInt,
{ {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The health point stat value. /// The health point stat value.
hp: T, hp: T,
/// The physical attack stat value. /// The physical attack stat value.
@ -175,7 +156,6 @@ where
/// Create a new static statistic set. /// Create a new static statistic set.
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
Self { Self {
identifier: Default::default(),
hp, hp,
attack, attack,
defense, defense,
@ -223,15 +203,6 @@ where
} }
} }
impl<T> ValueIdentifiable for StaticStatisticSet<T>
where
T: PrimInt,
{
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
/// A clamped statistic set holds the 6 normal stats for a Pokemon, but ensures it always remains /// A clamped statistic set holds the 6 normal stats for a Pokemon, but ensures it always remains
/// between two values (inclusive on the two values). /// between two values (inclusive on the two values).
#[derive(Default, Debug)] #[derive(Default, Debug)]
@ -245,8 +216,6 @@ where
T: NumCast, T: NumCast,
T: PrimInt, T: PrimInt,
{ {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The health point stat value. /// The health point stat value.
hp: Atomic<T>, hp: Atomic<T>,
/// The physical attack stat value. /// The physical attack stat value.
@ -295,7 +264,6 @@ where
/// Instantiates a new clamped statistic set. /// Instantiates a new clamped statistic set.
pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self { pub fn new(hp: T, attack: T, defense: T, special_attack: T, special_defense: T, speed: T) -> Self {
Self { Self {
identifier: Default::default(),
hp: Self::clamped_cast(hp), hp: Self::clamped_cast(hp),
attack: Self::clamped_cast(attack), attack: Self::clamped_cast(attack),
defense: Self::clamped_cast(defense), defense: Self::clamped_cast(defense),
@ -409,21 +377,6 @@ where
} }
} }
impl<T, const MIN: i64, const MAX: i64> ValueIdentifiable for ClampedStatisticSet<T, MIN, MAX>
where
T: PrimitiveAtom,
T: Atom,
T: PrimitiveAtomInteger,
<T as Atom>::Repr: PrimitiveAtomInteger,
T: AtomInteger,
T: NumCast,
T: PrimInt,
{
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -3,8 +3,6 @@ pub use random::Random;
#[doc(inline)] #[doc(inline)]
pub use string_key::StringKey; pub use string_key::StringKey;
#[doc(inline)] #[doc(inline)]
pub use value_identifier::*;
#[doc(inline)]
pub use vec_ext::*; pub use vec_ext::*;
/// The random module defines a RNG implementation used in pkmn_lib /// The random module defines a RNG implementation used in pkmn_lib
@ -12,7 +10,5 @@ mod random;
/// The string_key module defines a custom string handling for reduced allocations and fast lookups /// The string_key module defines a custom string handling for reduced allocations and fast lookups
/// and equality checks. /// and equality checks.
mod string_key; mod string_key;
/// Helper tool to keep track of moving memory for FFI.
mod value_identifier;
/// Helper functions for vecs /// Helper functions for vecs
mod vec_ext; mod vec_ext;

View File

@ -1,4 +1,3 @@
use crate::{ValueIdentifiable, ValueIdentifier};
use arcstr::ArcStr; use arcstr::ArcStr;
use hashbrown::HashMap; use hashbrown::HashMap;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -126,12 +125,6 @@ impl From<&CStr> for StringKey {
} }
} }
impl ValueIdentifiable for StringKey {
fn value_identifier(&self) -> ValueIdentifier {
ValueIdentifier::new(self.hash as usize)
}
}
/// The difference in ascii characters to translate from uppercase to lowercase. /// The difference in ascii characters to translate from uppercase to lowercase.
const CAPITAL_DIFF: u8 = b'a' - b'A'; const CAPITAL_DIFF: u8 = b'a' - b'A';

View File

@ -1,33 +0,0 @@
use std::sync::atomic::{AtomicUsize, Ordering};
/// The current index for the value counter.
static CURRENT: AtomicUsize = AtomicUsize::new(1);
/// An extremely basic way to identify a piece of data.
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct ValueIdentifier(usize);
impl Default for ValueIdentifier {
fn default() -> Self {
Self(CURRENT.fetch_add(1, Ordering::SeqCst))
}
}
impl ValueIdentifier {
/// Creates an identifier by number.
pub(crate) fn new(v: usize) -> Self {
Self(v)
}
/// Get the underlying numeric integer of the value
pub fn value(&self) -> usize {
self.0
}
}
/// An object with a specific identifier.
pub trait ValueIdentifiable {
/// Get the identifier for the current object.
fn value_identifier(&self) -> ValueIdentifier;
}

View File

@ -107,7 +107,7 @@ pub fn load_types(path: &String) -> Arc<dyn TypeLibrary> {
.from_path(path.to_string() + "Types.csv") .from_path(path.to_string() + "Types.csv")
.unwrap(); .unwrap();
let mut type_library = TypeLibraryImpl::new(20); let type_library = TypeLibraryImpl::new(20);
let headers = reader.headers().unwrap(); let headers = reader.headers().unwrap();
for header in headers.iter().skip(1) { for header in headers.iter().skip(1) {
@ -135,7 +135,7 @@ pub fn load_natures(path: &String) -> Arc<dyn NatureLibrary> {
.from_path(path.to_string() + "Natures.csv") .from_path(path.to_string() + "Natures.csv")
.unwrap(); .unwrap();
let mut nature_library = NatureLibraryImpl::new(24); let nature_library = NatureLibraryImpl::new(24);
for record in reader.records() { for record in reader.records() {
let record = record.unwrap(); let record = record.unwrap();
let nature_name = record.get(0).unwrap().into(); let nature_name = record.get(0).unwrap().into();
@ -162,7 +162,7 @@ pub fn load_items(path: &String) -> Arc<dyn ItemLibrary> {
let json: Value = serde_json::from_str(&data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap();
let json_array = json.as_array().unwrap(); let json_array = json.as_array().unwrap();
let mut item_library = ItemLibraryImpl::new(400); let item_library = ItemLibraryImpl::new(400);
for v in json_array { for v in json_array {
let name = v.get("name").unwrap().as_str().unwrap().into(); let name = v.get("name").unwrap().as_str().unwrap().into();
let category = serde_json::from_value(v.get("itemType").unwrap().clone()).unwrap(); let category = serde_json::from_value(v.get("itemType").unwrap().clone()).unwrap();
@ -194,7 +194,7 @@ pub fn load_growth_rates(path: &String) -> Arc<dyn GrowthRateLibrary> {
let json: Value = serde_json::from_str(&data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap();
let o = json.as_object().unwrap(); let o = json.as_object().unwrap();
let mut growth_rate_library = GrowthRateLibraryImpl::new(10); let growth_rate_library = GrowthRateLibraryImpl::new(10);
for (key, value) in o { for (key, value) in o {
let name = StringKey::new(key); let name = StringKey::new(key);
let experience_required_json = value.as_array().unwrap(); let experience_required_json = value.as_array().unwrap();
@ -203,7 +203,7 @@ pub fn load_growth_rates(path: &String) -> Arc<dyn GrowthRateLibrary> {
experience_required.push(v.as_i64().unwrap() as u32); experience_required.push(v.as_i64().unwrap() as u32);
} }
growth_rate_library.add_growth_rate(&name, Box::new(LookupGrowthRate::new(experience_required))); growth_rate_library.add_growth_rate(&name, Arc::new(LookupGrowthRate::new(experience_required)));
} }
Arc::new(growth_rate_library) Arc::new(growth_rate_library)
} }
@ -215,7 +215,7 @@ pub fn load_abilities(path: &String) -> Arc<dyn AbilityLibrary> {
let json: Value = serde_json::from_str(&data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap();
let o = json.as_object().unwrap(); let o = json.as_object().unwrap();
let mut ability_library = AbilityLibraryImpl::new(400); let ability_library = AbilityLibraryImpl::new(400);
for (key, value) in o { for (key, value) in o {
let name = StringKey::new(key); let name = StringKey::new(key);
let mut effect = StringKey::empty(); let mut effect = StringKey::empty();
@ -240,7 +240,7 @@ pub fn load_moves(path: &String, types: &Arc<dyn TypeLibrary>) -> Arc<dyn MoveLi
file.read_to_string(&mut data).unwrap(); file.read_to_string(&mut data).unwrap();
let json: Value = serde_json::from_str(&data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap();
let data = json.as_object().unwrap().get("data").unwrap().as_array().unwrap(); let data = json.as_object().unwrap().get("data").unwrap().as_array().unwrap();
let mut move_library = MoveLibraryImpl::new(600); let move_library = MoveLibraryImpl::new(600);
for move_data in data { for move_data in data {
let move_data = move_data.as_object().unwrap(); let move_data = move_data.as_object().unwrap();
let move_name = move_data.get("name").unwrap().as_str().unwrap().into(); let move_name = move_data.get("name").unwrap().as_str().unwrap().into();
@ -252,7 +252,7 @@ pub fn load_moves(path: &String, types: &Arc<dyn TypeLibrary>) -> Arc<dyn MoveLi
let pp = move_data.get("pp").unwrap().as_i64().unwrap() as u8; let pp = move_data.get("pp").unwrap().as_i64().unwrap() as u8;
let target = serde_json::from_value(move_data.get("target").unwrap().clone()).unwrap(); let target = serde_json::from_value(move_data.get("target").unwrap().clone()).unwrap();
let priority = move_data.get("priority").unwrap().as_i64().unwrap() as i8; let priority = move_data.get("priority").unwrap().as_i64().unwrap() as i8;
let secondary_effect: Option<Box<dyn SecondaryEffect>> = if let Some(v) = move_data.get("effect") { let secondary_effect: Option<Arc<dyn SecondaryEffect>> = if let Some(v) = move_data.get("effect") {
let mut chance = -1.0; let mut chance = -1.0;
if let Some(chance_value) = v.get("chance") { if let Some(chance_value) = v.get("chance") {
chance = chance_value.as_f64().unwrap() as f32; chance = chance_value.as_f64().unwrap() as f32;
@ -265,7 +265,7 @@ pub fn load_moves(path: &String, types: &Arc<dyn TypeLibrary>) -> Arc<dyn MoveLi
} }
} }
Some(Box::new(SecondaryEffectImpl::new( Some(Arc::new(SecondaryEffectImpl::new(
chance, chance,
v.get("name").unwrap().as_str().unwrap().into(), v.get("name").unwrap().as_str().unwrap().into(),
parameters, parameters,
@ -312,7 +312,7 @@ pub fn load_species(
let json: Value = serde_json::from_str(&data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap();
let o = json.as_object().unwrap(); let o = json.as_object().unwrap();
let mut species_library = SpeciesLibraryImpl::new(800); let species_library = SpeciesLibraryImpl::new(800);
for (key, value) in o.iter() { for (key, value) in o.iter() {
if key.starts_with('$') { if key.starts_with('$') {
continue; continue;
@ -353,13 +353,13 @@ pub fn load_species(
} }
#[cfg(not(feature = "wasm"))] #[cfg(not(feature = "wasm"))]
fn load_script_resolver(path: &String) -> Box<dyn ScriptResolver> { fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
Box::new(EmptyScriptResolver::default()) Arc::new(EmptyScriptResolver::default())
} }
#[cfg(feature = "wasm")] #[cfg(feature = "wasm")]
fn load_script_resolver(path: &String) -> Box<dyn ScriptResolver> { fn load_script_resolver(path: &String) -> Arc<dyn ScriptResolver> {
let mut resolver = pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver::new(); let resolver = pkmn_lib::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver::new();
let file = File::open(path.to_string() + "gen7_scripts.wasm").unwrap(); let file = File::open(path.to_string() + "gen7_scripts.wasm").unwrap();
let mut reader = BufReader::new(file); let mut reader = BufReader::new(file);
let mut buffer = Vec::new(); let mut buffer = Vec::new();
@ -413,12 +413,12 @@ fn parse_form(
)) ))
} }
fn parse_statistics<T>(value: &Value) -> StaticStatisticSet<T> fn parse_statistics<T>(value: &Value) -> Arc<StaticStatisticSet<T>>
where where
T: PrimInt + TryFrom<u64>, T: PrimInt + TryFrom<u64>,
<T as TryFrom<u64>>::Error: Debug, <T as TryFrom<u64>>::Error: Debug,
{ {
StaticStatisticSet::new( Arc::new(StaticStatisticSet::new(
<T as TryFrom<u64>>::try_from(value.get("hp").unwrap_or(&Value::Number(0.into())).as_u64().unwrap()).unwrap(), <T as TryFrom<u64>>::try_from(value.get("hp").unwrap_or(&Value::Number(0.into())).as_u64().unwrap()).unwrap(),
<T as TryFrom<u64>>::try_from( <T as TryFrom<u64>>::try_from(
value value
@ -454,11 +454,11 @@ where
.unwrap(), .unwrap(),
<T as TryFrom<u64>>::try_from(value.get("speed").unwrap_or(&Value::Number(0.into())).as_u64().unwrap()) <T as TryFrom<u64>>::try_from(value.get("speed").unwrap_or(&Value::Number(0.into())).as_u64().unwrap())
.unwrap(), .unwrap(),
) ))
} }
fn parse_moves(value: &Value, move_library: &Arc<dyn MoveLibrary>) -> Box<dyn LearnableMoves> { fn parse_moves(value: &Value, move_library: &Arc<dyn MoveLibrary>) -> Arc<dyn LearnableMoves> {
let mut moves = LearnableMovesImpl::new(100); let moves = LearnableMovesImpl::new(100);
let level_moves = value.get("levelMoves").unwrap().as_array().unwrap(); let level_moves = value.get("levelMoves").unwrap().as_array().unwrap();
for level_move in level_moves { for level_move in level_moves {
@ -468,7 +468,7 @@ fn parse_moves(value: &Value, move_library: &Arc<dyn MoveLibrary>) -> Box<dyn Le
moves.add_level_move(level, &name).unwrap(); moves.add_level_move(level, &name).unwrap();
} }
Box::new(moves) Arc::new(moves)
} }
fn parse_effect_parameter(value: &Value) -> Arc<EffectParameter> { fn parse_effect_parameter(value: &Value) -> Arc<EffectParameter> {

View File

@ -1,4 +1,5 @@
use serde::Deserialize; use serde::Deserialize;
use std::sync::Arc;
use pkmn_lib::dynamic_data::Battle; use pkmn_lib::dynamic_data::Battle;
use pkmn_lib::dynamic_data::{MoveChoice, PassChoice, TurnChoice}; use pkmn_lib::dynamic_data::{MoveChoice, PassChoice, TurnChoice};
@ -56,12 +57,12 @@ impl TestStep {
assert!(used_move.is_some()); assert!(used_move.is_some());
assert!(battle assert!(battle
.try_set_choice(TurnChoice::Move(MoveChoice::new( .try_set_choice(Arc::new(TurnChoice::Move(MoveChoice::new(
pokemon, pokemon,
used_move.unwrap(), used_move.unwrap(),
target[0], target[0],
target[1], target[1],
))) ))))
.unwrap()); .unwrap());
} }
TestStep::SetPassChoice { for_pokemon } => { TestStep::SetPassChoice { for_pokemon } => {
@ -69,7 +70,9 @@ impl TestStep {
.as_ref() .as_ref()
.unwrap() .unwrap()
.clone(); .clone();
assert!(battle.try_set_choice(TurnChoice::Pass(PassChoice::new(p))).unwrap()); assert!(battle
.try_set_choice(Arc::new(TurnChoice::Pass(PassChoice::new(p))))
.unwrap());
} }
TestStep::Assert { value, expected } => { TestStep::Assert { value, expected } => {
let v = value.get(battle); let v = value.get(battle);

View File

@ -1,7 +1,8 @@
#![feature(custom_test_frameworks)] #![feature(custom_test_frameworks)]
#![feature(lazy_cell)]
#![allow(clippy::borrowed_box)] #![allow(clippy::borrowed_box)]
use std::sync::Arc; use std::sync::{Arc, LazyLock};
use pkmn_lib::dynamic_data::{ use pkmn_lib::dynamic_data::{
Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty, Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty,
@ -13,8 +14,10 @@ use crate::common::library_loader;
pub mod common; pub mod common;
pub mod datatests; pub mod datatests;
static LIBRARY: LazyLock<Arc<dyn DynamicLibrary>> = LazyLock::new(|| library_loader::load_library().library);
fn get_library() -> Arc<dyn DynamicLibrary> { fn get_library() -> Arc<dyn DynamicLibrary> {
library_loader::load_library().library LIBRARY.clone()
} }
#[test] #[test]