Documents the ScriptContainer.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2022-06-27 19:21:50 +02:00
parent cf4d74d898
commit 25e2a0dda1
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
3 changed files with 35 additions and 6 deletions

View File

@ -68,7 +68,7 @@ fn get_all_adjacent_opponent<'b, 'library>(
] ]
} }
/// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the pokemon to the /// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the Pokemon to the
/// left of it, and the Pokemon to the right of it. /// left of it, and the Pokemon to the right of it.
fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> { fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle<'b, 'library>) -> TargetList<'b, 'library> {
let left = index as i32 - 1; let left = index as i32 - 1;

View File

@ -5,13 +5,13 @@ use crate::dynamic_data::Pokemon;
use crate::static_data::Statistic; use crate::static_data::Statistic;
use crate::static_data::StatisticSet; use crate::static_data::StatisticSet;
/// A battle stat calculator is used to calculate stats for a pokemon. /// A battle stat calculator is used to calculate stats for a Pokemon.
pub trait BattleStatCalculator: Debug { pub trait BattleStatCalculator: Debug {
/// Calculate all the flat stats of a Pokemon, disregarding stat boosts. /// Calculate all the flat stats of a Pokemon, disregarding stat boosts.
fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>); fn calculate_flat_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>);
/// Calculate a single flat stat of a Pokemon, disregarding stat boost /// Calculate a single flat stat of a Pokemon, disregarding stat boost
fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32; fn calculate_flat_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32;
/// Calculate all the boosted stats of a pokemon, including stat boosts. /// Calculate all the boosted stats of a Pokemon, including stat boosts.
fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>); fn calculate_boosted_stats(&self, pokemon: &Pokemon, stats: &StatisticSet<AtomicU32>);
/// Calculate a single boosted stat of a Pokemon, including stat boosts. /// Calculate a single boosted stat of a Pokemon, including stat boosts.
fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32; fn calculate_boosted_stat(&self, pokemon: &Pokemon, stat: Statistic) -> u32;

View File

