From f06d46d8546e63f9786f5584860688663fa40538 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 14 Aug 2022 13:37:17 +0200 Subject: [PATCH] A lot of work on type registration --- .gitignore | 3 +- gen_7_scripts/src/test_script.rs | 21 +- pkmn_lib_interface/Cargo.toml | 4 +- .../app_interface/battling/battle_library.rs | 18 -- .../src/app_interface/battling/mod.rs | 5 - .../app_interface/battling/turn_choices.rs | 1 - .../src/app_interface/dynamic_data/battle.rs | 72 +++++ .../dynamic_data/battle_party.rs | 42 +++ .../dynamic_data/battle_random.rs | 32 +++ .../app_interface/dynamic_data/battle_side.rs | 63 ++++ .../dynamic_data/dynamic_library.rs | 44 +++ .../dynamic_data/learned_move.rs | 81 ++++++ .../src/app_interface/dynamic_data/mod.rs | 21 ++ .../src/app_interface/dynamic_data/party.rs | 27 ++ .../src/app_interface/dynamic_data/pokemon.rs | 236 +++++++++++++++ .../dynamic_data/statistic_set.rs | 194 +++++++++++++ .../dynamic_data/turn_choices.rs | 78 +++++ .../library/data_libraries/mod.rs | 73 ----- .../src/app_interface/library/species.rs | 149 ---------- pkmn_lib_interface/src/app_interface/mod.rs | 8 +- .../src/app_interface/static_data/ability.rs | 60 ++++ .../data_libraries/item_library.rs | 18 +- .../static_data/data_libraries/mod.rs | 149 ++++++++++ .../data_libraries/move_library.rs | 18 +- .../data_libraries/species_library.rs | 63 ++++ .../data_libraries/type_library.rs | 93 ++++++ .../effect_parameter.rs | 0 .../{library => static_data}/item.rs | 49 ++-- .../{library => static_data}/mod.rs | 5 + .../{library => static_data}/move_data.rs | 47 +-- .../src/app_interface/static_data/nature.rs | 52 ++++ .../src/app_interface/static_data/species.rs | 270 ++++++++++++++++++ pkmn_lib_interface/src/handling/cacheable.rs | 2 +- .../src/handling/cached_value.rs | 40 ++- pkmn_lib_interface/src/handling/extern_ref.rs | 20 +- pkmn_lib_interface/src/handling/mod.rs | 100 +++++++ pkmn_lib_interface/src/handling/script.rs | 8 +- pkmn_lib_interface/src/handling/temporary.rs | 87 ++++++ pkmn_lib_interface/src/lib.rs | 18 +- 39 files changed, 1910 insertions(+), 361 deletions(-) delete mode 100644 pkmn_lib_interface/src/app_interface/battling/battle_library.rs delete mode 100644 pkmn_lib_interface/src/app_interface/battling/mod.rs delete mode 100644 pkmn_lib_interface/src/app_interface/battling/turn_choices.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/dynamic_library.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/learned_move.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/party.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs create mode 100644 pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs delete mode 100644 pkmn_lib_interface/src/app_interface/library/data_libraries/mod.rs delete mode 100644 pkmn_lib_interface/src/app_interface/library/species.rs create mode 100644 pkmn_lib_interface/src/app_interface/static_data/ability.rs rename pkmn_lib_interface/src/app_interface/{library => static_data}/data_libraries/item_library.rs (78%) create mode 100644 pkmn_lib_interface/src/app_interface/static_data/data_libraries/mod.rs rename pkmn_lib_interface/src/app_interface/{library => static_data}/data_libraries/move_library.rs (80%) create mode 100644 pkmn_lib_interface/src/app_interface/static_data/data_libraries/species_library.rs create mode 100644 pkmn_lib_interface/src/app_interface/static_data/data_libraries/type_library.rs rename pkmn_lib_interface/src/app_interface/{library => static_data}/effect_parameter.rs (100%) rename pkmn_lib_interface/src/app_interface/{library => static_data}/item.rs (70%) rename pkmn_lib_interface/src/app_interface/{library => static_data}/mod.rs (75%) rename pkmn_lib_interface/src/app_interface/{library => static_data}/move_data.rs (69%) create mode 100644 pkmn_lib_interface/src/app_interface/static_data/nature.rs create mode 100644 pkmn_lib_interface/src/app_interface/static_data/species.rs create mode 100644 pkmn_lib_interface/src/handling/temporary.rs diff --git a/.gitignore b/.gitignore index 4fbbf9d..eea4afe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ **/*.rs.bk Cargo.lock bin/ -.idea \ No newline at end of file +.idea +gen7_scripts.wat \ No newline at end of file diff --git a/gen_7_scripts/src/test_script.rs b/gen_7_scripts/src/test_script.rs index 4c61ddd..38f36e6 100644 --- a/gen_7_scripts/src/test_script.rs +++ b/gen_7_scripts/src/test_script.rs @@ -1,5 +1,7 @@ use pkmn_lib_interface::app_interface::list::ImmutableList; -use pkmn_lib_interface::app_interface::{get_hash, BattleLibrary, DataLibrary, EffectParameter}; +use pkmn_lib_interface::app_interface::{ + get_hash, DataLibrary, DynamicLibrary, EffectParameter, TurnChoice, +}; use pkmn_lib_interface::dbg; use pkmn_lib_interface::handling::{Script, ScriptCapabilities}; @@ -16,12 +18,15 @@ impl Script for TestScript { } fn get_capabilities(&self) -> &[ScriptCapabilities] { - &[ScriptCapabilities::Initialize] + &[ + ScriptCapabilities::Initialize, + ScriptCapabilities::OnBeforeTurn, + ] } fn on_initialize( &self, - library: &BattleLibrary, + library: &DynamicLibrary, parameters: Option>, ) { let l = library.data_library(); @@ -32,6 +37,14 @@ impl Script for TestScript { dbg!( "Found a parameter with value: {}", parameters.unwrap().get(0).unwrap() - ) + ); + if m.has_flag(b"foo") {} + } + + fn on_before_turn(&self, choice: TurnChoice) { + dbg!( + "On before turn for user: {}", + choice.user().species().name() + ); } } diff --git a/pkmn_lib_interface/Cargo.toml b/pkmn_lib_interface/Cargo.toml index 56e8af0..70c62e2 100644 --- a/pkmn_lib_interface/Cargo.toml +++ b/pkmn_lib_interface/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] wee_alloc = "0.4.5" -cstr_core = { version = "0.2.5", features = ["nightly"]} +cstr_core = { version = "0.2.6", features = ["nightly"]} lazy_static = { version = "1.4.0", features = ["spin_no_std"] } enumflags2 = { version = "0.7.5", default-features = false } spin = { version = "0.9.4", default-features = false, features = ["rwlock"] } @@ -14,6 +14,4 @@ paste = { version = "1.0.7" } [dev-dependencies] -[profile.dev] -lto = false diff --git a/pkmn_lib_interface/src/app_interface/battling/battle_library.rs b/pkmn_lib_interface/src/app_interface/battling/battle_library.rs deleted file mode 100644 index 64380aa..0000000 --- a/pkmn_lib_interface/src/app_interface/battling/battle_library.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::app_interface::StaticData; -use crate::{impl_extern_ctor, ExternRef}; - -pub struct BattleLibrary { - ptr: ExternRef, -} - -impl_extern_ctor!(BattleLibrary); - -impl BattleLibrary { - pub fn data_library(&self) -> StaticData { - unsafe { StaticData::new(battle_library_get_static_data(self.ptr)) } - } -} - -extern "wasm" { - fn battle_library_get_static_data(ptr: ExternRef) -> ExternRef; -} diff --git a/pkmn_lib_interface/src/app_interface/battling/mod.rs b/pkmn_lib_interface/src/app_interface/battling/mod.rs deleted file mode 100644 index 4052a2a..0000000 --- a/pkmn_lib_interface/src/app_interface/battling/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod battle_library; -mod turn_choices; - -pub use battle_library::BattleLibrary; -pub use turn_choices::*; diff --git a/pkmn_lib_interface/src/app_interface/battling/turn_choices.rs b/pkmn_lib_interface/src/app_interface/battling/turn_choices.rs deleted file mode 100644 index 6fc5de6..0000000 --- a/pkmn_lib_interface/src/app_interface/battling/turn_choices.rs +++ /dev/null @@ -1 +0,0 @@ -pub struct BaseTurnChoice {} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs new file mode 100644 index 0000000..256daa3 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle.rs @@ -0,0 +1,72 @@ +use crate::app_interface::{BattleParty, BattleRandom, BattleSide, Pokemon}; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +use crate::{ + cached_value, cached_value_getters, wasm_value_getters, DynamicLibrary, ExternRef, + ExternalReferenceType, ImmutableList, VecExternRef, +}; +use alloc::rc::Rc; + +struct BattleInner { + reference: ExternRef, + library: CachedValue, + parties: CachedValue>, + sides: CachedValue>, + random: CachedValue, +} + +#[derive(Clone)] +pub struct Battle { + inner: Rc, +} + +impl Battle { + pub fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(BattleInner { + reference, + library: cached_value!({ battle_get_library(reference).get_value().unwrap() }), + parties: cached_value!({ battle_get_parties(reference).get_immutable_list() }), + sides: cached_value!({ battle_get_sides(reference).get_immutable_list() }), + random: cached_value!({ battle_get_random(reference).get_value().unwrap() }), + }), + }) + } + + cached_value_getters! { + pub fn library(&self) -> DynamicLibrary; + pub fn parties(&self) -> ImmutableList; + pub fn sides(&self) -> ImmutableList; + } + + pub fn get_pokemon(&self, side: u8, index: u8) -> Option { + unsafe { battle_get_pokemon(self.inner.reference, side, index).get_value() } + } +} + +wasm_value_getters! { + Battle, + pub fn can_flee(&self) -> bool; + pub fn number_of_sides(&self) -> u8; + pub fn pokemon_per_side(&self) -> u8; + pub fn has_ended(&self) -> bool; + pub fn has_ended_conclusively(&self) -> bool; + pub fn winning_side(&self) -> u8; + pub fn current_turn(&self) -> u32; +} + +crate::handling::cacheable::cacheable!(Battle); + +impl ExternalReferenceType for Battle { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn battle_get_library(r: ExternRef) -> ExternRef; + fn battle_get_parties(r: ExternRef) -> VecExternRef; + fn battle_get_sides(r: ExternRef) -> VecExternRef; + fn battle_get_random(r: ExternRef) -> ExternRef; + fn battle_get_pokemon(r: ExternRef, side: u8, index: u8) -> ExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs new file mode 100644 index 0000000..57eec8d --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_party.rs @@ -0,0 +1,42 @@ +use crate::app_interface::Party; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType}; +use alloc::rc::Rc; + +struct BattlePartyInner { + reference: ExternRef, + party: CachedValue, +} + +#[derive(Clone)] +pub struct BattleParty { + inner: Rc, +} + +impl BattleParty { + pub fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(BattlePartyInner { + reference, + party: cached_value!({ battle_party_get_party(reference).get_value().unwrap() }), + }), + }) + } + + cached_value_getters! { + pub fn party(&self) -> Party; + } +} + +crate::handling::cacheable::cacheable!(BattleParty); + +impl ExternalReferenceType for BattleParty { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn battle_party_get_party(r: ExternRef) -> ExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs new file mode 100644 index 0000000..5ad8636 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_random.rs @@ -0,0 +1,32 @@ +use crate::{ExternRef, ExternalReferenceType}; + +#[derive(Clone)] +pub struct BattleRandom { + reference: ExternRef, +} + +impl BattleRandom { + pub fn get(&self) -> i32 { + unsafe { battle_random_get(self.reference) } + } + pub fn get_max(&self, max: i32) -> i32 { + unsafe { battle_random_get_max(self.reference, max) } + } + pub fn get_between(&self, min: i32, max: i32) -> i32 { + unsafe { battle_random_get_between(self.reference, min, max) } + } + // TODO: effect_chance() +} + +impl ExternalReferenceType for BattleRandom { + fn from_extern_value(reference: ExternRef) -> Self { + Self { reference } + } +} + +extern "wasm" { + fn battle_random_get(r: ExternRef) -> i32; + fn battle_random_get_max(r: ExternRef, max: i32) -> i32; + fn battle_random_get_between(r: ExternRef, min: i32, max: i32) -> i32; + +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs new file mode 100644 index 0000000..1176e57 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/battle_side.rs @@ -0,0 +1,63 @@ +use crate::app_interface::{Battle, Pokemon}; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +use crate::{ + cached_value, cached_value_getters, wasm_value_getters, ExternRef, ExternalReferenceType, +}; +use alloc::rc::Rc; + +struct BattleSideInner { + reference: ExternRef, + side_index: CachedValue, + pokemon_per_side: CachedValue, + battle: CachedValue, +} + +#[derive(Clone)] +pub struct BattleSide { + inner: Rc, +} + +impl BattleSide { + pub fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(BattleSideInner { + reference, + side_index: cached_value!({ battleside_get_side_index(reference) }), + pokemon_per_side: cached_value!({ battleside_get_pokemon_per_side(reference) }), + battle: cached_value!({ battleside_get_battle(reference).get_value().unwrap() }), + }), + }) + } + + cached_value_getters! { + pub fn side_index(&self) -> u8; + pub fn pokemon_per_side(&self) -> u8; + pub fn battle(&self) -> Battle; + } + + pub fn get_pokemon(&self, index: usize) -> Option { + unsafe { battleside_get_pokemon(self.inner.reference, index).get_value() } + } +} + +wasm_value_getters! { + BattleSide, + pub fn has_fled_battle(&self) -> bool; + pub fn is_defeated(&self) -> bool; +} + +crate::handling::cacheable::cacheable!(BattleSide); + +impl ExternalReferenceType for BattleSide { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn battleside_get_side_index(r: ExternRef) -> u8; + fn battleside_get_pokemon_per_side(r: ExternRef) -> u8; + fn battleside_get_battle(r: ExternRef) -> ExternRef; + fn battleside_get_pokemon(r: ExternRef, index: usize) -> ExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/dynamic_library.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/dynamic_library.rs new file mode 100644 index 0000000..9a0ae01 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/dynamic_library.rs @@ -0,0 +1,44 @@ +use crate::app_interface::StaticData; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +use crate::{cached_value, ExternRef, ExternalReferenceType}; +use alloc::rc::Rc; + +struct DynamicLibraryInner { + ptr: ExternRef, + static_data: CachedValue, +} + +#[derive(Clone)] +pub struct DynamicLibrary { + inner: Rc, +} + +crate::handling::cacheable::cacheable!(DynamicLibrary); + +impl DynamicLibrary { + pub(crate) fn new(ptr: ExternRef) -> Self { + Self::from_ref(ptr, &|ptr| Self { + inner: Rc::new(DynamicLibraryInner { + ptr, + static_data: cached_value!({ + dynamic_library_get_static_data(ptr).get_value().unwrap() + }), + }), + }) + } + + pub fn data_library(&self) -> StaticData { + self.inner.static_data.value() + } +} + +impl ExternalReferenceType for DynamicLibrary { + fn from_extern_value(reference: ExternRef) -> Self { + DynamicLibrary::new(reference) + } +} + +extern "wasm" { + fn dynamic_library_get_static_data(ptr: ExternRef) -> ExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/learned_move.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/learned_move.rs new file mode 100644 index 0000000..ad50597 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/learned_move.rs @@ -0,0 +1,81 @@ +use crate::app_interface::MoveData; +use crate::handling::cacheable::Cacheable; +use crate::handling::cached_value::CachedValue; +use crate::{ + cached_value, cached_value_getters, wasm_value_getters, ExternRef, ExternalReferenceType, +}; + +use alloc::rc::Rc; + +struct LearnedMoveInner { + reference: ExternRef, + move_data: CachedValue, + learn_method: CachedValue, +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(u8)] +pub enum MoveLearnMethod { + /// We do not know the learn method. + #[default] + Unknown = 0, + /// The move was learned through level up. + Level = 1, +} + +#[derive(Clone)] +pub struct LearnedMove { + inner: Rc, +} + +crate::handling::cacheable::cacheable!(LearnedMove); + +impl ExternalReferenceType for LearnedMove { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +impl LearnedMove { + pub fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(LearnedMoveInner { + reference, + move_data: cached_value!({ + learned_move_get_move_data(reference).get_value().unwrap() + }), + learn_method: cached_value!({ learned_move_get_learn_method(reference) }), + }), + }) + } + + cached_value_getters! { + pub fn move_data(&self) -> MoveData; + pub fn learn_method(&self) -> MoveLearnMethod; + } + + pub fn restore_all_uses(&self) { + unsafe { + learned_move_restore_all_uses(self.inner.reference); + } + } + + pub fn restore_uses(&self, uses: u8) { + unsafe { + learned_move_restore_uses(self.inner.reference, uses); + } + } +} + +wasm_value_getters! { + LearnedMove, + pub fn max_pp(&self) -> u8; + pub fn remaining_pp(&self) -> u8; +} + +extern "wasm" { + fn learned_move_get_move_data(r: ExternRef) -> ExternRef; + fn learned_move_get_learn_method(r: ExternRef) -> MoveLearnMethod; + fn learned_move_restore_uses(r: ExternRef, uses: u8); + fn learned_move_restore_all_uses(r: ExternRef); +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs new file mode 100644 index 0000000..03edd0d --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/mod.rs @@ -0,0 +1,21 @@ +mod battle; +mod battle_party; +mod battle_random; +mod battle_side; +mod dynamic_library; +mod learned_move; +mod party; +mod pokemon; +mod statistic_set; +mod turn_choices; + +pub use battle::*; +pub use battle_party::*; +pub use battle_random::*; +pub use battle_side::*; +pub use dynamic_library::DynamicLibrary; +pub use learned_move::*; +pub use party::*; +pub use pokemon::*; +pub use statistic_set::*; +pub use turn_choices::*; diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs new file mode 100644 index 0000000..5ac5b12 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/party.rs @@ -0,0 +1,27 @@ +use crate::app_interface::Pokemon; +use crate::{ExternRef, ExternalReferenceType}; + +#[derive(Clone)] +pub struct Party { + reference: ExternRef, +} + +impl Party { + pub fn new(reference: ExternRef) -> Self { + Self { reference } + } + + pub fn get_pokemon(&self, index: usize) -> Option { + unsafe { party_get_pokemon(self.reference, index).get_value() } + } +} + +impl ExternalReferenceType for Party { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn party_get_pokemon(r: ExternRef, index: usize) -> ExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs new file mode 100644 index 0000000..0b7b536 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/pokemon.rs @@ -0,0 +1,236 @@ +use crate::app_interface::ability::{Ability, AbilityIndex}; +use crate::app_interface::{ + Battle, ClampedStatisticSet, Form, Gender, Item, LearnedMove, LevelInt, Nature, Species, + Statistic, StatisticSet, +}; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +use crate::{ + cached_value, cached_value_getters, wasm_optional_reference_getters, wasm_reference_getters, + wasm_value_getters, DynamicLibrary, ExternRef, ExternalReferenceType, Script, +}; +use alloc::boxed::Box; +use alloc::rc::Rc; +use cstr_core::{c_char, CString}; + +struct PokemonInner { + reference: ExternRef, + library: CachedValue, + // We cache the reference to the data, not the values stored inside, which are dynamic. + flat_stats: CachedValue>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + stat_boosts: CachedValue>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + boosted_stats: CachedValue>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + individual_values: CachedValue>, + // We cache the reference to the data, not the values stored inside, which are dynamic. + effort_values: CachedValue>, +} + +#[derive(Clone)] +pub struct Pokemon { + inner: Rc, +} + +impl Pokemon { + pub(crate) fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(PokemonInner { + reference, + library: cached_value!({ pokemon_get_library(reference).get_value().unwrap() }), + flat_stats: cached_value!({ + pokemon_get_flat_stats(reference).get_value().unwrap() + }), + stat_boosts: cached_value!({ + pokemon_get_stat_boosts(reference).get_value().unwrap() + }), + boosted_stats: cached_value!({ + pokemon_get_boosted_stats(reference).get_value().unwrap() + }), + individual_values: cached_value!({ + pokemon_get_individual_values(reference) + .get_value() + .unwrap() + }), + effort_values: cached_value!({ + pokemon_get_effort_values(reference).get_value().unwrap() + }), + }), + }) + } + + cached_value_getters! { + pub fn library(&self) -> DynamicLibrary; + pub fn flat_stats(&self) -> StatisticSet; + pub fn stat_boosts(&self) -> ClampedStatisticSet; + pub fn boosted_stats(&self) -> StatisticSet; + pub fn individual_values(&self) -> ClampedStatisticSet; + pub fn effort_values(&self) -> ClampedStatisticSet; + } + + pub fn has_held_item(&self, name: &str) -> bool { + let cstr = CString::new(name).unwrap(); + unsafe { pokemon_has_held_item(self.inner.reference, cstr.as_ptr()) } + } + + pub fn set_held_item(&self, item: &Item) -> Option { + unsafe { pokemon_set_held_item(self.inner.reference, item.reference()).get_value() } + } + + pub fn remove_held_item(&self) -> Option { + unsafe { pokemon_remove_held_item(self.inner.reference).get_value() } + } + + pub fn consume_held_item(&self) -> bool { + unsafe { pokemon_consume_held_item(self.inner.reference) } + } + + pub fn max_health(&self) -> u32 { + self.boosted_stats().hp() + } + + pub fn get_type(&self, index: usize) -> u8 { + unsafe { pokemon_get_type(self.inner.reference, index) } + } + pub fn has_type(&self, type_identifier: u8) -> bool { + unsafe { pokemon_has_type(self.inner.reference, type_identifier) } + } + pub fn has_type_by_name(&self, type_name: &str) -> bool { + let type_identifier = self + .library() + .data_library() + .type_library() + .get_type_from_name(type_name); + if let Some(type_identifier) = type_identifier { + return self.has_type(type_identifier); + } + false + } + pub fn get_learned_move(&self, index: usize) -> Option { + unsafe { pokemon_get_learned_move(self.inner.reference, index).get_value() } + } + pub fn change_stat_boost( + &self, + stat: Statistic, + diff_amount: i8, + self_inflicted: bool, + ) -> bool { + unsafe { + pokemon_change_stat_boost(self.inner.reference, stat, diff_amount, self_inflicted) + } + } + + pub fn ability_script(&self) -> Option<&Box> { + unsafe { pokemon_get_ability_script(self.inner.reference).as_ref() } + } + + pub fn change_species(&self, species: Species, form: Form) { + unsafe { + pokemon_change_species(self.inner.reference, species.reference(), form.reference()); + } + } + + pub fn change_form(&self, form: Form) { + unsafe { + pokemon_change_form(self.inner.reference, form.reference()); + } + } + + pub fn is_fainted(&self) -> bool { + self.current_health() == 0 + } + + pub fn damage(&self, damage: u32, source: DamageSource) { + unsafe { pokemon_damage(self.inner.reference, damage, source) } + } + + pub fn heal(&self, amount: u32, allow_revive: bool) -> bool { + unsafe { pokemon_heal(self.inner.reference, amount, allow_revive) } + } +} + +wasm_reference_getters! { + Pokemon, + pub fn species(&self) -> Species; + pub fn form(&self) -> Form; + pub fn active_ability(&self) -> Ability; + pub fn nature(&self) -> Nature; +} + +wasm_optional_reference_getters! { + Pokemon, + pub fn display_species(&self) -> Option; + pub fn display_form(&self) -> Option
; + pub fn held_item(&self) -> Option; + pub fn battle(&self) -> Option; +} + +wasm_value_getters! { + Pokemon, + pub fn level(&self) -> LevelInt; + pub fn experience(&self) -> u32; + pub fn unique_identifier(&self) -> u32; + pub fn gender(&self) -> Gender; + pub fn coloring(&self) -> u8; + pub fn current_health(&self) -> u32; + pub fn weight(&self) -> f32; + pub fn height(&self) -> f32; + pub fn nickname(&self) -> *const c_char; + pub fn real_ability(&self) -> AbilityIndex; + pub fn types_length(&self) -> usize; + pub fn battle_side_index(&self) -> u8; + pub fn battle_index(&self) -> u8; + pub fn is_ability_overriden(&self) -> u8; + pub fn allowed_experience_gain(&self) -> bool; + pub fn is_usable(&self) -> bool; +} + +/// A source of damage. This should be as unique as possible. +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum DamageSource { + /// The damage is done by a move. + MoveDamage = 0, + /// The damage is done by something else. + Misc = 1, +} + +crate::handling::cacheable::cacheable!(Pokemon); + +impl ExternalReferenceType for Pokemon { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn pokemon_get_library(r: ExternRef) -> ExternRef; + fn pokemon_get_flat_stats(r: ExternRef) -> ExternRef>; + fn pokemon_get_stat_boosts(r: ExternRef) -> ExternRef>; + fn pokemon_get_boosted_stats(r: ExternRef) -> ExternRef>; + fn pokemon_get_individual_values(r: ExternRef) -> ExternRef>; + fn pokemon_get_effort_values(r: ExternRef) -> ExternRef>; + fn pokemon_has_held_item(r: ExternRef, name: *const c_char) -> bool; + fn pokemon_set_held_item(r: ExternRef, item: ExternRef) -> ExternRef; + fn pokemon_remove_held_item(r: ExternRef) -> ExternRef; + fn pokemon_consume_held_item(r: ExternRef) -> bool; + fn pokemon_get_type(r: ExternRef, index: usize) -> u8; + fn pokemon_has_type(r: ExternRef, identifier: u8) -> bool; + fn pokemon_get_learned_move(r: ExternRef, index: usize) -> ExternRef; + fn pokemon_change_stat_boost( + r: ExternRef, + tat: Statistic, + diff_amount: i8, + self_inflicted: bool, + ) -> bool; + fn pokemon_get_ability_script(r: ExternRef) -> *const Box; + fn pokemon_change_species( + r: ExternRef, + species: ExternRef, + form: ExternRef, + ); + fn pokemon_change_form(r: ExternRef, form: ExternRef); + fn pokemon_damage(r: ExternRef, damage: u32, source: DamageSource); + fn pokemon_heal(r: ExternRef, amount: u32, allow_revive: bool) -> bool; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs new file mode 100644 index 0000000..cba199d --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/statistic_set.rs @@ -0,0 +1,194 @@ +use crate::app_interface::Statistic; +use crate::{ExternRef, ExternalReferenceType}; +use core::convert::{TryFrom, TryInto}; +use core::fmt::Debug; +use core::marker::PhantomData; + +#[derive(Clone)] +pub struct StatisticSet +where + T: TryFrom, + T: TryInto, +{ + reference: ExternRef, + _p: PhantomData, +} + +impl StatisticSet +where + T: TryFrom, + T: TryInto, + >::Error: Debug, + >::Error: Debug, +{ + pub(crate) fn new(reference: ExternRef) -> Self { + Self { + reference, + _p: Default::default(), + } + } + + pub fn hp(&self) -> T { + self.get_stat(Statistic::HP) + } + pub fn attack(&self) -> T { + self.get_stat(Statistic::Attack) + } + pub fn defense(&self) -> T { + self.get_stat(Statistic::Defense) + } + pub fn special_attack(&self) -> T { + self.get_stat(Statistic::SpecialAttack) + } + pub fn special_defense(&self) -> T { + self.get_stat(Statistic::SpecialDefense) + } + pub fn speed(&self) -> T { + self.get_stat(Statistic::Speed) + } + + pub fn get_stat(&self, stat: Statistic) -> T { + unsafe { + statistic_set_get(self.reference.cast(), stat) + .try_into() + .unwrap() + } + } + + pub fn set_stat(&self, stat: Statistic, value: T) { + unsafe { statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) } + } + + pub fn increase_stat(&self, stat: Statistic, value: T) { + unsafe { + statistic_set_increase_stat(self.reference.cast(), stat, value.try_into().unwrap()) + } + } + pub fn decrease_stat(&self, stat: Statistic, value: T) { + unsafe { + statistic_set_decrease_stat(self.reference.cast(), stat, value.try_into().unwrap()) + } + } +} + +impl ExternalReferenceType for StatisticSet +where + T: TryFrom, + T: TryInto, + >::Error: Debug, + >::Error: Debug, +{ + fn from_extern_value(reference: ExternRef) -> Self { + StatisticSet::::new(reference) + } +} + +#[derive(Clone)] +pub struct ClampedStatisticSet +where + T: TryFrom, + T: TryInto, +{ + reference: ExternRef, + _p: PhantomData, +} + +impl ClampedStatisticSet +where + T: TryFrom, + T: TryInto, + >::Error: Debug, + >::Error: Debug, +{ + pub(crate) fn new(reference: ExternRef) -> Self { + Self { + reference, + _p: Default::default(), + } + } + pub fn hp(&self) -> T { + self.get_stat(Statistic::HP) + } + pub fn attack(&self) -> T { + self.get_stat(Statistic::Attack) + } + pub fn defense(&self) -> T { + self.get_stat(Statistic::Defense) + } + pub fn special_attack(&self) -> T { + self.get_stat(Statistic::SpecialAttack) + } + pub fn special_defense(&self) -> T { + self.get_stat(Statistic::SpecialDefense) + } + pub fn speed(&self) -> T { + self.get_stat(Statistic::Speed) + } + + pub fn get_stat(&self, stat: Statistic) -> T { + unsafe { + clamped_statistic_set_get(self.reference.cast(), stat) + .try_into() + .unwrap() + } + } + + pub fn set_stat(&self, stat: Statistic, value: T) { + unsafe { clamped_statistic_set_set(self.reference.cast(), stat, value.try_into().unwrap()) } + } + + pub fn increase_stat(&self, stat: Statistic, value: T) -> bool { + unsafe { + clamped_statistic_set_increase_stat( + self.reference.cast(), + stat, + value.try_into().unwrap(), + ) + } + } + pub fn decrease_stat(&self, stat: Statistic, value: T) -> bool { + unsafe { + clamped_statistic_set_decrease_stat( + self.reference.cast(), + stat, + value.try_into().unwrap(), + ) + } + } +} + +impl ExternalReferenceType for ClampedStatisticSet +where + T: TryFrom, + T: TryInto, + >::Error: Debug, + >::Error: Debug, +{ + fn from_extern_value(reference: ExternRef) -> Self { + ClampedStatisticSet::::new(reference) + } +} + +extern "wasm" { + fn statistic_set_get(r: ExternRef>, stat: Statistic) -> i64; + fn statistic_set_set(r: ExternRef>, stat: Statistic, value: i64); + fn statistic_set_increase_stat(r: ExternRef>, stat: Statistic, value: i64); + fn statistic_set_decrease_stat(r: ExternRef>, stat: Statistic, value: i64); + + fn clamped_statistic_set_get(r: ExternRef>, stat: Statistic) -> i64; + fn clamped_statistic_set_set( + r: ExternRef>, + stat: Statistic, + value: i64, + ); + fn clamped_statistic_set_increase_stat( + r: ExternRef>, + stat: Statistic, + value: i64, + ) -> bool; + fn clamped_statistic_set_decrease_stat( + r: ExternRef>, + stat: Statistic, + value: i64, + ) -> bool; +} diff --git a/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs b/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs new file mode 100644 index 0000000..ae99823 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/dynamic_data/turn_choices.rs @@ -0,0 +1,78 @@ +use crate::app_interface::Pokemon; +use crate::handling::cached_value::CachedValue; +use crate::handling::temporary::Temporary; +use crate::{cached_value, ExternRef, ExternalReferenceType}; +use alloc::rc::Rc; + +struct BaseTurnChoiceData { + reference: ExternRef, + user: CachedValue, +} + +struct MoveTurnChoiceDataInner { + base: BaseTurnChoiceData, +} +#[derive(Clone)] +struct MoveTurnChoiceDataTemporary { + inner: Rc, +} +pub struct MoveTurnChoiceData { + temp: Temporary, +} + +pub enum TurnChoice { + Move(MoveTurnChoiceData), + Item(), + Switch(), + Flee, + Pass, +} + +impl TurnChoice { + pub fn user(&self) -> Pokemon { + match self { + TurnChoice::Move(data) => data.temp.value().inner.base.user.value(), + _ => panic!("Unknown turn choice type"), + } + } +} + +impl ExternalReferenceType for TurnChoice { + fn from_extern_value(reference: ExternRef) -> Self { + let kind = unsafe { turn_choice_get_kind(reference) }; + match kind { + 0 => TurnChoice::Move(MoveTurnChoiceData { + temp: Temporary::from_reference(reference.cast()), + }), + _ => panic!("Unknown turn choice type"), + } + } +} + +impl ExternalReferenceType for MoveTurnChoiceDataTemporary { + fn from_extern_value(reference: ExternRef) -> Self { + Self { + inner: Rc::new(MoveTurnChoiceDataInner { + base: BaseTurnChoiceData { + reference: reference.cast(), + user: cached_value!({ + turn_choice_get_user(reference.cast()).get_value().unwrap() + }), + }, + }), + } + } +} + +extern "wasm" { + fn turn_choice_get_kind(r: ExternRef) -> u8; + fn turn_choice_get_user(r: ExternRef) -> ExternRef; +} + +#[no_mangle] +unsafe extern "wasm" fn turn_choice_mark_deleted(r: ExternRef, kind: u8) { + match kind { + 0 => Temporary::::mark_as_deleted(r.cast()), + _ => panic!("Unknown turn choice type"), + } +} diff --git a/pkmn_lib_interface/src/app_interface/library/data_libraries/mod.rs b/pkmn_lib_interface/src/app_interface/library/data_libraries/mod.rs deleted file mode 100644 index f8163a8..0000000 --- a/pkmn_lib_interface/src/app_interface/library/data_libraries/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::{impl_extern_ctor, ExternRef, ExternalReferenceType, StringKey}; -use alloc::collections::BTreeMap; -use move_library::MoveLibrary; -use spin::rwlock::RwLock; - -pub mod item_library; -pub mod move_library; - -use crate::handling::Cacheable; -pub use item_library::*; -pub use move_library::*; - -pub struct StaticData { - ptr: ExternRef, -} - -impl_extern_ctor!(StaticData); -impl StaticData { - pub fn move_library(&self) -> MoveLibrary { - unsafe { MoveLibrary::new(static_data_get_move_library(self.ptr)) } - } -} - -extern "wasm" { - fn static_data_get_move_library(ptr: ExternRef) -> ExternRef; -} - -pub trait DataLibrary: Cacheable -where - T: ExternalReferenceType, - T: Clone, -{ - fn get_cache(&self) -> &RwLock>; - fn get_self_ref(&self) -> ExternRef - where - Self: Sized; - fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef - where - Self: Sized; - fn _get_ref_by_hash(ptr: ExternRef, hash: u32) -> ExternRef - where - Self: Sized; - - fn get(&self, name: &StringKey) -> Option - where - Self: Sized, - { - if let Some(v) = self.get_cache().read().get(&name.hash()) { - return Some(v.clone()); - } - - let v = Self::_get_ref_by_name(self.get_self_ref(), name.ptr()).get_value(); - if let Some(v) = &v { - self.get_cache().write().insert(name.hash(), v.clone()); - } - v - } - - fn get_by_hash(&self, hash: u32) -> Option - where - Self: Sized, - { - if let Some(v) = self.get_cache().read().get(&hash) { - return Some(v.clone()); - } - - let v = Self::_get_ref_by_hash(self.get_self_ref(), hash).get_value(); - if let Some(v) = &v { - self.get_cache().write().insert(hash, v.clone()); - } - v - } -} diff --git a/pkmn_lib_interface/src/app_interface/library/species.rs b/pkmn_lib_interface/src/app_interface/library/species.rs deleted file mode 100644 index 02b4a7e..0000000 --- a/pkmn_lib_interface/src/app_interface/library/species.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::handling::cached_value::CachedValue; -use crate::handling::Cacheable; -use crate::{ - cached_value, ExternRef, ExternalReferenceType, FFIArray, ImmutableList, StringKey, - VecExternRef, -}; -use alloc::rc::Rc; -use alloc::vec::Vec; - -#[repr(u8)] -pub enum Gender { - Male = 0, - Female = 1, - Genderless = 2, -} - -#[repr(u8)] -pub enum Statistic { - HP = 0, - Attack = 1, - Defense = 2, - SpecialAttack = 3, - SpecialDefense = 4, - Speed = 5, -} - -pub struct ImmutableStatisticSetInner { - ptr: ExternRef, - /// The health point stat value. - hp: CachedValue, - /// The physical attack stat value. - attack: CachedValue, - /// The physical defense stat value. - defense: CachedValue, - /// The special attack stat value. - special_attack: CachedValue, - /// The special defense stat value. - special_defense: CachedValue, - /// The speed stat value. - speed: CachedValue, -} - -#[derive(Clone)] -pub struct ImmutableStatisticSet { - inner: Rc, -} - -impl ImmutableStatisticSet { - pub(crate) fn new(ptr: ExternRef) -> Self { - Self::from_ref(ptr, &|ptr| Self { - inner: Rc::new(ImmutableStatisticSetInner { - ptr, - hp: cached_value!({ static_statistics_set_get_hp(ptr) }), - attack: cached_value!({ static_statistics_set_get_attack(ptr) }), - defense: cached_value!({ static_statistics_set_get_defense(ptr) }), - special_attack: cached_value!({ static_statistics_set_get_special_attack(ptr) }), - special_defense: cached_value!({ static_statistics_set_get_special_defense(ptr) }), - speed: cached_value!({ static_statistics_set_get_speed(ptr) }), - }), - }) - } - - pub fn hp(&self) -> u16 { - self.inner.hp.value() - } - pub fn attack(&self) -> u16 { - self.inner.attack.value() - } - pub fn defense(&self) -> u16 { - self.inner.defense.value() - } - pub fn special_attack(&self) -> u16 { - self.inner.special_attack.value() - } - pub fn special_defense(&self) -> u16 { - self.inner.special_defense.value() - } - pub fn speed(&self) -> u16 { - self.inner.speed.value() - } -} - -struct FormInner { - ptr: ExternRef, - name: CachedValue, - height: CachedValue, - weight: CachedValue, - types: CachedValue>, - base_experience: CachedValue, - base_stats: CachedValue, - abilities: CachedValue>, - hidden_abilities: CachedValue>, - // moves: CachedValue, -} - -#[derive(Clone)] -pub struct Form { - inner: Rc, -} - -impl Form { - pub(crate) fn new(ptr: ExternRef) -> Self { - Self::from_ref(ptr, &|ptr| Self { - inner: Rc::new(FormInner { - ptr, - name: cached_value!({ form_get_name(ptr).get_value().unwrap() }), - height: cached_value!({ form_get_height(ptr) }), - weight: cached_value!({ form_get_weight(ptr) }), - types: cached_value!({ - let raw = form_get_types(ptr); - Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len()) - }), - base_experience: cached_value!({ form_get_base_experience(ptr) }), - base_stats: cached_value!({ form_get_base_stats(ptr).get_value().unwrap() }), - abilities: cached_value!({ form_get_abilities(ptr).get_immutable_list() }), - hidden_abilities: cached_value!({ - form_get_hidden_abilities(ptr).get_immutable_list() - }), - }), - }) - } -} - -impl ExternalReferenceType for ImmutableStatisticSet { - fn from_extern_value(reference: ExternRef) -> Self { - ImmutableStatisticSet::new(reference) - } -} - -crate::handling::cacheable::cacheable!(ImmutableStatisticSet); -crate::handling::cacheable::cacheable!(Form); - -extern "wasm" { - fn static_statistics_set_get_hp(r: ExternRef) -> u16; - fn static_statistics_set_get_attack(r: ExternRef) -> u16; - fn static_statistics_set_get_defense(r: ExternRef) -> u16; - fn static_statistics_set_get_special_attack(r: ExternRef) -> u16; - fn static_statistics_set_get_special_defense(r: ExternRef) -> u16; - fn static_statistics_set_get_speed(r: ExternRef) -> u16; - - fn form_get_name(r: ExternRef) -> ExternRef; - fn form_get_height(r: ExternRef) -> f32; - fn form_get_weight(r: ExternRef) -> f32; - fn form_get_types(r: ExternRef) -> FFIArray; - fn form_get_base_experience(r: ExternRef) -> u32; - fn form_get_base_stats(r: ExternRef) -> ExternRef; - fn form_get_abilities(r: ExternRef) -> VecExternRef; - fn form_get_hidden_abilities(r: ExternRef) -> VecExternRef; -} diff --git a/pkmn_lib_interface/src/app_interface/mod.rs b/pkmn_lib_interface/src/app_interface/mod.rs index d170341..9f386cd 100644 --- a/pkmn_lib_interface/src/app_interface/mod.rs +++ b/pkmn_lib_interface/src/app_interface/mod.rs @@ -1,9 +1,9 @@ -pub mod battling; -pub mod library; +pub mod dynamic_data; pub mod list; +pub mod static_data; pub mod string_key; -pub use battling::*; -pub use library::*; +pub use dynamic_data::*; +pub use static_data::*; pub use string_key::get_hash; pub use string_key::StringKey; diff --git a/pkmn_lib_interface/src/app_interface/static_data/ability.rs b/pkmn_lib_interface/src/app_interface/static_data/ability.rs new file mode 100644 index 0000000..85db3ce --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/static_data/ability.rs @@ -0,0 +1,60 @@ +use crate::handling::cacheable::Cacheable; +use crate::handling::cached_value::CachedValue; +use crate::{ + cached_value, cached_value_getters, EffectParameter, ExternRef, ExternalReferenceType, + ImmutableList, StringKey, VecExternRef, +}; +use alloc::rc::Rc; + +struct AbilityInner { + reference: ExternRef, + name: CachedValue, + effect: CachedValue, + parameters: CachedValue>, +} + +#[derive(Clone)] +pub struct Ability { + inner: Rc, +} + +impl Ability { + pub fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(AbilityInner { + reference, + name: cached_value!({ ability_get_name(reference).get_value().unwrap() }), + effect: cached_value!({ ability_get_effect(reference).get_value().unwrap() }), + parameters: cached_value!({ + ability_get_parameters(reference).get_immutable_list() + }), + }), + }) + } + + cached_value_getters! { + pub fn name(&self) -> StringKey; + pub fn effect(&self) -> StringKey; + } +} + +impl ExternalReferenceType for Ability { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +crate::handling::cacheable::cacheable!(Ability); + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[repr(C)] +pub struct AbilityIndex { + pub hidden: bool, + pub index: u8, +} + +extern "wasm" { + fn ability_get_name(r: ExternRef) -> ExternRef; + fn ability_get_effect(r: ExternRef) -> ExternRef; + fn ability_get_parameters(r: ExternRef) -> VecExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/library/data_libraries/item_library.rs b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs similarity index 78% rename from pkmn_lib_interface/src/app_interface/library/data_libraries/item_library.rs rename to pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs index 087ad6f..3566e33 100644 --- a/pkmn_lib_interface/src/app_interface/library/data_libraries/item_library.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/item_library.rs @@ -1,6 +1,5 @@ use crate::app_interface::{DataLibrary, Item}; -use crate::handling::Cacheable; -use crate::{ExternRef, StringKey}; +use crate::{ExternRef, ExternalReferenceType, StringKey}; use alloc::collections::BTreeMap; use alloc::rc::Rc; use spin::rwlock::RwLock; @@ -32,7 +31,7 @@ impl DataLibrary for ItemLibrary { } fn get_self_ref(&self) -> ExternRef { - self.inner.ptr.clone() + self.inner.ptr } fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef { @@ -44,17 +43,14 @@ impl DataLibrary for ItemLibrary { } } -impl Cacheable for ItemLibrary { - fn get_cache<'a>() -> &'a mut BTreeMap, Self> - where - Self: Sized, - { - unsafe { &mut CACHE } +crate::handling::cacheable::cacheable!(ItemLibrary); + +impl ExternalReferenceType for ItemLibrary { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) } } -static mut CACHE: BTreeMap, ItemLibrary> = BTreeMap::new(); - extern "wasm" { fn move_library_get_move( ptr: ExternRef, diff --git a/pkmn_lib_interface/src/app_interface/static_data/data_libraries/mod.rs b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/mod.rs new file mode 100644 index 0000000..6aa6f3f --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/mod.rs @@ -0,0 +1,149 @@ +use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType, StringKey}; +use alloc::collections::BTreeMap; +use alloc::rc::Rc; +use move_library::MoveLibrary; +use spin::rwlock::RwLock; + +pub mod item_library; +pub mod move_library; +pub mod species_library; +pub mod type_library; + +use crate::app_interface::species_library::SpeciesLibrary; +use crate::app_interface::type_library::TypeLibrary; +use crate::app_interface::LevelInt; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +pub use item_library::*; +pub use move_library::*; + +struct StaticDataInner { + reference: ExternRef, + move_library: CachedValue, + item_library: CachedValue, + species_library: CachedValue, + type_library: CachedValue, +} + +#[derive(Clone)] +pub struct StaticData { + inner: Rc, +} + +impl StaticData { + pub(crate) fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(StaticDataInner { + reference, + move_library: cached_value!({ + static_data_get_move_library(reference).get_value().unwrap() + }), + item_library: cached_value!({ + static_data_get_item_library(reference).get_value().unwrap() + }), + species_library: cached_value!({ + static_data_get_species_library(reference) + .get_value() + .unwrap() + }), + type_library: cached_value!({ + static_data_get_type_library(reference).get_value().unwrap() + }), + }), + }) + } + + cached_value_getters! { + pub fn move_library(&self) -> MoveLibrary; + pub fn item_library(&self) -> ItemLibrary; + pub fn species_library(&self) -> SpeciesLibrary; + pub fn type_library(&self) -> TypeLibrary; + } +} + +crate::handling::cacheable::cacheable!(StaticData); + +impl ExternalReferenceType for StaticData { + fn from_extern_value(reference: ExternRef) -> Self { + StaticData::new(reference) + } +} + +struct LibrarySettingsInner { + maximum_level: CachedValue, +} + +#[derive(Clone)] +pub struct LibrarySettings { + inner: Rc, +} + +impl LibrarySettings { + pub(crate) fn new(ptr: ExternRef) -> Self { + Self { + inner: Rc::new(LibrarySettingsInner { + maximum_level: cached_value!({ library_settings_get_maximum_level(ptr) }), + }), + } + } + + cached_value_getters! { + pub fn maximum_level(&self) -> LevelInt; + } +} + +extern "wasm" { + fn static_data_get_move_library(ptr: ExternRef) -> ExternRef; + fn static_data_get_item_library(ptr: ExternRef) -> ExternRef; + fn static_data_get_species_library(ptr: ExternRef) -> ExternRef; + fn static_data_get_type_library(ptr: ExternRef) -> ExternRef; + + fn library_settings_get_maximum_level(ptr: ExternRef) -> LevelInt; +} + +pub trait DataLibrary: Cacheable +where + T: ExternalReferenceType, + T: Clone, +{ + fn get_cache(&self) -> &RwLock>; + fn get_self_ref(&self) -> ExternRef + where + Self: Sized; + fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef + where + Self: Sized; + fn _get_ref_by_hash(ptr: ExternRef, hash: u32) -> ExternRef + where + Self: Sized; + + fn get(&self, name: &StringKey) -> Option + where + Self: Sized, + { + if let Some(v) = self.get_cache().read().get(&name.hash()) { + return Some(v.clone()); + } + + let v = Self::_get_ref_by_name(self.get_self_ref(), name.ptr()).get_value(); + if let Some(v) = &v { + self.get_cache().write().insert(name.hash(), v.clone()); + } + v + } + + fn get_by_hash(&self, hash: u32) -> Option + where + Self: Sized, + { + if let Some(v) = self.get_cache().read().get(&hash) { + return Some(v.clone()); + } + + let v = Self::_get_ref_by_hash(self.get_self_ref(), hash).get_value(); + if let Some(v) = &v { + self.get_cache().write().insert(hash, v.clone()); + } + v + } +} diff --git a/pkmn_lib_interface/src/app_interface/library/data_libraries/move_library.rs b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/move_library.rs similarity index 80% rename from pkmn_lib_interface/src/app_interface/library/data_libraries/move_library.rs rename to pkmn_lib_interface/src/app_interface/static_data/data_libraries/move_library.rs index cb74ed9..4f5f159 100644 --- a/pkmn_lib_interface/src/app_interface/library/data_libraries/move_library.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/move_library.rs @@ -1,7 +1,6 @@ use crate::app_interface::data_libraries::DataLibrary; use crate::app_interface::{MoveData, StringKey}; -use crate::handling::Cacheable; -use crate::ExternRef; +use crate::{ExternRef, ExternalReferenceType}; use alloc::collections::BTreeMap; use alloc::rc::Rc; use spin::RwLock; @@ -33,7 +32,7 @@ impl DataLibrary for MoveLibrary { } fn get_self_ref(&self) -> ExternRef { - self.inner.ptr.clone() + self.inner.ptr } fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef { @@ -45,17 +44,14 @@ impl DataLibrary for MoveLibrary { } } -impl Cacheable for MoveLibrary { - fn get_cache<'a>() -> &'a mut BTreeMap, Self> - where - Self: Sized, - { - unsafe { &mut CACHE } +crate::handling::cacheable::cacheable!(MoveLibrary); + +impl ExternalReferenceType for MoveLibrary { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) } } -static mut CACHE: BTreeMap, MoveLibrary> = BTreeMap::new(); - extern "wasm" { fn move_library_get_move( ptr: ExternRef, diff --git a/pkmn_lib_interface/src/app_interface/static_data/data_libraries/species_library.rs b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/species_library.rs new file mode 100644 index 0000000..4bd9b9f --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/species_library.rs @@ -0,0 +1,63 @@ +use crate::app_interface::{DataLibrary, Species}; +use crate::{ExternRef, ExternalReferenceType, StringKey}; +use alloc::collections::BTreeMap; +use alloc::rc::Rc; +use spin::RwLock; + +struct SpeciesLibraryInner { + ptr: ExternRef, + cache: RwLock>, +} + +#[derive(Clone)] +pub struct SpeciesLibrary { + inner: Rc, +} + +impl SpeciesLibrary { + pub(crate) fn new(ptr: ExternRef) -> Self { + Self { + inner: Rc::new(SpeciesLibraryInner { + ptr, + cache: Default::default(), + }), + } + } +} + +impl DataLibrary for SpeciesLibrary { + fn get_cache(&self) -> &spin::rwlock::RwLock> { + &self.inner.cache + } + + fn get_self_ref(&self) -> ExternRef { + self.inner.ptr + } + + fn _get_ref_by_name(ptr: ExternRef, name: ExternRef) -> ExternRef { + unsafe { species_library_get_species(ptr, name) } + } + + fn _get_ref_by_hash(ptr: ExternRef, hash: u32) -> ExternRef { + unsafe { species_library_get_species_by_hash(ptr, hash) } + } +} + +crate::handling::cacheable::cacheable!(SpeciesLibrary); + +impl ExternalReferenceType for SpeciesLibrary { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn species_library_get_species( + ptr: ExternRef, + name: ExternRef, + ) -> ExternRef; + fn species_library_get_species_by_hash( + ptr: ExternRef, + hash: u32, + ) -> ExternRef; +} diff --git a/pkmn_lib_interface/src/app_interface/static_data/data_libraries/type_library.rs b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/type_library.rs new file mode 100644 index 0000000..fe07f01 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/static_data/data_libraries/type_library.rs @@ -0,0 +1,93 @@ +use crate::{ExternRef, ExternalReferenceType}; +use alloc::collections::BTreeMap; +use alloc::rc::Rc; +use alloc::string::{String, ToString}; +use cstr_core::{c_char, CString}; +use spin::RwLock; + +struct TypeLibraryInner { + reference: ExternRef, + name_to_type_cache: RwLock>, + effectiveness_cache: RwLock>, +} + +#[derive(Clone)] +pub struct TypeLibrary { + inner: Rc, +} + +impl TypeLibrary { + pub(crate) fn new(reference: ExternRef) -> Self { + Self { + inner: Rc::new(TypeLibraryInner { + reference, + name_to_type_cache: Default::default(), + effectiveness_cache: Default::default(), + }), + } + } + + pub fn get_type_from_name(&self, name: &str) -> Option { + if let Some(cached) = self.inner.name_to_type_cache.read().get(name) { + return Some(*cached); + } + let cstr = CString::new(name).unwrap(); + let v = unsafe { type_library_get_type_by_name(self.inner.reference, cstr.as_ptr()) }; + if v == 255 { + return None; + } + self.inner + .name_to_type_cache + .write() + .insert(name.to_string(), v); + Some(v) + } + + pub fn get_single_effectiveness(&self, attacking_type: u8, defending_type: u8) -> f32 { + if let Some(cached) = self + .inner + .effectiveness_cache + .read() + .get(&(attacking_type, defending_type)) + { + return *cached; + } + let effectiveness = unsafe { + type_library_get_single_effectiveness( + self.inner.reference, + attacking_type, + defending_type, + ) + }; + self.inner + .effectiveness_cache + .write() + .insert((attacking_type, defending_type), effectiveness); + effectiveness + } + + pub fn get_effectiveness(&self, attacking_type: u8, defending_types: &[u8]) -> f32 { + let mut f = 1.0; + for defending_type in defending_types { + f *= self.get_single_effectiveness(attacking_type, *defending_type); + } + f + } +} + +crate::handling::cacheable::cacheable!(TypeLibrary); + +impl ExternalReferenceType for TypeLibrary { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn type_library_get_single_effectiveness( + r: ExternRef, + attacking_type: u8, + defending_type: u8, + ) -> f32; + fn type_library_get_type_by_name(r: ExternRef, name: *const c_char) -> u8; +} diff --git a/pkmn_lib_interface/src/app_interface/library/effect_parameter.rs b/pkmn_lib_interface/src/app_interface/static_data/effect_parameter.rs similarity index 100% rename from pkmn_lib_interface/src/app_interface/library/effect_parameter.rs rename to pkmn_lib_interface/src/app_interface/static_data/effect_parameter.rs diff --git a/pkmn_lib_interface/src/app_interface/library/item.rs b/pkmn_lib_interface/src/app_interface/static_data/item.rs similarity index 70% rename from pkmn_lib_interface/src/app_interface/library/item.rs rename to pkmn_lib_interface/src/app_interface/static_data/item.rs index 433563a..2d782a4 100644 --- a/pkmn_lib_interface/src/app_interface/library/item.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/item.rs @@ -1,6 +1,6 @@ use crate::handling::cached_value::CachedValue; use crate::handling::Cacheable; -use crate::{cached_value, ExternRef, ExternalReferenceType, StringKey}; +use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType, StringKey}; use alloc::rc::Rc; /// An item category defines which bag slot items are stored in. @@ -42,7 +42,7 @@ pub enum BattleItemCategory { } struct ItemInner { - ptr: ExternRef, + reference: ExternRef, name: CachedValue, category: CachedValue, battle_category: CachedValue, @@ -56,40 +56,35 @@ pub struct Item { } impl Item { - pub(crate) fn new(ptr: ExternRef) -> Self { - Self::from_ref(ptr, &|ptr| Self { + pub(crate) fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { inner: Rc::new(ItemInner { - ptr, - name: cached_value!({ StringKey::new(item_get_name(ptr)) }), - category: cached_value!({ item_get_category(ptr) }), - battle_category: cached_value!({ item_get_battle_category(ptr) }), - price: cached_value!({ item_get_price(ptr) }), + reference, + name: cached_value!({ StringKey::new(item_get_name(reference)) }), + category: cached_value!({ item_get_category(reference) }), + battle_category: cached_value!({ item_get_battle_category(reference) }), + price: cached_value!({ item_get_price(reference) }), }), }) } - pub(crate) fn ptr(&self) -> ExternRef { - self.inner.ptr + pub(crate) fn reference(&self) -> ExternRef { + self.inner.reference } - /// The name of the item. - pub fn name(&self) -> StringKey { - self.inner.name.value() - } - /// Which bag slot items are stored in. - pub fn category(&self) -> ItemCategory { - self.inner.category.value() - } - /// How the item is categorized when in battle. - pub fn battle_category(&self) -> BattleItemCategory { - self.inner.battle_category.value() - } - /// The buying value of the item. - pub fn price(&self) -> i32 { - self.inner.price.value() + cached_value_getters! { + /// The name of the item. + pub fn name(&self) -> StringKey; + /// Which bag slot items are stored in. + pub fn category(&self) -> ItemCategory; + /// How the item is categorized when in battle. + pub fn battle_category(&self) -> BattleItemCategory; + /// The buying value of the item. + pub fn price(&self) -> i32; } + pub fn has_flag(&self, flag: &StringKey) -> bool { - unsafe { item_has_flag(self.ptr(), flag.ptr()) } + unsafe { item_has_flag(self.inner.reference, flag.ptr()) } } } diff --git a/pkmn_lib_interface/src/app_interface/library/mod.rs b/pkmn_lib_interface/src/app_interface/static_data/mod.rs similarity index 75% rename from pkmn_lib_interface/src/app_interface/library/mod.rs rename to pkmn_lib_interface/src/app_interface/static_data/mod.rs index 7f32d2b..9974b09 100644 --- a/pkmn_lib_interface/src/app_interface/library/mod.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/mod.rs @@ -1,11 +1,16 @@ +pub mod ability; pub mod data_libraries; pub mod effect_parameter; pub mod item; pub mod move_data; +mod nature; pub mod species; pub use data_libraries::*; pub use effect_parameter::EffectParameter; pub use item::*; pub use move_data::*; +pub use nature::*; pub use species::*; + +pub type LevelInt = u8; diff --git a/pkmn_lib_interface/src/app_interface/library/move_data.rs b/pkmn_lib_interface/src/app_interface/static_data/move_data.rs similarity index 69% rename from pkmn_lib_interface/src/app_interface/library/move_data.rs rename to pkmn_lib_interface/src/app_interface/static_data/move_data.rs index 0ca5a89..8bd79f6 100644 --- a/pkmn_lib_interface/src/app_interface/library/move_data.rs +++ b/pkmn_lib_interface/src/app_interface/static_data/move_data.rs @@ -1,8 +1,7 @@ -use crate::app_interface::StringKey; +use crate::app_interface::{get_hash, StringKey}; use crate::handling::cached_value::CachedValue; use crate::handling::Cacheable; -use crate::{cached_value, ExternRef, ExternalReferenceType}; -use alloc::collections::BTreeMap; +use crate::{cached_value, cached_value_getters, ExternRef, ExternalReferenceType}; use alloc::rc::Rc; #[repr(u8)] @@ -66,36 +65,20 @@ impl MoveData { }), }) } - pub(crate) fn ptr(&self) -> ExternRef { - self.inner.ptr - } - pub fn name(&self) -> StringKey { - self.inner.name.value() + cached_value_getters! { + pub fn name(&self) -> StringKey; + pub fn move_type(&self) -> u8; + pub fn category(&self) -> MoveCategory; + pub fn base_power(&self) -> u8; + pub fn accuracy(&self) -> u8; + pub fn base_usages(&self) -> u8; + pub fn target(&self) -> MoveTarget; + pub fn priority(&self) -> i8; } - pub fn move_type(&self) -> u8 { - self.inner.move_type.value() - } - pub fn category(&self) -> MoveCategory { - self.inner.category.value() - } - pub fn base_power(&self) -> u8 { - self.inner.base_power.value() - } - pub fn accuracy(&self) -> u8 { - self.inner.accuracy.value() - } - pub fn base_usages(&self) -> u8 { - self.inner.base_usages.value() - } - pub fn target(&self) -> MoveTarget { - self.inner.target.value() - } - pub fn priority(&self) -> i8 { - self.inner.priority.value() - } - pub fn has_flag(&self, flag: &StringKey) -> bool { - unsafe { move_data_has_flag(self.ptr(), flag.ptr()) } + pub fn has_flag(&self, flag: &[u8; N]) -> bool { + let hash = get_hash(flag); + unsafe { move_data_has_flag_by_hash(self.inner.ptr, hash) } } } @@ -116,5 +99,5 @@ extern "wasm" { fn move_data_get_base_usages(ptr: ExternRef) -> u8; fn move_data_get_target(ptr: ExternRef) -> MoveTarget; fn move_data_get_priority(ptr: ExternRef) -> i8; - fn move_data_has_flag(ptr: ExternRef, flag: ExternRef) -> bool; + fn move_data_has_flag_by_hash(ptr: ExternRef, flag_hash: u32) -> bool; } diff --git a/pkmn_lib_interface/src/app_interface/static_data/nature.rs b/pkmn_lib_interface/src/app_interface/static_data/nature.rs new file mode 100644 index 0000000..d1392d1 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/static_data/nature.rs @@ -0,0 +1,52 @@ +use crate::app_interface::Statistic; +use crate::handling::cacheable::Cacheable; +use crate::{ExternRef, ExternalReferenceType}; +use alloc::rc::Rc; + +struct NatureInner { + reference: ExternRef, + /// The stat that should receive the increased modifier. + increase_stat: Statistic, + /// The stat that should receive the decreased modifier. + decrease_stat: Statistic, + /// The amount by which the increased stat is multiplied. + increase_modifier: f32, + /// The amount by which the decreased stat is multiplied. + decrease_modifier: f32, +} + +#[derive(Clone)] +pub struct Nature { + inner: Rc, +} + +crate::handling::cacheable::cacheable!(Nature); + +impl Nature { + pub fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| unsafe { + Self { + inner: Rc::new(NatureInner { + reference, + increase_stat: nature_get_increase_stat(reference), + decrease_stat: nature_get_decrease_stat(reference), + increase_modifier: nature_get_increase_modifier(reference), + decrease_modifier: nature_get_decrease_modifier(reference), + }), + } + }) + } +} + +impl ExternalReferenceType for Nature { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +extern "wasm" { + fn nature_get_increase_stat(r: ExternRef) -> Statistic; + fn nature_get_decrease_stat(r: ExternRef) -> Statistic; + fn nature_get_increase_modifier(r: ExternRef) -> f32; + fn nature_get_decrease_modifier(r: ExternRef) -> f32; +} diff --git a/pkmn_lib_interface/src/app_interface/static_data/species.rs b/pkmn_lib_interface/src/app_interface/static_data/species.rs new file mode 100644 index 0000000..f7168f6 --- /dev/null +++ b/pkmn_lib_interface/src/app_interface/static_data/species.rs @@ -0,0 +1,270 @@ +use crate::app_interface::get_hash; +use crate::handling::cached_value::CachedValue; +use crate::handling::Cacheable; +use crate::{ + cached_value, cached_value_getters, ExternRef, ExternalReferenceType, FFIArray, ImmutableList, + StringKey, VecExternRef, +}; +use alloc::collections::BTreeMap; +use alloc::rc::Rc; +use alloc::vec::Vec; +use spin::RwLock; + +#[repr(u8)] +pub enum Gender { + Male = 0, + Female = 1, + Genderless = 2, +} + +#[repr(u8)] +pub enum Statistic { + HP = 0, + Attack = 1, + Defense = 2, + SpecialAttack = 3, + SpecialDefense = 4, + Speed = 5, +} + +pub struct ImmutableStatisticSetInner { + reference: ExternRef, + /// The health point stat value. + hp: CachedValue, + /// The physical attack stat value. + attack: CachedValue, + /// The physical defense stat value. + defense: CachedValue, + /// The special attack stat value. + special_attack: CachedValue, + /// The special defense stat value. + special_defense: CachedValue, + /// The speed stat value. + speed: CachedValue, +} + +#[derive(Clone)] +pub struct ImmutableStatisticSet { + inner: Rc, +} + +impl ImmutableStatisticSet { + pub(crate) fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(ImmutableStatisticSetInner { + reference, + hp: cached_value!({ static_statistics_set_get_hp(reference) }), + attack: cached_value!({ static_statistics_set_get_attack(reference) }), + defense: cached_value!({ static_statistics_set_get_defense(reference) }), + special_attack: cached_value!({ + static_statistics_set_get_special_attack(reference) + }), + special_defense: cached_value!({ + static_statistics_set_get_special_defense(reference) + }), + speed: cached_value!({ static_statistics_set_get_speed(reference) }), + }), + }) + } + + pub fn hp(&self) -> u16 { + self.inner.hp.value() + } + pub fn attack(&self) -> u16 { + self.inner.attack.value() + } + pub fn defense(&self) -> u16 { + self.inner.defense.value() + } + pub fn special_attack(&self) -> u16 { + self.inner.special_attack.value() + } + pub fn special_defense(&self) -> u16 { + self.inner.special_defense.value() + } + pub fn speed(&self) -> u16 { + self.inner.speed.value() + } +} + +struct FormInner { + reference: ExternRef, + name: CachedValue, + height: CachedValue, + weight: CachedValue, + types: CachedValue>, + base_experience: CachedValue, + base_stats: CachedValue, + abilities: CachedValue>, + hidden_abilities: CachedValue>, + // moves: CachedValue, +} + +#[derive(Clone)] +pub struct Form { + inner: Rc, +} + +impl Form { + pub(crate) fn new(reference: ExternRef) -> Self { + Self::from_ref(reference, &|reference| Self { + inner: Rc::new(FormInner { + reference, + name: cached_value!({ form_get_name(reference).get_value().unwrap() }), + height: cached_value!({ form_get_height(reference) }), + weight: cached_value!({ form_get_weight(reference) }), + types: cached_value!({ + let raw = form_get_types(reference); + Vec::from_raw_parts(raw.ptr(), raw.len(), raw.len()) + }), + base_experience: cached_value!({ form_get_base_experience(reference) }), + base_stats: cached_value!({ form_get_base_stats(reference).get_value().unwrap() }), + abilities: cached_value!({ form_get_abilities(reference).get_immutable_list() }), + hidden_abilities: cached_value!({ + form_get_hidden_abilities(reference).get_immutable_list() + }), + }), + }) + } + + pub(crate) fn reference(&self) -> ExternRef { + self.inner.reference + } + + cached_value_getters! { + pub fn name(&self) -> StringKey; + pub fn height(&self) -> f32; + pub fn weight(&self) -> f32; + pub fn base_experience(&self) -> u32; + pub fn base_stats(&self) -> ImmutableStatisticSet; + pub fn abilities(&self) -> ImmutableList; + pub fn hidden_abilities(&self) -> ImmutableList; + } + pub fn types(&self) -> &Vec { + self.inner.types.value_ref() + } + + pub fn has_flag(&self, flag: &[u8; N]) -> bool { + let hash = get_hash(flag); + unsafe { form_has_flag_by_hash(self.inner.reference, hash) } + } +} + +pub struct SpeciesInner { + reference: ExternRef, + id: CachedValue, + name: CachedValue, + gender_rate: CachedValue, + growth_rate: CachedValue, + capture_rate: CachedValue, + forms: RwLock>>, +} + +#[derive(Clone)] +pub struct Species { + inner: Rc, +} + +impl Species { + pub(crate) fn new(reference: ExternRef) -> Self { + Self { + inner: Rc::new(SpeciesInner { + reference, + id: cached_value!({ species_get_id(reference) }), + name: cached_value!({ species_get_name(reference).get_value().unwrap() }), + gender_rate: cached_value!({ species_get_gender_rate(reference) }), + growth_rate: cached_value!({ + species_get_growth_rate(reference).get_value().unwrap() + }), + capture_rate: cached_value!({ species_get_capture_rate(reference) }), + forms: Default::default(), + }), + } + } + + pub(crate) fn reference(&self) -> ExternRef { + self.inner.reference + } + + cached_value_getters! { + /// The national dex identifier of the Pokemon. + pub fn id(&self) -> u16; + /// The name of the Pokemon species. + pub fn name(&self) -> StringKey; + /// The chance between 0.0 and 1.0 that a Pokemon is female. + pub fn gender_rate(&self) -> f32; + /// How much experience is required for a level. + pub fn growth_rate(&self) -> StringKey; + /// How hard it is to capture a Pokemon. 255 means this will be always caught, 0 means this is + /// uncatchable. + pub fn capture_rate(&self) -> u8; + } + + pub fn get_form(&self, form_name: &[u8; N]) -> Option { + let hash = get_hash(form_name); + unsafe { + if let Some(v) = self.inner.forms.read().get(&hash) { + v.clone() + } else { + let r = species_get_form_by_hash(self.inner.reference, hash); + let value = r.get_value(); + self.inner.forms.write().insert(hash, value.clone()); + value + } + } + } + + pub fn has_flag(&self, flag: &[u8; N]) -> bool { + let hash = get_hash(flag); + unsafe { species_has_flag_by_hash(self.inner.reference, hash) } + } +} + +impl ExternalReferenceType for ImmutableStatisticSet { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +impl ExternalReferenceType for Form { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +impl ExternalReferenceType for Species { + fn from_extern_value(reference: ExternRef) -> Self { + Self::new(reference) + } +} + +crate::handling::cacheable::cacheable!(ImmutableStatisticSet); +crate::handling::cacheable::cacheable!(Form); +crate::handling::cacheable::cacheable!(Species); + +extern "wasm" { + fn static_statistics_set_get_hp(r: ExternRef) -> u16; + fn static_statistics_set_get_attack(r: ExternRef) -> u16; + fn static_statistics_set_get_defense(r: ExternRef) -> u16; + fn static_statistics_set_get_special_attack(r: ExternRef) -> u16; + fn static_statistics_set_get_special_defense(r: ExternRef) -> u16; + fn static_statistics_set_get_speed(r: ExternRef) -> u16; + + fn form_get_name(r: ExternRef) -> ExternRef; + fn form_get_height(r: ExternRef) -> f32; + fn form_get_weight(r: ExternRef) -> f32; + fn form_get_types(r: ExternRef) -> FFIArray; + fn form_get_base_experience(r: ExternRef) -> u32; + fn form_get_base_stats(r: ExternRef) -> ExternRef; + fn form_get_abilities(r: ExternRef) -> VecExternRef; + fn form_get_hidden_abilities(r: ExternRef) -> VecExternRef; + fn form_has_flag_by_hash(r: ExternRef, hash: u32) -> bool; + + fn species_get_id(r: ExternRef) -> u16; + fn species_get_name(r: ExternRef) -> ExternRef; + fn species_get_gender_rate(r: ExternRef) -> f32; + fn species_get_growth_rate(r: ExternRef) -> ExternRef; + fn species_get_capture_rate(r: ExternRef) -> u8; + fn species_get_form_by_hash(r: ExternRef, hash: u32) -> ExternRef; + fn species_has_flag_by_hash(r: ExternRef, flag_hash: u32) -> bool; +} diff --git a/pkmn_lib_interface/src/handling/cacheable.rs b/pkmn_lib_interface/src/handling/cacheable.rs index ba79e73..8edd186 100644 --- a/pkmn_lib_interface/src/handling/cacheable.rs +++ b/pkmn_lib_interface/src/handling/cacheable.rs @@ -21,7 +21,7 @@ pub trait Cacheable { } macro_rules! cacheable { - ($type: ident) => { + ($type: ty) => { paste::paste!{ static mut [<$type:upper _CACHE>]: alloc::collections::BTreeMap, $type> = alloc::collections::BTreeMap::new(); diff --git a/pkmn_lib_interface/src/handling/cached_value.rs b/pkmn_lib_interface/src/handling/cached_value.rs index b5700fe..8af5823 100644 --- a/pkmn_lib_interface/src/handling/cached_value.rs +++ b/pkmn_lib_interface/src/handling/cached_value.rs @@ -5,10 +5,7 @@ pub struct CachedValue { value: Option, } -impl CachedValue -where - T: Clone, -{ +impl CachedValue { pub fn new(init_fn: Box T>) -> Self { Self { init_fn, @@ -16,16 +13,30 @@ where } } - #[inline] - pub fn value(&self) -> T { + #[inline(always)] + fn init_if_empty(&self) { if self.value.is_none() { unsafe { let s = self as *const Self as *mut Self; s.as_mut().unwrap().value.replace((self.init_fn)()); } } + } + + #[inline] + pub fn value(&self) -> T + where + T: Clone, + { + self.init_if_empty(); self.value.as_ref().unwrap().clone() } + + #[inline] + pub fn value_ref(&self) -> &T { + self.init_if_empty(); + self.value.as_ref().unwrap() + } } #[macro_export] @@ -34,3 +45,20 @@ macro_rules! cached_value { CachedValue::new(alloc::boxed::Box::new(move || unsafe { $init })) }; } + +#[macro_export] +macro_rules! cached_value_getters { + ( + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { + $( + $(#[$attr])* + $v fn $name(&self) -> $type { + self.inner.$name.value() + } + )* + }; +} diff --git a/pkmn_lib_interface/src/handling/extern_ref.rs b/pkmn_lib_interface/src/handling/extern_ref.rs index dedf95e..6ea9a25 100644 --- a/pkmn_lib_interface/src/handling/extern_ref.rs +++ b/pkmn_lib_interface/src/handling/extern_ref.rs @@ -14,6 +14,10 @@ impl ExternRef { self.p == 0 } + pub(crate) fn get_internal_index(&self) -> u32 { + self.p + } + pub fn get_value(&self) -> Option where T: ExternalReferenceType, @@ -22,6 +26,14 @@ impl ExternRef { { T::instantiate_from_extern_value(*self) } + + #[inline] + pub(crate) fn cast(&self) -> ExternRef { + ExternRef:: { + p: self.p, + resource_type: Default::default(), + } + } } impl Clone for ExternRef { @@ -71,12 +83,12 @@ impl VecExternRef { v.0 } - pub fn len(&self) -> u32 { + pub(crate) fn len(&self) -> u32 { let v: (u32, u32) = unsafe { transmute(self.v) }; v.1 } - pub fn at(&self, index: u32) -> ExternRef { + pub(crate) fn at(&self, index: u32) -> ExternRef { let p = unsafe { _vec_extern_ref_get_value(self.get_internal_index(), index) }; ExternRef { p, @@ -84,12 +96,12 @@ impl VecExternRef { } } - pub fn get_immutable_list(&self) -> ImmutableList + pub(crate) fn get_immutable_list(&self) -> ImmutableList where T: Clone, T: ExternalReferenceType, { - ImmutableList::from_ref(self.clone()) + ImmutableList::from_ref(*self) } } diff --git a/pkmn_lib_interface/src/handling/mod.rs b/pkmn_lib_interface/src/handling/mod.rs index 60684d9..d82784b 100644 --- a/pkmn_lib_interface/src/handling/mod.rs +++ b/pkmn_lib_interface/src/handling/mod.rs @@ -4,6 +4,7 @@ pub mod capabilities; pub mod extern_ref; pub mod ffi_array; pub mod script; +pub(crate) mod temporary; pub use capabilities::*; @@ -20,3 +21,102 @@ pub enum ScriptCategory { Side, ItemBattleTrigger, } + +#[macro_export] +macro_rules! wasm_reference_getters { + ( + $base_type:ty, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { + impl $base_type { + $( + $(#[$attr])* + $v fn $name(&self) -> $type { + paste::paste!{ + unsafe{ + [<$base_type:snake _get_ $name>](self.inner.reference).get_value().unwrap() + } + } + } + )* + + } + + extern "wasm" { + $( + paste::paste!{ + fn [<$base_type:snake _get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>; + } + )* + } + }; +} + +#[macro_export] +macro_rules! wasm_optional_reference_getters { + ( + $base_type:ty, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> Option<$type:ty>; + )* + ) => { + impl $base_type { + $( + $(#[$attr])* + $v fn $name(&self) -> Option<$type> { + paste::paste!{ + unsafe{ + [<$base_type:snake get_ $name>](self.inner.reference).get_value() + } + } + } + )* + + } + + extern "wasm" { + $( + paste::paste!{ + fn [<$base_type:snake get_ $name>](r: ExternRef<$base_type>) -> ExternRef<$type>; + } + )* + } + }; +} + +#[macro_export] +macro_rules! wasm_value_getters { + ( + $base_type:ty, + $( + $(#[$attr:meta])* + $v:vis fn $name:ident(&self) -> $type:ty; + )* + ) => { + impl $base_type { + $( + $(#[$attr])* + $v fn $name(&self) -> $type { + paste::paste!{ + unsafe{ + [<$base_type:snake get_ $name>](self.inner.reference) + } + } + } + )* + + } + + extern "wasm" { + $( + paste::paste!{ + fn [<$base_type:snake get_ $name>](r: ExternRef<$base_type>) -> $type; + } + )* + } + }; +} diff --git a/pkmn_lib_interface/src/handling/script.rs b/pkmn_lib_interface/src/handling/script.rs index 820acea..5902e3e 100644 --- a/pkmn_lib_interface/src/handling/script.rs +++ b/pkmn_lib_interface/src/handling/script.rs @@ -1,7 +1,7 @@ use crate::app_interface::list::ImmutableList; -use crate::app_interface::{BaseTurnChoice, BattleLibrary, EffectParameter}; +use crate::app_interface::{DynamicLibrary, EffectParameter}; use crate::handling::ScriptCapabilities; -use crate::ExternRef; +use crate::{ExternRef, TurnChoice}; use core::ffi::c_void; use core::fmt::Debug; @@ -15,11 +15,11 @@ pub trait Script { fn on_initialize( &self, - _library: &BattleLibrary, + _library: &DynamicLibrary, _parameters: Option>, ) { } - fn on_before_turn(&self, _choice: ExternRef) {} + fn on_before_turn(&self, _choice: TurnChoice) {} } impl Debug for dyn Script { diff --git a/pkmn_lib_interface/src/handling/temporary.rs b/pkmn_lib_interface/src/handling/temporary.rs new file mode 100644 index 0000000..9bfca69 --- /dev/null +++ b/pkmn_lib_interface/src/handling/temporary.rs @@ -0,0 +1,87 @@ +use crate::{dbg, println, ExternRef, ExternalReferenceType}; +use alloc::boxed::Box; +use core::cell::Cell; +use core::mem::forget; + +struct TemporaryData { + use_count: Cell, + is_deleted: bool, + value: T, +} + +pub struct Temporary { + value: *mut TemporaryData, +} + +static mut TEMPORARIES: alloc::collections::BTreeMap = + alloc::collections::BTreeMap::new(); +impl Temporary +where + T: ExternalReferenceType, + T: Clone, +{ + pub fn from_reference(reference: ExternRef) -> Self { + let temporaries = unsafe { &mut TEMPORARIES }; + let existing = temporaries.get(&reference.get_internal_index()); + unsafe { + if let Some(v) = existing { + let rc = (*v as *mut TemporaryData).as_mut().unwrap(); + if !rc.is_deleted { + *rc.use_count.get_mut() += 1; + return Self { + value: rc as *mut TemporaryData, + }; + } + } + } + + let value = reference.get_value().unwrap(); + let mut reference_counter = TemporaryData { + use_count: Cell::new(1), + is_deleted: false, + value, + }; + let ptr = &mut reference_counter as *mut TemporaryData; + forget(reference_counter); + temporaries.insert(reference.get_internal_index(), ptr as *const u8); + Self { value: ptr } + } + + pub fn value(&self) -> T { + unsafe { self.value.as_ref().unwrap().value.clone() } + } + + pub(crate) fn mark_as_deleted(reference: ExternRef) { + let temporaries = unsafe { &mut TEMPORARIES }; + let existing = temporaries.get(&reference.get_internal_index()); + unsafe { + if let Some(v) = existing { + crate::utils::print_raw(b"Dropping temporary"); + let rc = (*v as *mut TemporaryData).as_mut().unwrap(); + rc.is_deleted = true; + if rc.use_count.get() == 0 { + drop(Box::from(*v as *mut TemporaryData)) + } + temporaries.remove(&reference.get_internal_index()); + } + } + } +} + +impl Clone for Temporary { + fn clone(&self) -> Self { + *unsafe { self.value.as_mut() }.unwrap().use_count.get_mut() += 1; + Self { value: self.value } + } +} + +impl Drop for Temporary { + fn drop(&mut self) { + let data = unsafe { self.value.as_mut() }.unwrap(); + let v = data.use_count.get_mut(); + *v -= 1; + if *v == 0 && data.is_deleted { + drop(Box::from(self.value)) + } + } +} diff --git a/pkmn_lib_interface/src/lib.rs b/pkmn_lib_interface/src/lib.rs index 2d91bbf..7b538c1 100644 --- a/pkmn_lib_interface/src/lib.rs +++ b/pkmn_lib_interface/src/lib.rs @@ -23,7 +23,7 @@ extern crate wee_alloc; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; use crate::app_interface::list::ImmutableList; -use crate::app_interface::{BaseTurnChoice, BattleLibrary, EffectParameter, StringKey}; +use crate::app_interface::{DynamicLibrary, EffectParameter, StringKey, TurnChoice}; pub(crate) use crate::handling::extern_ref::*; use crate::handling::ffi_array::FFIArray; use crate::handling::{Script, ScriptCapabilities, ScriptCategory}; @@ -57,10 +57,10 @@ extern "wasm" fn load_script(category: ScriptCategory, name: ExternRef) { // By turning it from a raw pointer back into a Box with from_raw, we give ownership back to rust. // This lets Rust do the cleanup. - let boxed_script = Box::from_raw(script as *mut Box); + let boxed_script = Box::from_raw(script); boxed_script.destroy(); } @@ -75,10 +75,10 @@ unsafe extern "wasm" fn get_script_capabilities( #[no_mangle] unsafe extern "wasm" fn script_on_initialize( script: *const Box, - library: ExternRef, + library: ExternRef, parameters: VecExternRef, ) { - let lib = BattleLibrary::new(library); + let lib = DynamicLibrary::new(library); let parameters = ImmutableList::from_ref(parameters); script .as_ref() @@ -90,7 +90,11 @@ unsafe extern "wasm" fn script_on_initialize( #[no_mangle] unsafe extern "wasm" fn script_on_before_turn( script: *const Box, - choice: ExternRef, + choice: ExternRef, ) { - script.as_ref().unwrap().as_ref().on_before_turn(choice) + script + .as_ref() + .unwrap() + .as_ref() + .on_before_turn(choice.get_value().unwrap()) }