Major work on WASM results

This commit is contained in:
2023-06-17 19:05:27 +02:00
parent 0d3d5bcbe7
commit 6a2353df4c
34 changed files with 818 additions and 472 deletions

View File

@@ -1,6 +1,6 @@
use parking_lot::RwLock;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use std::sync::RwLock;
use crate::dynamic_data::DamageSource;
use crate::dynamic_data::ExecutingMove;
@@ -29,14 +29,15 @@ impl EventHook {
/// listeners can exist at the same time. Note that for these functions the event will be disposed
/// of after the event is finished being sent.
pub fn register_listener(&self, func: EvtHookFn) {
self.evt_hook_function.write().push(func);
self.evt_hook_function.write().unwrap().push(func);
}
/// Run a new event. This will send the event to all externally defined event listeners. It will
/// dispose of the event afterwards.
pub fn trigger(&self, evt: Event) {
let b = Box::new(&evt);
for f in self.evt_hook_function.read().iter() {
let read_lock = self.evt_hook_function.read().unwrap();
for f in read_lock.iter() {
f(&b);
}
}

View File

@@ -70,7 +70,7 @@ impl Battle {
number_of_sides: u8,
pokemon_per_side: u8,
random_seed: Option<u128>,
) -> Self {
) -> Arc<Self> {
// If no seed was passed, we use the current time as seed for the RNG, otherwise we use the
// seed.
let random = if let Some(seed) = random_seed {
@@ -83,7 +83,7 @@ impl Battle {
sides.push(BattleSide::new(i, pokemon_per_side));
}
let mut battle = Self {
let battle = Self {
identifier: Default::default(),
library,
parties,
@@ -103,12 +103,16 @@ impl Battle {
script_source_data: Default::default(),
};
let ptr: *mut Battle = &mut battle;
for side in &mut battle.sides {
side.set_battle(ptr);
let battle_arc = Arc::new(battle);
let battle_ptr = Arc::as_ptr(&battle_arc) as *mut Battle;
unsafe {
for side in &mut battle_ptr.as_mut().unwrap().sides {
side.set_battle(Arc::downgrade(&battle_arc));
}
}
battle
battle_arc
}
/// The library the battle uses for handling.
@@ -135,10 +139,6 @@ impl Battle {
pub fn sides(&self) -> &Vec<BattleSide> {
&self.sides
}
/// A mutable list of all sides in the battle.
pub fn sides_mut(&mut self) -> &mut Vec<BattleSide> {
&mut self.sides
}
/// The RNG used for the battle.
pub fn random(&self) -> &BattleRandom {
&self.random

View File

@@ -1,6 +1,6 @@
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::Arc;
use std::sync::{Arc, Weak};
use anyhow::{anyhow, Result};
use parking_lot::lock_api::RwLockReadGuard;
@@ -35,7 +35,7 @@ pub struct BattleSide {
/// The number of choices that are set.
choices_set: AtomicU8,
/// A reference to the battle we're part of.
battle: *mut Battle,
battle: Weak<Battle>,
/// Whether or not this side has fled.
has_fled_battle: bool,
/// The volatile scripts that are attached to the side.
@@ -68,7 +68,7 @@ impl BattleSide {
choices,
fillable_slots,
choices_set: AtomicU8::new(0),
battle: std::ptr::null_mut::<Battle>(),
battle: Weak::new(),
has_fled_battle: false,
volatile_scripts: Default::default(),
script_source_data: Default::default(),
@@ -76,7 +76,7 @@ impl BattleSide {
}
/// Set the battle this side belongs to.
pub(crate) fn set_battle(&mut self, battle: *mut Battle) {
pub(crate) fn set_battle(&mut self, battle: Weak<Battle>) {
self.battle = battle;
}
@@ -106,8 +106,10 @@ impl BattleSide {
self.choices_set.load(Ordering::SeqCst)
}
/// A reference to the battle we're part of.
pub fn battle(&self) -> Result<&Battle> {
unsafe { self.battle.as_ref().ok_or(anyhow!("Battle was not set, but requested")) }
pub fn battle(&self) -> Result<Arc<Battle>> {
self.battle
.upgrade()
.ok_or(anyhow!("Battle was not set, but requested"))
}
/// Whether or not this side has fled.
pub fn has_fled_battle(&self) -> bool {
@@ -194,7 +196,7 @@ impl BattleSide {
&read_lock.get_res(index as usize)?.clone()
};
if let Some(pokemon) = pokemon {
pokemon.set_battle_data(self.battle, self.index);
pokemon.set_battle_data(self.battle.clone(), self.index);
pokemon.set_on_battlefield(true)?;
pokemon.set_battle_index(index);
@@ -227,7 +229,7 @@ impl BattleSide {
/// Checks whether a Pokemon is on the field in this side.
pub fn is_pokemon_on_side(&self, pokemon: Arc<Pokemon>) -> bool {
for p in self.pokemon.read().iter().flatten() {
if std::ptr::eq(p.deref().deref(), pokemon.deref()) {
if Arc::ptr_eq(p, &pokemon) {
return true;
}
}
@@ -247,7 +249,7 @@ impl BattleSide {
pub fn is_slot_unfillable(&self, pokemon: Arc<Pokemon>) -> Result<bool> {
for (i, slot) in self.pokemon.read().iter().enumerate() {
if let Some(p) = slot {
if std::ptr::eq(p.deref().deref(), pokemon.deref()) {
if Arc::ptr_eq(p, &pokemon) {
return Ok(self.fillable_slots.get_res(i)?.load(Ordering::Relaxed));
}
}
@@ -290,7 +292,8 @@ impl BattleSide {
// Fetch parties for the two indices.
let mut party_a = None;
let mut party_b = None;
for party in self.battle()?.parties() {
let battle = self.battle()?;
for party in battle.parties() {
if party.is_responsible_for_index(self.index, a) {
party_a = Some(party);
}

View File

@@ -1,4 +1,3 @@
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
use std::sync::Arc;
@@ -166,10 +165,10 @@ impl ExecutingMove {
}
/// Gets a hit data for a target, with a specific index.
pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> Result<&HitData> {
pub fn get_hit_data(&self, for_target: &Arc<Pokemon>, hit: u8) -> Result<&HitData> {
for (index, target) in self.targets.iter().enumerate() {
if let Some(target) = target {
if std::ptr::eq(target.deref().deref(), for_target.deref().deref()) {
if Arc::ptr_eq(target, for_target) {
let i = index * self.number_of_hits as usize + hit as usize;
return match self.hits.get(i) {
Some(hit) => Ok(hit),
@@ -188,7 +187,7 @@ impl ExecutingMove {
/// Checks whether a Pokemon is a target for this move.
pub fn is_pokemon_target(&self, pokemon: &Arc<Pokemon>) -> bool {
for target in self.targets.iter().flatten() {
if std::ptr::eq(target.deref().deref(), pokemon.deref().deref()) {
if Arc::ptr_eq(target, pokemon) {
return true;
}
}
@@ -199,7 +198,7 @@ impl ExecutingMove {
pub(crate) fn get_index_of_target(&self, for_target: &Arc<Pokemon>) -> Result<usize> {
for (index, target) in self.targets.iter().enumerate() {
if let Some(target) = target {
if std::ptr::eq(target.deref().deref(), for_target.deref().deref()) {
if Arc::ptr_eq(target, for_target) {
let i = index * self.number_of_hits as usize;
return Ok(i);
}

View File

@@ -1,4 +1,3 @@
use anyhow::Result;
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
@@ -81,7 +80,7 @@ impl LearnedMove {
}
/// Restore the remaining PP by a certain amount. Will prevent it from going above max PP.
pub fn restore_uses(&self, mut uses: u8) -> Result<()> {
pub fn restore_uses(&self, mut uses: u8) {
self.remaining_pp
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
if x + uses > self.max_pp {
@@ -90,7 +89,6 @@ impl LearnedMove {
Some(x + uses)
})
.ok();
Ok(())
}
}
@@ -113,7 +111,7 @@ mod tests {
let data: Arc<dyn MoveData> = Arc::new(mock);
let learned_move = LearnedMove::new(data, MoveLearnMethod::Level);
assert!(learned_move.try_use(15));
learned_move.restore_uses(5).unwrap();
learned_move.restore_uses(5);
assert_eq!(20, learned_move.remaining_pp());
}
}

View File

@@ -1,3 +1,4 @@
use std::fmt::{Debug, Formatter};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
use std::sync::{Arc, Weak};
@@ -26,7 +27,6 @@ use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifie
use anyhow::{anyhow, bail, Result};
/// An individual Pokemon as we know and love them.
#[derive(Debug)]
pub struct Pokemon {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
@@ -392,10 +392,10 @@ impl Pokemon {
}
/// Gets the battle the battle is currently in.
pub fn get_battle(&self) -> Option<&Battle> {
pub fn get_battle(&self) -> Option<Arc<Battle>> {
let r = self.battle_data.read();
if let Some(data) = &r.deref() {
unsafe { data.battle.as_ref() }
data.battle.upgrade()
} else {
None
}
@@ -480,13 +480,8 @@ impl Pokemon {
// If we're in battle, use the battle random for predictability
let r = self.battle_data.read();
if let Some(data) = r.deref() {
let mut random = match data
.battle()
.ok_or(anyhow!("Battle not set"))?
.random()
.get_rng()
.lock()
{
let battle = data.battle().ok_or(anyhow!("Battle not set"))?;
let mut random = match battle.random().get_rng().lock() {
Ok(v) => v,
Err(_) => return Err(PkmnError::UnableToAcquireLock.into()),
};
@@ -585,7 +580,7 @@ impl Pokemon {
}
/// Sets the current battle the Pokemon is in.
pub fn set_battle_data(&self, battle: *mut Battle, battle_side_index: u8) {
pub fn set_battle_data(&self, battle: Weak<Battle>, battle_side_index: u8) {
let mut w = self.battle_data.write();
if let Some(battle_data) = w.deref_mut() {
battle_data.battle = battle;
@@ -770,7 +765,7 @@ impl Pokemon {
#[derive(Debug)]
pub struct PokemonBattleData {
/// The battle data of the Pokemon
battle: *mut Battle,
battle: Weak<Battle>,
/// The index of the side of the Pokemon
battle_side_index: AtomicU8,
/// The index of the slot on the side of the Pokemon.
@@ -783,12 +778,12 @@ pub struct PokemonBattleData {
impl PokemonBattleData {
/// The battle data of the Pokemon
pub fn battle_mut(&mut self) -> Option<&mut Battle> {
unsafe { self.battle.as_mut() }
pub fn battle_mut(&mut self) -> Option<Arc<Battle>> {
self.battle.upgrade()
}
/// The battle data of the Pokemon
pub fn battle(&self) -> Option<&Battle> {
unsafe { self.battle.as_ref() }
pub fn battle(&self) -> Option<Arc<Battle>> {
self.battle.upgrade()
}
/// The index of the side of the Pokemon
@@ -876,6 +871,18 @@ pub enum DamageSource {
Struggle = 2,
}
impl Debug for Pokemon {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Pokemon(")?;
write!(f, "Species: {}, ", self.species().name())?;
write!(f, "Form: {}, ", self.form().name())?;
write!(f, "Level: {}, ", self.level())?;
f.write_str(")")?;
Ok(())
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
pub mod test {