A bunch more work on replacing every potential panic with results
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-04-16 19:57:21 +02:00
parent 1b8403ecda
commit 00d596d656
37 changed files with 526 additions and 300 deletions

View File

@@ -20,7 +20,7 @@ use crate::dynamic_data::VolatileScriptsOwner;
use crate::dynamic_data::{is_valid_target, ScriptWrapper};
use crate::dynamic_data::{ChoiceQueue, ScriptContainer};
use crate::dynamic_data::{ScriptCategory, ScriptSource, ScriptSourceData};
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier};
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
/// A pokemon battle, with any amount of sides and pokemon per side.
#[derive(Debug)]
@@ -271,13 +271,7 @@ impl Battle {
let side = choice.user().get_battle_side_index();
match side {
Some(side) => {
self.sides
.get(side as usize)
.ok_or(PkmnError::IndexOutOfBounds {
index: side as usize,
len: self.sides.len(),
})?
.set_choice(choice)?;
self.sides.get_res(side as usize)?.set_choice(choice)?;
self.check_choices_set_and_run()?;
Ok(true)
}

View File

@@ -1,3 +1,4 @@
use anyhow::Result;
use std::sync::Arc;
use crate::dynamic_data::models::pokemon::Pokemon;
@@ -19,12 +20,12 @@ pub struct BattleParty {
impl BattleParty {
/// Initializes a battle party with the underlying party, and the indices the party is responsible
/// for.
pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Self {
Self {
pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Result<Self> {
Ok(Self {
identifier: Default::default(),
party,
responsible_indices,
}
})
}
/// Checks whether the party is responsible for the given index.

View File

@@ -14,7 +14,7 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
use crate::dynamic_data::Script;
use crate::dynamic_data::ScriptSet;
use crate::dynamic_data::VolatileScriptsOwner;
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier};
use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
/// A side on a battle.
#[derive(Debug)]
@@ -149,12 +149,7 @@ impl BattleSide {
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()) {
let len = self.choices.read().len();
self.choices
.write()
.get_mut(index)
.ok_or(PkmnError::IndexOutOfBounds { index, len })?
.replace(choice);
self.choices.write().get_mut_res(index)?.replace(choice);
self.choices_set.fetch_add(1, Ordering::SeqCst);
return Ok(());
}
@@ -180,10 +175,7 @@ impl BattleSide {
pub fn set_pokemon(&self, index: u8, pokemon: Option<Arc<Pokemon>>) -> Result<()> {
{
let mut write_lock = self.pokemon.write();
let old = write_lock.get_mut(index as usize).ok_or(PkmnError::IndexOutOfBounds {
index: index as usize,
len: self.pokemon_per_side as usize,
})?;
let old = write_lock.get_mut_res(index as usize)?;
let old = match pokemon {
Some(pokemon) => old.replace(pokemon),
None => old.take(),
@@ -193,23 +185,17 @@ impl BattleSide {
// side again.
drop(write_lock);
script_hook!(on_remove, old_pokemon,);
old_pokemon.set_on_battlefield(false);
old_pokemon.set_on_battlefield(false)?;
}
}
let pokemon = {
let read_lock = self.pokemon.read();
&read_lock
.get(index as usize)
.ok_or(PkmnError::IndexOutOfBounds {
index: index as usize,
len: read_lock.len(),
})?
.clone()
&read_lock.get_res(index as usize)?.clone()
};
if let Some(pokemon) = pokemon {
pokemon.set_battle_data(self.battle, self.index);
pokemon.set_on_battlefield(true);
pokemon.set_on_battlefield(true)?;
pokemon.set_battle_index(index);
let battle = self.battle()?;
@@ -252,11 +238,7 @@ impl BattleSide {
/// If this happens, the slot can not be used again.
pub(crate) fn mark_slot_as_unfillable(&self, index: u8) -> Result<()> {
self.fillable_slots
.get(index as usize)
.ok_or(PkmnError::IndexOutOfBounds {
index: index as usize,
len: self.fillable_slots.len(),
})?
.get_res(index as usize)?
.store(false, Ordering::SeqCst);
Ok(())
}
@@ -266,14 +248,7 @@ impl BattleSide {
for (i, slot) in self.pokemon.read().iter().enumerate() {
if let Some(p) = slot {
if std::ptr::eq(p.deref().deref(), pokemon.deref()) {
return Ok(self
.fillable_slots
.get(i)
.ok_or(PkmnError::IndexOutOfBounds {
index: i,
len: self.fillable_slots.len(),
})?
.load(Ordering::Relaxed));
return Ok(self.fillable_slots.get_res(i)?.load(Ordering::Relaxed));
}
}
}

View File

@@ -22,7 +22,7 @@ use crate::static_data::TypeIdentifier;
use crate::static_data::{Ability, Statistic};
use crate::static_data::{ClampedStatisticSet, StatisticSet};
use crate::utils::Random;
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier};
use crate::{script_hook, PkmnError, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
use anyhow::{anyhow, bail, Result};
/// An individual Pokemon as we know and love them.
@@ -595,16 +595,17 @@ impl Pokemon {
}
/// Sets whether or not the Pokemon is on the battlefield.
pub fn set_on_battlefield(&self, value: bool) {
pub fn set_on_battlefield(&self, value: bool) -> Result<()> {
let r = self.battle_data.read();
if let Some(data) = &mut r.deref() {
data.on_battle_field.store(value, Ordering::SeqCst);
if !value {
self.volatile.clear();
self.volatile.clear()?;
self.weight.store(self.form().weight(), Ordering::SeqCst);
self.height.store(self.form().height(), Ordering::SeqCst);
}
}
Ok(())
}
/// Sets the index of the slot of the side the Pokemon is on.
@@ -676,11 +677,7 @@ impl Pokemon {
if !battle.can_slot_be_filled(battle_data.battle_side_index(), battle_data.index()) {
battle
.sides()
.get(battle_data.battle_side_index() as usize)
.ok_or(PkmnError::IndexOutOfBounds {
index: battle_data.battle_side_index() as usize,
len: battle.sides().len(),
})?
.get_res(battle_data.battle_side_index() as usize)?
.mark_slot_as_unfillable(battle_data.index())?;
}
@@ -721,9 +718,12 @@ impl Pokemon {
pub fn learn_move(&self, move_name: &StringKey, learn_method: MoveLearnMethod) -> Result<()> {
let mut learned_moves = self.learned_moves().write();
let move_pos = learned_moves.iter().position(|a| a.is_none());
if move_pos.is_none() {
bail!("No more moves with an empty space found.");
}
let move_pos = match move_pos {
Some(a) => a,
None => {
bail!("No more moves with an empty space found.");
}
};
let move_data = self
.library
.static_data()
@@ -732,7 +732,9 @@ impl Pokemon {
.ok_or(PkmnError::InvalidMoveName {
move_name: move_name.clone(),
})?;
learned_moves[move_pos.unwrap()] = Some(Arc::new(LearnedMove::new(move_data, learn_method)));
learned_moves
.get_mut_res(move_pos)?
.replace(Arc::new(LearnedMove::new(move_data, learn_method)));
Ok(())
}
@@ -805,7 +807,10 @@ impl ScriptSource for Pokemon {
let mut c = 3;
if let Some(battle_data) = &self.battle_data.read().deref() {
if let Some(battle) = battle_data.battle() {
c += battle.sides()[battle_data.battle_side_index() as usize].get_script_count()?;
c += battle
.sides()
.get_res(battle_data.battle_side_index() as usize)?
.get_script_count()?;
}
}
Ok(c)
@@ -826,7 +831,10 @@ impl ScriptSource for Pokemon {
self.get_own_scripts(scripts);
if let Some(battle_data) = &self.battle_data.read().deref() {
if let Some(battle) = battle_data.battle() {
battle.sides()[battle_data.battle_side_index() as usize].collect_scripts(scripts)?;
battle
.sides()
.get_res(battle_data.battle_side_index() as usize)?
.collect_scripts(scripts)?;
}
}
Ok(())
@@ -862,6 +870,7 @@ pub enum DamageSource {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
pub mod test {
use crate::dynamic_data::libraries::test::MockDynamicLibrary;
use crate::dynamic_data::models::pokemon::Pokemon;

View File

@@ -5,7 +5,7 @@ use crate::dynamic_data::models::learned_move::MoveLearnMethod;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::DynamicLibrary;
use crate::static_data::{AbilityIndex, Gender};
use crate::{Random, StringKey};
use crate::{PkmnError, Random, StringKey};
use anyhow::Result;
/// This allows for the easy chain building of a Pokemon.
@@ -47,7 +47,12 @@ impl PokemonBuilder {
Random::default()
};
let species = self.library.static_data().species().get(&self.species).unwrap();
let species = self
.library
.static_data()
.species()
.get(&self.species)
.ok_or(PkmnError::InvalidSpeciesName { species: self.species })?;
let form = species.get_default_form();
let p = Pokemon::new(
self.library,

View File

@@ -1,9 +1,10 @@
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};
use crate::{ValueIdentifiable, ValueIdentifier, VecExt};
/// A list of Pokemon belonging to a trainer.
#[derive(Debug)]
@@ -52,14 +53,17 @@ impl PokemonParty {
}
/// Sets the Pokemon at an index to a Pokemon, returning the old Pokemon.
pub fn swap_into(&self, index: usize, pokemon: Option<Arc<Pokemon>>) -> Option<Arc<Pokemon>> {
pub fn swap_into(&self, index: usize, pokemon: Option<Arc<Pokemon>>) -> Result<Option<Arc<Pokemon>>> {
let mut party = self.pokemon.write();
if index >= party.len() {
return pokemon;
return Ok(pokemon);
}
let old = party[index].as_ref().cloned();
party[index] = pokemon;
old
let value = party.get_mut_res(index)?;
let old = match pokemon {
Some(p) => value.replace(p),
None => value.take(),
};
Ok(old)
}
/// Whether or not the party still has Pokemon that can be used in battle.
@@ -83,18 +87,18 @@ impl PokemonParty {
}
/// Makes sure there are no empty spots in the party anymore, leaving the length the same.
pub fn pack_party(&self) {
pub fn pack_party(&self) -> Result<()> {
let mut first_empty = None;
let mut i = 0;
let mut party = self.pokemon.write();
loop {
if party[i].is_none() {
if party.get_res(i)?.is_none() {
if first_empty.is_none() {
first_empty = Some(i)
}
} else if first_empty.is_some() {
party.swap(first_empty.unwrap(), i);
i = first_empty.unwrap();
} else if let Some(f) = first_empty {
party.swap(f, i);
i = f;
first_empty = None;
}
i += 1;
@@ -102,6 +106,7 @@ impl PokemonParty {
break;
}
}
Ok(())
}
/// Checks if the party contains a given pokemon.