Clippy fixes, additional WASM registration work
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
1e43c07d43
commit
c5fb81c179
|
@ -175,7 +175,7 @@ pub struct MoveChoice {
|
|||
choice_data: Box<CommonChoiceData>,
|
||||
}
|
||||
|
||||
impl<'user, 'library> MoveChoice {
|
||||
impl MoveChoice {
|
||||
/// Initializes the data for a new move choice.
|
||||
pub fn new(user: Arc<Pokemon>, used_move: Arc<LearnedMove>, target_side: u8, target_index: u8) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct EventHook {
|
|||
evt_hook_function: Vec<fn(&Box<&Event>)>,
|
||||
}
|
||||
|
||||
impl<'battle, 'library> EventHook {
|
||||
impl EventHook {
|
||||
/// Register a new listener. This will start receiving all events in the battle. Multiple event
|
||||
/// listeners can exist at the same time. Note that for these functions the event will be disposed
|
||||
/// of after the event is finished being sent.
|
||||
|
|
|
@ -25,7 +25,7 @@ impl ChoiceQueue {
|
|||
/// Dequeues the next turn choice to be executed. This gives ownership to the callee, and replaces
|
||||
/// our own reference to the turn choice with an empty spot. It also increments the current position
|
||||
/// by one.
|
||||
pub fn dequeue<'b>(&'b mut self) -> TurnChoice {
|
||||
pub fn dequeue(&mut self) -> TurnChoice {
|
||||
let c = self.queue[self.current].take();
|
||||
self.current += 1;
|
||||
c.unwrap()
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::static_data::MoveTarget;
|
|||
pub type TargetList = Vec<Option<Arc<Pokemon>>>;
|
||||
|
||||
/// This returns all Pokemon in the battle.
|
||||
fn get_all_targets<'b, 'library>(battle: &Battle) -> TargetList {
|
||||
fn get_all_targets(battle: &Battle) -> TargetList {
|
||||
let mut v = Vec::with_capacity(battle.pokemon_per_side() as usize * battle.number_of_sides() as usize);
|
||||
for side in battle.sides() {
|
||||
for pokemon in side.pokemon().deref() {
|
||||
|
@ -31,7 +31,7 @@ fn get_opposite_side(side: u8) -> u8 {
|
|||
|
||||
/// Gets all Pokemon that are adjacent to of directly opposite of a Pokemon. This means the target,
|
||||
/// the Pokemon left of it, the Pokemon right of it, and the Pokemon opposite of it.
|
||||
fn get_all_adjacent_opponent<'b, 'library>(side: u8, index: u8, battle: &Battle) -> TargetList {
|
||||
fn get_all_adjacent_opponent(side: u8, index: u8, battle: &Battle) -> TargetList {
|
||||
let left = index as i32 - 1;
|
||||
let right = index + 1;
|
||||
if left < 0 && right >= battle.pokemon_per_side() {
|
||||
|
@ -76,7 +76,7 @@ fn get_all_adjacent_opponent<'b, 'library>(side: u8, index: u8, battle: &Battle)
|
|||
|
||||
/// Gets all Pokemon that are adjacent to a Pokemon. This includes the target, the Pokemon to the
|
||||
/// left of it, and the Pokemon to the right of it.
|
||||
fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle) -> TargetList {
|
||||
fn get_all_adjacent(side: u8, index: u8, battle: &Battle) -> TargetList {
|
||||
let left = index as i32 - 1;
|
||||
let right = index + 1;
|
||||
if left < 0 && right >= battle.pokemon_per_side() {
|
||||
|
@ -102,7 +102,7 @@ fn get_all_adjacent<'b, 'library>(side: u8, index: u8, battle: &Battle) -> Targe
|
|||
}
|
||||
|
||||
/// Gets the target for a specific move target type, given the targeted position.
|
||||
pub fn resolve_targets<'b, 'library>(side: u8, index: u8, target: MoveTarget, battle: &Battle) -> TargetList {
|
||||
pub fn resolve_targets(side: u8, index: u8, target: MoveTarget, battle: &Battle) -> TargetList {
|
||||
match target {
|
||||
// These all resolve to a single position. We let the client deal with where the target is,
|
||||
// and just return the Pokemon at that given target here.
|
||||
|
|
|
@ -14,7 +14,7 @@ pub trait MiscLibrary: Debug {
|
|||
/// Returns whether or not a Pokemon is allowed to flee or switch out.
|
||||
fn can_flee(&self, choice: &TurnChoice) -> bool;
|
||||
/// Returns the move we need to use if we can't use another move. Typically Struggle.
|
||||
fn replacement_move<'func>(&'func self, user: &Arc<Pokemon>, target_side: u8, target_index: u8) -> TurnChoice;
|
||||
fn replacement_move(&self, user: &Arc<Pokemon>, target_side: u8, target_index: u8) -> TurnChoice;
|
||||
// TODO: can evolve from level up?
|
||||
// TODO: get time
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ impl Gen7MiscLibrary {
|
|||
Some(SecondaryEffect::new(-1.0, StringKey::new("struggle"), vec![])),
|
||||
HashSet::new(),
|
||||
));
|
||||
let struggle_learned_move = Arc::new(LearnedMove::new(&struggle_data.clone(), MoveLearnMethod::Unknown));
|
||||
let struggle_learned_move = Arc::new(LearnedMove::new(&struggle_data, MoveLearnMethod::Unknown));
|
||||
Self { struggle_learned_move }
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ impl MiscLibrary for Gen7MiscLibrary {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn replacement_move<'func>(&'func self, user: &Arc<Pokemon>, target_side: u8, target_index: u8) -> TurnChoice {
|
||||
fn replacement_move(&self, user: &Arc<Pokemon>, target_side: u8, target_index: u8) -> TurnChoice {
|
||||
self.struggle_learned_move.restore_all_uses();
|
||||
TurnChoice::Move(MoveChoice::new(
|
||||
user.clone(),
|
||||
|
|
|
@ -55,7 +55,7 @@ pub struct Battle {
|
|||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'own, 'library> Battle {
|
||||
impl Battle {
|
||||
/// Initializes a new battle.
|
||||
pub fn new(
|
||||
library: Arc<DynamicLibrary>,
|
||||
|
|
|
@ -43,7 +43,7 @@ pub struct BattleSide {
|
|||
script_source_data: RwLock<ScriptSourceData>,
|
||||
}
|
||||
|
||||
impl<'own, 'library> BattleSide {
|
||||
impl BattleSide {
|
||||
/// Instantiates a battle side.
|
||||
pub fn new(index: u8, pokemon_per_side: u8) -> Self {
|
||||
let mut pokemon = Vec::with_capacity(pokemon_per_side as usize);
|
||||
|
|
|
@ -260,7 +260,7 @@ impl Pokemon {
|
|||
}
|
||||
let script = self
|
||||
.library
|
||||
.load_item_script(&self.held_item.read().as_ref().unwrap())
|
||||
.load_item_script(self.held_item.read().as_ref().unwrap())
|
||||
.unwrap();
|
||||
if script.is_none() {
|
||||
return false;
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct PokemonParty {
|
|||
pokemon: Vec<Option<Arc<Pokemon>>>,
|
||||
}
|
||||
|
||||
impl<'own, 'library> PokemonParty {
|
||||
impl PokemonParty {
|
||||
/// Instantiates a party with a set size.
|
||||
pub fn new(size: usize) -> Self {
|
||||
let mut pokemon = Vec::with_capacity(size);
|
||||
|
|
|
@ -225,8 +225,6 @@ mod tests {
|
|||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
|
||||
use crate::dynamic_data::script_handling::script::ScriptContainer;
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::static_data::EffectParameter;
|
||||
use crate::StringKey;
|
||||
|
||||
use super::*;
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::script_implementations::wasm::export_registry::register;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use wasmer::{Exports, Store};
|
||||
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::StaticData;
|
||||
|
||||
/// Learned move registration
|
||||
mod learned_move;
|
||||
/// Pokemon registration
|
||||
mod pokemon;
|
||||
/// Turn choice registration
|
||||
mod turn_choice;
|
||||
|
||||
pub(crate) fn register(exports: &mut Exports, store: &Store, env: WebAssemblyEnv) {
|
||||
register! {
|
||||
fn dynamic_library_get_static_data(
|
||||
env: &WebAssemblyEnv,
|
||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||
) -> ExternRef<StaticData> {
|
||||
ExternRef::new(env.data().as_ref(), dynamic_lib.value(env).unwrap().static_data())
|
||||
}
|
||||
manual manual_register
|
||||
}
|
||||
|
||||
/// Additional required manual registration
|
||||
fn manual_register(exports: &mut Exports, store: &Store, env: WebAssemblyEnv) {
|
||||
turn_choice::register(exports, store, env.clone());
|
||||
pokemon::register(exports, store, env.clone());
|
||||
learned_move::register(exports, store, env.clone());
|
||||
learned_move::register(exports, store, env);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,17 @@ use std::mem::{align_of, forget};
|
|||
|
||||
use wasmer::{Exports, Store};
|
||||
|
||||
use crate::dynamic_data::DynamicLibrary;
|
||||
use crate::script_implementations::wasm::extern_ref::ExternRef;
|
||||
use crate::script_implementations::wasm::script_resolver::WebAssemblyEnv;
|
||||
use crate::static_data::{EffectParameter, StaticData};
|
||||
use crate::static_data::EffectParameter;
|
||||
use crate::StringKey;
|
||||
|
||||
/// Dynamic data registration
|
||||
mod dynamic_data;
|
||||
/// Static data registration
|
||||
mod static_data;
|
||||
|
||||
/// Register a single function.
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! register_func {
|
||||
($exports: ident, $store: ident, $func: ident) => {
|
||||
|
@ -19,6 +21,7 @@ macro_rules! register_func {
|
|||
};
|
||||
}
|
||||
|
||||
/// Register a single function that requires environment data.
|
||||
macro_rules! register_func_with_env {
|
||||
($exports: ident, $store: ident, $func: ident, $env: expr) => {
|
||||
$exports.insert(
|
||||
|
@ -28,11 +31,15 @@ macro_rules! register_func_with_env {
|
|||
};
|
||||
}
|
||||
|
||||
/// Utility macro to register a bunch of WASM functions easily.
|
||||
macro_rules! register {
|
||||
(
|
||||
$(
|
||||
fn $name:ident($($par:ident: $par_type:ty),*$(,)?) $(-> $return:ty)? $block:block
|
||||
)*
|
||||
$(
|
||||
manual $manual_name:ident
|
||||
)?
|
||||
) => {
|
||||
pub(crate) fn register(exports: &mut crate::script_implementations::wasm::export_registry::Exports,
|
||||
store: &crate::script_implementations::wasm::export_registry::Store,
|
||||
|
@ -46,7 +53,7 @@ macro_rules! register {
|
|||
) $(-> $return)* $block
|
||||
crate::script_implementations::wasm::export_registry::register_func_with_env!(exports, store, $name, env);
|
||||
)*
|
||||
|
||||
$( $manual_name(exports, store, env) )*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -54,6 +61,7 @@ macro_rules! register {
|
|||
pub(crate) use register;
|
||||
pub(crate) use register_func_with_env;
|
||||
|
||||
/// Register the functions we expose to WASM.
|
||||
pub(crate) fn register_webassembly_funcs(exports: &mut Exports, store: &Store, env: WebAssemblyEnv) {
|
||||
register_func_with_env!(exports, store, _print, env);
|
||||
register_func_with_env!(exports, store, _error, env);
|
||||
|
@ -64,7 +72,6 @@ pub(crate) fn register_webassembly_funcs(exports: &mut Exports, store: &Store, e
|
|||
|
||||
register_func_with_env!(exports, store, string_key_get_hash, env);
|
||||
register_func_with_env!(exports, store, string_key_get_str, env);
|
||||
register_func_with_env!(exports, store, dynamic_library_get_static_data, env);
|
||||
register_func_with_env!(exports, store, effect_parameter_get_type, env);
|
||||
register_func_with_env!(exports, store, effect_parameter_as_bool, env);
|
||||
register_func_with_env!(exports, store, effect_parameter_as_int, env);
|
||||
|
@ -72,6 +79,7 @@ pub(crate) fn register_webassembly_funcs(exports: &mut Exports, store: &Store, e
|
|||
register_func_with_env!(exports, store, effect_parameter_as_string, env);
|
||||
}
|
||||
|
||||
/// Logging function for WASM.
|
||||
fn _print(env: &WebAssemblyEnv, p: u32, len: u32) {
|
||||
unsafe {
|
||||
let mem: *mut u8 = env.data().memory().data_ptr().offset(p as isize);
|
||||
|
@ -81,6 +89,7 @@ fn _print(env: &WebAssemblyEnv, p: u32, len: u32) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Triggers when WASM panics.
|
||||
#[track_caller]
|
||||
fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_len: u32, line: u32, position: u32) {
|
||||
unsafe {
|
||||
|
@ -95,14 +104,18 @@ fn _error(env: &WebAssemblyEnv, message: u32, message_len: u32, file: u32, file_
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a single item from an earlier passed VecExternRef
|
||||
fn _vec_extern_ref_get_value(env: &WebAssemblyEnv, reference: u32, index: u32) -> u32 {
|
||||
env.data().get_extern_vec_ref_extern_ref(reference, index)
|
||||
}
|
||||
|
||||
/// Gets the hash value of a StringKey.
|
||||
fn string_key_get_hash(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) -> u32 {
|
||||
string_key.value(env).unwrap().hash()
|
||||
}
|
||||
|
||||
/// Get a null-terminated C string from a StringKey. Note that this involves a copy into WASM
|
||||
/// memory, so this is relatively heavy.
|
||||
fn string_key_get_str(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) -> u32 {
|
||||
let string_key = string_key.value(env).unwrap().str();
|
||||
let wasm_string_ptr = env
|
||||
|
@ -112,18 +125,12 @@ fn string_key_get_str(env: &WebAssemblyEnv, string_key: ExternRef<StringKey>) ->
|
|||
unsafe { Vec::from_raw_parts(wasm_string_ptr.0, string_key.len() + 1, string_key.len() + 1) };
|
||||
wasm_string.resize(string_key.len() + 1, 0);
|
||||
string_key.as_bytes().clone_into(&mut wasm_string);
|
||||
wasm_string.insert(string_key.len(), 0 as u8);
|
||||
wasm_string.insert(string_key.len(), 0_u8);
|
||||
forget(wasm_string);
|
||||
wasm_string_ptr.1
|
||||
}
|
||||
|
||||
fn dynamic_library_get_static_data(
|
||||
env: &WebAssemblyEnv,
|
||||
dynamic_lib: ExternRef<DynamicLibrary>,
|
||||
) -> ExternRef<StaticData> {
|
||||
ExternRef::new(env.data().as_ref(), dynamic_lib.value(env).unwrap().static_data())
|
||||
}
|
||||
|
||||
/// Gets the type of an EffectParameter
|
||||
fn effect_parameter_get_type(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> u8 {
|
||||
let v = parameter.value(env).unwrap();
|
||||
match v {
|
||||
|
@ -134,6 +141,7 @@ fn effect_parameter_get_type(env: &WebAssemblyEnv, parameter: ExternRef<EffectPa
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the inner bool data of an EffectParameter. Panics if it's not a bool.
|
||||
fn effect_parameter_as_bool(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> u8 {
|
||||
let v = parameter.value(env).unwrap();
|
||||
match v {
|
||||
|
@ -148,6 +156,7 @@ fn effect_parameter_as_bool(env: &WebAssemblyEnv, parameter: ExternRef<EffectPar
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the inner int data of an EffectParameter. Panics if it's not an int.
|
||||
fn effect_parameter_as_int(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> i64 {
|
||||
let v = parameter.value(env).unwrap();
|
||||
match v {
|
||||
|
@ -156,6 +165,7 @@ fn effect_parameter_as_int(env: &WebAssemblyEnv, parameter: ExternRef<EffectPara
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the inner float data of an EffectParameter. Panics if it's not a float.
|
||||
fn effect_parameter_as_float(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> f32 {
|
||||
let v = parameter.value(env).unwrap();
|
||||
match v {
|
||||
|
@ -164,6 +174,7 @@ fn effect_parameter_as_float(env: &WebAssemblyEnv, parameter: ExternRef<EffectPa
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the inner string data of an EffectParameter. Panics if it's not a string.
|
||||
fn effect_parameter_as_string(env: &WebAssemblyEnv, parameter: ExternRef<EffectParameter>) -> ExternRef<StringKey> {
|
||||
let v = parameter.value(env).unwrap();
|
||||
match v {
|
||||
|
|
|
@ -1,52 +1,52 @@
|
|||
use wasmer::{Exports, Store};
|
||||
|
||||
use crate::defines::LevelInt;
|
||||
use crate::script_implementations::wasm::export_registry::register_func_with_env;
|
||||
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::{ItemLibrary, LibrarySettings, MoveLibrary, SpeciesLibrary, StaticData, TypeLibrary};
|
||||
|
||||
/// Moves data registration
|
||||
mod moves;
|
||||
/// Species data registration
|
||||
mod species;
|
||||
|
||||
pub(crate) fn register(exports: &mut Exports, store: &Store, env: WebAssemblyEnv) {
|
||||
register_func_with_env!(exports, store, static_data_get_move_library, env);
|
||||
register_func_with_env!(exports, store, static_data_get_species_library, env);
|
||||
register_func_with_env!(exports, store, static_data_get_item_library, env);
|
||||
register_func_with_env!(exports, store, static_data_get_type_library, env);
|
||||
register_func_with_env!(exports, store, static_data_get_library_settings, env);
|
||||
register_func_with_env!(exports, store, library_settings_get_maximum_level, env);
|
||||
register! {
|
||||
fn static_data_get_move_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<MoveLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().moves())
|
||||
}
|
||||
|
||||
fn static_data_get_species_library(
|
||||
env: &WebAssemblyEnv,
|
||||
data_library: ExternRef<StaticData>,
|
||||
) -> ExternRef<SpeciesLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().species())
|
||||
}
|
||||
|
||||
fn static_data_get_item_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<ItemLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().items())
|
||||
}
|
||||
|
||||
fn static_data_get_type_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<TypeLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().types())
|
||||
}
|
||||
|
||||
fn static_data_get_library_settings(
|
||||
env: &WebAssemblyEnv,
|
||||
data_library: ExternRef<StaticData>,
|
||||
) -> ExternRef<LibrarySettings> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().settings())
|
||||
}
|
||||
|
||||
fn library_settings_get_maximum_level(env: &WebAssemblyEnv, data_library: ExternRef<LibrarySettings>) -> LevelInt {
|
||||
data_library.value(env).unwrap().maximum_level()
|
||||
}
|
||||
|
||||
manual manual_registration
|
||||
}
|
||||
|
||||
/// Additional required manual registration.
|
||||
fn manual_registration(exports: &mut Exports, store: &Store, env: WebAssemblyEnv) {
|
||||
moves::register(exports, store, env.clone());
|
||||
species::register(exports, store, env.clone());
|
||||
}
|
||||
|
||||
fn static_data_get_move_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<MoveLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().moves())
|
||||
}
|
||||
|
||||
fn static_data_get_species_library(
|
||||
env: &WebAssemblyEnv,
|
||||
data_library: ExternRef<StaticData>,
|
||||
) -> ExternRef<SpeciesLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().species())
|
||||
}
|
||||
|
||||
fn static_data_get_item_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<ItemLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().items())
|
||||
}
|
||||
|
||||
fn static_data_get_type_library(env: &WebAssemblyEnv, data_library: ExternRef<StaticData>) -> ExternRef<TypeLibrary> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().types())
|
||||
}
|
||||
|
||||
fn static_data_get_library_settings(
|
||||
env: &WebAssemblyEnv,
|
||||
data_library: ExternRef<StaticData>,
|
||||
) -> ExternRef<LibrarySettings> {
|
||||
ExternRef::new(env.data().as_ref(), data_library.value(env).unwrap().settings())
|
||||
}
|
||||
|
||||
fn library_settings_get_maximum_level(env: &WebAssemblyEnv, data_library: ExternRef<LibrarySettings>) -> LevelInt {
|
||||
data_library.value(env).unwrap().maximum_level()
|
||||
species::register(exports, store, env);
|
||||
}
|
||||
|
|
|
@ -8,12 +8,19 @@ use crate::script_implementations::wasm::script_resolver::{
|
|||
WebAssemblyEnv, WebAssemblyEnvironmentData, WebAssemblyScriptResolver,
|
||||
};
|
||||
|
||||
/// An Extern Ref allows us to pass objects to WASM without actually passing raw memory, or
|
||||
/// requiring us to make copies. Instead, we pass a simple increment index, that we can then use
|
||||
/// to find the relevant data.
|
||||
pub(crate) struct ExternRef<T: UniqueTypeId<u64>> {
|
||||
/// The lookup index we can use to find the data.
|
||||
index: u32,
|
||||
/// Phantom data so we can get a type generic.
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: UniqueTypeId<u64>> ExternRef<T> {
|
||||
/// Instantiates a new ExternRef for a bit of data. If we already have made an Extern Ref for
|
||||
/// this data and type, we use that instead.
|
||||
pub fn new(env: &WebAssemblyEnvironmentData, value: &T) -> Self {
|
||||
Self {
|
||||
index: env.get_extern_ref_index(value),
|
||||
|
@ -60,13 +67,19 @@ unsafe impl<T: UniqueTypeId<u64>> FromToNativeWasmType for ExternRef<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A VecExternRef is an Extern Ref for vector types. This allows us to pass Vecs to WASM without
|
||||
/// actually passing raw memory, or requiring us to make copies.
|
||||
pub(crate) struct VecExternRef<T> {
|
||||
/// The lookup index we can use to find the data.
|
||||
index: u32,
|
||||
/// The number of items in the vec.
|
||||
size: u32,
|
||||
/// Phantom data so we can get a type generic.
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: UniqueTypeId<u64>> VecExternRef<T> {
|
||||
/// Instantiates a new VecExternRef for a given slice.
|
||||
pub fn new(env: &WebAssemblyEnvironmentData, value: &[T]) -> Self {
|
||||
Self {
|
||||
index: env.get_extern_vec_ref_index(value),
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
/// The export registry module deals with registering all functions we require in WebAssembly.
|
||||
mod export_registry;
|
||||
/// A hacky extern ref implementation to ensure the client does not do things it is not allowed to do.
|
||||
pub(crate) mod extern_ref;
|
||||
/// The script module deals with the actual running of WASM functions.
|
||||
pub mod script;
|
||||
/// A cache of all script functions for easy calls
|
||||
mod script_function_cache;
|
||||
/// The script resolver deals with the loading of scripts.
|
||||
pub mod script_resolver;
|
||||
/// A small simple allocator for use for rapid short lived WASM allocations.
|
||||
mod temp_wasm_allocator;
|
||||
mod script_function_cache;
|
||||
|
||||
/// The WebAssemblyScriptCapabilities define which functions are implemented on a script. This allows
|
||||
/// us to not call a function if we do not need to.
|
||||
|
|
|
@ -3,7 +3,6 @@ use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize};
|
|||
use std::sync::{Arc, Weak};
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use wasmer::NativeFunc;
|
||||
|
||||
use crate::dynamic_data::{DynamicLibrary, Script, TurnChoice};
|
||||
use crate::script_implementations::wasm::extern_ref::{ExternRef, VecExternRef};
|
||||
|
@ -67,6 +66,28 @@ impl Script for WebAssemblyScript {
|
|||
&self.suppressed_count
|
||||
}
|
||||
|
||||
fn stack(&self) {
|
||||
if !self.capabilities.contains(&WebAssemblyScriptCapabilities::OnStack) {
|
||||
return;
|
||||
}
|
||||
let env = self.environment.upgrade().unwrap();
|
||||
let func = env.script_function_cache().stack(&env);
|
||||
if let Some(func) = func {
|
||||
func.call(self.self_ptr).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_remove(&self) {
|
||||
if !self.capabilities.contains(&WebAssemblyScriptCapabilities::OnRemove) {
|
||||
return;
|
||||
}
|
||||
let env = self.environment.upgrade().unwrap();
|
||||
let func = env.script_function_cache().on_remove(&env);
|
||||
if let Some(func) = func {
|
||||
func.call(self.self_ptr).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_initialize(&self, library: &DynamicLibrary, pars: &[EffectParameter]) {
|
||||
if !self.capabilities.contains(&WebAssemblyScriptCapabilities::Initialize) {
|
||||
return;
|
||||
|
@ -101,15 +122,30 @@ impl Script for WebAssemblyScript {
|
|||
}
|
||||
|
||||
let env = self.environment.upgrade().unwrap();
|
||||
let exported = env.exported_functions();
|
||||
if let Some(f) = exported.get::<StringKey>(&"script_change_speed".into()) {
|
||||
let func: NativeFunc<(u32, ExternRef<TurnChoice>, u32), ()> = f.native().unwrap();
|
||||
let ptr = env.temp_allocate_mem_typed::<u32>();
|
||||
let func = env.script_function_cache().change_speed(&env);
|
||||
if let Some(func) = func {
|
||||
let ptr = env.temp_allocate_mem_typed::<u32>(*speed);
|
||||
func.call(self.self_ptr, ExternRef::new(env.as_ref(), choice), ptr.wasm_pointer)
|
||||
.unwrap();
|
||||
unsafe {
|
||||
*speed = *ptr.ptr;
|
||||
}
|
||||
*speed = *ptr.value();
|
||||
}
|
||||
}
|
||||
|
||||
fn change_priority(&self, choice: &TurnChoice, priority: &mut i8) {
|
||||
if !self
|
||||
.capabilities
|
||||
.contains(&WebAssemblyScriptCapabilities::ChangePriority)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let env = self.environment.upgrade().unwrap();
|
||||
let func = env.script_function_cache().change_priority(&env);
|
||||
if let Some(func) = func {
|
||||
let ptr = env.temp_allocate_mem_typed::<i8>(*priority);
|
||||
func.call(self.self_ptr, ExternRef::new(env.as_ref(), choice), ptr.wasm_pointer)
|
||||
.unwrap();
|
||||
*priority = *ptr.value();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,16 +10,18 @@ use crate::script_implementations::wasm::script_resolver::WebAssemblyEnvironment
|
|||
use crate::static_data::EffectParameter;
|
||||
use crate::StringKey;
|
||||
|
||||
/// A macro to generate the script function cache a bit easier.
|
||||
macro_rules! script_function_cache {
|
||||
(
|
||||
$(
|
||||
$name:ident -> $return:ty
|
||||
$name:ident($($par_type:ty),*$(,)?)
|
||||
)*
|
||||
) => {
|
||||
#[derive(Default)]
|
||||
#[allow(unused_parens)]
|
||||
pub struct ScriptFunctionCache {
|
||||
$(
|
||||
$name: RwLock<Option<$return>>,
|
||||
$name: RwLock<Option<NativeFunc<(u32$(, $par_type)*), ()>>>,
|
||||
)*
|
||||
}
|
||||
|
||||
|
@ -27,20 +29,22 @@ macro_rules! script_function_cache {
|
|||
$(
|
||||
paste! {
|
||||
#[cold]
|
||||
#[allow(unused_parens)]
|
||||
fn [<initialize_ $name>](&self, env: &Arc<WebAssemblyEnvironmentData>) {
|
||||
let exported = env.exported_functions();
|
||||
let f = exported.get::<StringKey>(&stringify!([< script_ $name >]).into());
|
||||
if let Some(f) = f {
|
||||
let func: $return = f.native().unwrap();
|
||||
let func: NativeFunc<(u32 $(,$par_type)*), ()> = f.native().unwrap();
|
||||
let _ = self.$name.write().insert(func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[allow(unused_parens)]
|
||||
pub(crate) fn [<$name>](
|
||||
&self,
|
||||
env: &Arc<WebAssemblyEnvironmentData>,
|
||||
) -> Option<$return> {
|
||||
) -> Option<NativeFunc<(u32 $(,$par_type)*), ()>> {
|
||||
{
|
||||
let read_lock = self.$name.read();
|
||||
if let Some(f) = read_lock.as_ref() {
|
||||
|
@ -57,6 +61,10 @@ macro_rules! script_function_cache {
|
|||
}
|
||||
|
||||
script_function_cache! {
|
||||
on_initialize -> NativeFunc<(u32, ExternRef<DynamicLibrary>, VecExternRef<EffectParameter>), ()>
|
||||
on_before_turn -> NativeFunc<(u32, ExternRef<TurnChoice>), ()>
|
||||
stack()
|
||||
on_remove()
|
||||
on_initialize(ExternRef<DynamicLibrary>, VecExternRef<EffectParameter>)
|
||||
on_before_turn(ExternRef<TurnChoice>)
|
||||
change_speed(ExternRef<TurnChoice>, u32)
|
||||
change_priority(ExternRef<TurnChoice>, u32)
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ pub struct WebAssemblyScriptResolver {
|
|||
/// WASM calls.
|
||||
script_capabilities: RwLock<HashMap<ScriptCapabilitiesKey, Arc<HashSet<WebAssemblyScriptCapabilities>>>>,
|
||||
|
||||
/// The data for use in the scripting function calls.
|
||||
environment_data: Arc<WebAssemblyEnvironmentData>,
|
||||
}
|
||||
|
||||
|
@ -102,10 +103,8 @@ impl WebAssemblyScriptResolver {
|
|||
let exports = &instance.exports;
|
||||
|
||||
let init_fn = exports.get_extern("_init");
|
||||
if let Some(init_fn) = init_fn {
|
||||
if let Extern::Function(init_fn) = init_fn {
|
||||
init_fn.call(&[]).unwrap();
|
||||
}
|
||||
if let Some(Extern::Function(init_fn)) = init_fn {
|
||||
init_fn.call(&[]).unwrap();
|
||||
}
|
||||
|
||||
let mut exported_functions = self.environment_data.exported_functions.write();
|
||||
|
@ -245,6 +244,7 @@ pub struct WebAssemblyEnvironmentData {
|
|||
/// This is a map of all the functions that WASM gives us.
|
||||
exported_functions: RwLock<HashMap<StringKey, Function>>,
|
||||
|
||||
/// A cache of all script functions for faster calls.
|
||||
script_function_cache: ScriptFunctionCache,
|
||||
|
||||
/// This is the WASM function to allocate memory inside the WASM container.
|
||||
|
@ -254,10 +254,14 @@ pub struct WebAssemblyEnvironmentData {
|
|||
temp_allocator: RwLock<Option<TempWasmAllocator>>,
|
||||
}
|
||||
|
||||
/// A quick lookup so we can find the extern ref of the value.
|
||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||
struct ExternRefLookupKey {
|
||||
/// The raw pointer to the data
|
||||
pub ptr: *const u8,
|
||||
/// Whether or not the reference is a Vec
|
||||
pub is_vec: bool,
|
||||
/// The unique identifier of the type.
|
||||
pub t: u64,
|
||||
}
|
||||
|
||||
|
@ -324,8 +328,8 @@ impl WebAssemblyEnvironmentData {
|
|||
/// Allocate a piece of memory inside WASM with a very short lifespan. This is mainly used for
|
||||
/// rapid allocation of script function parameters, where WASM needs to write to a specific
|
||||
/// pointer.
|
||||
pub fn temp_allocate_mem_typed<T>(&self) -> AllocatedObject<T> {
|
||||
self.temp_allocator.read().as_ref().unwrap().alloc::<T>()
|
||||
pub fn temp_allocate_mem_typed<T>(&self, value: T) -> AllocatedObject<T> {
|
||||
self.temp_allocator.read().as_ref().unwrap().alloc::<T>(value)
|
||||
}
|
||||
|
||||
/// Get a numeric value from any given value. This is not a true Extern Ref from WASM, as this
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
use std::mem::size_of;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
/// A TempWasmAllocator is a bump allocator for use with very short lived allocations within WASM.
|
||||
/// This is for example used to allocate the values by reference in our script functions. These
|
||||
/// live only during the call, and then get deallocated again. Once everything is deallocated, we
|
||||
/// reset the allocator to the start again.
|
||||
pub(super) struct TempWasmAllocator {
|
||||
/// The raw pointer in host memory where the allocation lives.
|
||||
data: *mut u8,
|
||||
/// The pointer in client memory where the allocation lives.
|
||||
wasm_pointer: u32,
|
||||
/// The total amount we've currently allocated. This fluctuates up and down, when allocating
|
||||
/// and de-allocating. When this hits 0, the allocation gets reset.
|
||||
currently_allocated: AtomicUsize,
|
||||
/// The bump position for our allocations. we increment this when we allocate, but don't decrement
|
||||
/// when we de-allocate. We reset this to 0 when currently_allocated hits 0.
|
||||
offset_high: AtomicUsize,
|
||||
}
|
||||
|
||||
impl TempWasmAllocator {
|
||||
/// Creates a new allocator, with a given pointer to memory, and the associated position
|
||||
/// within WASM memory.
|
||||
pub(super) fn new(data: *mut u8, wasm_pointer: u32) -> Self {
|
||||
Self {
|
||||
data,
|
||||
|
@ -18,10 +30,14 @@ impl TempWasmAllocator {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn alloc<T>(&self) -> AllocatedObject<T> {
|
||||
/// Allocates a new object with a certain type.
|
||||
pub fn alloc<T>(&self, value: T) -> AllocatedObject<T> {
|
||||
self.currently_allocated.fetch_add(size_of::<T>(), Ordering::SeqCst);
|
||||
let ptr_offset = self.offset_high.fetch_add(size_of::<T>(), Ordering::SeqCst);
|
||||
let ptr = unsafe { self.data.add(ptr_offset) } as *mut T;
|
||||
unsafe {
|
||||
*ptr = value;
|
||||
}
|
||||
AllocatedObject::<T> {
|
||||
ptr,
|
||||
wasm_pointer: self.wasm_pointer + ptr_offset as u32,
|
||||
|
@ -29,6 +45,7 @@ impl TempWasmAllocator {
|
|||
}
|
||||
}
|
||||
|
||||
/// Drops an earlier allocated type.
|
||||
pub fn drop<T>(&self) {
|
||||
self.currently_allocated.fetch_sub(size_of::<T>(), Ordering::SeqCst);
|
||||
// As soon as we've no longer allocated anything, we reset our allocating back to the start.
|
||||
|
@ -38,12 +55,23 @@ impl TempWasmAllocator {
|
|||
}
|
||||
}
|
||||
|
||||
/// A value allocated within WASM memory. Once this goes out of scope, it gets deallocated,
|
||||
pub struct AllocatedObject<T> {
|
||||
/// The pointer in host memory to where the object lives.
|
||||
pub ptr: *mut T,
|
||||
/// The pointer in client memory to where the object lives.
|
||||
pub wasm_pointer: u32,
|
||||
/// A raw pointer to the allocator we use, so we know where to deallocate to.
|
||||
allocator: *const TempWasmAllocator,
|
||||
}
|
||||
|
||||
impl<T> AllocatedObject<T> {
|
||||
/// Gets the currently underlying value from the pointer.
|
||||
pub fn value(&self) -> &T {
|
||||
unsafe { &*self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for AllocatedObject<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
|
|
@ -17,9 +17,9 @@ impl From<u8> for TypeIdentifier {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for TypeIdentifier {
|
||||
fn into(self) -> u8 {
|
||||
self.val
|
||||
impl From<TypeIdentifier> for u8 {
|
||||
fn from(id: TypeIdentifier) -> Self {
|
||||
id.val
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,14 +36,13 @@ pub fn load_library() -> DynamicLibrary {
|
|||
let mut resolver = WebAssemblyScriptResolver::new();
|
||||
load_wasm(&path, resolver.as_mut());
|
||||
|
||||
let dynamic = DynamicLibrary::new(
|
||||
DynamicLibrary::new(
|
||||
data,
|
||||
Box::new(Gen7BattleStatCalculator {}),
|
||||
Box::new(Gen7DamageLibrary::new(false)),
|
||||
Box::new(Gen7MiscLibrary::new()),
|
||||
resolver,
|
||||
);
|
||||
dynamic
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_types(path: &String, type_library: &mut TypeLibrary) {
|
||||
|
|
|
@ -18,7 +18,7 @@ pub mod common;
|
|||
|
||||
static LIBRARY: OnceCell<Arc<DynamicLibrary>> = OnceCell::uninit();
|
||||
|
||||
fn get_library<'a>() -> Arc<DynamicLibrary> {
|
||||
fn get_library() -> Arc<DynamicLibrary> {
|
||||
LIBRARY
|
||||
.get_or_init(|| {
|
||||
let start_time = chrono::Utc::now();
|
||||
|
@ -47,7 +47,7 @@ fn integration_tests(input: &Path) {
|
|||
let mut str: String = "".to_string();
|
||||
let mut file = File::open(input).unwrap();
|
||||
file.read_to_string(&mut str).unwrap();
|
||||
let test_case = serde_yaml::from_str::<TestCase>(&*str).unwrap();
|
||||
let test_case = serde_yaml::from_str::<TestCase>(&str).unwrap();
|
||||
println!("\tRunning integration test {}", test_case.name);
|
||||
test_case.run_test(get_library());
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ fn integration_tests(input: &Path) {
|
|||
fn validate_script() {
|
||||
let lib = get_library();
|
||||
let script = lib
|
||||
.load_script(0 as *const u8, ScriptCategory::Move, &"test".into())
|
||||
.load_script(std::ptr::null(), ScriptCategory::Move, &"test".into())
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let parameters = [EffectParameter::String("foo".into())];
|
||||
|
@ -71,7 +71,7 @@ fn validate_script() {
|
|||
fn validate_script_2() {
|
||||
let lib = get_library();
|
||||
let script = lib
|
||||
.load_script(0 as *const u8, ScriptCategory::Move, &"test".into())
|
||||
.load_script(std::ptr::null(), ScriptCategory::Move, &"test".into())
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let user = Arc::new(
|
||||
|
|
Loading…
Reference in New Issue