PkmnLib_rs/src/script_implementations/rune/script.rs

154 lines
5.0 KiB
Rust

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::{Any, Unit, Value};
use std::convert::TryFrom;
use std::error::Error;
use std::ops::Deref;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::Arc;
pub struct RuneScript {
name: StringKey,
state: RwLock<Shared<Object>>,
/// 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<RuneScriptType>,
runtime: Arc<RuntimeContext>,
unit: Arc<Unit>,
}
unsafe impl Send for RuneScript {}
unsafe impl Sync for RuneScript {}
impl RuneScript {
pub fn new(
name: StringKey,
object: Shared<Object>,
owner: ScriptOwnerData,
script_type: Arc<RuneScriptType>,
runtime: Arc<RuntimeContext>,
unit: Arc<Unit>,
) -> 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<dyn DynamicLibrary>,
pars: &HashMap<StringKey, Arc<Parameter>>,
) -> anyhow::Result<()> {
if pars.is_empty() {
return Ok(());
}
let mut 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<ExecutingMove>,
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<TurnChoice>, 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<Value, VmError> {
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()),
}
}