Complete refactor of the FFI to use handles instead of pointers.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-06-24 14:44:23 +02:00
parent 4c222cb753
commit 78bb91093b
76 changed files with 1510 additions and 1952 deletions

View File

@@ -21,13 +21,11 @@ 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, VecExt};
use crate::{script_hook, PkmnError, StringKey, VecExt};
/// The data of a battle.
#[derive(Debug)]
struct BattleData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The library the battle uses for handling.
library: Arc<dyn DynamicLibrary>,
/// A list of all different parties in the battle.
@@ -99,7 +97,6 @@ impl Battle {
}
let battle = BattleData {
identifier: Default::default(),
library,
parties,
can_flee,
@@ -127,13 +124,6 @@ impl Battle {
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<dyn DynamicLibrary> {
&self.data.library
@@ -272,7 +262,7 @@ impl Battle {
}
/// Try and set the choice for the battle. If the choice is not valid, this returns false.
pub fn try_set_choice(&self, choice: TurnChoice) -> Result<bool> {
pub fn try_set_choice(&self, choice: Arc<TurnChoice>) -> Result<bool> {
if !self.can_use(&choice) {
return Ok(false);
}
@@ -380,6 +370,23 @@ impl Battle {
Ok(None)
}
}
/// Returns a weak reference to the battle.
pub fn weak(&self) -> WeakBattleReference {
WeakBattleReference {
data: Arc::downgrade(&self.data),
}
}
pub fn as_ptr(&self) -> *const c_void {
Arc::as_ptr(&self.data) as *const c_void
}
}
impl PartialEq for Battle {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.data, &other.data)
}
}
impl WeakBattleReference {
@@ -437,12 +444,6 @@ impl ScriptSource for Battle {
}
}
impl ValueIdentifiable for Battle {
fn value_identifier(&self) -> ValueIdentifier {
self.data.identifier
}
}
/// The result of a battle.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BattleResult {

View File

@@ -3,14 +3,11 @@ use std::sync::Arc;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::models::pokemon_party::PokemonParty;
use crate::{ValueIdentifiable, ValueIdentifier};
/// A battle party is a wrapper around a party, with the indices for which the party is responsible
/// on the field attached.
#[derive(Debug)]
pub struct BattleParty {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The party the BattleParty is holding.
party: Arc<PokemonParty>,
/// The indices for which the party is responsible, in the format (side, index)
@@ -22,7 +19,6 @@ impl BattleParty {
/// for.
pub fn new(party: Arc<PokemonParty>, responsible_indices: Vec<(u8, u8)>) -> Result<Self> {
Ok(Self {
identifier: Default::default(),
party,
responsible_indices,
})
@@ -58,9 +54,3 @@ impl BattleParty {
&self.party
}
}
impl ValueIdentifiable for BattleParty {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@@ -6,13 +6,11 @@ use crate::dynamic_data::models::executing_move::ExecutingMove;
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::dynamic_data::script_handling::ScriptSource;
use crate::utils::Random;
use crate::{script_hook, PkmnError, ValueIdentifiable, ValueIdentifier};
use crate::{script_hook, PkmnError};
/// The RNG for a battle.
#[derive(Default)]
pub struct BattleRandom {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The actual underlying RNG. This is in a mutex, so it is thread safe, and can be ran
/// predictably, with guaranteed the same outputs.
random: Mutex<Random>,
@@ -22,7 +20,6 @@ impl BattleRandom {
/// Initializes a new RNG with a given seed.
pub fn new_with_seed(seed: u128) -> Self {
BattleRandom {
identifier: Default::default(),
random: Mutex::new(Random::new(seed)),
}
}
@@ -104,8 +101,6 @@ impl Debug for BattleRandom {
impl Clone for BattleRandom {
fn clone(&self) -> Self {
Self {
identifier: Default::default(),
// As cloning when we can't get a lock on the randomness is completely impossible, we
// should unwrap here.
#[allow(clippy::unwrap_used)]
@@ -113,9 +108,3 @@ impl Clone for BattleRandom {
}
}
}
impl ValueIdentifiable for BattleRandom {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@@ -15,13 +15,11 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
use crate::dynamic_data::ScriptSet;
use crate::dynamic_data::VolatileScriptsOwner;
use crate::dynamic_data::{Script, WeakBattleReference};
use crate::{script_hook, StringKey, ValueIdentifiable, ValueIdentifier, VecExt};
use crate::{script_hook, StringKey, VecExt};
/// The data that is stored for a battle side.
#[derive(Debug)]
struct BattleSideData {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The index of the side on the battle.
index: u8,
/// The number of Pokemon that can be on the side.
@@ -47,7 +45,7 @@ struct BattleSideData {
}
/// A side on a battle.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct BattleSide {
/// The data that is stored for this side.
data: Arc<BattleSideData>,
@@ -77,7 +75,6 @@ impl BattleSide {
Self {
data: Arc::new(BattleSideData {
identifier: Default::default(),
index,
pokemon_per_side,
pokemon,
@@ -171,11 +168,11 @@ impl BattleSide {
}
/// Sets a choice for a Pokemon on this side.
pub(crate) fn set_choice(&self, choice: TurnChoice) -> Result<()> {
pub(crate) fn set_choice(&self, choice: Arc<TurnChoice>) -> Result<()> {
for (index, pokemon_slot) in self.data.pokemon.read().iter().enumerate() {
if let Some(pokemon) = pokemon_slot {
if Pokemon::eq(pokemon, choice.user()) {
self.data.choices.write().get_mut_res(index)?.replace(choice.into());
self.data.choices.write().get_mut_res(index)?.replace(choice);
self.data.choices_set.fetch_add(1, Ordering::SeqCst);
return Ok(());
}
@@ -337,7 +334,7 @@ impl BattleSide {
None => return Ok(false),
};
// Don't allow swapping if different parties are responsible for the indices.
if party_a.value_identifier() != party_b.value_identifier() {
if !Arc::ptr_eq(party_a, party_b) {
return Ok(false);
}
@@ -356,6 +353,16 @@ impl BattleSide {
data: Arc::downgrade(&self.data),
}
}
pub fn as_ptr(&self) -> *const c_void {
Arc::as_ptr(&self.data) as *const c_void
}
}
impl PartialEq for BattleSide {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.data, &other.data)
}
}
impl WeakBattleSideReference {
@@ -411,9 +418,3 @@ impl ScriptSource for BattleSide {
self.battle()?.collect_scripts(scripts)
}
}
impl ValueIdentifiable for BattleSide {
fn value_identifier(&self) -> ValueIdentifier {
self.data.identifier
}
}

View File

@@ -12,13 +12,11 @@ use crate::dynamic_data::script_handling::{ScriptSource, ScriptSourceData, Scrip
use crate::dynamic_data::ScriptContainer;
use crate::dynamic_data::TargetList;
use crate::static_data::{MoveData, TypeIdentifier};
use crate::{PkmnError, ValueIdentifiable, ValueIdentifier};
use crate::PkmnError;
/// 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,
/// Whether or not the hit is critical.
critical: AtomicBool,
/// The base power of the hit.
@@ -89,8 +87,6 @@ impl HitData {
#[derive(Debug)]
pub struct ExecutingMove {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The number of hits this move has.
number_of_hits: u8,
/// A list of hits for this move. For multi target multi hit moves, this stores the hits linearly,
@@ -126,7 +122,6 @@ impl ExecutingMove {
hits.push(Arc::new(HitData::default()))
}
Self {
identifier: Default::default(),
number_of_hits,
hits,
user,
@@ -238,15 +233,3 @@ impl ScriptSource for ExecutingMove {
Ok(())
}
}
impl ValueIdentifiable for ExecutingMove {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
impl ValueIdentifiable for HitData {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}

View File

@@ -2,14 +2,11 @@ use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use crate::static_data::MoveData;
use crate::{ValueIdentifiable, ValueIdentifier};
/// A learned move is the data attached to a Pokemon for a move it has learned. It has information
/// such as the remaining amount of users, how it has been learned, etc.
#[derive(Debug)]
pub struct LearnedMove {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The immutable move information of the move.
move_data: Arc<dyn MoveData>,
/// The maximal power points for this move.
@@ -36,7 +33,6 @@ impl LearnedMove {
pub fn new(move_data: Arc<dyn MoveData>, learn_method: MoveLearnMethod) -> Self {
let max_pp = move_data.base_usages();
Self {
identifier: Default::default(),
move_data,
max_pp,
remaining_pp: AtomicU8::new(max_pp),
@@ -92,12 +88,6 @@ impl LearnedMove {
}
}
impl ValueIdentifiable for LearnedMove {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {

View File

@@ -26,13 +26,11 @@ 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, VecExt};
use crate::{script_hook, PkmnError, StringKey, VecExt};
use anyhow::{anyhow, bail, Result};
/// 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.
library: Arc<dyn DynamicLibrary>,
/// The species of the Pokemon.
@@ -165,7 +163,6 @@ impl Pokemon {
.get_nature(nature)
.ok_or(PkmnError::InvalidNatureName { nature: nature.clone() })?;
let pokemon_data = PokemonData {
identifier: Default::default(),
library,
species: RwLock::new(species),
form: RwLock::new(form.clone()),
@@ -546,7 +543,7 @@ impl Pokemon {
/// Change the form of the Pokemon.
pub fn change_form(&self, form: &Arc<dyn Form>) -> Result<()> {
if self.form().value_identifier() == form.value_identifier() {
if Arc::ptr_eq(&self.form(), form) {
return Ok(());
}
*self.data.form.write() = form.clone();
@@ -818,6 +815,10 @@ impl Pokemon {
data: Arc::downgrade(&self.data),
}
}
pub fn as_ptr(&self) -> *const c_void {
Arc::as_ptr(&self.data) as *const c_void
}
}
impl PartialEq for Pokemon {
@@ -938,12 +939,6 @@ impl VolatileScriptsOwner for Pokemon {
}
}
impl ValueIdentifiable for Pokemon {
fn value_identifier(&self) -> ValueIdentifier {
self.data.identifier
}
}
/// A source of damage. This should be as unique as possible.
#[derive(Debug, Clone, Copy)]
#[repr(u8)]

View File

@@ -3,13 +3,11 @@ use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::{RawRwLock, RwLock};
use crate::dynamic_data::models::pokemon::Pokemon;
use crate::{ValueIdentifiable, ValueIdentifier, VecExt};
use crate::VecExt;
/// A list of Pokemon belonging to a trainer.
#[derive(Debug)]
pub struct PokemonParty {
/// A unique identifier so we know what value this is.
identifier: ValueIdentifier,
/// The underlying list of Pokemon.
pokemon: RwLock<Vec<Option<Pokemon>>>,
}
@@ -22,7 +20,6 @@ impl PokemonParty {
pokemon.push(None);
}
Self {
identifier: Default::default(),
pokemon: RwLock::new(pokemon),
}
}
@@ -30,7 +27,6 @@ impl PokemonParty {
/// Instantiates a party with a list.
pub fn new_from_vec(pokemon: Vec<Option<Pokemon>>) -> Self {
Self {
identifier: Default::default(),
pokemon: RwLock::new(pokemon),
}
}
@@ -118,9 +114,3 @@ impl PokemonParty {
false
}
}
impl ValueIdentifiable for PokemonParty {
fn value_identifier(&self) -> ValueIdentifier {
self.identifier
}
}