This commit is contained in:
102 files changed
+748
-202
No files matched your search
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+25
-25
@@ -1,4 +1,4 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
@@ -20,7 +20,7 @@ struct CommonChoiceData {
|
||||
random_value: u32,
|
||||
/// Whether or not the choice has failed. A failed choice will stop running, and execute special
|
||||
/// fail handling during turn execution.
|
||||
has_failed: bool,
|
||||
has_failed: AtomicBool,
|
||||
/// The data we can use to retrieve scripts that are affecting this choice. This will be written
|
||||
/// to once: when we need to initialize it. After that, this is only used to read. To prevent a
|
||||
/// read while we're writing to it, this is a RwLock.
|
||||
@@ -85,13 +85,13 @@ impl TurnChoice {
|
||||
/// Gets whether or not the choice has failed. If we notice this when we execute the choice, we
|
||||
/// will not execute it.
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.choice_data().has_failed
|
||||
self.choice_data().has_failed.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// Fails the choice. This will prevent it from executing and run a specific fail handling during
|
||||
/// execution. Note that this can not be undone.
|
||||
pub fn fail(&mut self) {
|
||||
self.choice_data_mut().has_failed = true
|
||||
pub fn fail(&self) {
|
||||
self.choice_data().has_failed.store(true, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// The random value of a turn choice gets set during the start of a choice, and is used for tie
|
||||
@@ -188,7 +188,7 @@ impl MoveChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -259,7 +259,7 @@ impl ItemChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -297,7 +297,7 @@ impl SwitchChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -335,7 +335,7 @@ impl FleeChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -373,7 +373,7 @@ impl PassChoice {
|
||||
user,
|
||||
speed: 0,
|
||||
random_value: 0,
|
||||
has_failed: false,
|
||||
has_failed: Default::default(),
|
||||
script_source_data: Default::default(),
|
||||
}),
|
||||
}
|
||||
@@ -405,68 +405,68 @@ impl PartialEq<Self> for TurnChoice {
|
||||
impl Eq for TurnChoice {}
|
||||
|
||||
impl PartialOrd for TurnChoice {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TurnChoice {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
match self {
|
||||
TurnChoice::Move(data) => {
|
||||
if let TurnChoice::Move(other_data) = other {
|
||||
let priority_compare = data.priority.cmp(&other_data.priority);
|
||||
if priority_compare != Ordering::Equal {
|
||||
if priority_compare != std::cmp::Ordering::Equal {
|
||||
return priority_compare;
|
||||
}
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Greater
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
TurnChoice::Item { .. } => {
|
||||
if let TurnChoice::Move { .. } = other {
|
||||
return Ordering::Less;
|
||||
return std::cmp::Ordering::Less;
|
||||
}
|
||||
if let TurnChoice::Item { .. } = other {
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Greater
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
TurnChoice::Switch { .. } => {
|
||||
if let TurnChoice::Move { .. } = other {
|
||||
return Ordering::Less;
|
||||
return std::cmp::Ordering::Less;
|
||||
}
|
||||
if let TurnChoice::Item { .. } = other {
|
||||
return Ordering::Less;
|
||||
return std::cmp::Ordering::Less;
|
||||
}
|
||||
if let TurnChoice::Switch { .. } = other {
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Greater
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
TurnChoice::Flee { .. } => {
|
||||
if let TurnChoice::Flee { .. } = other {
|
||||
let speed_compare = self.speed().cmp(&other.speed());
|
||||
if speed_compare != Ordering::Equal {
|
||||
if speed_compare != std::cmp::Ordering::Equal {
|
||||
return speed_compare;
|
||||
}
|
||||
return self.random_value().cmp(&other.random_value());
|
||||
}
|
||||
Ordering::Less
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
TurnChoice::Pass(..) => Ordering::Less,
|
||||
TurnChoice::Pass(..) => std::cmp::Ordering::Less,
|
||||
}
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+25
-16
@@ -1,5 +1,7 @@
|
||||
use crate::dynamic_data::choices::TurnChoice;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use parking_lot::lock_api::MappedRwLockReadGuard;
|
||||
use parking_lot::{RawRwLock, RwLock, RwLockReadGuard};
|
||||
|
||||
/// The ChoiceQueue is used to run choices one by one.
|
||||
///
|
||||
@@ -8,10 +10,11 @@ use crate::dynamic_data::Pokemon;
|
||||
/// helper functions to change the turn order while doing the execution. This is needed, as several
|
||||
/// moves in Pokemon actively mess with this order.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct ChoiceQueue {
|
||||
/// Our storage of turn choices. Starts out completely filled, then slowly empties as turns get
|
||||
/// executed.
|
||||
queue: Vec<Option<TurnChoice>>,
|
||||
queue: RwLock<Vec<Option<TurnChoice>>>,
|
||||
/// The current index of the turn we need to execute next.
|
||||
current: usize,
|
||||
}
|
||||
@@ -19,42 +22,47 @@ pub struct ChoiceQueue {
|
||||
impl ChoiceQueue {
|
||||
/// Initializes a ChoiceQueue. We expect the given queue to already be sorted here.
|
||||
pub(crate) fn new(queue: Vec<Option<TurnChoice>>) -> Self {
|
||||
Self { queue, current: 0 }
|
||||
Self {
|
||||
queue: RwLock::new(queue),
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeues the next turn choice to be executed. This gives ownership to the callee, and replaces
|
||||
/// our own reference to the turn choice with an empty spot. It also increments the current position
|
||||
/// by one.
|
||||
pub fn dequeue(&mut self) -> TurnChoice {
|
||||
let c = self.queue[self.current].take();
|
||||
let c = self.queue.write()[self.current].take();
|
||||
self.current += 1;
|
||||
c.unwrap()
|
||||
}
|
||||
|
||||
/// This reads what the next choice to execute will be, without modifying state.
|
||||
pub fn peek(&self) -> &TurnChoice {
|
||||
self.queue[self.current].as_ref().unwrap()
|
||||
pub fn peek(&self) -> MappedRwLockReadGuard<'_, RawRwLock, TurnChoice> {
|
||||
let read_lock = self.queue.read();
|
||||
RwLockReadGuard::map(read_lock, |a| a[self.current].as_ref().unwrap())
|
||||
}
|
||||
|
||||
/// Check if we have any choices remaining.
|
||||
pub fn has_next(&self) -> bool {
|
||||
self.current < self.queue.len()
|
||||
self.current < self.queue.read().len()
|
||||
}
|
||||
|
||||
/// This resorts the yet to be executed choices. This can be useful for dealing with situations
|
||||
/// such as Pokemon changing forms just after the very start of a turn, when turn order has
|
||||
/// technically already been decided.
|
||||
pub fn resort(&mut self) {
|
||||
let len = self.queue.len();
|
||||
self.queue[self.current..len].sort_unstable_by(|a, b| b.cmp(a));
|
||||
let len = self.queue.read().len();
|
||||
self.queue.write()[self.current..len].sort_unstable_by(|a, b| b.cmp(a));
|
||||
}
|
||||
|
||||
/// This moves the choice of a specific Pokemon up to the next choice to be executed.
|
||||
pub fn move_pokemon_choice_next(&mut self, pokemon: &Pokemon) -> bool {
|
||||
pub fn move_pokemon_choice_next(&self, pokemon: &Pokemon) -> bool {
|
||||
let mut queue_lock = self.queue.write();
|
||||
let mut desired_index = None;
|
||||
// Find the index for the choice we want to move up.
|
||||
for index in self.current..self.queue.len() {
|
||||
if let Some(choice) = &self.queue[index] {
|
||||
for index in self.current..queue_lock.len() {
|
||||
if let Some(choice) = &queue_lock[index] {
|
||||
if std::ptr::eq(choice.user().as_ref(), pokemon) {
|
||||
desired_index = Some(index);
|
||||
break;
|
||||
@@ -72,19 +80,20 @@ impl ChoiceQueue {
|
||||
}
|
||||
|
||||
// Take the choice we want to move forward out of it's place.
|
||||
let choice = self.queue[desired_index].take().unwrap();
|
||||
let choice = queue_lock[desired_index].take().unwrap();
|
||||
// Iterate backwards from the spot before the choice we want to move up, push them all back
|
||||
// by 1 spot.
|
||||
for index in (desired_index - 1)..self.current {
|
||||
self.queue.swap(index, index + 1);
|
||||
queue_lock.swap(index, index + 1);
|
||||
}
|
||||
// Place the choice that needs to be next in the next to be executed position.
|
||||
let _ = self.queue[self.current].insert(choice);
|
||||
let _ = queue_lock[self.current].insert(choice);
|
||||
true
|
||||
}
|
||||
|
||||
/// Internal helper function to be easily able to iterate over the yet to be executed choices.
|
||||
pub(crate) fn get_queue(&self) -> &[Option<TurnChoice>] {
|
||||
&self.queue[self.current..self.queue.len()]
|
||||
pub(crate) fn get_queue(&self) -> MappedRwLockReadGuard<'_, RawRwLock, [Option<TurnChoice>]> {
|
||||
let read_lock = self.queue.read();
|
||||
RwLockReadGuard::map(read_lock, |a| &a[self.current..self.queue.read().len()])
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+2
-2
@@ -5,8 +5,8 @@ use crate::dynamic_data::libraries::battle_stat_calculator::BattleStatCalculator
|
||||
use crate::dynamic_data::libraries::damage_library::DamageLibrary;
|
||||
use crate::dynamic_data::libraries::misc_library::MiscLibrary;
|
||||
use crate::dynamic_data::libraries::script_resolver::ScriptCategory;
|
||||
use crate::dynamic_data::Script;
|
||||
use crate::dynamic_data::{ItemScript, ScriptResolver};
|
||||
use crate::dynamic_data::{Script, ScriptOwnerData};
|
||||
use crate::static_data::Item;
|
||||
use crate::static_data::StaticData;
|
||||
use crate::{PkmnResult, StringKey};
|
||||
@@ -75,7 +75,7 @@ impl DynamicLibrary {
|
||||
/// can be created with this combination, returns None.
|
||||
pub fn load_script(
|
||||
&self,
|
||||
owner: *const u8,
|
||||
owner: ScriptOwnerData,
|
||||
_category: ScriptCategory,
|
||||
_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+3
-3
@@ -1,7 +1,7 @@
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::dynamic_data::{ItemScript, Script};
|
||||
use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData};
|
||||
use crate::static_data::Item;
|
||||
use crate::{PkmnResult, StringKey};
|
||||
|
||||
@@ -13,7 +13,7 @@ pub trait ScriptResolver: Debug {
|
||||
/// can be created with this combination, returns None.
|
||||
fn load_script(
|
||||
&self,
|
||||
owner: *const u8,
|
||||
owner: ScriptOwnerData,
|
||||
category: ScriptCategory,
|
||||
script_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>>;
|
||||
@@ -58,7 +58,7 @@ pub struct EmptyScriptResolver {}
|
||||
impl ScriptResolver for EmptyScriptResolver {
|
||||
fn load_script(
|
||||
&self,
|
||||
_owner: *const u8,
|
||||
_owner: ScriptOwnerData,
|
||||
_category: ScriptCategory,
|
||||
_script_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+2
-3
@@ -194,7 +194,7 @@ impl Battle {
|
||||
let mut winning_side = None;
|
||||
for (side_index, side) in self.sides.iter().enumerate() {
|
||||
// If any side has fled, the battle end.
|
||||
if side.has_fled() {
|
||||
if side.has_fled_battle() {
|
||||
let _w = self.result.write();
|
||||
unsafe {
|
||||
self.result.data_ptr().replace(BattleResult::Inconclusive);
|
||||
@@ -339,8 +339,7 @@ impl VolatileScriptsOwner for Battle {
|
||||
}
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
self.library
|
||||
.load_script((self as *const Self).cast(), ScriptCategory::Battle, key)
|
||||
self.library.load_script(self.into(), ScriptCategory::Battle, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+6
@@ -6,6 +6,7 @@ use crate::dynamic_data::models::pokemon_party::PokemonParty;
|
||||
/// A battle party is a wrapper around a party, with the indices for which the party is responsible
|
||||
/// on the field attached.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct BattleParty {
|
||||
/// The party the BattleParty is holding.
|
||||
party: Arc<PokemonParty>,
|
||||
@@ -47,4 +48,9 @@ impl BattleParty {
|
||||
pub fn get_pokemon(&self, index: usize) -> &Option<Arc<Pokemon>> {
|
||||
self.party.at(index)
|
||||
}
|
||||
|
||||
/// Gets the underlying Pokemon Party
|
||||
pub fn party(&self) -> &Arc<PokemonParty> {
|
||||
&self.party
|
||||
}
|
||||
}
|
||||
Regular → Executable
+1
@@ -9,6 +9,7 @@ use crate::utils::Random;
|
||||
|
||||
/// The RNG for a battle.
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct BattleRandom {
|
||||
/// The actual underlying RNG. This is in a mutex, so it is thread safe, and can be ran
|
||||
/// predictably, with guaranteed the same outputs.
|
||||
|
||||
Regular → Executable
+2
-6
@@ -18,6 +18,7 @@ use crate::{script_hook, PkmnResult, StringKey};
|
||||
|
||||
/// A side on a battle.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct BattleSide {
|
||||
/// The index of the side on the battle.
|
||||
index: u8,
|
||||
@@ -239,11 +240,6 @@ impl BattleSide {
|
||||
true
|
||||
}
|
||||
|
||||
/// Checks whether the side has fled.
|
||||
pub fn has_fled(&self) -> bool {
|
||||
self.has_fled_battle
|
||||
}
|
||||
|
||||
/// Mark the side as fled.
|
||||
pub fn mark_as_fled(&mut self) {
|
||||
self.has_fled_battle = true;
|
||||
@@ -304,7 +300,7 @@ impl VolatileScriptsOwner for BattleSide {
|
||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
self.battle()
|
||||
.library()
|
||||
.load_script((self as *const Self).cast(), crate::ScriptCategory::Side, key)
|
||||
.load_script(self.into(), crate::ScriptCategory::Side, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
+2
-1
@@ -15,6 +15,7 @@ use crate::{PkmnResult, PokemonError};
|
||||
|
||||
/// A hit data is the data for a single hit, on a single target.
|
||||
#[derive(Default, Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct HitData {
|
||||
/// Whether or not the hit is critical.
|
||||
critical: AtomicBool,
|
||||
@@ -158,7 +159,7 @@ impl ExecutingMove {
|
||||
}
|
||||
|
||||
/// Gets a hit data for a target, with a specific index.
|
||||
pub fn get_hit_data<'func>(&'func self, for_target: &'func Arc<Pokemon>, hit: u8) -> PkmnResult<&'func HitData> {
|
||||
pub fn get_hit_data(&self, for_target: &Pokemon, hit: u8) -> PkmnResult<&HitData> {
|
||||
for (index, target) in self.targets.iter().enumerate() {
|
||||
if let Some(target) = target {
|
||||
if std::ptr::eq(target.deref().deref(), for_target.deref().deref()) {
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+2
-7
@@ -502,11 +502,7 @@ impl Pokemon {
|
||||
|
||||
let ability_script = self
|
||||
.library
|
||||
.load_script(
|
||||
(self as *const Self).cast(),
|
||||
ScriptCategory::Ability,
|
||||
self.active_ability().name(),
|
||||
)
|
||||
.load_script((&*self).into(), ScriptCategory::Ability, self.active_ability().name())
|
||||
.unwrap();
|
||||
if let Some(ability_script) = ability_script {
|
||||
self.ability_script
|
||||
@@ -772,8 +768,7 @@ impl VolatileScriptsOwner for Pokemon {
|
||||
}
|
||||
|
||||
fn load_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
self.library
|
||||
.load_script((self as *const Self).cast(), ScriptCategory::Pokemon, key)
|
||||
self.library.load_script(self.into(), ScriptCategory::Pokemon, key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+13
@@ -4,6 +4,7 @@ use crate::dynamic_data::models::pokemon::Pokemon;
|
||||
|
||||
/// A list of Pokemon belonging to a trainer.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))]
|
||||
pub struct PokemonParty {
|
||||
/// The underlying list of Pokemon.
|
||||
pokemon: Vec<Option<Arc<Pokemon>>>,
|
||||
@@ -89,4 +90,16 @@ impl PokemonParty {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the party contains a given pokemon.
|
||||
pub fn has_pokemon(&self, pokemon: &Pokemon) -> bool {
|
||||
for p in &self.pokemon {
|
||||
if let Some(p) = p {
|
||||
if std::ptr::eq(p.as_ref(), pokemon) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+32
-2
@@ -1,17 +1,17 @@
|
||||
use std::any::Any;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
|
||||
|
||||
use crate::dynamic_data::choices::TurnChoice;
|
||||
use crate::dynamic_data::DamageSource;
|
||||
use crate::dynamic_data::ExecutingMove;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use crate::dynamic_data::{Battle, DynamicLibrary};
|
||||
use crate::dynamic_data::{BattleSide, DamageSource};
|
||||
use crate::static_data::{EffectParameter, TypeIdentifier};
|
||||
use crate::static_data::{Item, Statistic};
|
||||
use crate::StringKey;
|
||||
@@ -543,3 +543,33 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Data to store references to their owning objects on scripts.
|
||||
pub enum ScriptOwnerData {
|
||||
/// A script attached to a Pokemon has a reference to that Pokemon.
|
||||
Pokemon(AtomicPtr<Pokemon>),
|
||||
/// A script attached to a Battle Side has a reference to that Battle Side.
|
||||
BattleSide(AtomicPtr<BattleSide>),
|
||||
/// A script attached to a Battle has a reference to that Battle.
|
||||
Battle(AtomicPtr<Battle>),
|
||||
/// A script also can have no owner.
|
||||
None,
|
||||
}
|
||||
|
||||
impl Into<ScriptOwnerData> for &Pokemon {
|
||||
fn into(self) -> ScriptOwnerData {
|
||||
ScriptOwnerData::Pokemon(AtomicPtr::new(self as *const Pokemon as *mut Pokemon))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ScriptOwnerData> for &BattleSide {
|
||||
fn into(self) -> ScriptOwnerData {
|
||||
ScriptOwnerData::BattleSide(AtomicPtr::new(self as *const BattleSide as *mut BattleSide))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ScriptOwnerData> for &Battle {
|
||||
fn into(self) -> ScriptOwnerData {
|
||||
ScriptOwnerData::Battle(AtomicPtr::new(self as *const Battle as *mut Battle))
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+8
-2
@@ -22,13 +22,19 @@ pub trait VolatileScriptsOwner {
|
||||
}
|
||||
|
||||
/// Adds a volatile script by name.
|
||||
fn add_volatile_script(&mut self, key: &StringKey) -> PkmnResult<Option<ScriptContainer>> {
|
||||
fn add_volatile_script(&self, key: &StringKey) -> PkmnResult<Option<ScriptContainer>> {
|
||||
self.volatile_scripts()
|
||||
.stack_or_add(key, &|| self.load_volatile_script(key))
|
||||
}
|
||||
|
||||
/// Adds a volatile script by name.
|
||||
fn add_volatile_script_with_script(&self, script: Arc<dyn Script>) -> PkmnResult<Option<ScriptContainer>> {
|
||||
self.volatile_scripts()
|
||||
.stack_or_add(&script.name().clone(), &|| Ok(Some(script.clone())))
|
||||
}
|
||||
|
||||
/// Removes a volatile script by name.
|
||||
fn remove_volatile_script(&mut self, key: &StringKey) {
|
||||
fn remove_volatile_script(&self, key: &StringKey) {
|
||||
self.volatile_scripts().remove(key)
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
@@ -0,0 +1,71 @@
|
||||
use crate::dynamic_data::{
|
||||
Battle, BattleParty, BattleRandom, BattleSide, ChoiceQueue, DynamicLibrary, Pokemon, PokemonParty,
|
||||
};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef};
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn battle_get_parties(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> VecExternRef<BattleParty> {
|
||||
VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env).unwrap().parties())
|
||||
}
|
||||
|
||||
fn battle_get_choice_queue(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> ExternRef<ChoiceQueue> {
|
||||
let queue = battle.value_func(&env).unwrap().current_turn_queue().read();
|
||||
if let Some(queue) = queue.as_ref() {
|
||||
ExternRef::func_new(&env, queue)
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn battle_get_library(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> ExternRef<DynamicLibrary> {
|
||||
ExternRef::func_new(&env, battle.value_func(&env).unwrap().library().as_ref())
|
||||
}
|
||||
|
||||
fn battle_get_sides(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> VecExternRef<BattleSide> {
|
||||
VecExternRef::new(env.data().data().as_ref(), battle.value_func(&env).unwrap().sides())
|
||||
}
|
||||
|
||||
fn battle_get_random(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
) -> ExternRef<BattleRandom> {
|
||||
ExternRef::func_new(&env, battle.value_func(&env).unwrap().random())
|
||||
}
|
||||
|
||||
fn battle_find_party_for_pokemon(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle: ExternRef<Battle>,
|
||||
pokemon: ExternRef<Pokemon>
|
||||
) -> ExternRef<BattleParty> {
|
||||
let battle = battle.value_func(&env).unwrap();
|
||||
let pokemon = pokemon.value_func(&env).unwrap();
|
||||
for party in battle.parties() {
|
||||
if party.party().has_pokemon(pokemon) {
|
||||
return ExternRef::func_new(&env, party);
|
||||
}
|
||||
}
|
||||
ExternRef::null()
|
||||
}
|
||||
|
||||
fn battle_party_get_party(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_party: ExternRef<BattleParty>,
|
||||
) -> ExternRef<PokemonParty> {
|
||||
ExternRef::func_new(&env, battle_party.value_func(&env).unwrap().party().as_ref())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
use crate::dynamic_data::BattleRandom;
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
|
||||
register! {
|
||||
fn battle_random_get(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<BattleRandom>,
|
||||
) -> i32 {
|
||||
battle_random.value_func(&env).unwrap().get()
|
||||
}
|
||||
fn battle_random_get_max(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<BattleRandom>,
|
||||
max: i32
|
||||
) -> i32 {
|
||||
battle_random.value_func(&env).unwrap().get_max(max)
|
||||
}
|
||||
fn battle_random_get_between(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<BattleRandom>,
|
||||
min: i32,
|
||||
max: i32
|
||||
) -> i32 {
|
||||
battle_random.value_func(&env).unwrap().get_between(min, max)
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
use crate::dynamic_data::{Battle, BattleSide, Pokemon, VolatileScriptsOwner};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script::WebAssemblyScript;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::{ScriptCategory, StringKey};
|
||||
use std::ffi::CString;
|
||||
use wasmer::{FunctionEnvMut, Value};
|
||||
|
||||
register! {
|
||||
fn battleside_has_fled_battle(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
if side.value_func(&env).unwrap().has_fled_battle() { 1 } else { 0 }
|
||||
}
|
||||
|
||||
fn battleside_is_defeated(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
if side.value_func(&env).unwrap().is_defeated() { 1 } else { 0 }
|
||||
}
|
||||
|
||||
fn battleside_get_side_index(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
side.value_func(&env).unwrap().index()
|
||||
}
|
||||
|
||||
fn battleside_get_pokemon_per_side(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> u8 {
|
||||
side.value_func(&env).unwrap().pokemon_per_side()
|
||||
}
|
||||
|
||||
fn battleside_get_battle(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
) -> ExternRef<Battle> {
|
||||
ExternRef::func_new(&env, side.value_func(&env).unwrap().battle())
|
||||
}
|
||||
|
||||
fn battleside_get_pokemon(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
index: u32
|
||||
) -> ExternRef<Pokemon> {
|
||||
if let Some(Some(p)) = side.value_func(&env).unwrap().pokemon().get(index as usize) {
|
||||
ExternRef::func_new(&env, p.as_ref())
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn battleside_add_volatile_by_name(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
name_ptr: u32
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let c_name = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
let script = side.value_func(&env).unwrap().add_volatile_script(&c_name.into()).unwrap();
|
||||
if let Some(script) = script {
|
||||
let script = script.get_as::<WebAssemblyScript>();
|
||||
script.get_wasm_pointer()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn battleside_add_volatile(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
script_ptr: u32
|
||||
) -> u32 {
|
||||
let side = side.value_func(&env).unwrap();
|
||||
let name_ptr = env.data().data().exported_functions().get(&StringKey::new("script_get_name")).unwrap().call(&mut env.data().data().store_mut(), &[Value::I32(script_ptr as i32)]).unwrap().get(0).unwrap().i32().unwrap() as u32;
|
||||
unsafe{
|
||||
let name_ptr: CString = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
let script = env.data().data().setup_script(script_ptr, ScriptCategory::Side, &name_ptr.into(), side.into()).unwrap();
|
||||
if let Some(script) = script {
|
||||
let script = side.add_volatile_script_with_script(script);
|
||||
script.unwrap().unwrap().get_as::<WebAssemblyScript>().get_wasm_pointer()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn battleside_get_volatile(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
name_ptr: u32
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let c_name = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
let script = side.value_func(&env).unwrap().get_volatile_script(&c_name.into());
|
||||
if let Some(script) = script {
|
||||
let script = script.get_as::<WebAssemblyScript>();
|
||||
script.get_wasm_pointer()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn battleside_remove_volatile(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
side: ExternRef<BattleSide>,
|
||||
name_ptr: u32
|
||||
) {
|
||||
unsafe {
|
||||
let c_name = CString::from_raw(env.data().data().get_raw_pointer(name_ptr));
|
||||
side.value_func(&env).unwrap().remove_volatile_script(&c_name.into());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use crate::dynamic_data::{ChoiceQueue, Pokemon};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn choice_queue_move_pokemon_choice_next(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
battle_random: ExternRef<ChoiceQueue>,
|
||||
pokemon: ExternRef<Pokemon>
|
||||
) -> u8 {
|
||||
if battle_random.value_func(&env).unwrap().move_pokemon_choice_next(pokemon.value_func(&env).unwrap()) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use crate::dynamic_data::{ExecutingMove, HitData, LearnedMove, Pokemon};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::MoveData;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn executing_move_get_user(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> ExternRef<Pokemon> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().user().as_ref())
|
||||
}
|
||||
|
||||
fn executing_move_get_use_move(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> ExternRef<MoveData> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().use_move().as_ref())
|
||||
}
|
||||
|
||||
fn executing_move_get_chosen_move(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> ExternRef<LearnedMove> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().chosen_move().as_ref())
|
||||
}
|
||||
|
||||
fn executing_move_get_number_of_hits(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
) -> u8 {
|
||||
executing_move.value_func(&env).unwrap().number_of_hits()
|
||||
}
|
||||
|
||||
fn executing_move_get_hit_data(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
executing_move: ExternRef<ExecutingMove>,
|
||||
target: ExternRef<Pokemon>,
|
||||
hit: u8
|
||||
) -> ExternRef<HitData> {
|
||||
ExternRef::func_new(&env, executing_move.value_func(&env).unwrap().get_hit_data(target.value_func(&env).unwrap(), hit).unwrap())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use crate::dynamic_data::HitData;
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn hit_data_fail(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
hit: ExternRef<HitData>,
|
||||
) {
|
||||
hit.value_func(&env).unwrap().fail()
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+42
-6
@@ -1,31 +1,67 @@
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::dynamic_data::{DynamicLibrary, ScriptOwnerData};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use std::sync::atomic::Ordering;
|
||||
use wasmer::{FunctionEnv, FunctionEnvMut, Imports, StoreMut};
|
||||
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::StaticData;
|
||||
|
||||
mod battle_random;
|
||||
/// Battle side registration
|
||||
mod battle_side;
|
||||
mod choice_queue;
|
||||
mod executing_move;
|
||||
/// Learned move registration
|
||||
mod learned_move;
|
||||
mod party;
|
||||
/// Pokemon registration
|
||||
mod pokemon;
|
||||
/// Turn choice registration
|
||||
mod turn_choice;
|
||||
mod hit_data;
|
||||
mod battle;
|
||||
|
||||
register! {
|
||||
fn dynamic_library_get_static_data(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||
) -> ExternRef<StaticData> {
|
||||
ExternRef::func_new(&env, dynamic_lib.value_func(&env).unwrap().static_data())
|
||||
}
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||
) -> ExternRef<StaticData> {
|
||||
ExternRef::func_new(&env, dynamic_lib.value_func(&env).unwrap().static_data())
|
||||
}
|
||||
|
||||
fn script_get_owner(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
script: u32,
|
||||
) -> u32 {
|
||||
unsafe {
|
||||
let script = env.data().data().get_loaded_script(script);
|
||||
if let Some(script) = script {
|
||||
match script.get_owner() {
|
||||
ScriptOwnerData::Pokemon(p) => env.data().data().get_extern_ref_index(p.load(Ordering::Relaxed).as_ref().unwrap()),
|
||||
ScriptOwnerData::BattleSide(p) => env.data().data().get_extern_ref_index(p.load(Ordering::Relaxed).as_ref().unwrap()),
|
||||
ScriptOwnerData::Battle(p) => env.data().data().get_extern_ref_index(p.load(Ordering::Relaxed).as_ref().unwrap()),
|
||||
ScriptOwnerData::None => 0,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manual manual_register
|
||||
}
|
||||
|
||||
/// Additional required manual registration
|
||||
fn manual_register(imports: &mut Imports, store: &mut StoreMut, env: &FunctionEnv<WebAssemblyEnv>) {
|
||||
battle::register(imports, store, env);
|
||||
turn_choice::register(imports, store, env);
|
||||
pokemon::register(imports, store, env);
|
||||
learned_move::register(imports, store, env);
|
||||
battle_side::register(imports, store, env);
|
||||
battle_random::register(imports, store, env);
|
||||
choice_queue::register(imports, store, env);
|
||||
party::register(imports, store, env);
|
||||
executing_move::register(imports, store, env);
|
||||
hit_data::register(imports, store, env);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
use crate::dynamic_data::{Pokemon, PokemonParty};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn party_get_pokemon(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
party: ExternRef<PokemonParty>,
|
||||
index: u32
|
||||
) -> ExternRef<Pokemon> {
|
||||
if let Some(v) = &party.value_func(&env).unwrap().pokemon()[index as usize] {
|
||||
ExternRef::func_new(&env, v.as_ref())
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn party_get_length(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
party: ExternRef<PokemonParty>,
|
||||
) -> u32 {
|
||||
party.value_func(&env).unwrap().length() as u32
|
||||
}
|
||||
}
|
||||
Regular → Executable
+68
-2
@@ -1,11 +1,11 @@
|
||||
use std::mem::transmute;
|
||||
|
||||
use crate::dynamic_data::{DynamicLibrary, Pokemon};
|
||||
use crate::dynamic_data::{Battle, DynamicLibrary, LearnedMove, Pokemon};
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::StatisticSet;
|
||||
use crate::static_data::{ClampedStatisticSet, Species};
|
||||
use crate::static_data::{Item, StatisticSet};
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
@@ -75,4 +75,70 @@ register! {
|
||||
pokemon.value_func(&env).unwrap().damage(damage, transmute(source));
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_learned_move(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
index: u32
|
||||
) -> ExternRef<LearnedMove> {
|
||||
let read_lock = pokemon.value_func(&env).unwrap().learned_moves().read();
|
||||
let mv = read_lock.get(index as usize);
|
||||
if let Some(Some(mv)) = mv {
|
||||
ExternRef::func_new(&env, mv)
|
||||
}
|
||||
else{
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_change_stat_boost(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
stat: u8,
|
||||
amount: i8,
|
||||
self_inflicted: u8
|
||||
) -> u8 {
|
||||
unsafe{
|
||||
if pokemon.value_func(&env).unwrap().change_stat_boost(transmute(stat), amount, self_inflicted == 1) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_battle(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
) -> ExternRef<Battle> {
|
||||
if let Some(battle) = pokemon.value_func(&env).unwrap().get_battle() {
|
||||
ExternRef::func_new(&env, battle)
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_battle_side_index(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
) -> u8 {
|
||||
if let Some(i) = pokemon.value_func(&env).unwrap().get_battle_index() {
|
||||
i
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn pokemon_get_held_item(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
pokemon: ExternRef<Pokemon>,
|
||||
) -> ExternRef<Item> {
|
||||
let read_lock = pokemon.value_func(&env).unwrap().held_item().read();
|
||||
if let Some(item) = read_lock.as_ref() {
|
||||
ExternRef::func_new(&env, item.as_ref())
|
||||
} else {
|
||||
ExternRef::null()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Regular → Executable
+7
@@ -59,4 +59,11 @@ register! {
|
||||
panic!("Invalid turn choice");
|
||||
}
|
||||
|
||||
fn turn_choice_fail(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
turn_choice: ExternRef<TurnChoice>,
|
||||
) {
|
||||
turn_choice.value_func(&env).unwrap().fail();
|
||||
}
|
||||
|
||||
}
|
||||
Regular → Executable
File mode changed.
@@ -0,0 +1,38 @@
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::Item;
|
||||
use crate::StringKey;
|
||||
use std::mem::transmute;
|
||||
use wasmer::FunctionEnvMut;
|
||||
|
||||
register! {
|
||||
fn item_get_price(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
item: ExternRef<Item>,
|
||||
) -> i32 {
|
||||
item.value_func(&env).unwrap().price()
|
||||
}
|
||||
|
||||
fn item_get_name(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
item: ExternRef<Item>,
|
||||
) -> ExternRef<StringKey> {
|
||||
ExternRef::func_new(&env, item.value_func(&env).unwrap().name())
|
||||
}
|
||||
|
||||
fn item_get_category(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
item: ExternRef<Item>,
|
||||
) -> u8 {
|
||||
unsafe { transmute(item.value_func(&env).unwrap().category()) }
|
||||
|
||||
}
|
||||
|
||||
fn item_get_battle_category(
|
||||
env: FunctionEnvMut<WebAssemblyEnv>,
|
||||
item: ExternRef<Item>,
|
||||
) -> u8 {
|
||||
unsafe { transmute(item.value_func(&env).unwrap().battle_category()) }
|
||||
}
|
||||
}
|
||||
Regular → Executable
+2
@@ -6,6 +6,7 @@ use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::{ItemLibrary, LibrarySettings, MoveLibrary, SpeciesLibrary, StaticData, TypeLibrary};
|
||||
|
||||
mod item;
|
||||
/// Moves data registration
|
||||
mod moves;
|
||||
/// Species data registration
|
||||
@@ -49,4 +50,5 @@ register! {
|
||||
fn manual_registration(imports: &mut Imports, store: &mut StoreMut, env: &FunctionEnv<WebAssemblyEnv>) {
|
||||
moves::register(imports, store, env);
|
||||
species::register(imports, store, env);
|
||||
item::register(imports, store, env);
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+16
-5
@@ -1,10 +1,12 @@
|
||||
use std::any::Any;
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize};
|
||||
use std::sync::Arc;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
|
||||
use crate::dynamic_data::{Battle, DamageSource, DynamicLibrary, ExecutingMove, Pokemon, Script, TurnChoice};
|
||||
use crate::dynamic_data::{
|
||||
Battle, DamageSource, DynamicLibrary, ExecutingMove, Pokemon, Script, ScriptOwnerData, TurnChoice,
|
||||
};
|
||||
use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef};
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
|
||||
use crate::script_implementations::wasm::WebAssemblyScriptCapabilities;
|
||||
@@ -23,7 +25,7 @@ pub struct WebAssemblyScript {
|
||||
/// we will not execute its methods. This holds the number of suppressions on the script.
|
||||
suppressed_count: AtomicUsize,
|
||||
/// The owner of this script (where the script is attached to)
|
||||
_owner_ptr: AtomicPtr<u8>,
|
||||
owner: ScriptOwnerData,
|
||||
/// Pointer inside WebAssembly memory where the data is for this script.
|
||||
self_ptr: u32,
|
||||
/// Capabilities define which functions we actually implement.
|
||||
@@ -35,7 +37,7 @@ pub struct WebAssemblyScript {
|
||||
impl WebAssemblyScript {
|
||||
/// Instantiates a new WebAssemblyScript.
|
||||
pub fn new(
|
||||
owner_ptr: *mut u8,
|
||||
owner: ScriptOwnerData,
|
||||
self_ptr: u32,
|
||||
capabilities: Arc<HashSet<WebAssemblyScriptCapabilities>>,
|
||||
environment: Arc<WebAssemblyEnvironmentData>,
|
||||
@@ -45,18 +47,27 @@ impl WebAssemblyScript {
|
||||
name,
|
||||
marked_for_deletion: Default::default(),
|
||||
suppressed_count: Default::default(),
|
||||
_owner_ptr: AtomicPtr::new(owner_ptr),
|
||||
owner,
|
||||
self_ptr,
|
||||
capabilities,
|
||||
environment,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_wasm_pointer(&self) -> u32 {
|
||||
self.self_ptr
|
||||
}
|
||||
|
||||
/// Check if this script implements a certain capability.
|
||||
#[inline(always)]
|
||||
fn has_capability(&self, cap: &WebAssemblyScriptCapabilities) -> bool {
|
||||
self.capabilities.contains(cap)
|
||||
}
|
||||
|
||||
/// Gets the thing the script is owned by.
|
||||
pub fn get_owner(&self) -> &ScriptOwnerData {
|
||||
&self.owner
|
||||
}
|
||||
}
|
||||
|
||||
/// Util macro to reduce function call verbosity.
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
+100
-52
@@ -11,7 +11,7 @@ use wasmer::{
|
||||
Memory, Module, Store, StoreMut, StoreRef, TypedFunction, Value,
|
||||
};
|
||||
|
||||
use crate::dynamic_data::{ItemScript, Script, ScriptResolver};
|
||||
use crate::dynamic_data::{ItemScript, Script, ScriptOwnerData, ScriptResolver};
|
||||
use crate::script_implementations::wasm::export_registry::register_webassembly_funcs;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script::WebAssemblyScript;
|
||||
@@ -34,10 +34,6 @@ pub struct WebAssemblyScriptResolver {
|
||||
/// This is the WASM function to load a script.
|
||||
load_script_fn: Option<TypedFunction<(u8, ExternRef<StringKey>), u32>>,
|
||||
|
||||
/// Script capabilities tell us which functions are implemented on a given script. This allows us to skip unneeded
|
||||
/// WASM calls.
|
||||
script_capabilities: RwLock<HashMap<ScriptCapabilitiesKey, Arc<HashSet<WebAssemblyScriptCapabilities>>>>,
|
||||
|
||||
/// The data for use in the scripting function calls.
|
||||
environment_data: Arc<WebAssemblyEnvironmentData>,
|
||||
}
|
||||
@@ -63,13 +59,15 @@ impl WebAssemblyScriptResolver {
|
||||
let store_ptr: *mut Store = store.as_mut();
|
||||
forget(store);
|
||||
|
||||
let environment = Arc::new(WebAssemblyEnvironmentData::new(store_ptr));
|
||||
environment.self_arc.write().replace(Arc::downgrade(&environment));
|
||||
|
||||
let s = Self {
|
||||
_store: store_ptr,
|
||||
modules: Default::default(),
|
||||
instances: Default::default(),
|
||||
load_script_fn: None,
|
||||
script_capabilities: Default::default(),
|
||||
environment_data: Arc::new(WebAssemblyEnvironmentData::new(store_ptr)),
|
||||
environment_data: environment,
|
||||
};
|
||||
|
||||
Box::new(s)
|
||||
@@ -168,7 +166,7 @@ impl WebAssemblyScriptResolver {
|
||||
impl ScriptResolver for WebAssemblyScriptResolver {
|
||||
fn load_script(
|
||||
&self,
|
||||
owner: *const u8,
|
||||
owner: ScriptOwnerData,
|
||||
category: ScriptCategory,
|
||||
script_key: &StringKey,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
@@ -182,50 +180,7 @@ impl ScriptResolver for WebAssemblyScriptResolver {
|
||||
ExternRef::new_with_resolver(self, script_key),
|
||||
)
|
||||
.unwrap();
|
||||
if script == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let key = ScriptCapabilitiesKey {
|
||||
category,
|
||||
script_key: script_key.clone(),
|
||||
};
|
||||
|
||||
if !self.script_capabilities.read().contains_key(&key) {
|
||||
let mut capabilities = HashSet::new();
|
||||
unsafe {
|
||||
if let Some(get_cap) = self
|
||||
.environment_data
|
||||
.exported_functions
|
||||
.read()
|
||||
.get::<StringKey>(&"get_script_capabilities".into())
|
||||
{
|
||||
let res = get_cap
|
||||
.call(&mut self.store_mut(), &[Value::I32(script as i32)])
|
||||
.unwrap();
|
||||
let ptr = (self.environment_data.memory() as *const WebAssemblyScriptCapabilities)
|
||||
.offset(res[0].i32().unwrap() as isize);
|
||||
let length = res[1].i32().unwrap() as usize;
|
||||
for i in 0..length {
|
||||
capabilities.insert(*ptr.add(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.script_capabilities
|
||||
.write()
|
||||
.insert(key.clone(), Arc::new(capabilities));
|
||||
}
|
||||
|
||||
let read_guard = self.script_capabilities.read();
|
||||
let capabilities = read_guard.get(&key).unwrap();
|
||||
|
||||
Ok(Some(Arc::new(WebAssemblyScript::new(
|
||||
owner as *mut u8,
|
||||
script,
|
||||
capabilities.clone(),
|
||||
self.environment_data.clone(),
|
||||
script_key.clone(),
|
||||
))))
|
||||
self.environment_data.setup_script(script, category, script_key, owner)
|
||||
}
|
||||
|
||||
fn load_item_script(&self, _key: &Item) -> PkmnResult<Option<Arc<dyn ItemScript>>> {
|
||||
@@ -283,6 +238,16 @@ pub struct WebAssemblyEnvironmentData {
|
||||
|
||||
/// The WASM store.
|
||||
store: *mut Store,
|
||||
|
||||
/// Script capabilities tell us which functions are implemented on a given script. This allows us to skip unneeded
|
||||
/// WASM calls.
|
||||
script_capabilities: RwLock<HashMap<ScriptCapabilitiesKey, Arc<HashSet<WebAssemblyScriptCapabilities>>>>,
|
||||
|
||||
/// A weak reference to ourselves.
|
||||
self_arc: RwLock<Option<Weak<Self>>>,
|
||||
|
||||
/// A lookup from WASM memory pointer to their actual script wrappers.
|
||||
loaded_scripts: RwLock<HashMap<u32, Weak<WebAssemblyScript>>>,
|
||||
}
|
||||
|
||||
/// A quick lookup so we can find the extern ref of the value.
|
||||
@@ -310,6 +275,9 @@ impl WebAssemblyEnvironmentData {
|
||||
allocate_mem_fn: Default::default(),
|
||||
temp_allocator: Default::default(),
|
||||
store,
|
||||
script_capabilities: Default::default(),
|
||||
self_arc: Default::default(),
|
||||
loaded_scripts: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +286,19 @@ impl WebAssemblyEnvironmentData {
|
||||
self.memory.read().as_ref().unwrap().view(&self.store_ref()).data_ptr()
|
||||
}
|
||||
|
||||
/// Return a pointer to something inside the WASM memory.
|
||||
pub fn get_raw_pointer<T>(&self, offset: u32) -> *mut T {
|
||||
unsafe {
|
||||
self.memory
|
||||
.read()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.view(&self.store_ref())
|
||||
.data_ptr()
|
||||
.offset(offset as isize) as *mut T
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns the functions exported from WASM.
|
||||
pub fn exported_functions(&self) -> RwLockReadGuard<'_, RawRwLock, HashMap<StringKey, Function>> {
|
||||
self.exported_functions.read()
|
||||
@@ -371,6 +352,7 @@ impl WebAssemblyEnvironmentData {
|
||||
/// access can be touched through this, and we ensure the value is the correct type. In the future,
|
||||
/// when extern refs get actually properly implemented at compile time we might want to get rid
|
||||
/// of this code.
|
||||
#[inline(always)]
|
||||
pub fn get_extern_ref_index<T: UniqueTypeId<u64> + ?Sized>(&self, value: &T) -> u32 {
|
||||
self.get_extern_ref_from_ptr(value as *const T as *const u8, T::id().0, false)
|
||||
}
|
||||
@@ -400,6 +382,7 @@ impl WebAssemblyEnvironmentData {
|
||||
|
||||
/// Gets the extern ref index belonging to a specific pointer. If none exists, this will create
|
||||
/// a new one.
|
||||
#[inline(always)]
|
||||
fn get_extern_ref_from_ptr(&self, ptr: *const u8, type_id: u64, is_vec: bool) -> u32 {
|
||||
if let Some(v) = self.extern_ref_pointers_lookup.read().get(&ExternRefLookupKey {
|
||||
ptr,
|
||||
@@ -462,6 +445,71 @@ impl WebAssemblyEnvironmentData {
|
||||
pub fn store_mut(&self) -> StoreMut<'_> {
|
||||
unsafe { self.store.as_mut().unwrap().as_store_mut() }
|
||||
}
|
||||
|
||||
/// Find a loaded script based on the pointer in WASM memory.
|
||||
pub(crate) fn get_loaded_script(&self, wasm_ptr: u32) -> Option<Arc<WebAssemblyScript>> {
|
||||
if let Some(script) = self.loaded_scripts.read().get(&wasm_ptr) {
|
||||
script.upgrade()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap a script pointer in WASM memory into a host managed script.
|
||||
pub fn setup_script(
|
||||
&self,
|
||||
script_ptr: u32,
|
||||
category: ScriptCategory,
|
||||
script_key: &StringKey,
|
||||
owner: ScriptOwnerData,
|
||||
) -> PkmnResult<Option<Arc<dyn Script>>> {
|
||||
if script_ptr == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let key = ScriptCapabilitiesKey {
|
||||
category,
|
||||
script_key: script_key.clone(),
|
||||
};
|
||||
|
||||
if !self.script_capabilities.read().contains_key(&key) {
|
||||
let mut capabilities = HashSet::new();
|
||||
unsafe {
|
||||
if let Some(get_cap) = self
|
||||
.exported_functions
|
||||
.read()
|
||||
.get::<StringKey>(&"get_script_capabilities".into())
|
||||
{
|
||||
let res = get_cap
|
||||
.call(&mut self.store_mut(), &[Value::I32(script_ptr as i32)])
|
||||
.unwrap();
|
||||
let ptr =
|
||||
(self.memory() as *const WebAssemblyScriptCapabilities).offset(res[0].i32().unwrap() as isize);
|
||||
let length = res[1].i32().unwrap() as usize;
|
||||
for i in 0..length {
|
||||
capabilities.insert(*ptr.add(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.script_capabilities
|
||||
.write()
|
||||
.insert(key.clone(), Arc::new(capabilities));
|
||||
}
|
||||
|
||||
let read_guard = self.script_capabilities.read();
|
||||
let capabilities = read_guard.get(&key).unwrap();
|
||||
|
||||
let script = Arc::new(WebAssemblyScript::new(
|
||||
owner,
|
||||
script_ptr,
|
||||
capabilities.clone(),
|
||||
self.self_arc.read().as_ref().unwrap().upgrade().unwrap(),
|
||||
script_key.clone(),
|
||||
));
|
||||
|
||||
self.loaded_scripts.write().insert(script_ptr, Arc::downgrade(&script));
|
||||
Ok(Some(script))
|
||||
}
|
||||
}
|
||||
|
||||
/// The runtime environment for script execution. This is passed to most of the host functions being called.
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
+23
-20
@@ -1,4 +1,5 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::ffi::CString;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
@@ -27,23 +28,13 @@ static STRING_CACHE: OnceCell<Mutex<HashMap<u32, Weak<str>>>> = OnceCell::uninit
|
||||
static EMPTY: OnceCell<StringKey> = OnceCell::uninit();
|
||||
|
||||
impl StringKey {
|
||||
/// Calculates the hash of a string key in a const manner.
|
||||
pub const fn get_hash_const<const N: usize>(s: &[u8; N]) -> u32 {
|
||||
let mut crc: u32 = 0xffffffff;
|
||||
|
||||
let mut i: usize = 0;
|
||||
while i < N {
|
||||
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(s[i]) as u32)) & 0xff) as usize];
|
||||
i += 1;
|
||||
}
|
||||
crc ^ 0xffffffff
|
||||
}
|
||||
|
||||
/// Gets the hash of a string.
|
||||
pub fn get_hash(s: &str) -> u32 {
|
||||
pub const fn get_hash(s: &str) -> u32 {
|
||||
let mut crc: u32 = 0xffffffff;
|
||||
for byte in s.bytes() {
|
||||
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(byte) as u32)) & 0xff) as usize];
|
||||
let mut i: usize = 0;
|
||||
while i < s.len() {
|
||||
crc = (crc >> 8) ^ CRC_TABLE[((crc ^ (to_lower(s.as_bytes()[i]) as u32)) & 0xff) as usize];
|
||||
i += 1;
|
||||
}
|
||||
crc ^ 0xffffffff
|
||||
}
|
||||
@@ -115,6 +106,18 @@ impl Display for StringKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<StringKey> for CString {
|
||||
fn into(self) -> StringKey {
|
||||
StringKey::new(self.to_str().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<StringKey> for &CString {
|
||||
fn into(self) -> StringKey {
|
||||
StringKey::new(self.to_str().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a character to lowercased in a const safe way.
|
||||
const fn to_lower(c: u8) -> u8 {
|
||||
if c >= b'A' && c <= b'Z' {
|
||||
@@ -167,7 +170,7 @@ mod tests {
|
||||
let sk = StringKey::new("");
|
||||
assert_eq!(sk.str(), "");
|
||||
assert_eq!(sk.hash(), 0);
|
||||
assert_eq!(sk.hash(), StringKey::get_hash_const(b""));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -175,8 +178,8 @@ mod tests {
|
||||
let sk = StringKey::new("foo");
|
||||
assert_eq!(sk.str(), "foo");
|
||||
assert_eq!(sk.hash(), 2356372769);
|
||||
assert_eq!(sk.hash(), StringKey::get_hash_const(b"foo"));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash_const(b"FOo"));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash("foo"));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash("FOo"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -184,7 +187,7 @@ mod tests {
|
||||
let sk = StringKey::new("bar");
|
||||
assert_eq!(sk.str(), "bar");
|
||||
assert_eq!(sk.hash(), 1996459178);
|
||||
assert_eq!(sk.hash(), StringKey::get_hash_const(b"bar"));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash_const(b"baR"));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash("bar"));
|
||||
assert_eq!(sk.hash(), StringKey::get_hash("baR"));
|
||||
}
|
||||
}
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Binary file not shown.
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user