From df662ce6b5299e6b8c5d5c4b1d92ce80c933bcc6 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 4 Jun 2022 12:40:32 +0200 Subject: [PATCH] Change to RwLock over Mutex, so we can read without locking, changes to BattleRandom to allow for cloning, and prevent race conditions. --- Cargo.toml | 4 +-- src/dynamic_data/event_hooks/event_hook.rs | 13 ++------ src/dynamic_data/models/battle.rs | 14 ++++----- src/dynamic_data/models/battle_random.rs | 36 ++++++++++++---------- src/dynamic_data/models/battle_side.rs | 28 ++++++++--------- src/dynamic_data/models/pokemon.rs | 18 ++++++----- src/utils/random.rs | 1 + 7 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e90e655..cfb852b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,8 +43,8 @@ assert_approx_eq = "1.1.0" # Used for time based code (i.e. randomness) chrono = "0.4.19" # Used for RNG -rand = "0.8.3" -rand_pcg = "0.3.0" +rand = "0.8.5" +rand_pcg = "0.3.1" # Used for the hashmap!{} macro, creating a simple initializer pattern for hashmaps. maplit = "1.0.2" failure = "0.1.8" diff --git a/src/dynamic_data/event_hooks/event_hook.rs b/src/dynamic_data/event_hooks/event_hook.rs index 5575e0f..d3d28be 100644 --- a/src/dynamic_data/event_hooks/event_hook.rs +++ b/src/dynamic_data/event_hooks/event_hook.rs @@ -1,7 +1,8 @@ use crate::dynamic_data::models::pokemon::Pokemon; use std::fmt::{Debug, Formatter}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock}; +#[derive(Default)] pub struct EventHook { evt_hook_function: Vec)>, } @@ -19,14 +20,6 @@ impl EventHook { } } -impl Default for EventHook { - fn default() -> Self { - EventHook { - evt_hook_function: vec![], - } - } -} - impl Debug for EventHook { fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result { Ok(()) @@ -38,6 +31,6 @@ pub enum Event<'a> { Switch { side_index: u8, index: u8, - pokemon: Option>>>, + pokemon: Option>>>, }, } diff --git a/src/dynamic_data/models/battle.rs b/src/dynamic_data/models/battle.rs index 9e0850f..61f7053 100644 --- a/src/dynamic_data/models/battle.rs +++ b/src/dynamic_data/models/battle.rs @@ -8,7 +8,7 @@ use crate::dynamic_data::models::battle_result::BattleResult; use crate::dynamic_data::models::battle_side::BattleSide; use crate::dynamic_data::script_handling::script_set::ScriptSet; use derive_getters::Getters; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock}; #[derive(Getters, Debug)] pub struct Battle<'a> { @@ -38,14 +38,14 @@ impl<'a> Battle<'a> { number_of_sides: u8, pokemon_per_side: u8, random_seed: Option, - ) -> Arc> { + ) -> Arc> { let random = if let Some(seed) = random_seed { BattleRandom::new_with_seed(seed) } else { - BattleRandom::new() + BattleRandom::default() }; let sides = Vec::with_capacity(number_of_sides as usize); - let battle = Arc::new(Mutex::new(Self { + let battle = Arc::new(RwLock::new(Self { library, parties, can_flee, @@ -64,14 +64,14 @@ impl<'a> Battle<'a> { })); for i in 0..number_of_sides { - battle.lock().unwrap().sides[i as usize] = + battle.write().unwrap().sides[i as usize] = BattleSide::new(i, Arc::downgrade(&battle), pokemon_per_side); } battle } - pub fn random(&mut self) -> &mut BattleRandom { - &mut self.random + pub fn random(&self) -> &BattleRandom { + &self.random } pub fn can_slot_be_filled(&self) -> bool { diff --git a/src/dynamic_data/models/battle_random.rs b/src/dynamic_data/models/battle_random.rs index e03adac..6932d23 100644 --- a/src/dynamic_data/models/battle_random.rs +++ b/src/dynamic_data/models/battle_random.rs @@ -1,8 +1,22 @@ use crate::utils::random::Random; use std::fmt::{Debug, Formatter}; +use std::sync::Mutex; +#[derive(Default)] pub struct BattleRandom { - random: Random, + random: Mutex, +} + +impl BattleRandom { + pub fn new_with_seed(seed: u128) -> Self { + BattleRandom { + random: Mutex::new(Random::new(seed)), + } + } + + pub fn get_rng(&self) -> &Mutex { + &self.random + } } impl Debug for BattleRandom { @@ -11,20 +25,10 @@ impl Debug for BattleRandom { } } -impl BattleRandom { - pub fn new() -> Self { - return BattleRandom { - random: Default::default(), - }; - } - - pub fn new_with_seed(seed: u128) -> Self { - return BattleRandom { - random: Random::new(seed), - }; - } - - pub fn get_rng(&mut self) -> &mut Random { - &mut self.random +impl Clone for BattleRandom { + fn clone(&self) -> Self { + Self { + random: Mutex::new(self.random.lock().unwrap().clone()), + } } } diff --git a/src/dynamic_data/models/battle_side.rs b/src/dynamic_data/models/battle_side.rs index 074e325..06f8bc2 100644 --- a/src/dynamic_data/models/battle_side.rs +++ b/src/dynamic_data/models/battle_side.rs @@ -5,22 +5,22 @@ use crate::dynamic_data::models::pokemon::Pokemon; use crate::dynamic_data::script_handling::ScriptSource; use crate::script_hook; use derive_getters::Getters; -use std::sync::{Arc, Mutex, Weak}; +use std::sync::{Arc, RwLock, Weak}; #[derive(Getters, Debug)] pub struct BattleSide<'a> { index: u8, pokemon_per_side: u8, - pokemon: Vec>>>>, + pokemon: Vec>>>>, choices: Vec>>>, fillable_slots: Vec, choices_set: u8, - battle: Weak>>, + battle: Weak>>, has_fled: bool, } impl<'a> BattleSide<'a> { - pub fn new(index: u8, battle: Weak>>, pokemon_per_side: u8) -> Self { + pub fn new(index: u8, battle: Weak>>, pokemon_per_side: u8) -> Self { let mut pokemon = Vec::with_capacity(pokemon_per_side as usize); let mut choices = Vec::with_capacity(pokemon_per_side as usize); let mut fillable_slots = Vec::with_capacity(pokemon_per_side as usize); @@ -52,12 +52,12 @@ impl<'a> BattleSide<'a> { /// empty, but can't be filled by any party anymore. pub fn all_slots_filled(&self) -> bool { for pokemon in &self.pokemon { - if (!pokemon.is_none() || !pokemon.as_ref().unwrap().lock().unwrap().is_usable()) + if (!pokemon.is_none() || !pokemon.as_ref().unwrap().read().unwrap().is_usable()) && self .battle .upgrade() .unwrap() - .lock() + .read() .unwrap() .can_slot_be_filled() { @@ -70,7 +70,7 @@ impl<'a> BattleSide<'a> { pub fn set_choice(&mut self, choice: TurnChoice<'a>) { for (index, pokemon_slot) in self.pokemon.iter().enumerate() { if let Some(pokemon) = pokemon_slot { - if pokemon.lock().unwrap().unique_identifier() == choice.user().unique_identifier() + if pokemon.read().unwrap().unique_identifier() == choice.user().unique_identifier() { self.choices[index] = Some(Arc::new(choice)); self.choices_set += 1; @@ -84,29 +84,29 @@ impl<'a> BattleSide<'a> { self.pokemon[index as usize] = None; } - pub fn set_pokemon(&mut self, index: u8, pokemon: Option>>>) { + pub fn set_pokemon(&mut self, index: u8, pokemon: Option>>>) { let old = &mut self.pokemon[index as usize]; if let Some(old_pokemon) = old { - let mut p = old_pokemon.lock().unwrap(); + let mut p = old_pokemon.write().unwrap(); script_hook!(on_remove, p,); p.set_on_battlefield(false); } self.pokemon[index as usize] = pokemon; let pokemon = &self.pokemon[index as usize]; if let Some(pokemon_mutex) = pokemon { - let mut pokemon = pokemon_mutex.lock().unwrap(); + let mut pokemon = pokemon_mutex.write().unwrap(); pokemon.set_battle_data(self.battle.clone(), self.index); pokemon.set_on_battlefield(true); pokemon.set_battle_index(index); let battle = self.battle.upgrade().unwrap(); - let battle = battle.lock().unwrap(); + let battle = battle.read().unwrap(); for side in battle.sides() { if *side.index() == self.index { continue; } for opponent in side.pokemon().iter().flatten() { - let mut opponent = opponent.lock().unwrap(); + let mut opponent = opponent.write().unwrap(); opponent.mark_opponent_as_seen(*pokemon.unique_identifier()); pokemon.mark_opponent_as_seen(*opponent.unique_identifier()); } @@ -119,7 +119,7 @@ impl<'a> BattleSide<'a> { script_hook!(on_switch_in, pokemon, &pokemon); } else { let battle = self.battle.upgrade().unwrap(); - let battle = battle.lock().unwrap(); + let battle = battle.read().unwrap(); battle.event_hook().trigger(Event::Switch { side_index: self.index, index, @@ -130,7 +130,7 @@ impl<'a> BattleSide<'a> { pub fn is_pokemon_on_side(&self, pokemon: Arc>) -> bool { for p in self.pokemon.iter().flatten() { - if p.lock().unwrap().unique_identifier() == pokemon.unique_identifier() { + if p.read().unwrap().unique_identifier() == pokemon.unique_identifier() { return true; } } diff --git a/src/dynamic_data/models/pokemon.rs b/src/dynamic_data/models/pokemon.rs index f02be5c..ba04a1a 100644 --- a/src/dynamic_data/models/pokemon.rs +++ b/src/dynamic_data/models/pokemon.rs @@ -15,11 +15,11 @@ use crate::static_data::statistics::Statistic; use crate::utils::random::Random; use derive_getters::Getters; use std::collections::HashSet; -use std::sync::{Mutex, Weak}; +use std::sync::{RwLock, Weak}; #[derive(Debug)] pub struct PokemonBattleData<'a> { - battle: Weak>>, + battle: Weak>>, battle_side_index: u8, index: u8, on_battle_field: bool, @@ -27,7 +27,7 @@ pub struct PokemonBattleData<'a> { } impl<'a> PokemonBattleData<'a> { - pub fn battle(&'a mut self) -> &'a mut Weak>> { + pub fn battle(&'a mut self) -> &'a mut Weak>> { &mut self.battle } pub fn battle_side_index(&self) -> u8 { @@ -141,16 +141,18 @@ impl<'a> Pokemon<'a> { // 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 self.battle_data.is_some() { - let battle = self.battle_data.as_mut().unwrap(); + let battle_data = self.battle_data.as_mut().unwrap(); self.gender = species.get_random_gender( - battle + &mut battle_data .battle .upgrade() .unwrap() - .lock() + .read() .unwrap() .random() - .get_rng(), + .get_rng() + .lock() + .unwrap(), ); } else { self.gender = species.get_random_gender(&mut Random::default()); @@ -167,7 +169,7 @@ impl<'a> Pokemon<'a> { todo!() } - pub fn set_battle_data(&mut self, battle: Weak>>, battle_side_index: u8) { + pub fn set_battle_data(&mut self, battle: Weak>>, battle_side_index: u8) { if let Some(battle_data) = &mut self.battle_data { battle_data.battle = battle; battle_data.battle_side_index = battle_side_index; diff --git a/src/utils/random.rs b/src/utils/random.rs index 2c8530d..cc7da5a 100644 --- a/src/utils/random.rs +++ b/src/utils/random.rs @@ -2,6 +2,7 @@ use rand::distributions::{Distribution, Uniform}; use rand::{Rng, SeedableRng}; use rand_pcg::Pcg32; +#[derive(Clone)] pub struct Random { seed: u128, distribution: Uniform,