From a840605bf7239633a1956cfb6e8bc71303b357e2 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 14 Oct 2022 10:33:19 +0200 Subject: [PATCH] FFI for dynamic libraries --- .../libraries/battle_stat_calculator.rs | 21 +++++++++- src/dynamic_data/libraries/damage_library.rs | 17 ++++++-- src/dynamic_data/libraries/dynamic_library.rs | 18 ++++++-- src/dynamic_data/libraries/misc_library.rs | 17 ++++++-- src/dynamic_data/libraries/script_resolver.rs | 15 +++++-- .../libraries/battle_stat_calculator.rs | 10 +++++ .../dynamic_data/libraries/damage_library.rs | 10 +++++ .../dynamic_data/libraries/dynamic_library.rs | 23 +++++++++++ .../dynamic_data/libraries/misc_library.rs | 10 +++++ src/ffi/dynamic_data/libraries/mod.rs | 5 +++ .../dynamic_data/libraries/script_resolver.rs | 41 +++++++++++++++++++ src/ffi/dynamic_data/mod.rs | 1 + src/ffi/mod.rs | 7 ++++ .../wasm/script_resolver.rs | 11 ++++- tests/common/library_loader.rs | 2 +- 15 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 src/ffi/dynamic_data/libraries/battle_stat_calculator.rs create mode 100644 src/ffi/dynamic_data/libraries/damage_library.rs create mode 100644 src/ffi/dynamic_data/libraries/dynamic_library.rs create mode 100644 src/ffi/dynamic_data/libraries/misc_library.rs create mode 100644 src/ffi/dynamic_data/libraries/mod.rs create mode 100644 src/ffi/dynamic_data/libraries/script_resolver.rs create mode 100644 src/ffi/dynamic_data/mod.rs diff --git a/src/dynamic_data/libraries/battle_stat_calculator.rs b/src/dynamic_data/libraries/battle_stat_calculator.rs index b058af0..3ff69ab 100755 --- a/src/dynamic_data/libraries/battle_stat_calculator.rs +++ b/src/dynamic_data/libraries/battle_stat_calculator.rs @@ -3,9 +3,10 @@ use std::fmt::Debug; use crate::dynamic_data::Pokemon; use crate::static_data::Statistic; use crate::static_data::StatisticSet; +use crate::{ValueIdentifiable, ValueIdentifier}; /// A battle stat calculator is used to calculate stats for a Pokemon. -pub trait BattleStatCalculator: Debug { +pub trait BattleStatCalculator: Debug + ValueIdentifiable { /// Calculate all the flat stats of a Pokemon, disregarding stat boosts. fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet); /// Calculate a single flat stat of a Pokemon, disregarding stat boost @@ -18,9 +19,19 @@ pub trait BattleStatCalculator: Debug { /// A basic implementation of the Gen 7 stat calculator. #[derive(Debug)] -pub struct Gen7BattleStatCalculator {} +pub struct Gen7BattleStatCalculator { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, +} impl Gen7BattleStatCalculator { + /// Creates a new Gen 7 battle stat calculator + pub fn new() -> Self { + Self { + identifier: Default::default(), + } + } + /// The calculation used for health points. fn calculate_health_stat(&self, pokemon: &Pokemon) -> u32 { let base = pokemon.form().get_base_stat(Statistic::HP) as u32; @@ -114,3 +125,9 @@ impl BattleStatCalculator for Gen7BattleStatCalculator { (self.calculate_flat_stat(pokemon, stat) as f32 * self.get_stat_boost_modifier(pokemon, stat)) as u32 } } + +impl ValueIdentifiable for Gen7BattleStatCalculator { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/dynamic_data/libraries/damage_library.rs b/src/dynamic_data/libraries/damage_library.rs index dc672bd..0e7e8fe 100755 --- a/src/dynamic_data/libraries/damage_library.rs +++ b/src/dynamic_data/libraries/damage_library.rs @@ -3,12 +3,12 @@ use std::sync::Arc; use crate::dynamic_data::script_handling::ScriptSource; use crate::dynamic_data::{Battle, Pokemon}; use crate::dynamic_data::{ExecutingMove, HitData}; -use crate::script_hook; 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 /// different generations and implementations, this is handled through a trait. -pub trait DamageLibrary: std::fmt::Debug { +pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { /// Calculate the damage for a given hit on a Pokemon. fn get_damage( &self, @@ -40,6 +40,8 @@ pub trait DamageLibrary: std::fmt::Debug { /// The implementation of a Damage Library for generation 7. #[derive(Debug)] 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). has_randomness: bool, } @@ -48,7 +50,10 @@ impl Gen7DamageLibrary { /// 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. pub fn new(has_randomness: bool) -> Self { - Self { has_randomness } + Self { + identifier: Default::default(), + has_randomness, + } } /// Calculates the modifier applied to damage from the statistics of the relevant Pokemon. @@ -303,3 +308,9 @@ impl DamageLibrary for Gen7DamageLibrary { } } } + +impl ValueIdentifiable for Gen7DamageLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/dynamic_data/libraries/dynamic_library.rs b/src/dynamic_data/libraries/dynamic_library.rs index 70219d2..2b6b18e 100755 --- a/src/dynamic_data/libraries/dynamic_library.rs +++ b/src/dynamic_data/libraries/dynamic_library.rs @@ -9,13 +9,15 @@ use crate::dynamic_data::{ItemScript, ScriptResolver}; use crate::dynamic_data::{Script, ScriptOwnerData}; use crate::static_data::Item; use crate::static_data::StaticData; -use crate::{PkmnResult, StringKey}; +use crate::{PkmnResult, StringKey, ValueIdentifiable, ValueIdentifier}; /// 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. #[derive(Debug)] #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct DynamicLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The static data is the immutable storage data for this library. static_data: StaticData, /// The stat calculator deals with the calculation of flat and boosted stats, based on the @@ -44,6 +46,7 @@ impl DynamicLibrary { script_resolver: Box, ) -> Self { Self { + identifier: Default::default(), static_data, stat_calculator, damage_calculator, @@ -89,6 +92,12 @@ impl DynamicLibrary { } } +impl ValueIdentifiable for DynamicLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + #[cfg(test)] pub mod test { use crate::dynamic_data::libraries::battle_stat_calculator::Gen7BattleStatCalculator; @@ -99,11 +108,14 @@ pub mod test { pub fn build() -> DynamicLibrary { DynamicLibrary { + identifier: Default::default(), static_data: crate::static_data::libraries::static_data::test::build(), - stat_calculator: Box::new(Gen7BattleStatCalculator {}), + stat_calculator: Box::new(Gen7BattleStatCalculator::new()), damage_calculator: Box::new(Gen7DamageLibrary::new(false)), misc_library: Box::new(Gen7MiscLibrary::new()), - script_resolver: Box::new(EmptyScriptResolver {}), + script_resolver: Box::new(EmptyScriptResolver { + identifier: Default::default(), + }), } } } diff --git a/src/dynamic_data/libraries/misc_library.rs b/src/dynamic_data/libraries/misc_library.rs index 1775a95..f339d9d 100755 --- a/src/dynamic_data/libraries/misc_library.rs +++ b/src/dynamic_data/libraries/misc_library.rs @@ -7,10 +7,10 @@ use crate::dynamic_data::choices::{MoveChoice, TurnChoice}; use crate::dynamic_data::Pokemon; use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; use crate::static_data::{MoveCategory, MoveData, MoveTarget, SecondaryEffect}; -use crate::StringKey; +use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// The misc library holds several misc functions required for the battle to run. -pub trait MiscLibrary: Debug { +pub trait MiscLibrary: Debug + ValueIdentifiable { /// Returns whether or not a Pokemon is allowed to flee or switch out. fn can_flee(&self, choice: &TurnChoice) -> bool; /// Returns the move we need to use if we can't use another move. Typically Struggle. @@ -22,6 +22,8 @@ pub trait MiscLibrary: Debug { /// A gen 7 implementation for the MiscLibrary. #[derive(Debug)] pub struct Gen7MiscLibrary { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The learned move data for struggle. struggle_learned_move: Arc, } @@ -42,7 +44,10 @@ impl Gen7MiscLibrary { HashSet::new(), )); let struggle_learned_move = Arc::new(LearnedMove::new(&struggle_data, MoveLearnMethod::Unknown)); - Self { struggle_learned_move } + Self { + identifier: Default::default(), + struggle_learned_move, + } } } @@ -67,3 +72,9 @@ impl MiscLibrary for Gen7MiscLibrary { )) } } + +impl ValueIdentifiable for Gen7MiscLibrary { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} diff --git a/src/dynamic_data/libraries/script_resolver.rs b/src/dynamic_data/libraries/script_resolver.rs index b5c452b..e494488 100755 --- a/src/dynamic_data/libraries/script_resolver.rs +++ b/src/dynamic_data/libraries/script_resolver.rs @@ -3,12 +3,12 @@ use std::sync::Arc; use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData}; use crate::static_data::Item; -use crate::{PkmnResult, StringKey}; +use crate::{PkmnResult, StringKey, ValueIdentifiable, ValueIdentifier}; /// 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 /// differences, and custom implementations. -pub trait ScriptResolver: Debug { +pub trait ScriptResolver: Debug + ValueIdentifiable { /// Loads a standard script with a given unique combination of category and key. If no script /// can be created with this combination, returns None. fn load_script( @@ -55,7 +55,16 @@ pub enum ScriptCategory { /// A basic empty script resolver, that always returns None. #[derive(Debug)] -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 { fn load_script( diff --git a/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs b/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs new file mode 100644 index 0000000..aec9e8d --- /dev/null +++ b/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs @@ -0,0 +1,10 @@ +use crate::dynamic_data::{BattleStatCalculator, Gen7BattleStatCalculator}; +use crate::ffi::IdentifiablePointer; + +#[no_mangle] +extern "C" fn gen_7_battle_stat_calculator_new() -> IdentifiablePointer> { + let v: Box = Box::new(Gen7BattleStatCalculator::new()); + let id = v.value_identifier(); + let ptr = Box::into_raw(Box::new(v)); + IdentifiablePointer::new(ptr, id) +} diff --git a/src/ffi/dynamic_data/libraries/damage_library.rs b/src/ffi/dynamic_data/libraries/damage_library.rs new file mode 100644 index 0000000..d4dd9da --- /dev/null +++ b/src/ffi/dynamic_data/libraries/damage_library.rs @@ -0,0 +1,10 @@ +use crate::dynamic_data::{DamageLibrary, Gen7DamageLibrary}; +use crate::ffi::IdentifiablePointer; + +#[no_mangle] +extern "C" fn gen_7_damage_library_new(randomness: u8) -> IdentifiablePointer> { + let v: Box = Box::new(Gen7DamageLibrary::new(randomness == 1)); + let id = v.value_identifier(); + let ptr = Box::into_raw(Box::new(v)); + IdentifiablePointer::new(ptr, id) +} diff --git a/src/ffi/dynamic_data/libraries/dynamic_library.rs b/src/ffi/dynamic_data/libraries/dynamic_library.rs new file mode 100644 index 0000000..6d7c9b9 --- /dev/null +++ b/src/ffi/dynamic_data/libraries/dynamic_library.rs @@ -0,0 +1,23 @@ +use crate::dynamic_data::{BattleStatCalculator, DamageLibrary, DynamicLibrary, MiscLibrary, ScriptResolver}; +use crate::ffi::{IdentifiablePointer, OwnedPtr}; +use crate::static_data::StaticData; + +#[no_mangle] +extern "C" fn dynamic_library_new( + static_data: OwnedPtr, + stat_calculator: OwnedPtr>, + damage_library: OwnedPtr>, + misc_library: OwnedPtr>, + script_resolver: OwnedPtr>, +) -> IdentifiablePointer { + unsafe { + Box::new(DynamicLibrary::new( + *Box::from_raw(static_data), + *Box::from_raw(stat_calculator), + *Box::from_raw(damage_library), + *Box::from_raw(misc_library), + *Box::from_raw(script_resolver), + )) + .into() + } +} diff --git a/src/ffi/dynamic_data/libraries/misc_library.rs b/src/ffi/dynamic_data/libraries/misc_library.rs new file mode 100644 index 0000000..a9b1f26 --- /dev/null +++ b/src/ffi/dynamic_data/libraries/misc_library.rs @@ -0,0 +1,10 @@ +use crate::dynamic_data::{Gen7MiscLibrary, MiscLibrary}; +use crate::ffi::IdentifiablePointer; + +#[no_mangle] +extern "C" fn gen_7_misc_library_new() -> IdentifiablePointer> { + let v: Box = Box::new(Gen7MiscLibrary::new()); + let id = v.value_identifier(); + let ptr = Box::into_raw(Box::new(v)); + IdentifiablePointer::new(ptr, id) +} diff --git a/src/ffi/dynamic_data/libraries/mod.rs b/src/ffi/dynamic_data/libraries/mod.rs new file mode 100644 index 0000000..698ee5d --- /dev/null +++ b/src/ffi/dynamic_data/libraries/mod.rs @@ -0,0 +1,5 @@ +mod battle_stat_calculator; +mod damage_library; +mod dynamic_library; +mod misc_library; +mod script_resolver; diff --git a/src/ffi/dynamic_data/libraries/script_resolver.rs b/src/ffi/dynamic_data/libraries/script_resolver.rs new file mode 100644 index 0000000..5da1e01 --- /dev/null +++ b/src/ffi/dynamic_data/libraries/script_resolver.rs @@ -0,0 +1,41 @@ +use crate::dynamic_data::{EmptyScriptResolver, ScriptResolver}; +use crate::ffi::IdentifiablePointer; + +#[no_mangle] +extern "C" fn empty_script_resolver_new() -> IdentifiablePointer> { + let v: Box = Box::new(EmptyScriptResolver { + identifier: Default::default(), + }); + let id = v.value_identifier(); + let ptr = Box::into_raw(Box::new(v)); + IdentifiablePointer::new(ptr, id) +} + +#[cfg(feature = "wasm")] +mod web_assembly_script_resolver { + use crate::dynamic_data::ScriptResolver; + use crate::ffi::{ExternPointer, IdentifiablePointer}; + use crate::script_implementations::wasm::script_resolver::WebAssemblyScriptResolver; + + #[no_mangle] + extern "C" fn webassembly_script_resolver_new() -> IdentifiablePointer> { + let v: Box = WebAssemblyScriptResolver::new(); + let id = v.value_identifier(); + let ptr = Box::into_raw(Box::new(v)); + IdentifiablePointer::new(ptr, id) + } + + #[no_mangle] + extern "C" fn webassembly_script_resolver_load_wasm_from_bytes( + ptr: ExternPointer>, + arr: *const u8, + len: usize, + ) { + unsafe { ptr.as_mut().load_wasm_from_bytes(std::slice::from_raw_parts(arr, len)) } + } + + #[no_mangle] + extern "C" fn webassembly_script_resolver_finalize(ptr: ExternPointer>) { + ptr.as_mut().finalize(); + } +} diff --git a/src/ffi/dynamic_data/mod.rs b/src/ffi/dynamic_data/mod.rs new file mode 100644 index 0000000..87ec77b --- /dev/null +++ b/src/ffi/dynamic_data/mod.rs @@ -0,0 +1 @@ +mod libraries; \ No newline at end of file diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index aab36ad..df5b374 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -1,3 +1,4 @@ +mod dynamic_data; mod static_data; type OwnedPtr = *mut T; @@ -121,6 +122,12 @@ pub(self) struct IdentifiablePointer { pub id: ValueIdentifier, } +impl IdentifiablePointer { + pub(self) fn new(ptr: *const T, id: ValueIdentifier) -> Self { + Self { ptr, id } + } +} + impl From> for IdentifiablePointer> { fn from(v: Arc) -> Self { let id = v.value_identifier(); diff --git a/src/script_implementations/wasm/script_resolver.rs b/src/script_implementations/wasm/script_resolver.rs index ba4a774..8f5d2c0 100755 --- a/src/script_implementations/wasm/script_resolver.rs +++ b/src/script_implementations/wasm/script_resolver.rs @@ -19,10 +19,12 @@ use crate::script_implementations::wasm::script_function_cache::ScriptFunctionCa use crate::script_implementations::wasm::temp_wasm_allocator::{AllocatedObject, TempWasmAllocator}; use crate::script_implementations::wasm::WebAssemblyScriptCapabilities; use crate::static_data::Item; -use crate::{PkmnResult, ScriptCategory, StringKey}; +use crate::{PkmnResult, ScriptCategory, StringKey, ValueIdentifiable, ValueIdentifier}; /// A WebAssembly script resolver implements the dynamic scripts functionality with WebAssembly. pub struct WebAssemblyScriptResolver { + /// A unique identifier so we know what value this is. + identifier: ValueIdentifier, /// The global state storage of WASM. _store: *mut Store, /// The WASM modules we have loaded. @@ -63,6 +65,7 @@ impl WebAssemblyScriptResolver { environment.self_arc.write().replace(Arc::downgrade(&environment)); let s = Self { + identifier: Default::default(), _store: store_ptr, modules: Default::default(), instances: Default::default(), @@ -163,6 +166,12 @@ impl WebAssemblyScriptResolver { } } +impl ValueIdentifiable for WebAssemblyScriptResolver { + fn value_identifier(&self) -> ValueIdentifier { + self.identifier + } +} + impl ScriptResolver for WebAssemblyScriptResolver { fn load_script( &self, diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index 0f1e8b0..7f6cc9f 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -39,7 +39,7 @@ pub fn load_library() -> DynamicLibrary { DynamicLibrary::new( data, - Box::new(Gen7BattleStatCalculator {}), + Box::new(Gen7BattleStatCalculator::new()), Box::new(Gen7DamageLibrary::new(false)), Box::new(Gen7MiscLibrary::new()), resolver,