A lot more work on WASM script execution
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -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
src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs
Executable file
123
src/script_implementations/wasm/export_registry/dynamic_data/battle_side.rs
Executable file
@@ -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()
|
||||
}
|
||||
}
|
||||
0
src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs
Normal file → Executable file
0
src/script_implementations/wasm/export_registry/dynamic_data/learned_move.rs
Normal file → Executable file
48
src/script_implementations/wasm/export_registry/dynamic_data/mod.rs
Normal file → Executable file
48
src/script_implementations/wasm/export_registry/dynamic_data/mod.rs
Normal file → Executable file
@@ -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
|
||||
}
|
||||
}
|
||||
70
src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs
Normal file → Executable file
70
src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs
Normal file → Executable file
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
7
src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs
Normal file → Executable file
7
src/script_implementations/wasm/export_registry/dynamic_data/turn_choice.rs
Normal file → Executable file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
0
src/script_implementations/wasm/export_registry/mod.rs
Normal file → Executable file
0
src/script_implementations/wasm/export_registry/mod.rs
Normal file → Executable file
@@ -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()) }
|
||||
}
|
||||
}
|
||||
2
src/script_implementations/wasm/export_registry/static_data/mod.rs
Normal file → Executable file
2
src/script_implementations/wasm/export_registry/static_data/mod.rs
Normal file → Executable file
@@ -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);
|
||||
}
|
||||
|
||||
0
src/script_implementations/wasm/export_registry/static_data/moves.rs
Normal file → Executable file
0
src/script_implementations/wasm/export_registry/static_data/moves.rs
Normal file → Executable file
0
src/script_implementations/wasm/export_registry/static_data/species.rs
Normal file → Executable file
0
src/script_implementations/wasm/export_registry/static_data/species.rs
Normal file → Executable file
0
src/script_implementations/wasm/extern_ref.rs
Normal file → Executable file
0
src/script_implementations/wasm/extern_ref.rs
Normal file → Executable file
0
src/script_implementations/wasm/mod.rs
Normal file → Executable file
0
src/script_implementations/wasm/mod.rs
Normal file → Executable file
21
src/script_implementations/wasm/script.rs
Normal file → Executable file
21
src/script_implementations/wasm/script.rs
Normal file → Executable file
@@ -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.
|
||||
|
||||
0
src/script_implementations/wasm/script_function_cache.rs
Normal file → Executable file
0
src/script_implementations/wasm/script_function_cache.rs
Normal file → Executable file
152
src/script_implementations/wasm/script_resolver.rs
Normal file → Executable file
152
src/script_implementations/wasm/script_resolver.rs
Normal file → Executable file
@@ -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.
|
||||
|
||||
0
src/script_implementations/wasm/temp_wasm_allocator.rs
Normal file → Executable file
0
src/script_implementations/wasm/temp_wasm_allocator.rs
Normal file → Executable file
Reference in New Issue
Block a user