A lot of work on type registration

This commit is contained in:
Deukhoofd 2022-08-14 13:37:17 +02:00
parent 174137dcf6
commit f06d46d854
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
39 changed files with 1910 additions and 361 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
Cargo.lock
bin/
.idea
gen7_scripts.wat

View File

@ -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<ImmutableList<EffectParameter>>,
) {
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()
);
}
}

View File

@ -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

View File

@ -1,18 +0,0 @@
use crate::app_interface::StaticData;
use crate::{impl_extern_ctor, ExternRef};
pub struct BattleLibrary {
ptr: ExternRef<BattleLibrary>,
}
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<BattleLibrary>) -> ExternRef<StaticData>;
}

View File

@ -1,5 +0,0 @@
mod battle_library;
mod turn_choices;
pub use battle_library::BattleLibrary;
pub use turn_choices::*;

View File

@ -1 +0,0 @@
pub struct BaseTurnChoice {}

View File

@ -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<Battle>,
library: CachedValue<DynamicLibrary>,
parties: CachedValue<ImmutableList<BattleParty>>,
sides: CachedValue<ImmutableList<BattleSide>>,
random: CachedValue<BattleRandom>,
}
#[derive(Clone)]
pub struct Battle {
inner: Rc<BattleInner>,
}
impl Battle {
pub fn new(reference: ExternRef<Battle>) -> 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<BattleParty>;
pub fn sides(&self) -> ImmutableList<BattleSide>;
}
pub fn get_pokemon(&self, side: u8, index: u8) -> Option<Pokemon> {
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 {
Self::new(reference)
}
}
extern "wasm" {
fn battle_get_library(r: ExternRef<Battle>) -> ExternRef<DynamicLibrary>;
fn battle_get_parties(r: ExternRef<Battle>) -> VecExternRef<BattleParty>;
fn battle_get_sides(r: ExternRef<Battle>) -> VecExternRef<BattleSide>;
fn battle_get_random(r: ExternRef<Battle>) -> ExternRef<BattleRandom>;
fn battle_get_pokemon(r: ExternRef<Battle>, side: u8, index: u8) -> ExternRef<Pokemon>;
}

View File

@ -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<BattleParty>,
party: CachedValue<Party>,
}
#[derive(Clone)]
pub struct BattleParty {
inner: Rc<BattlePartyInner>,
}
impl BattleParty {
pub fn new(reference: ExternRef<BattleParty>) -> 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 {
Self::new(reference)
}
}
extern "wasm" {
fn battle_party_get_party(r: ExternRef<BattleParty>) -> ExternRef<Party>;
}

View File

@ -0,0 +1,32 @@
use crate::{ExternRef, ExternalReferenceType};
#[derive(Clone)]
pub struct BattleRandom {
reference: ExternRef<Self>,
}
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 {
Self { reference }
}
}
extern "wasm" {
fn battle_random_get(r: ExternRef<BattleRandom>) -> i32;
fn battle_random_get_max(r: ExternRef<BattleRandom>, max: i32) -> i32;
fn battle_random_get_between(r: ExternRef<BattleRandom>, min: i32, max: i32) -> i32;
}

View File

@ -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<BattleSide>,
side_index: CachedValue<u8>,
pokemon_per_side: CachedValue<u8>,
battle: CachedValue<Battle>,
}
#[derive(Clone)]
pub struct BattleSide {
inner: Rc<BattleSideInner>,
}
impl BattleSide {
pub fn new(reference: ExternRef<Self>) -> 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<Pokemon> {
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 {
Self::new(reference)
}
}
extern "wasm" {
fn battleside_get_side_index(r: ExternRef<BattleSide>) -> u8;
fn battleside_get_pokemon_per_side(r: ExternRef<BattleSide>) -> u8;
fn battleside_get_battle(r: ExternRef<BattleSide>) -> ExternRef<Battle>;
fn battleside_get_pokemon(r: ExternRef<BattleSide>, index: usize) -> ExternRef<Pokemon>;
}

View File

@ -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<DynamicLibrary>,
static_data: CachedValue<StaticData>,
}
#[derive(Clone)]
pub struct DynamicLibrary {
inner: Rc<DynamicLibraryInner>,
}
crate::handling::cacheable::cacheable!(DynamicLibrary);
impl DynamicLibrary {
pub(crate) fn new(ptr: ExternRef<Self>) -> 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>) -> Self {
DynamicLibrary::new(reference)
}
}
extern "wasm" {
fn dynamic_library_get_static_data(ptr: ExternRef<DynamicLibrary>) -> ExternRef<StaticData>;
}

