168 lines
5.9 KiB
Rust
168 lines
5.9 KiB
Rust
use crate::dynamic_data::{ItemScript, Pokemon};
|
|
use crate::script_implementations::wasm::export_registry::WasmVoidResultExtension;
|
|
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
|
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironmentData;
|
|
use crate::static_data::Parameter;
|
|
use crate::StringKey;
|
|
use std::sync::Arc;
|
|
|
|
/// A web assembly implementation of the item script.
|
|
pub struct WebAssemblyItemScript {
|
|
/// The unique identifier of the script.
|
|
name: StringKey,
|
|
|
|
/// Pointer inside WebAssembly memory where the data is for this script.
|
|
self_ptr: u32,
|
|
|
|
/// Cached value for the is_usable function.
|
|
is_usable: Option<bool>,
|
|
|
|
/// Cached value for the requires_target function.
|
|
requires_target: Option<bool>,
|
|
|
|
/// Cached value for the is_holdable function.
|
|
is_holdable: Option<bool>,
|
|
|
|
/// The global runtime environment data.
|
|
environment: Arc<WebAssemblyEnvironmentData>,
|
|
}
|
|
|
|
impl WebAssemblyItemScript {
|
|
/// Create a new instance of the script.
|
|
pub fn new(name: StringKey, self_ptr: u32, environment: Arc<WebAssemblyEnvironmentData>) -> Self {
|
|
Self {
|
|
name,
|
|
self_ptr,
|
|
is_usable: None,
|
|
requires_target: None,
|
|
is_holdable: None,
|
|
environment,
|
|
}
|
|
}
|
|
|
|
/// Get the name of the script.
|
|
pub fn name(&self) -> &StringKey {
|
|
&self.name
|
|
}
|
|
}
|
|
|
|
/// Util macro to reduce function call verbosity.
|
|
macro_rules! call_func {
|
|
($func:ident, $env:ident, $self:ident $(, $par_name:expr)*) => {
|
|
match $func.call(&mut $env.store_mut(), $self.self_ptr $(, $par_name)*) {
|
|
Ok(res) => res.into_result_env($env)?,
|
|
Err(e) => return Err(e.into()),
|
|
};
|
|
}
|
|
}
|
|
|
|
/// Util macro to reduce extern ref instantiation verbosity.
|
|
macro_rules! ex_ref {
|
|
($env:ident, $value:expr) => {
|
|
ExternRef::new($env.as_ref(), $value.into())
|
|
};
|
|
}
|
|
|
|
impl ItemScript for WebAssemblyItemScript {
|
|
fn on_initialize(&self, pars: Vec<Arc<Parameter>>) -> anyhow_ext::Result<()> {
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_on_initialize(env) {
|
|
let pars = pars
|
|
.into_iter()
|
|
.map(|p| ExternRef::<Parameter>::new(env, (&p).into()).index() as u32)
|
|
.collect::<Vec<_>>();
|
|
let wasm_ptr = env.copy_value_vec_to_wasm(&pars)?;
|
|
let r: u64 = unsafe { std::mem::transmute((wasm_ptr, pars.len() as u32)) };
|
|
call_func!(func, env, self, r);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn is_item_usable(&self) -> anyhow_ext::Result<bool> {
|
|
if let Some(is_usable) = self.is_usable {
|
|
return Ok(is_usable);
|
|
}
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_is_usable(env) {
|
|
let res_ptr = env.allocate_temp::<bool>(false);
|
|
call_func!(func, env, self, res_ptr.wasm_ptr);
|
|
let res = *res_ptr.value();
|
|
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut().unwrap_unchecked() };
|
|
self_mut.is_usable = Some(res);
|
|
return Ok(res);
|
|
}
|
|
Ok(true)
|
|
}
|
|
|
|
fn requires_target(&self) -> anyhow_ext::Result<bool> {
|
|
if let Some(requires_target) = self.requires_target {
|
|
return Ok(requires_target);
|
|
}
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_requires_target(env) {
|
|
let res_ptr = env.allocate_temp::<bool>(false);
|
|
call_func!(func, env, self, res_ptr.wasm_ptr);
|
|
let res = *res_ptr.value();
|
|
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut().unwrap_unchecked() };
|
|
self_mut.requires_target = Some(res);
|
|
return Ok(res);
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
fn is_target_valid(&self, target: &Pokemon) -> anyhow::Result<bool> {
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_is_target_valid(env) {
|
|
let target = ex_ref!(env, target);
|
|
let res_ptr = env.allocate_temp::<bool>(false);
|
|
call_func!(func, env, self, target, res_ptr.wasm_ptr);
|
|
return Ok(*res_ptr.value());
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
fn is_holdable(&self) -> anyhow::Result<bool> {
|
|
if let Some(is_holdable) = self.is_holdable {
|
|
return Ok(is_holdable);
|
|
}
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_is_holdable(env) {
|
|
let res_ptr = env.allocate_temp::<bool>(false);
|
|
call_func!(func, env, self, res_ptr.wasm_ptr);
|
|
let res = *res_ptr.value();
|
|
let self_mut = unsafe { (self as *const Self as *mut Self).as_mut().unwrap_unchecked() };
|
|
self_mut.is_holdable = Some(res);
|
|
return Ok(res);
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
fn can_target_hold(&self, target: &Pokemon) -> anyhow::Result<bool> {
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_can_target_hold(env) {
|
|
let target = ex_ref!(env, target);
|
|
let res_ptr = env.allocate_temp::<bool>(false);
|
|
call_func!(func, env, self, target, res_ptr.wasm_ptr);
|
|
return Ok(*res_ptr.value());
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
fn on_use(&self) -> anyhow::Result<()> {
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_on_use(env) {
|
|
call_func!(func, env, self);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn on_use_with_target(&self, target: &Pokemon) -> anyhow::Result<()> {
|
|
let env = &self.environment;
|
|
if let Some(func) = env.script_function_cache().item_on_use_with_target(env) {
|
|
let target = ex_ref!(env, target);
|
|
call_func!(func, env, self, target);
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|