use crate::dynamic_data::{DynamicLibrary, ExecutingMove, Pokemon, Script, ScriptOwnerData, TurnChoice}; use crate::script_implementations::rune::wrappers::*; use crate::script_implementations::rune::RuneScriptType; use crate::static_data::Parameter; use crate::StringKey; use hashbrown::HashMap; use parking_lot::RwLock; use rune::runtime::{Object, RuntimeContext, Shared, VmError, VmResult}; use rune::{Unit, Value}; use std::convert::TryFrom; use std::ops::Deref; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::Arc; pub struct RuneScript { name: StringKey, state: RwLock>, /// Returns an atomic bool for internal marking of deletion. This is currently only specifically /// used for deletion of a script while we are holding a reference to it (i.e. executing a script /// hook on it). marked_for_deletion: AtomicBool, /// A script can be suppressed by other scripts. If a script is suppressed by at least one script /// 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: ScriptOwnerData, script_type: Arc, runtime: Arc, unit: Arc, } unsafe impl Send for RuneScript {} unsafe impl Sync for RuneScript {} impl RuneScript { pub fn new( name: StringKey, object: Shared, owner: ScriptOwnerData, script_type: Arc, runtime: Arc, unit: Arc, ) -> Self { Self { name, state: RwLock::new(object), marked_for_deletion: Default::default(), suppressed_count: Default::default(), owner, script_type, runtime, unit, } } } impl Script for RuneScript { fn name(&self) -> anyhow::Result<&StringKey> { Ok(&self.name) } fn get_marked_for_deletion(&self) -> &AtomicBool { &self.marked_for_deletion } fn get_suppressed_count(&self) -> &AtomicUsize { &self.suppressed_count } fn on_initialize( &self, _: &Arc, pars: &HashMap>, ) -> anyhow::Result<()> { if pars.is_empty() { return Ok(()); } let write_lock = self.state.write(); for par in pars { let key = rune::alloc::string::String::try_from(par.0.str())?; write_lock .borrow_mut()? .insert(key, parameter_to_rune_value(par.1.as_ref())?)?; } Ok(()) } fn block_critical( &self, move_data: &Arc, target: &Pokemon, hit: u8, block_critical: &mut bool, ) -> anyhow::Result<()> { if let Some(hash) = self.script_type.fn_block_critical { let mut vm = rune::runtime::Vm::new(self.runtime.clone(), self.unit.clone()); todo!() // let block_critical_handle = RuneValueWrapper::new_mut(block_critical); // let read_lock = self.state.read(); // let state = read_lock.deref(); // // vm.execute( // hash, // vec![ // Value::Object(state.clone()), // Value::from(move_data.wrap()?), // Value::from(target.wrap()?), // Value::from(hit), // Value::from(block_critical_handle.clone().wrap()?), // ], // )?; // *block_critical = block_critical_handle.value(); } Ok(()) } fn change_speed(&self, choice: &Arc, speed: &mut u32) -> anyhow::Result<()> { if let Some(hash) = self.script_type.fn_change_speed { let mut vm = rune::runtime::Vm::new(self.runtime.clone(), self.unit.clone()); let speed_handle = wrap_value_reference(*speed as i64)?; let read_lock = self.state.read(); let state = read_lock.deref(); let res = vm .execute( hash, vec![ Value::Object(state.clone()), Value::from(choice.wrap()), speed_handle.clone(), ], )? .complete(); if let VmResult::Err(e) = res { return Err(anyhow::anyhow!("Error executing script: {}", e)); } *speed = get_value_reference(speed_handle)? as u32; } Ok(()) } fn as_any(&self) -> &dyn std::any::Any { self } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } } fn parameter_to_rune_value(parameter: &Parameter) -> Result { match parameter { Parameter::Bool(b) => rune::to_value(*b), Parameter::Int(i) => rune::to_value(*i), Parameter::Float(f) => rune::to_value(*f), Parameter::String(s) => rune::to_value(s.str()), } }