View File

@ -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<LearnedMove>,
move_data: CachedValue<MoveData>,
learn_method: CachedValue<MoveLearnMethod>,
}
#[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<LearnedMoveInner>,
}
crate::handling::cacheable::cacheable!(LearnedMove);
impl ExternalReferenceType for LearnedMove {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
impl LearnedMove {
pub fn new(reference: ExternRef<Self>) -> 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<LearnedMove>) -> ExternRef<MoveData>;
fn learned_move_get_learn_method(r: ExternRef<LearnedMove>) -> MoveLearnMethod;
fn learned_move_restore_uses(r: ExternRef<LearnedMove>, uses: u8);
fn learned_move_restore_all_uses(r: ExternRef<LearnedMove>);
}

View File

@ -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::*;

View File

@ -0,0 +1,27 @@
use crate::app_interface::Pokemon;
use crate::{ExternRef, ExternalReferenceType};
#[derive(Clone)]
pub struct Party {
reference: ExternRef<Party>,
}
impl Party {
pub fn new(reference: ExternRef<Party>) -> Self {
Self { reference }
}
pub fn get_pokemon(&self, index: usize) -> Option<Pokemon> {
unsafe { party_get_pokemon(self.reference, index).get_value() }
}
}
impl ExternalReferenceType for Party {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
extern "wasm" {
fn party_get_pokemon(r: ExternRef<Party>, index: usize) -> ExternRef<Pokemon>;
}

View File

@ -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<Pokemon>,
library: CachedValue<DynamicLibrary>,
// We cache the reference to the data, not the values stored inside, which are dynamic.
flat_stats: CachedValue<StatisticSet<u32>>,
// We cache the reference to the data, not the values stored inside, which are dynamic.
stat_boosts: CachedValue<ClampedStatisticSet<i8>>,
// We cache the reference to the data, not the values stored inside, which are dynamic.
boosted_stats: CachedValue<StatisticSet<u32>>,
// We cache the reference to the data, not the values stored inside, which are dynamic.
individual_values: CachedValue<ClampedStatisticSet<u8>>,
// We cache the reference to the data, not the values stored inside, which are dynamic.
effort_values: CachedValue<ClampedStatisticSet<u8>>,
}
#[derive(Clone)]
pub struct Pokemon {
inner: Rc<PokemonInner>,
}
impl Pokemon {
pub(crate) fn new(reference: ExternRef<Self>) -> 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<u32>;
pub fn stat_boosts(&self) -> ClampedStatisticSet<i8>;
pub fn boosted_stats(&self) -> StatisticSet<u32>;
pub fn individual_values(&self) -> ClampedStatisticSet<u8>;
pub fn effort_values(&self) -> ClampedStatisticSet<u8>;
}
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<Item> {
unsafe { pokemon_set_held_item(self.inner.reference, item.reference()).get_value() }
}
pub fn remove_held_item(&self) -> Option<Item> {
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<LearnedMove> {
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<dyn Script>> {
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<Species>;
pub fn display_form(&self) -> Option<Form>;
pub fn held_item(&self) -> Option<Item>;
pub fn battle(&self) -> Option<Battle>;
}
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 {
Self::new(reference)
}
}
extern "wasm" {
fn pokemon_get_library(r: ExternRef<Pokemon>) -> ExternRef<DynamicLibrary>;
fn pokemon_get_flat_stats(r: ExternRef<Pokemon>) -> ExternRef<StatisticSet<u32>>;
fn pokemon_get_stat_boosts(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<i8>>;
fn pokemon_get_boosted_stats(r: ExternRef<Pokemon>) -> ExternRef<StatisticSet<u32>>;
fn pokemon_get_individual_values(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<u8>>;
fn pokemon_get_effort_values(r: ExternRef<Pokemon>) -> ExternRef<ClampedStatisticSet<u8>>;
fn pokemon_has_held_item(r: ExternRef<Pokemon>, name: *const c_char) -> bool;
fn pokemon_set_held_item(r: ExternRef<Pokemon>, item: ExternRef<Item>) -> ExternRef<Item>;
fn pokemon_remove_held_item(r: ExternRef<Pokemon>) -> ExternRef<Item>;
fn pokemon_consume_held_item(r: ExternRef<Pokemon>) -> bool;
fn pokemon_get_type(r: ExternRef<Pokemon>, index: usize) -> u8;
fn pokemon_has_type(r: ExternRef<Pokemon>, identifier: u8) -> bool;
fn pokemon_get_learned_move(r: ExternRef<Pokemon>, index: usize) -> ExternRef<LearnedMove>;
fn pokemon_change_stat_boost(
r: ExternRef<Pokemon>,
tat: Statistic,
diff_amount: i8,
self_inflicted: bool,
) -> bool;
fn pokemon_get_ability_script(r: ExternRef<Pokemon>) -> *const Box<dyn Script>;
fn pokemon_change_species(
r: ExternRef<Pokemon>,
species: ExternRef<Species>,
form: ExternRef<Form>,
);
fn pokemon_change_form(r: ExternRef<Pokemon>, form: ExternRef<Form>);
fn pokemon_damage(r: ExternRef<Pokemon>, damage: u32, source: DamageSource);
fn pokemon_heal(r: ExternRef<Pokemon>, amount: u32, allow_revive: bool) -> bool;
}

View File

@ -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<T>
where
T: TryFrom<i64>,
T: TryInto<i64>,
{
reference: ExternRef<Self>,
_p: PhantomData<T>,
}
impl<T> StatisticSet<T>
where
T: TryFrom<i64>,
T: TryInto<i64>,
<T as TryFrom<i64>>::Error: Debug,
<T as TryInto<i64>>::Error: Debug,
{
pub(crate) fn new(reference: ExternRef<Self>) -> 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<T> ExternalReferenceType for StatisticSet<T>
where
T: TryFrom<i64>,
T: TryInto<i64>,
<T as TryFrom<i64>>::Error: Debug,
<T as TryInto<i64>>::Error: Debug,
{
fn from_extern_value(reference: ExternRef<Self>) -> Self {
StatisticSet::<T>::new(reference)
}
}
#[derive(Clone)]
pub struct ClampedStatisticSet<T>
where
T: TryFrom<i64>,
T: TryInto<i64>,
{
reference: ExternRef<Self>,
_p: PhantomData<T>,
}
impl<T> ClampedStatisticSet<T>
where
T: TryFrom<i64>,
T: TryInto<i64>,
<T as TryFrom<i64>>::Error: Debug,
<T as TryInto<i64>>::Error: Debug,
{
pub(crate) fn new(reference: ExternRef<Self>) -> 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<T> ExternalReferenceType for ClampedStatisticSet<T>
where
T: TryFrom<i64>,
T: TryInto<i64>,
<T as TryFrom<i64>>::Error: Debug,
<T as TryInto<i64>>::Error: Debug,
{
fn from_extern_value(reference: ExternRef<Self>) -> Self {
ClampedStatisticSet::<T>::new(reference)
}
}
extern "wasm" {
fn statistic_set_get(r: ExternRef<StatisticSet<i64>>, stat: Statistic) -> i64;
fn statistic_set_set(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64);
fn statistic_set_increase_stat(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64);
fn statistic_set_decrease_stat(r: ExternRef<StatisticSet<i64>>, stat: Statistic, value: i64);
fn clamped_statistic_set_get(r: ExternRef<ClampedStatisticSet<i64>>, stat: Statistic) -> i64;
fn clamped_statistic_set_set(
r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic,
value: i64,
);
fn clamped_statistic_set_increase_stat(
r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic,
value: i64,
) -> bool;
fn clamped_statistic_set_decrease_stat(
r: ExternRef<ClampedStatisticSet<i64>>,
stat: Statistic,
value: i64,
) -> bool;
}

View File

@ -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<TurnChoice>,
user: CachedValue<Pokemon>,
}
struct MoveTurnChoiceDataInner {
base: BaseTurnChoiceData,
}
#[derive(Clone)]
struct MoveTurnChoiceDataTemporary {
inner: Rc<MoveTurnChoiceDataInner>,
}
pub struct MoveTurnChoiceData {
temp: Temporary<MoveTurnChoiceDataTemporary>,
}
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>) -> 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 {
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<TurnChoice>) -> u8;
fn turn_choice_get_user(r: ExternRef<TurnChoice>) -> ExternRef<Pokemon>;
}
#[no_mangle]
unsafe extern "wasm" fn turn_choice_mark_deleted(r: ExternRef<TurnChoice>, kind: u8) {
match kind {
0 => Temporary::<MoveTurnChoiceDataTemporary>::mark_as_deleted(r.cast()),
_ => panic!("Unknown turn choice type"),
}
}

View File

@ -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<Self>,
}
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<StaticData>) -> ExternRef<MoveLibrary>;
}
pub trait DataLibrary<T>: Cacheable
where
T: ExternalReferenceType,
T: Clone,
{
fn get_cache(&self) -> &RwLock<BTreeMap<u32, T>>;
fn get_self_ref(&self) -> ExternRef<Self>
where
Self: Sized;
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<T>
where
Self: Sized;
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<T>
where
Self: Sized;
fn get(&self, name: &StringKey) -> Option<T>
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<T>
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
}
}

