Initial work on rune as scripting library
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
/// The WASM module handles loading dynamic scripts through WebAssembly.
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm;
|
||||
|
||||
/// The Rune module handles loading dynamic scripts through the Rune language.
|
||||
#[cfg(feature = "rune")]
|
||||
pub mod rune;
|
||||
|
||||
134
src/script_implementations/rune/mod.rs
Normal file
134
src/script_implementations/rune/mod.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
use crate::dynamic_data::{Battle, DamageSource, ExecutingMove, Pokemon, TurnChoice};
|
||||
use crate::static_data::{Item, Statistic, TypeIdentifier};
|
||||
use crate::StringKey;
|
||||
use rune::Hash;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod script;
|
||||
pub mod script_resolver;
|
||||
pub(self) mod wrappers;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(self) struct RuneScriptType {
|
||||
pub fn_on_initialize: Option<Hash>,
|
||||
pub fn_on_stack: Option<Hash>,
|
||||
pub fn_on_remove: Option<Hash>,
|
||||
pub fn_on_before_turn: Option<Hash>,
|
||||
|
||||
pub fn_change_speed: Option<Hash>,
|
||||
pub fn_change_priority: Option<Hash>,
|
||||
pub fn_change_move: Option<Hash>,
|
||||
pub fn_change_number_of_hits: Option<Hash>,
|
||||
pub fn_prevent_move: Option<Hash>,
|
||||
pub fn_fail_move: Option<Hash>,
|
||||
pub fn_stop_before_move: Option<Hash>,
|
||||
pub fn_on_before_move: Option<Hash>,
|
||||
pub fn_fail_incoming_move: Option<Hash>,
|
||||
pub fn_is_invulnerable: Option<Hash>,
|
||||
pub fn_on_move_miss: Option<Hash>,
|
||||
pub fn_change_move_type: Option<Hash>,
|
||||
pub fn_change_effectiveness: Option<Hash>,
|
||||
pub fn_block_critical: Option<Hash>,
|
||||
pub fn_block_incoming_critical: Option<Hash>,
|
||||
pub fn_change_accuracy: Option<Hash>,
|
||||
pub fn_change_critical_stage: Option<Hash>,
|
||||
pub fn_change_critical_modifier: Option<Hash>,
|
||||
pub fn_change_stab_modifier: Option<Hash>,
|
||||
pub fn_change_base_power: Option<Hash>,
|
||||
pub fn_bypass_defensive_stat_boost: Option<Hash>,
|
||||
pub fn_bypass_offensive_stat_boost: Option<Hash>,
|
||||
pub fn_change_offensive_stat_value: Option<Hash>,
|
||||
pub fn_change_defensive_stat_value: Option<Hash>,
|
||||
pub fn_change_damage_stat_modifier: Option<Hash>,
|
||||
pub fn_change_damage_modifier: Option<Hash>,
|
||||
pub fn_change_damage: Option<Hash>,
|
||||
pub fn_change_incoming_damage: Option<Hash>,
|
||||
pub fn_on_incoming_hit: Option<Hash>,
|
||||
pub fn_on_opponent_faints: Option<Hash>,
|
||||
pub fn_prevent_stat_boost_change: Option<Hash>,
|
||||
pub fn_change_stat_boost_change: Option<Hash>,
|
||||
pub fn_prevent_secondary_effect: Option<Hash>,
|
||||
pub fn_change_effect_chance: Option<Hash>,
|
||||
pub fn_change_incoming_effect_chance: Option<Hash>,
|
||||
pub fn_on_secondary_effect: Option<Hash>,
|
||||
pub fn_on_after_hits: Option<Hash>,
|
||||
pub fn_prevent_self_switch: Option<Hash>,
|
||||
pub fn_prevent_opponent_switch: Option<Hash>,
|
||||
pub fn_on_fail: Option<Hash>,
|
||||
pub fn_on_opponent_fail: Option<Hash>,
|
||||
pub fn_prevent_self_run_away: Option<Hash>,
|
||||
pub fn_prevent_opponent_run_away: Option<Hash>,
|
||||
pub fn_on_end_turn: Option<Hash>,
|
||||
pub fn_on_damage: Option<Hash>,
|
||||
pub fn_on_faint: Option<Hash>,
|
||||
pub fn_on_switch_in: Option<Hash>,
|
||||
pub fn_on_after_held_item_consume: Option<Hash>,
|
||||
pub fn_change_experience_gained: Option<Hash>,
|
||||
pub fn_share_experience: Option<Hash>,
|
||||
pub fn_block_weather: Option<Hash>,
|
||||
pub fn_change_capture_rate_bonus: Option<Hash>,
|
||||
}
|
||||
|
||||
impl RuneScriptType {
|
||||
pub fn on_found_fn(&mut self, fn_name: &str, hash: Hash) {
|
||||
match fn_name {
|
||||
"on_initialize" => self.fn_on_initialize = Some(hash),
|
||||
"on_stack" => self.fn_on_stack = Some(hash),
|
||||
"on_remove" => self.fn_on_remove = Some(hash),
|
||||
"on_before_turn" => self.fn_on_before_turn = Some(hash),
|
||||
"change_speed" => self.fn_change_speed = Some(hash),
|
||||
"change_priority" => self.fn_change_priority = Some(hash),
|
||||
"change_move" => self.fn_change_move = Some(hash),
|
||||
"change_number_of_hits" => self.fn_change_number_of_hits = Some(hash),
|
||||
"prevent_move" => self.fn_prevent_move = Some(hash),
|
||||
"fail_move" => self.fn_fail_move = Some(hash),
|
||||
"stop_before_move" => self.fn_stop_before_move = Some(hash),
|
||||
"on_before_move" => self.fn_on_before_move = Some(hash),
|
||||
"fail_incoming_move" => self.fn_fail_incoming_move = Some(hash),
|
||||
"is_invulnerable" => self.fn_is_invulnerable = Some(hash),
|
||||
"on_move_miss" => self.fn_on_move_miss = Some(hash),
|
||||
"change_move_type" => self.fn_change_move_type = Some(hash),
|
||||
"change_effectiveness" => self.fn_change_effectiveness = Some(hash),
|
||||
"block_critical" => self.fn_block_critical = Some(hash),
|
||||
"block_incoming_critical" => self.fn_block_incoming_critical = Some(hash),
|
||||
"change_accuracy" => self.fn_change_accuracy = Some(hash),
|
||||
"change_critical_stage" => self.fn_change_critical_stage = Some(hash),
|
||||
"change_critical_modifier" => self.fn_change_critical_modifier = Some(hash),
|
||||
"change_stab_modifier" => self.fn_change_stab_modifier = Some(hash),
|
||||
"change_base_power" => self.fn_change_base_power = Some(hash),
|
||||
"bypass_defensive_stat_boost" => self.fn_bypass_defensive_stat_boost = Some(hash),
|
||||
"bypass_offensive_stat_boost" => self.fn_bypass_offensive_stat_boost = Some(hash),
|
||||
"change_offensive_stat_value" => self.fn_change_offensive_stat_value = Some(hash),
|
||||
"change_defensive_stat_value" => self.fn_change_defensive_stat_value = Some(hash),
|
||||
"change_damage_stat_modifier" => self.fn_change_damage_stat_modifier = Some(hash),
|
||||
"change_damage_modifier" => self.fn_change_damage_modifier = Some(hash),
|
||||
"change_damage" => self.fn_change_damage = Some(hash),
|
||||
"change_incoming_damage" => self.fn_change_incoming_damage = Some(hash),
|
||||
"on_incoming_hit" => self.fn_on_incoming_hit = Some(hash),
|
||||
"on_opponent_faints" => self.fn_on_opponent_faints = Some(hash),
|
||||
"prevent_stat_boost_change" => self.fn_prevent_stat_boost_change = Some(hash),
|
||||
"change_stat_boost_change" => self.fn_change_stat_boost_change = Some(hash),
|
||||
"prevent_secondary_effect" => self.fn_prevent_secondary_effect = Some(hash),
|
||||
"change_effect_chance" => self.fn_change_effect_chance = Some(hash),
|
||||
"change_incoming_effect_chance" => self.fn_change_incoming_effect_chance = Some(hash),
|
||||
"on_secondary_effect" => self.fn_on_secondary_effect = Some(hash),
|
||||
"on_after_hits" => self.fn_on_after_hits = Some(hash),
|
||||
"prevent_self_switch" => self.fn_prevent_self_switch = Some(hash),
|
||||
"prevent_opponent_switch" => self.fn_prevent_opponent_switch = Some(hash),
|
||||
"on_fail" => self.fn_on_fail = Some(hash),
|
||||
"on_opponent_fail" => self.fn_on_opponent_fail = Some(hash),
|
||||
"prevent_self_run_away" => self.fn_prevent_self_run_away = Some(hash),
|
||||
"prevent_opponent_run_away" => self.fn_prevent_opponent_run_away = Some(hash),
|
||||
"on_end_turn" => self.fn_on_end_turn = Some(hash),
|
||||
"on_damage" => self.fn_on_damage = Some(hash),
|
||||
"on_faint" => self.fn_on_faint = Some(hash),
|
||||
"on_switch_in" => self.fn_on_switch_in = Some(hash),
|
||||
"on_after_held_item_consume" => self.fn_on_after_held_item_consume = Some(hash),
|
||||
"change_experience_gained" => self.fn_change_experience_gained = Some(hash),
|
||||
"share_experience" => self.fn_share_experience = Some(hash),
|
||||
"block_weather" => self.fn_block_weather = Some(hash),
|
||||
"change_capture_rate_bonus" => self.fn_change_capture_rate_bonus = Some(hash),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
153
src/script_implementations/rune/script.rs
Normal file
153
src/script_implementations/rune/script.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
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()),
|
||||
}
|
||||
}
|
||||
179
src/script_implementations/rune/script_resolver.rs
Normal file
179
src/script_implementations/rune/script_resolver.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
use crate::dynamic_data::{ItemScript, Script, ScriptCategory, ScriptOwnerData, ScriptResolver};
|
||||
use crate::script_implementations::rune::script::RuneScript;
|
||||
use crate::script_implementations::rune::RuneScriptType;
|
||||
use crate::static_data::Item;
|
||||
use crate::StringKey;
|
||||
use hashbrown::HashMap;
|
||||
use parking_lot::RwLock;
|
||||
use rune::compile::meta::AssociatedKind;
|
||||
use rune::compile::{ComponentRef, MetaError};
|
||||
use rune::diagnostics::Diagnostic;
|
||||
use rune::runtime::{RuntimeContext, Shared};
|
||||
use rune::{Context, Diagnostics, Hash, Options, Source, Sources, Unit, Vm};
|
||||
use std::any::Any;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RuneScriptResolver {
|
||||
runtime: Arc<RuntimeContext>,
|
||||
unit: Arc<Unit>,
|
||||
script_types: HashMap<(ScriptCategory, StringKey), Arc<RuneScriptType>>,
|
||||
}
|
||||
|
||||
pub struct RuneScriptResolverBuilder {
|
||||
context: Context,
|
||||
scripts: Sources,
|
||||
}
|
||||
|
||||
impl ScriptResolver for RuneScriptResolver {
|
||||
fn load_script(
|
||||
&self,
|
||||
owner: ScriptOwnerData,
|
||||
category: ScriptCategory,
|
||||
script_key: &StringKey,
|
||||
) -> anyhow::Result<Option<Arc<dyn Script>>> {
|
||||
let script_type = if let Some(script_type) = self.script_types.get(&(category, script_key.clone())) {
|
||||
script_type
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let state = Shared::new(rune::runtime::Object::new())?;
|
||||
let script = Arc::new(RuneScript::new(
|
||||
script_key.clone(),
|
||||
state,
|
||||
owner,
|
||||
script_type.clone(),
|
||||
self.runtime.clone(),
|
||||
self.unit.clone(),
|
||||
));
|
||||
Ok(Some(script))
|
||||
}
|
||||
|
||||
fn load_item_script(&self, _key: &dyn Item) -> anyhow::Result<Option<Arc<dyn ItemScript>>> { Ok(None) }
|
||||
|
||||
fn as_any(&self) -> &dyn Any { self }
|
||||
}
|
||||
|
||||
impl RuneScriptResolverBuilder {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let mut context = Context::with_default_modules()?;
|
||||
context.install(super::wrappers::module()?)?;
|
||||
|
||||
Ok(Self {
|
||||
context,
|
||||
scripts: Sources::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn insert_script(&mut self, path: &Path, name: &str, script: &str) -> anyhow::Result<&mut Self> {
|
||||
self.scripts
|
||||
.insert(Source::with_path(name, script.to_string(), path)?)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn build(mut self) -> anyhow::Result<Arc<dyn ScriptResolver>> {
|
||||
let mut visitor = FindScriptTypeVisitor::default();
|
||||
let mut diagnostics = Diagnostics::new();
|
||||
|
||||
let mut options = Options::default();
|
||||
options.debug_info(true);
|
||||
options.memoize_instance_fn(true);
|
||||
options.macros(true);
|
||||
options.bytecode(true);
|
||||
|
||||
let result = rune::prepare(&mut self.scripts)
|
||||
.with_context(&self.context)
|
||||
.with_visitor(&mut visitor)?
|
||||
.with_diagnostics(&mut diagnostics)
|
||||
.with_options(&options)
|
||||
.build();
|
||||
if diagnostics.has_error() {
|
||||
let error_message = diagnostics
|
||||
.diagnostics()
|
||||
.iter()
|
||||
.filter_map(|d| match d {
|
||||
Diagnostic::Fatal(f) => Some(f.to_string()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
return Err(anyhow::anyhow!("Error building Rune script: {}", error_message));
|
||||
}
|
||||
|
||||
let mut script_types = HashMap::with_capacity(visitor.script_types.len());
|
||||
for (key, script_type) in visitor.script_types {
|
||||
script_types.insert(key, Arc::new(script_type));
|
||||
}
|
||||
|
||||
Ok(Arc::new(RuneScriptResolver {
|
||||
runtime: Arc::new(self.context.runtime()?),
|
||||
unit: Arc::new(result?),
|
||||
script_types,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct FindScriptTypeVisitor {
|
||||
script_types: HashMap<(ScriptCategory, StringKey), RuneScriptType>,
|
||||
}
|
||||
|
||||
impl rune::compile::CompileVisitor for FindScriptTypeVisitor {
|
||||
fn register_meta(&mut self, meta: rune::compile::MetaRef<'_>) -> Result<(), MetaError> {
|
||||
match meta.kind {
|
||||
rune::compile::meta::Kind::Struct { .. } => {
|
||||
if meta.item.iter().count() < 2 {
|
||||
return Ok(());
|
||||
}
|
||||
let mod_name = meta.item.iter().nth(0).unwrap();
|
||||
let category = match get_mod_category(mod_name) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
let name = meta.item.last().unwrap();
|
||||
self.script_types
|
||||
.insert((category, name.to_string().as_str().into()), RuneScriptType::default());
|
||||
}
|
||||
rune::compile::meta::Kind::Function {
|
||||
associated: Some(AssociatedKind::Instance(associated)),
|
||||
..
|
||||
} => {
|
||||
if meta.item.iter().count() < 3 {
|
||||
return Ok(());
|
||||
}
|
||||
let mod_name = meta.item.iter().nth(0).unwrap();
|
||||
let category = match get_mod_category(mod_name) {
|
||||
Ok(value) => value,
|
||||
Err(value) => return value,
|
||||
};
|
||||
let instance = meta.item.iter().nth_back(1).unwrap();
|
||||
if let Some(script_type) = self
|
||||
.script_types
|
||||
.get_mut(&(category, instance.to_string().as_str().into()))
|
||||
{
|
||||
script_type.on_found_fn(associated.to_string().as_str(), meta.hash);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mod_category(mod_name: ComponentRef) -> Result<ScriptCategory, Result<(), MetaError>> {
|
||||
Ok(match mod_name.to_string().as_str() {
|
||||
"moves" => ScriptCategory::Move,
|
||||
"abilities" => ScriptCategory::Ability,
|
||||
"status" => ScriptCategory::Status,
|
||||
"pokemon" => ScriptCategory::Pokemon,
|
||||
"sides" => ScriptCategory::Side,
|
||||
"battle" => ScriptCategory::Battle,
|
||||
"weather" => ScriptCategory::Weather,
|
||||
"item_battle_triggers" => ScriptCategory::ItemBattleTrigger,
|
||||
_ => return Err(Ok(())),
|
||||
})
|
||||
}
|
||||
26
src/script_implementations/rune/wrappers/executing_move.rs
Normal file
26
src/script_implementations/rune/wrappers/executing_move.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::dynamic_data::ExecutingMove;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use rune::runtime::{AnyObj, Shared};
|
||||
use rune::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneExecutingMove>()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Any)]
|
||||
pub struct RuneExecutingMove {
|
||||
inner: Arc<ExecutingMove>,
|
||||
}
|
||||
|
||||
impl RuneExecutingMove {
|
||||
#[rune::function]
|
||||
pub fn target_count(&self) -> usize { self.inner.target_count() }
|
||||
#[rune::function]
|
||||
pub fn number_of_hits(&self) -> u8 { self.inner.number_of_hits() }
|
||||
#[rune::function]
|
||||
pub fn user(&self) -> Shared<AnyObj> { self.inner.user().wrap() }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Arc<ExecutingMove>, RuneExecutingMove);
|
||||
67
src/script_implementations/rune/wrappers/mod.rs
Normal file
67
src/script_implementations/rune/wrappers/mod.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use rune::runtime::Protocol;
|
||||
use rune::runtime::{AnyObj, Shared};
|
||||
use rune::{Any, Value};
|
||||
use std::ops::Deref;
|
||||
|
||||
mod executing_move;
|
||||
mod pokemon;
|
||||
mod turn_choice;
|
||||
|
||||
pub use executing_move::*;
|
||||
pub use pokemon::*;
|
||||
|
||||
pub trait RuneWrapper {
|
||||
#[inline]
|
||||
fn wrap(self) -> Shared<AnyObj>;
|
||||
}
|
||||
|
||||
pub fn module() -> anyhow::Result<rune::Module> {
|
||||
let mut module = rune::Module::new();
|
||||
module.ty::<RuneValueIntWrapper>()?;
|
||||
turn_choice::register(&mut module)?;
|
||||
pokemon::register(&mut module)?;
|
||||
|
||||
executing_move::register(&mut module)?;
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
pub fn wrap_value_reference(value: i64) -> anyhow::Result<Value> {
|
||||
Ok(Value::Any(Shared::new(AnyObj::new(RuneValueIntWrapper::new(value))?)?))
|
||||
}
|
||||
|
||||
pub fn get_value_reference(value: Value) -> anyhow::Result<i64> {
|
||||
let obj = value.into_any().into_result()?;
|
||||
let obj = obj.take()?;
|
||||
let obj = obj.downcast_borrow_ref::<RuneValueIntWrapper>().unwrap();
|
||||
Ok(obj.value())
|
||||
}
|
||||
|
||||
#[derive(Any, Clone)]
|
||||
struct RuneValueIntWrapper {
|
||||
#[rune(get, set)]
|
||||
value: i64,
|
||||
}
|
||||
|
||||
impl RuneValueIntWrapper {
|
||||
pub fn new(value: i64) -> Self { Self { value } }
|
||||
|
||||
pub fn value(&self) -> i64 { self.value }
|
||||
pub fn set_value(&mut self, value: i64) { self.value = value; }
|
||||
}
|
||||
|
||||
impl RuneWrapper for RuneValueIntWrapper {
|
||||
fn wrap(self) -> Shared<AnyObj> { Shared::new(AnyObj::new(self).unwrap()).unwrap() }
|
||||
}
|
||||
|
||||
macro_rules! impl_rune_wrapper {
|
||||
($t:ty, $wrapped_type:ident) => {
|
||||
impl crate::script_implementations::rune::wrappers::RuneWrapper for $t {
|
||||
fn wrap(self) -> rune::runtime::Shared<rune::runtime::AnyObj> {
|
||||
rune::runtime::Shared::new(rune::runtime::AnyObj::new($wrapped_type { inner: self.clone() }).unwrap())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(self) use impl_rune_wrapper;
|
||||
22
src/script_implementations/rune/wrappers/pokemon.rs
Normal file
22
src/script_implementations/rune/wrappers/pokemon.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use crate::defines::LevelInt;
|
||||
use crate::dynamic_data::Pokemon;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneWrapper};
|
||||
use rune::Any;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RunePokemon>()?;
|
||||
module.function_meta(RunePokemon::level)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Any)]
|
||||
pub struct RunePokemon {
|
||||
inner: Pokemon,
|
||||
}
|
||||
|
||||
impl RunePokemon {
|
||||
#[rune::function]
|
||||
fn level(&self) -> LevelInt { self.inner.level() }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Pokemon, RunePokemon);
|
||||
26
src/script_implementations/rune/wrappers/turn_choice.rs
Normal file
26
src/script_implementations/rune/wrappers/turn_choice.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::dynamic_data::TurnChoice;
|
||||
use crate::script_implementations::rune::wrappers::{impl_rune_wrapper, RuneExecutingMove, RuneWrapper};
|
||||
use rune::{Any, Value};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn register(module: &mut rune::Module) -> anyhow::Result<()> {
|
||||
module.ty::<RuneTurnChoice>()?;
|
||||
module.function_meta(RuneTurnChoice::speed)?;
|
||||
module.function_meta(RuneTurnChoice::user)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Any)]
|
||||
pub struct RuneTurnChoice {
|
||||
inner: Arc<TurnChoice>,
|
||||
}
|
||||
|
||||
impl RuneTurnChoice {
|
||||
#[rune::function]
|
||||
fn speed(&self) -> u32 { self.inner.speed() }
|
||||
|
||||
#[rune::function]
|
||||
fn user(&self) -> Value { Value::from(self.inner.user().wrap()) }
|
||||
}
|
||||
|
||||
impl_rune_wrapper!(&Arc<TurnChoice>, RuneTurnChoice);
|
||||
Reference in New Issue
Block a user