From a4ac678154a7b6bc7e15513f00f0e248d09cb7e0 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 22 May 2022 13:00:53 +0200 Subject: [PATCH] Adds a lot more WASM type registry --- .../Library/WASMAbilityRegistry.cpp | 13 ++++++++++++ .../Library/WASMAbilityRegistry.hpp | 10 +++++++++ .../Library/WASMEffectParameter.cpp | 16 ++++++++++++++ .../Library/WASMEffectParameter.hpp | 10 +++++++++ .../Library/WASMFormeRegistry.hpp | 3 +-- .../WASM/InterfaceMethods/TypeRegistry.hpp | 10 +++++++-- .../WASM/InterfaceMethods/WASMHelperFile.hpp | 8 ++++++- .../InterfaceMethods/WASMListRegistry.cpp | 20 ++++++++++++++++++ .../InterfaceMethods/WASMListRegistry.hpp | 10 +++++++++ .../WASM/InterfaceMethods/WASMStringView.cpp | 4 ++-- .../{pkmn_lib.wit => pkmn_lib_host.wit} | 15 ++++++++----- .../WASM/WebAssemblyBattleScript.cpp | 7 +++--- tests/ScriptTests/WASM/gen7_scripts_rs.wasm | Bin 28446 -> 32142 bytes 13 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.cpp create mode 100644 src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.hpp create mode 100644 src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.cpp create mode 100644 src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.hpp create mode 100644 src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.cpp create mode 100644 src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.hpp rename src/ScriptResolving/WASM/InterfaceMethods/{pkmn_lib.wit => pkmn_lib_host.wit} (93%) diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.cpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.cpp new file mode 100644 index 0000000..0b01454 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.cpp @@ -0,0 +1,13 @@ +#include "WASMAbilityRegistry.hpp" +#include "../WASMHelperFile.hpp" +#include "wasm.h" + +using namespace CreatureLib::Library; +using namespace PkmnLib::Library; + +void WASMAbilityRegistry::Register(ArbUt::Dictionary& externs, + WebAssemblyScriptResolver* resolver) { + REGISTER_GETTER("ability_get_name", Talent, GetName, resolver); + REGISTER_GETTER("ability_get_effect", Talent, GetEffect, resolver); + REGISTER_GETTER("ability_get_parameters", Talent, GetParameters, resolver); +} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.hpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.hpp new file mode 100644 index 0000000..75e4837 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMAbilityRegistry.hpp @@ -0,0 +1,10 @@ +#ifndef PKMNLIB_WASMABILITYREGISTRY_HPP +#define PKMNLIB_WASMABILITYREGISTRY_HPP +#include "../../WebAssemblyScriptResolver.hpp" + +class WASMAbilityRegistry { +public: + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); +}; + +#endif // PKMNLIB_WASMABILITYREGISTRY_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.cpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.cpp new file mode 100644 index 0000000..612e105 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.cpp @@ -0,0 +1,16 @@ +#include "WASMEffectParameter.hpp" +#include "../../../../Battling/Library/BattleLibrary.hpp" +#include "../../WebAssemblyScriptResolver.hpp" +#include "../WASMHelperFile.hpp" +#include "wasm.h" + +using namespace CreatureLib::Library; + +void WASMEffectParameter::Register(ArbUt::Dictionary& externs, + WebAssemblyScriptResolver* resolver) { + REGISTER_GETTER("effect_parameter_get_type", EffectParameter, GetType, resolver) + REGISTER_GETTER("effect_parameter_as_bool", EffectParameter, AsBool, resolver) + REGISTER_GETTER("effect_parameter_as_int", EffectParameter, AsInt, resolver) + REGISTER_GETTER("effect_parameter_as_float", EffectParameter, AsFloat, resolver) + REGISTER_GETTER("effect_parameter_as_string", EffectParameter, AsString, resolver) +} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.hpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.hpp new file mode 100644 index 0000000..2793ed0 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMEffectParameter.hpp @@ -0,0 +1,10 @@ +#ifndef PKMNLIB_WASMEFFECTPARAMETER_HPP +#define PKMNLIB_WASMEFFECTPARAMETER_HPP +#include "../../WebAssemblyScriptResolver.hpp" + +class WASMEffectParameter { +public: + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); +}; + +#endif // PKMNLIB_WASMEFFECTPARAMETER_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMFormeRegistry.hpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMFormeRegistry.hpp index 9dd74cc..3ccdd55 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMFormeRegistry.hpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMFormeRegistry.hpp @@ -7,8 +7,7 @@ class WebAssemblyScriptResolver; class WASMFormeRegistry { public: - static void Register(ArbUt::Dictionary& externs, - WebAssemblyScriptResolver* resolver); + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); }; #endif // PKMNLIB_WASMFORMEREGISTRY_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp b/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp index c27fdd9..664c563 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp @@ -5,11 +5,14 @@ #include "../WebAssemblyScriptResolver.hpp" #include "Arbutils/Collections/Dictionary.hpp" #include "Library/LibraryMethods.hpp" +#include "Library/WASMAbilityRegistry.hpp" +#include "Library/WASMEffectParameter.hpp" +#include "Library/WASMFormeRegistry.hpp" #include "Library/WASMItemRegistry.hpp" #include "Library/WASMMoveDataRegistry.hpp" #include "Library/WASMSpeciesRegistry.hpp" -#include "Library/WASMFormeRegistry.hpp" #include "WASMCoreMethods.hpp" +#include "WASMListRegistry.hpp" #include "WASMStringView.hpp" class TypeRegistry { @@ -17,12 +20,15 @@ public: static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver) { WASMCoreMethods::Register(externs, resolver); WASMStringView::Register(externs, resolver); + WASMListRegistry::Register(externs, resolver); + LibraryMethods::Register(externs, resolver); + WASMEffectParameter::Register(externs, resolver); WASMMoveDataRegistry::Register(externs, resolver); WASMItemRegistry::Register(externs, resolver); WASMSpeciesRegistry::Register(externs, resolver); WASMFormeRegistry::Register(externs, resolver); - + WASMAbilityRegistry::Register(externs, resolver); } }; diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp index a6f2cd1..95af186 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp @@ -1,6 +1,7 @@ #ifndef PKMNLIB_HELPERFILE_H #define PKMNLIB_HELPERFILE_H #include +#include #include #include #include @@ -122,8 +123,10 @@ private: } } else if constexpr (std::is_same()) { return wasm_valtype_new_i64(); + } else if constexpr (is_specialization()) { + return wasm_valtype_new_i64(); } - THROW("Unhandled value type: ", std::string(typeid(T).name())); + THROW("Unhandled value type: ", std::string(abi::__cxa_demangle(typeid(T).name(), 0, 0, 0))); } template inline static wasm_val_t ToVal(const T& val) { @@ -150,6 +153,9 @@ private: } else if constexpr (std::is_same()) { auto v = &val; return WASM_I64_VAL(reinterpret_cast(v)); + } else if constexpr (is_specialization()) { + auto v = &val; + return WASM_I64_VAL(reinterpret_cast(v)); } THROW("Unhandled value type: ", typeid(T).name()); } diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.cpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.cpp new file mode 100644 index 0000000..eab5e08 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.cpp @@ -0,0 +1,20 @@ +#include "WASMListRegistry.hpp" +#include "WASMHelperFile.hpp" + +wasm_func_t* List_GetLength(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc*>( + resolver, {[](WebAssemblyScriptResolver*, const ArbUt::List* list) -> size_t { return list->Count(); }}); +} + +wasm_func_t* List_GetValue(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc*, size_t>( + resolver, {[](WebAssemblyScriptResolver*, const ArbUt::List* list, size_t index) -> void* { + return list->At(index); + }}); +} + +void WASMListRegistry::Register(ArbUt::Dictionary& externs, + WebAssemblyScriptResolver* resolver) { + externs.Insert("list_get_length", List_GetLength(resolver)); + externs.Insert("list_get_at", List_GetValue(resolver)); +} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.hpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.hpp new file mode 100644 index 0000000..b327356 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMListRegistry.hpp @@ -0,0 +1,10 @@ +#ifndef PKMNLIB_WASMLISTREGISTRY_HPP +#define PKMNLIB_WASMLISTREGISTRY_HPP +#include "../WebAssemblyScriptResolver.hpp" + +class WASMListRegistry { +public: + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); +}; + +#endif // PKMNLIB_WASMLISTREGISTRY_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp index 4628c17..e0fcab6 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp @@ -23,6 +23,6 @@ wasm_func_t* ConstString_GetStr(WebAssemblyScriptResolver* resolver) { void WASMStringView::Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver) { - externs.Insert("arbutils_const_string_get_hash", ConstString_GetHash(resolver)); - externs.Insert("arbutils_const_string_get_str", ConstString_GetStr(resolver)); + externs.Insert("const_string_get_hash", ConstString_GetHash(resolver)); + externs.Insert("const_string_get_str", ConstString_GetStr(resolver)); } diff --git a/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib.wit b/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib_host.wit similarity index 93% rename from src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib.wit rename to src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib_host.wit index a60bb5d..c17bea1 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib.wit +++ b/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib_host.wit @@ -1,4 +1,5 @@ -// This file documents the entire interface API currently used by the WebAssembly script resolver. +// This file documents the entire Host interface API currently used by the WebAssembly script resolver, so the methods +// that can be used from the client wasm. // Currently, we only define a bunch of functions, but in the future when interface types are actually implemented, // we'd like to implement those as well. @@ -11,10 +12,15 @@ _print: function(i32 message_pointer, s32 message_length) // StringView class type const_string = u64; -arbutils_const_string_get_hash: function(const_string ptr) -> u32 +const_string_get_hash: function(const_string ptr) -> u32 // Returns a pointer to the WASM memory where the string can be found. // NOTE: This requires us to copy the string into WASM memory. -arbutils_const_string_get_str: function(const_string ptr) -> s32 +const_string_get_str: function(const_string ptr) -> s32 + +// List class +type list = u64 +list_get_length: function(list) -> u64 +list_get_at: function(list, u64) -> u64 // Library types type pokemon_library = u64 @@ -149,5 +155,4 @@ forme_get_hidden_ability_count: function(forme) -> u64 forme_get_ability: function(forme, bool hidden, u8 index) -> ability forme_has_flag_by_hash: function(forme, u32) -> bool - - +// Ability class diff --git a/src/ScriptResolving/WASM/WebAssemblyBattleScript.cpp b/src/ScriptResolving/WASM/WebAssemblyBattleScript.cpp index faa276e..63d14bf 100644 --- a/src/ScriptResolving/WASM/WebAssemblyBattleScript.cpp +++ b/src/ScriptResolving/WASM/WebAssemblyBattleScript.cpp @@ -22,15 +22,16 @@ WebAssemblyBattleScript::~WebAssemblyBattleScript() { if (!funcOpt.has_value()) { \ return; \ } \ - auto& func = funcOpt.value(); \ + auto& func = funcOpt.value(); \ parameter_setup; \ func.Call(); void WebAssemblyBattleScript::OnInitialize(const CreatureLib::Battling::BattleLibrary* library, - const ArbUt::List&) { - WASM_CALL(Initialize, "script_on_initialize", 2, 0, { + const ArbUt::List& parameters) { + WASM_CALL(Initialize, "script_on_initialize", 3, 0, { func.Loadi32(0, _wasmPtr); func.LoadExternRef(1, library); + func.LoadExternRef(2, ¶meters); }); } diff --git a/tests/ScriptTests/WASM/gen7_scripts_rs.wasm b/tests/ScriptTests/WASM/gen7_scripts_rs.wasm index 7ef8adae8c99345c7d1d4fc57b670fdfad4864bd..b4e087553d942361cef285262297be63665033df 100755 GIT binary patch delta 7865 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