View File

@ -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<ImmutableStatisticSet>,
/// The health point stat value.
hp: CachedValue<u16>,
/// The physical attack stat value.
attack: CachedValue<u16>,
/// The physical defense stat value.
defense: CachedValue<u16>,
/// The special attack stat value.
special_attack: CachedValue<u16>,
/// The special defense stat value.
special_defense: CachedValue<u16>,
/// The speed stat value.
speed: CachedValue<u16>,
}
#[derive(Clone)]
pub struct ImmutableStatisticSet {
inner: Rc<ImmutableStatisticSetInner>,
}
impl ImmutableStatisticSet {
pub(crate) fn new(ptr: ExternRef<Self>) -> 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<Form>,
name: CachedValue<StringKey>,
height: CachedValue<f32>,
weight: CachedValue<f32>,
types: CachedValue<Vec<u8>>,
base_experience: CachedValue<u32>,
base_stats: CachedValue<ImmutableStatisticSet>,
abilities: CachedValue<ImmutableList<StringKey>>,
hidden_abilities: CachedValue<ImmutableList<StringKey>>,
// moves: CachedValue<LearnableMoves>,
}
#[derive(Clone)]
pub struct Form {
inner: Rc<FormInner>,
}
impl Form {
pub(crate) fn new(ptr: ExternRef<Self>) -> 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>) -> Self {
ImmutableStatisticSet::new(reference)
}
}
crate::handling::cacheable::cacheable!(ImmutableStatisticSet);
crate::handling::cacheable::cacheable!(Form);
extern "wasm" {
fn static_statistics_set_get_hp(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_special_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_special_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_speed(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn form_get_name(r: ExternRef<Form>) -> ExternRef<StringKey>;
fn form_get_height(r: ExternRef<Form>) -> f32;
fn form_get_weight(r: ExternRef<Form>) -> f32;
fn form_get_types(r: ExternRef<Form>) -> FFIArray<u8>;
fn form_get_base_experience(r: ExternRef<Form>) -> u32;
fn form_get_base_stats(r: ExternRef<Form>) -> ExternRef<ImmutableStatisticSet>;
fn form_get_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
fn form_get_hidden_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
}

View File

@ -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;

View File

@ -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<Ability>,
name: CachedValue<StringKey>,
effect: CachedValue<StringKey>,
parameters: CachedValue<ImmutableList<EffectParameter>>,
}
#[derive(Clone)]
pub struct Ability {
inner: Rc<AbilityInner>,
}
impl Ability {
pub fn new(reference: ExternRef<Self>) -> 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 {
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<Ability>) -> ExternRef<StringKey>;
fn ability_get_effect(r: ExternRef<Ability>) -> ExternRef<StringKey>;
fn ability_get_parameters(r: ExternRef<Ability>) -> VecExternRef<EffectParameter>;
}

View File

@ -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<Item> for ItemLibrary {
}
fn get_self_ref(&self) -> ExternRef<Self> {
self.inner.ptr.clone()
self.inner.ptr
}
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<Item> {
@ -44,17 +43,14 @@ impl DataLibrary<Item> for ItemLibrary {
}
}
impl Cacheable for ItemLibrary {
fn get_cache<'a>() -> &'a mut BTreeMap<ExternRef<Self>, Self>
where
Self: Sized,
{
unsafe { &mut CACHE }
crate::handling::cacheable::cacheable!(ItemLibrary);
impl ExternalReferenceType for ItemLibrary {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
static mut CACHE: BTreeMap<ExternRef<ItemLibrary>, ItemLibrary> = BTreeMap::new();
extern "wasm" {
fn move_library_get_move(
ptr: ExternRef<ItemLibrary>,

View File

@ -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<StaticData>,
move_library: CachedValue<MoveLibrary>,
item_library: CachedValue<ItemLibrary>,
species_library: CachedValue<SpeciesLibrary>,
type_library: CachedValue<TypeLibrary>,
}
#[derive(Clone)]
pub struct StaticData {
inner: Rc<StaticDataInner>,
}
impl StaticData {
pub(crate) fn new(reference: ExternRef<StaticData>) -> 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>) -> Self {
StaticData::new(reference)
}
}
struct LibrarySettingsInner {
maximum_level: CachedValue<LevelInt>,
}
#[derive(Clone)]
pub struct LibrarySettings {
inner: Rc<LibrarySettingsInner>,
}
impl LibrarySettings {
pub(crate) fn new(ptr: ExternRef<LibrarySettings>) -> 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<StaticData>) -> ExternRef<MoveLibrary>;
fn static_data_get_item_library(ptr: ExternRef<StaticData>) -> ExternRef<ItemLibrary>;
fn static_data_get_species_library(ptr: ExternRef<StaticData>) -> ExternRef<SpeciesLibrary>;
fn static_data_get_type_library(ptr: ExternRef<StaticData>) -> ExternRef<TypeLibrary>;
fn library_settings_get_maximum_level(ptr: ExternRef<LibrarySettings>) -> LevelInt;
}
pub trait DataLibrary<T>: Cacheable
where
T: ExternalReferenceType,
T: Clone,
{
fn get_cache(&self) -> &RwLock<BTreeMap<u32, T>>;
fn get_self_ref(&self) -> ExternRef<Self>
where
Self: Sized;
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<T>
where
Self: Sized;
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<T>
where
Self: Sized;
fn get(&self, name: &StringKey) -> Option<T>
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<T>
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
}
}

View File

@ -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<MoveData> for MoveLibrary {
}
fn get_self_ref(&self) -> ExternRef<Self> {
self.inner.ptr.clone()
self.inner.ptr
}
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<MoveData> {
@ -45,17 +44,14 @@ impl DataLibrary<MoveData> for MoveLibrary {
}
}
impl Cacheable for MoveLibrary {
fn get_cache<'a>() -> &'a mut BTreeMap<ExternRef<Self>, Self>
where
Self: Sized,
{
unsafe { &mut CACHE }
crate::handling::cacheable::cacheable!(MoveLibrary);
impl ExternalReferenceType for MoveLibrary {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
static mut CACHE: BTreeMap<ExternRef<MoveLibrary>, MoveLibrary> = BTreeMap::new();
extern "wasm" {
fn move_library_get_move(
ptr: ExternRef<MoveLibrary>,

View File

@ -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<SpeciesLibrary>,
cache: RwLock<BTreeMap<u32, Species>>,
}
#[derive(Clone)]
pub struct SpeciesLibrary {
inner: Rc<SpeciesLibraryInner>,
}
impl SpeciesLibrary {
pub(crate) fn new(ptr: ExternRef<SpeciesLibrary>) -> Self {
Self {
inner: Rc::new(SpeciesLibraryInner {
ptr,
cache: Default::default(),
}),
}
}
}
impl DataLibrary<Species> for SpeciesLibrary {
fn get_cache(&self) -> &spin::rwlock::RwLock<BTreeMap<u32, Species>> {
&self.inner.cache
}
fn get_self_ref(&self) -> ExternRef<Self> {
self.inner.ptr
}
fn _get_ref_by_name(ptr: ExternRef<Self>, name: ExternRef<StringKey>) -> ExternRef<Species> {
unsafe { species_library_get_species(ptr, name) }
}
fn _get_ref_by_hash(ptr: ExternRef<Self>, hash: u32) -> ExternRef<Species> {
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 {
Self::new(reference)
}
}
extern "wasm" {
fn species_library_get_species(
ptr: ExternRef<SpeciesLibrary>,
name: ExternRef<StringKey>,
) -> ExternRef<Species>;
fn species_library_get_species_by_hash(
ptr: ExternRef<SpeciesLibrary>,
hash: u32,
) -> ExternRef<Species>;
}

View File

@ -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<TypeLibrary>,
name_to_type_cache: RwLock<BTreeMap<String, u8>>,
effectiveness_cache: RwLock<BTreeMap<(u8, u8), f32>>,
}
#[derive(Clone)]
pub struct TypeLibrary {
inner: Rc<TypeLibraryInner>,
}
impl TypeLibrary {
pub(crate) fn new(reference: ExternRef<Self>) -> 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<u8> {
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 {
Self::new(reference)
}
}
extern "wasm" {
fn type_library_get_single_effectiveness(
r: ExternRef<TypeLibrary>,
attacking_type: u8,
defending_type: u8,
) -> f32;
fn type_library_get_type_by_name(r: ExternRef<TypeLibrary>, name: *const c_char) -> u8;
}

View File

@ -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<Item>,
reference: ExternRef<Item>,
name: CachedValue<StringKey>,
category: CachedValue<ItemCategory>,
battle_category: CachedValue<BattleItemCategory>,
@ -56,40 +56,35 @@ pub struct Item {
}
impl Item {
pub(crate) fn new(ptr: ExternRef<Self>) -> Self {
Self::from_ref(ptr, &|ptr| Self {
pub(crate) fn new(reference: ExternRef<Self>) -> 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> {
self.inner.ptr
pub(crate) fn reference(&self) -> ExternRef<Self> {
self.inner.reference
}
cached_value_getters! {
/// The name of the item.
pub fn name(&self) -> StringKey {
self.inner.name.value()
}
pub fn name(&self) -> StringKey;
/// Which bag slot items are stored in.
pub fn category(&self) -> ItemCategory {
self.inner.category.value()
}
pub fn category(&self) -> ItemCategory;
/// How the item is categorized when in battle.
pub fn battle_category(&self) -> BattleItemCategory {
self.inner.battle_category.value()
}
pub fn battle_category(&self) -> BattleItemCategory;
/// The buying value of the item.
pub fn price(&self) -> i32 {
self.inner.price.value()
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()) }
}
}

View File

@ -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;

View File

@ -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> {
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<const N: usize>(&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<MoveData>) -> u8;
fn move_data_get_target(ptr: ExternRef<MoveData>) -> MoveTarget;
fn move_data_get_priority(ptr: ExternRef<MoveData>) -> i8;
fn move_data_has_flag(ptr: ExternRef<MoveData>, flag: ExternRef<StringKey>) -> bool;
fn move_data_has_flag_by_hash(ptr: ExternRef<MoveData>, flag_hash: u32) -> bool;
}

View File

@ -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<Nature>,
/// 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<NatureInner>,
}
crate::handling::cacheable::cacheable!(Nature);
impl Nature {
pub fn new(reference: ExternRef<Self>) -> 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 {
Self::new(reference)
}
}
extern "wasm" {
fn nature_get_increase_stat(r: ExternRef<Nature>) -> Statistic;
fn nature_get_decrease_stat(r: ExternRef<Nature>) -> Statistic;
fn nature_get_increase_modifier(r: ExternRef<Nature>) -> f32;
fn nature_get_decrease_modifier(r: ExternRef<Nature>) -> f32;
}

View File

@ -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<ImmutableStatisticSet>,
/// The health point stat value.
hp: CachedValue<u16>,
/// The physical attack stat value.
attack: CachedValue<u16>,
/// The physical defense stat value.
defense: CachedValue<u16>,
/// The special attack stat value.
special_attack: CachedValue<u16>,
/// The special defense stat value.
special_defense: CachedValue<u16>,
/// The speed stat value.
speed: CachedValue<u16>,
}
#[derive(Clone)]
pub struct ImmutableStatisticSet {
inner: Rc<ImmutableStatisticSetInner>,
}
impl ImmutableStatisticSet {
pub(crate) fn new(reference: ExternRef<Self>) -> 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<Form>,
name: CachedValue<StringKey>,
height: CachedValue<f32>,
weight: CachedValue<f32>,
types: CachedValue<Vec<u8>>,
base_experience: CachedValue<u32>,
base_stats: CachedValue<ImmutableStatisticSet>,
abilities: CachedValue<ImmutableList<StringKey>>,
hidden_abilities: CachedValue<ImmutableList<StringKey>>,
// moves: CachedValue<LearnableMoves>,
}
#[derive(Clone)]
pub struct Form {
inner: Rc<FormInner>,
}
impl Form {
pub(crate) fn new(reference: ExternRef<Self>) -> 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> {
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<StringKey>;
pub fn hidden_abilities(&self) -> ImmutableList<StringKey>;
}
pub fn types(&self) -> &Vec<u8> {
self.inner.types.value_ref()
}
pub fn has_flag<const N: usize>(&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<Species>,
id: CachedValue<u16>,
name: CachedValue<StringKey>,
gender_rate: CachedValue<f32>,
growth_rate: CachedValue<StringKey>,
capture_rate: CachedValue<u8>,
forms: RwLock<BTreeMap<u32, Option<Form>>>,
}
#[derive(Clone)]
pub struct Species {
inner: Rc<SpeciesInner>,
}
impl Species {
pub(crate) fn new(reference: ExternRef<Species>) -> 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> {
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<const N: usize>(&self, form_name: &[u8; N]) -> Option<Form> {
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<const N: usize>(&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 {
Self::new(reference)
}
}
impl ExternalReferenceType for Form {
fn from_extern_value(reference: ExternRef<Self>) -> Self {
Self::new(reference)
}
}
impl ExternalReferenceType for Species {
fn from_extern_value(reference: ExternRef<Self>) -> 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<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_special_attack(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_special_defense(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn static_statistics_set_get_speed(r: ExternRef<ImmutableStatisticSet>) -> u16;
fn form_get_name(r: ExternRef<Form>) -> ExternRef<StringKey>;
fn form_get_height(r: ExternRef<Form>) -> f32;
fn form_get_weight(r: ExternRef<Form>) -> f32;
fn form_get_types(r: ExternRef<Form>) -> FFIArray<u8>;
fn form_get_base_experience(r: ExternRef<Form>) -> u32;
fn form_get_base_stats(r: ExternRef<Form>) -> ExternRef<ImmutableStatisticSet>;
fn form_get_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
fn form_get_hidden_abilities(r: ExternRef<Form>) -> VecExternRef<StringKey>;
fn form_has_flag_by_hash(r: ExternRef<Form>, hash: u32) -> bool;
fn species_get_id(r: ExternRef<Species>) -> u16;
fn species_get_name(r: ExternRef<Species>) -> ExternRef<StringKey>;
fn species_get_gender_rate(r: ExternRef<Species>) -> f32;
fn species_get_growth_rate(r: ExternRef<Species>) -> ExternRef<StringKey>;
fn species_get_capture_rate(r: ExternRef<Species>) -> u8;
fn species_get_form_by_hash(r: ExternRef<Species>, hash: u32) -> ExternRef<Form>;
fn species_has_flag_by_hash(r: ExternRef<Species>, flag_hash: u32) -> bool;
}

View File

@ -21,7 +21,7 @@ pub trait Cacheable {
}
macro_rules! cacheable {
($type: ident) => {
($type: ty) => {
paste::paste!{
static mut [<$type:upper _CACHE>]: alloc::collections::BTreeMap<ExternRef<$type>, $type> =
alloc::collections::BTreeMap::new();

View File

@ -5,10 +5,7 @@ pub struct CachedValue<T> {
value: Option<T>,
}
impl<T> CachedValue<T>
where
T: Clone,
{
impl<T> CachedValue<T> {
pub fn new(init_fn: Box<dyn Fn() -> 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()
}
)*
};
}

View File

@ -14,6 +14,10 @@ impl<T> ExternRef<T> {
self.p == 0
}
pub(crate) fn get_internal_index(&self) -> u32 {
self.p
}
pub fn get_value(&self) -> Option<T>
where
T: ExternalReferenceType,
@ -22,6 +26,14 @@ impl<T> ExternRef<T> {
{
T::instantiate_from_extern_value(*self)
}
#[inline]
pub(crate) fn cast<TCast>(&self) -> ExternRef<TCast> {
ExternRef::<TCast> {
p: self.p,
resource_type: Default::default(),
}
}
}
impl<T> Clone for ExternRef<T> {
@ -71,12 +83,12 @@ impl<T> VecExternRef<T> {
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<T> {
pub(crate) fn at(&self, index: u32) -> ExternRef<T> {
let p = unsafe { _vec_extern_ref_get_value(self.get_internal_index(), index) };
ExternRef {
p,
@ -84,12 +96,12 @@ impl<T> VecExternRef<T> {
}
}
pub fn get_immutable_list(&self) -> ImmutableList<T>
pub(crate) fn get_immutable_list(&self) -> ImmutableList<T>
where
T: Clone,
T: ExternalReferenceType,
{
ImmutableList::from_ref(self.clone())
ImmutableList::from_ref(*self)
}
}

View File

@ -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;
}
)*
}
};
}

View File

@ -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<ImmutableList<EffectParameter>>,
) {
}
fn on_before_turn(&self, _choice: ExternRef<BaseTurnChoice>) {}
fn on_before_turn(&self, _choice: TurnChoice) {}
}
impl Debug for dyn Script {

View File

@ -0,0 +1,87 @@
use crate::{dbg, println, ExternRef, ExternalReferenceType};
use alloc::boxed::Box;
use core::cell::Cell;
use core::mem::forget;
struct TemporaryData<T> {
use_count: Cell<usize>,
is_deleted: bool,
value: T,
}
pub struct Temporary<T> {
value: *mut TemporaryData<T>,
}
static mut TEMPORARIES: alloc::collections::BTreeMap<u32, *const u8> =
alloc::collections::BTreeMap::new();
impl<T> Temporary<T>
where
T: ExternalReferenceType,
T: Clone,
{
pub fn from_reference(reference: ExternRef<T>) -> 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<T>).as_mut().unwrap();
if !rc.is_deleted {
*rc.use_count.get_mut() += 1;
return Self {
value: rc as *mut TemporaryData<T>,
};
}
}
}
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<T>;
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<T>) {
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<T>).as_mut().unwrap();
rc.is_deleted = true;
if rc.use_count.get() == 0 {
drop(Box::from(*v as *mut TemporaryData<T>))
}
temporaries.remove(&reference.get_internal_index());
}
}
}
}
impl<T> Clone for Temporary<T> {
fn clone(&self) -> Self {
*unsafe { self.value.as_mut() }.unwrap().use_count.get_mut() += 1;
Self { value: self.value }
}
}
impl<T> Drop for Temporary<T> {
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))
}
}
}

View File

@ -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<StringKey
}
#[no_mangle]
unsafe extern "wasm" fn destroy_script(script: *mut u8) {
unsafe extern "wasm" fn destroy_script(script: *mut Box<dyn Script>) {
// 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<dyn Script>);
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<dyn Script>,
library: ExternRef<BattleLibrary>,
library: ExternRef<DynamicLibrary>,
parameters: VecExternRef<EffectParameter>,
) {
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<dyn Script>,
choice: ExternRef<BaseTurnChoice>,
choice: ExternRef<TurnChoice>,
) {
script.as_ref().unwrap().as_ref().on_before_turn(choice)
script
.as_ref()
.unwrap()
.as_ref()
.on_before_turn(choice.get_value().unwrap())
}