More work on switching battle data to interior mutability, instead of exterior mutability.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -35,7 +35,7 @@ pub struct Battle<'own, 'library> {
|
||||
event_hook: EventHook,
|
||||
history_holder: Box<HistoryHolder>,
|
||||
current_turn: AtomicU32,
|
||||
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
||||
volatile_scripts: Arc<ScriptSet>,
|
||||
last_turn_time: Atomic<chrono::Duration>,
|
||||
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
@@ -134,16 +134,13 @@ impl<'own, 'library> Battle<'own, 'library> {
|
||||
&self.current_turn_queue
|
||||
}
|
||||
|
||||
pub fn get_pokemon(&self, side: u8, index: u8) -> &Option<Arc<Pokemon<'own, 'library>>> {
|
||||
pub fn get_pokemon(&self, side: u8, index: u8) -> Option<Arc<Pokemon<'own, 'library>>> {
|
||||
let side = self.sides.get(side as usize);
|
||||
if side.is_none() {
|
||||
return &None;
|
||||
}
|
||||
let pokemon = side.unwrap().pokemon().get(index as usize);
|
||||
if pokemon.is_none() {
|
||||
return &None;
|
||||
}
|
||||
pokemon.unwrap()
|
||||
side?;
|
||||
let pokemon_read_lock = side.unwrap().pokemon();
|
||||
let pokemon = pokemon_read_lock.get(index as usize);
|
||||
pokemon?;
|
||||
pokemon.unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn can_slot_be_filled(&self, side: u8, index: u8) -> bool {
|
||||
@@ -288,7 +285,7 @@ impl<'own, 'library> Battle<'own, 'library> {
|
||||
}
|
||||
|
||||
impl<'own, 'library> VolatileScripts<'own> for Battle<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile_scripts
|
||||
}
|
||||
|
||||
|
||||
@@ -8,22 +8,23 @@ use crate::dynamic_data::script_handling::script_set::ScriptSet;
|
||||
use crate::dynamic_data::script_handling::volatile_scripts::VolatileScripts;
|
||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||
use crate::{script_hook, PkmnResult, StringKey};
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::lock_api::RwLockReadGuard;
|
||||
use parking_lot::{RawRwLock, RwLock};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BattleSide<'own, 'library> {
|
||||
index: u8,
|
||||
pokemon_per_side: u8,
|
||||
pokemon: Vec<Option<Arc<Pokemon<'own, 'library>>>>,
|
||||
pokemon: RwLock<Vec<Option<Arc<Pokemon<'own, 'library>>>>>,
|
||||
choices: RwLock<Vec<Option<TurnChoice<'own, 'library>>>>,
|
||||
fillable_slots: Vec<AtomicBool>,
|
||||
choices_set: u8,
|
||||
choices_set: AtomicU8,
|
||||
battle: *mut Battle<'own, 'library>,
|
||||
has_fled_battle: bool,
|
||||
volatile_scripts: Arc<RwLock<ScriptSet>>,
|
||||
volatile_scripts: Arc<ScriptSet>,
|
||||
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
@@ -40,6 +41,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
fillable_slots.push(AtomicBool::new(false));
|
||||
}
|
||||
let choices = RwLock::new(choices);
|
||||
let pokemon = RwLock::new(pokemon);
|
||||
|
||||
Self {
|
||||
index,
|
||||
@@ -47,7 +49,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
pokemon,
|
||||
choices,
|
||||
fillable_slots,
|
||||
choices_set: 0,
|
||||
choices_set: AtomicU8::new(0),
|
||||
battle: std::ptr::null_mut::<Battle>(),
|
||||
has_fled_battle: false,
|
||||
volatile_scripts: Default::default(),
|
||||
@@ -65,8 +67,8 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
pub fn pokemon_per_side(&self) -> u8 {
|
||||
self.pokemon_per_side
|
||||
}
|
||||
pub fn pokemon(&self) -> &Vec<Option<Arc<Pokemon<'own, 'library>>>> {
|
||||
&self.pokemon
|
||||
pub fn pokemon(&self) -> RwLockReadGuard<'_, RawRwLock, Vec<Option<Arc<Pokemon<'own, 'library>>>>> {
|
||||
self.pokemon.read()
|
||||
}
|
||||
pub fn choices(&self) -> &RwLock<Vec<Option<TurnChoice<'own, 'library>>>> {
|
||||
&self.choices
|
||||
@@ -76,7 +78,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
&self.fillable_slots
|
||||
}
|
||||
pub fn choices_set(&self) -> u8 {
|
||||
self.choices_set
|
||||
self.choices_set.load(Ordering::SeqCst)
|
||||
}
|
||||
pub fn battle(&self) -> &Battle<'own, 'library> {
|
||||
unsafe { self.battle.as_ref().unwrap() }
|
||||
@@ -84,19 +86,19 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
pub fn has_fled_battle(&self) -> bool {
|
||||
self.has_fled_battle
|
||||
}
|
||||
pub fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||
pub fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile_scripts
|
||||
}
|
||||
|
||||
pub fn all_choices_set(&self) -> bool {
|
||||
self.choices_set == self.pokemon_per_side
|
||||
self.choices_set() == self.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) -> bool {
|
||||
for (i, pokemon) in self.pokemon.iter().enumerate() {
|
||||
for (i, pokemon) in self.pokemon.read().iter().enumerate() {
|
||||
if (!pokemon.is_none() || !pokemon.as_ref().unwrap().is_usable())
|
||||
&& self.battle().can_slot_be_filled(self.index, i as u8)
|
||||
{
|
||||
@@ -106,12 +108,12 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_choice(&mut self, choice: TurnChoice<'own, 'library>) {
|
||||
for (index, pokemon_slot) in self.pokemon.iter().enumerate() {
|
||||
pub fn set_choice(&self, choice: TurnChoice<'own, 'library>) {
|
||||
for (index, pokemon_slot) in self.pokemon.read().iter().enumerate() {
|
||||
if let Some(pokemon) = pokemon_slot {
|
||||
if std::ptr::eq(pokemon.deref(), choice.user().deref()) {
|
||||
self.choices.write()[index] = Some(choice);
|
||||
self.choices_set += 1;
|
||||
self.choices_set.fetch_add(1, Ordering::SeqCst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -126,17 +128,19 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
}
|
||||
|
||||
pub fn force_clear_pokemon(&mut self, index: u8) {
|
||||
self.pokemon[index as usize] = None;
|
||||
self.pokemon.write()[index as usize] = None;
|
||||
}
|
||||
|
||||
pub fn set_pokemon(&mut self, index: u8, pokemon: Option<Arc<Pokemon<'own, 'library>>>) {
|
||||
let old = &mut self.pokemon[index as usize];
|
||||
if let Some(old_pokemon) = old {
|
||||
script_hook!(on_remove, old_pokemon,);
|
||||
old_pokemon.set_on_battlefield(false);
|
||||
pub fn set_pokemon(&self, index: u8, pokemon: Option<Arc<Pokemon<'own, 'library>>>) {
|
||||
{
|
||||
let old = &self.pokemon.read()[index as usize];
|
||||
if let Some(old_pokemon) = old {
|
||||
script_hook!(on_remove, old_pokemon,);
|
||||
old_pokemon.set_on_battlefield(false);
|
||||
}
|
||||
}
|
||||
self.pokemon[index as usize] = pokemon;
|
||||
let pokemon = &self.pokemon[index as usize];
|
||||
self.pokemon.write()[index as usize] = pokemon;
|
||||
let pokemon = &self.pokemon.read()[index as usize];
|
||||
if let Some(pokemon) = pokemon {
|
||||
pokemon.set_battle_data(self.battle, self.index);
|
||||
pokemon.set_on_battlefield(true);
|
||||
@@ -168,7 +172,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
}
|
||||
|
||||
pub fn is_pokemon_on_side(&self, pokemon: Arc<Pokemon<'own, 'library>>) -> bool {
|
||||
for p in self.pokemon.iter().flatten() {
|
||||
for p in self.pokemon.read().iter().flatten() {
|
||||
if std::ptr::eq(p.deref().deref(), pokemon.deref()) {
|
||||
return true;
|
||||
}
|
||||
@@ -181,7 +185,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
}
|
||||
|
||||
pub fn is_slot_unfillable(&self, pokemon: Arc<Pokemon<'own, 'library>>) -> bool {
|
||||
for (i, slot) in self.pokemon.iter().enumerate() {
|
||||
for (i, slot) in self.pokemon.read().iter().enumerate() {
|
||||
if let Some(p) = slot {
|
||||
if std::ptr::eq(p.deref().deref(), pokemon.deref()) {
|
||||
return self.fillable_slots[i].load(Ordering::Relaxed);
|
||||
@@ -243,7 +247,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.pokemon.swap(a as usize, b as usize);
|
||||
self.pokemon.write().swap(a as usize, b as usize);
|
||||
self.battle().event_hook().trigger(Event::Swap {
|
||||
side_index: self.index,
|
||||
index_a: a,
|
||||
@@ -254,7 +258,7 @@ impl<'own, 'library> BattleSide<'own, 'library> {
|
||||
}
|
||||
|
||||
impl<'own, 'library> VolatileScripts<'own> for BattleSide<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile_scripts
|
||||
}
|
||||
|
||||
|
||||
@@ -5,57 +5,59 @@ use crate::dynamic_data::script_handling::script::ScriptContainer;
|
||||
use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, ScriptWrapper};
|
||||
use crate::static_data::MoveData;
|
||||
use crate::{PkmnResult, PokemonError};
|
||||
use atomic::Atomic;
|
||||
use parking_lot::RwLock;
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU8, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct HitData {
|
||||
critical: bool,
|
||||
base_power: u8,
|
||||
effectiveness: f32,
|
||||
damage: u32,
|
||||
move_type: u8,
|
||||
has_failed: bool,
|
||||
critical: AtomicBool,
|
||||
base_power: AtomicU8,
|
||||
effectiveness: Atomic<f32>,
|
||||
damage: AtomicU32,
|
||||
move_type: AtomicU8,
|
||||
has_failed: AtomicBool,
|
||||
}
|
||||
|
||||
impl HitData {
|
||||
pub fn is_critical(&self) -> bool {
|
||||
self.critical
|
||||
self.critical.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn base_power(&self) -> u8 {
|
||||
self.base_power
|
||||
self.base_power.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn effectiveness(&self) -> f32 {
|
||||
self.effectiveness
|
||||
self.effectiveness.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn damage(&self) -> u32 {
|
||||
self.damage
|
||||
self.damage.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn move_type(&self) -> u8 {
|
||||
self.move_type
|
||||
self.move_type.load(Ordering::Relaxed)
|
||||
}
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.has_failed
|
||||
self.has_failed.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn set_critical(&mut self, value: bool) {
|
||||
self.critical = value;
|
||||
pub fn set_critical(&self, value: bool) {
|
||||
self.critical.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_base_power(&mut self, value: u8) {
|
||||
self.base_power = value;
|
||||
pub fn set_base_power(&self, value: u8) {
|
||||
self.base_power.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_effectiveness(&mut self, value: f32) {
|
||||
self.effectiveness = value;
|
||||
pub fn set_effectiveness(&self, value: f32) {
|
||||
self.effectiveness.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_damage(&mut self, value: u32) {
|
||||
self.damage = value;
|
||||
pub fn set_damage(&self, value: u32) {
|
||||
self.damage.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn set_move_type(&mut self, value: u8) {
|
||||
self.move_type = value;
|
||||
pub fn set_move_type(&self, value: u8) {
|
||||
self.move_type.store(value, Ordering::SeqCst);
|
||||
}
|
||||
pub fn fail(&mut self) {
|
||||
self.has_failed = true;
|
||||
pub fn fail(&self) {
|
||||
self.has_failed.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,9 +158,6 @@ impl<'own, 'battle, 'library> ExecutingMove<'own, 'battle, 'library> {
|
||||
pub(crate) fn get_hit_from_raw_index(&self, index: usize) -> &HitData {
|
||||
&self.hits[index]
|
||||
}
|
||||
pub(crate) fn get_hit_from_raw_index_mut(&mut self, index: usize) -> &mut HitData {
|
||||
&mut self.hits[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'own, 'battle, 'library> ScriptSource<'own> for ExecutingMove<'own, 'battle, 'library> {
|
||||
|
||||
@@ -73,7 +73,7 @@ where
|
||||
unique_identifier: u32,
|
||||
gender: Gender,
|
||||
coloring: u8,
|
||||
held_item: Option<&'own Item>,
|
||||
held_item: RwLock<Option<&'own Item>>,
|
||||
current_health: AtomicU32,
|
||||
|
||||
weight: Atomic<f32>,
|
||||
@@ -104,7 +104,7 @@ where
|
||||
held_item_trigger_script: ScriptContainer,
|
||||
ability_script: ScriptContainer,
|
||||
status_script: ScriptContainer,
|
||||
volatile: Arc<RwLock<ScriptSet>>,
|
||||
volatile: Arc<ScriptSet>,
|
||||
|
||||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
@@ -144,7 +144,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
unique_identifier,
|
||||
gender,
|
||||
coloring,
|
||||
held_item: None,
|
||||
held_item: RwLock::new(None),
|
||||
current_health: AtomicU32::new(1),
|
||||
weight: Atomic::new(weight),
|
||||
height: Atomic::new(height),
|
||||
@@ -216,27 +216,27 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
pub fn coloring(&self) -> u8 {
|
||||
self.coloring
|
||||
}
|
||||
pub fn held_item(&self) -> Option<&'own Item> {
|
||||
self.held_item
|
||||
pub fn held_item(&self) -> &RwLock<Option<&'own Item>> {
|
||||
&self.held_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 {
|
||||
if let Some(v) = self.held_item.read().deref() {
|
||||
return v.name() == name;
|
||||
}
|
||||
false
|
||||
}
|
||||
pub fn set_held_item(&mut self, item: &'own Item) {
|
||||
self.held_item = Some(item);
|
||||
pub fn set_held_item(&self, item: &'own Item) -> Option<&'own Item> {
|
||||
self.held_item.write().replace(item)
|
||||
}
|
||||
pub fn remove_held_item(&mut self) {
|
||||
self.held_item = None;
|
||||
pub fn remove_held_item(&self) -> Option<&'own Item> {
|
||||
self.held_item.write().take()
|
||||
}
|
||||
pub fn consume_held_item(&mut self) -> bool {
|
||||
if self.held_item.is_none() {
|
||||
pub fn consume_held_item(&self) -> bool {
|
||||
if self.held_item.read().is_none() {
|
||||
return false;
|
||||
}
|
||||
let script = self.library.load_item_script(self.held_item.unwrap()).unwrap();
|
||||
let script = self.library.load_item_script(self.held_item.read().unwrap()).unwrap();
|
||||
if script.is_none() {
|
||||
return false;
|
||||
}
|
||||
@@ -408,8 +408,10 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
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);
|
||||
} else if diff_health < 0 {
|
||||
self.current_health.fetch_sub(-diff_health as u32, Ordering::SeqCst);
|
||||
} else {
|
||||
self.current_health.fetch_add(diff_health as u32, Ordering::Acquire);
|
||||
self.current_health.fetch_add(diff_health as u32, Ordering::SeqCst);
|
||||
}
|
||||
// TODO: consider form specific attacks?
|
||||
|
||||
@@ -450,7 +452,7 @@ impl<'own, 'library> Pokemon<'own, 'library> {
|
||||
if let Some(data) = &mut r.deref() {
|
||||
data.on_battle_field.store(value, Ordering::SeqCst);
|
||||
if !value {
|
||||
self.volatile.write().clear();
|
||||
self.volatile.clear();
|
||||
self.weight.store(self.form.weight(), Ordering::SeqCst);
|
||||
self.height.store(self.form.height(), Ordering::SeqCst);
|
||||
}
|
||||
@@ -572,7 +574,7 @@ impl<'own, 'library> ScriptSource<'own> for Pokemon<'own, 'library> {
|
||||
}
|
||||
|
||||
impl<'own, 'library> VolatileScripts<'own> for Pokemon<'own, 'library> {
|
||||
fn volatile_scripts(&self) -> &Arc<RwLock<ScriptSet>> {
|
||||
fn volatile_scripts(&self) -> &Arc<ScriptSet> {
|
||||
&self.volatile
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user