@ -218,7 +218,7 @@ pub trait Script: Send + Sync {
fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {} fn on_secondary_effect(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>, _hit: u8) {}
/// This function triggers on a move or its parents when all hits on a target are finished. /// 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<Pokemon>) {} fn on_after_hits(&self, _move: &ExecutingMove, _target: &Arc<Pokemon>) {}
/// This function prevents the pokemon it is attached to from being able to switch out. /// 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) {} fn prevent_self_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
/// This function allows the prevention of switching for any opponent. /// This function allows the prevention of switching for any opponent.
fn prevent_opponent_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {} fn prevent_opponent_switch(&self, _choice: &TurnChoice, _prevent: &mut bool) {}
@ -253,7 +253,7 @@ pub trait Script: Send + Sync {
/// This function is triggered on a battle and its parents when something attempts to change the /// This function is triggered on a battle and its parents when something attempts to change the
/// weather, and allows for blocking the weather change. /// weather, and allows for blocking the weather change.
fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) {} fn block_weather(&self, _battle: &Battle, _blocked: &mut bool) {}
/// This function is called when a pokeball is thrown at a Pokemon, and allows modifying the catch /// 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 /// rate of this attempt. Pokeball modifier effects should be implemented here, as well as for
/// example status effects that change capture rates. /// example status effects that change capture rates.
fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &Item, _modifier: &mut u8) {} fn change_capture_rate_bonus(&self, _target: &Pokemon, _pokeball: &Item, _modifier: &mut u8) {}
@ -270,15 +270,32 @@ impl Debug for dyn Script {
} }
} }
/// A script holder defines the underlying type of how we store individual scripts on a script source.
/// The outer [`Arc`] here is so we can take a weak reference to it with dynamic lifetimes, as well as
/// copy the value for use during threading.
/// The [`RwLock`] is so we cannot modify the internal script while we're reading from it.
/// The inner [`Arc`] is the default of Scripts, where there can be multiple owners, and where it can be
/// often copied.
type ScriptHolder = Arc<RwLock<Option<Arc<dyn Script>>>>; type ScriptHolder = Arc<RwLock<Option<Arc<dyn Script>>>>;
/// A script container is used to store a exclusive script. This is for example used for non-volatile
/// Pokemon status, weather, ability, etc. It can only hold one script, and that script can be replaced
/// if needed.
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct ScriptContainer { pub struct ScriptContainer {
/// The actual place where the script is stored.
script: ScriptHolder, script: ScriptHolder,
/// The join_handle is a very specific piece of data used in one single specific case; the replacing
/// of a script while the script is actively being read from. The RwLock blocks the write, and
/// as such, this is delayed to a thread. This join handle is this thread. In some very specific
/// cases (mostly test cases), it can be required to make sure that this has been completed before
/// continuing.
pub(crate) join_handle: RwLock<Option<JoinHandle<()>>>, pub(crate) join_handle: RwLock<Option<JoinHandle<()>>>,
} }
impl ScriptContainer { impl ScriptContainer {
/// Initialize a script container with a specific script. To initialize with an empty script, use
/// default() instead.
pub fn new(script: Arc<dyn Script>) -> ScriptContainer { pub fn new(script: Arc<dyn Script>) -> ScriptContainer {
Self { Self {
script: Arc::new(RwLock::new(Some(script))), script: Arc::new(RwLock::new(Some(script))),
@ -286,6 +303,7 @@ impl ScriptContainer {
} }
} }
/// Get the internal script. Note that this can only be None if the script was marked for deletion.
pub fn get(&self) -> Option<&ScriptHolder> { pub fn get(&self) -> Option<&ScriptHolder> {
if self.script.read().is_some_and(|a| a.is_marked_for_deletion()) { if self.script.read().is_some_and(|a| a.is_marked_for_deletion()) {
if !self.script.is_locked() { if !self.script.is_locked() {
@ -297,11 +315,17 @@ impl ScriptContainer {
} }
} }
/// Changes the internal script. This has several side effects: primarily that it calls the
/// [`Script::on_remove`] function on itself. Other special cases are that the script is currently read
/// from, and as such can not be replaced yet. In this case, the script will be replaced on a
/// separate thread, and be replaced immediately after the script stops being active.
pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> { pub fn set(&self, script: Arc<dyn Script>) -> Arc<dyn Script> {
if let Some(v) = self.script.read().deref() { if let Some(v) = self.script.read().deref() {
v.on_remove(); v.on_remove();
v.mark_for_deletion(); v.mark_for_deletion();
} }
// If we have a lock on the script, we can't replace it now. Wait until we can get the lock,
// and only replace it then. Don't block in the meantime.
if self.script.is_locked() { if self.script.is_locked() {
let holder = self.script.clone(); let holder = self.script.clone();
let new = script.clone(); let new = script.clone();
@ -315,6 +339,9 @@ impl ScriptContainer {
script script
} }
/// Removes the internal script. This calls the [`Script::on_remove`] function on itself. If no
/// locks are held to the script, we also immediately set the internal value to None, otherwise
/// we just mark it as deleted. If we do this we remove the script later on.
pub fn clear(&self) { pub fn clear(&self) {
if let Some(v) = self.script.read().deref() { if let Some(v) = self.script.read().deref() {
v.on_remove(); v.on_remove();
@ -325,10 +352,12 @@ impl ScriptContainer {
} }
} }
/// Gets the underlying reference counter to the script.
pub fn arc(&self) -> &ScriptHolder { pub fn arc(&self) -> &ScriptHolder {
&self.script &self.script
} }
/// Get the underlying script as the downcasted value.
pub fn get_as<T: 'static>(&self) -> MappedRwLockReadGuard<T> { pub fn get_as<T: 'static>(&self) -> MappedRwLockReadGuard<T> {
RwLockReadGuard::map(self.script.read(), |a| unsafe { RwLockReadGuard::map(self.script.read(), |a| unsafe {
let ptr = a.as_ref().as_ref().unwrap().as_ref() as *const dyn Script; let ptr = a.as_ref().as_ref().unwrap().as_ref() as *const dyn Script;