diff --git a/.cargo/config.toml b/.cargo/config.toml index 803e058..c658a16 100755 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,2 @@ -[target.x86_64-unknown-linux-gnu] -linker = "/usr/bin/clang" -rustflags = ["-Clink-arg=-fuse-ld=/usr/bin/mold"] - [rust] debuginfo-level = 1 \ No newline at end of file diff --git a/src/dynamic_data/choices.rs b/src/dynamic_data/choices.rs index 2efb6cd..2b42c3b 100755 --- a/src/dynamic_data/choices.rs +++ b/src/dynamic_data/choices.rs @@ -1,5 +1,5 @@ use anyhow::{bail, Result}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicI8, AtomicU32, Ordering}; use std::sync::Arc; use parking_lot::RwLock; @@ -16,12 +16,12 @@ struct CommonChoiceData { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The user of the turn choice - user: Arc, + user: Pokemon, /// The speed of the user at the beginning of the turn. - speed: u32, + speed: AtomicU32, /// This random value is set at the beginning of the turn. It is used for tie breaking of the /// turn order in a predictable way, regardless of implementation and hardware. - random_value: u32, + random_value: AtomicU32, /// Whether or not the choice has failed. A failed choice will stop running, and execute special /// fail handling during turn execution. has_failed: AtomicBool, @@ -57,32 +57,22 @@ impl TurnChoice { TurnChoice::Pass(data) => &data.choice_data, } } - /// The shared choice data between each of the different turn choices. - fn choice_data_mut(&mut self) -> &mut Box { - match self { - TurnChoice::Move(data) => &mut data.choice_data, - TurnChoice::Item(data) => &mut data.choice_data, - TurnChoice::Switch(data) => &mut data.choice_data, - TurnChoice::Flee(data) => &mut data.choice_data, - TurnChoice::Pass(data) => &mut data.choice_data, - } - } /// Get the user of the given choice. - pub fn user(&self) -> &Arc { + pub fn user(&self) -> &Pokemon { &self.choice_data().user } /// Get the speed of the user for the choice. Note that this speed is the speed of the Pokemon /// at the start of the turn! pub fn speed(&self) -> u32 { - self.choice_data().speed + self.choice_data().speed.load(Ordering::Relaxed) } - /// Get the mutable speed of the user for the choice. Note that this speed is the speed of the Pokemon - /// at the start of the turn! - pub fn speed_mut(&mut self) -> &mut u32 { - &mut self.choice_data_mut().speed + /// Sets the speed of user for the choice. Note that this speed is the speed of the Pokemon at + /// the start of the turn! + pub fn set_speed(&self, value: u32) { + self.choice_data().speed.store(value, Ordering::Relaxed); } /// Gets whether or not the choice has failed. If we notice this when we execute the choice, we @@ -101,12 +91,12 @@ impl TurnChoice { /// breaking of turn executions. This means that choices get executed with a predictable order, /// regardless of implementation details. pub(crate) fn random_value(&self) -> u32 { - self.choice_data().random_value + self.choice_data().random_value.load(Ordering::Relaxed) } /// This sets the above random value. - pub(crate) fn set_random_value(&mut self, val: u32) { - self.choice_data_mut().random_value = val; + pub(crate) fn set_random_value(&self, val: u32) { + self.choice_data().random_value.store(val, Ordering::Relaxed) } /// Helper function to get the move choice data from a turn. Note that this will panic if not @@ -174,26 +164,26 @@ pub struct MoveChoice { /// The move script. script: ScriptContainer, /// The priority of the move choice at the beginning of the turn. - priority: i8, + priority: AtomicI8, /// The common turn choice data. choice_data: Box, } impl MoveChoice { /// Initializes the data for a new move choice. - pub fn new(user: Arc, used_move: Arc, target_side: u8, target_index: u8) -> Self { + pub fn new(user: Pokemon, used_move: Arc, target_side: u8, target_index: u8) -> Self { let speed = user.boosted_stats().speed(); Self { used_move, target_side, target_index, script: Default::default(), - priority: 0, + priority: AtomicI8::new(0), choice_data: Box::new(CommonChoiceData { identifier: Default::default(), user, - speed, - random_value: 0, + speed: AtomicU32::new(speed), + random_value: AtomicU32::new(0), has_failed: Default::default(), script_source_data: Default::default(), }), @@ -215,14 +205,14 @@ impl MoveChoice { } /// The priority of the move choice at the beginning of the turn. pub fn priority(&self) -> i8 { - self.priority + self.priority.load(Ordering::Relaxed) } /// The priority of the move choice at the beginning of the turn. - pub fn priority_mut(&mut self) -> &mut i8 { - &mut self.priority + pub fn set_priority(&self, value: i8) { + self.priority.store(value, Ordering::Relaxed) } /// The user of the choice. - pub fn user(&self) -> &Arc { + pub fn user(&self) -> &Pokemon { &self.choice_data.user } /// The move script of the choice. @@ -259,14 +249,14 @@ pub struct ItemChoice { impl ItemChoice { /// Initialised a new item choice. - pub fn new(user: Arc) -> Self { + pub fn new(user: Pokemon) -> Self { let speed = user.boosted_stats().speed(); Self { choice_data: Box::new(CommonChoiceData { identifier: Default::default(), user, - speed, - random_value: 0, + speed: AtomicU32::new(speed), + random_value: AtomicU32::new(0), has_failed: Default::default(), script_source_data: Default::default(), }), @@ -299,14 +289,14 @@ pub struct SwitchChoice { impl SwitchChoice { /// Initialise the turn choice data. - pub fn new(user: Arc) -> Self { + pub fn new(user: Pokemon) -> Self { let speed = user.boosted_stats().speed(); Self { choice_data: Box::new(CommonChoiceData { identifier: Default::default(), user, - speed, - random_value: 0, + speed: AtomicU32::new(speed), + random_value: AtomicU32::new(0), has_failed: Default::default(), script_source_data: Default::default(), }), @@ -339,13 +329,13 @@ pub struct FleeChoice { impl FleeChoice { /// Initialises a new flee choice. - pub fn new(user: Arc) -> Self { + pub fn new(user: Pokemon) -> Self { Self { choice_data: Box::new(CommonChoiceData { identifier: Default::default(), user, - speed: 0, - random_value: 0, + speed: AtomicU32::new(0), + random_value: AtomicU32::new(0), has_failed: Default::default(), script_source_data: Default::default(), }), @@ -378,14 +368,14 @@ pub struct PassChoice { impl PassChoice { /// Initialised a new pass choice. - pub fn new(user: Arc) -> Self { + pub fn new(user: Pokemon) -> Self { let speed = user.boosted_stats().speed(); Self { choice_data: Box::new(CommonChoiceData { identifier: Default::default(), user, - speed, - random_value: 0, + speed: AtomicU32::new(speed), + random_value: AtomicU32::new(0), has_failed: Default::default(), script_source_data: Default::default(), }), @@ -428,7 +418,10 @@ impl Ord for TurnChoice { match self { TurnChoice::Move(data) => { if let TurnChoice::Move(other_data) = other { - let priority_compare = data.priority.cmp(&other_data.priority); + let priority_compare = data + .priority + .load(Ordering::Relaxed) + .cmp(&other_data.priority.load(Ordering::Relaxed)); if priority_compare != std::cmp::Ordering::Equal { return priority_compare; } diff --git a/src/dynamic_data/event_hooks.rs b/src/dynamic_data/event_hooks.rs index 7f80222..3b1b980 100755 --- a/src/dynamic_data/event_hooks.rs +++ b/src/dynamic_data/event_hooks.rs @@ -29,6 +29,7 @@ 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) { + #[allow(clippy::unwrap_used)] // This should never fail. self.evt_hook_function.write().unwrap().push(func); } @@ -36,6 +37,7 @@ impl EventHook { /// dispose of the event afterwards. pub fn trigger(&self, evt: Event) { let b = Box::new(&evt); + #[allow(clippy::unwrap_used)] // This should never fail. let read_lock = self.evt_hook_function.read().unwrap(); for f in read_lock.iter() { f(&b); @@ -59,7 +61,7 @@ pub enum Event<'own> { /// The index of the Pokemon that got switched in/out on its side index: u8, /// The new Pokemon that will be on the spot. If none, the spot will now be empty. - pokemon: Option>, + pokemon: Option, }, /// A swap event happens when two Pokemon on a side swap positions. Note that this is rare. Swap { diff --git a/src/dynamic_data/flow/choice_queue.rs b/src/dynamic_data/flow/choice_queue.rs index 67e2700..54288fe 100755 --- a/src/dynamic_data/flow/choice_queue.rs +++ b/src/dynamic_data/flow/choice_queue.rs @@ -6,6 +6,8 @@ use anyhow::Result; use anyhow_ext::anyhow; use parking_lot::lock_api::MappedRwLockReadGuard; use parking_lot::{RawRwLock, RwLock, RwLockReadGuard}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; /// The ChoiceQueue is used to run choices one by one. /// @@ -14,51 +16,50 @@ use parking_lot::{RawRwLock, RwLock, RwLockReadGuard}; /// helper functions to change the turn order while doing the execution. This is needed, as several /// moves in Pokemon actively mess with this order. #[derive(Debug)] - pub struct ChoiceQueue { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get /// executed. - queue: RwLock>>, + queue: RwLock>>>, /// The current index of the turn we need to execute next. - current: usize, + current: AtomicUsize, } impl ChoiceQueue { /// Initializes a ChoiceQueue, and sort the choices. - pub(crate) fn new(mut queue: Vec>) -> Self { + pub(crate) fn new(mut queue: Vec>>) -> Self { queue.sort_unstable_by(|a, b| b.cmp(a)); Self { identifier: Default::default(), queue: RwLock::new(queue), - current: 0, + current: AtomicUsize::new(0), } } /// Dequeues the next turn choice to be executed. This gives ownership to the callee, and replaces /// our own reference to the turn choice with an empty spot. It also increments the current position /// by one. - pub fn dequeue(&mut self) -> Result> { + pub fn dequeue(&self) -> Result>> { let mut write_lock = self.queue.write(); - if self.current >= write_lock.len() { + if self.current.load(Ordering::Relaxed) >= write_lock.len() { return Ok(None); } let c = write_lock - .get_mut(self.current) + .get_mut(self.current.load(Ordering::Relaxed)) .ok_or(anyhow!("Unable to get current turn choice"))? .take(); - self.current += 1; + self.current.fetch_add(1, Ordering::Relaxed); Ok(c) } /// This reads what the next choice to execute will be, without modifying state. - pub fn peek(&self) -> Result>> { + pub fn peek(&self) -> Result>>> { let read_lock = self.queue.read(); - if self.current >= read_lock.len() { + if self.current.load(Ordering::Relaxed) >= read_lock.len() { Ok(None) } else { - let v = RwLockReadGuard::try_map(read_lock, |a| match a.get(self.current) { + let v = RwLockReadGuard::try_map(read_lock, |a| match a.get(self.current.load(Ordering::Relaxed)) { Some(Some(v)) => Some(v), _ => None, }); @@ -71,7 +72,7 @@ impl ChoiceQueue { /// Check if we have any choices remaining. pub fn has_next(&self) -> bool { - self.current < self.queue.read().len() + self.current.load(Ordering::Relaxed) < self.queue.read().len() } /// This resorts the yet to be executed choices. This can be useful for dealing with situations @@ -80,19 +81,19 @@ impl ChoiceQueue { pub fn resort(&mut self) -> Result<()> { let len = self.queue.read().len(); let mut write_lock = self.queue.write(); - for index in self.current..len { + for index in self.current.load(Ordering::Relaxed)..len { let choice = &mut write_lock.get_mut_res(index)?; if let Some(choice) = choice { let mut speed = choice.user().boosted_stats().speed(); script_hook!(change_speed, (*choice), choice, &mut speed); - *choice.speed_mut() = speed; + choice.set_speed(speed) } } write_lock - .get_mut(self.current..len) + .get_mut(self.current.load(Ordering::Relaxed)..len) .ok_or(PkmnError::IndexOutOfBounds { - index: self.current, + index: self.current.load(Ordering::Relaxed), len, })? .sort_unstable_by(|a, b| b.cmp(a)); @@ -104,7 +105,7 @@ impl ChoiceQueue { let mut queue_lock = self.queue.write(); let mut desired_index = None; // Find the index for the choice we want to move up. - for index in self.current..queue_lock.len() { + for index in self.current.load(Ordering::Relaxed)..queue_lock.len() { if let Some(Some(choice)) = &queue_lock.get(index) { if pokemon.value_identifier() == choice.user().value_identifier() { desired_index = Some(index); @@ -115,7 +116,7 @@ impl ChoiceQueue { let result = match desired_index { Some(desired_index) => { // If the choice we want to move up is already the next choice, just return. - if desired_index == self.current { + if desired_index == self.current.load(Ordering::Relaxed) { return Ok(true); } @@ -126,11 +127,14 @@ impl ChoiceQueue { .ok_or(anyhow!("Choice was already taken"))?; // Iterate backwards from the spot before the choice we want to move up, push them all back // by 1 spot. - for index in (self.current..desired_index).rev() { + let current = self.current.load(Ordering::Relaxed); + for index in (current..desired_index).rev() { queue_lock.swap(index, index + 1); } // Place the choice that needs to be next in the next to be executed position. - let _ = queue_lock.get_mut_res(self.current)?.insert(choice); + let _ = queue_lock + .get_mut_res(self.current.load(Ordering::Relaxed))? + .insert(choice); true } None => false, @@ -139,12 +143,14 @@ impl ChoiceQueue { } /// Internal helper function to be easily able to iterate over the yet to be executed choices. - pub(crate) fn get_queue(&self) -> Result]>> { + pub(crate) fn get_queue(&self) -> Result>]>> { let read_lock = self.queue.read(); - match RwLockReadGuard::try_map(read_lock, |a| a.get(self.current..self.queue.read().len())) { + match RwLockReadGuard::try_map(read_lock, |a| { + a.get(self.current.load(Ordering::Relaxed)..self.queue.read().len()) + }) { Ok(v) => Ok(v), Err(_) => Err(PkmnError::IndexOutOfBounds { - index: self.current, + index: self.current.load(Ordering::Relaxed), len: self.queue.read().len(), } .into()), @@ -176,7 +182,7 @@ mod tests { #[test] fn dequeue_from_empty_queue() { - let mut queue = ChoiceQueue::new(Vec::new()); + let queue = ChoiceQueue::new(Vec::new()); assert!(queue.dequeue().unwrap().is_none()); } @@ -204,9 +210,9 @@ mod tests { #[test] fn create_queue_with_single_item() { - let user = Arc::new(get_user(10)); + let user = get_user(10); - let queue = ChoiceQueue::new(vec![Some(TurnChoice::Pass(PassChoice::new(user)))]); + let queue = ChoiceQueue::new(vec![Some(Arc::new(TurnChoice::Pass(PassChoice::new(user))))]); assert!(queue.has_next()); assert!(queue.peek().unwrap().is_some()); assert_eq!(7, queue.peek().unwrap().unwrap().speed()); @@ -214,9 +220,9 @@ mod tests { #[test] fn dequeue_from_queue_with_single_item() { - let user = Arc::new(get_user(10)); + let user = get_user(10); - let mut queue = ChoiceQueue::new(vec![Some(TurnChoice::Pass(PassChoice::new(user)))]); + let queue = ChoiceQueue::new(vec![Some(Arc::new(TurnChoice::Pass(PassChoice::new(user))))]); assert!(queue.has_next()); assert_eq!(7, queue.dequeue().unwrap().unwrap().speed()); assert!(!queue.has_next()); @@ -225,12 +231,12 @@ mod tests { #[test] fn create_queue_with_two_items_with_equal_order() { - let user1 = Arc::new(get_user(10)); - let user2 = Arc::new(get_user(10)); + let user1 = get_user(10); + let user2 = get_user(10); let queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1))), - Some(TurnChoice::Pass(PassChoice::new(user2))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1)))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), ]); assert!(queue.has_next()); assert!(queue.peek().unwrap().is_some()); @@ -239,12 +245,12 @@ mod tests { #[test] fn create_queue_with_two_items_get_queue() { - let user1 = Arc::new(get_user(10)); - let user2 = Arc::new(get_user(5)); + let user1 = get_user(10); + let user2 = get_user(5); let queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1.clone()))), - Some(TurnChoice::Pass(PassChoice::new(user2))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), ]); let inner_queue = queue.get_queue().unwrap(); assert_eq!( @@ -255,12 +261,12 @@ mod tests { #[test] fn create_queue_with_two_items_in_wrong_order_sorts_correctly() { - let user1 = Arc::new(get_user(5)); - let user2 = Arc::new(get_user(100)); + let user1 = get_user(5); + let user2 = get_user(100); - let mut queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1))), - Some(TurnChoice::Pass(PassChoice::new(user2))), + let queue = ChoiceQueue::new(vec![ + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1)))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), ]); assert_eq!(25, queue.dequeue().unwrap().unwrap().speed()); assert_eq!(6, queue.dequeue().unwrap().unwrap().speed()); @@ -268,12 +274,12 @@ mod tests { #[test] fn resort_with_two_choices() { - let user1 = Arc::new(get_user(50)); - let user2 = Arc::new(get_user(1)); + let user1 = get_user(50); + let user2 = get_user(1); let mut queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1.clone()))), - Some(TurnChoice::Pass(PassChoice::new(user2.clone()))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), ]); user2.change_level_by(60).unwrap(); @@ -290,18 +296,18 @@ mod tests { #[test] fn move_pokemon_choice_first_with_two_choices() { - let user1 = Arc::new(get_user(100)); - let user2 = Arc::new(get_user(1)); + let user1 = get_user(100); + let user2 = get_user(1); - let mut queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1.clone()))), - Some(TurnChoice::Pass(PassChoice::new(user2.clone()))), + let queue = ChoiceQueue::new(vec![ + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), ]); assert_eq!( user1.value_identifier(), queue.peek().unwrap().unwrap().user().value_identifier() ); - assert!(queue.move_pokemon_choice_next(user2.as_ref()).unwrap()); + assert!(queue.move_pokemon_choice_next(&user2).unwrap()); assert_eq!( user2.value_identifier(), @@ -315,18 +321,18 @@ mod tests { #[test] fn move_pokemon_choice_first_when_choice_has_already_been() { - let user1 = Arc::new(get_user(10)); - let user2 = Arc::new(get_user(100)); + let user1 = get_user(10); + let user2 = get_user(100); - let mut queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1.clone()))), - Some(TurnChoice::Pass(PassChoice::new(user2.clone()))), + let queue = ChoiceQueue::new(vec![ + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2.clone())))), ]); assert_eq!( user2.value_identifier(), queue.dequeue().unwrap().unwrap().user().value_identifier() ); - assert!(!queue.move_pokemon_choice_next(user2.as_ref()).unwrap()); + assert!(!queue.move_pokemon_choice_next(&user2).unwrap()); assert_eq!( user1.value_identifier(), @@ -337,18 +343,18 @@ mod tests { #[test] fn move_pokemon_choice_first_when_choice_is_next() { - let user1 = Arc::new(get_user(100)); - let user2 = Arc::new(get_user(10)); + let user1 = get_user(100); + let user2 = get_user(10); let queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(user1.clone()))), - Some(TurnChoice::Pass(PassChoice::new(user2))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user1.clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(user2)))), ]); assert_eq!( user1.value_identifier(), queue.peek().unwrap().unwrap().user().value_identifier() ); - assert!(queue.move_pokemon_choice_next(user1.as_ref()).unwrap()); + assert!(queue.move_pokemon_choice_next(&user1).unwrap()); assert_eq!( user1.value_identifier(), queue.peek().unwrap().unwrap().user().value_identifier() @@ -358,29 +364,29 @@ mod tests { #[test] fn move_pokemon_choice_first_with_seven_choices() { let users = [ - Arc::new(get_user(100)), - Arc::new(get_user(90)), - Arc::new(get_user(80)), - Arc::new(get_user(70)), - Arc::new(get_user(60)), - Arc::new(get_user(50)), - Arc::new(get_user(40)), + get_user(100), + get_user(90), + get_user(80), + get_user(70), + get_user(60), + get_user(50), + get_user(40), ]; - let mut queue = ChoiceQueue::new(vec![ - Some(TurnChoice::Pass(PassChoice::new(users[0].clone()))), - Some(TurnChoice::Pass(PassChoice::new(users[1].clone()))), - Some(TurnChoice::Pass(PassChoice::new(users[2].clone()))), - Some(TurnChoice::Pass(PassChoice::new(users[3].clone()))), - Some(TurnChoice::Pass(PassChoice::new(users[4].clone()))), - Some(TurnChoice::Pass(PassChoice::new(users[5].clone()))), - Some(TurnChoice::Pass(PassChoice::new(users[6].clone()))), + let queue = ChoiceQueue::new(vec![ + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[0].clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[1].clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[2].clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[3].clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[4].clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[5].clone())))), + Some(Arc::new(TurnChoice::Pass(PassChoice::new(users[6].clone())))), ]); assert_eq!( users[0].value_identifier(), queue.peek().unwrap().unwrap().user().value_identifier() ); - assert!(queue.move_pokemon_choice_next(users[4].as_ref()).unwrap()); + assert!(queue.move_pokemon_choice_next(&users[4]).unwrap()); assert_eq!( users[4].value_identifier(), diff --git a/src/dynamic_data/flow/target_resolver.rs b/src/dynamic_data/flow/target_resolver.rs index 99b1dfb..7020e63 100755 --- a/src/dynamic_data/flow/target_resolver.rs +++ b/src/dynamic_data/flow/target_resolver.rs @@ -1,6 +1,5 @@ use anyhow::Result; use std::ops::Deref; -use std::sync::Arc; use num_traits::abs; @@ -10,7 +9,7 @@ use crate::static_data::MoveTarget; use crate::VecExt; /// Helper type for the vector of targ ets we will return. -pub type TargetList = Vec>>; +pub type TargetList = Vec>; /// This returns all Pokemon in the battle. fn get_all_targets(battle: &Battle) -> TargetList { diff --git a/src/dynamic_data/flow/turn_runner.rs b/src/dynamic_data/flow/turn_runner.rs index 010f503..903ab71 100755 --- a/src/dynamic_data/flow/turn_runner.rs +++ b/src/dynamic_data/flow/turn_runner.rs @@ -77,9 +77,9 @@ impl Battle { } /// Executes a single choice. - fn execute_choice(&self, choice: &TurnChoice) -> Result<()> { + fn execute_choice(&self, choice: &Arc) -> Result<()> { // A pass turn choice means the user does not intend to do anything. As such, return. - if let TurnChoice::Pass(..) = choice { + if let TurnChoice::Pass(..) = choice.deref() { return Ok(()); } if self.has_ended() { @@ -95,7 +95,7 @@ impl Battle { if !self.can_use(choice) { return Ok(()); } - match choice { + match choice.deref() { TurnChoice::Move(..) => self.execute_move_choice(choice)?, TurnChoice::Item(_) => {} TurnChoice::Switch(_) => {} @@ -106,7 +106,7 @@ impl Battle { } /// Executes a move choice. - fn execute_move_choice<'func>(&'func self, choice: &'func TurnChoice) -> Result<()> { + fn execute_move_choice<'func>(&'func self, choice: &'func Arc) -> Result<()> { let move_choice = choice.get_move_turn_data()?; let used_move = move_choice.used_move(); let move_data = { @@ -129,14 +129,14 @@ impl Battle { if number_of_hits == 0 { return Ok(()); } - let mut executing_move = ExecutingMove::new( + let executing_move = Arc::new(ExecutingMove::new( targets.clone(), number_of_hits, choice.user().clone(), used_move.clone(), move_data, move_choice.script().clone(), - ); + )); let mut prevented = false; script_hook!(prevent_move, executing_move, &executing_move, &mut prevented); if prevented { @@ -161,13 +161,13 @@ impl Battle { } script_hook!(on_before_move, executing_move, &executing_move); for target in targets.iter().flatten() { - self.handle_move_for_target(&mut executing_move, target)?; + self.handle_move_for_target(&executing_move, target)?; } Ok(()) } /// Executes a move turn choice on a single target. - fn handle_move_for_target(&self, executing_move: &mut ExecutingMove, target: &Arc) -> Result<()> { + fn handle_move_for_target(&self, executing_move: &Arc, target: &Pokemon) -> Result<()> { { let mut fail = false; script_hook!(fail_incoming_move, target, executing_move, target, &mut fail); diff --git a/src/dynamic_data/libraries/damage_library.rs b/src/dynamic_data/libraries/damage_library.rs index c632df0..964e286 100755 --- a/src/dynamic_data/libraries/damage_library.rs +++ b/src/dynamic_data/libraries/damage_library.rs @@ -14,8 +14,8 @@ pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { /// Calculate the damage for a given hit on a Pokemon. fn get_damage( &self, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, hit_data: &HitData, ) -> Result; @@ -23,8 +23,8 @@ pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { /// Calculate the base power for a given hit on a Pokemon. fn get_base_power( &self, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, hit_data: &HitData, ) -> Result; @@ -33,8 +33,8 @@ pub trait DamageLibrary: std::fmt::Debug + ValueIdentifiable { fn is_critical( &self, battle: &Battle, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, ) -> Result; } @@ -61,8 +61,8 @@ impl Gen7DamageLibrary { /// Calculates the modifier applied to damage from the statistics of the relevant Pokemon. fn get_stat_modifier( &self, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, hit_data: &HitData, ) -> Result { @@ -151,8 +151,8 @@ impl Gen7DamageLibrary { /// to apply a raw modifier to the damage. fn get_damage_modifier( &self, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, _hit_data: &HitData, ) -> Result { @@ -172,8 +172,8 @@ impl Gen7DamageLibrary { impl DamageLibrary for Gen7DamageLibrary { fn get_damage( &self, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, hit_data: &HitData, ) -> Result { @@ -260,8 +260,8 @@ impl DamageLibrary for Gen7DamageLibrary { fn get_base_power( &self, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, _hit_data: &HitData, ) -> Result { @@ -284,8 +284,8 @@ impl DamageLibrary for Gen7DamageLibrary { fn is_critical( &self, battle: &Battle, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, ) -> Result { // Status moves can't be critical. diff --git a/src/dynamic_data/libraries/dynamic_library.rs b/src/dynamic_data/libraries/dynamic_library.rs index 828b0f0..bb386e0 100755 --- a/src/dynamic_data/libraries/dynamic_library.rs +++ b/src/dynamic_data/libraries/dynamic_library.rs @@ -16,15 +16,15 @@ use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; /// calculators that might be customized between different generations and implementations. pub trait DynamicLibrary: Debug + ValueIdentifiable { /// The static data is the immutable storage data for this library. - fn static_data(&self) -> &Box; + fn static_data(&self) -> &Arc; /// The stat calculator deals with the calculation of flat and boosted stats, based on the /// Pokemons attributes. - fn stat_calculator(&self) -> &Box; + fn stat_calculator(&self) -> &Arc; /// The damage calculator deals with the calculation of things relating to damage. - fn damage_calculator(&self) -> &Box; + fn damage_calculator(&self) -> &Arc; /// The Misc Library holds minor functions that do not fall in any of the other libraries and /// calculators. - fn misc_library(&self) -> &Box; + fn misc_library(&self) -> &Arc; /// Loads a standard script with a given unique combination of category and key. If no script /// can be created with this combination, returns None. @@ -47,15 +47,15 @@ pub struct DynamicLibraryImpl { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The static data is the immutable storage data for this library. - static_data: Box, + static_data: Arc, /// The stat calculator deals with the calculation of flat and boosted stats, based on the /// Pokemons attributes. - stat_calculator: Box, + stat_calculator: Arc, /// The damage calculator deals with the calculation of things relating to damage. - damage_calculator: Box, + damage_calculator: Arc, /// The Misc Library holds minor functions that do not fall in any of the other libraries and /// calculators. - misc_library: Box, + misc_library: Arc, /// The script resolver deals with how to resolve the scripts from specific unique key combinations. script_resolver: Box, @@ -64,10 +64,10 @@ pub struct DynamicLibraryImpl { impl DynamicLibraryImpl { /// Instantiates a new DynamicLibrary with given parameters. pub fn new( - static_data: Box, - stat_calculator: Box, - damage_calculator: Box, - misc_library: Box, + static_data: Arc, + stat_calculator: Arc, + damage_calculator: Arc, + misc_library: Arc, script_resolver: Box, ) -> Self { Self { @@ -83,21 +83,21 @@ impl DynamicLibraryImpl { impl DynamicLibrary for DynamicLibraryImpl { /// The static data is the immutable storage data for this library. - fn static_data(&self) -> &Box { + fn static_data(&self) -> &Arc { &self.static_data } /// The stat calculator deals with the calculation of flat and boosted stats, based on the /// Pokemons attributes. - fn stat_calculator(&self) -> &Box { + fn stat_calculator(&self) -> &Arc { &self.stat_calculator } /// The damage calculator deals with the calculation of things relating to damage. - fn damage_calculator(&self) -> &Box { + fn damage_calculator(&self) -> &Arc { &self.damage_calculator } /// The Misc Library holds minor functions that do not fall in any of the other libraries and /// calculators. - fn misc_library(&self) -> &Box { + fn misc_library(&self) -> &Arc { &self.misc_library } @@ -139,10 +139,10 @@ pub mod test { #[derive(Debug)] pub DynamicLibrary{} impl DynamicLibrary for DynamicLibrary { - fn static_data(&self) -> &Box; - fn stat_calculator(&self) -> &Box; - fn damage_calculator(&self) -> &Box; - fn misc_library(&self) -> &Box; + fn static_data(&self) -> &Arc; + fn stat_calculator(&self) -> &Arc; + fn damage_calculator(&self) -> &Arc; + fn misc_library(&self) -> &Arc; fn load_script( &self, owner: ScriptOwnerData, @@ -161,10 +161,10 @@ pub mod test { pub fn build() -> DynamicLibraryImpl { DynamicLibraryImpl { identifier: Default::default(), - static_data: Box::new(crate::static_data::libraries::static_data::test::build()), - stat_calculator: Box::new(Gen7BattleStatCalculator::new()), - damage_calculator: Box::new(Gen7DamageLibrary::new(false)), - misc_library: Box::new(Gen7MiscLibrary::new()), + static_data: Arc::new(crate::static_data::libraries::static_data::test::build()), + stat_calculator: Arc::new(Gen7BattleStatCalculator::new()), + damage_calculator: Arc::new(Gen7DamageLibrary::new(false)), + misc_library: Arc::new(Gen7MiscLibrary::new()), script_resolver: Box::new(EmptyScriptResolver { identifier: Default::default(), }), diff --git a/src/dynamic_data/libraries/misc_library.rs b/src/dynamic_data/libraries/misc_library.rs index adf9d76..8997ac8 100755 --- a/src/dynamic_data/libraries/misc_library.rs +++ b/src/dynamic_data/libraries/misc_library.rs @@ -14,7 +14,7 @@ pub trait MiscLibrary: Debug + ValueIdentifiable { /// Returns whether or not a Pokemon is allowed to flee or switch out. fn can_flee(&self, choice: &TurnChoice) -> bool; /// Returns the move we need to use if we can't use another move. Typically Struggle. - fn replacement_move(&self, user: &Arc, target_side: u8, target_index: u8) -> TurnChoice; + fn replacement_move(&self, user: &Pokemon, target_side: u8, target_index: u8) -> TurnChoice; // TODO: can evolve from level up? // TODO: get time } @@ -66,7 +66,7 @@ impl MiscLibrary for Gen7MiscLibrary { todo!() } - fn replacement_move(&self, user: &Arc, target_side: u8, target_index: u8) -> TurnChoice { + fn replacement_move(&self, user: &Pokemon, target_side: u8, target_index: u8) -> TurnChoice { self.struggle_learned_move.restore_all_uses(); TurnChoice::Move(MoveChoice::new( user.clone(), diff --git a/src/dynamic_data/models/battle.rs b/src/dynamic_data/models/battle.rs index 8a6c5d7..b750b7f 100755 --- a/src/dynamic_data/models/battle.rs +++ b/src/dynamic_data/models/battle.rs @@ -1,6 +1,7 @@ +use std::ffi::c_void; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, Weak}; use anyhow::Result; use anyhow_ext::anyhow; @@ -22,15 +23,15 @@ use crate::dynamic_data::{ChoiceQueue, ScriptContainer}; use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData}; use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; -/// A pokemon battle, with any amount of sides and pokemon per side. +/// The data of a battle. #[derive(Debug)] -pub struct Battle { +struct BattleData { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The library the battle uses for handling. library: Arc, /// A list of all different parties in the battle. - parties: Vec, + parties: Vec>, /// Whether or not Pokemon can flee from the battle. can_flee: bool, /// The number of sides in the battle. Typically 2. @@ -40,9 +41,9 @@ pub struct Battle { /// A list of all sides in the battle. sides: Vec, /// The RNG used for the battle. - random: BattleRandom, + random: Arc, /// A queue of the yet to be executed choices in a turn. - current_turn_queue: RwLock>, + current_turn_queue: RwLock>>, /// Whether or not the battle has ended. has_ended: AtomicBool, /// The eventual result of the battle. Inconclusive until the battle is ended. @@ -61,16 +62,30 @@ pub struct Battle { script_source_data: RwLock, } +/// A pokemon battle, with any amount of sides and pokemon per side. +#[derive(Clone, Debug)] +pub struct Battle { + /// The actual data of the battle. + data: Arc, +} + +/// A weak reference to a battle. +#[derive(Clone, Debug, Default)] +pub struct WeakBattleReference { + /// A weak reference to the actual data of the battle. + data: Weak, +} + impl Battle { /// Initializes a new battle. pub fn new( library: Arc, - parties: Vec, + parties: Vec>, can_flee: bool, number_of_sides: u8, pokemon_per_side: u8, random_seed: Option, - ) -> 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 +98,7 @@ impl Battle { sides.push(BattleSide::new(i, pokemon_per_side)); } - let battle = Self { + let battle = BattleData { identifier: Default::default(), library, parties, @@ -91,7 +106,7 @@ impl Battle { number_of_sides, pokemon_per_side, sides, - random, + random: Arc::new(random), current_turn_queue: RwLock::new(None), has_ended: AtomicBool::new(false), result: RwLock::new(BattleResult::Inconclusive), @@ -104,73 +119,77 @@ impl Battle { }; 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)); - } + let battle = Self { data: battle_arc }; + for side in &battle.data.sides { + side.set_battle(battle.weak()); } - battle_arc + battle + } + + /// Returns a weak reference to the battle. + pub fn weak(&self) -> WeakBattleReference { + WeakBattleReference { + data: Arc::downgrade(&self.data), + } } /// The library the battle uses for handling. pub fn library(&self) -> &Arc { - &self.library + &self.data.library } /// A list of all different parties in the battle. - pub fn parties(&self) -> &Vec { - &self.parties + pub fn parties(&self) -> &Vec> { + &self.data.parties } /// Whether or not Pokemon can flee from the battle. pub fn can_flee(&self) -> bool { - self.can_flee + self.data.can_flee } /// The number of sides in the battle. Typically 2. pub fn number_of_sides(&self) -> u8 { - self.number_of_sides + self.data.number_of_sides } /// The number of Pokemon that can be on each side. pub fn pokemon_per_side(&self) -> u8 { - self.pokemon_per_side + self.data.pokemon_per_side } /// A list of all sides in the battle. pub fn sides(&self) -> &Vec { - &self.sides + &self.data.sides } /// The RNG used for the battle. - pub fn random(&self) -> &BattleRandom { - &self.random + pub fn random(&self) -> &Arc { + &self.data.random } /// Whether or not the battle has ended. pub fn has_ended(&self) -> bool { - self.has_ended.load(Ordering::Relaxed) + self.data.has_ended.load(Ordering::Relaxed) } /// The eventual result of the battle. Inconclusive until the battle is ended. pub fn result(&self) -> BattleResult { - *self.result.read() + *self.data.result.read() } /// The handler to send all events to. pub fn event_hook(&self) -> &EventHook { - &self.event_hook + &self.data.event_hook } /// The index of the current turn. 0 until all choices pub fn current_turn(&self) -> u32 { - self.current_turn.load(Ordering::Relaxed) + self.data.current_turn.load(Ordering::Relaxed) } /// The time in nanoseconds the last turn took to run. Defaults to 0. pub fn last_turn_time(&self) -> u64 { - self.last_turn_time.load(Ordering::Relaxed) + self.data.last_turn_time.load(Ordering::Relaxed) } /// A queue of the yet to be executed choices in a turn. - pub fn current_turn_queue(&self) -> &RwLock> { - &self.current_turn_queue + pub fn current_turn_queue(&self) -> &RwLock>> { + &self.data.current_turn_queue } /// Get a Pokemon on the battlefield, on a specific side and an index on that side. - pub fn get_pokemon(&self, side: u8, index: u8) -> Option> { - let side = self.sides.get(side as usize); + pub fn get_pokemon(&self, side: u8, index: u8) -> Option { + let side = self.data.sides.get(side as usize); let pokemon_read_lock = side?.pokemon(); let pokemon = pokemon_read_lock.get(index as usize); pokemon?.clone() @@ -180,7 +199,7 @@ impl Battle { /// for that slot, or a party is responsible, but has no remaining Pokemon to throw out anymore, /// this returns false. pub fn can_slot_be_filled(&self, side: u8, index: u8) -> bool { - for party in &self.parties { + for party in &self.data.parties { if party.is_responsible_for_index(side, index) && party.has_pokemon_not_in_field() { return true; } @@ -197,12 +216,12 @@ impl Battle { } let mut surviving_side_exists = false; let mut winning_side = None; - for (side_index, side) in self.sides.iter().enumerate() { + for (side_index, side) in self.data.sides.iter().enumerate() { // If any side has fled, the battle end. if side.has_fled_battle() { - let mut w = self.result.write(); + let mut w = self.data.result.write(); *w = BattleResult::Inconclusive; - self.has_ended.store(true, Ordering::SeqCst); + self.data.has_ended.store(true, Ordering::SeqCst); return Ok(()); } // If the side is not defeated @@ -217,15 +236,15 @@ impl Battle { } // Everyone died :( if !surviving_side_exists { - let mut w = self.result.write(); + let mut w = self.data.result.write(); *w = BattleResult::Inconclusive; } // Someone survived, they won! else { - let mut w = self.result.write(); + let mut w = self.data.result.write(); *w = BattleResult::Conclusive(winning_side.ok_or(anyhow!("Winning side was not set"))?); } - self.has_ended.store(true, Ordering::SeqCst); + self.data.has_ended.store(true, Ordering::SeqCst); Ok(()) } @@ -263,7 +282,7 @@ impl Battle { let side = choice.user().get_battle_side_index(); match side { Some(side) => { - self.sides.get_res(side as usize)?.set_choice(choice)?; + self.data.sides.get_res(side as usize)?.set_choice(choice)?; self.check_choices_set_and_run()?; Ok(true) } @@ -274,7 +293,7 @@ impl Battle { /// Checks to see whether all Pokemon on the field have set their choices. If so, we then run /// the turn. fn check_choices_set_and_run(&self) -> Result<()> { - for side in &self.sides { + for side in &self.data.sides { if !side.all_choices_set() { return Ok(()); } @@ -283,20 +302,19 @@ impl Battle { } } let start_time = chrono::Utc::now(); - let mut choices = Vec::with_capacity(self.number_of_sides as usize * self.pokemon_per_side as usize); - for side in &self.sides { + let mut choices = Vec::with_capacity(self.data.number_of_sides as usize * self.data.pokemon_per_side as usize); + for side in &self.data.sides { let mut side_choices = side.choices().write(); for choice_opt in side_choices.deref_mut() { - let mut choice = choice_opt + let choice = choice_opt .as_mut() .ok_or(anyhow!("Choice was none, but all choices were set? Logic error."))?; - let c = choice.deref(); - if let TurnChoice::Move(data) = c { + if let TurnChoice::Move(data) = choice.clone().deref() { let mut change_priority = data.priority(); - script_hook!(change_priority, c, c, &mut change_priority); + script_hook!(change_priority, choice, choice, &mut change_priority); if change_priority != data.priority() { - if let TurnChoice::Move(data) = choice.deref_mut() { - *data.priority_mut() = change_priority; + if let TurnChoice::Move(data) = choice.clone().deref() { + data.set_priority(change_priority); } } } @@ -304,31 +322,34 @@ impl Battle { let mut speed = choice.user().boosted_stats().speed(); let c = choice.deref(); script_hook!(change_speed, c, c, &mut speed); - *choice.speed_mut() = speed; + choice.set_speed(speed); - choice.set_random_value(self.random.get()? as u32); + choice.set_random_value(self.data.random.get()? as u32); choices.push(choice_opt.take()); } // Drop the lock guard, as we need to write into it in reset_choices. drop(side_choices); side.reset_choices(); } - self.current_turn.fetch_add(1, Ordering::SeqCst); + self.data.current_turn.fetch_add(1, Ordering::SeqCst); - self.current_turn_queue.write().replace(ChoiceQueue::new(choices)); + self.data + .current_turn_queue + .write() + .replace(Arc::new(ChoiceQueue::new(choices))); { self.run_turn()?; } - self.current_turn_queue.write().take(); - self.event_hook.trigger(Event::EndTurn); + self.data.current_turn_queue.write().take(); + self.data.event_hook.trigger(Event::EndTurn); let end_time = chrono::Utc::now(); let time = end_time - start_time; match time.num_nanoseconds() { None => {} Some(v) => { - self.last_turn_time.store(v as u64, Ordering::SeqCst); + self.data.last_turn_time.store(v as u64, Ordering::SeqCst); } } Ok(()) @@ -341,16 +362,16 @@ impl Battle { .library() .load_script(self.into(), ScriptCategory::Weather, &weather)? .ok_or(anyhow!("Couldn't find weather script by name {}", weather))?; - self.weather.set(script); + self.data.weather.set(script); } else { - self.weather.clear(); + self.data.weather.clear(); } Ok(()) } /// Gets the current weather of the battle. If no weather is present, this returns None. pub fn weather_name(&self) -> Result> { - if let Some(script) = self.weather.get() { + if let Some(script) = self.data.weather.get() { let lock = script.read(); Ok(Some( lock.as_ref().ok_or(PkmnError::UnableToAcquireLock)?.name()?.clone(), @@ -361,13 +382,38 @@ impl Battle { } } +impl WeakBattleReference { + /// Attempts to upgrade the weak reference to a strong reference. If the strong reference has + /// been dropped, this returns None. + pub fn upgrade(&self) -> Option { + self.data.upgrade().map(|battle| Battle { data: battle }) + } + + /// Gets the inner pointer to the reference counted data. + pub(crate) fn as_ptr(&self) -> *const c_void { + self.data.as_ptr() as *const c_void + } +} + +unsafe impl Send for WeakBattleReference {} + +unsafe impl Sync for WeakBattleReference {} + +impl PartialEq for WeakBattleReference { + fn eq(&self, other: &Self) -> bool { + self.data.ptr_eq(&other.data) + } +} + +impl Eq for WeakBattleReference {} + impl VolatileScriptsOwner for Battle { fn volatile_scripts(&self) -> &Arc { - &self.volatile_scripts + &self.data.volatile_scripts } fn load_volatile_script(&self, key: &StringKey) -> Result>> { - self.library.load_script(self.into(), ScriptCategory::Battle, key) + self.data.library.load_script(self.into(), ScriptCategory::Battle, key) } } @@ -377,12 +423,12 @@ impl ScriptSource for Battle { } fn get_script_source_data(&self) -> &RwLock { - &self.script_source_data + &self.data.script_source_data } fn get_own_scripts(&self, scripts: &mut Vec) { - scripts.push((&self.weather).into()); - scripts.push((&self.volatile_scripts).into()); + scripts.push((&self.data.weather).into()); + scripts.push((&self.data.volatile_scripts).into()); } fn collect_scripts(&self, scripts: &mut Vec) -> Result<()> { @@ -393,7 +439,7 @@ impl ScriptSource for Battle { impl ValueIdentifiable for Battle { fn value_identifier(&self) -> ValueIdentifier { - self.identifier + self.data.identifier } } diff --git a/src/dynamic_data/models/battle_party.rs b/src/dynamic_data/models/battle_party.rs index 7cb6514..d61c84c 100755 --- a/src/dynamic_data/models/battle_party.rs +++ b/src/dynamic_data/models/battle_party.rs @@ -49,7 +49,7 @@ impl BattleParty { } /// Gets a Pokemon at an index. - pub fn get_pokemon(&self, index: usize) -> Option> { + pub fn get_pokemon(&self, index: usize) -> Option { self.party.at(index) } diff --git a/src/dynamic_data/models/battle_random.rs b/src/dynamic_data/models/battle_random.rs index 9a88b61..0d2c5dc 100755 --- a/src/dynamic_data/models/battle_random.rs +++ b/src/dynamic_data/models/battle_random.rs @@ -60,8 +60,8 @@ impl BattleRandom { pub fn effect_chance( &self, mut chance: f32, - executing_move: &ExecutingMove, - target: &Arc, + executing_move: &Arc, + target: &Pokemon, hit_number: u8, ) -> Result { script_hook!( diff --git a/src/dynamic_data/models/battle_side.rs b/src/dynamic_data/models/battle_side.rs index 8d878ba..635d2b3 100755 --- a/src/dynamic_data/models/battle_side.rs +++ b/src/dynamic_data/models/battle_side.rs @@ -1,3 +1,4 @@ +use std::ffi::c_void; use std::ops::Deref; use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; use std::sync::{Arc, Weak}; @@ -11,14 +12,14 @@ use crate::dynamic_data::event_hooks::Event; use crate::dynamic_data::models::battle::Battle; use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper}; -use crate::dynamic_data::Script; use crate::dynamic_data::ScriptSet; use crate::dynamic_data::VolatileScriptsOwner; +use crate::dynamic_data::{Script, WeakBattleReference}; use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; -/// A side on a battle. +/// The data that is stored for a battle side. #[derive(Debug)] -pub struct BattleSide { +struct BattleSideData { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The index of the side on the battle. @@ -26,18 +27,18 @@ pub struct BattleSide { /// The number of Pokemon that can be on the side. pokemon_per_side: u8, /// A list of pokemon currently on the battlefield. - pokemon: RwLock>>>, + pokemon: RwLock>>, /// The currently set choices for all Pokemon on the battlefield. Cleared when the turn starts. - choices: RwLock>>, + choices: RwLock>>>, /// The slots on the side that can still be filled. Once all slots are set to false, this side /// has lost the battle. fillable_slots: Vec, /// The number of choices that are set. choices_set: AtomicU8, /// A reference to the battle we're part of. - battle: Weak, + battle: WeakBattleReference, /// Whether or not this side has fled. - has_fled_battle: bool, + has_fled_battle: AtomicBool, /// The volatile scripts that are attached to the side. volatile_scripts: Arc, @@ -45,6 +46,20 @@ pub struct BattleSide { script_source_data: RwLock, } +/// A side on a battle. +#[derive(Debug)] +pub struct BattleSide { + /// The data that is stored for this side. + data: Arc, +} + +/// A non owning reference to a battle side. +#[derive(Debug, Clone)] +pub struct WeakBattleSideReference { + /// A weak reference to the data of the battle side. + data: Weak, +} + impl BattleSide { /// Instantiates a battle side. pub fn new(index: u8, pokemon_per_side: u8) -> Self { @@ -61,83 +76,92 @@ impl BattleSide { let pokemon = RwLock::new(pokemon); Self { - identifier: Default::default(), - index, - pokemon_per_side, - pokemon, - choices, - fillable_slots, - choices_set: AtomicU8::new(0), - battle: Weak::new(), - has_fled_battle: false, - volatile_scripts: Default::default(), - script_source_data: Default::default(), + data: Arc::new(BattleSideData { + identifier: Default::default(), + index, + pokemon_per_side, + pokemon, + choices, + fillable_slots, + choices_set: AtomicU8::new(0), + battle: WeakBattleReference::default(), + has_fled_battle: AtomicBool::new(false), + volatile_scripts: Default::default(), + script_source_data: Default::default(), + }), } } /// Set the battle this side belongs to. - pub(crate) fn set_battle(&mut self, battle: Weak) { - self.battle = battle; + pub(crate) fn set_battle(&self, battle: WeakBattleReference) { + #[allow(clippy::unwrap_used)] // Can only be Some() + unsafe { + (self.data.deref() as *const BattleSideData as *mut BattleSideData) + .as_mut() + .unwrap() + .battle = battle; + } } /// The index of the side on the battle. pub fn index(&self) -> u8 { - self.index + self.data.index } /// The number of Pokemon that can be on the side. pub fn pokemon_per_side(&self) -> u8 { - self.pokemon_per_side + self.data.pokemon_per_side } /// A list of pokemon currently on the battlefield. - pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec>>> { - self.pokemon.read() + pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec>> { + self.data.pokemon.read() } /// The currently set choices for all Pokemon on the battlefield. Cleared when the turn starts. - pub fn choices(&self) -> &RwLock>> { - &self.choices + pub fn choices(&self) -> &RwLock>>> { + &self.data.choices } /// The slots on the side that can still be filled. Once all slots are set to false, this side /// has lost the battle. pub fn fillable_slots(&self) -> &Vec { - &self.fillable_slots + &self.data.fillable_slots } /// The number of choices that are set. pub fn choices_set(&self) -> u8 { - self.choices_set.load(Ordering::SeqCst) + self.data.choices_set.load(Ordering::SeqCst) } /// A reference to the battle we're part of. - pub fn battle(&self) -> Result> { - self.battle + pub fn battle(&self) -> Result { + self.data + .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 { - self.has_fled_battle + self.data.has_fled_battle.load(Ordering::SeqCst) } /// The volatile scripts that are attached to the side. pub fn volatile_scripts(&self) -> &Arc { - &self.volatile_scripts + &self.data.volatile_scripts } /// Whether every Pokemon on this side has its choices pub fn all_choices_set(&self) -> bool { - self.choices_set() == self.pokemon_per_side + self.choices_set() == self.data.pokemon_per_side } /// Returns true if there are slots that need to be filled with a new pokemon, that have parties /// responsible for them. Returns false if all slots are filled with usable pokemon, or slots are /// empty, but can't be filled by any party anymore. pub fn all_slots_filled(&self) -> Result { - for (i, pokemon) in self.pokemon.read().iter().enumerate() { + for (i, pokemon) in self.data.pokemon.read().iter().enumerate() { match pokemon { Some(pokemon) => { - if !pokemon.is_usable() && self.battle()?.can_slot_be_filled(self.index, i as u8) { + if !pokemon.is_usable() && self.battle()?.can_slot_be_filled(self.data.index, i as u8) { return Ok(false); } } None => { - if self.battle()?.can_slot_be_filled(self.index, i as u8) { + if self.battle()?.can_slot_be_filled(self.data.index, i as u8) { return Ok(false); } } @@ -148,11 +172,11 @@ impl BattleSide { /// Sets a choice for a Pokemon on this side. pub(crate) fn set_choice(&self, choice: TurnChoice) -> Result<()> { - for (index, pokemon_slot) in self.pokemon.read().iter().enumerate() { + for (index, pokemon_slot) in self.data.pokemon.read().iter().enumerate() { if let Some(pokemon) = pokemon_slot { - if std::ptr::eq(pokemon.deref(), choice.user().deref()) { - self.choices.write().get_mut_res(index)?.replace(choice); - self.choices_set.fetch_add(1, Ordering::SeqCst); + if Pokemon::eq(pokemon, choice.user()) { + self.data.choices.write().get_mut_res(index)?.replace(choice.into()); + self.data.choices_set.fetch_add(1, Ordering::SeqCst); return Ok(()); } } @@ -162,21 +186,21 @@ impl BattleSide { /// Resets all choices on this side. pub fn reset_choices(&self) { - let len = self.choices.read().len(); + let len = self.data.choices.read().len(); for i in 0..len { - self.choices.write().get_mut(i).take(); + self.data.choices.write().get_mut(i).take(); } } /// Forcibly removes a Pokemon from the field. pub fn force_clear_pokemon(&mut self, index: u8) { - self.pokemon.write().get_mut(index as usize).take(); + self.data.pokemon.write().get_mut(index as usize).take(); } /// Switches out a spot on the field for a different Pokemon. - pub fn set_pokemon(&self, index: u8, pokemon: Option>) -> Result<()> { + pub fn set_pokemon(&self, index: u8, pokemon: Option) -> Result<()> { { - let mut write_lock = self.pokemon.write(); + let mut write_lock = self.data.pokemon.write(); let old = write_lock.get_mut_res(index as usize)?; let old = match pokemon { Some(pokemon) => old.replace(pokemon), @@ -192,33 +216,33 @@ impl BattleSide { } let pokemon = { - let read_lock = self.pokemon.read(); + let read_lock = self.data.pokemon.read(); &read_lock.get_res(index as usize)?.clone() }; if let Some(pokemon) = pokemon { - pokemon.set_battle_data(self.battle.clone(), self.index); + pokemon.set_battle_data(self.data.battle.clone(), self.data.index); pokemon.set_on_battlefield(true)?; pokemon.set_battle_index(index); let battle = self.battle()?; for side in battle.sides() { - if side.index() == self.index { + if side.index() == self.data.index { continue; } for opponent in side.pokemon().iter().flatten() { - opponent.mark_opponent_as_seen(Arc::downgrade(pokemon)); - pokemon.mark_opponent_as_seen(Arc::downgrade(opponent)); + opponent.mark_opponent_as_seen(pokemon.weak()); + pokemon.mark_opponent_as_seen(opponent.weak()); } } battle.event_hook().trigger(Event::Switch { - side_index: self.index, + side_index: self.data.index, index, pokemon: Some(pokemon.clone()), }); script_hook!(on_switch_in, pokemon, pokemon); } else { self.battle()?.event_hook().trigger(Event::Switch { - side_index: self.index, + side_index: self.data.index, index, pokemon: None, }); @@ -227,9 +251,9 @@ impl BattleSide { } /// Checks whether a Pokemon is on the field in this side. - pub fn is_pokemon_on_side(&self, pokemon: Arc) -> bool { - for p in self.pokemon.read().iter().flatten() { - if Arc::ptr_eq(p, &pokemon) { + pub fn is_pokemon_on_side(&self, pokemon: Pokemon) -> bool { + for p in self.data.pokemon.read().iter().flatten() { + if Pokemon::eq(p, &pokemon) { return true; } } @@ -239,18 +263,19 @@ impl BattleSide { /// Marks a slot as unfillable. This happens when no parties are able to fill the slot anymore. /// If this happens, the slot can not be used again. pub(crate) fn mark_slot_as_unfillable(&self, index: u8) -> Result<()> { - self.fillable_slots + self.data + .fillable_slots .get_res(index as usize)? .store(false, Ordering::SeqCst); Ok(()) } /// Checks whether a slot is unfillable or not. - pub fn is_slot_unfillable(&self, pokemon: Arc) -> Result { - for (i, slot) in self.pokemon.read().iter().enumerate() { + pub fn is_slot_unfillable(&self, pokemon: Pokemon) -> Result { + for (i, slot) in self.data.pokemon.read().iter().enumerate() { if let Some(p) = slot { - if Arc::ptr_eq(p, &pokemon) { - return Ok(self.fillable_slots.get_res(i)?.load(Ordering::Relaxed)); + if Pokemon::eq(p, &pokemon) { + return Ok(self.data.fillable_slots.get_res(i)?.load(Ordering::Relaxed)); } } } @@ -259,7 +284,7 @@ impl BattleSide { /// Checks whether the side has been defeated. pub fn is_defeated(&self) -> bool { - for fillable_slot in &self.fillable_slots { + for fillable_slot in &self.data.fillable_slots { if fillable_slot.load(Ordering::Relaxed) { return false; } @@ -269,19 +294,20 @@ impl BattleSide { /// Mark the side as fled. pub fn mark_as_fled(&mut self) { - self.has_fled_battle = true; + self.data.has_fled_battle.store(true, Ordering::SeqCst); } /// Gets a random Pokemon on the given side. pub fn get_random_creature_index(&self) -> Result { // TODO: Consider adding parameter to only get index for available creatures. - Ok(self.battle()?.random().get_max(self.pokemon_per_side as i32)? as u8) + Ok(self.battle()?.random().get_max(self.data.pokemon_per_side as i32)? as u8) } /// Swap two Pokemon on a single side around. pub fn swap_positions(&mut self, a: u8, b: u8) -> Result { + let data = &self.data; // If out of range, don't allow swapping. - if a >= self.pokemon_per_side || b >= self.pokemon_per_side { + if a >= data.pokemon_per_side || b >= data.pokemon_per_side { return Ok(false); } // If the two indices are the same, don't allow swapping. @@ -294,10 +320,10 @@ impl BattleSide { let mut party_b = None; let battle = self.battle()?; for party in battle.parties() { - if party.is_responsible_for_index(self.index, a) { + if party.is_responsible_for_index(data.index, a) { party_a = Some(party); } - if party.is_responsible_for_index(self.index, b) { + if party.is_responsible_for_index(data.index, b) { party_b = Some(party); } } @@ -315,19 +341,49 @@ impl BattleSide { return Ok(false); } - self.pokemon.write().swap(a as usize, b as usize); + data.pokemon.write().swap(a as usize, b as usize); self.battle()?.event_hook().trigger(Event::Swap { - side_index: self.index, + side_index: data.index, index_a: a, index_b: b, }); Ok(true) } + + /// Gets a weak reference to the side. + pub fn weak(&self) -> WeakBattleSideReference { + WeakBattleSideReference { + data: Arc::downgrade(&self.data), + } + } +} + +impl WeakBattleSideReference { + /// Upgrades the weak reference to a strong reference, returning `None` if the side has been + /// dropped. + pub fn upgrade(&self) -> Option { + self.data.upgrade().map(|data| BattleSide { data }) + } + + /// Gets the underlying pointer to the data of the side. + pub(crate) fn as_ptr(&self) -> *const c_void { + self.data.as_ptr() as *const c_void + } +} + +unsafe impl Send for WeakBattleSideReference {} + +unsafe impl Sync for WeakBattleSideReference {} + +impl PartialEq for WeakBattleSideReference { + fn eq(&self, other: &Self) -> bool { + self.data.ptr_eq(&other.data) + } } impl VolatileScriptsOwner for BattleSide { fn volatile_scripts(&self) -> &Arc { - &self.volatile_scripts + &self.data.volatile_scripts } fn load_volatile_script(&self, key: &StringKey) -> Result>> { @@ -343,11 +399,11 @@ impl ScriptSource for BattleSide { } fn get_script_source_data(&self) -> &RwLock { - &self.script_source_data + &self.data.script_source_data } fn get_own_scripts(&self, scripts: &mut Vec) { - scripts.push((&self.volatile_scripts).into()); + scripts.push((&self.data.volatile_scripts).into()); } fn collect_scripts(&self, scripts: &mut Vec) -> Result<()> { @@ -358,6 +414,6 @@ impl ScriptSource for BattleSide { impl ValueIdentifiable for BattleSide { fn value_identifier(&self) -> ValueIdentifier { - self.identifier + self.data.identifier } } diff --git a/src/dynamic_data/models/executing_move.rs b/src/dynamic_data/models/executing_move.rs index aa060d1..47a7caa 100755 --- a/src/dynamic_data/models/executing_move.rs +++ b/src/dynamic_data/models/executing_move.rs @@ -16,7 +16,6 @@ use crate::{PkmnError, ValueIdentifiable, ValueIdentifier}; /// A hit data is the data for a single hit, on a single target. #[derive(Default, Debug)] - pub struct HitData { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, @@ -96,9 +95,9 @@ pub struct ExecutingMove { number_of_hits: u8, /// A list of hits for this move. For multi target multi hit moves, this stores the hits linearly, /// for example: (target1, hit1), (target1, hit2), (target2, hit1), (target2, hit2), etc. - hits: Vec, + hits: Vec>, /// The user of the move. - user: Arc, + user: Pokemon, /// The move the user has actually chosen to do. chosen_move: Arc, /// The move that the user is actually going to do. @@ -116,7 +115,7 @@ impl ExecutingMove { pub fn new( targets: TargetList, number_of_hits: u8, - user: Arc, + user: Pokemon, chosen_move: Arc, use_move: Arc, script: ScriptContainer, @@ -124,7 +123,7 @@ impl ExecutingMove { let total_hits = number_of_hits as usize * targets.len(); let mut hits = Vec::with_capacity(total_hits); for _i in 0..total_hits { - hits.push(HitData::default()) + hits.push(Arc::new(HitData::default())) } Self { identifier: Default::default(), @@ -148,7 +147,7 @@ impl ExecutingMove { self.number_of_hits } /// The user of the move. - pub fn user(&self) -> &Arc { + pub fn user(&self) -> &Pokemon { &self.user } /// The move the user has actually chosen to do. @@ -165,10 +164,10 @@ impl ExecutingMove { } /// Gets a hit data for a target, with a specific index. - pub fn get_hit_data(&self, for_target: &Arc, hit: u8) -> Result<&HitData> { + pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> Result<&Arc> { for (index, target) in self.targets.iter().enumerate() { if let Some(target) = target { - if Arc::ptr_eq(target, for_target) { + if Pokemon::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), @@ -185,9 +184,9 @@ impl ExecutingMove { } /// Checks whether a Pokemon is a target for this move. - pub fn is_pokemon_target(&self, pokemon: &Arc) -> bool { + pub fn is_pokemon_target(&self, pokemon: &Pokemon) -> bool { for target in self.targets.iter().flatten() { - if Arc::ptr_eq(target, pokemon) { + if Pokemon::eq(target, pokemon) { return true; } } @@ -195,10 +194,10 @@ impl ExecutingMove { } /// Gets the index of the hits in this move where the hits for a specific target start. - pub(crate) fn get_index_of_target(&self, for_target: &Arc) -> Result { + pub(crate) fn get_index_of_target(&self, for_target: &Pokemon) -> Result { for (index, target) in self.targets.iter().enumerate() { if let Some(target) = target { - if Arc::ptr_eq(target, for_target) { + if Pokemon::eq(target, for_target) { let i = index * self.number_of_hits as usize; return Ok(i); } diff --git a/src/dynamic_data/models/pokemon.rs b/src/dynamic_data/models/pokemon.rs index 20e6cc4..79751a9 100755 --- a/src/dynamic_data/models/pokemon.rs +++ b/src/dynamic_data/models/pokemon.rs @@ -1,3 +1,4 @@ +use std::ffi::c_void; use std::fmt::{Debug, Formatter}; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering}; @@ -12,7 +13,9 @@ use crate::dynamic_data::event_hooks::Event; use crate::dynamic_data::models::battle::Battle; use crate::dynamic_data::models::learned_move::{LearnedMove, MoveLearnMethod}; use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper}; -use crate::dynamic_data::{DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScriptsOwner}; +use crate::dynamic_data::{ + DynamicLibrary, Script, ScriptCategory, ScriptContainer, ScriptSet, VolatileScriptsOwner, WeakBattleReference, +}; use crate::static_data::AbilityIndex; use crate::static_data::Form; use crate::static_data::Gender; @@ -26,8 +29,8 @@ use crate::utils::Random; use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt}; use anyhow::{anyhow, bail, Result}; -/// An individual Pokemon as we know and love them. -pub struct Pokemon { +/// The data of a Pokemon. +struct PokemonData { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The library data of the Pokemon. @@ -67,16 +70,16 @@ pub struct Pokemon { height: Atomic, /// The stats of the Pokemon when disregarding any stat boosts. - flat_stats: StatisticSet, + flat_stats: Arc>, /// The statistics boosts of the Pokemon. Will prevent the value from going above 6, and below /// -6. - stat_boost: ClampedStatisticSet, + stat_boost: Arc>, /// The stats of the Pokemon including the stat boosts - boosted_stats: StatisticSet, + boosted_stats: Arc>, /// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. - individual_values: ClampedStatisticSet, + individual_values: Arc>, /// The [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. - effort_values: ClampedStatisticSet, + effort_values: Arc>, /// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon. nature: Arc, @@ -118,6 +121,24 @@ pub struct Pokemon { script_source_data: RwLock, } +/// An individual Pokemon. +#[derive(Clone)] +pub struct Pokemon { + /// The data of the Pokemon. + data: Arc, +} + +/// A non-owning reference to a Pokemon. +#[derive(Debug, Clone)] +pub struct WeakPokemonReference { + /// The weak reference to the data. + data: Weak, +} + +unsafe impl Send for WeakPokemonReference {} + +unsafe impl Sync for WeakPokemonReference {} + impl Pokemon { /// Instantiates a new Pokemon. pub fn new( @@ -143,7 +164,7 @@ impl Pokemon { .natures() .get_nature(nature) .ok_or(PkmnError::InvalidNatureName { nature: nature.clone() })?; - let mut pokemon = Self { + let pokemon_data = PokemonData { identifier: Default::default(), library, species: RwLock::new(species), @@ -180,28 +201,32 @@ impl Pokemon { volatile: Default::default(), script_source_data: Default::default(), }; + + let pokemon = Self { + data: Arc::new(pokemon_data), + }; pokemon.recalculate_flat_stats()?; let health = pokemon.flat_stats().hp(); - pokemon.current_health = AtomicU32::new(health); + pokemon.data.current_health.store(health, Ordering::Relaxed); Ok(pokemon) } /// The library data of the Pokemon. pub fn library(&self) -> &Arc { - &self.library + &self.data.library } /// The species of the Pokemon. pub fn species(&self) -> Arc { - self.species.read().clone() + self.data.species.read().clone() } /// The form of the Pokemon. pub fn form(&self) -> Arc { - self.form.read().clone() + self.data.form.read().clone() } /// The species that should be displayed to the user. This handles stuff like the Illusion ability. pub fn display_species(&self) -> Arc { - if let Some(v) = &self.display_species { + if let Some(v) = &self.data.display_species { v.clone() } else { self.species() @@ -209,7 +234,7 @@ impl Pokemon { } /// The form that should be displayed to the user. This handles stuff like the Illusion ability. pub fn display_form(&self) -> Arc { - if let Some(v) = &self.display_form { + if let Some(v) = &self.data.display_form { v.clone() } else { self.form() @@ -217,53 +242,57 @@ impl Pokemon { } /// The current level of the Pokemon. pub fn level(&self) -> LevelInt { - self.level.load(Ordering::Relaxed) + self.data.level.load(Ordering::Relaxed) } /// The amount of experience of the Pokemon. pub fn experience(&self) -> u32 { - self.experience.load(Ordering::Relaxed) + self.data.experience.load(Ordering::Relaxed) } /// A unique random number for this Pokemon. pub fn unique_identifier(&self) -> u32 { - self.unique_identifier + self.data.unique_identifier } /// The gender of the Pokemon. pub fn gender(&self) -> Gender { - *self.gender.read() + *self.data.gender.read() } /// The coloring of the Pokemon. Value 0 is the default, value 1 means shiny. Other values are /// currently not used, and can be used for other implementations. pub fn coloring(&self) -> u8 { - self.coloring + self.data.coloring } /// Gets the held item of a Pokemon pub fn held_item(&self) -> &RwLock>> { - &self.held_item + &self.data.held_item } /// Checks whether the Pokemon is holding a specific item. pub fn has_held_item(&self, name: &StringKey) -> bool { // Only true if we have an item, and the item name is the same as the requested item. - if let Some(v) = self.held_item.read().deref() { + if let Some(v) = self.data.held_item.read().deref() { return v.name() == name; } false } /// Changes the held item of the Pokemon. Returns the previously held item. pub fn set_held_item(&self, item: &Arc) -> Option> { - self.held_item.write().replace(item.clone()) + self.data.held_item.write().replace(item.clone()) } /// Removes the held item from the Pokemon. Returns the previously held item. pub fn remove_held_item(&self) -> Option> { - self.held_item.write().take() + self.data.held_item.write().take() } /// Makes the Pokemon uses its held item. pub fn consume_held_item(&self) -> Result { - if self.held_item.read().is_none() { + if self.data.held_item.read().is_none() { return Ok(false); } - let script = self - .library - .load_item_script(self.held_item.read().as_ref().ok_or(PkmnError::UnableToAcquireLock)?)?; + let script = self.data.library.load_item_script( + self.data + .held_item + .read() + .as_ref() + .ok_or(PkmnError::UnableToAcquireLock)?, + )?; if script.is_none() { return Ok(false); } @@ -274,60 +303,60 @@ impl Pokemon { /// The remaining health points of the Pokemon. pub fn current_health(&self) -> u32 { - self.current_health.load(Ordering::Relaxed) + self.data.current_health.load(Ordering::Relaxed) } /// The max health points of the Pokemon. pub fn max_health(&self) -> u32 { - self.boosted_stats.hp() + self.data.boosted_stats.hp() } /// The weight of the Pokemon in kilograms. pub fn weight(&self) -> f32 { - self.weight.load(Ordering::Relaxed) + self.data.weight.load(Ordering::Relaxed) } /// Sets the weight of the Pokemon in kilograms. pub fn set_weight(&self, weight: f32) { - self.weight.store(weight, Ordering::Relaxed) + self.data.weight.store(weight, Ordering::Relaxed) } /// The height of the Pokemon in meters. pub fn height(&self) -> f32 { - self.height.load(Ordering::Relaxed) + self.data.height.load(Ordering::Relaxed) } /// An optional nickname of the Pokemon. pub fn nickname(&self) -> &Option { - &self.nickname + &self.data.nickname } /// An index of the ability to find the actual ability on the form. pub fn real_ability(&self) -> &AbilityIndex { - &self.ability_index + &self.data.ability_index } /// The current types of the Pokemon. pub fn types(&self) -> RwLockReadGuard<'_, RawRwLock, Vec> { - self.types.read() + self.data.types.read() } /// The moves the Pokemon has learned. This is of a set length of [`MAX_MOVES`]. Empty move slots /// are defined by None. pub fn learned_moves(&self) -> &RwLock<[Option>; MAX_MOVES]> { - &self.moves + &self.data.moves } /// The stats of the Pokemon when disregarding any stat boosts. - pub fn flat_stats(&self) -> &StatisticSet { - &self.flat_stats + pub fn flat_stats(&self) -> &Arc> { + &self.data.flat_stats } /// The amount of boosts on a specific stat. - pub fn stat_boosts(&self) -> &ClampedStatisticSet { - &self.stat_boost + pub fn stat_boosts(&self) -> &Arc> { + &self.data.stat_boost } /// The stats of the Pokemon including the stat boosts - pub fn boosted_stats(&self) -> &StatisticSet { - &self.boosted_stats + pub fn boosted_stats(&self) -> &Arc> { + &self.data.boosted_stats } /// Get the stat boosts for a specific stat. pub fn stat_boost(&self, stat: Statistic) -> i8 { - self.stat_boost.get_stat(stat) + self.data.stat_boost.get_stat(stat) } /// Change a boosted stat by a certain amount. pub fn change_stat_boost(&self, stat: Statistic, mut diff_amount: i8, self_inflicted: bool) -> Result { @@ -357,13 +386,13 @@ impl Pokemon { } let mut changed = false; - let old_value = self.stat_boost.get_stat(stat); + let old_value = self.data.stat_boost.get_stat(stat); match diff_amount.cmp(&0_i8) { std::cmp::Ordering::Less => { - changed = self.stat_boost.decrease_stat(stat, -diff_amount); + changed = self.data.stat_boost.decrease_stat(stat, -diff_amount); } std::cmp::Ordering::Greater => { - changed = self.stat_boost.increase_stat(stat, -diff_amount); + changed = self.data.stat_boost.increase_stat(stat, -diff_amount); } _ => {} } @@ -383,17 +412,17 @@ impl Pokemon { } /// The [individual values](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. - pub fn individual_values(&self) -> &ClampedStatisticSet { - &self.individual_values + pub fn individual_values(&self) -> &Arc> { + &self.data.individual_values } /// The [effort values](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. - pub fn effort_values(&self) -> &ClampedStatisticSet { - &self.effort_values + pub fn effort_values(&self) -> &Arc> { + &self.data.effort_values } /// Gets the battle the battle is currently in. - pub fn get_battle(&self) -> Option> { - let r = self.battle_data.read(); + pub fn get_battle(&self) -> Option { + let r = self.data.battle_data.read(); if let Some(data) = &r.deref() { data.battle.upgrade() } else { @@ -403,26 +432,31 @@ impl Pokemon { /// Get the index of the side of the battle the Pokemon is in. Only returns a value if the Pokemon /// is on the battlefield. pub fn get_battle_side_index(&self) -> Option { - self.battle_data.read().as_ref().map(|data| data.battle_side_index()) + self.data + .battle_data + .read() + .as_ref() + .map(|data| data.battle_side_index()) } /// Get the index of the slot on the side of the battle the Pokemon is in. Only returns a value /// if the Pokemon is on the battlefield. pub fn get_battle_index(&self) -> Option { - self.battle_data.read().as_ref().map(|data| data.index()) + self.data.battle_data.read().as_ref().map(|data| data.index()) } /// Returns whether something overrides the ability. pub fn is_ability_overriden(&self) -> bool { - self.override_ability.is_some() + self.data.override_ability.is_some() } /// Returns the currently active ability. pub fn active_ability(&self) -> Result> { - if let Some(v) = &self.override_ability { + if let Some(v) = &self.data.override_ability { return Ok(v.clone()); } let form = self.form(); - let ability = form.get_ability(self.ability_index)?; + let ability = form.get_ability(self.data.ability_index)?; Ok(self + .data .library .static_data() .abilities() @@ -434,68 +468,70 @@ impl Pokemon { /// The script for the status. pub fn status(&self) -> &ScriptContainer { - &self.status_script + &self.data.status_script } /// Returns the script for the currently active ability. pub fn ability_script(&self) -> &ScriptContainer { - &self.ability_script + &self.data.ability_script } /// Whether or not the Pokemon is allowed to gain experience. pub fn allowed_experience_gain(&self) -> bool { - self.allowed_experience + self.data.allowed_experience } /// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon. pub fn nature(&self) -> &Arc { - &self.nature + &self.data.nature } /// Calculates the flat stats on the Pokemon. This should be called when for example the base /// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted /// stats, as those depend on the flat stats. pub fn recalculate_flat_stats(&self) -> Result<()> { - self.library + self.data + .library .stat_calculator() - .calculate_flat_stats(self, &self.flat_stats)?; + .calculate_flat_stats(self, &self.data.flat_stats)?; self.recalculate_boosted_stats()?; Ok(()) } /// Calculates the boosted stats on the Pokemon, _without_ recalculating the flat stats. /// This should be called when a stat boost changes. pub fn recalculate_boosted_stats(&self) -> Result<()> { - self.library + self.data + .library .stat_calculator() - .calculate_boosted_stats(self, &self.boosted_stats) + .calculate_boosted_stats(self, &self.data.boosted_stats) } /// Change the species of the Pokemon. pub fn change_species(&self, species: Arc, form: Arc) -> Result<()> { - *self.species.write() = species.clone(); - *self.form.write() = form.clone(); + *self.data.species.write() = species.clone(); + *self.data.form.write() = form.clone(); // If the pokemon is genderless, but it's new species is not, we want to set its gender if self.gender() != Gender::Genderless && species.gender_rate() < 0.0 { // If we're in battle, use the battle random for predictability - let r = self.battle_data.read(); + let r = self.data.battle_data.read(); if let Some(data) = r.deref() { 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()), }; - *self.gender.write() = species.get_random_gender(random.deref_mut()); + *self.data.gender.write() = species.get_random_gender(random.deref_mut()); } else { // If we're not in battle, just use a new random. - *self.gender.write() = species.get_random_gender(&mut Random::default()); + *self.data.gender.write() = species.get_random_gender(&mut Random::default()); } } // Else if the new species is genderless, but the pokemon has a gender, make the creature genderless. else if species.gender_rate() < 0.0 && self.gender() != Gender::Genderless { - *self.gender.write() = Gender::Genderless; + *self.data.gender.write() = Gender::Genderless; } - let r = self.battle_data.read(); + let r = self.data.battle_data.read(); if let Some(battle_data) = &r.deref() { if let Some(battle) = battle_data.battle() { battle.event_hook().trigger(Event::SpeciesChange { @@ -513,29 +549,31 @@ impl Pokemon { if self.form().value_identifier() == form.value_identifier() { return Ok(()); } - *self.form.write() = form.clone(); + *self.data.form.write() = form.clone(); { - let mut type_lock = self.types.write(); + let mut type_lock = self.data.types.write(); type_lock.clear(); for t in form.types() { type_lock.push(*t); } } - self.weight.store(form.weight(), Ordering::SeqCst); - self.height.store(form.height(), Ordering::SeqCst); + self.data.weight.store(form.weight(), Ordering::SeqCst); + self.data.height.store(form.height(), Ordering::SeqCst); let ability = self.active_ability()?; let ability_script = self + .data .library .load_script(self.into(), ScriptCategory::Ability, ability.name())?; if let Some(ability_script) = ability_script { let script_result = self + .data .ability_script .set(ability_script) .as_ref() // Ensure the ability script gets initialized with the parameters for the ability. - .on_initialize(&self.library, ability.parameters().to_vec()); + .on_initialize(&self.data.library, ability.parameters().to_vec()); match script_result { Ok(_) => (), Err(e) => { @@ -543,21 +581,23 @@ impl Pokemon { } } } else { - self.ability_script.clear(); + self.data.ability_script.clear(); } let old_health = self.max_health(); self.recalculate_flat_stats()?; let diff_health = (self.max_health() - old_health) as i32; if self.current_health() == 0 && (self.current_health() as i32) < -diff_health { - self.current_health.store(0, Ordering::SeqCst); + self.data.current_health.store(0, Ordering::SeqCst); } else if diff_health < 0 { - self.current_health.fetch_sub(-diff_health as u32, Ordering::SeqCst); + self.data + .current_health + .fetch_sub(-diff_health as u32, Ordering::SeqCst); } else { - self.current_health.fetch_add(diff_health as u32, Ordering::SeqCst); + self.data.current_health.fetch_add(diff_health as u32, Ordering::SeqCst); } // TODO: consider form specific attacks? - let r = self.battle_data.read(); + let r = self.data.battle_data.read(); if let Some(battle_data) = r.deref() { if let Some(battle) = battle_data.battle() { battle.event_hook().trigger(Event::FormChange { @@ -571,7 +611,7 @@ impl Pokemon { /// Whether or not the Pokemon is useable in a battle. pub fn is_usable(&self) -> bool { - !self.is_caught && !self.is_egg && !self.is_fainted() + !self.data.is_caught && !self.data.is_egg && !self.is_fainted() } /// Returns whether the Pokemon is fainted. @@ -580,8 +620,8 @@ impl Pokemon { } /// Sets the current battle the Pokemon is in. - pub fn set_battle_data(&self, battle: Weak, battle_side_index: u8) { - let mut w = self.battle_data.write(); + pub fn set_battle_data(&self, battle: WeakBattleReference, battle_side_index: u8) { + let mut w = self.data.battle_data.write(); if let Some(battle_data) = w.deref_mut() { battle_data.battle = battle; battle_data.battle_side_index.store(battle_side_index, Ordering::SeqCst); @@ -598,13 +638,13 @@ impl Pokemon { /// Sets whether or not the Pokemon is on the battlefield. pub fn set_on_battlefield(&self, value: bool) -> Result<()> { - let r = self.battle_data.read(); + let r = self.data.battle_data.read(); if let Some(data) = &mut r.deref() { data.on_battle_field.store(value, Ordering::SeqCst); if !value { - self.volatile.clear()?; - self.weight.store(self.form().weight(), Ordering::SeqCst); - self.height.store(self.form().height(), Ordering::SeqCst); + self.data.volatile.clear()?; + self.data.weight.store(self.form().weight(), Ordering::SeqCst); + self.data.height.store(self.form().height(), Ordering::SeqCst); } } Ok(()) @@ -612,7 +652,7 @@ impl Pokemon { /// Sets the index of the slot of the side the Pokemon is on. pub fn set_battle_index(&self, index: u8) { - let r = self.battle_data.read(); + let r = self.data.battle_data.read(); if let Some(data) = r.deref() { data.index.store(index, Ordering::SeqCst) } @@ -620,16 +660,20 @@ impl Pokemon { /// Whether or not the Pokemon is on the battlefield. pub fn is_on_battlefield(&self) -> bool { - self.battle_data.read().as_ref().is_some_and(|a| a.on_battle_field()) + self.data + .battle_data + .read() + .as_ref() + .is_some_and(|a| a.on_battle_field()) } /// Marks an opponent as seen, for use in experience gain. - pub fn mark_opponent_as_seen(&self, pokemon: Weak) { - let r = self.battle_data.read(); - if let Some(battle_data) = &r.deref() { + pub fn mark_opponent_as_seen(&self, pokemon: WeakPokemonReference) { + let r = self.data.battle_data.read(); + if let Some(battle_data) = r.deref() { let mut opponents = battle_data.seen_opponents().write(); for seen_opponent in opponents.deref() { - if seen_opponent.ptr_eq(&pokemon) { + if seen_opponent.eq(&pokemon) { return; } } @@ -646,7 +690,7 @@ impl Pokemon { return Ok(()); } let new_health = self.current_health() - damage; - if let Some(battle_data) = &self.battle_data.read().deref() { + if let Some(battle_data) = &self.data.battle_data.read().deref() { if let Some(battle) = battle_data.battle() { battle.event_hook().trigger(Event::Damage { pokemon: self, @@ -656,11 +700,17 @@ impl Pokemon { }); } } - if self.battle_data.read().as_ref().is_some_and(|a| a.on_battle_field()) { + if self + .data + .battle_data + .read() + .as_ref() + .is_some_and(|a| a.on_battle_field()) + { script_hook!(on_damage, self, self, source, self.current_health(), new_health); } - self.current_health.store(new_health, Ordering::SeqCst); + self.data.current_health.store(new_health, Ordering::SeqCst); if self.is_fainted() && damage > 0 { self.on_faint(source)?; } @@ -669,7 +719,7 @@ impl Pokemon { /// Triggers when the Pokemon faints. fn on_faint(&self, source: DamageSource) -> Result<()> { - let r = self.battle_data.read(); + let r = self.data.battle_data.read(); if let Some(battle_data) = r.deref() { if let Some(battle) = battle_data.battle() { battle.event_hook().trigger(Event::Faint { pokemon: self }); @@ -703,7 +753,7 @@ impl Pokemon { return false; } let new_health = self.current_health() + max_amount; - if let Some(battle_data) = &self.battle_data.read().deref() { + if let Some(battle_data) = &self.data.battle_data.read().deref() { if let Some(battle) = battle_data.battle() { battle.event_hook().trigger(Event::Heal { pokemon: self, @@ -712,7 +762,7 @@ impl Pokemon { }); } } - self.current_health.store(new_health, Ordering::SeqCst); + self.data.current_health.store(new_health, Ordering::SeqCst); true } @@ -727,6 +777,7 @@ impl Pokemon { } }; let move_data = self + .data .library .static_data() .moves() @@ -742,12 +793,13 @@ impl Pokemon { /// Removes the current non-volatile status from the Pokemon. pub fn clear_status(&self) { - self.status_script.clear() + self.data.status_script.clear() } /// Increases the level by a certain amount pub fn change_level_by(&self, amount: LevelInt) -> Result<()> { - self.level + self.data + .level .fetch_update(Ordering::SeqCst, Ordering::Relaxed, |x| { let max_level = self.library().static_data().settings().maximum_level(); if x + amount > max_level { @@ -759,13 +811,50 @@ impl Pokemon { .ok(); self.recalculate_flat_stats() } + + /// Take a weak reference to the Pokemon. + pub fn weak(&self) -> WeakPokemonReference { + WeakPokemonReference { + data: Arc::downgrade(&self.data), + } + } +} + +impl PartialEq for Pokemon { + fn eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.data, &other.data) + } +} + +impl Eq for Pokemon {} + +impl PartialEq for WeakPokemonReference { + fn eq(&self, other: &Self) -> bool { + Weak::ptr_eq(&self.data, &other.data) + } +} + +impl Eq for WeakPokemonReference {} + +impl WeakPokemonReference { + /// Attempts to upgrade the weak reference to a strong reference. + pub fn upgrade(&self) -> Option { + Some(Pokemon { + data: self.data.upgrade()?, + }) + } + + /// Gets the pointer to the underlying data. + pub(crate) fn as_ptr(&self) -> *const c_void { + self.data.as_ptr() as *const c_void + } } /// The data of the Pokemon related to being in a battle. #[derive(Debug)] pub struct PokemonBattleData { /// The battle data of the Pokemon - battle: Weak, + battle: WeakBattleReference, /// The index of the side of the Pokemon battle_side_index: AtomicU8, /// The index of the slot on the side of the Pokemon. @@ -773,16 +862,12 @@ pub struct PokemonBattleData { /// Whether or not the Pokemon is on the battlefield. on_battle_field: AtomicBool, /// A list of opponents the Pokemon has seen this battle. - seen_opponents: RwLock>>, + seen_opponents: RwLock>, } impl PokemonBattleData { /// The battle data of the Pokemon - pub fn battle_mut(&mut self) -> Option> { - self.battle.upgrade() - } - /// The battle data of the Pokemon - pub fn battle(&self) -> Option> { + pub fn battle(&self) -> Option { self.battle.upgrade() } @@ -799,7 +884,7 @@ impl PokemonBattleData { self.on_battle_field.load(Ordering::Relaxed) } /// A list of opponents the Pokemon has seen this battle. - pub fn seen_opponents(&self) -> &RwLock>> { + pub fn seen_opponents(&self) -> &RwLock> { &self.seen_opponents } } @@ -807,7 +892,7 @@ impl PokemonBattleData { impl ScriptSource for Pokemon { fn get_script_count(&self) -> Result { let mut c = 3; - if let Some(battle_data) = &self.battle_data.read().deref() { + if let Some(battle_data) = &self.data.battle_data.read().deref() { if let Some(battle) = battle_data.battle() { c += battle .sides() @@ -819,19 +904,19 @@ impl ScriptSource for Pokemon { } fn get_script_source_data(&self) -> &RwLock { - &self.script_source_data + &self.data.script_source_data } fn get_own_scripts(&self, scripts: &mut Vec) { - scripts.push((&self.held_item_trigger_script).into()); - scripts.push((&self.ability_script).into()); - scripts.push((&self.status_script).into()); - scripts.push((&self.volatile).into()); + scripts.push((&self.data.held_item_trigger_script).into()); + scripts.push((&self.data.ability_script).into()); + scripts.push((&self.data.status_script).into()); + scripts.push((&self.data.volatile).into()); } fn collect_scripts(&self, scripts: &mut Vec) -> Result<()> { self.get_own_scripts(scripts); - if let Some(battle_data) = &self.battle_data.read().deref() { + if let Some(battle_data) = &self.data.battle_data.read().deref() { if let Some(battle) = battle_data.battle() { battle .sides() @@ -845,17 +930,17 @@ impl ScriptSource for Pokemon { impl VolatileScriptsOwner for Pokemon { fn volatile_scripts(&self) -> &Arc { - &self.volatile + &self.data.volatile } fn load_volatile_script(&self, key: &StringKey) -> Result>> { - self.library.load_script(self.into(), ScriptCategory::Pokemon, key) + self.data.library.load_script(self.into(), ScriptCategory::Pokemon, key) } } impl ValueIdentifiable for Pokemon { fn value_identifier(&self) -> ValueIdentifier { - self.identifier + self.data.identifier } } @@ -921,7 +1006,7 @@ pub mod test { }); let mut static_lib = MockStaticData::new(); - static_lib.expect_species().return_const(Box::new(species_lib)); + static_lib.expect_species().return_const(Arc::new(species_lib)); let mut growth_rate_lib = MockGrowthRateLibrary::new(); growth_rate_lib @@ -934,8 +1019,8 @@ pub mod test { Some(Arc::new(n)) }); - static_lib.expect_growth_rates().return_const(Box::new(growth_rate_lib)); - static_lib.expect_natures().return_const(Box::new(nature_lib)); + static_lib.expect_growth_rates().return_const(Arc::new(growth_rate_lib)); + static_lib.expect_natures().return_const(Arc::new(nature_lib)); let mut stat_calculator = MockBattleStatCalculator::new(); stat_calculator.expect_calculate_flat_stats().returning(|_, _| Ok(())); @@ -944,8 +1029,8 @@ pub mod test { .returning(|_, _| Ok(())); let mut lib = MockDynamicLibrary::new(); - lib.expect_static_data().return_const(Box::new(static_lib)); - lib.expect_stat_calculator().return_const(Box::new(stat_calculator)); + lib.expect_static_data().return_const(Arc::new(static_lib)); + lib.expect_stat_calculator().return_const(Arc::new(stat_calculator)); Arc::new(lib) } diff --git a/src/dynamic_data/models/pokemon_party.rs b/src/dynamic_data/models/pokemon_party.rs index bbe1307..98a7e6e 100755 --- a/src/dynamic_data/models/pokemon_party.rs +++ b/src/dynamic_data/models/pokemon_party.rs @@ -1,7 +1,6 @@ use anyhow::Result; use parking_lot::lock_api::RwLockReadGuard; use parking_lot::{RawRwLock, RwLock}; -use std::sync::Arc; use crate::dynamic_data::models::pokemon::Pokemon; use crate::{ValueIdentifiable, ValueIdentifier, VecExt}; @@ -12,7 +11,7 @@ pub struct PokemonParty { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// The underlying list of Pokemon. - pokemon: RwLock>>>, + pokemon: RwLock>>, } impl PokemonParty { @@ -29,7 +28,7 @@ impl PokemonParty { } /// Instantiates a party with a list. - pub fn new_from_vec(pokemon: Vec>>) -> Self { + pub fn new_from_vec(pokemon: Vec>) -> Self { Self { identifier: Default::default(), pokemon: RwLock::new(pokemon), @@ -37,7 +36,7 @@ impl PokemonParty { } /// Gets a Pokemon at an index in the party. - pub fn at(&self, index: usize) -> Option> { + pub fn at(&self, index: usize) -> Option { let read_lock = self.pokemon.read(); let opt = read_lock.get(index); if let Some(v) = opt { @@ -53,7 +52,7 @@ impl PokemonParty { } /// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon. - pub fn swap_into(&self, index: usize, pokemon: Option>) -> Result>> { + pub fn swap_into(&self, index: usize, pokemon: Option) -> Result> { let mut party = self.pokemon.write(); if index >= party.len() { return Ok(pokemon); @@ -82,7 +81,7 @@ impl PokemonParty { } /// Gets the underlying list of Pokemon. - pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec>>> { + pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec>> { self.pokemon.read() } @@ -112,7 +111,7 @@ impl PokemonParty { /// Checks if the party contains a given pokemon. pub fn has_pokemon(&self, pokemon: &Pokemon) -> bool { for p in self.pokemon.read().iter().flatten() { - if std::ptr::eq(p.as_ref(), pokemon) { + if Pokemon::eq(p, pokemon) { return true; } } diff --git a/src/dynamic_data/script_handling/mod.rs b/src/dynamic_data/script_handling/mod.rs index 95ab715..6723053 100755 --- a/src/dynamic_data/script_handling/mod.rs +++ b/src/dynamic_data/script_handling/mod.rs @@ -236,7 +236,7 @@ impl ScriptIterator { } } else if let ScriptWrapper::Script(script) = wrapper { if let Some(v) = script.upgrade() { - if let Some(..) = v.read().as_ref() { + if v.read().as_ref().is_some() { return Ok(true); } } diff --git a/src/dynamic_data/script_handling/script.rs b/src/dynamic_data/script_handling/script.rs index 2f2a7b7..da88d33 100755 --- a/src/dynamic_data/script_handling/script.rs +++ b/src/dynamic_data/script_handling/script.rs @@ -2,17 +2,17 @@ use anyhow::{anyhow, Result}; use std::any::Any; use std::fmt::{Debug, Formatter}; use std::ops::Deref; -use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread::JoinHandle; use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard}; use crate::dynamic_data::choices::TurnChoice; -use crate::dynamic_data::ExecutingMove; -use crate::dynamic_data::Pokemon; use crate::dynamic_data::{Battle, DynamicLibrary}; use crate::dynamic_data::{BattleSide, DamageSource}; +use crate::dynamic_data::{ExecutingMove, WeakBattleReference, WeakPokemonReference}; +use crate::dynamic_data::{Pokemon, WeakBattleSideReference}; use crate::static_data::{EffectParameter, TypeIdentifier}; use crate::static_data::{Item, Statistic}; use crate::StringKey; @@ -69,77 +69,77 @@ pub trait Script: Send + Sync { Ok(()) } /// This function is ran when this script starts being in effect. - fn on_initialize(&self, _library: &Arc, _pars: Vec) -> Result<()> { + fn on_initialize(&self, _library: &Arc, _pars: Vec>) -> Result<()> { Ok(()) } /// This function is ran just before the start of the turn. Everyone has made its choices here, /// and the turn is about to start. This is a great place to initialize data if you need to know /// something has happened during a turn. - fn on_before_turn(&self, _choice: &TurnChoice) -> Result<()> { + fn on_before_turn(&self, _choice: &Arc) -> Result<()> { Ok(()) } /// This function allows you to modify the effective speed of the Pokemon. This is ran before /// turn ordering, so overriding here will allow you to put certain Pokemon before others. - fn change_speed(&self, _choice: &TurnChoice, _speed: &mut u32) -> Result<()> { + fn change_speed(&self, _choice: &Arc, _speed: &mut u32) -> Result<()> { Ok(()) } /// This function allows you to modify the effective priority of the Pokemon. This is ran before /// turn ordering, so overriding here will allow you to put certain Pokemon before others. Note /// that this is only relevant on move choices, as other turn choice types do not have a priority. - fn change_priority(&self, _choice: &TurnChoice, _priority: &mut i8) -> Result<()> { + fn change_priority(&self, _choice: &Arc, _priority: &mut i8) -> Result<()> { Ok(()) } /// This function allows you to change the move that is used during execution. This is useful for /// moves such as metronome, where the move chosen actually differs from the move used. - fn change_move(&self, _choice: &TurnChoice, _move_name: &mut StringKey) -> Result<()> { + fn change_move(&self, _choice: &Arc, _move_name: &mut StringKey) -> Result<()> { Ok(()) } /// This function allows you to change a move into a multi-hit move. The number of hits set here /// gets used as the number of hits. If set to 0, this will behave as if the move missed on its /// first hit. - fn change_number_of_hits(&self, _choice: &TurnChoice, _number_of_hits: &mut u8) -> Result<()> { + fn change_number_of_hits(&self, _choice: &Arc, _number_of_hits: &mut u8) -> Result<()> { Ok(()) } /// This function allows you to prevent a move from running. If this gets set to true, the move /// ends execution here. No PP will be decreased in this case. - fn prevent_move(&self, _move: &ExecutingMove, _prevent: &mut bool) -> Result<()> { + fn prevent_move(&self, _move: &Arc, _prevent: &mut bool) -> Result<()> { Ok(()) } /// This function makes the move fail. If the fail field gets set to true, the move ends execution, /// and fail events get triggered. - fn fail_move(&self, _move: &ExecutingMove, _fail: &mut bool) -> Result<()> { + fn fail_move(&self, _move: &Arc, _fail: &mut bool) -> Result<()> { Ok(()) } /// Similar to [`Self::prevent_move`]. This function will also stop execution, but PP will be /// decreased. - fn stop_before_move(&self, _move: &ExecutingMove, _stop: &mut bool) -> Result<()> { + fn stop_before_move(&self, _move: &Arc, _stop: &mut bool) -> Result<()> { Ok(()) } /// This function runs just before the move starts its execution. - fn on_before_move(&self, _move: &ExecutingMove) -> Result<()> { + fn on_before_move(&self, _move: &Arc) -> Result<()> { Ok(()) } /// This function allows a script to prevent a move that is targeted at its owner. If set to true /// the move fails, and fail events get triggered. - fn fail_incoming_move(&self, _move: &ExecutingMove, _target: &Arc, _fail: &mut bool) -> Result<()> { + fn fail_incoming_move(&self, _move: &Arc, _target: &Pokemon, _fail: &mut bool) -> Result<()> { Ok(()) } /// This function allows a script to make its owner invulnerable to an incoming move. - fn is_invulnerable(&self, _move: &ExecutingMove, _target: &Arc, _invulnerable: &mut bool) -> Result<()> { + fn is_invulnerable(&self, _move: &Arc, _target: &Pokemon, _invulnerable: &mut bool) -> Result<()> { Ok(()) } /// This function occurs when a move gets missed. This runs on the scripts belonging to the executing /// move, which include the scripts that are attached to the owner of the script. - fn on_move_miss(&self, _move: &ExecutingMove, _target: &Arc) -> Result<()> { + fn on_move_miss(&self, _move: &Arc, _target: &Pokemon) -> Result<()> { Ok(()) } /// This function allows the script to change the actual type that is used for the move on a target. fn change_move_type( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _move_type: &mut TypeIdentifier, ) -> Result<()> { @@ -148,8 +148,8 @@ pub trait Script: Send + Sync { /// This function allows the script to change how effective a move is on a target. fn change_effectiveness( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _effectiveness: &mut f32, ) -> Result<()> { @@ -158,8 +158,8 @@ pub trait Script: Send + Sync { /// This function allows a script to block an outgoing move from being critical. fn block_critical( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _block_critical: &mut bool, ) -> Result<()> { @@ -168,8 +168,8 @@ pub trait Script: Send + Sync { /// This function allows a script to block an incoming move from being critical. fn block_incoming_critical( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _block_critical: &mut bool, ) -> Result<()> { @@ -179,8 +179,8 @@ pub trait Script: Send + Sync { /// the percentage accuracy, so anything above 100% will make it always hit. fn change_accuracy( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _accuracy: &mut u8, ) -> Result<()> { @@ -190,8 +190,8 @@ pub trait Script: Send + Sync { /// This function allows a script to change the critical stage of the move used. fn change_critical_stage( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _stage: &mut u8, ) -> Result<()> { @@ -201,8 +201,8 @@ pub trait Script: Send + Sync { /// run when a hit is critical. fn change_critical_modifier( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _modifier: &mut f32, ) -> Result<()> { @@ -212,8 +212,8 @@ pub trait Script: Send + Sync { /// occurs when the user has the move type as one of its own types. fn change_stab_modifier( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _modifier: &mut f32, ) -> Result<()> { @@ -223,8 +223,8 @@ pub trait Script: Send + Sync { /// This function allows a script to change the effective base power of a move hit. fn change_base_power( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _base_power: &mut u8, ) -> Result<()> { @@ -233,8 +233,8 @@ pub trait Script: Send + Sync { /// This function allows a script to bypass defensive stat boosts for a move hit. fn bypass_defensive_stat_boost( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _bypass: &mut bool, ) -> Result<()> { @@ -243,8 +243,8 @@ pub trait Script: Send + Sync { /// This function allows a script to bypass offensive stat boosts for a move hit. fn bypass_offensive_stat_boost( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _bypass: &mut bool, ) -> Result<()> { @@ -253,8 +253,8 @@ pub trait Script: Send + Sync { /// This function allows a script to change the actual offensive stat values used when calculating damage fn change_offensive_stat_value( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _amount: &mut u32, ) -> Result<()> { @@ -263,8 +263,8 @@ pub trait Script: Send + Sync { /// This function allows a script to change the actual defensive stat values used when calculating damage. fn change_defensive_stat_value( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _amount: &mut u32, ) -> Result<()> { @@ -275,8 +275,8 @@ pub trait Script: Send + Sync { /// defender and attacker. fn change_damage_stat_modifier( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _modifier: &mut f32, ) -> Result<()> { @@ -285,22 +285,22 @@ pub trait Script: Send + Sync { /// This function allows a script to apply a raw multiplier to the damage done by a move. fn change_damage_modifier( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _modifier: &mut f32, ) -> Result<()> { Ok(()) } /// This function allows a script to modify the outgoing damage done by a move. - fn change_damage(&self, _move: &ExecutingMove, _target: &Arc, _hit: u8, _damage: &mut u32) -> Result<()> { + fn change_damage(&self, _move: &Arc, _target: &Pokemon, _hit: u8, _damage: &mut u32) -> Result<()> { Ok(()) } /// This function allows a script to modify the incoming damage done by a move. fn change_incoming_damage( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _damage: &mut u32, ) -> Result<()> { @@ -308,11 +308,11 @@ pub trait Script: Send + Sync { } /// This function triggers when an incoming hit happens. This triggers after the damage is done, /// but before the secondary effect of the move happens. - fn on_incoming_hit(&self, _move: &ExecutingMove, _target: &Arc, _hit: u8) -> Result<()> { + fn on_incoming_hit(&self, _move: &Arc, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) } /// This function triggers when an opponent on the field faints. - fn on_opponent_faints(&self, _move: &ExecutingMove, _target: &Arc, _hit: u8) -> Result<()> { + fn on_opponent_faints(&self, _move: &Arc, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) } /// This function allows a script attached to a Pokemon or its parents to prevent stat boost @@ -344,8 +344,8 @@ pub trait Script: Send + Sync { /// secondary effect. Note that this function is not called for status moves. fn prevent_secondary_effect( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _prevent: &mut bool, ) -> Result<()> { @@ -357,8 +357,8 @@ pub trait Script: Send + Sync { /// below 0 will make it never hit. fn change_effect_chance( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _chance: &mut f32, ) -> Result<()> { @@ -370,8 +370,8 @@ pub trait Script: Send + Sync { /// or below 0 will make it never hit. fn change_incoming_effect_chance( &self, - _move: &ExecutingMove, - _target: &Arc, + _move: &Arc, + _target: &Pokemon, _hit: u8, _chance: &mut f32, ) -> Result<()> { @@ -380,19 +380,19 @@ pub trait Script: Send + Sync { /// This function triggers when the move uses its secondary effect. Moves should implement their /// secondary effects here. Status moves should implement their actual functionality in this /// function as well, as status moves effects are defined as secondary effects for simplicity. - fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc, _hit: u8) -> Result<()> { + fn on_secondary_effect(&self, _move: &Arc, _target: &Pokemon, _hit: u8) -> Result<()> { Ok(()) } /// This function triggers on a move or its parents when all hits on a target are finished. - fn on_after_hits(&self, _move: &ExecutingMove, _target: &Arc) -> Result<()> { + fn on_after_hits(&self, _move: &Arc, _target: &Pokemon) -> Result<()> { Ok(()) } /// This function prevents the Pokemon it is attached to from being able to switch out. - fn prevent_self_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) -> Result<()> { + fn prevent_self_switch(&self, _choice: &Arc, _prevent: &mut bool) -> Result<()> { Ok(()) } /// This function allows the prevention of switching for any opponent. - fn prevent_opponent_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) -> Result<()> { + fn prevent_opponent_switch(&self, _choice: &Arc, _prevent: &mut bool) -> Result<()> { Ok(()) } /// This function is called on a move and its parents when the move fails. @@ -404,11 +404,11 @@ pub trait Script: Send + Sync { Ok(()) } /// This function allows preventing the running away of the Pokemon its attached to - fn prevent_self_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) -> Result<()> { + fn prevent_self_run_away(&self, _choice: &Arc, _prevent: &mut bool) -> Result<()> { Ok(()) } /// This function prevents a Pokemon on another side than where its attached to from running away. - fn prevent_opponent_run_away(&self, _choice: &TurnChoice, _prevent: &mut bool) -> Result<()> { + fn prevent_opponent_run_away(&self, _choice: &Arc, _prevent: &mut bool) -> Result<()> { Ok(()) } /// This function id triggered on all scripts active in the battle after all choices have finished @@ -432,7 +432,7 @@ pub trait Script: Send + Sync { } /// This function is triggered on a Pokemon and its parents when the given Pokemon consumes the /// held item it had. - fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &dyn Item) -> Result<()> { + fn on_after_held_item_consume(&self, _pokemon: &Pokemon, _item: &Arc) -> Result<()> { Ok(()) } /// This function is triggered on a Pokemon and its parents when the given Pokemon gains experience, @@ -458,7 +458,12 @@ pub trait Script: Send + Sync { /// This function is called when a Pokeball is thrown at a Pokemon, and allows modifying the catch /// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for /// example status effects that change capture rates. - fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &dyn Item, _modifier: &mut u8) -> Result<()> { + fn change_capture_rate_bonus( + &self, + _target: &Pokemon, + _pokeball: &Arc, + _modifier: &mut u8, + ) -> Result<()> { Ok(()) } @@ -778,29 +783,29 @@ mod tests { /// Data to store references to their owning objects on scripts. pub enum ScriptOwnerData { /// A script attached to a Pokemon has a reference to that Pokemon. - Pokemon(AtomicPtr), + Pokemon(WeakPokemonReference), /// A script attached to a Battle Side has a reference to that Battle Side. - BattleSide(AtomicPtr), + BattleSide(WeakBattleSideReference), /// A script attached to a Battle has a reference to that Battle. - Battle(AtomicPtr), + Battle(WeakBattleReference), /// A script also can have no owner. None, } impl From<&Pokemon> for ScriptOwnerData { fn from(p: &Pokemon) -> Self { - ScriptOwnerData::Pokemon(AtomicPtr::new(p as *const Pokemon as *mut Pokemon)) + ScriptOwnerData::Pokemon(p.weak()) } } impl From<&BattleSide> for ScriptOwnerData { fn from(p: &BattleSide) -> Self { - ScriptOwnerData::BattleSide(AtomicPtr::new(p as *const BattleSide as *mut BattleSide)) + ScriptOwnerData::BattleSide(p.weak()) } } impl From<&Battle> for ScriptOwnerData { fn from(p: &Battle) -> Self { - ScriptOwnerData::Battle(AtomicPtr::new(p as *const Battle as *mut Battle)) + ScriptOwnerData::Battle(p.weak()) } } diff --git a/src/ffi/dynamic_data/choices.rs b/src/ffi/dynamic_data/choices.rs index b497362..5a19a0c 100644 --- a/src/ffi/dynamic_data/choices.rs +++ b/src/ffi/dynamic_data/choices.rs @@ -12,7 +12,7 @@ extern "C" fn turn_choice_drop(choice: OwnedPtr) { /// Get the user of the given choice. #[no_mangle] -extern "C" fn turn_choice_user(choice: ExternPointer) -> IdentifiablePointer> { +extern "C" fn turn_choice_user(choice: ExternPointer) -> IdentifiablePointer { choice.as_ref().user().clone().into() } @@ -40,7 +40,7 @@ extern "C" fn turn_choice_fail(choice: ExternPointer) { /// Creates a new Turn Choice with a move to use. #[no_mangle] extern "C" fn turn_choice_move_new( - user: ExternPointer>, + user: ExternPointer, learned_move: ExternPointer>, target_side: u8, target_index: u8, @@ -94,12 +94,12 @@ extern "C" fn turn_choice_move_priority(choice: ExternPointer) -> Na /// Creates a new Turn Choice for the user to flee. #[no_mangle] -extern "C" fn turn_choice_flee_new(user: ExternPointer>) -> IdentifiablePointer { +extern "C" fn turn_choice_flee_new(user: ExternPointer) -> IdentifiablePointer { Box::new(TurnChoice::Flee(FleeChoice::new(user.as_ref().clone()))).into() } /// Creates a new Turn Choice for the user to pass the turn. #[no_mangle] -extern "C" fn turn_choice_pass_new(user: ExternPointer>) -> IdentifiablePointer { +extern "C" fn turn_choice_pass_new(user: ExternPointer) -> IdentifiablePointer { Box::new(TurnChoice::Pass(PassChoice::new(user.as_ref().clone()))).into() } diff --git a/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs b/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs index a9836b8..16bd6e5 100644 --- a/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs +++ b/src/ffi/dynamic_data/libraries/battle_stat_calculator.rs @@ -2,7 +2,6 @@ use crate::dynamic_data::{BattleStatCalculator, Gen7BattleStatCalculator, Pokemo use crate::ffi::{ExternPointer, IdentifiablePointer, NativeResult, OwnedPtr}; use crate::static_data::{Statistic, StatisticSet}; use std::ptr::drop_in_place; -use std::sync::Arc; /// Creates a new Gen 7 battle stat calculator #[no_mangle] @@ -23,7 +22,7 @@ extern "C" fn battle_stat_calculator_drop(ptr: OwnedPtr>, - pokemon: ExternPointer>, + pokemon: ExternPointer, mut stats: ExternPointer>>, ) -> NativeResult<()> { ptr.as_ref() @@ -35,7 +34,7 @@ extern "C" fn battle_stat_calculator_calculate_flat_stats( #[no_mangle] extern "C" fn battle_stat_calculator_calculate_flat_stat( ptr: ExternPointer>, - pokemon: ExternPointer>, + pokemon: ExternPointer, stat: Statistic, ) -> NativeResult { ptr.as_ref().calculate_flat_stat(pokemon.as_ref(), stat).into() @@ -45,7 +44,7 @@ extern "C" fn battle_stat_calculator_calculate_flat_stat( #[no_mangle] extern "C" fn battle_stat_calculator_calculate_boosted_stats( ptr: ExternPointer>, - pokemon: ExternPointer>, + pokemon: ExternPointer, mut stats: ExternPointer>>, ) -> NativeResult<()> { ptr.as_ref() @@ -57,7 +56,7 @@ extern "C" fn battle_stat_calculator_calculate_boosted_stats( #[no_mangle] extern "C" fn battle_stat_calculator_calculate_boosted_stat( ptr: ExternPointer>, - pokemon: ExternPointer>, + pokemon: ExternPointer, stat: Statistic, ) -> NativeResult { ptr.as_ref().calculate_boosted_stat(pokemon.as_ref(), stat).into() diff --git a/src/ffi/dynamic_data/libraries/dynamic_library.rs b/src/ffi/dynamic_data/libraries/dynamic_library.rs index d6a168a..5729101 100644 --- a/src/ffi/dynamic_data/libraries/dynamic_library.rs +++ b/src/ffi/dynamic_data/libraries/dynamic_library.rs @@ -9,18 +9,18 @@ use std::sync::Arc; /// Instantiates a new DynamicLibrary with given parameters. #[no_mangle] extern "C" fn dynamic_library_new( - static_data: OwnedPtr>, - stat_calculator: OwnedPtr>, - damage_library: OwnedPtr>, - misc_library: OwnedPtr>, + static_data: OwnedPtr>, + stat_calculator: OwnedPtr>, + damage_library: OwnedPtr>, + misc_library: OwnedPtr>, script_resolver: OwnedPtr>, ) -> IdentifiablePointer> { unsafe { let a: Arc = Arc::new(DynamicLibraryImpl::new( - *Box::from_raw(static_data), - *Box::from_raw(stat_calculator), - *Box::from_raw(damage_library), - *Box::from_raw(misc_library), + static_data.read(), + stat_calculator.read(), + damage_library.read(), + misc_library.read(), *Box::from_raw(script_resolver), )); a.into() @@ -37,8 +37,8 @@ extern "C" fn dynamic_library_drop(ptr: OwnedPtr>) { #[no_mangle] extern "C" fn dynamic_library_get_static_data( ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().static_data().into() +) -> IdentifiablePointer> { + ptr.as_ref().static_data().clone().into() } /// The stat calculator deals with the calculation of flat and boosted stats, based on the @@ -46,16 +46,16 @@ extern "C" fn dynamic_library_get_static_data( #[no_mangle] extern "C" fn dynamic_library_get_stat_calculator( ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().stat_calculator().into() +) -> IdentifiablePointer> { + ptr.as_ref().stat_calculator().clone().into() } /// The damage calculator deals with the calculation of things relating to damage. #[no_mangle] extern "C" fn dynamic_library_get_damage_calculator( ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().damage_calculator().into() +) -> IdentifiablePointer> { + ptr.as_ref().damage_calculator().clone().into() } /// The Misc Library holds minor functions that do not fall in any of the other libraries and @@ -63,6 +63,6 @@ extern "C" fn dynamic_library_get_damage_calculator( #[no_mangle] extern "C" fn dynamic_library_get_misc_library( ptr: ExternPointer>, -) -> IdentifiablePointer> { - ptr.as_ref().misc_library().into() +) -> IdentifiablePointer> { + ptr.as_ref().misc_library().clone().into() } diff --git a/src/ffi/dynamic_data/models/battle.rs b/src/ffi/dynamic_data/models/battle.rs index 8f03fb8..df22307 100644 --- a/src/ffi/dynamic_data/models/battle.rs +++ b/src/ffi/dynamic_data/models/battle.rs @@ -11,7 +11,7 @@ use std::sync::Arc; #[no_mangle] extern "C" fn battle_new( library: ExternPointer>, - parties: *const OwnedPtr, + parties: *const OwnedPtr>, parties_length: usize, can_flee: u8, number_of_sides: u8, @@ -19,7 +19,7 @@ extern "C" fn battle_new( // NOTE: Split into two due to u128 not being ABI safe: https://github.com/rust-lang/rust/issues/54341 random_seed_1: u64, random_seed_2: u64, -) -> IdentifiablePointer> { +) -> IdentifiablePointer { let parties = unsafe { std::slice::from_raw_parts(parties, parties_length) .iter() @@ -59,9 +59,12 @@ extern "C" fn battle_parties_length(ptr: ExternPointer>) -> usize { /// Get a party in the battle. #[no_mangle] -extern "C" fn battle_parties_get(ptr: ExternPointer>, index: usize) -> IdentifiablePointer { +extern "C" fn battle_parties_get( + ptr: ExternPointer>, + index: usize, +) -> IdentifiablePointer> { if let Some(v) = ptr.as_ref().parties().get(index) { - (v as *const BattleParty).into() + v.clone().into() } else { IdentifiablePointer::none() } @@ -103,8 +106,8 @@ extern "C" fn battle_sides_get(ptr: ExternPointer>, index: usize) -> /// The RNG used for the battle. #[no_mangle] -extern "C" fn battle_random(ptr: ExternPointer>) -> IdentifiablePointer { - (ptr.as_ref().random() as *const BattleRandom).into() +extern "C" fn battle_random(ptr: ExternPointer>) -> IdentifiablePointer> { + ptr.as_ref().random().clone().into() } /// Whether or not the battle has ended. @@ -150,11 +153,7 @@ extern "C" fn battle_last_turn_time(ptr: ExternPointer>) -> u64 { /// Get a Pokemon on the battlefield, on a specific side and an index on that side. #[no_mangle] -extern "C" fn battle_get_pokemon( - ptr: ExternPointer>, - side: u8, - index: u8, -) -> IdentifiablePointer> { +extern "C" fn battle_get_pokemon(ptr: ExternPointer>, side: u8, index: u8) -> IdentifiablePointer { if let Some(v) = ptr.as_ref().get_pokemon(side, index) { v.into() } else { diff --git a/src/ffi/dynamic_data/models/battle_party.rs b/src/ffi/dynamic_data/models/battle_party.rs index 98bda5f..750af6a 100644 --- a/src/ffi/dynamic_data/models/battle_party.rs +++ b/src/ffi/dynamic_data/models/battle_party.rs @@ -58,7 +58,7 @@ extern "C" fn battle_party_has_pokemon_not_in_field(ptr: ExternPointer>, index: usize, -) -> IdentifiablePointer> { +) -> IdentifiablePointer { if let Some(v) = ptr.as_ref().get_pokemon(index) { v.into() } else { diff --git a/src/ffi/dynamic_data/models/event.rs b/src/ffi/dynamic_data/models/event.rs index 4052073..c266465 100644 --- a/src/ffi/dynamic_data/models/event.rs +++ b/src/ffi/dynamic_data/models/event.rs @@ -1,6 +1,5 @@ use crate::dynamic_data::{Event, Pokemon}; use crate::ffi::{ExternPointer, IdentifiablePointer}; -use std::sync::Arc; /// The kind of the event. #[no_mangle] @@ -67,7 +66,7 @@ event_ffi!( /// The index of the Pokemon that got switched in/out on its side index: u8, /// The new Pokemon that will be on the spot. If none, the spot will be null. - pokemon: IdentifiablePointer>, + pokemon: IdentifiablePointer, }, { return SwitchData{ diff --git a/src/ffi/dynamic_data/models/learned_move.rs b/src/ffi/dynamic_data/models/learned_move.rs index f1ee004..6c3866d 100644 --- a/src/ffi/dynamic_data/models/learned_move.rs +++ b/src/ffi/dynamic_data/models/learned_move.rs @@ -61,5 +61,6 @@ extern "C" fn learned_move_restore_all_uses(learned_move: ExternPointer>, amount: u8) -> NativeResult<()> { - learned_move.as_ref().restore_uses(amount).into() + learned_move.as_ref().restore_uses(amount); + NativeResult::ok(()) } diff --git a/src/ffi/dynamic_data/models/pokemon.rs b/src/ffi/dynamic_data/models/pokemon.rs index dd3eb01..fb5454a 100644 --- a/src/ffi/dynamic_data/models/pokemon.rs +++ b/src/ffi/dynamic_data/models/pokemon.rs @@ -22,7 +22,7 @@ extern "C" fn pokemon_new( gender: Gender, coloring: u8, nature: *const c_char, -) -> NativeResult>> { +) -> NativeResult> { let nature = unsafe { CStr::from_ptr(nature) }.into(); let pokemon = Pokemon::new( library.as_ref().clone(), @@ -39,44 +39,44 @@ extern "C" fn pokemon_new( &nature, ); match pokemon { - Ok(pokemon) => NativeResult::ok(Arc::new(pokemon).into()), + Ok(pokemon) => NativeResult::ok(pokemon.into()), Err(err) => NativeResult::err(err), } } /// Drops an Arc reference held by the FFI. #[no_mangle] -unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr>) { +unsafe extern "C" fn pokemon_drop(ptr: OwnedPtr) { drop_in_place(ptr); } /// The library data of the Pokemon. #[no_mangle] -extern "C" fn pokemon_library(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_library(ptr: ExternPointer) -> IdentifiablePointer> { ptr.as_ref().library().clone().into() } /// The species of the Pokemon. #[no_mangle] -extern "C" fn pokemon_species(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_species(ptr: ExternPointer) -> IdentifiablePointer> { ptr.as_ref().species().into() } /// The form of the Pokemon. #[no_mangle] -extern "C" fn pokemon_form(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_form(ptr: ExternPointer) -> IdentifiablePointer> { ptr.as_ref().form().into() } /// The species that should be displayed to the user. This handles stuff like the Illusion ability. #[no_mangle] -extern "C" fn pokemon_display_species(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_display_species(ptr: ExternPointer) -> IdentifiablePointer> { ptr.as_ref().display_species().into() } /// The form that should be displayed to the user. This handles stuff like the Illusion ability. #[no_mangle] -extern "C" fn pokemon_display_form(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_display_form(ptr: ExternPointer) -> IdentifiablePointer> { ptr.as_ref().display_form().into() } @@ -88,7 +88,7 @@ ffi_arc_getter!(Pokemon, coloring, u8); /// Gets the held item of a Pokemon #[no_mangle] -extern "C" fn pokemon_held_item(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_held_item(ptr: ExternPointer) -> IdentifiablePointer> { if let Some(v) = ptr.as_ref().held_item().read().as_ref() { v.clone().into() } else { @@ -98,7 +98,7 @@ extern "C" fn pokemon_held_item(ptr: ExternPointer>) -> Identifiabl /// Checks whether the Pokemon is holding a specific item. #[no_mangle] -extern "C" fn pokemon_has_held_item(ptr: ExternPointer>, name: *const c_char) -> u8 { +extern "C" fn pokemon_has_held_item(ptr: ExternPointer, name: *const c_char) -> u8 { let name = unsafe { CStr::from_ptr(name) }.into(); u8::from(ptr.as_ref().has_held_item(&name)) } @@ -106,7 +106,7 @@ extern "C" fn pokemon_has_held_item(ptr: ExternPointer>, name: *con /// Changes the held item of the Pokemon. Returns the previously held item. #[no_mangle] extern "C" fn pokemon_set_held_item( - ptr: ExternPointer>, + ptr: ExternPointer, item: ExternPointer>, ) -> IdentifiablePointer> { if let Some(v) = ptr.as_ref().set_held_item(item.as_ref()) { @@ -118,7 +118,7 @@ extern "C" fn pokemon_set_held_item( /// Removes the held item from the Pokemon. Returns the previously held item. #[no_mangle] -extern "C" fn pokemon_remove_held_item(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_remove_held_item(ptr: ExternPointer) -> IdentifiablePointer> { if let Some(v) = ptr.as_ref().remove_held_item() { v.into() } else { @@ -128,7 +128,7 @@ extern "C" fn pokemon_remove_held_item(ptr: ExternPointer>) -> Iden /// Makes the Pokemon uses its held item. #[no_mangle] -extern "C" fn pokemon_consume_held_item(ptr: ExternPointer>) -> NativeResult { +extern "C" fn pokemon_consume_held_item(ptr: ExternPointer) -> NativeResult { match ptr.as_ref().consume_held_item() { Ok(v) => NativeResult::ok(u8::from(v)), Err(err) => NativeResult::err(err), @@ -142,7 +142,7 @@ ffi_arc_getter!(Pokemon, height, f32); /// An optional nickname of the Pokemon. #[no_mangle] -extern "C" fn pokemon_nickname(ptr: ExternPointer>) -> NativeResult<*mut c_char> { +extern "C" fn pokemon_nickname(ptr: ExternPointer) -> NativeResult<*mut c_char> { let name = ptr.as_ref().nickname(); if let Some(v) = name { match CString::new(v.as_str()) { @@ -156,13 +156,13 @@ extern "C" fn pokemon_nickname(ptr: ExternPointer>) -> NativeResult /// Whether the actual ability on the form is a hidden ability. #[no_mangle] -extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_real_ability_is_hidden(ptr: ExternPointer) -> u8 { u8::from(ptr.as_ref().real_ability().hidden) } /// The index of the actual ability on the form. #[no_mangle] -extern "C" fn pokemon_real_ability_index(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_real_ability_index(ptr: ExternPointer) -> u8 { ptr.as_ref().real_ability().index } @@ -172,7 +172,7 @@ ffi_vec_value_getters!(Pokemon, Pokemon, types, TypeIdentifier); /// a null pointer otherwise. #[no_mangle] extern "C" fn pokemon_learned_move_get( - ptr: ExternPointer>, + ptr: ExternPointer, index: usize, ) -> IdentifiablePointer> { if let Some(Some(v)) = ptr.as_ref().learned_moves().read().get(index) { @@ -184,26 +184,26 @@ extern "C" fn pokemon_learned_move_get( /// The stats of the Pokemon when disregarding any stat boosts. #[no_mangle] -extern "C" fn pokemon_flat_stats(ptr: ExternPointer>) -> IdentifiablePointer> { - (ptr.as_ref().flat_stats() as *const StatisticSet).into() +extern "C" fn pokemon_flat_stats(ptr: ExternPointer) -> IdentifiablePointer>> { + ptr.as_ref().flat_stats().clone().into() } /// The stats of the Pokemon including the stat boosts. #[no_mangle] -extern "C" fn pokemon_boosted_stats(ptr: ExternPointer>) -> IdentifiablePointer> { - (ptr.as_ref().boosted_stats() as *const StatisticSet).into() +extern "C" fn pokemon_boosted_stats(ptr: ExternPointer) -> IdentifiablePointer>> { + ptr.as_ref().boosted_stats().clone().into() } /// Get the stat boosts for a specific stat. #[no_mangle] -extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer>, statistic: Statistic) -> i8 { +extern "C" fn pokemon_get_stat_boost(ptr: ExternPointer, statistic: Statistic) -> i8 { ptr.as_ref().stat_boost(statistic) } /// Change a boosted stat by a certain amount. #[no_mangle] extern "C" fn pokemon_change_stat_boost( - ptr: ExternPointer>, + ptr: ExternPointer, stat: Statistic, diff_amount: i8, self_inflicted: u8, @@ -216,14 +216,14 @@ extern "C" fn pokemon_change_stat_boost( /// Gets a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_get_individual_value(ptr: ExternPointer>, stat: Statistic) -> u8 { +extern "C" fn pokemon_get_individual_value(ptr: ExternPointer, stat: Statistic) -> u8 { ptr.as_ref().individual_values().get_stat(stat) } /// Modifies a [individual value](https://bulbapedia.bulbagarden.net/wiki/Individual_values) of the Pokemon. #[no_mangle] extern "C" fn pokemon_set_individual_value( - ptr: ExternPointer>, + ptr: ExternPointer, stat: Statistic, value: u8, ) -> NativeResult<()> { @@ -233,17 +233,13 @@ extern "C" fn pokemon_set_individual_value( /// Gets a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_get_effort_value(ptr: ExternPointer>, stat: Statistic) -> u8 { +extern "C" fn pokemon_get_effort_value(ptr: ExternPointer, stat: Statistic) -> u8 { ptr.as_ref().effort_values().get_stat(stat) } /// Modifies a [effort value](https://bulbapedia.bulbagarden.net/wiki/Effort_values) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_set_effort_value( - ptr: ExternPointer>, - stat: Statistic, - value: u8, -) -> NativeResult<()> { +extern "C" fn pokemon_set_effort_value(ptr: ExternPointer, stat: Statistic, value: u8) -> NativeResult<()> { ptr.as_ref().effort_values().set_stat(stat, value); ptr.as_ref().recalculate_flat_stats().into() } @@ -251,7 +247,7 @@ extern "C" fn pokemon_set_effort_value( /// Gets the data for the battle the Pokemon is currently in. If the Pokemon is not in a battle, this /// returns null. #[no_mangle] -extern "C" fn pokemon_get_battle(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_get_battle(ptr: ExternPointer) -> IdentifiablePointer { if let Some(v) = ptr.as_ref().get_battle() { v.into() } else { @@ -262,27 +258,27 @@ extern "C" fn pokemon_get_battle(ptr: ExternPointer>) -> Identifiab /// Get the index of the side of the battle the Pokemon is in. If the Pokemon /// is not on the battlefield, this always returns 0. #[no_mangle] -extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_get_battle_side_index(ptr: ExternPointer) -> u8 { ptr.as_ref().get_battle_side_index().unwrap_or_default() } /// Get the index of the slot on the side of the battle the Pokemon is in. If the Pokemon /// is not on the battlefield, this always returns 0. #[no_mangle] -extern "C" fn pokemon_get_battle_index(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_get_battle_index(ptr: ExternPointer) -> u8 { ptr.as_ref().get_battle_index().unwrap_or_default() } /// Returns whether something overrides the ability. #[no_mangle] -extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_is_ability_overriden(ptr: ExternPointer) -> u8 { u8::from(ptr.as_ref().is_ability_overriden()) } /// Returns the currently active ability. #[no_mangle] extern "C" fn pokemon_active_ability( - ptr: ExternPointer>, + ptr: ExternPointer, ) -> NativeResult>> { match ptr.as_ref().active_ability() { Ok(v) => NativeResult::ok(v.clone().into()), @@ -292,13 +288,13 @@ extern "C" fn pokemon_active_ability( /// Whether or not the Pokemon is allowed to gain experience. #[no_mangle] -extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_allowed_experience_gain(ptr: ExternPointer) -> u8 { u8::from(ptr.as_ref().allowed_experience_gain()) } /// The [nature](https://bulbapedia.bulbagarden.net/wiki/Nature) of the Pokemon. #[no_mangle] -extern "C" fn pokemon_nature(ptr: ExternPointer>) -> IdentifiablePointer> { +extern "C" fn pokemon_nature(ptr: ExternPointer) -> IdentifiablePointer> { ptr.as_ref().nature().clone().into() } @@ -306,20 +302,20 @@ extern "C" fn pokemon_nature(ptr: ExternPointer>) -> IdentifiablePo /// stats, level, nature, IV, or EV changes. This has a side effect of recalculating the boosted /// stats, as those depend on the flat stats. #[no_mangle] -extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer>) -> NativeResult<()> { +extern "C" fn pokemon_recalculate_flat_stats(ptr: ExternPointer) -> NativeResult<()> { ptr.as_ref().recalculate_flat_stats().into() } /// Calculates the boosted stats on the Pokemon. This should be called when a stat boost changes. #[no_mangle] -extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer>) -> NativeResult<()> { +extern "C" fn pokemon_recalculate_boosted_stats(ptr: ExternPointer) -> NativeResult<()> { ptr.as_ref().recalculate_boosted_stats().into() } /// Change the species of the Pokemon. #[no_mangle] extern "C" fn pokemon_change_species( - ptr: ExternPointer>, + ptr: ExternPointer, species: ExternPointer>, form: ExternPointer>, ) -> NativeResult<()> { @@ -330,48 +326,45 @@ extern "C" fn pokemon_change_species( /// Change the form of the Pokemon. #[no_mangle] -extern "C" fn pokemon_change_form( - ptr: ExternPointer>, - form: ExternPointer>, -) -> NativeResult<()> { +extern "C" fn pokemon_change_form(ptr: ExternPointer, form: ExternPointer>) -> NativeResult<()> { ptr.as_ref().change_form(form.as_ref()).into() } /// Whether or not the Pokemon is useable in a battle. #[no_mangle] -extern "C" fn pokemon_is_usable(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_is_usable(ptr: ExternPointer) -> u8 { u8::from(ptr.as_ref().is_usable()) } /// Returns whether the Pokemon is fainted. #[no_mangle] -extern "C" fn pokemon_is_fainted(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_is_fainted(ptr: ExternPointer) -> u8 { u8::from(ptr.as_ref().is_fainted()) } /// Whether or not the Pokemon is on the battlefield. #[no_mangle] -extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer>) -> u8 { +extern "C" fn pokemon_is_on_battlefield(ptr: ExternPointer) -> u8 { u8::from(ptr.as_ref().is_on_battlefield()) } /// Damages the Pokemon by a certain amount of damage, from a damage source. #[no_mangle] -extern "C" fn pokemon_damage(ptr: ExternPointer>, damage: u32, source: DamageSource) -> NativeResult<()> { +extern "C" fn pokemon_damage(ptr: ExternPointer, damage: u32, source: DamageSource) -> NativeResult<()> { ptr.as_ref().damage(damage, source).into() } /// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not /// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false. #[no_mangle] -extern "C" fn pokemon_heal(ptr: ExternPointer>, amount: u32, allow_revive: u8) -> bool { +extern "C" fn pokemon_heal(ptr: ExternPointer, amount: u32, allow_revive: u8) -> bool { ptr.as_ref().heal(amount, allow_revive == 1) } /// Learn a move. #[no_mangle] extern "C" fn pokemon_learn_move( - ptr: ExternPointer>, + ptr: ExternPointer, move_name: *const c_char, learn_method: MoveLearnMethod, ) -> NativeResult<()> { @@ -384,6 +377,6 @@ extern "C" fn pokemon_learn_move( /// Removes the current non-volatile status from the Pokemon. #[no_mangle] -extern "C" fn pokemon_clear_status(ptr: ExternPointer>) { +extern "C" fn pokemon_clear_status(ptr: ExternPointer) { ptr.as_ref().clear_status() } diff --git a/src/ffi/dynamic_data/models/pokemon_party.rs b/src/ffi/dynamic_data/models/pokemon_party.rs index 958c400..723428a 100644 --- a/src/ffi/dynamic_data/models/pokemon_party.rs +++ b/src/ffi/dynamic_data/models/pokemon_party.rs @@ -10,10 +10,7 @@ extern "C" fn pokemon_party_new(capacity: usize) -> IdentifiablePointer>, - index: usize, -) -> IdentifiablePointer> { +extern "C" fn pokemon_party_at(ptr: ExternPointer>, index: usize) -> IdentifiablePointer { if let Some(v) = ptr.as_ref().at(index) { v.into() } else { @@ -32,8 +29,8 @@ extern "C" fn pokemon_party_switch(ptr: ExternPointer>, a: usi extern "C" fn pokemon_party_swap_into( ptr: ExternPointer>, index: usize, - pokemon: ExternPointer>, -) -> NativeResult>> { + pokemon: ExternPointer, +) -> NativeResult> { let pokemon = if pokemon.ptr.is_null() { None } else { @@ -66,9 +63,6 @@ extern "C" fn pokemon_party_pack_party(ptr: ExternPointer>) -> /// Checks if the party contains a given pokemon. #[no_mangle] -extern "C" fn pokemon_party_has_pokemon( - ptr: ExternPointer>, - pokemon: ExternPointer>, -) -> u8 { +extern "C" fn pokemon_party_has_pokemon(ptr: ExternPointer>, pokemon: ExternPointer) -> u8 { u8::from(ptr.as_ref().has_pokemon(pokemon.as_ref())) } diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 5dc53db..5f4f45f 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -87,6 +87,7 @@ macro_rules! ffi_vec_stringkey_getters { }; } +use crate::dynamic_data::{Battle, Pokemon}; use crate::{ValueIdentifiable, ValueIdentifier}; pub(self) use ffi_arc_dyn_getter; pub(self) use ffi_arc_getter; @@ -250,6 +251,40 @@ impl From<*const T> for IdentifiablePointer { } } +impl From for IdentifiablePointer { + fn from(v: Pokemon) -> Self { + let id = v.value_identifier().value(); + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } +} + +impl From> for IdentifiablePointer { + fn from(v: Option) -> Self { + if let Some(v) = v { + let id = unsafe { transmute(v.value_identifier()) }; + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } else { + IdentifiablePointer::none() + } + } +} + +impl From for IdentifiablePointer { + fn from(v: Battle) -> Self { + let id = v.value_identifier().value(); + Self { + ptr: Box::into_raw(Box::new(v)), + id, + } + } +} + impl IdentifiablePointer { /// Returns an identifiable pointer with null as pointer, and 0 as identifier. pub fn none() -> Self { diff --git a/src/ffi/static_data/ability.rs b/src/ffi/static_data/ability.rs index 7a44063..146718a 100644 --- a/src/ffi/static_data/ability.rs +++ b/src/ffi/static_data/ability.rs @@ -11,13 +11,13 @@ use std::sync::Arc; unsafe extern "C" fn ability_new( name: *const c_char, effect: *const c_char, - parameters: *const OwnedPtr, + parameters: *const OwnedPtr>, parameters_length: usize, ) -> NativeResult>> { let parameters = std::slice::from_raw_parts(parameters, parameters_length); - let mut parameters_vec: Vec = Vec::with_capacity(parameters_length); + let mut parameters_vec: Vec> = Vec::with_capacity(parameters_length); for parameter in parameters { - parameters_vec.push(*Box::from_raw(*parameter)); + parameters_vec.push(parameter.read()); } let name: StringKey = match CStr::from_ptr(name).to_str() { @@ -68,9 +68,9 @@ unsafe extern "C" fn ability_parameter_length(ptr: ExternPointer>, index: usize, -) -> IdentifiablePointer { +) -> IdentifiablePointer> { if let Some(p) = ptr.as_ref().parameters().get(index) { - (p as *const EffectParameter).into() + p.clone().into() } else { IdentifiablePointer::none() } diff --git a/src/ffi/static_data/form.rs b/src/ffi/static_data/form.rs index e3c8044..0e34eae 100644 --- a/src/ffi/static_data/form.rs +++ b/src/ffi/static_data/form.rs @@ -95,8 +95,8 @@ ffi_vec_value_getters!(Form, dyn Form, types, TypeIdentifier); #[no_mangle] unsafe extern "C" fn form_base_stats( ptr: ExternPointer>, -) -> IdentifiablePointer> { - (ptr.as_ref().base_stats() as *const StaticStatisticSet).into() +) -> IdentifiablePointer>> { + ptr.as_ref().base_stats().clone().into() } ffi_vec_stringkey_getters!(Form, abilities); diff --git a/src/ffi/static_data/libraries/static_data.rs b/src/ffi/static_data/libraries/static_data.rs index 370bb68..9532aab 100644 --- a/src/ffi/static_data/libraries/static_data.rs +++ b/src/ffi/static_data/libraries/static_data.rs @@ -4,28 +4,29 @@ use crate::static_data::{ StaticData, StaticDataImpl, TypeLibrary, }; use std::ptr::drop_in_place; +use std::sync::Arc; /// Instantiates a new data collection. #[no_mangle] unsafe extern "C" fn static_data_new( - settings: OwnedPtr>, - species: OwnedPtr>, - moves: OwnedPtr>, - items: OwnedPtr>, - growth_rates: OwnedPtr>, - types: OwnedPtr>, - natures: OwnedPtr>, - abilities: OwnedPtr>, -) -> IdentifiablePointer> { - let b: Box = Box::new(StaticDataImpl::new( - *Box::from_raw(settings), - *Box::from_raw(species), - *Box::from_raw(moves), - *Box::from_raw(items), - *Box::from_raw(growth_rates), - *Box::from_raw(types), - *Box::from_raw(natures), - *Box::from_raw(abilities), + settings: OwnedPtr>, + species: OwnedPtr>, + moves: OwnedPtr>, + items: OwnedPtr>, + growth_rates: OwnedPtr>, + types: OwnedPtr>, + natures: OwnedPtr>, + abilities: OwnedPtr>, +) -> IdentifiablePointer> { + let b: Arc = Arc::new(StaticDataImpl::new( + settings.read(), + species.read(), + moves.read(), + items.read(), + growth_rates.read(), + types.read(), + natures.read(), + abilities.read(), )); b.into() } @@ -39,63 +40,63 @@ unsafe extern "C" fn static_data_drop(ptr: OwnedPtr>) { /// Several misc settings for the library. #[no_mangle] unsafe extern "C" fn static_data_settings( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().settings().into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + data.as_mut().settings().clone().into() } /// All data for Pokemon species. #[no_mangle] unsafe extern "C" fn static_data_species( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().species().into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + data.as_mut().species().clone().into() } /// All data for the moves. #[no_mangle] unsafe extern "C" fn static_data_moves( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().moves().into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + data.as_mut().moves().clone().into() } /// All data for the items. #[no_mangle] unsafe extern "C" fn static_data_items( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - (data.as_mut().items()).into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + (data.as_mut().items()).clone().into() } /// All data for growth rates. #[no_mangle] unsafe extern "C" fn static_data_growth_rates( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().growth_rates().into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + data.as_mut().growth_rates().clone().into() } /// All data related to types and type effectiveness. #[no_mangle] unsafe extern "C" fn static_data_types( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_mut().types().into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + data.as_mut().types().clone().into() } /// All data related to natures. #[no_mangle] unsafe extern "C" fn static_data_natures( - data: ExternPointer>, -) -> IdentifiablePointer> { - data.as_ref().natures().into() + data: ExternPointer>, +) -> IdentifiablePointer> { + data.as_ref().natures().clone().into() } /// All data related to abilities. #[no_mangle] unsafe extern "C" fn static_data_abilities( - mut data: ExternPointer>, -) -> IdentifiablePointer> { - (data.as_mut().abilities()).into() + mut data: ExternPointer>, +) -> IdentifiablePointer> { + (data.as_mut().abilities()).clone().into() } diff --git a/src/ffi/static_data/move_data.rs b/src/ffi/static_data/move_data.rs index d0be0ab..53f8e1e 100644 --- a/src/ffi/static_data/move_data.rs +++ b/src/ffi/static_data/move_data.rs @@ -102,7 +102,7 @@ unsafe extern "C" fn move_data_has_flag(ptr: ExternPointer>, f unsafe extern "C" fn secondary_effect_new( chance: f32, effect_name: BorrowedPtr, - parameters: *mut OwnedPtr, + parameters: *mut OwnedPtr>, parameters_length: usize, ) -> IdentifiablePointer> { let parameter_slice = std::slice::from_raw_parts(parameters, parameters_length); @@ -156,9 +156,9 @@ unsafe extern "C" fn secondary_effect_parameter_length(ptr: ExternPointer>, index: usize, -) -> IdentifiablePointer { +) -> IdentifiablePointer> { if let Some(v) = ptr.as_ref().parameters().get(index) { - (v as *const EffectParameter).into() + v.clone().into() } else { IdentifiablePointer::none() } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs b/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs index 7597b10..6e885e7 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/battle.rs @@ -5,10 +5,9 @@ use crate::script_implementations::wasm::export_registry::wasm_result::{ get_value, get_value_arc, get_value_call_getter, try_wasm, }; use crate::script_implementations::wasm::export_registry::{register, wasm_ok, WasmResult}; -use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; +use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::StringKey; -use anyhow_ext::Context; use wasmer::FunctionEnvMut; register! { @@ -23,19 +22,27 @@ register! { fn battle_get_parties( env: FunctionEnvMut, battle: ExternRef, - ) -> WasmResult> { - let parties = get_value_call_getter!(battle.parties(), env); - wasm_ok(VecExternRef::new(env.data().data().as_ref(), parties)) + ) -> WasmResult { + let battle = get_value!(battle, env); + let parties = battle.parties(); + let mut vec : Vec = Vec::with_capacity(parties.len()); + for party in parties { + vec.push(ExternRef::::func_new(&env, party.into()).index() as u32); + } + let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&vec), env); + let r: u64 = unsafe { std::mem::transmute((wasm_ptr, vec.len() as u32)) }; + wasm_ok(r) } fn battle_get_choice_queue( env: FunctionEnvMut, battle: ExternRef, ) -> WasmResult> { - let value = get_value_call_getter!(battle.current_turn_queue(), env); + let battle = get_value!(battle, env); + let value = battle.current_turn_queue(); let queue = value.read(); wasm_ok(if let Some(queue) = queue.as_ref() { - ExternRef::::func_new(&env, queue) + ExternRef::::func_new(&env, queue.into()) } else { ExternRef::null() }) @@ -45,24 +52,34 @@ register! { env: FunctionEnvMut, battle: ExternRef, ) -> WasmResult> { - let value = get_value_call_getter!(battle.library(), env); - wasm_ok(ExternRef::::func_new(&env, &value.clone())) + let battle = get_value!(battle, env); + let value = battle.library(); + wasm_ok(ExternRef::func_new(&env, value.into())) } fn battle_get_sides( env: FunctionEnvMut, battle: ExternRef, - ) -> WasmResult> { - let value = get_value_arc!(battle, env); - wasm_ok(VecExternRef::new(env.data().data().as_ref(), value.sides())) + ) -> WasmResult { + let value = get_value!(battle, env); + let sides = value.sides(); + let mut vec : Vec = Vec::with_capacity(sides.len()); + for side in sides { + vec.push(ExternRef::::func_new(&env, side.into()).index() as u32); + } + let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&vec), env); + let r: u64 = unsafe { std::mem::transmute((wasm_ptr, vec.len() as u32)) }; + wasm_ok(r) + } fn battle_get_random( env: FunctionEnvMut, battle: ExternRef, ) -> WasmResult> { - let random = get_value_call_getter!(battle.random(), env); - wasm_ok(ExternRef::::func_new(&env, random)) + let battle = get_value!(battle, env); + let random = battle.random(); + wasm_ok(ExternRef::::func_new(&env, random.into())) } fn battle_get_weather_name( @@ -72,7 +89,7 @@ register! { let weather = get_value_call_getter!(battle.weather_name(), env); let weather = try_wasm!(weather, env); wasm_ok(if let Some(weather) = weather { - ExternRef::::func_new(&env, &weather) + ExternRef::::func_new(&env, weather.into()) } else { ExternRef::null() }) @@ -86,8 +103,8 @@ register! { let battle = get_value!(battle, env); let pokemon = get_value!(pokemon, env); for party in battle.parties() { - if party.party().has_pokemon(pokemon) { - return wasm_ok(ExternRef::::func_new(&env, party)); + if party.party().has_pokemon(&pokemon) { + return wasm_ok(ExternRef::::func_new(&env, party.into())); } } wasm_ok(ExternRef::::null()) @@ -101,7 +118,7 @@ register! { let battle = get_value!(battle, env); let pokemon = battle.get_pokemon(side, index); wasm_ok(if let Some(pokemon) = pokemon { - ExternRef::::func_new(&env, &pokemon) + ExternRef::::func_new(&env, (&pokemon).into()) } else { ExternRef::null() }) @@ -159,7 +176,7 @@ register! { env: FunctionEnvMut, battle_party: ExternRef, ) -> WasmResult> { - let value = get_value_call_getter!(battle_party.party(), env); - wasm_ok(ExternRef::::func_new(&env, value.as_ref())) + let battle_party = get_value_arc!(battle_party, env); + wasm_ok(ExternRef::::func_new(&env, battle_party.party().into())) } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs b/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs index fa1894e..a0ed4db 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/battle_random.rs @@ -1,21 +1,18 @@ use crate::dynamic_data::BattleRandom; -use crate::script_implementations::wasm::export_registry::wasm_result::{ - get_value, get_value_call_getter, try_wasm, wasm_ok, -}; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value_arc, try_wasm, wasm_ok}; use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use wasmer::FunctionEnvMut; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; -use anyhow_ext::Context; register! { fn battle_random_get( env: FunctionEnvMut, battle_random: ExternRef, ) -> WasmResult { - let v = get_value_call_getter!(battle_random.get(), env); - let v = try_wasm!(v, env); + let v = get_value_arc!(battle_random, env); + let v = try_wasm!(v.get(), env); wasm_ok(v) } fn battle_random_get_max( @@ -23,7 +20,7 @@ register! { battle_random: ExternRef, max: i32 ) -> WasmResult { - let battle_random = get_value!(battle_random, env); + let battle_random = get_value_arc!(battle_random, env); let v = try_wasm!(battle_random.get_max(max), env); wasm_ok(v) } @@ -33,7 +30,7 @@ register! { min: i32, max: i32 ) -> WasmResult { - let battle_random = get_value!(battle_random, env); + let battle_random = get_value_arc!(battle_random, env); let v = try_wasm!(battle_random.get_between(min, max), env); wasm_ok(v) } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs b/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs index 8089084..9226130 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs @@ -7,7 +7,6 @@ use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use anyhow::anyhow; -use anyhow_ext::Context; use std::ffi::CStr; use wasmer::FunctionEnvMut; @@ -46,7 +45,7 @@ register! { ) -> WasmResult> { let value = get_value_call_getter!(side.battle(), env); let value = try_wasm!(value, env); - wasm_ok(ExternRef::func_new(&env, &value)) + wasm_ok(ExternRef::func_new(&env, (&value).into())) } fn battleside_get_pokemon( @@ -55,11 +54,11 @@ register! { index: u32 ) -> WasmResult> { let side = get_value!(side, env); - wasm_ok(if let Some(Some(p)) = side.pokemon().get(index as usize) { - ExternRef::::func_new(&env, p.as_ref()) + let x = wasm_ok(if let Some(Some(p)) = side.pokemon().get(index as usize) { + ExternRef::::func_new(&env, p.into()) } else { ExternRef::null() - }) + }); x } fn battle_side_get_has_fled_battle( @@ -99,13 +98,13 @@ register! { side: ExternRef, script_ptr: u32 ) -> WasmResult { - let side : &BattleSide = get_value!(side, env); + let side = get_value!(side, env); unsafe { let e = env.data().data(); let name_func = try_wasm!(e.script_function_cache().script_get_name(&e), env); let name_ptr = try_wasm!(name_func.call(&mut e.store_mut(), script_ptr), env); let c_name: &CStr = CStr::from_ptr(e.get_raw_pointer(name_ptr)); - let script = try_wasm!(e.setup_script(script_ptr, ScriptCategory::Side, &c_name.as_ref().into(), side.into()), env); + let script = try_wasm!(e.setup_script(script_ptr, ScriptCategory::Side, &c_name.as_ref().into(), (&side).into()), env); try_wasm!(e.script_function_cache().dealloc_cstring(&e, name_ptr), env); if let Some(script) = script { diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs b/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs index 2b5a57e..c2de197 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/choice_queue.rs @@ -1,8 +1,8 @@ use crate::dynamic_data::{ChoiceQueue, Pokemon}; +use crate::script_implementations::wasm::export_registry::wasm_result::get_value_arc; use crate::script_implementations::wasm::export_registry::{get_value, register, try_wasm, wasm_ok, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; -use anyhow_ext::Context; use wasmer::FunctionEnvMut; register! { @@ -11,9 +11,9 @@ register! { battle_random: ExternRef, pokemon: ExternRef ) -> WasmResult { - let battle_random = get_value!(battle_random, env); + let battle_random = get_value_arc!(battle_random, env); let pokemon = get_value!(pokemon, env); - let res = try_wasm!(battle_random.move_pokemon_choice_next(pokemon), env); + let res = try_wasm!(battle_random.move_pokemon_choice_next(&pokemon), env); wasm_ok(u8::from(res)) } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs b/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs index 68aa902..8ed40f8 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/executing_move.rs @@ -1,13 +1,10 @@ use crate::dynamic_data::{ExecutingMove, HitData, LearnedMove, Pokemon}; use crate::script_implementations::wasm::export_registry::wasm_result::get_value_arc; -use crate::script_implementations::wasm::export_registry::{ - get_value, get_value_call_getter, register, try_wasm, wasm_ok, WasmResult, -}; +use crate::script_implementations::wasm::export_registry::{get_value, register, try_wasm, wasm_ok, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::MoveData; -use anyhow_ext::Context; use wasmer::FunctionEnvMut; register! { @@ -15,31 +12,32 @@ register! { env: FunctionEnvMut, executing_move: ExternRef, ) -> WasmResult> { - let user = get_value_call_getter!(executing_move.user(), env); - wasm_ok(ExternRef::::func_new(&env, user.as_ref())) + let executing_move = get_value_arc!(executing_move, env); + wasm_ok(ExternRef::::func_new(&env, executing_move.user().into())) } fn executing_move_get_use_move( env: FunctionEnvMut, executing_move: ExternRef, ) -> WasmResult> { - let use_move = get_value_call_getter!(executing_move.use_move(), env); - wasm_ok(ExternRef::::func_new(&env, use_move)) + let executing_move = get_value_arc!(executing_move, env); + wasm_ok(ExternRef::::func_new(&env, executing_move.use_move().into())) } fn executing_move_get_chosen_move( env: FunctionEnvMut, executing_move: ExternRef, ) -> WasmResult> { - let chosen_move = get_value_call_getter!(executing_move.chosen_move(), env); - wasm_ok(ExternRef::::func_new(&env, chosen_move.as_ref())) + let executing_move = get_value_arc!(executing_move, env); + wasm_ok(ExternRef::::func_new(&env, executing_move.chosen_move().into())) } fn executing_move_get_number_of_hits( env: FunctionEnvMut, executing_move: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(executing_move.number_of_hits(), env)) + let executing_move = get_value_arc!(executing_move, env); + wasm_ok(executing_move.number_of_hits()) } fn executing_move_get_hit_data( @@ -48,17 +46,18 @@ register! { target: ExternRef, hit: u8 ) -> WasmResult> { - let executing_move = get_value!(executing_move, env); - let target = get_value_arc!(target, env); + let executing_move = get_value_arc!(executing_move, env); + let target = get_value!(target, env); let hit_data = try_wasm!(executing_move.get_hit_data(&target, hit), env); - wasm_ok(ExternRef::::func_new(&env, hit_data)) + wasm_ok(ExternRef::::func_new(&env, hit_data.into())) } fn executing_move_get_number_of_targets( env: FunctionEnvMut, executing_move: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(executing_move.target_count(), env) as u32) + let executing_move = get_value_arc!(executing_move, env); + wasm_ok(executing_move.target_count() as u32) } fn executing_move_is_pokemon_target( @@ -66,8 +65,8 @@ register! { executing_move: ExternRef, pokemon: ExternRef ) -> WasmResult { - let executing_move = get_value!(executing_move, env); - let pokemon = get_value_arc!(pokemon, env); + let executing_move = get_value_arc!(executing_move, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if executing_move.is_pokemon_target(&pokemon) { 1 } else { 0 }) } @@ -77,7 +76,7 @@ register! { env: FunctionEnvMut, executing_move: ExternRef, ) -> WasmResult { - let executing_move = get_value!(executing_move, env); + let executing_move = get_value_arc!(executing_move, env); let script = executing_move.script(); if script.is_any() { let script = try_wasm!(script.get_as::(), env); diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/hit_data.rs b/src/script_implementations/wasm/export_registry/dynamic_data/hit_data.rs index c42a37d..5d74e87 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/hit_data.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/hit_data.rs @@ -1,11 +1,10 @@ use crate::dynamic_data::HitData; use crate::script_implementations::wasm::export_registry::wasm_result::{ - get_value_call_getter, get_value_void, wasm_ok, WasmVoidResultExtension, + get_value_arc, get_value_arc_void, wasm_ok, WasmVoidResultExtension, }; use crate::script_implementations::wasm::export_registry::{register, WasmResult, WasmVoidResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; -use anyhow_ext::Context; use wasmer::FunctionEnvMut; register! { @@ -13,22 +12,23 @@ register! { env: FunctionEnvMut, hit: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(hit.damage(), env)) + let hit = get_value_arc!(hit, env); + wasm_ok(hit.damage()) } fn hit_data_is_critical( env: FunctionEnvMut, hit: ExternRef, ) -> WasmResult { - let is_critical = get_value_call_getter!(hit.is_critical(), env); - wasm_ok(u8::from(is_critical)) + let hit = get_value_arc!(hit, env); + wasm_ok(u8::from(hit.is_critical())) } fn hit_data_fail( env: FunctionEnvMut, hit: ExternRef, ) -> WasmVoidResult { - let hit = get_value_void!(hit, env); + let hit = get_value_arc_void!(hit, env); hit.fail(); WasmVoidResult::ok() } @@ -37,21 +37,24 @@ register! { env: FunctionEnvMut, hit: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(hit.base_power(), env)) + let hit = get_value_arc!(hit, env); + wasm_ok(hit.base_power()) } fn hit_data_get_effectiveness( env: FunctionEnvMut, hit: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(hit.effectiveness(), env)) + let hit = get_value_arc!(hit, env); + wasm_ok(hit.effectiveness()) } fn hit_data_get_move_type( env: FunctionEnvMut, hit: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(hit.move_type(), env).into()) + let hit = get_value_arc!(hit, env); + wasm_ok(hit.move_type().into()) } fn hit_data_set_critical( @@ -59,7 +62,7 @@ register! { hit: ExternRef, value: u8 ) -> WasmVoidResult { - let hit = get_value_void!(hit, env); + let hit = get_value_arc_void!(hit, env); hit.set_critical(value == 1); WasmVoidResult::ok() } @@ -69,7 +72,7 @@ register! { hit: ExternRef, effectiveness: f32 ) -> WasmVoidResult { - let hit = get_value_void!(hit, env); + let hit = get_value_arc_void!(hit, env); hit.set_effectiveness(effectiveness); WasmVoidResult::ok() } @@ -79,7 +82,7 @@ register! { hit: ExternRef, damage: u32 ) -> WasmVoidResult { - let hit = get_value_void!(hit, env); + let hit = get_value_arc_void!(hit, env); hit.set_damage(damage); WasmVoidResult::ok() } @@ -89,7 +92,7 @@ register! { hit: ExternRef, move_type: u8 ) -> WasmVoidResult { - let hit = get_value_void!(hit, env); + let hit = get_value_arc_void!(hit, env); hit.set_move_type(move_type.into()); WasmVoidResult::ok() } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs b/src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs index 3f1e39f..f593ddb 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs @@ -2,13 +2,12 @@ use std::intrinsics::transmute; use crate::dynamic_data::{LearnedMove, MoveLearnMethod}; use crate::script_implementations::wasm::export_registry::wasm_result::{ - get_value_call_getter, get_value_void, wasm_ok, WasmVoidResult, WasmVoidResultExtension, + get_value_arc, get_value_arc_void, wasm_ok, WasmVoidResult, WasmVoidResultExtension, }; use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::MoveData; -use anyhow_ext::Context; use wasmer::FunctionEnvMut; register! { @@ -17,8 +16,8 @@ register! { turn_choice: ExternRef, ) -> WasmResult { unsafe { - let learn_method = get_value_call_getter!(turn_choice.learn_method(), &env); - wasm_ok(transmute::(learn_method)) + let learned_move = get_value_arc!(turn_choice, env); + wasm_ok(transmute::(learned_move.learn_method())) } } @@ -26,15 +25,15 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult> { - let move_data = get_value_call_getter!(turn_choice.move_data(), &env); - wasm_ok(ExternRef::::func_new(&env, move_data)) + let turn_choice = get_value_arc!(turn_choice, env); + wasm_ok(ExternRef::func_new(&env, turn_choice.move_data().into())) } fn learned_move_restore_all_uses( env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmVoidResult { - let turn_choice = get_value_void!(turn_choice, env); + let turn_choice = get_value_arc_void!(turn_choice, env); turn_choice.restore_all_uses(); WasmVoidResult::ok() } @@ -44,7 +43,7 @@ register! { turn_choice: ExternRef, amount: u8, ) -> WasmVoidResult { - let turn_choice = get_value_void!(turn_choice, env); + let turn_choice = get_value_arc_void!(turn_choice, env); turn_choice.restore_uses(amount); WasmVoidResult::ok() } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/mod.rs b/src/script_implementations/wasm/export_registry/dynamic_data/mod.rs index 33db355..f617755 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/mod.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/mod.rs @@ -2,12 +2,10 @@ use crate::dynamic_data::{DynamicLibrary, ScriptOwnerData}; use crate::script_implementations::wasm::export_registry::register; use crate::script_implementations::wasm::export_registry::wasm_result::{try_wasm, wasm_ok, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; -use std::sync::atomic::Ordering; use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut}; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::StaticData; -use anyhow_ext::Context; /// The battle registration mod battle; @@ -37,25 +35,23 @@ register! { ) -> WasmResult> { let dynamic_lib = try_wasm!(dynamic_lib.value_func_arc(&env), env); let static_data = dynamic_lib.static_data(); - wasm_ok(ExternRef::::func_new(&env, static_data)) + wasm_ok(ExternRef::::func_new(&env, static_data.into())) } fn script_get_owner( env: FunctionEnvMut, script: u32, ) -> u32 { - unsafe { - let script = env.data().data().get_loaded_script(script); - if let Some(script) = script { - match script.get_owner() { - ScriptOwnerData::Pokemon(p) => env.data().data().get_extern_ref_index::(p.load(Ordering::Relaxed).as_ref().unwrap()) as u32, - ScriptOwnerData::BattleSide(p) => env.data().data().get_extern_ref_index::(p.load(Ordering::Relaxed).as_ref().unwrap()) as u32, - ScriptOwnerData::Battle(p) => env.data().data().get_extern_ref_index::(p.load(Ordering::Relaxed).as_ref().unwrap()) as u32, - ScriptOwnerData::None => 0, - } - } else { - 0 + let script = env.data().data().get_loaded_script(script); + if let Some(script) = script { + match script.get_owner() { + ScriptOwnerData::Pokemon(p) => env.data().data().get_extern_ref_index(p.into()) as u32, + ScriptOwnerData::BattleSide(p) => env.data().data().get_extern_ref_index(p.into()) as u32, + ScriptOwnerData::Battle(p) => env.data().data().get_extern_ref_index(p.into()) as u32, + ScriptOwnerData::None => 0, } + } else { + 0 } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/party.rs b/src/script_implementations/wasm/export_registry/dynamic_data/party.rs index 797d3ab..742f5f8 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/party.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/party.rs @@ -1,9 +1,8 @@ use crate::dynamic_data::{Pokemon, PokemonParty}; use crate::script_implementations::wasm::export_registry::register; -use crate::script_implementations::wasm::export_registry::wasm_result::{get_value, wasm_ok, WasmResult}; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value_arc, wasm_ok, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; -use anyhow_ext::Context; use wasmer::FunctionEnvMut; register! { @@ -12,20 +11,20 @@ register! { party: ExternRef, index: u32 ) -> WasmResult> { - let party = get_value!(party, env); - wasm_ok( + let party = get_value_arc!(party, env); + let x = wasm_ok( if let Some(Some(v)) = &party.pokemon().get(index as usize) { - ExternRef::func_new(&env, v.as_ref()) + ExternRef::func_new(&env, v.into()) } else { ExternRef::null() - }) + }); x } fn party_get_length( env: FunctionEnvMut, party: ExternRef, ) -> WasmResult { - let party = get_value!(party, env); + let party = get_value_arc!(party, env); wasm_ok(party.length() as u32) } } diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs index 5a7cc12..5c4730b 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs @@ -3,8 +3,8 @@ use std::mem::transmute; use crate::defines::LevelInt; use crate::dynamic_data::{Battle, DynamicLibrary, LearnedMove, Pokemon, VolatileScriptsOwner}; use crate::script_implementations::wasm::export_registry::{ - get_value_arc, get_value_arc_void, get_value_call_getter, get_value_void, register, try_wasm, wasm_err, wasm_ok, - WasmResult, WasmVoidResult, WasmVoidResultExtension, + get_value, get_value_arc, get_value_arc_void, get_value_call_getter, get_value_void, register, try_wasm, wasm_err, + wasm_ok, WasmResult, WasmVoidResult, WasmVoidResultExtension, }; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; @@ -13,7 +13,6 @@ use crate::static_data::{Ability, ClampedStatisticSet, Form, Nature, Species}; use crate::static_data::{Item, StatisticSet}; use crate::{ScriptCategory, VecExt}; use anyhow::anyhow; -use anyhow_ext::Context; use std::ffi::{c_char, CStr, CString}; use wasmer::FunctionEnvMut; @@ -22,56 +21,62 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult> { - let lib = get_value_call_getter!(pokemon.library(), env).clone(); - wasm_ok(ExternRef::::func_new(&env, &lib)) + let pokemon = get_value!(pokemon, env); + let lib = pokemon.library(); + wasm_ok(ExternRef::::func_new(&env, lib.into())) } fn pokemon_get_boosted_stats( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult>> { - let statistic_set = get_value_call_getter!(pokemon.boosted_stats(), env).clone(); - wasm_ok(ExternRef::>::func_new(&env, statistic_set)) + let pokemon = get_value!(pokemon, env); + let statistic_set = pokemon.boosted_stats(); + wasm_ok(ExternRef::>::func_new(&env, statistic_set.into())) } fn pokemon_get_flat_stats( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult>> { - let statistic_set = get_value_call_getter!(pokemon.flat_stats(), env).clone(); - wasm_ok(ExternRef::>::func_new(&env, statistic_set)) + let pokemon = get_value!(pokemon, env); + let statistic_set = pokemon.flat_stats(); + wasm_ok(ExternRef::>::func_new(&env, statistic_set.into())) } fn pokemon_get_stat_boosts( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult>> { - let statistic_set = get_value_call_getter!(pokemon.stat_boosts(), env).clone(); - wasm_ok(ExternRef::>::func_new(&env, statistic_set)) + let pokemon = get_value!(pokemon, env); + let statistic_set = pokemon.stat_boosts(); + wasm_ok(ExternRef::>::func_new(&env, statistic_set.into())) } fn pokemon_get_individual_values( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult>> { - let statistic_set = get_value_call_getter!(pokemon.individual_values(), env).clone(); - wasm_ok(ExternRef::>::func_new(&env, statistic_set)) + let pokemon = get_value!(pokemon, env); + let statistic_set = pokemon.individual_values(); + wasm_ok(ExternRef::>::func_new(&env, statistic_set.into())) } fn pokemon_get_effort_values( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult>> { - let statistic_set = get_value_call_getter!(pokemon.effort_values(), env).clone(); - wasm_ok(ExternRef::>::func_new(&env, statistic_set)) + let pokemon = get_value!(pokemon, env); + let statistic_set = pokemon.effort_values(); + wasm_ok(ExternRef::>::func_new(&env, statistic_set.into())) } fn pokemon_get_species( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult> { - let species = get_value_call_getter!(pokemon.species(), env).clone(); - wasm_ok(ExternRef::::func_new(&env, &species)) + let species = get_value_call_getter!(pokemon.species(), env); + wasm_ok(ExternRef::::func_new(&env, (&species).into())) } fn pokemon_get_weight( @@ -134,11 +139,11 @@ register! { pokemon: ExternRef, index: u32 ) -> WasmResult> { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let read_lock = pokemon.learned_moves().read(); let mv = read_lock.get(index as usize); wasm_ok(if let Some(Some(mv)) = mv { - ExternRef::::func_new(&env, mv) + ExternRef::::func_new(&env, mv.into()) } else{ ExternRef::::null() @@ -153,7 +158,7 @@ register! { self_inflicted: u8 ) -> WasmResult { unsafe{ - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let res = try_wasm!(pokemon.change_stat_boost(transmute(stat), amount, self_inflicted == 1), env); wasm_ok(u8::from(res)) } @@ -163,11 +168,9 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult> { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if let Some(battle) = pokemon.get_battle() { - let r = ExternRef::func_new(&env, &battle); - std::mem::forget(battle); - r + ExternRef::func_new(&env, (&battle).into()) } else { ExternRef::null() }) @@ -177,7 +180,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if let Some(i) = pokemon.get_battle_index() { i } else { @@ -189,7 +192,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if let Some(i) = pokemon.get_battle_side_index() { i } else { @@ -201,10 +204,10 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult> { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let read_lock = pokemon.held_item().read(); wasm_ok(if let Some(item) = read_lock.as_ref() { - ExternRef::::func_new(&env, item.as_ref()) + ExternRef::::func_new(&env, item.into()) } else { ExternRef::::null() }) @@ -217,7 +220,7 @@ register! { ) -> WasmResult { let name : *mut c_char = env.data().data().get_raw_pointer(name); let name = unsafe { CStr::from_ptr(name) }; - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(u8::from(pokemon.has_held_item(&name.into()))) } @@ -227,7 +230,7 @@ register! { amount: u32, allow_revive: u8 ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(u8::from(pokemon.heal(amount, allow_revive == 1))) } @@ -248,14 +251,16 @@ register! { pokemon: ExternRef, ) -> WasmResult> { let active_ability = get_value_call_getter!(pokemon.active_ability(), env); - wasm_ok(ExternRef::::func_new(&env, &active_ability)) + let active_ability = try_wasm!(active_ability, env); + wasm_ok(ExternRef::::func_new(&env, (&active_ability).into())) } fn pokemon_get_real_ability( env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let index = get_value_call_getter!(pokemon.real_ability(), env); + let pokemon = get_value!(pokemon, env); + let index = pokemon.real_ability(); let t: (u8, u8) = (if index.hidden { 1 } else { 0 }, index.index); let r: u16 = unsafe { transmute(t) }; wasm_ok(r) @@ -265,7 +270,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if pokemon.is_ability_overriden() { 1 } else { 0 }) } @@ -273,7 +278,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if pokemon.allowed_experience_gain() { 1 } else { 0 }) } @@ -281,7 +286,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if pokemon.is_usable() { 1 } else { 0 }) } @@ -292,10 +297,10 @@ register! { item: ExternRef ) -> WasmResult> { let item = get_value_arc!(item, env); - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let old_item = pokemon.set_held_item(&item); wasm_ok(if let Some(old_item) = old_item { - ExternRef::::func_new(&env, &old_item) + ExternRef::::func_new(&env, (&old_item).into()) } else { ExternRef::null() }) @@ -305,10 +310,10 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult> { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let old_item = pokemon.remove_held_item(); wasm_ok(if let Some(old_item) = old_item { - ExternRef::::func_new(&env, &old_item) + ExternRef::::func_new(&env, (&old_item).into()) } else { ExternRef::::null() }) @@ -318,7 +323,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let res = try_wasm!(pokemon.consume_held_item(), env); wasm_ok(if res { 1 } else { 0 }) } @@ -327,7 +332,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let len = pokemon.types().len(); wasm_ok(len as u32) } @@ -337,7 +342,7 @@ register! { pokemon: ExternRef, index: u32 ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let types = pokemon.types(); let type_v = types.get_res(index as usize); match type_v { @@ -351,7 +356,7 @@ register! { pokemon: ExternRef, t: u8 ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(if pokemon.types().contains(&t.into()) { 1 } else { 0 }) } @@ -398,8 +403,9 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult> { - let nature = get_value_call_getter!(pokemon.nature(), env); - wasm_ok(ExternRef::::func_new(&env, nature)) + let pokemon = get_value!(pokemon, env); + let nature = pokemon.nature(); + wasm_ok(ExternRef::::func_new(&env, nature.into())) } fn pokemon_get_form( @@ -407,7 +413,7 @@ register! { pokemon: ExternRef, ) -> WasmResult> { let form = get_value_call_getter!(pokemon.form(), env); - wasm_ok(ExternRef::::func_new(&env, &form)) + wasm_ok(ExternRef::::func_new(&env, (&form).into())) } fn pokemon_get_display_species( @@ -415,7 +421,7 @@ register! { pokemon: ExternRef, ) -> WasmResult> { let display_species = get_value_call_getter!(pokemon.display_species(), env); - wasm_ok(ExternRef::::func_new(&env, &display_species)) + wasm_ok(ExternRef::::func_new(&env, (&display_species).into())) } fn pokemon_get_display_form( @@ -423,7 +429,7 @@ register! { pokemon: ExternRef, ) -> WasmResult> { let display_form = get_value_call_getter!(pokemon.display_form(), env); - wasm_ok(ExternRef::::func_new(&env, &display_form)) + wasm_ok(ExternRef::::func_new(&env, (&display_form).into())) } fn pokemon_get_level( @@ -458,7 +464,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let nickname = pokemon.nickname(); if let Some(nickname) = nickname { let nickname: CString = match CString::new(nickname.as_str()) { @@ -482,7 +488,7 @@ register! { name_ptr: u32 ) -> WasmResult { unsafe { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); let script = try_wasm!(pokemon.add_volatile_script(&c_name.as_ref().into()), env); if let Some(script) = script { @@ -499,7 +505,7 @@ register! { pokemon: ExternRef, script_ptr: u32 ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); unsafe{ let env_data = env.data().data(); let name_ptr = match try_wasm!(env_data.script_function_cache().script_get_name(&env_data), env).call(&mut env_data.store_mut(), script_ptr){ @@ -507,14 +513,14 @@ register! { Err(e) => return wasm_err::(e.into(), &env) }; let c_name: &CStr = CStr::from_ptr(env_data.get_raw_pointer(name_ptr)); - let script = try_wasm!(env_data.setup_script(script_ptr, ScriptCategory::Pokemon, &c_name.as_ref().into(), pokemon.as_ref().into()), env); + let script = try_wasm!(env_data.setup_script(script_ptr, ScriptCategory::Pokemon, &c_name.as_ref().into(), (&pokemon).into()), env); try_wasm!(env_data.script_function_cache().dealloc_cstring(&env_data, name_ptr), env); if let Some(script) = script { let script = try_wasm!(pokemon.add_volatile_script_with_script(script), env); let s = match script.as_ref() { Some(s) => s, - None => return wasm_err::(anyhow!("Unable to get script").into(), &env) + None => return wasm_err::(anyhow!("Unable to get script"), &env) }; let s = try_wasm!(s.get_as::(), env); wasm_ok(s.get_wasm_pointer()) @@ -531,7 +537,7 @@ register! { ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); wasm_ok(u8::from(pokemon.has_volatile_script(&c_name.as_ref().into()))) } } @@ -543,7 +549,7 @@ register! { ) -> WasmResult { unsafe { let c_name = CStr::from_ptr(env.data().data().get_raw_pointer(name_ptr)); - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let script = pokemon.get_volatile_script(&c_name.as_ref().into()); wasm_ok(if let Some(script) = script { let script = try_wasm!(script.get_as::(), env); @@ -564,7 +570,7 @@ register! { let pokemon = get_value_void!(pokemon, env); match pokemon.remove_volatile_script(&c_name.as_ref().into()) { Ok(_) => WasmVoidResult::ok(), - Err(e) => WasmVoidResult::err(e.into(), &env) + Err(e) => WasmVoidResult::err(e, &env) } } } @@ -573,7 +579,7 @@ register! { env: FunctionEnvMut, pokemon: ExternRef, ) -> WasmResult { - let pokemon = get_value_arc!(pokemon, env); + let pokemon = get_value!(pokemon, env); let script = pokemon.ability_script(); if script.is_any() { let script = try_wasm!(script.get_as::(), env); diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs b/src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs index ac73c72..565b220 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs @@ -1,14 +1,12 @@ use crate::dynamic_data::{LearnedMove, Pokemon, TurnChoice}; -use crate::script_implementations::wasm::export_registry::wasm_result::{ - get_value, get_value_call_getter, get_value_void, wasm_err, -}; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value_arc, get_value_arc_void, wasm_err}; use crate::script_implementations::wasm::export_registry::{ register, wasm_ok, WasmResult, WasmVoidResult, WasmVoidResultExtension, }; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; -use anyhow_ext::Context; +use std::ops::Deref; use wasmer::FunctionEnvMut; register! { @@ -17,16 +15,16 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult> { - let user = get_value_call_getter!(turn_choice.user(), &env); - wasm_ok(ExternRef::func_new(&env, user)) + let turn_choice = get_value_arc!(turn_choice, env); + wasm_ok(ExternRef::func_new(&env, turn_choice.user().into())) } fn turn_choice_get_kind( env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - let turn_choice = get_value!(turn_choice, env); - wasm_ok(match turn_choice { + let turn_choice = get_value_arc!(turn_choice, env); + wasm_ok(match turn_choice.deref() { TurnChoice::Move(_) => 0, TurnChoice::Item(_) => 1, TurnChoice::Switch(_) => 2, @@ -39,21 +37,23 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - wasm_ok(get_value_call_getter!(turn_choice.speed(), &env)) + let turn_choice = get_value_arc!(turn_choice, env); + wasm_ok(turn_choice.speed()) } fn turn_choice_has_failed( env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - wasm_ok(if get_value_call_getter!(turn_choice.has_failed(), &env) { 1 } else { 0 }) + let turn_choice = get_value_arc!(turn_choice, env); + wasm_ok(if turn_choice.has_failed() { 1 } else { 0 }) } fn turn_choice_fail( env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmVoidResult { - let turn_choice = get_value_void!(turn_choice, env); + let turn_choice = get_value_arc_void!(turn_choice, env); turn_choice.fail(); WasmVoidResult::ok() } @@ -63,9 +63,9 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - return match turn_choice.value_func(&env) { + return match turn_choice.value_func_arc(&env) { Ok(v) => { - match v { + match v.deref() { TurnChoice::Move(m) => wasm_ok(m.priority()), _ => wasm_err::(anyhow_ext::anyhow!("Invalid turn choice"), &env) } @@ -78,10 +78,10 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult> { - return match turn_choice.value_func(&env) { + return match turn_choice.value_func_arc(&env) { Ok(v) => { - match v { - TurnChoice::Move(m) => wasm_ok(ExternRef::::func_new(&env, m.used_move())), + match v.deref() { + TurnChoice::Move(m) => wasm_ok(ExternRef::func_new(&env, m.used_move().into())), _ => wasm_err::>(anyhow_ext::anyhow!("Invalid turn choice"), &env) } }, @@ -93,9 +93,9 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - return match turn_choice.value_func(&env) { + return match turn_choice.value_func_arc(&env) { Ok(v) => { - match v { + match v.deref() { TurnChoice::Move(m) => wasm_ok(m.target_side()), _ => wasm_err::(anyhow_ext::anyhow!("Invalid turn choice"), &env) } @@ -108,9 +108,9 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - return match turn_choice.value_func(&env) { + return match turn_choice.value_func_arc(&env) { Ok(v) => { - match v { + match v.deref() { TurnChoice::Move(m) => wasm_ok(m.target_index()), _ => wasm_err::(anyhow_ext::anyhow!("Invalid turn choice"), &env) } @@ -123,9 +123,9 @@ register! { env: FunctionEnvMut, turn_choice: ExternRef, ) -> WasmResult { - return match turn_choice.value_func(&env) { + return match turn_choice.value_func_arc(&env) { Ok(v) => { - match v { + match v.deref() { TurnChoice::Move(d) => { if let Some(script) = d.script().get() { let read_lock = script.read(); diff --git a/src/script_implementations/wasm/export_registry/mod.rs b/src/script_implementations/wasm/export_registry/mod.rs index 97d89ce..b611054 100755 --- a/src/script_implementations/wasm/export_registry/mod.rs +++ b/src/script_implementations/wasm/export_registry/mod.rs @@ -1,21 +1,25 @@ use anyhow_ext::anyhow; use std::ffi::{c_char, CStr, CString}; use std::mem::{align_of, forget}; +use std::ops::Deref; use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::EffectParameter; use crate::StringKey; -use anyhow_ext::Context; /// Dynamic data registration mod dynamic_data; /// Static data registration mod static_data; +/// Handling for opaque handles passed to WASM mod wasm_object; +/// Result types for WASM mod wasm_result; +#[doc(inline)] +pub(super) use wasm_object::*; #[doc(inline)] pub use wasm_result::*; @@ -71,7 +75,6 @@ pub(crate) fn register_webassembly_funcs( ) { register_func_with_env!(imports, store, _print, env); register_func_with_env!(imports, store, _error, env); - register_func_with_env!(imports, store, _vec_extern_ref_get_value, env); static_data::register(imports, store, env); dynamic_data::register(imports, store, env); @@ -90,7 +93,9 @@ fn _print(env: FunctionEnvMut, p: u32) { unsafe { let mem: *mut c_char = env.data().data().get_raw_pointer(p); let s = CStr::from_ptr(mem); - println!("{}", s.to_str().unwrap()); + if let Ok(v) = s.to_str() { + println!("{}", v); + } } } @@ -100,21 +105,13 @@ fn _error(env: FunctionEnvMut, message: u32) { unsafe { let mem: *const c_char = env.data().data().get_raw_pointer(message); let message_str = CStr::from_ptr(mem); - panic!("WASM Error: {}", message_str.to_str().unwrap()); + #[allow(clippy::panic)] + if let Ok(v) = message_str.to_str() { + panic!("WASM Error: {}", v); + } } } -/// Get a single item from an earlier passed VecExternRef -fn _vec_extern_ref_get_value(env: FunctionEnvMut, reference: u32, index: u32) -> WasmResult { - let res = try_wasm!( - env.data() - .data() - .get_extern_vec_ref_extern_ref(reference as usize, index as usize), - env - ); - wasm_ok(res as u32) -} - /// Gets the hash value of a StringKey. fn string_key_get_hash(env: FunctionEnvMut, string_key: ExternRef) -> WasmResult { let value = get_value!(string_key, env); @@ -123,7 +120,7 @@ fn string_key_get_hash(env: FunctionEnvMut, string_key: ExternRe /// Get a null-terminated C string from a StringKey. Note that this involves a copy into WASM /// memory, so this is relatively heavy. -fn string_key_get_str(env: FunctionEnvMut, string_key: ExternRef) -> (u32, u32) { +fn string_key_get_str(env: FunctionEnvMut, string_key: ExternRef) -> WasmResult { let value = get_value!(string_key, env); let string_key = value.str(); let wasm_string_ptr = try_wasm!( @@ -147,8 +144,8 @@ fn effect_parameter_get_type( env: FunctionEnvMut, parameter: ExternRef, ) -> WasmResult { - let value = get_value!(parameter, env); - wasm_ok(match value { + let value = get_value_arc!(parameter, env); + wasm_ok(match value.deref() { EffectParameter::Bool(_, _) => 1, EffectParameter::Int(_, _) => 2, EffectParameter::Float(_, _) => 3, @@ -161,8 +158,8 @@ fn effect_parameter_as_bool( env: FunctionEnvMut, parameter: ExternRef, ) -> WasmResult { - let value = get_value!(parameter, env); - match value { + let value = get_value_arc!(parameter, env); + match value.deref() { EffectParameter::Bool(_, b) => wasm_ok(>::from(*b)), _ => wasm_err::(anyhow!("Unexpected parameter type. Expected bool, got {}", value), &env), } @@ -173,8 +170,8 @@ fn effect_parameter_as_int( env: FunctionEnvMut, parameter: ExternRef, ) -> WasmResult { - let value = get_value!(parameter, env); - match value { + let value = get_value_arc!(parameter, env); + match value.deref() { EffectParameter::Int(_, i) => wasm_ok(*i), _ => wasm_err::(anyhow!("Unexpected parameter type. Expected int, got {}", value), &env), } @@ -185,8 +182,8 @@ fn effect_parameter_as_float( env: FunctionEnvMut, parameter: ExternRef, ) -> WasmResult { - let value = get_value!(parameter, env); - match value { + let value = get_value_arc!(parameter, env); + match value.deref() { EffectParameter::Float(_, f) => wasm_ok(*f), _ => wasm_err::( anyhow!("Unexpected parameter type. Expected float, got {}", value), @@ -200,9 +197,9 @@ fn effect_parameter_as_string( env: FunctionEnvMut, parameter: ExternRef, ) -> WasmResult> { - let value = get_value!(parameter, env); - match value { - EffectParameter::Float(_, s) => wasm_ok(ExternRef::::func_new(&env, s)), + let value = get_value_arc!(parameter, env); + match value.deref() { + EffectParameter::String(_, s) => wasm_ok(ExternRef::::func_new(&env, s.clone().into())), _ => wasm_err::>( anyhow!("Unexpected parameter type. Expected string, got {}", value), &env, diff --git a/src/script_implementations/wasm/export_registry/static_data/ability.rs b/src/script_implementations/wasm/export_registry/static_data/ability.rs index 4055a07..0571a32 100644 --- a/src/script_implementations/wasm/export_registry/static_data/ability.rs +++ b/src/script_implementations/wasm/export_registry/static_data/ability.rs @@ -1,6 +1,7 @@ -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::wasm_result::get_value_arc; use crate::script_implementations::wasm::export_registry::FunctionEnvMut; -use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; +use crate::script_implementations::wasm::export_registry::{register, try_wasm, wasm_ok, WasmResult}; +use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::{Ability, EffectParameter}; use crate::StringKey; @@ -10,25 +11,32 @@ register! { fn ability_get_name( env: FunctionEnvMut, ability: ExternRef -) -> ExternRef { - let ability = ability.value_func_arc(&env).unwrap(); - ExternRef::func_new(&env, ability.name()) +) -> WasmResult> { + let ability = get_value_arc!(ability, env); + wasm_ok(ExternRef::func_new(&env, ability.name().clone().into())) } fn ability_get_effect( env: FunctionEnvMut, ability: ExternRef -) -> ExternRef { - let ability = ability.value_func_arc(&env).unwrap(); - ExternRef::func_new(&env, ability.effect()) +) -> WasmResult> { + let ability = get_value_arc!(ability, env); + wasm_ok(ExternRef::func_new(&env, ability.effect().clone().into())) } fn ability_get_parameters( env: FunctionEnvMut, ability: ExternRef -) -> VecExternRef { - let ability = ability.value_func_arc(&env).unwrap(); - VecExternRef::new(env.data().data().as_ref(), ability.parameters()) +) -> WasmResult { + let ability = get_value_arc!(ability, env); + let parameters = ability.parameters(); + let mut vec : Vec = Vec::with_capacity(parameters.len()); + for parameter in parameters { + vec.push(ExternRef::::func_new(&env, parameter.into()).index() as u32); + } + let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&vec), env); + let r: u64 = unsafe { std::mem::transmute((wasm_ptr, vec.len() as u32)) }; + wasm_ok(r) } } diff --git a/src/script_implementations/wasm/export_registry/static_data/form.rs b/src/script_implementations/wasm/export_registry/static_data/form.rs index cf21193..aa94ffd 100644 --- a/src/script_implementations/wasm/export_registry/static_data/form.rs +++ b/src/script_implementations/wasm/export_registry/static_data/form.rs @@ -1,26 +1,25 @@ -use crate::script_implementations::wasm::export_registry::wasm_result::try_wasm; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value_arc, try_wasm}; use crate::script_implementations::wasm::export_registry::{register, wasm_ok, FunctionEnvMut, WasmResult}; -use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; +use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::{Form, StatisticSet}; use crate::StringKey; -use anyhow_ext::Context; register! { fn form_get_name( env: FunctionEnvMut, form: ExternRef -) -> ExternRef { - let form = form.value_func_arc(&env).unwrap(); - ExternRef::func_new(&env, form.name()) +) -> WasmResult> { + let form = get_value_arc!(form, env); + wasm_ok(ExternRef::func_new(&env, form.name().clone().into())) } fn form_get_types( env: FunctionEnvMut, form: ExternRef ) -> WasmResult { - let form = form.value_func_arc(&env).unwrap(); + let form = get_value_arc!(form, env); let vec = form.types(); let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(vec), env); let r: u64 = unsafe { std::mem::transmute((wasm_ptr, vec.len() as u32)) }; @@ -30,54 +29,69 @@ fn form_get_types( fn form_get_height( env: FunctionEnvMut, form: ExternRef -) -> f32 { - form.value_func_arc(&env).unwrap().height() +) -> WasmResult { + wasm_ok(get_value_arc!(form, env).height()) } fn form_get_weight( env: FunctionEnvMut, form: ExternRef -) -> f32 { - form.value_func_arc(&env).unwrap().weight() +) -> WasmResult { + wasm_ok(get_value_arc!(form, env).weight()) } fn form_get_base_experience( env: FunctionEnvMut, form: ExternRef -) -> u32 { - form.value_func_arc(&env).unwrap().base_experience() +) -> WasmResult { + wasm_ok(get_value_arc!(form, env).base_experience()) } fn form_get_base_stats( env: FunctionEnvMut, form: ExternRef -) -> ExternRef> { - let form = form.value_func_arc(&env).unwrap(); - ExternRef::func_new(&env, form.base_stats()) +) -> WasmResult>> { + let form = get_value_arc!(form, env); + wasm_ok(ExternRef::func_new(&env, form.base_stats().into())) } fn form_get_abilities( env: FunctionEnvMut, form: ExternRef -) -> VecExternRef { - let form = form.value_func_arc(&env).unwrap(); - VecExternRef::new(env.data().data().as_ref(), form.abilities()) +) -> WasmResult { + let form = get_value_arc!(form, env); + let abilities = form.abilities(); + let mut ability_refs : Vec = Vec::with_capacity(abilities.len()); + for ability in abilities { + ability_refs.push(ExternRef::::func_new(&env, ability.clone().into()).index() as u32); + } + let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&ability_refs), env); + let r: u64 = unsafe { std::mem::transmute((wasm_ptr, ability_refs.len() as u32)) }; + wasm_ok(r) } fn form_get_hidden_abilities( env: FunctionEnvMut, form: ExternRef -) -> VecExternRef { - let form = form.value_func_arc(&env).unwrap(); - VecExternRef::new(env.data().data().as_ref(), form.hidden_abilities()) +) -> WasmResult { + let form = get_value_arc!(form, env); + let abilities = form.hidden_abilities(); + let mut ability_refs : Vec = Vec::with_capacity(abilities.len()); + for ability in abilities { + ability_refs.push(ExternRef::::func_new(&env, ability.clone().into()).index() as u32); + } + let wasm_ptr = try_wasm!(env.data().data().copy_value_vec_to_wasm(&ability_refs), env); + let r: u64 = unsafe { std::mem::transmute((wasm_ptr, ability_refs.len() as u32)) }; + wasm_ok(r) } fn form_has_flag_by_hash( env: FunctionEnvMut, form: ExternRef, flag_hash: u32, -) -> u8 { - if form.value_func_arc(&env).unwrap().has_flag_by_hash(flag_hash) { 1 } else { 0 } +) -> WasmResult { + let form = get_value_arc!(form, env); + wasm_ok(if form.has_flag_by_hash(flag_hash) { 1 } else { 0 }) } diff --git a/src/script_implementations/wasm/export_registry/static_data/item.rs b/src/script_implementations/wasm/export_registry/static_data/item.rs index be8c750..7cdfd2a 100755 --- a/src/script_implementations/wasm/export_registry/static_data/item.rs +++ b/src/script_implementations/wasm/export_registry/static_data/item.rs @@ -1,4 +1,5 @@ -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value, get_value_arc, wasm_ok}; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::Item; @@ -12,60 +13,67 @@ register! { env: FunctionEnvMut, lib: ExternRef, string_key: ExternRef, - ) -> ExternRef { - let lib = lib.value_func_box(&env).unwrap(); - let m = lib.get(string_key.value_func(&env).unwrap()); - if let Some(v) = m { - ExternRef::func_new(&env, &v) + ) -> WasmResult> { + let lib = get_value_arc!(lib, env); + let string_key = get_value!(string_key, env); + let m = lib.get(&string_key); + wasm_ok(if let Some(v) = m { + ExternRef::func_new(&env, (&v).into()) } else { ExternRef::null() - } + }) } - fn item_library_get_item_by_hash(env: FunctionEnvMut, lib: ExternRef, hash: u32) -> ExternRef { - let lib = lib.value_func_box(&env).unwrap(); + fn item_library_get_item_by_hash(env: FunctionEnvMut, lib: ExternRef, hash: u32) -> WasmResult> { + let lib = get_value_arc!(lib, env); let m = lib.get_by_hash(hash); - if let Some(v) = m { - ExternRef::func_new(&env, &v) + wasm_ok(if let Some(v) = m { + ExternRef::func_new(&env, (&v).into()) } else { ExternRef::null() - } + }) } fn item_get_price( env: FunctionEnvMut, item: ExternRef, - ) -> i32 { - item.value_func_arc(&env).unwrap().price() + ) -> WasmResult { + let item = get_value_arc!(item, env); + wasm_ok(item.price()) } fn item_get_name( env: FunctionEnvMut, item: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, item.value_func_arc(&env).unwrap().name()) + ) -> WasmResult> { + let item = get_value_arc!(item, env); + wasm_ok(ExternRef::func_new(&env, item.name().clone().into())) } fn item_get_category( env: FunctionEnvMut, item: ExternRef, - ) -> u8 { - unsafe { transmute(item.value_func_arc(&env).unwrap().category()) } + ) -> WasmResult { + let item = get_value_arc!(item, env); + unsafe { wasm_ok(transmute(item.category())) } } fn item_get_battle_category( env: FunctionEnvMut, item: ExternRef, - ) -> u8 { - unsafe { transmute(item.value_func_arc(&env).unwrap().battle_category()) } + ) -> WasmResult { + let item = get_value_arc!(item, env); + unsafe { wasm_ok(transmute(item.battle_category())) } } fn item_has_flag( env: FunctionEnvMut, item: ExternRef, key: ExternRef - ) -> u8 { - if item.value_func_arc(&env).unwrap().has_flag(key.value_func(&env).unwrap()) { 1 } else { 0 } + ) -> WasmResult { + let item = get_value_arc!(item, env); + let key = get_value!(key, env); + wasm_ok(if item.has_flag(&key) { 1 } else { 0 }) } } diff --git a/src/script_implementations/wasm/export_registry/static_data/mod.rs b/src/script_implementations/wasm/export_registry/static_data/mod.rs index 769ba13..60d32d7 100755 --- a/src/script_implementations/wasm/export_registry/static_data/mod.rs +++ b/src/script_implementations/wasm/export_registry/static_data/mod.rs @@ -3,7 +3,7 @@ use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut}; use crate::defines::LevelInt; use crate::script_implementations::wasm::export_registry::wasm_result::{ - get_value, get_value_void, wasm_ok, WasmResult, + get_value_arc, get_value_arc_void, wasm_ok, WasmResult, }; use crate::script_implementations::wasm::export_registry::{register, WasmVoidResult, WasmVoidResultExtension}; use crate::script_implementations::wasm::extern_ref::ExternRef; @@ -12,7 +12,6 @@ use crate::static_data::{ ItemLibrary, LibrarySettings, MoveLibrary, SpeciesLibrary, StaticData, StaticStatisticSet, StatisticSet, TypeLibrary, }; -use anyhow_ext::Context; /// Ability data registration mod ability; @@ -30,52 +29,59 @@ mod species; mod types; register! { - fn static_data_get_move_library(env: FunctionEnvMut, data_library: ExternRef) -> ExternRef { - ExternRef::func_new(&env, data_library.value_func_box(&env).unwrap().moves()) + fn static_data_get_move_library(env: FunctionEnvMut, data_library: ExternRef) -> WasmResult> { + let data_library = get_value_arc!(data_library, env); + wasm_ok(ExternRef::func_new(&env, data_library.moves().into())) } fn static_data_get_species_library( env: FunctionEnvMut, data_library: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, data_library.value_func_box(&env).unwrap().species()) + ) -> WasmResult> { + let data_library = get_value_arc!(data_library, env); + wasm_ok(ExternRef::func_new(&env, data_library.species().into())) } - fn static_data_get_item_library(env: FunctionEnvMut, data_library: ExternRef) -> ExternRef { - ExternRef::func_new(&env, data_library.value_func_box(&env).unwrap().items()) + fn static_data_get_item_library(env: FunctionEnvMut, data_library: ExternRef) -> WasmResult> { + let data_library = get_value_arc!(data_library, env); + wasm_ok(ExternRef::func_new(&env, data_library.items().into())) } - fn static_data_get_type_library(env: FunctionEnvMut, data_library: ExternRef) -> ExternRef { - ExternRef::func_new(&env, data_library.value_func_box(&env).unwrap().types()) + fn static_data_get_type_library(env: FunctionEnvMut, data_library: ExternRef) -> WasmResult> { + let data_library = get_value_arc!(data_library, env); + wasm_ok(ExternRef::func_new(&env, data_library.types().into())) } fn static_data_get_library_settings( env: FunctionEnvMut, data_library: ExternRef, - ) -> ExternRef { - ExternRef::func_new(&env, data_library.value_func_box(&env).unwrap().settings()) + ) -> WasmResult> { + let data_library = get_value_arc!(data_library, env); + wasm_ok(ExternRef::func_new(&env, data_library.settings().into())) } - fn library_settings_get_maximum_level(env: FunctionEnvMut, data_library: ExternRef) -> LevelInt { - data_library.value_func_box(&env).unwrap().maximum_level() + fn library_settings_get_maximum_level(env: FunctionEnvMut, data_library: ExternRef) -> WasmResult { + let data_library = get_value_arc!(data_library, env); + wasm_ok(data_library.maximum_level()) } - fn static_statistics_set_get_stat(env: FunctionEnvMut, statistics_set: ExternRef>, stat: u8) -> u32 { + fn static_statistics_set_get_stat(env: FunctionEnvMut, statistics_set: ExternRef>, stat: u8) -> WasmResult { unsafe { - statistics_set.value_func(&env).unwrap().get_stat(transmute(stat)) as u32 + let statistics_set = get_value_arc!(statistics_set, env); + wasm_ok(statistics_set.get_stat(transmute(stat)) as u32) } } fn statistic_set_get(env: FunctionEnvMut, statistics_set: ExternRef>, stat: u8) -> WasmResult { unsafe { - let statistics_set = get_value!(statistics_set, env); + let statistics_set = get_value_arc!(statistics_set, env); wasm_ok(statistics_set.get_stat(transmute(stat)) as i64) } } fn statistic_set_set(env: FunctionEnvMut, statistics_set: ExternRef>, stat: u8, value: u64) -> WasmVoidResult { unsafe { - let statistics_set = get_value_void!(statistics_set, env); + let statistics_set = get_value_arc_void!(statistics_set, env); statistics_set.set_stat(transmute(stat), value as u32); WasmVoidResult::ok() } @@ -83,7 +89,7 @@ register! { fn statistic_set_increase_stat(env: FunctionEnvMut, statistics_set: ExternRef>, stat: u8, value: u64) -> WasmVoidResult { unsafe { - let statistics_set = get_value_void!(statistics_set, env); + let statistics_set = get_value_arc_void!(statistics_set, env); statistics_set.increase_stat(transmute(stat), value as u32); WasmVoidResult::ok() } @@ -91,7 +97,7 @@ register! { fn statistic_set_decrease_stat(env: FunctionEnvMut, statistics_set: ExternRef>, stat: u8, value: u64) -> WasmVoidResult { unsafe { - let statistics_set = get_value_void!(statistics_set, env); + let statistics_set = get_value_arc_void!(statistics_set, env); statistics_set.decrease_stat(transmute(stat), value as u32); WasmVoidResult::ok() } diff --git a/src/script_implementations/wasm/export_registry/static_data/moves.rs b/src/script_implementations/wasm/export_registry/static_data/moves.rs index aaec1cd..0197d5e 100755 --- a/src/script_implementations/wasm/export_registry/static_data/moves.rs +++ b/src/script_implementations/wasm/export_registry/static_data/moves.rs @@ -1,4 +1,5 @@ -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value, get_value_arc, wasm_ok}; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::{MoveData, MoveLibrary}; @@ -10,55 +11,67 @@ fn move_library_get_move( env: FunctionEnvMut, lib: ExternRef, string_key: ExternRef, -) -> ExternRef { - let lib = lib.value_func_box(&env).unwrap(); - let m = lib.get(string_key.value_func(&env).unwrap()); - if let Some(v) = m { - ExternRef::func_new(&env, &v) +) -> WasmResult> { + let lib = get_value_arc!(lib, env); + let string_key = get_value!(string_key, env); + let m = lib.get(&string_key); + wasm_ok(if let Some(v) = m { + ExternRef::func_new(&env, (&v).into()) } else { ExternRef::null() - } + }) } -fn move_library_get_move_by_hash(env: FunctionEnvMut, lib: ExternRef, hash: u32) -> ExternRef { - let lib = lib.value_func_box(&env).unwrap(); +fn move_library_get_move_by_hash(env: FunctionEnvMut, lib: ExternRef, hash: u32) -> WasmResult> { + let lib = get_value_arc!(lib, env); let m = lib.get_by_hash(hash); - if let Some(v) = m { - ExternRef::func_new(&env, &v) + wasm_ok(if let Some(v) = m { + ExternRef::func_new(&env, (&v).into()) } else { ExternRef::null() - } + }) } -fn move_data_get_name(env: FunctionEnvMut, move_data: ExternRef) -> ExternRef { - ExternRef::func_new(&env, move_data.value_func_arc(&env).unwrap().name()) +fn move_data_get_name(env: FunctionEnvMut, move_data: ExternRef) ->WasmResult> { + let move_data = get_value_arc!(move_data, env); + wasm_ok(ExternRef::func_new(&env, move_data.name().clone().into())) } -fn move_data_get_type(env: FunctionEnvMut, move_data: ExternRef) -> u8 { - move_data.value_func_arc(&env).unwrap().move_type().into() +fn move_data_get_type(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.move_type().into()) } -fn move_data_get_category(env: FunctionEnvMut, move_data: ExternRef) -> u8 { - move_data.value_func_arc(&env).unwrap().category() as u8 +fn move_data_get_category(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.category() as u8) } -fn move_data_get_base_power(env: FunctionEnvMut, move_data: ExternRef) -> u8 { - move_data.value_func_arc(&env).unwrap().base_power() +fn move_data_get_base_power(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.base_power()) } -fn move_data_get_accuracy(env: FunctionEnvMut, move_data: ExternRef) -> u8 { - move_data.value_func_arc(&env).unwrap().accuracy() +fn move_data_get_accuracy(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.accuracy()) } -fn move_data_get_base_usages(env: FunctionEnvMut, move_data: ExternRef) -> u8 { - move_data.value_func_arc(&env).unwrap().base_usages() +fn move_data_get_base_usages(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.base_usages()) } -fn move_data_get_target(env: FunctionEnvMut, move_data: ExternRef) -> u8 { - move_data.value_func_arc(&env).unwrap().target() as u8 +fn move_data_get_target(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.target() as u8) } -fn move_data_get_priority(env: FunctionEnvMut, move_data: ExternRef) -> i8 { - move_data.value_func_arc(&env).unwrap().priority() +fn move_data_get_priority(env: FunctionEnvMut, move_data: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(move_data.priority()) } -fn move_data_has_flag(env: FunctionEnvMut, move_data: ExternRef, flag: ExternRef) -> u8 { - u8::from(move_data.value_func_arc(&env).unwrap().has_flag(flag.value_func(&env).unwrap())) +fn move_data_has_flag(env: FunctionEnvMut, move_data: ExternRef, flag: ExternRef) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + let flag = get_value!(flag, env); + wasm_ok(u8::from(move_data.has_flag(&flag))) } -fn move_data_has_flag_by_hash(env: FunctionEnvMut, move_data: ExternRef, flag_hash: u32) -> u8 { - u8::from(move_data.value_func_arc(&env).unwrap().has_flag_by_hash(flag_hash)) +fn move_data_has_flag_by_hash(env: FunctionEnvMut, move_data: ExternRef, flag_hash: u32) -> WasmResult { + let move_data = get_value_arc!(move_data, env); + wasm_ok(u8::from(move_data.has_flag_by_hash(flag_hash))) } } diff --git a/src/script_implementations/wasm/export_registry/static_data/nature.rs b/src/script_implementations/wasm/export_registry/static_data/nature.rs index f370c49..081cd55 100644 --- a/src/script_implementations/wasm/export_registry/static_data/nature.rs +++ b/src/script_implementations/wasm/export_registry/static_data/nature.rs @@ -1,4 +1,5 @@ -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value_arc, wasm_ok}; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::Nature; @@ -9,25 +10,29 @@ register! { fn nature_get_increase_stat( env: FunctionEnvMut, nature: ExternRef -) -> u8 { - unsafe { transmute(nature.value_func_box(&env).unwrap().increased_stat()) } +) -> WasmResult { + let nature = get_value_arc!(nature, env); + wasm_ok(unsafe { transmute(nature.increased_stat()) }) } fn nature_get_decrease_stat( env: FunctionEnvMut, nature: ExternRef -) -> u8 { - unsafe { transmute(nature.value_func_box(&env).unwrap().decreased_stat()) } +) -> WasmResult { + let nature = get_value_arc!(nature, env); + wasm_ok(unsafe { transmute(nature.decreased_stat()) }) } fn nature_get_increase_modifier( env: FunctionEnvMut, nature: ExternRef -) -> f32 { - nature.value_func_box(&env).unwrap().increased_modifier() +) -> WasmResult { + let nature = get_value_arc!(nature, env); + wasm_ok(nature.increased_modifier()) } fn nature_get_decrease_modifier( env: FunctionEnvMut, nature: ExternRef -) -> f32 { - nature.value_func_box(&env).unwrap().decreased_modifier() +) -> WasmResult { + let nature = get_value_arc!(nature, env); + wasm_ok(nature.decreased_modifier()) } } diff --git a/src/script_implementations/wasm/export_registry/static_data/species.rs b/src/script_implementations/wasm/export_registry/static_data/species.rs index 5793c16..01d5447 100755 --- a/src/script_implementations/wasm/export_registry/static_data/species.rs +++ b/src/script_implementations/wasm/export_registry/static_data/species.rs @@ -1,4 +1,5 @@ -use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::wasm_result::{get_value, get_value_arc, wasm_ok}; +use crate::script_implementations::wasm::export_registry::{register, WasmResult}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; use crate::static_data::SpeciesLibrary; @@ -12,73 +13,78 @@ fn species_library_get_species( env: FunctionEnvMut, lib: ExternRef, string_key: ExternRef, -) -> ExternRef { - let lib = lib.value_func_box(&env).unwrap(); - let m = lib.get(string_key.value_func(&env).unwrap()); - if let Some(v) = m { - ExternRef::func_new(&env, &v) +) -> WasmResult> { + let lib = get_value_arc!(lib, env); + let string_key = get_value!(string_key, env); + let m = lib.get(&string_key); + wasm_ok(if let Some(v) = m { + ExternRef::func_new(&env, (&v).into()) } else { ExternRef::null() - } + }) } fn species_get_capture_rate( env: FunctionEnvMut, species: ExternRef, -) -> u8 { - species.value_func_arc(&env).unwrap().capture_rate() +) -> WasmResult { + let species = get_value_arc!(species, env); + wasm_ok(species.capture_rate()) } fn species_get_growth_rate( env: FunctionEnvMut, species: ExternRef, -) -> ExternRef { - let species = species.value_func_arc(&env).unwrap(); - ExternRef::func_new(&env, species.growth_rate()) +) -> WasmResult> { + let species = get_value_arc!(species, env); + wasm_ok(ExternRef::func_new(&env, species.growth_rate().clone().into())) } fn species_get_gender_rate( env: FunctionEnvMut, species: ExternRef, -) -> f32 { - species.value_func_arc(&env).unwrap().gender_rate() +) -> WasmResult { + let species = get_value_arc!(species, env); + wasm_ok(species.gender_rate()) } fn species_get_name( env: FunctionEnvMut, species: ExternRef, -) -> ExternRef { - let species = species.value_func_arc(&env).unwrap(); - ExternRef::func_new(&env, species.name()) +) -> WasmResult> { + let species = get_value_arc!(species, env); + wasm_ok(ExternRef::func_new(&env, species.name().clone().into())) } fn species_get_id( env: FunctionEnvMut, species: ExternRef, -) -> u16 { - species.value_func_arc(&env).unwrap().id() +) -> WasmResult { + let species = get_value_arc!(species, env); + wasm_ok(species.id()) } fn species_get_form_by_hash( env: FunctionEnvMut, species: ExternRef, form_hash: u32 -) -> ExternRef { - let species = species.value_func_arc(&env).unwrap(); - let form = species.get_form_by_hash(form_hash); - if let Some(form) = form { - ExternRef::func_new(&env, &form) - } else { - ExternRef::null() - } +) -> WasmResult> { + let species = get_value_arc!(species, env); + let form = species.get_form_by_hash(form_hash); + wasm_ok(if let Some(form) = form { + ExternRef::func_new(&env, (&form).into()) + } else { + ExternRef::null() + }) } fn species_has_flag_by_hash( env: FunctionEnvMut, species: ExternRef, flag_hash: u32 -) -> u8 { - if species.value_func_arc(&env).unwrap().has_flag_by_hash(flag_hash) { 1 } else { 0 } +) -> WasmResult { + let species = get_value_arc!(species, env); + wasm_ok(if species.has_flag_by_hash(flag_hash) { 1 } else { 0 }) } diff --git a/src/script_implementations/wasm/export_registry/static_data/types.rs b/src/script_implementations/wasm/export_registry/static_data/types.rs index 7e0cc9d..9323a6d 100644 --- a/src/script_implementations/wasm/export_registry/static_data/types.rs +++ b/src/script_implementations/wasm/export_registry/static_data/types.rs @@ -1,4 +1,7 @@ use crate::script_implementations::wasm::export_registry::register; +use crate::script_implementations::wasm::export_registry::wasm_result::{ + get_value, get_value_arc, try_wasm, wasm_ok, WasmResult, +}; use crate::script_implementations::wasm::export_registry::FunctionEnvMut; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv; @@ -11,15 +14,15 @@ register! { env: FunctionEnvMut, lib: ExternRef, name: ExternRef - ) -> u8 { - let lib = lib.value_func_arc(&env).unwrap(); - let name = name.value_func(&env).unwrap(); - let type_id = lib.get_type_id(name); - if let Some(type_id) = type_id { + ) -> WasmResult { + let lib = get_value_arc!(lib, env); + let name = get_value!(name, env); + let type_id = lib.get_type_id(&name); + wasm_ok(if let Some(type_id) = type_id { type_id.into() } else { 0 - } + }) } fn type_library_get_single_effectiveness( @@ -27,9 +30,10 @@ register! { lib: ExternRef, attacking: u8, defending: u8 - ) -> f32 { - let lib = lib.value_func_arc(&env).unwrap(); - lib.get_single_effectiveness(attacking.into(), defending.into()).unwrap() + ) -> WasmResult { + let lib = get_value_arc!(lib, env); + let effectiveness = try_wasm!(lib.get_single_effectiveness(attacking.into(), defending.into()), env); + wasm_ok(effectiveness) } } diff --git a/src/script_implementations/wasm/export_registry/wasm_object.rs b/src/script_implementations/wasm/export_registry/wasm_object.rs index 8b13789..f098f5a 100644 --- a/src/script_implementations/wasm/export_registry/wasm_object.rs +++ b/src/script_implementations/wasm/export_registry/wasm_object.rs @@ -1 +1,449 @@ +use crate::dynamic_data::{Battle, Pokemon, WeakBattleReference, WeakBattleSideReference, WeakPokemonReference}; +use anyhow::anyhow; +use anyhow_ext::Result; +use std::hash::{Hash, Hasher}; +use std::sync::{Arc, Weak}; +#[derive(Clone)] +#[allow(clippy::missing_docs_in_private_items)] +pub(crate) enum WasmObject { + // Static data + StringKey(crate::StringKey), + EffectParameter(Weak), + + MoveData(Weak), + Species(Weak), + Form(Weak), + Item(Weak), + Ability(Weak), + Nature(Weak), + + StaticStatisticSetU16(Weak>), + StatisticSetU32(Weak>), + StatChangeStatisticSet(Weak>), + EVStatisticSet(Weak>), + IVStatisticSet(Weak>), + + // Static data libraries + MoveLibrary(Weak), + SpeciesLibrary(Weak), + ItemLibrary(Weak), + TypeLibrary(Weak), + LibrarySettings(Weak), + AbilityLibrary(Weak), + StaticData(Weak), + + // Dynamic data + Pokemon(WeakPokemonReference), + PokemonParty(Weak), + LearnedMove(Weak), + + // Dynamic data libraries + DynamicLibrary(Weak), + + // Battle data + Battle(WeakBattleReference), + ChoiceQueue(Weak), + BattleRandom(Weak), + BattleSide(WeakBattleSideReference), + BattleParty(Weak), + TurnChoice(Weak), + ExecutingMove(Weak), + HitData(Weak), +} + +/// Trait for converting from a [`WasmObject`] to a Rust object. +pub(crate) trait FromWasmObj +where + Self: Sized, +{ + /// Converts from a [`WasmObject`] to a Rust object. + fn from_wasm_obj(obj: WasmObject) -> Result; +} + +impl PartialEq for WasmObject { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (WasmObject::StringKey(s1), WasmObject::StringKey(s2)) => s1 == s2, + (WasmObject::EffectParameter(s1), WasmObject::EffectParameter(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::MoveData(s1), WasmObject::MoveData(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Species(s1), WasmObject::Species(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Form(s1), WasmObject::Form(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Item(s1), WasmObject::Item(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Ability(s1), WasmObject::Ability(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Nature(s1), WasmObject::Nature(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::StaticStatisticSetU16(s1), WasmObject::StaticStatisticSetU16(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::StatisticSetU32(s1), WasmObject::StatisticSetU32(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::StatChangeStatisticSet(s1), WasmObject::StatChangeStatisticSet(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::EVStatisticSet(s1), WasmObject::EVStatisticSet(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::IVStatisticSet(s1), WasmObject::IVStatisticSet(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::MoveLibrary(s1), WasmObject::MoveLibrary(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::SpeciesLibrary(s1), WasmObject::SpeciesLibrary(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::ItemLibrary(s1), WasmObject::ItemLibrary(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::TypeLibrary(s1), WasmObject::TypeLibrary(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::LibrarySettings(s1), WasmObject::LibrarySettings(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::AbilityLibrary(s1), WasmObject::AbilityLibrary(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::StaticData(s1), WasmObject::StaticData(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Pokemon(s1), WasmObject::Pokemon(s2)) => WeakPokemonReference::eq(s1, s2), + (WasmObject::PokemonParty(s1), WasmObject::PokemonParty(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::LearnedMove(s1), WasmObject::LearnedMove(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::DynamicLibrary(s1), WasmObject::DynamicLibrary(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::Battle(s1), WasmObject::Battle(s2)) => WeakBattleReference::eq(s1, s2), + (WasmObject::ChoiceQueue(s1), WasmObject::ChoiceQueue(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::BattleRandom(s1), WasmObject::BattleRandom(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::BattleSide(s1), WasmObject::BattleSide(s2)) => WeakBattleSideReference::eq(s1, s2), + (WasmObject::BattleParty(s1), WasmObject::BattleParty(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::TurnChoice(s1), WasmObject::TurnChoice(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::ExecutingMove(s1), WasmObject::ExecutingMove(s2)) => Weak::ptr_eq(s1, s2), + (WasmObject::HitData(s1), WasmObject::HitData(s2)) => Weak::ptr_eq(s1, s2), + + _ => false, + } + } +} + +impl Eq for WasmObject {} + +impl Hash for WasmObject { + fn hash(&self, state: &mut H) { + match self { + WasmObject::StringKey(s) => state.write_u32(s.hash()), + WasmObject::EffectParameter(m) => m.as_ptr().hash(state), + WasmObject::MoveData(m) => m.as_ptr().hash(state), + WasmObject::Species(m) => m.as_ptr().hash(state), + WasmObject::Form(m) => m.as_ptr().hash(state), + WasmObject::Item(m) => m.as_ptr().hash(state), + WasmObject::Ability(m) => m.as_ptr().hash(state), + WasmObject::Nature(m) => m.as_ptr().hash(state), + WasmObject::StaticStatisticSetU16(m) => m.as_ptr().hash(state), + WasmObject::StatisticSetU32(m) => m.as_ptr().hash(state), + WasmObject::StatChangeStatisticSet(m) => m.as_ptr().hash(state), + WasmObject::EVStatisticSet(m) => m.as_ptr().hash(state), + WasmObject::IVStatisticSet(m) => m.as_ptr().hash(state), + WasmObject::MoveLibrary(m) => m.as_ptr().hash(state), + WasmObject::SpeciesLibrary(m) => m.as_ptr().hash(state), + WasmObject::ItemLibrary(m) => m.as_ptr().hash(state), + WasmObject::TypeLibrary(m) => m.as_ptr().hash(state), + WasmObject::LibrarySettings(m) => m.as_ptr().hash(state), + WasmObject::AbilityLibrary(m) => m.as_ptr().hash(state), + WasmObject::StaticData(m) => m.as_ptr().hash(state), + WasmObject::Pokemon(m) => m.as_ptr().hash(state), + WasmObject::PokemonParty(m) => m.as_ptr().hash(state), + WasmObject::LearnedMove(m) => m.as_ptr().hash(state), + WasmObject::DynamicLibrary(m) => m.as_ptr().hash(state), + WasmObject::Battle(m) => m.as_ptr().hash(state), + WasmObject::ChoiceQueue(m) => m.as_ptr().hash(state), + WasmObject::BattleRandom(m) => m.as_ptr().hash(state), + WasmObject::BattleSide(m) => m.as_ptr().hash(state), + WasmObject::BattleParty(m) => m.as_ptr().hash(state), + WasmObject::TurnChoice(m) => m.as_ptr().hash(state), + WasmObject::ExecutingMove(m) => m.as_ptr().hash(state), + WasmObject::HitData(m) => m.as_ptr().hash(state), + }; + } +} + +/// Macro to convert a `WasmObject` into a `Result` of the specified type. +macro_rules! get_from_wasm_obj { + ($variant:ident, $obj:expr) => { + match $obj { + WasmObject::$variant(b) => b.upgrade().ok_or(anyhow!("$variant was dropped")), + _ => Err(anyhow!("Expected $variant")), + } + }; +} + +/// Macro to implement `FromWasmObj` for a type. +macro_rules! impl_from_wasm_obj { + ($variant:ident, $ty:ty) => { + impl FromWasmObj for $ty { + fn from_wasm_obj(obj: WasmObject) -> Result { + get_from_wasm_obj!($variant, obj) + } + } + }; +} + +impl From for WasmObject { + fn from(value: crate::StringKey) -> Self { + Self::StringKey(value) + } +} + +impl FromWasmObj for crate::StringKey { + fn from_wasm_obj(obj: WasmObject) -> Result { + match obj { + WasmObject::StringKey(b) => Ok(b), + _ => Err(anyhow!("Expected StringKey")), + } + } +} + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::EffectParameter(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(EffectParameter, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::MoveData(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(MoveData, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::Species(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(Species, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::Form(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(Form, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::Item(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(Item, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::Ability(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(Ability, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::Nature(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(Nature, Arc); + +impl From<&Arc>> for WasmObject { + fn from(value: &Arc>) -> Self { + Self::StaticStatisticSetU16(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(StaticStatisticSetU16, Arc>); + +impl From<&Arc>> for WasmObject { + fn from(value: &Arc>) -> Self { + Self::StatisticSetU32(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(StatisticSetU32, Arc>); + +impl From<&Arc>> for WasmObject { + fn from(value: &Arc>) -> Self { + Self::StatChangeStatisticSet(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!( + StatChangeStatisticSet, + Arc> +); + +impl From<&Arc>> for WasmObject { + fn from(value: &Arc>) -> Self { + Self::EVStatisticSet(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(EVStatisticSet, Arc>); + +impl From<&Arc>> for WasmObject { + fn from(value: &Arc>) -> Self { + Self::IVStatisticSet(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(IVStatisticSet, Arc>); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::MoveLibrary(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(MoveLibrary, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::SpeciesLibrary(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(SpeciesLibrary, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::ItemLibrary(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(ItemLibrary, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::TypeLibrary(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(TypeLibrary, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::LibrarySettings(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(LibrarySettings, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::AbilityLibrary(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(AbilityLibrary, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::StaticData(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(StaticData, Arc); + +impl From<&Pokemon> for WasmObject { + fn from(value: &Pokemon) -> Self { + Self::Pokemon(value.weak()) + } +} + +impl From<&WeakPokemonReference> for WasmObject { + fn from(value: &WeakPokemonReference) -> Self { + Self::Pokemon(value.clone()) + } +} + +impl_from_wasm_obj!(Pokemon, Pokemon); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::PokemonParty(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(PokemonParty, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::LearnedMove(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(LearnedMove, Arc); + +impl From<&Battle> for WasmObject { + fn from(value: &Battle) -> Self { + Self::Battle(value.weak()) + } +} + +impl From<&WeakBattleReference> for WasmObject { + fn from(value: &WeakBattleReference) -> Self { + Self::Battle(value.clone()) + } +} + +impl_from_wasm_obj!(Battle, crate::dynamic_data::Battle); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::ChoiceQueue(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(ChoiceQueue, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::DynamicLibrary(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(DynamicLibrary, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::BattleRandom(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(BattleRandom, Arc); + +impl From<&crate::dynamic_data::BattleSide> for WasmObject { + fn from(value: &crate::dynamic_data::BattleSide) -> Self { + Self::BattleSide(value.weak()) + } +} + +impl From<&WeakBattleSideReference> for WasmObject { + fn from(value: &WeakBattleSideReference) -> Self { + Self::BattleSide(value.clone()) + } +} + +impl_from_wasm_obj!(BattleSide, crate::dynamic_data::BattleSide); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::BattleParty(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(BattleParty, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::TurnChoice(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(TurnChoice, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::ExecutingMove(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(ExecutingMove, Arc); + +impl From<&Arc> for WasmObject { + fn from(value: &Arc) -> Self { + Self::HitData(Arc::downgrade(value)) + } +} + +impl_from_wasm_obj!(HitData, Arc); diff --git a/src/script_implementations/wasm/export_registry/wasm_result.rs b/src/script_implementations/wasm/export_registry/wasm_result.rs index d028244..3b30c21 100644 --- a/src/script_implementations/wasm/export_registry/wasm_result.rs +++ b/src/script_implementations/wasm/export_registry/wasm_result.rs @@ -10,14 +10,18 @@ pub type WasmResult = (u32, T); /// A result type that can be given to, or returned from WASM, but does not contain a value. pub type WasmVoidResult = u32; +/// An extension trait for `WasmResult` that provides some convenience methods. pub(crate) trait WasmVoidResultExtension { - fn into_result(self, env: FunctionEnvMut) -> anyhow_ext::Result<()>; - fn into_result_env(self, env: &Arc) -> anyhow_ext::Result<()>; - fn from_result(res: anyhow_ext::Result<()>, env: &FunctionEnvMut) -> Self; + /// Returns a `WasmVoidResult` that indicates success. fn ok() -> Self; + /// Returns a `WasmVoidResult` that indicates failure. fn err(err: anyhow::Error, env: &FunctionEnvMut) -> Self; + /// Converts a `WasmVoidResult` into a `Result<(), anyhow::Error>`. Used specifically for script + /// function calls. + fn into_result_env(self, env: &Arc) -> anyhow::Result<()>; } +/// Returns a success `WasmResult` with the given value. pub(super) fn wasm_ok(value: T) -> WasmResult where T: FromToNativeWasmType, @@ -26,6 +30,8 @@ where (0, value) } +/// Returns a failure `WasmResult` with the given error. +#[allow(clippy::unwrap_used)] pub(super) fn wasm_err(err: Error, env: &FunctionEnvMut) -> WasmResult where T: FromToNativeWasmType + Default, @@ -36,50 +42,38 @@ where } impl WasmVoidResultExtension for WasmVoidResult { - fn into_result(self, env: FunctionEnvMut) -> anyhow::Result<()> { - Self::into_result_env(self, &env.data().data()) + fn ok() -> Self { + 0 } + #[allow(clippy::unwrap_used)] + fn err(err: Error, env: &FunctionEnvMut) -> Self { + let s = CString::new(err.to_string()).unwrap(); + let ptr = env.data().data().copy_value_vec_to_wasm(s.as_bytes()).unwrap(); + ptr + } + + #[allow(clippy::unwrap_used)] fn into_result_env(self, env: &Arc) -> anyhow::Result<()> { if self == 0 { Ok(()) } else { unsafe { let ptr = self; - let mem: *mut c_char = env.get_raw_pointer(ptr as u32); + let mem: *mut c_char = env.get_raw_pointer(ptr); let string = std::ffi::CStr::from_ptr(mem); let e = anyhow_ext::anyhow!("{}", string.to_str().unwrap()); - env.script_function_cache().dealloc_cstring(&env, ptr as u32).unwrap(); + env.script_function_cache().dealloc_cstring(env, ptr).unwrap(); Err(e) } } } - - fn from_result(res: anyhow::Result<()>, env: &FunctionEnvMut) -> Self { - match res { - Ok(_) => 0, - Err(e) => { - let s = CString::new(e.to_string()).unwrap(); - let ptr = env.data().data().copy_value_vec_to_wasm(s.as_bytes()).unwrap(); - ptr as u32 - } - } - } - - fn ok() -> Self { - 0 - } - - fn err(err: Error, env: &FunctionEnvMut) -> Self { - let s = CString::new(err.to_string()).unwrap(); - let ptr = env.data().data().copy_value_vec_to_wasm(s.as_bytes()).unwrap(); - ptr as u32 - } } +/// Macro to try an expression, and return a `WasmResult` if it fails. macro_rules! try_wasm { ($e:expr, $env:expr) => { - match $e.with_context(|| format!("WASM function {}", stdext::function_name!())) { + match $e { Ok(v) => v, Err(e) => { return crate::script_implementations::wasm::export_registry::wasm_err(e.into(), &$env); @@ -88,12 +82,13 @@ macro_rules! try_wasm { }; } +/// Macro to try an expression, and return a `WasmVoidResult` if it fails. macro_rules! try_wasm_void { ($e:expr, $env:expr) => { - match $e.with_context(|| format!("WASM function {}", stdext::function_name!())) { + match $e { Ok(v) => v, Err(e) => { - return WasmVoidResult::from_result(Err(e.into()), &$env); + return WasmVoidResult::err(e.into(), &$env); } } }; @@ -102,24 +97,28 @@ macro_rules! try_wasm_void { pub(super) use try_wasm; pub(super) use try_wasm_void; +/// Resolve an externref to a value. Returns an error if this fails. macro_rules! get_value { ($e:expr, $env:expr) => { crate::script_implementations::wasm::export_registry::try_wasm!($e.value_func(&$env), $env) }; } +/// Resolve an externref of an Arc to a value. Returns an error if this fails. macro_rules! get_value_arc { ($e:expr, $env:expr) => { crate::script_implementations::wasm::export_registry::try_wasm!($e.value_func_arc(&$env), $env) }; } +/// Resolve an externref to a value. Returns an error if this fails. macro_rules! get_value_void { ($e:expr, $env:expr) => { crate::script_implementations::wasm::export_registry::try_wasm_void!($e.value_func(&$env), $env) }; } +/// Resolve an externref of an Arc to a value. Returns an error if this fails. macro_rules! get_value_arc_void { ($e:expr, $env:expr) => { crate::script_implementations::wasm::export_registry::try_wasm_void!($e.value_func_arc(&$env), $env) @@ -131,6 +130,7 @@ pub(super) use get_value_arc; pub(super) use get_value_arc_void; pub(super) use get_value_void; +/// Resolve an externref to a value, and call a getter on it. Returns an error if this fails. macro_rules! get_value_call_getter { ($e:ident.$func:ident(), $env:expr) => {{ let _value = crate::script_implementations::wasm::export_registry::try_wasm!($e.value_func(&$env), $env); diff --git a/src/script_implementations/wasm/extern_ref.rs b/src/script_implementations/wasm/extern_ref.rs index 6b23e0b..503b7fe 100755 --- a/src/script_implementations/wasm/extern_ref.rs +++ b/src/script_implementations/wasm/extern_ref.rs @@ -1,10 +1,10 @@ -use crate::{PkmnError, ValueIdentifiable}; +use crate::ValueIdentifiable; use anyhow_ext::Result; -use std::any::Any; use std::marker::PhantomData; use std::mem::transmute; use std::sync::Arc; +use crate::script_implementations::wasm::export_registry::{FromWasmObj, WasmObject}; use crate::script_implementations::wasm::script_resolver::{ WebAssemblyEnv, WebAssemblyEnvironmentData, WebAssemblyScriptResolver, }; @@ -44,26 +44,26 @@ impl Default for ExternRef { impl ExternRef { /// Instantiates a new ExternRef for a bit of data. If we already have made an Extern Ref for /// this data and type, we use that instead. - pub fn new(env: &WebAssemblyEnvironmentData, value: &dyn Any) -> Self { + pub fn new(env: &WebAssemblyEnvironmentData, value: WasmObject) -> Self { Self { - index: env.get_extern_ref_index::(value), + index: env.get_extern_ref_index(value), _phantom: Default::default(), } } /// Instantiates a new ExternRef for a bit of data using the function environment. If we already /// have made an Extern Ref for this data and type, we use that instead. - pub fn func_new(env: &FunctionEnvMut, value: &dyn Any) -> Self { + pub fn func_new(env: &FunctionEnvMut, value: WasmObject) -> Self { Self { - index: env.data().data().get_extern_ref_index::(value), + index: env.data().data().get_extern_ref_index(value), _phantom: Default::default(), } } /// Creates an ExternRef with a given resolver. This can be used in cases where we do not have an environment variable. - pub(crate) fn new_with_resolver(resolver: &WebAssemblyScriptResolver, value: &dyn Any) -> Self { + pub(crate) fn new_with_resolver(resolver: &WebAssemblyScriptResolver, value: WasmObject) -> Self { Self { - index: resolver.environment_data().get_extern_ref_index::(value), + index: resolver.environment_data().get_extern_ref_index(value), _phantom: Default::default(), } } @@ -78,62 +78,46 @@ impl ExternRef { /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the /// value when it was passed before. If these types do not match, this will panic. - pub fn value_func<'a>(&self, env: &'a FunctionEnvMut) -> Result<&'a T> + pub fn value_func(&self, env: &FunctionEnvMut) -> Result where - T: Sized + 'static, + T: FromWasmObj, { - self.value(&env.data().data())?.ok_or(PkmnError::NullReference.into()) + self.value(&env.data().data()) } /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the /// value when it was passed before. If these types do not match, this will panic. pub fn value_func_arc(&self, env: &FunctionEnvMut) -> Result> where - T: 'static, + Arc: FromWasmObj, { - self.value_arc(&env.data().data())? - .ok_or(PkmnError::NullReference.into()) + self.value_arc(&env.data().data()) } /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the /// value when it was passed before. If these types do not match, this will panic. - pub fn value_func_box(&self, env: &FunctionEnvMut) -> Result<&Box> + pub fn value(&self, env: &Arc) -> Result where - T: 'static, + T: FromWasmObj, { - self.value_box(&env.data().data()) + let value = env.get_extern_ref_value::(self.index)?; + let o = FromWasmObj::from_wasm_obj(value)?; + Ok(o) } /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the /// value when it was passed before. If these types do not match, this will panic. - pub fn value<'a>(&self, env: &Arc) -> Result> + pub fn value_arc(&self, env: &Arc) -> Result> where - T: Sized + 'static, + Arc: FromWasmObj, { - Ok(env.get_extern_ref_value::(self.index)?.downcast_ref::()) + let wasm_obj = env.get_extern_ref_value::(self.index)?; + FromWasmObj::from_wasm_obj(wasm_obj) } - /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the - /// value when it was passed before. If these types do not match, this will panic. - pub fn value_arc(&self, env: &Arc) -> Result>> - where - T: 'static, - { - Ok(env - .get_extern_ref_value::(self.index)? - .downcast_ref::>() - .cloned()) - } - - /// Returns the real value for a given ExternRef. Note that the requested type must be the same as the type of the - /// value when it was passed before. If these types do not match, this will panic. - pub fn value_box(&self, env: &Arc) -> Result<&Box> - where - T: 'static, - { - env.get_extern_ref_value::(self.index)? - .downcast_ref::>() - .ok_or(PkmnError::NullReference.into()) + /// Returns the internal index for this ExternRef. + pub(crate) fn index(&self) -> usize { + self.index } } @@ -185,16 +169,16 @@ impl Default for VecExternRef { } } -impl VecExternRef { - /// Instantiates a new VecExternRef for a given slice. - pub fn new(env: &WebAssemblyEnvironmentData, value: &Vec) -> Self { - Self { - index: env.get_extern_vec_ref_index(value), - size: value.len() as u32, - _phantom: Default::default(), - } - } -} +// impl VecExternRef { +// /// Instantiates a new VecExternRef for a given slice. +// pub fn new(env: &WebAssemblyEnvironmentData, value: &Vec) -> Self { +// Self { +// index: env.get_extern_vec_ref_index(value), +// size: value.len() as u32, +// _phantom: Default::default(), +// } +// } +// } unsafe impl FromToNativeWasmType for VecExternRef { type Native = i64; diff --git a/src/script_implementations/wasm/script.rs b/src/script_implementations/wasm/script.rs index 2799b38..4848750 100755 --- a/src/script_implementations/wasm/script.rs +++ b/src/script_implementations/wasm/script.rs @@ -1,4 +1,4 @@ -use anyhow_ext::{anyhow, Result}; +use anyhow_ext::Result; use std::any::Any; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::Arc; @@ -9,7 +9,7 @@ use crate::dynamic_data::{ Battle, DamageSource, DynamicLibrary, ExecutingMove, Pokemon, Script, ScriptOwnerData, TurnChoice, }; use crate::script_implementations::wasm::export_registry::WasmVoidResultExtension; -use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; +use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData; use crate::script_implementations::wasm::WebAssemblyScriptCapabilities; use crate::static_data::{EffectParameter, Item, Statistic, TypeIdentifier}; @@ -86,14 +86,7 @@ macro_rules! call_func { /// Util macro to reduce extern ref instantiation verbosity. macro_rules! ex_ref { ($env:ident, $value:expr) => { - ExternRef::new($env.as_ref(), $value) - }; -} - -/// Util macro to reduce vec extern ref instantiation verbosity. -macro_rules! vec_ex_ref { - ($env:ident, $value:expr) => { - VecExternRef::new($env.as_ref(), $value) + ExternRef::new($env.as_ref(), $value.into()) }; } @@ -132,19 +125,25 @@ impl Script for WebAssemblyScript { Ok(()) } - fn on_initialize(&self, library: &Arc, pars: Vec) -> Result<()> { + fn on_initialize(&self, library: &Arc, pars: Vec>) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::Initialize) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().on_initialize(env) { - call_func!(func, env, self, ex_ref!(env, library), vec_ex_ref!(env, &pars)); + let pars = pars + .into_iter() + .map(|p| ExternRef::::new(env, (&p).into()).index() as u32) + .collect::>(); + let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?; + let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) }; + call_func!(func, env, self, ex_ref!(env, library), r); } Ok(()) } - fn on_before_turn(&self, choice: &TurnChoice) -> Result<()> { + fn on_before_turn(&self, choice: &Arc) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeTurn) { return Ok(()); } @@ -155,7 +154,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_speed(&self, choice: &TurnChoice, speed: &mut u32) -> Result<()> { + fn change_speed(&self, choice: &Arc, speed: &mut u32) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeSpeed) { return Ok(()); } @@ -169,7 +168,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_priority(&self, choice: &TurnChoice, priority: &mut i8) -> Result<()> { + fn change_priority(&self, choice: &Arc, priority: &mut i8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangePriority) { return Ok(()); } @@ -183,26 +182,22 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_move(&self, choice: &TurnChoice, move_name: &mut StringKey) -> Result<()> { + fn change_move(&self, choice: &Arc, move_name: &mut StringKey) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeMove) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().change_move(env) { - let move_ref = ex_ref!(env, move_name); + let move_ref = ex_ref!(env, move_name.clone()); let ptr = env.allocate_temp::>(move_ref); call_func!(func, env, self, ex_ref!(env, choice), ptr.wasm_ptr); - *move_name = ptr - .value() - .value(env)? - .ok_or(anyhow!("Unable to get move name"))? - .clone(); + *move_name = ptr.value().value(env)?; } Ok(()) } - fn change_number_of_hits(&self, choice: &TurnChoice, number_of_hits: &mut u8) -> Result<()> { + fn change_number_of_hits(&self, choice: &Arc, number_of_hits: &mut u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeNumberOfHits) { return Ok(()); } @@ -216,7 +211,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn prevent_move(&self, mv: &ExecutingMove, prevent: &mut bool) -> Result<()> { + fn prevent_move(&self, mv: &Arc, prevent: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventMove) { return Ok(()); } @@ -230,7 +225,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn fail_move(&self, mv: &ExecutingMove, fail: &mut bool) -> Result<()> { + fn fail_move(&self, mv: &Arc, fail: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::FailMove) { return Ok(()); } @@ -244,7 +239,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn stop_before_move(&self, mv: &ExecutingMove, stop: &mut bool) -> Result<()> { + fn stop_before_move(&self, mv: &Arc, stop: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::StopBeforeMove) { return Ok(()); } @@ -258,7 +253,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn on_before_move(&self, mv: &ExecutingMove) -> Result<()> { + fn on_before_move(&self, mv: &Arc) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnBeforeMove) { return Ok(()); } @@ -269,61 +264,47 @@ impl Script for WebAssemblyScript { Ok(()) } - fn fail_incoming_move(&self, mv: &ExecutingMove, target: &Arc, fail: &mut bool) -> Result<()> { + fn fail_incoming_move(&self, mv: &Arc, target: &Pokemon, fail: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::FailIncomingMove) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().fail_incoming_move(env) { let ptr = env.allocate_temp::(*fail); - call_func!( - func, - env, - self, - ex_ref!(env, mv), - ex_ref!(env, target.as_ref()), - ptr.wasm_ptr - ); + call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), ptr.wasm_ptr); *fail = *ptr.value(); } Ok(()) } - fn is_invulnerable(&self, mv: &ExecutingMove, target: &Arc, invulnerable: &mut bool) -> Result<()> { + fn is_invulnerable(&self, mv: &Arc, target: &Pokemon, invulnerable: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::IsInvulnerable) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().is_invulnerable(env) { let ptr = env.allocate_temp::(*invulnerable); - call_func!( - func, - env, - self, - ex_ref!(env, mv), - ex_ref!(env, target.as_ref()), - ptr.wasm_ptr - ); + call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), ptr.wasm_ptr); *invulnerable = *ptr.value(); } Ok(()) } - fn on_move_miss(&self, mv: &ExecutingMove, target: &Arc) -> Result<()> { + fn on_move_miss(&self, mv: &Arc, target: &Pokemon) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnMoveMiss) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().on_move_miss(env) { - call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target.as_ref())); + call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target)); } Ok(()) } fn change_move_type( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, move_type: &mut TypeIdentifier, ) -> Result<()> { @@ -333,7 +314,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_move_type(env) { let ptr = env.allocate_temp::(*move_type); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *move_type = *ptr.value(); @@ -343,8 +324,8 @@ impl Script for WebAssemblyScript { fn change_effectiveness( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, effectiveness: &mut f32, ) -> Result<()> { @@ -354,7 +335,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_effectiveness(env) { let ptr = env.allocate_temp(*effectiveness); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *effectiveness = *ptr.value(); @@ -364,8 +345,8 @@ impl Script for WebAssemblyScript { fn block_critical( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, block_critical: &mut bool, ) -> Result<()> { @@ -375,7 +356,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().block_critical(env) { let ptr = env.allocate_temp(*block_critical); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *block_critical = *ptr.value(); @@ -385,8 +366,8 @@ impl Script for WebAssemblyScript { fn block_incoming_critical( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, block_critical: &mut bool, ) -> Result<()> { @@ -396,7 +377,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().block_incoming_critical(env) { let ptr = env.allocate_temp(*block_critical); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *block_critical = *ptr.value(); @@ -404,14 +385,14 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_accuracy(&self, mv: &ExecutingMove, target: &Arc, hit: u8, accuracy: &mut u8) -> Result<()> { + fn change_accuracy(&self, mv: &Arc, target: &Pokemon, hit: u8, accuracy: &mut u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeAccuracy) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().change_accuracy(env) { let ptr = env.allocate_temp(*accuracy); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *accuracy = *ptr.value(); @@ -419,14 +400,14 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_critical_stage(&self, mv: &ExecutingMove, target: &Arc, hit: u8, stage: &mut u8) -> Result<()> { + fn change_critical_stage(&self, mv: &Arc, target: &Pokemon, hit: u8, stage: &mut u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCriticalStage) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().change_critical_stage(env) { let ptr = env.allocate_temp(*stage); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *stage = *ptr.value(); @@ -436,8 +417,8 @@ impl Script for WebAssemblyScript { fn change_critical_modifier( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, modifier: &mut f32, ) -> Result<()> { @@ -447,7 +428,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_critical_modifier(env) { let ptr = env.allocate_temp(*modifier); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *modifier = *ptr.value(); @@ -457,8 +438,8 @@ impl Script for WebAssemblyScript { fn change_stab_modifier( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, modifier: &mut f32, ) -> Result<()> { @@ -468,7 +449,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_stab_modifier(env) { let ptr = env.allocate_temp(*modifier); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *modifier = *ptr.value(); @@ -476,14 +457,14 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_base_power(&self, mv: &ExecutingMove, target: &Arc, hit: u8, base_power: &mut u8) -> Result<()> { + fn change_base_power(&self, mv: &Arc, target: &Pokemon, hit: u8, base_power: &mut u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeBasePower) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().change_base_power(env) { let ptr = env.allocate_temp(*base_power); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *base_power = *ptr.value(); @@ -493,8 +474,8 @@ impl Script for WebAssemblyScript { fn bypass_defensive_stat_boost( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, bypass: &mut bool, ) -> Result<()> { @@ -504,7 +485,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().bypass_defensive_stat_boost(env) { let ptr = env.allocate_temp(*bypass); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *bypass = *ptr.value(); @@ -514,8 +495,8 @@ impl Script for WebAssemblyScript { fn bypass_offensive_stat_boost( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, bypass: &mut bool, ) -> Result<()> { @@ -525,7 +506,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().bypass_offensive_stat_boost(env) { let ptr = env.allocate_temp(*bypass); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *bypass = *ptr.value(); @@ -535,8 +516,8 @@ impl Script for WebAssemblyScript { fn change_offensive_stat_value( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, amount: &mut u32, ) -> Result<()> { @@ -546,7 +527,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_offensive_stat_value(env) { let ptr = env.allocate_temp(*amount); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *amount = *ptr.value(); @@ -556,8 +537,8 @@ impl Script for WebAssemblyScript { fn change_defensive_stat_value( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, amount: &mut u32, ) -> Result<()> { @@ -567,7 +548,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_defensive_stat_value(env) { let ptr = env.allocate_temp(*amount); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *amount = *ptr.value(); @@ -577,8 +558,8 @@ impl Script for WebAssemblyScript { fn change_damage_stat_modifier( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, modifier: &mut f32, ) -> Result<()> { @@ -588,7 +569,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_damage_stat_modifier(env) { let ptr = env.allocate_temp(*modifier); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *modifier = *ptr.value(); @@ -598,8 +579,8 @@ impl Script for WebAssemblyScript { fn change_damage_modifier( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, modifier: &mut f32, ) -> Result<()> { @@ -609,7 +590,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_damage_modifier(env) { let ptr = env.allocate_temp(*modifier); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *modifier = *ptr.value(); @@ -617,14 +598,14 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_damage(&self, mv: &ExecutingMove, target: &Arc, hit: u8, damage: &mut u32) -> Result<()> { + fn change_damage(&self, mv: &Arc, target: &Pokemon, hit: u8, damage: &mut u32) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeDamage) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().change_damage(env) { let ptr = env.allocate_temp(*damage); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *damage = *ptr.value(); @@ -634,8 +615,8 @@ impl Script for WebAssemblyScript { fn change_incoming_damage( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, damage: &mut u32, ) -> Result<()> { @@ -645,7 +626,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_incoming_damage(env) { let ptr = env.allocate_temp(*damage); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *damage = *ptr.value(); @@ -653,25 +634,25 @@ impl Script for WebAssemblyScript { Ok(()) } - fn on_incoming_hit(&self, mv: &ExecutingMove, target: &Arc, hit: u8) -> Result<()> { + fn on_incoming_hit(&self, mv: &Arc, target: &Pokemon, hit: u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnIncomingHit) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().on_incoming_hit(env) { - let target = target.as_ref(); + let target = target; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit); } Ok(()) } - fn on_opponent_faints(&self, mv: &ExecutingMove, target: &Arc, hit: u8) -> Result<()> { + fn on_opponent_faints(&self, mv: &Arc, target: &Pokemon, hit: u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().on_opponent_faints(env) { - let target = target.as_ref(); + let target = target; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit); } Ok(()) @@ -709,8 +690,8 @@ impl Script for WebAssemblyScript { fn prevent_secondary_effect( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, prevent: &mut bool, ) -> Result<()> { @@ -720,7 +701,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().prevent_secondary_effect(env) { let ptr = env.allocate_temp(*prevent); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *prevent = *ptr.value(); @@ -728,14 +709,14 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_effect_chance(&self, mv: &ExecutingMove, target: &Arc, hit: u8, chance: &mut f32) -> Result<()> { + fn change_effect_chance(&self, mv: &Arc, target: &Pokemon, hit: u8, chance: &mut f32) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeEffectChance) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().change_effect_chance(env) { let ptr = env.allocate_temp(*chance); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *chance = *ptr.value(); @@ -745,8 +726,8 @@ impl Script for WebAssemblyScript { fn change_incoming_effect_chance( &self, - mv: &ExecutingMove, - target: &Arc, + mv: &Arc, + target: &Pokemon, hit: u8, chance: &mut f32, ) -> Result<()> { @@ -756,7 +737,7 @@ impl Script for WebAssemblyScript { let env = &self.environment; if let Some(func) = env.script_function_cache().change_incoming_effect_chance(env) { let ptr = env.allocate_temp(*chance); - let target = target.as_ref(); + let target = target; let w_ptr = ptr.wasm_ptr; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit, w_ptr); *chance = *ptr.value(); @@ -764,31 +745,31 @@ impl Script for WebAssemblyScript { Ok(()) } - fn on_secondary_effect(&self, mv: &ExecutingMove, target: &Arc, hit: u8) -> Result<()> { + fn on_secondary_effect(&self, mv: &Arc, target: &Pokemon, hit: u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnFaintingOpponent) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().on_secondary_effect(env) { - let target = target.as_ref(); + let target = target; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target), hit); } Ok(()) } - fn on_after_hits(&self, mv: &ExecutingMove, target: &Arc) -> Result<()> { + fn on_after_hits(&self, mv: &Arc, target: &Pokemon) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHits) { return Ok(()); } let env = &self.environment; if let Some(func) = env.script_function_cache().on_after_hits(env) { - let target = target.as_ref(); + let target = target; call_func!(func, env, self, ex_ref!(env, mv), ex_ref!(env, target)); } Ok(()) } - fn prevent_self_switch(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> { + fn prevent_self_switch(&self, choice: &Arc, prevent: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) { return Ok(()); } @@ -801,7 +782,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn prevent_opponent_switch(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> { + fn prevent_opponent_switch(&self, choice: &Arc, prevent: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfSwitch) { return Ok(()); } @@ -836,7 +817,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn prevent_self_run_away(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> { + fn prevent_self_run_away(&self, choice: &Arc, prevent: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventSelfRunAway) { return Ok(()); } @@ -849,7 +830,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn prevent_opponent_run_away(&self, choice: &TurnChoice, prevent: &mut bool) -> Result<()> { + fn prevent_opponent_run_away(&self, choice: &Arc, prevent: &mut bool) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::PreventOpponentRunAway) { return Ok(()); } @@ -906,7 +887,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn on_after_held_item_consume(&self, pokemon: &Pokemon, item: &dyn Item) -> Result<()> { + fn on_after_held_item_consume(&self, pokemon: &Pokemon, item: &Arc) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::OnAfterHeldItemConsume) { return Ok(()); } @@ -960,7 +941,7 @@ impl Script for WebAssemblyScript { Ok(()) } - fn change_capture_rate_bonus(&self, target: &Pokemon, pokeball: &dyn Item, modifier: &mut u8) -> Result<()> { + fn change_capture_rate_bonus(&self, target: &Pokemon, pokeball: &Arc, modifier: &mut u8) -> Result<()> { if !self.has_capability(&WebAssemblyScriptCapabilities::ChangeCaptureRate) { return Ok(()); } diff --git a/src/script_implementations/wasm/script_function_cache.rs b/src/script_implementations/wasm/script_function_cache.rs index a932ad8..2bac161 100755 --- a/src/script_implementations/wasm/script_function_cache.rs +++ b/src/script_implementations/wasm/script_function_cache.rs @@ -8,9 +8,9 @@ use paste::paste; use crate::dynamic_data::{Battle, DynamicLibrary, ExecutingMove, Pokemon, TurnChoice}; use crate::script_implementations::wasm::export_registry::WasmVoidResult; -use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef}; +use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData; -use crate::static_data::{EffectParameter, Item, TypeIdentifier}; +use crate::static_data::{Item, TypeIdentifier}; use crate::StringKey; use wasmer::{FromToNativeWasmType, TypedFunction}; @@ -123,7 +123,7 @@ unsafe impl FromToNativeWasmType for WasmPtr { script_function_cache! { stack() on_remove() - on_initialize(ExternRef, VecExternRef) + on_initialize(ExternRef, u64) on_before_turn(ExternRef) change_speed(ExternRef, WasmPtr) change_priority(ExternRef, WasmPtr) diff --git a/src/script_implementations/wasm/script_resolver.rs b/src/script_implementations/wasm/script_resolver.rs index 468b20a..92f21a4 100755 --- a/src/script_implementations/wasm/script_resolver.rs +++ b/src/script_implementations/wasm/script_resolver.rs @@ -1,9 +1,8 @@ -use std::any::Any; use std::fmt::{Debug, Formatter}; use std::mem::{align_of, forget, size_of}; use std::sync::{Arc, Weak}; -use anyhow_ext::{anyhow, ensure, Context, Result}; +use anyhow_ext::{anyhow, Context, Result}; use hashbrown::{HashMap, HashSet}; use parking_lot::lock_api::RwLockReadGuard; use parking_lot::{RawRwLock, RwLock}; @@ -13,7 +12,7 @@ use wasmer::{ }; use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData, ScriptResolver}; -use crate::script_implementations::wasm::export_registry::register_webassembly_funcs; +use crate::script_implementations::wasm::export_registry::{register_webassembly_funcs, WasmObject}; use crate::script_implementations::wasm::extern_ref::ExternRef; use crate::script_implementations::wasm::script::WebAssemblyScript; use crate::script_implementations::wasm::script_function_cache::ScriptFunctionCache; @@ -192,7 +191,7 @@ impl ScriptResolver for WebAssemblyScriptResolver { .call( &mut self.store_mut(), category as u8, - ExternRef::new_with_resolver(self, script_key), + ExternRef::new_with_resolver(self, WasmObject::StringKey(script_key.clone())), )?; self.environment_data.setup_script(script, category, script_key, owner) } @@ -223,7 +222,7 @@ pub struct WebAssemblyEnvironmentData { /// we instead keep track of all the data we've sent to WASM, and pass the ID of that data to WASM. This allows us /// to only operate on data we know WASM owns. We currently store this data in this continuous Vec, and give the index /// of the data as the ID. - extern_ref_pointers: RwLock>, + extern_ref_pointers: RwLock>, /// To make sure we send the same identifier to WASM when we send the same piece of data multiple times, we have a /// backwards lookup on extern_ref_pointers. This allows us to get the index for a given piece of data. extern_ref_pointers_lookup: RwLock>, @@ -269,9 +268,7 @@ pub struct WebAssemblyEnvironmentData { #[derive(Clone, Eq, PartialEq, Hash)] struct ExternRefLookupKey { /// The raw pointer to the data - pub ptr: *const dyn Any, - /// Whether or not the reference is a Vec - pub is_vec: bool, + pub obj: WasmObject, } impl WebAssemblyEnvironmentData { @@ -387,8 +384,8 @@ impl WebAssemblyEnvironmentData { /// when extern refs get actually properly implemented at compile time we might want to get rid /// of this code. #[inline(always)] - pub fn get_extern_ref_index(&self, value: &dyn Any) -> usize { - self.get_extern_ref_from_identifier(value, false) + pub(crate) fn get_extern_ref_index(&self, value: WasmObject) -> usize { + self.get_extern_ref_from_identifier(value) } /// Get a numeric value from any given value. This is not a true Extern Ref from WASM, as this @@ -397,15 +394,15 @@ impl WebAssemblyEnvironmentData { /// access can be touched through this, and we ensure the value is the correct type. In the future, /// when extern refs get actually properly implemented at compile time we might want to get rid /// of this code. - pub fn get_extern_vec_ref_index(&self, value: &Vec) -> usize { - let mut vec = Vec::with_capacity(value.len()); - for v in value { - vec.push(self.get_extern_ref_index::(v)); - } - let p = self.get_extern_ref_from_identifier(value, true); - self.extern_vec_ref_lookup.write().insert(p, vec); - p - } + // pub fn get_extern_vec_ref_index(&self, value: &Vec) -> usize { + // let mut vec = Vec::with_capacity(value.len()); + // for v in value { + // vec.push(self.get_extern_ref_index(v)); + // } + // let p = self.get_extern_ref_from_identifier(value); + // self.extern_vec_ref_lookup.write().insert(p, vec); + // p + // } /// Get an extern ref belonging to a vector we have passed to WASM. pub fn get_extern_vec_ref_extern_ref(&self, extern_vec_ref: usize, index: usize) -> Result { @@ -417,44 +414,37 @@ impl WebAssemblyEnvironmentData { /// Gets the extern ref index belonging to a specific pointer. If none exists, this will create /// a new one. #[inline(always)] - fn get_extern_ref_from_identifier(&self, value: &dyn Any, is_vec: bool) -> usize { - if let Some(v) = self.extern_ref_pointers_lookup.read().get(&ExternRefLookupKey { - ptr: value as *const dyn Any, - is_vec, - }) { + fn get_extern_ref_from_identifier(&self, value: WasmObject) -> usize { + if let Some(v) = self + .extern_ref_pointers_lookup + .read() + .get(&ExternRefLookupKey { obj: value.clone() }) + { return *v; } let index = { let mut extern_ref_guard = self.extern_ref_pointers.write(); - extern_ref_guard.push(value as *const dyn Any); + extern_ref_guard.push(value.clone()); extern_ref_guard.len() }; - self.extern_ref_pointers_lookup.write().insert( - ExternRefLookupKey { - ptr: value as *const dyn Any, - is_vec, - }, - index, - ); - self.extern_ref_type_lookup.write().insert(ExternRefLookupKey { - ptr: value as *const dyn Any, - is_vec, - }); + self.extern_ref_pointers_lookup + .write() + .insert(ExternRefLookupKey { obj: value.clone() }, index); + self.extern_ref_type_lookup + .write() + .insert(ExternRefLookupKey { obj: value }); index } /// Gets a value from the extern ref lookup. This turns an earlier registered index back into /// its proper value, validates its type, and returns the value. - pub fn get_extern_ref_value<'a, T: ?Sized>(&self, index: usize) -> Result<&'a dyn Any> { + pub(crate) fn get_extern_ref_value(&self, index: usize) -> Result { let read_guard = self.extern_ref_pointers.read(); let ptr = read_guard.get_res(index - 1)?; if self .extern_ref_type_lookup .read() - .get(&ExternRefLookupKey { - ptr: *ptr, - is_vec: false, - }) + .get(&ExternRefLookupKey { obj: ptr.clone() }) .is_none() { #[allow(clippy::panic)] // Allow panic here, as this is a security error. @@ -466,17 +456,23 @@ impl WebAssemblyEnvironmentData { } } - unsafe { Ok(ptr.as_ref().unwrap()) } + Ok(ptr.clone()) } /// The WASM store. pub fn store_ref(&self) -> StoreRef<'_> { - unsafe { self.store.as_ref().unwrap().as_store_ref() } + #[allow(clippy::unwrap_used)] // This should never be None when used. + unsafe { + self.store.as_ref().unwrap().as_store_ref() + } } /// The mutable WASM store. pub fn store_mut(&self) -> StoreMut<'_> { - unsafe { self.store.as_mut().unwrap().as_store_mut() } + #[allow(clippy::unwrap_used)] // This should never be None when used. + unsafe { + self.store.as_mut().unwrap().as_store_mut() + } } /// Find a loaded script based on the pointer in WASM memory. @@ -514,12 +510,16 @@ impl WebAssemblyEnvironmentData { .get::(&"get_script_capabilities".into()) { let res = get_cap.call(&mut self.store_mut(), &[Value::I32(script_ptr as i32)])?; - let ptr = - (self.memory() as *const WebAssemblyScriptCapabilities).offset(res[0].i32().unwrap() as isize); - let length = res[1].i32(); - ensure!(length.is_some(), "Script capabilities length was not a valid i32"); - for i in 0..length.unwrap() as usize { - capabilities.insert(*ptr.add(i)); + let ptr = (self.memory() as *const WebAssemblyScriptCapabilities) + .offset(res.get_res(0)?.unwrap_i32() as isize); + let length = res.get_res(1)?.i32(); + match length { + None => return Err(anyhow_ext::anyhow!("Script capabilities length was not a valid i32")), + Some(length) => { + for i in 0..length as usize { + capabilities.insert(*ptr.add(i)); + } + } } } } @@ -529,13 +529,16 @@ impl WebAssemblyEnvironmentData { } let read_guard = self.script_capabilities.read(); - let capabilities = read_guard.get(&key).unwrap(); + let capabilities = read_guard.get(&key).ok_or(anyhow!("Script capabilities not found"))?; + + #[allow(clippy::unwrap_used)] // This should never be None when used. + let environment = { self.self_arc.read().as_ref().unwrap().upgrade().unwrap() }; let script = Arc::new(WebAssemblyScript::new( owner, script_ptr, capabilities.clone(), - self.self_arc.read().as_ref().unwrap().upgrade().unwrap(), + environment, script_key.clone(), )); @@ -558,6 +561,7 @@ impl WebAssemblyEnv { } /// Get the actual data belonging to the current context. + #[allow(clippy::unwrap_used)] // This should never be None when used. pub fn data(&self) -> Arc { self.data.upgrade().unwrap() } diff --git a/src/static_data/libraries/item_library.rs b/src/static_data/libraries/item_library.rs index 9053b66..0b2d59d 100755 --- a/src/static_data/libraries/item_library.rs +++ b/src/static_data/libraries/item_library.rs @@ -67,7 +67,7 @@ pub mod tests { ) } - pub fn build() -> Box { + pub fn build() -> Arc { let mut lib = ItemLibraryImpl::new(1); let m = build_item(); // Borrow as mut so we can insert @@ -75,6 +75,6 @@ pub mod tests { w.add(&"foo".into(), Arc::new(m)); // Drops borrow as mut - Box::new(lib) + Arc::new(lib) } } diff --git a/src/static_data/libraries/move_library.rs b/src/static_data/libraries/move_library.rs index 16db077..5361bc6 100755 --- a/src/static_data/libraries/move_library.rs +++ b/src/static_data/libraries/move_library.rs @@ -71,7 +71,7 @@ pub mod tests { ) } - pub fn build() -> Box { + pub fn build() -> Arc { let mut lib = MoveLibraryImpl::new(1); let m = build_move(); // Borrow as mut so we can insert @@ -79,6 +79,6 @@ pub mod tests { w.add(&StringKey::new("foo"), Arc::new(m)); // Drops borrow as mut - Box::new(lib) + Arc::new(lib) } } diff --git a/src/static_data/libraries/species_library.rs b/src/static_data/libraries/species_library.rs index c050bd6..2b9c6cd 100755 --- a/src/static_data/libraries/species_library.rs +++ b/src/static_data/libraries/species_library.rs @@ -95,7 +95,7 @@ pub mod tests { )) } - pub fn build() -> Box { + pub fn build() -> Arc { let mut lib = SpeciesLibraryImpl::new(1); let species = build_species(); // Borrow as mut so we can insert @@ -103,7 +103,7 @@ pub mod tests { w.add(&"foo".into(), species); // Drops borrow as mut - Box::new(lib) + Arc::new(lib) } #[test] @@ -124,6 +124,8 @@ pub mod tests { fn add_species_to_library_then_remove() { let mut lib = build(); + let lib = Arc::get_mut(&mut lib).unwrap(); + lib.remove(&"foo".into()); // Borrow as read so we can read diff --git a/src/static_data/libraries/static_data.rs b/src/static_data/libraries/static_data.rs index d83a829..2d3d6dc 100755 --- a/src/static_data/libraries/static_data.rs +++ b/src/static_data/libraries/static_data.rs @@ -8,40 +8,27 @@ use crate::static_data::SpeciesLibrary; use crate::static_data::TypeLibrary; use crate::{ValueIdentifiable, ValueIdentifier}; use std::fmt::Debug; +use std::sync::Arc; /// The storage for all different libraries. pub trait StaticData: Debug + ValueIdentifiable { /// Several misc settings for the library. - fn settings(&self) -> &Box; + fn settings(&self) -> &Arc; /// All data for Pokemon species. - fn species(&self) -> &Box; - /// All data for Pokemon species. - fn species_mut(&mut self) -> &mut Box; + fn species(&self) -> &Arc; /// All data for the moves. - fn moves(&self) -> &Box; - /// All data for the moves. - fn moves_mut(&mut self) -> &mut Box; + fn moves(&self) -> &Arc; /// All data for the items. - fn items(&self) -> &Box; - /// All data for the items. - fn items_mut(&mut self) -> &mut Box; + fn items(&self) -> &Arc; /// All data for growth rates. - fn growth_rates(&self) -> &Box; - /// All data for growth rates. - fn growth_rates_mut(&mut self) -> &mut Box; + fn growth_rates(&self) -> &Arc; /// All data related to types and type effectiveness. - fn types(&self) -> &Box; - /// All data related to types and type effectiveness. - fn types_mut(&mut self) -> &mut Box; + fn types(&self) -> &Arc; /// All data related to natures. - fn natures(&self) -> &Box; - /// All data related to natures. - fn natures_mut(&mut self) -> &mut Box; + fn natures(&self) -> &Arc; /// All data related to abilities. - fn abilities(&self) -> &Box; - /// All data related to abilities. - fn abilities_mut(&mut self) -> &mut Box; + fn abilities(&self) -> &Arc; } /// The storage for all different libraries. @@ -50,34 +37,34 @@ pub struct StaticDataImpl { /// A unique identifier so we know what value this is. identifier: ValueIdentifier, /// Several misc settings for the library. - settings: Box, + settings: Arc, /// All data for Pokemon species. - species: Box, + species: Arc, /// All data for the moves. - moves: Box, + moves: Arc, /// All data for the items. - items: Box, + items: Arc, /// All data for growth rates. - growth_rates: Box, + growth_rates: Arc, /// All data related to types and type effectiveness. - types: Box, + types: Arc, /// All data related to natures. - natures: Box, + natures: Arc, /// All data related to abilities. - abilities: Box, + abilities: Arc, } impl StaticDataImpl { /// Instantiates a new data collection. pub fn new( - settings: Box, - species: Box, - moves: Box, - items: Box, - growth_rates: Box, - types: Box, - natures: Box, - abilities: Box, + settings: Arc, + species: Arc, + moves: Arc, + items: Arc, + growth_rates: Arc, + types: Arc, + natures: Arc, + abilities: Arc, ) -> Self { Self { identifier: Default::default(), @@ -95,66 +82,38 @@ impl StaticDataImpl { impl StaticData for StaticDataImpl { /// Several misc settings for the library. - fn settings(&self) -> &Box { + fn settings(&self) -> &Arc { &self.settings } /// All data for Pokemon species. - fn species(&self) -> &Box { + fn species(&self) -> &Arc { &self.species } - /// All data for Pokemon species. - fn species_mut(&mut self) -> &mut Box { - &mut self.species - } /// All data for the moves. - fn moves(&self) -> &Box { + fn moves(&self) -> &Arc { &self.moves } - /// All data for the moves. - fn moves_mut(&mut self) -> &mut Box { - &mut self.moves - } /// All data for the items. - fn items(&self) -> &Box { + fn items(&self) -> &Arc { &self.items } - /// All data for the items. - fn items_mut(&mut self) -> &mut Box { - &mut self.items - } /// All data for growth rates. - fn growth_rates(&self) -> &Box { + fn growth_rates(&self) -> &Arc { &self.growth_rates } - /// All data for growth rates. - fn growth_rates_mut(&mut self) -> &mut Box { - &mut self.growth_rates - } /// All data related to types and type effectiveness. - fn types(&self) -> &Box { + fn types(&self) -> &Arc { &self.types } - /// All data related to types and type effectiveness. - fn types_mut(&mut self) -> &mut Box { - &mut self.types - } /// All data related to natures. - fn natures(&self) -> &Box { + fn natures(&self) -> &Arc { &self.natures } - /// All data related to natures. - fn natures_mut(&mut self) -> &mut Box { - &mut self.natures - } /// All data related to abilities. - fn abilities(&self) -> &Box { + fn abilities(&self) -> &Arc { &self.abilities } - /// All data related to abilities. - fn abilities_mut(&mut self) -> &mut Box { - &mut self.abilities - } } impl ValueIdentifiable for StaticDataImpl { @@ -174,22 +133,15 @@ pub mod test { #[derive(Debug)] pub StaticData{} impl StaticData for StaticData { - fn settings(&self) -> &Box; - fn species(&self) -> &Box; - fn species_mut(&mut self) -> &mut Box; - fn moves(&self) -> &Box; - fn moves_mut(&mut self) -> &mut Box; - fn items(&self) -> &Box; - fn items_mut(&mut self) -> &mut Box; + fn settings(&self) -> &Arc; + fn species(&self) -> &Arc; + fn moves(&self) -> &Arc; + fn items(&self) -> &Arc; - fn growth_rates(&self) -> & Box; - fn growth_rates_mut(&mut self) -> &mut Box; - fn types(&self) -> &Box; - fn types_mut(&mut self) -> &mut Box; - fn natures(&self) -> &Box; - fn natures_mut(&mut self) -> &mut Box; - fn abilities(&self) -> &Box; - fn abilities_mut(&mut self) -> &mut Box; + fn growth_rates(&self) -> & Arc; + fn types(&self) -> &Arc; + fn natures(&self) -> &Arc; + fn abilities(&self) -> &Arc; } impl ValueIdentifiable for StaticData { fn value_identifier(&self) -> ValueIdentifier{ @@ -201,14 +153,14 @@ pub mod test { pub fn build() -> StaticDataImpl { StaticDataImpl { identifier: Default::default(), - settings: Box::new(LibrarySettingsImpl::new(100, 100).unwrap()), + settings: Arc::new(LibrarySettingsImpl::new(100, 100).unwrap()), species: crate::static_data::libraries::species_library::tests::build(), moves: crate::static_data::libraries::move_library::tests::build(), items: crate::static_data::libraries::item_library::tests::build(), - growth_rates: Box::new(crate::static_data::libraries::growth_rate_library::tests::build()), - types: Box::new(crate::static_data::libraries::type_library::tests::build()), - natures: Box::new(crate::static_data::libraries::nature_library::tests::build()), - abilities: Box::new(crate::static_data::libraries::ability_library::tests::build()), + growth_rates: Arc::new(crate::static_data::libraries::growth_rate_library::tests::build()), + types: Arc::new(crate::static_data::libraries::type_library::tests::build()), + natures: Arc::new(crate::static_data::libraries::nature_library::tests::build()), + abilities: Arc::new(crate::static_data::libraries::ability_library::tests::build()), } } } diff --git a/src/static_data/moves/secondary_effect.rs b/src/static_data/moves/secondary_effect.rs index a1bd59c..8ee083c 100755 --- a/src/static_data/moves/secondary_effect.rs +++ b/src/static_data/moves/secondary_effect.rs @@ -1,6 +1,7 @@ use crate::static_data::EffectParameter; use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use std::fmt::Debug; +use std::sync::Arc; /// A secondary effect is an effect on a move that happens after it hits. pub trait SecondaryEffect: Debug + ValueIdentifiable { @@ -9,7 +10,7 @@ pub trait SecondaryEffect: Debug + ValueIdentifiable { /// The name of the effect. fn effect_name(&self) -> &StringKey; /// A list of parameters for the effect. - fn parameters(&self) -> &Vec; + fn parameters(&self) -> &Vec>; } /// A secondary effect is an effect on a move that happens after it hits. @@ -22,12 +23,12 @@ pub struct SecondaryEffectImpl { /// The name of the effect. effect_name: StringKey, /// A list of parameters for the effect. - parameters: Vec, + parameters: Vec>, } impl SecondaryEffectImpl { /// Instantiates a new Secondary Effect. - pub fn new(chance: f32, effect_name: StringKey, parameters: Vec) -> Self { + pub fn new(chance: f32, effect_name: StringKey, parameters: Vec>) -> Self { Self { identifier: Default::default(), chance, @@ -47,7 +48,7 @@ impl SecondaryEffect for SecondaryEffectImpl { &self.effect_name } /// A list of parameters for the effect. - fn parameters(&self) -> &Vec { + fn parameters(&self) -> &Vec> { &self.parameters } } @@ -74,7 +75,7 @@ pub(crate) mod tests { impl SecondaryEffect for SecondaryEffect { fn chance(&self) -> f32; fn effect_name(&self) -> &StringKey; - fn parameters(&self) -> &Vec; + fn parameters(&self) -> &Vec>; } impl ValueIdentifiable for SecondaryEffect{ fn value_identifier(&self) -> ValueIdentifier{ diff --git a/src/static_data/species_data/ability.rs b/src/static_data/species_data/ability.rs index 61e31db..425763c 100755 --- a/src/static_data/species_data/ability.rs +++ b/src/static_data/species_data/ability.rs @@ -1,6 +1,7 @@ use crate::static_data::EffectParameter; use crate::{StringKey, ValueIdentifiable, ValueIdentifier}; use std::fmt::Debug; +use std::sync::Arc; /// An ability is a passive effect in battle that is attached to a Pokemon. pub trait Ability: Debug + ValueIdentifiable { @@ -9,7 +10,7 @@ pub trait Ability: Debug + ValueIdentifiable { /// The name of the script effect of the ability. fn effect(&self) -> &StringKey; /// The parameters for the script effect of the ability. - fn parameters(&self) -> &Vec; + fn parameters(&self) -> &Vec>; } /// An ability is a passive effect in battle that is attached to a Pokemon. @@ -22,12 +23,12 @@ pub struct AbilityImpl { /// The name of the script effect of the ability. effect: StringKey, /// The parameters for the script effect of the ability. - parameters: Vec, + parameters: Vec>, } impl AbilityImpl { /// Instantiates a new ability. - pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec) -> Self { + pub fn new(name: &StringKey, effect: &StringKey, parameters: Vec>) -> Self { Self { identifier: Default::default(), name: name.clone(), @@ -47,7 +48,7 @@ impl Ability for AbilityImpl { &self.effect } /// The parameters for the script effect of the ability. - fn parameters(&self) -> &Vec { + fn parameters(&self) -> &Vec> { &self.parameters } } @@ -81,7 +82,7 @@ pub(crate) mod tests { impl Ability for Ability { fn name(&self) -> &StringKey; fn effect(&self) -> &StringKey; - fn parameters(&self) -> &Vec; + fn parameters(&self) -> &Vec>; } impl ValueIdentifiable for Ability { fn value_identifier(&self) -> ValueIdentifier { diff --git a/src/static_data/species_data/form.rs b/src/static_data/species_data/form.rs index 71fbe8b..a5fd7d4 100755 --- a/src/static_data/species_data/form.rs +++ b/src/static_data/species_data/form.rs @@ -1,6 +1,7 @@ use anyhow_ext::{ensure, Result}; use hashbrown::HashSet; use std::fmt::Debug; +use std::sync::Arc; use crate::static_data::Statistic; use crate::static_data::TypeIdentifier; @@ -23,7 +24,7 @@ pub trait Form: ValueIdentifiable + Debug { /// The normal types a Pokemon with this form has. fn types(&self) -> &Vec; /// The inherent values of a form of species that are used for the stats of a Pokemon. - fn base_stats(&self) -> &StaticStatisticSet; + fn base_stats(&self) -> &Arc>; /// The possible abilities a Pokemon with this form can have. fn abilities(&self) -> &Vec; /// The possible hidden abilities a Pokemon with this form can have. @@ -74,7 +75,7 @@ pub struct FormImpl { /// The normal types a Pokemon with this form has. types: Vec, /// The inherent values of a form of species that are used for the stats of a Pokemon. - base_stats: StaticStatisticSet, + base_stats: Arc>, /// The possible abilities a Pokemon with this form can have. abilities: Vec, /// The possible hidden abilities a Pokemon with this form can have. @@ -106,7 +107,7 @@ impl FormImpl { weight, base_experience, types, - base_stats, + base_stats: Arc::new(base_stats), abilities, hidden_abilities, moves, @@ -137,7 +138,7 @@ impl Form for FormImpl { &self.types } /// The inherent values of a form of species that are used for the stats of a Pokemon. - fn base_stats(&self) -> &StaticStatisticSet { + fn base_stats(&self) -> &Arc> { &self.base_stats } /// The possible abilities a Pokemon with this form can have. @@ -242,7 +243,7 @@ pub(crate) mod tests { fn weight(&self) -> f32; fn base_experience(&self) -> u32; fn types(&self) -> &Vec; - fn base_stats(&self) -> &StaticStatisticSet; + fn base_stats(&self) -> &Arc>; fn abilities(&self) -> &Vec; fn hidden_abilities(&self) -> &Vec; fn moves(&self) -> &Box; diff --git a/tests/common/data_getter.rs b/tests/common/data_getter.rs index cf99a99..67c6f7c 100755 --- a/tests/common/data_getter.rs +++ b/tests/common/data_getter.rs @@ -1,5 +1,4 @@ use serde::Deserialize; -use std::sync::Arc; use pkmn_lib::dynamic_data::Battle; @@ -10,7 +9,7 @@ pub enum TestDataGetter { } impl TestDataGetter { - pub fn get(&self, battle: &Arc) -> String { + pub fn get(&self, battle: &Battle) -> String { match self { TestDataGetter::PokemonHealth { index } => battle .get_pokemon(index[0], index[1]) diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index fa060ac..aaf82a0 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -65,7 +65,7 @@ pub fn load_library() -> LoadResult { let species_load_time = t2 - t1; let data = StaticDataImpl::new( - Box::new(LibrarySettingsImpl::new(100, 100).unwrap()), + Arc::new(LibrarySettingsImpl::new(100, 100).unwrap()), species, moves, items, @@ -81,10 +81,10 @@ pub fn load_library() -> LoadResult { let wasm_load_time = t2 - t1; let library = Arc::new(DynamicLibraryImpl::new( - Box::new(data), - Box::new(Gen7BattleStatCalculator::new()), - Box::new(Gen7DamageLibrary::new(false)), - Box::new(Gen7MiscLibrary::new()), + Arc::new(data), + Arc::new(Gen7BattleStatCalculator::new()), + Arc::new(Gen7DamageLibrary::new(false)), + Arc::new(Gen7MiscLibrary::new()), script_resolver, )); @@ -101,13 +101,13 @@ pub fn load_library() -> LoadResult { } } -pub fn load_types(path: &String) -> Box { +pub fn load_types(path: &String) -> Arc { let mut reader = csv::ReaderBuilder::new() .delimiter(b'|') .from_path(path.to_string() + "Types.csv") .unwrap(); - let mut type_library = Box::new(TypeLibraryImpl::new(20)); + let mut type_library = TypeLibraryImpl::new(20); let headers = reader.headers().unwrap(); for header in headers.iter().skip(1) { @@ -126,16 +126,16 @@ pub fn load_types(path: &String) -> Box { .unwrap(); } } - type_library + Arc::new(type_library) } -pub fn load_natures(path: &String) -> Box { +pub fn load_natures(path: &String) -> Arc { let mut reader = csv::ReaderBuilder::new() .delimiter(b'|') .from_path(path.to_string() + "Natures.csv") .unwrap(); - let mut nature_library = Box::new(NatureLibraryImpl::new(24)); + let mut nature_library = NatureLibraryImpl::new(24); for record in reader.records() { let record = record.unwrap(); let nature_name = record.get(0).unwrap().into(); @@ -152,17 +152,17 @@ pub fn load_natures(path: &String) -> Box { ); } } - nature_library + Arc::new(nature_library) } -pub fn load_items(path: &String) -> Box { +pub fn load_items(path: &String) -> Arc { let mut file = File::open(path.to_string() + "Items.json").unwrap(); let mut data = String::new(); file.read_to_string(&mut data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap(); let json_array = json.as_array().unwrap(); - let mut item_library = Box::new(ItemLibraryImpl::new(400)); + let mut item_library = ItemLibraryImpl::new(400); for v in json_array { let name = v.get("name").unwrap().as_str().unwrap().into(); let category = serde_json::from_value(v.get("itemType").unwrap().clone()).unwrap(); @@ -184,17 +184,17 @@ pub fn load_items(path: &String) -> Box { Arc::new(ItemImpl::new(&name, category, battle_category, price as i32, flags)), ); } - item_library + Arc::new(item_library) } -pub fn load_growth_rates(path: &String) -> Box { +pub fn load_growth_rates(path: &String) -> Arc { let mut file = File::open(path.to_string() + "GrowthRates.json").unwrap(); let mut data = String::new(); file.read_to_string(&mut data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap(); let o = json.as_object().unwrap(); - let mut growth_rate_library = Box::new(GrowthRateLibraryImpl::new(10)); + let mut growth_rate_library = GrowthRateLibraryImpl::new(10); for (key, value) in o { let name = StringKey::new(key); let experience_required_json = value.as_array().unwrap(); @@ -205,17 +205,17 @@ pub fn load_growth_rates(path: &String) -> Box { growth_rate_library.add_growth_rate(&name, Box::new(LookupGrowthRate::new(experience_required))); } - growth_rate_library + Arc::new(growth_rate_library) } -pub fn load_abilities(path: &String) -> Box { +pub fn load_abilities(path: &String) -> Arc { let mut file = File::open(path.to_string() + "Abilities.json").unwrap(); let mut data = String::new(); file.read_to_string(&mut data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap(); let o = json.as_object().unwrap(); - let mut ability_library = Box::new(AbilityLibraryImpl::new(400)); + let mut ability_library = AbilityLibraryImpl::new(400); for (key, value) in o { let name = StringKey::new(key); let mut effect = StringKey::empty(); @@ -231,16 +231,16 @@ pub fn load_abilities(path: &String) -> Box { ability_library.add(&name, Arc::new(AbilityImpl::new(&name, &effect, parameters))); } - ability_library + Arc::new(ability_library) } -pub fn load_moves(path: &String, types: &Box) -> Box { +pub fn load_moves(path: &String, types: &Arc) -> Arc { let mut file = File::open(path.to_string() + "Moves.json").unwrap(); let mut data = String::new(); file.read_to_string(&mut data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap(); let data = json.as_object().unwrap().get("data").unwrap().as_array().unwrap(); - let mut move_library = Box::new(MoveLibraryImpl::new(600)); + let mut move_library = MoveLibraryImpl::new(600); for move_data in data { let move_data = move_data.as_object().unwrap(); let move_name = move_data.get("name").unwrap().as_str().unwrap().into(); @@ -298,21 +298,21 @@ pub fn load_moves(path: &String, types: &Box) -> Box, - moves: &Box, -) -> Box { + types: &Arc, + moves: &Arc, +) -> Arc { let mut file = File::open(path.to_string() + "Pokemon.json").unwrap(); let mut data = String::new(); file.read_to_string(&mut data).unwrap(); let json: Value = serde_json::from_str(&data).unwrap(); let o = json.as_object().unwrap(); - let mut species_library = Box::new(SpeciesLibraryImpl::new(800)); + let mut species_library = SpeciesLibraryImpl::new(800); for (key, value) in o.iter() { if key.starts_with('$') { continue; @@ -349,7 +349,7 @@ pub fn load_species( ); species_library.add(&name, Arc::new(species)); } - species_library + Arc::new(species_library) } #[cfg(not(feature = "wasm"))] @@ -372,8 +372,8 @@ fn load_script_resolver(path: &String) -> Box { fn parse_form( name: StringKey, value: &Value, - types: &Box, - moves: &Box, + types: &Arc, + moves: &Arc, ) -> Arc { let mut abilities = Vec::new(); for a in value.get("abilities").unwrap().as_array().unwrap() { @@ -457,7 +457,7 @@ where ) } -fn parse_moves(value: &Value, move_library: &Box) -> Box { +fn parse_moves(value: &Value, move_library: &Arc) -> Box { let mut moves = LearnableMovesImpl::new(100); let level_moves = value.get("levelMoves").unwrap().as_array().unwrap(); @@ -471,8 +471,8 @@ fn parse_moves(value: &Value, move_library: &Box) -> Box EffectParameter { - match value { +fn parse_effect_parameter(value: &Value) -> Arc { + Arc::new(match value { Value::Null => { panic!("Unexpected type") } @@ -491,7 +491,7 @@ fn parse_effect_parameter(value: &Value) -> EffectParameter { Value::Object(_) => { panic!("Unexpected type") } - } + }) } #[test] diff --git a/tests/common/test_case.rs b/tests/common/test_case.rs index d3d1159..8dff71d 100755 --- a/tests/common/test_case.rs +++ b/tests/common/test_case.rs @@ -49,14 +49,14 @@ impl TestCase { let pokemon = party .pokemon .iter() - .map(|a| Some(Arc::new(a.to_pokemon(library.clone())))) + .map(|a| Some(a.to_pokemon(library.clone()))) .collect(); let indices = party.indices.iter().map(|a| (a[0], a[1])).collect(); parties.push((Arc::new(PokemonParty::new_from_vec(pokemon)), indices)); } let mut battle_parties = Vec::new(); for party in parties { - battle_parties.push(BattleParty::new(party.0.clone(), party.1).unwrap()); + battle_parties.push(Arc::new(BattleParty::new(party.0.clone(), party.1).unwrap())); } let battle = Battle::new( library, diff --git a/tests/common/test_step.rs b/tests/common/test_step.rs index 7eab33a..f5fe1ed 100755 --- a/tests/common/test_step.rs +++ b/tests/common/test_step.rs @@ -1,5 +1,4 @@ use serde::Deserialize; -use std::sync::Arc; use pkmn_lib::dynamic_data::Battle; use pkmn_lib::dynamic_data::{MoveChoice, PassChoice, TurnChoice}; @@ -32,7 +31,7 @@ pub enum TestStep { } impl TestStep { - pub fn execute(&self, battle: &Arc) { + pub fn execute(&self, battle: &Battle) { match self { TestStep::SetPokemon { place, from_party } => { let p = battle.parties()[from_party[0] as usize].get_pokemon(from_party[1] as usize); @@ -73,7 +72,7 @@ impl TestStep { assert!(battle.try_set_choice(TurnChoice::Pass(PassChoice::new(p))).unwrap()); } TestStep::Assert { value, expected } => { - let v = value.get(&battle); + let v = value.get(battle); assert_eq!(&v, expected) } } diff --git a/tests/data/gen7_scripts.wasm b/tests/data/gen7_scripts.wasm index d966ca8..e70de53 100755 Binary files a/tests/data/gen7_scripts.wasm and b/tests/data/gen7_scripts.wasm differ diff --git a/tests/integration.rs b/tests/integration.rs index 6dfe6d7..33d49c1 100755 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -84,29 +84,28 @@ fn load_non_existing_wasm_script() { #[test] fn validate_assurance() { let lib = get_library(); - let p1 = Arc::new( - PokemonBuilder::new(lib.clone(), "charizard".into(), 100) - .learn_move("assurance".into()) - .build() - .unwrap(), + let p1 = PokemonBuilder::new(lib.clone(), "charizard".into(), 100) + .learn_move("assurance".into()) + .build() + .unwrap(); + let p2 = PokemonBuilder::new(lib.clone(), "venusaur".into(), 100) + .build() + .unwrap(); + let party1 = Arc::new( + BattleParty::new( + Arc::new(PokemonParty::new_from_vec(vec![Some(p1.clone())])), + vec![(0, 0)], + ) + .unwrap(), ); - let p2 = Arc::new( - PokemonBuilder::new(lib.clone(), "venusaur".into(), 100) - .build() - .unwrap(), + let party2 = Arc::new( + BattleParty::new( + Arc::new(PokemonParty::new_from_vec(vec![Some(p2.clone())])), + vec![(1, 0)], + ) + .unwrap(), ); - let party1 = BattleParty::new( - Arc::new(PokemonParty::new_from_vec(vec![Some(p1.clone())])), - vec![(0, 0)], - ) - .unwrap(); - let party2 = BattleParty::new( - Arc::new(PokemonParty::new_from_vec(vec![Some(p2.clone())])), - vec![(1, 0)], - ) - .unwrap(); - let battle = Battle::new(lib.clone(), vec![party1, party2], false, 2, 1, None); battle.sides()[0].set_pokemon(0, Some(p1.clone())).unwrap(); @@ -118,18 +117,18 @@ fn validate_assurance() { .unwrap(); let mv = p1.learned_moves().read()[0].as_ref().unwrap().clone(); - let choice = TurnChoice::Move(MoveChoice::new(p1.clone(), mv.clone(), 1, 0)); + let choice = Arc::new(TurnChoice::Move(MoveChoice::new(p1.clone(), mv.clone(), 1, 0))); script.on_before_turn(&choice).unwrap(); assert!(battle.sides()[1].has_volatile_script(&"assurance_data".into())); - let executing_move = ExecutingMove::new( + let executing_move = Arc::new(ExecutingMove::new( vec![], 1, p1, mv.clone(), mv.move_data().clone(), ScriptContainer::default(), - ); + )); let mut v = 20_u8; script.change_base_power(&executing_move, &p2, 0, &mut v).unwrap(); assert_eq!(v, 20_u8);