diff --git a/src/Library/Items/ItemLibrary.hpp b/src/Library/Items/ItemLibrary.hpp index 5ad39cd..4bb4e5d 100644 --- a/src/Library/Items/ItemLibrary.hpp +++ b/src/Library/Items/ItemLibrary.hpp @@ -6,17 +6,23 @@ namespace PkmnLib::Library { class ItemLibrary final : public CreatureLib::Library::ItemLibrary { public: - inline std::optional> TryGet(const ArbUt::BasicStringView& name) const { - auto res = CreatureLib::Library::ItemLibrary::TryGet(name.GetHash()); + inline std::optional> TryGet(const ArbUt::StringView& name) const { + auto res = CreatureLib::Library::ItemLibrary::TryGet(name); + if (!res.has_value()) + return {}; + return res.value().ForceAs(); + } + inline std::optional> TryGet(u32 hashedKey) const { + auto res = CreatureLib::Library::ItemLibrary::TryGetByHash(hashedKey); if (!res.has_value()) return {}; return res.value().ForceAs(); } - inline ArbUt::BorrowedPtr Get(const ArbUt::BasicStringView& name) const { + inline ArbUt::BorrowedPtr Get(const ArbUt::StringView& name) const { return CreatureLib::Library::ItemLibrary::Get(name).ForceAs(); } - inline ArbUt::BorrowedPtr operator[](const ArbUt::BasicStringView& name) const { return Get(name); } + inline ArbUt::BorrowedPtr operator[](const ArbUt::StringView& name) const { return Get(name); } }; } diff --git a/src/Library/Moves/MoveLibrary.hpp b/src/Library/Moves/MoveLibrary.hpp index 4e4a770..27c195e 100644 --- a/src/Library/Moves/MoveLibrary.hpp +++ b/src/Library/Moves/MoveLibrary.hpp @@ -12,24 +12,24 @@ namespace PkmnLib::Library { return Get(name); } - inline std::optional> TryGet(const ArbUt::BasicStringView& name) const { + inline std::optional> TryGet(const ArbUt::StringView& name) const { auto res = CreatureLib::Library::AttackLibrary::TryGet(name); if (!res.has_value()) return {}; return res.value().ForceAs(); } - inline std::optional> TryGet(u32 hash) const { - auto res = CreatureLib::Library::AttackLibrary::TryGet(hash); + inline std::optional> TryGetByHash(u32 hash) const { + auto res = CreatureLib::Library::AttackLibrary::TryGetByHash(hash); if (!res.has_value()) return {}; return res.value().ForceAs(); } - inline ArbUt::BorrowedPtr Get(const ArbUt::BasicStringView& name) const { + inline ArbUt::BorrowedPtr Get(const ArbUt::StringView& name) const { return CreatureLib::Library::AttackLibrary::Get(name).As(); } inline ArbUt::BorrowedPtr Get(u32 hash) const { - return CreatureLib::Library::AttackLibrary::Get(hash).As(); + return CreatureLib::Library::AttackLibrary::GetByHash(hash).As(); } }; } diff --git a/src/Library/Natures/NatureLibrary.hpp b/src/Library/Natures/NatureLibrary.hpp index 7119134..86a8dca 100644 --- a/src/Library/Natures/NatureLibrary.hpp +++ b/src/Library/Natures/NatureLibrary.hpp @@ -1,6 +1,7 @@ #ifndef PKMNLIB_NATURELIBRARY_HPP #define PKMNLIB_NATURELIBRARY_HPP +#include #include #include #include @@ -9,7 +10,7 @@ namespace PkmnLib::Library { class NatureLibrary { private: - std::unordered_map> _items; + ArbUt::StringViewDictionary> _items; public: explicit NatureLibrary(size_t size = 32) noexcept : _items(size) {} @@ -17,19 +18,23 @@ namespace PkmnLib::Library { ~NatureLibrary() = default; inline void LoadNature(const ArbUt::StringView& name, const Nature* nature) { - _items.insert({name, std::unique_ptr(nature)}); + _items.GetStdMap().insert({name, std::unique_ptr(nature)}); } inline ArbUt::BorrowedPtr GetNatureByName(const ArbUt::StringView& name) const { - return _items.at(name); + return _items.Get(name); + } + + inline ArbUt::BorrowedPtr GetNatureByHash(u32 hash) const { + return _items.GetFromHash(hash); } inline const ArbUt::StringView& GetRandomNatureName(ArbUt::Random rand = ArbUt::Random()) const { - auto i = rand.Get(_items.size()); + auto i = rand.Get(_items.Count()); return std::next(std::begin(_items), i)->first; } - inline ArbUt::StringView GetNatureName(ArbUt::BorrowedPtr nature) { + inline const ArbUt::StringView& GetNatureName(ArbUt::BorrowedPtr nature) { for (const auto& v : _items) { if (v.second.get() == nature.GetRaw()) { return v.first; @@ -38,7 +43,7 @@ namespace PkmnLib::Library { throw ArbUt::Exception("Nature not found."); } - size_t GetNatureCount() const noexcept { return _items.size(); } + size_t GetNatureCount() const noexcept { return _items.Count(); } inline const ArbUt::StringView& GetNatureFromIndex(size_t index) const { return std::next(std::begin(_items), index)->first; } diff --git a/src/Library/Species/SpeciesLibrary.hpp b/src/Library/Species/SpeciesLibrary.hpp index a82825c..7791c8f 100644 --- a/src/Library/Species/SpeciesLibrary.hpp +++ b/src/Library/Species/SpeciesLibrary.hpp @@ -12,19 +12,28 @@ namespace PkmnLib::Library { public: SpeciesLibrary(size_t initialCapacity = 32) : CreatureLib::Library::SpeciesLibrary(initialCapacity) {} - inline std::optional> - TryGet(const ArbUt::BasicStringView& name) const { + inline std::optional> TryGet(const ArbUt::StringView& name) const { auto res = CreatureLib::Library::SpeciesLibrary::TryGet(name); if (!res.has_value()) return {}; return res.value().ForceAs(); } - inline ArbUt::BorrowedPtr Get(const ArbUt::BasicStringView& name) const { - return CreatureLib::Library::SpeciesLibrary::Get(name).As(); + inline std::optional> TryGetByHash(u32 hashedKey) const { + auto res = CreatureLib::Library::SpeciesLibrary::TryGetByHash(hashedKey); + if (!res.has_value()) + return {}; + return res.value().ForceAs(); } - ArbUt::BorrowedPtr operator[](const ArbUt::BasicStringView& name) const { + inline ArbUt::BorrowedPtr Get(const ArbUt::StringView& name) const { + return CreatureLib::Library::SpeciesLibrary::Get(name).As(); + } + inline ArbUt::BorrowedPtr GetByHash(u32 hashedKey) const { + return CreatureLib::Library::SpeciesLibrary::GetByHash(hashedKey).As(); + } + + ArbUt::BorrowedPtr operator[](const ArbUt::StringView& name) const { return Get(name); } diff --git a/src/ScriptResolving/WASM/InterfaceMethods/CoreMethods.cpp b/src/ScriptResolving/WASM/InterfaceMethods/CoreMethods.cpp deleted file mode 100644 index edef7e6..0000000 --- a/src/ScriptResolving/WASM/InterfaceMethods/CoreMethods.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "CoreMethods.hpp" -#include -#include "../WebAssemblyScriptResolver.hpp" -#include "WasmHelperFile.hpp" -#include "wasm.h" - -wasm_func_t* CreateErrorFunc(wasm_store_t* store, WebAssemblyScriptResolver* resolver) { - // This is probably the most horrific function we need to expose. As we do not want the scripting library to be - // responsible for string formatting for size reasons, we pass a lot of data separately. This includes several - // strings. - return WasmHelpers::CreateFunc( - store, resolver, [](void* env, const wasm_val_vec_t* args, wasm_val_vec_t*) -> wasm_trap_t* { - auto msg = args->data[0].of.i32; - auto msg_len = args->data[1].of.i32; - auto file = args->data[2].of.i32; - auto file_len = args->data[3].of.i32; - auto line = args->data[4].of.i32; - auto position = args->data[5].of.i32; - - auto* resolver = (WebAssemblyScriptResolver*)env; - auto* msgPointer = wasm_memory_data(resolver->GetMemory()) + msg; - auto* filePointer = wasm_memory_data(resolver->GetMemory()) + file; - - auto msgString = std::string_view(msgPointer, msg_len); - auto fileString = std::string_view(filePointer, file_len); - - std::stringstream fullMessage; - fullMessage << "WASM Error with message: " << msgString << std::endl - << "in file: " << fileString << ". Line: " << line << ":" << position; - - wasm_message_t message; - wasm_name_new_from_string_nt(&message, fullMessage.str().c_str()); - wasm_trap_t* trap = wasm_trap_new(resolver->GetStore(), &message); - wasm_name_delete(&message); - return trap; - }); -} - -wasm_func_t* CreatePrintFunc(wasm_store_t* store, WebAssemblyScriptResolver* resolver) { - return WasmHelpers::CreateFunc( - store, resolver, [](void* env, const wasm_val_vec_t* args, wasm_val_vec_t*) -> wasm_trap_t* { - auto msg = args->data[0].of.i32; - auto msg_len = args->data[1].of.i32; - auto resolver = (WebAssemblyScriptResolver*)env; - auto* msgPointer = wasm_memory_data(resolver->GetMemory()) + msg; - auto msgString = std::string_view(msgPointer, msg_len); - std::cout << msgString << std::endl; - return nullptr; - }); - ; -} - -wasm_func_t* ConstString_GetHash(wasm_store_t* store, WebAssemblyScriptResolver* resolver) { - return WasmHelpers::CreateFunc2( - store, resolver, - std::function( - [](WebAssemblyScriptResolver*, const ArbUt::StringView* sv) -> u32 { return sv->GetHash(); })); -} - -wasm_func_t* ConstString_GetStr(wasm_store_t* store, WebAssemblyScriptResolver* resolver) { - return WasmHelpers::CreateFunc( - store, resolver, [](void* env, const wasm_val_vec_t* args, wasm_val_vec_t* returns) -> wasm_trap_t* { - auto resolver = (WebAssemblyScriptResolver*)env; - auto& constString = *(ArbUt::StringView*)args->data[0].of.i64; - - // To allow webassembly to access the C String, we need to allocate it inside it's memory. - // Length + 1 to make room for the '\0' - auto stringPointer = resolver->AllocateMemory(constString.Length() + 1, std::alignment_of()); - - // After we have the pointer to the memory allocated for the string, copy the string with specified length - // to it, then suffix it with the null byte to end it. - strncpy(reinterpret_cast(stringPointer.first), constString.c_str(), constString.Length()); - stringPointer.first[constString.Length()] = '\0'; - - returns->data[0] = WASM_I32_VAL(stringPointer.second); - return nullptr; - }); -} - -void WebAssemblyCoreMethods::Register(wasm_store_t* store, ArbUt::Dictionary& externs, - WebAssemblyScriptResolver* resolver) { - externs.Insert("_error", CreateErrorFunc(store, resolver)); - externs.Insert("_print", CreatePrintFunc(store, resolver)); - externs.Insert("arbutils_const_string_get_hash", ConstString_GetHash(store, resolver)); - externs.Insert("arbutils_const_string_get_str", ConstString_GetStr(store, resolver)); -} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/CoreMethods.hpp b/src/ScriptResolving/WASM/InterfaceMethods/CoreMethods.hpp deleted file mode 100644 index 0bf9bf6..0000000 --- a/src/ScriptResolving/WASM/InterfaceMethods/CoreMethods.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef PKMNLIB_COREMETHODS_HPP -#define PKMNLIB_COREMETHODS_HPP - -#include -#include - -class WebAssemblyScriptResolver; -class WebAssemblyCoreMethods { -public: - static void Register(wasm_store_t* store, ArbUt::Dictionary& externs, - WebAssemblyScriptResolver* resolver); -}; - -#endif // PKMNLIB_COREMETHODS_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.cpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.cpp index 58c7cec..ddf6b32 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.cpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.cpp @@ -2,38 +2,115 @@ #include #include "../../../../Battling/Library/BattleLibrary.hpp" #include "../../WebAssemblyScriptResolver.hpp" -#include "../WasmHelperFile.hpp" +#include "../WASMHelperFile.hpp" #include "wasm.h" -wasm_func_t* MoveLibrary_GetMoveByHash(wasm_store_t* store) { - wasm_functype_t* type = - wasm_functype_new_2_1(wasm_valtype_new_i64(), wasm_valtype_new_i32(), wasm_valtype_new_i64()); - auto* f = wasm_func_new(store, type, [](const wasm_val_vec_t* args, wasm_val_vec_t* returns) -> wasm_trap_t* { - auto moveLibrary = (PkmnLib::Library::MoveLibrary*)args->data[0].of.i64; - auto hash = (u32)args->data[1].of.i32; - auto opt = moveLibrary->TryGet(hash); - if (!opt.has_value()) { - returns->data[0] = WASM_I64_VAL(0); - } else{ - returns->data[0] = WASM_I64_VAL(reinterpret_cast(moveLibrary->Get(hash).GetRaw())); - } - return nullptr; - }); - wasm_functype_delete(type); - return f; +using namespace PkmnLib::Library; + +#define BASELIBRARY_GET_VALUE_FUNC(type, value_type) \ + wasm_func_t* type##Library_Get##type##ByHash(WebAssemblyScriptResolver* resolver) { \ + return WasmHelpers::CreateFunc( \ + resolver, {[](WebAssemblyScriptResolver*, type##Library* lib, u32 hash) -> const value_type* { \ + auto opt = lib->TryGetByHash(hash); \ + if (!opt.has_value()) { \ + return nullptr; \ + } \ + return opt.value(); \ + }}); \ + } + +BASELIBRARY_GET_VALUE_FUNC(Species, PokemonSpecies) +BASELIBRARY_GET_VALUE_FUNC(Move, MoveData) +BASELIBRARY_GET_VALUE_FUNC(Item, CreatureLib::Library::Item) + +#define REGISTER_BASE_LIB_FUNCS(typeName, type) \ + externs.Insert(typeName "_library_get_" typeName "_by_hash", type##Library_Get##type##ByHash(resolver)) + +wasm_func_t* GrowthRates_CalculateLevelWithHash(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, CreatureLib::Library::GrowthRateLibrary* lib, u32 hash, + u32 experience) -> level_int_t { return lib->CalculateLevel(hash, experience); }}); } -void LibraryMethods::Register(wasm_store_t* store, ArbUt::Dictionary& externs, +wasm_func_t* GrowthRates_CalculateExperienceWithHash(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, CreatureLib::Library::GrowthRateLibrary* lib, u32 hash, + level_int_t level) -> u32 { return lib->CalculateExperience(hash, level); }}); +} + +wasm_func_t* TypeLibrary_GetTypeIdFromHash(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, CreatureLib::Library::TypeLibrary* lib, u32 hash) -> u8 { + return lib->GetTypeIdByHash(hash); + }}); +} + +wasm_func_t* TypeLibrary_GetSingleEffectiveness(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, CreatureLib::Library::TypeLibrary* lib, u8 attacking, + u8 defensive) -> float { return lib->GetSingleEffectiveness(attacking, defensive); }}); +} + +wasm_func_t* TypeLibrary_GetTypeName(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, CreatureLib::Library::TypeLibrary* lib, + u8 type) -> const ArbUt::StringView* { return &lib->GetTypeName(type); }}); +} + +wasm_func_t* NatureLibrary_GetNatureByHash(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, NatureLibrary* lib, u32 hash) -> const Nature* { + return lib->GetNatureByHash(hash); + }}); +} + +wasm_func_t* NatureLibrary_GetNatureName(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, NatureLibrary* lib, + const Nature* nature) -> const ArbUt::StringView* { return &lib->GetNatureName(nature); }}); +} + +void LibraryMethods::Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver) { - REGISTER_GETTER("battling_battle_library_get_data_library", PkmnLib::Battling::BattleLibrary, GetStaticLib, store, - resolver); - REGISTER_GETTER("library_data_library_get_move_library", PkmnLib::Library::PokemonLibrary, GetMoveLibrary, store, - resolver); - externs.Insert("library_move_library_get_move_by_hash", MoveLibrary_GetMoveByHash(store)); + REGISTER_GETTER("battle_library_get_data_library", PkmnLib::Battling::BattleLibrary, GetStaticLib, resolver) - REGISTER_GETTER("library_move_data_get_base_power", CreatureLib::Library::AttackData, GetBasePower, store, - resolver); + // Data Library + REGISTER_GETTER("data_library_get_settings", PokemonLibrary, GetSettings, resolver) + REGISTER_GETTER("data_library_get_species_library", PokemonLibrary, GetSpeciesLibrary, resolver) + REGISTER_GETTER("data_library_get_move_library", PokemonLibrary, GetMoveLibrary, resolver) + REGISTER_GETTER("data_library_get_item_library", PokemonLibrary, GetItemLibrary, resolver) + REGISTER_GETTER("data_library_get_growth_rates", CreatureLib::Library::DataLibrary, GetGrowthRates, resolver) + REGISTER_GETTER("data_library_get_type_library", CreatureLib::Library::DataLibrary, GetTypeLibrary, resolver) + REGISTER_GETTER("data_library_get_talent_library", CreatureLib::Library::DataLibrary, GetTalentLibrary, resolver) + REGISTER_GETTER("data_library_get_nature_library", PokemonLibrary, GetNatureLibrary, resolver) - REGISTER_GETTER("library_move_data_get_name", CreatureLib::Library::AttackData, GetName, store, - resolver); + // Library Settings + REGISTER_GETTER("settings_get_max_level", CreatureLib::Library::LibrarySettings, GetMaximalLevel, resolver) + REGISTER_GETTER("settings_get_max_moves", CreatureLib::Library::LibrarySettings, GetMaximalAttacks, resolver) + REGISTER_GETTER("settings_get_shiny_rate", LibrarySettings, GetShinyRate, resolver) + + // Base libraries + REGISTER_BASE_LIB_FUNCS("species", Species); + REGISTER_BASE_LIB_FUNCS("move", Move); + REGISTER_BASE_LIB_FUNCS("item", Item); + + // Growth Rates + externs.Insert("growthrate_library_calculate_level_by_hash", GrowthRates_CalculateLevelWithHash(resolver)); + externs.Insert("growthrate_library_calculate_experience_by_hash", + GrowthRates_CalculateExperienceWithHash(resolver)); + + // Type Library + externs.Insert("type_library_get_type_id_by_hash", TypeLibrary_GetTypeIdFromHash(resolver)); + externs.Insert("type_library_get_single_effectiveness", TypeLibrary_GetSingleEffectiveness(resolver)); + externs.Insert("type_library_get_type_name", TypeLibrary_GetTypeName(resolver)); + + // Nature Library + externs.Insert("nature_library_get_nature_by_hash", NatureLibrary_GetNatureByHash(resolver)); + externs.Insert("nature_library_get_nature_name", NatureLibrary_GetNatureName(resolver)); + + // Natures + REGISTER_GETTER("nature_get_increased_modifier", Nature, GetIncreaseModifier, resolver) + REGISTER_GETTER("nature_get_decreased_modifier", Nature, GetDecreaseModifier, resolver) + REGISTER_GETTER("nature_get_increased_stat", Nature, GetIncreasedStat, resolver) + REGISTER_GETTER("nature_get_decreased_stat", Nature, GetDecreasedStat, resolver) } diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.hpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.hpp index 6220258..46c51d0 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.hpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/LibraryMethods.hpp @@ -6,7 +6,7 @@ class WebAssemblyScriptResolver; class LibraryMethods { public: - static void Register(wasm_store_t* store, ArbUt::Dictionary& externs, + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); }; diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMMoveDataRegistry.cpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMMoveDataRegistry.cpp new file mode 100644 index 0000000..b3cf725 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMMoveDataRegistry.cpp @@ -0,0 +1,29 @@ +#include "WASMMoveDataRegistry.hpp" +#include +#include "../../../../Battling/Library/BattleLibrary.hpp" +#include "../../WebAssemblyScriptResolver.hpp" +#include "../WASMHelperFile.hpp" +#include "wasm.h" + +using namespace CreatureLib::Library; + +wasm_func_t* MoveData_HasFlagByHash(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, AttackData* move, u32 flag) -> bool { + return move->HasFlag(flag); + }}); +} + +void WASMMoveDataRegistry::Register(ArbUt::Dictionary& externs, + WebAssemblyScriptResolver* resolver) { + REGISTER_GETTER("move_data_get_name", AttackData, GetName, resolver) + REGISTER_GETTER("move_data_get_type", AttackData, GetType, resolver) + REGISTER_GETTER("move_data_get_category", AttackData, GetCategory, resolver) + REGISTER_GETTER("move_data_get_base_power", AttackData, GetBasePower, resolver); + REGISTER_GETTER("move_data_get_accuracy", AttackData, GetAccuracy, resolver); + REGISTER_GETTER("move_data_get_base_usages", AttackData, GetBaseUsages, resolver); + REGISTER_GETTER("move_data_get_target", AttackData, GetTarget, resolver); + REGISTER_GETTER("move_data_get_priority", AttackData, GetPriority, resolver); + REGISTER_GETTER("move_data_has_secondary_effect", AttackData, HasSecondaryEffect, resolver); + externs.Insert("move_data_has_flag_by_hash", MoveData_HasFlagByHash(resolver)); +} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMMoveDataRegistry.hpp b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMMoveDataRegistry.hpp new file mode 100644 index 0000000..c32d905 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/Library/WASMMoveDataRegistry.hpp @@ -0,0 +1,14 @@ +#ifndef PKMNLIB_WASMMOVEDATAREGISTRY_H +#define PKMNLIB_WASMMOVEDATAREGISTRY_H + +#include +#include + +class WebAssemblyScriptResolver; +class WASMMoveDataRegistry { +public: + static void Register(ArbUt::Dictionary& externs, + WebAssemblyScriptResolver* resolver); +}; + +#endif // PKMNLIB_WASMMOVEDATAREGISTRY_H diff --git a/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp b/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp new file mode 100644 index 0000000..bb9833f --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/TypeRegistry.hpp @@ -0,0 +1,22 @@ +#ifndef PKMNLIB_TYPEREGISTRY_HPP +#define PKMNLIB_TYPEREGISTRY_HPP + +#include +#include "../WebAssemblyScriptResolver.hpp" +#include "Arbutils/Collections/Dictionary.hpp" +#include "Library/LibraryMethods.hpp" +#include "Library/WASMMoveDataRegistry.hpp" +#include "WASMCoreMethods.hpp" +#include "WASMStringView.hpp" + +class TypeRegistry { +public: + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver) { + WASMCoreMethods::Register(externs, resolver); + WASMStringView::Register(externs, resolver); + LibraryMethods::Register(externs, resolver); + WASMMoveDataRegistry::Register(externs, resolver); + } +}; + +#endif // PKMNLIB_TYPEREGISTRY_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMCoreMethods.cpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMCoreMethods.cpp new file mode 100644 index 0000000..0d2c3bc --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMCoreMethods.cpp @@ -0,0 +1,45 @@ +#include "WASMCoreMethods.hpp" +#include +#include "../WebAssemblyScriptResolver.hpp" +#include "WASMHelperFile.hpp" +#include "wasm.h" + +wasm_func_t* CreateErrorFunc(WebAssemblyScriptResolver* resolver) { + // This is probably the most horrific function we need to expose. As we do not want the scripting library to be + // responsible for string formatting for size reasons, we pass a lot of data separately. This includes several + // strings. + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver* resolver, i32 msg, i32 msg_len, i32 file, i32 file_len, i32 line, + i32 position) -> wasm_trap_t* { + auto* msgPointer = wasm_memory_data(resolver->GetMemory()) + msg; + auto* filePointer = wasm_memory_data(resolver->GetMemory()) + file; + + auto msgString = std::string_view(msgPointer, msg_len); + auto fileString = std::string_view(filePointer, file_len); + + std::stringstream fullMessage; + fullMessage << "WASM Error with message: " << msgString << std::endl + << "in file: " << fileString << ". Line: " << line << ":" << position; + + wasm_message_t message; + wasm_name_new_from_string_nt(&message, fullMessage.str().c_str()); + wasm_trap_t* trap = wasm_trap_new(resolver->GetStore(), &message); + wasm_name_delete(&message); + return trap; + }}); +} + +wasm_func_t* CreatePrintFunc(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc(resolver, + {[](WebAssemblyScriptResolver* resolver, i32 msg, i32 msg_len) { + auto* msgPointer = wasm_memory_data(resolver->GetMemory()) + msg; + auto msgString = std::string_view(msgPointer, msg_len); + std::cout << msgString << std::endl; + }}); +} + +void WASMCoreMethods::Register(ArbUt::Dictionary& externs, + WebAssemblyScriptResolver* resolver) { + externs.Insert("_error", CreateErrorFunc(resolver)); + externs.Insert("_print", CreatePrintFunc(resolver)); +} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMCoreMethods.hpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMCoreMethods.hpp new file mode 100644 index 0000000..3b1a22e --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMCoreMethods.hpp @@ -0,0 +1,13 @@ +#ifndef PKMNLIB_WASMCOREMETHODS_HPP +#define PKMNLIB_WASMCOREMETHODS_HPP + +#include +#include + +class WebAssemblyScriptResolver; +class WASMCoreMethods { +public: + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); +}; + +#endif // PKMNLIB_WASMCOREMETHODS_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WasmHelperFile.hpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp similarity index 80% rename from src/ScriptResolving/WASM/InterfaceMethods/WasmHelperFile.hpp rename to src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp index b86b738..a6f2cd1 100644 --- a/src/ScriptResolving/WASM/InterfaceMethods/WasmHelperFile.hpp +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMHelperFile.hpp @@ -39,10 +39,10 @@ public: } template - static wasm_func_t* RegisterGetter(wasm_store_t* store, WebAssemblyScriptResolver* resolver) { + static wasm_func_t* RegisterGetter(WebAssemblyScriptResolver* resolver) { wasm_functype_t* type = wasm_functype_new_1_1(wasm_valtype_new_i64(), GetValType()); auto* f = wasm_func_new_with_env( - store, type, + resolver->GetStore(), type, [](void* env, const wasm_val_vec_t* args, wasm_val_vec_t* returns) -> wasm_trap_t* { try { auto obj = (const T*)args->data[0].of.i64; @@ -59,26 +59,17 @@ public: return f; } - template - static wasm_func_t* CreateFunc(wasm_store_t* store, WebAssemblyScriptResolver* resolver, - wasm_func_callback_with_env_t func) { - auto funcType = GetFuncType(); - auto* f = wasm_func_new_with_env(store, funcType, func, resolver, nullptr); - wasm_functype_delete(funcType); - return f; - } - template inline static T ConvertAllArguments(const wasm_val_vec_t* t, std::size_t& index) { return FromVal(t->data[index++]); } template - static wasm_func_t* CreateFunc2(wasm_store_t* store, WebAssemblyScriptResolver* resolver, - std::function func) { + static wasm_func_t* CreateFunc(WebAssemblyScriptResolver* resolver, + R (*func)(WebAssemblyScriptResolver*, Args...)) { auto funcType = GetFuncType(); struct Env { WebAssemblyScriptResolver* Resolver; - std::function Func; + R (*Func)(WebAssemblyScriptResolver*, Args...); ~Env() {} }; @@ -86,13 +77,19 @@ public: new (env) Env{.Resolver = resolver, .Func = func}; resolver->Temp_WasmerBug2_2_1_Bypass.Append(env); auto* f = wasm_func_new_with_env( - store, funcType, + resolver->GetStore(), funcType, [](void* env, const wasm_val_vec_t* parameters, wasm_val_vec_t* results) -> wasm_trap_t* { auto e = *(Env*)env; size_t index = 0; try { - R result = e.Func(e.Resolver, ConvertAllArguments(parameters, index)...); - results->data[0] = ToVal(result); + if constexpr (std::is_void()) { + e.Func(e.Resolver, ConvertAllArguments(parameters, index)...); + } else if constexpr (std::is_same()) { + return e.Func(e.Resolver, ConvertAllArguments(parameters, index)...); + } else { + R result = e.Func(e.Resolver, ConvertAllArguments(parameters, index)...); + results->data[0] = ToVal(result); + } } catch (ArbUt::Exception& exception) { return CreateTrapFromException(exception, e.Resolver); } catch (std::exception& exception) { @@ -117,10 +114,16 @@ private: } else { return wasm_valtype_new_i32(); } + } else if constexpr (std::is_floating_point()) { + if constexpr (sizeof(T) > 4) { + return wasm_valtype_new_f64(); + } else { + return wasm_valtype_new_f32(); + } } else if constexpr (std::is_same()) { return wasm_valtype_new_i64(); } - THROW("Unhandled value type: ", typeid(T).name()); + THROW("Unhandled value type: ", std::string(typeid(T).name())); } template inline static wasm_val_t ToVal(const T& val) { @@ -138,6 +141,12 @@ private: } else { return WASM_I32_VAL((i32)val); } + } else if constexpr (std::is_floating_point()) { + if constexpr (sizeof(T) > 4) { + return WASM_F64_VAL((f64)val); + } else { + return WASM_F32_VAL((f32)val); + } } else if constexpr (std::is_same()) { auto v = &val; return WASM_I64_VAL(reinterpret_cast(v)); @@ -156,9 +165,15 @@ private: return dynamic_cast(reinterpret_cast(val.of.i64)); } else if constexpr (std::is_enum() || std::is_integral()) { if constexpr (sizeof(T) > 4) { - return reinterpret_cast(val.of.i64); + return static_cast(val.of.i64); } else { - return reinterpret_cast(val.of.i32); + return static_cast(val.of.i32); + } + } else if constexpr (std::is_floating_point()) { + if constexpr (sizeof(T) > 4) { + return static_cast(val.of.f64); + } else { + return static_cast(val.of.f32); } } THROW("Unhandled value type: ", typeid(T).name()); @@ -177,7 +192,7 @@ private: AppendArgument<0, Args...>(ps); wasm_valtype_vec_t params, results; - if constexpr (std::is_void()) { + if constexpr (std::is_void() || std::is_same()) { results = WASM_EMPTY_VEC; } else { wasm_valtype_t* rs[1] = {GetValType()}; @@ -188,10 +203,10 @@ private: } }; -#define REGISTER_GETTER(name, cType, cFunc, store, resolver) \ +#define REGISTER_GETTER(name, cType, cFunc, resolver) \ externs.Insert( \ name, \ WasmHelpers::RegisterGetter::type, &cType::cFunc>( \ - store, resolver)); + resolver)); #endif // PKMNLIB_HELPERFILE_H diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp new file mode 100644 index 0000000..4628c17 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.cpp @@ -0,0 +1,28 @@ +#include "WASMStringView.hpp" +#include "WASMHelperFile.hpp" + +wasm_func_t* ConstString_GetHash(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver*, const ArbUt::StringView* sv) -> u32 { return sv->GetHash(); }}); +} + +wasm_func_t* ConstString_GetStr(WebAssemblyScriptResolver* resolver) { + return WasmHelpers::CreateFunc( + resolver, {[](WebAssemblyScriptResolver* resolver, const ArbUt::StringView* constString) -> i32 { + // To allow webassembly to access the C String, we need to allocate it inside it's memory. + // Length + 1 to make room for the '\0' + auto stringPointer = resolver->AllocateMemory(constString->Length() + 1, std::alignment_of()); + + // After we have the pointer to the memory allocated for the string, copy the string with specified length + // to it, then suffix it with the null byte to end it. + strncpy(reinterpret_cast(stringPointer.first), constString->c_str(), constString->Length()); + stringPointer.first[constString->Length()] = '\0'; + return stringPointer.second; + }}); +} + +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)); +} diff --git a/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.hpp b/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.hpp new file mode 100644 index 0000000..86c831b --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/WASMStringView.hpp @@ -0,0 +1,10 @@ +#ifndef PKMNLIB_WASMSTRINGVIEW_HPP +#define PKMNLIB_WASMSTRINGVIEW_HPP +#include "../WebAssemblyScriptResolver.hpp" + +class WASMStringView { +public: + static void Register(ArbUt::Dictionary& externs, WebAssemblyScriptResolver* resolver); +}; + +#endif // PKMNLIB_WASMSTRINGVIEW_HPP diff --git a/src/ScriptResolving/WASM/InterfaceMethods/gen7_scripts_rs.wasm b/src/ScriptResolving/WASM/InterfaceMethods/gen7_scripts_rs.wasm new file mode 100755 index 0000000..89c7b41 Binary files /dev/null and b/src/ScriptResolving/WASM/InterfaceMethods/gen7_scripts_rs.wasm differ diff --git a/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib.wit b/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib.wit new file mode 100644 index 0000000..cc5eaf7 --- /dev/null +++ b/src/ScriptResolving/WASM/InterfaceMethods/pkmn_lib.wit @@ -0,0 +1,111 @@ +// This file documents the entire interface API currently used by the WebAssembly script resolver. +// 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. + +// Core functions +// These are the core utility functions for use. +// _error can be used for crash handling in the script handler. It takes a message string, file name string, line and position. +_error: function(i32 message_pointer, s32 message_length, i32 file_pointer, i32 file_length, i32 line, i32 position) +// _print can be used to print a message to the hosts stdout +_print: function(i32 message_pointer, s32 message_length) + +// StringView class +type const_string = u64; +arbutils_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 + +// Library types +type pokemon_library = u64 +type library_settings = u64 +type species_library = u64 +type move_library = u64 +type item_library = u64 +type growth_rate_library = u64 +type type_library = u64 +type talent_library = u64 +type nature_library = u64 + +type level_int = u8 + +type species = u64 +type move = u64 +type item = u64 +type nature = u64 + +enum Statistic { + Health, + Attack, + Defense + SpecialAttack, + SpecialDefense, + Speed, +} + +// PokemonLibrary class +data_library_get_settings: function(pokemon_library ptr) -> library_settings +data_library_get_species_library: function(pokemon_library ptr) -> species_library +data_library_get_move_library: function(pokemon_library ptr) -> move_library +data_library_get_item_library: function(pokemon_library ptr) -> item_library +data_library_get_growth_rates: function(pokemon_library ptr) -> growth_rate_library +data_library_get_type_library: function(pokemon_library ptr) -> type_library +data_library_get_talent_library: function(pokemon_library ptr) -> talent_library +data_library_get_nature_library: function(pokemon_library ptr) -> nature_library + +// LibrarySettings class +library_settings_get_max_level: function(library_settings ptr) -> level_int +library_settings_get_max_moves: function(library_settings ptr) -> u8 +library_settings_get_shiny_rate: function(library_settings ptr) -> u16 + +// SpeciesLibrary class +species_library_get_species_by_hash: function(species_library library, u32 hash) -> species + +// MoveLibrary class +move_library_get_move_by_hash: function(move_library library, u32 hash) -> move + +// ItemLibrary class +item_library_get_item_by_hash: function(item_library library, u32 hash) -> item + +// GrowthRateLibrary class +growthrate_library_calculate_level_by_hash: function(growth_rate_library library, u32 hash, u32 experience) -> level_int +growthrate_library_calculate_experience_by_hash: function(growth_rate_library library, u32 hash, level_int level) -> u32 + +// TypeLibrary class +type_library_get_type_id_by_hash: function(type_library, u32 hash) -> u8 +type_library_get_single_effectiveness: function(type_library, u8 attacking, u8 offensive) -> f32 +type_library_get_type_name: function(type_library, u8 type) -> const_string + +// NatureLibrary class +nature_library_get_nature_by_hash: function(nature_library, u32 hash) -> nature +nature_library_get_nature_name: function(nature_library, nature) -> const_string + +// Nature class +nature_get_increased_modifier: function(nature) -> f32 +nature_get_decreased_modifier: function(nature) -> f32 +nature_get_increased_stat: function(nature) -> Statistic +nature_get_decreased_stat: function(nature) -> Statistic + +// MoveData class +enum MoveCategory { + Physical, Special, Status, +} +enum MoveTarget { + Adjacent, AdjacentAlly, AdjacentAllySelf, AdjacentOpponent, + All, AllAdjacent, AllAdjacentOpponent, AllAlly, AllOpponent, + Any, + RandomOpponent, Self +} + +move_data_get_name: function(move) -> const_string +move_data_get_type: function(move) -> u8 +move_data_get_category: function(move) -> MoveCategory +move_data_get_base_power: function(move) -> u8 +move_data_get_accuracy: function(move) -> u8 +move_data_get_base_usages: function(move) -> u8 +move_data_get_target: function(move) -> MoveTarget +move_data_get_priority: function(move) -> s8 +move_data_has_secondary_effect: function(move) -> bool +move_data_has_flag_by_hash: function(move, u32 hash) -> bool + + diff --git a/src/ScriptResolving/WASM/WebAssemblyScriptResolver.cpp b/src/ScriptResolving/WASM/WebAssemblyScriptResolver.cpp index f7eb1e8..0949ebb 100644 --- a/src/ScriptResolving/WASM/WebAssemblyScriptResolver.cpp +++ b/src/ScriptResolving/WASM/WebAssemblyScriptResolver.cpp @@ -2,8 +2,7 @@ #include #include #include -#include "InterfaceMethods/CoreMethods.hpp" -#include "InterfaceMethods/Library/LibraryMethods.hpp" +#include "InterfaceMethods/TypeRegistry.hpp" #include "WebAssemblyBattleScript.hpp" #include "WebAssemblyFunctionCall.hpp" #include "wasm.h" @@ -80,10 +79,7 @@ u8 WebAssemblyScriptResolver::LoadWatFromString(const std::string& data) { void WebAssemblyScriptResolver::RegisterFunction() {} -void WebAssemblyScriptResolver::RegisterDefaultMethods() { - WebAssemblyCoreMethods::Register(_store, _imports, this); - LibraryMethods::Register(_store, _imports, this); -} +void WebAssemblyScriptResolver::RegisterDefaultMethods() { TypeRegistry::Register(_imports, this); } void WebAssemblyScriptResolver::Finalize() { RegisterDefaultMethods(); diff --git a/tests/ScriptTests/WASM/gen7_scripts_rs.wasm b/tests/ScriptTests/WASM/gen7_scripts_rs.wasm index fce3ea3..7ef8ada 100755 Binary files a/tests/ScriptTests/WASM/gen7_scripts_rs.wasm and b/tests/ScriptTests/WASM/gen7_scripts_rs.wasm differ diff --git a/tests/TestLibrary/TestLibrary.cpp b/tests/TestLibrary/TestLibrary.cpp index f99a71c..5293b8f 100644 --- a/tests/TestLibrary/TestLibrary.cpp +++ b/tests/TestLibrary/TestLibrary.cpp @@ -4,7 +4,7 @@ PkmnLib::Battling::BattleLibrary* TestLibrary::_library = nullptr; PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib::Library::TalentLibrary* talentLibrary) { auto lib = new PkmnLib::Library::SpeciesLibrary(); - lib->Insert("testSpecies"_cnc.GetHash(), + lib->Insert("testSpecies"_cnc, new PkmnLib::Library::PokemonSpecies( 1, "testSpecies"_cnc, new PkmnLib::Library::PokemonForme( @@ -13,7 +13,7 @@ PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib:: {talentLibrary->Get("testAbility"_cnc)}, {talentLibrary->Get("testHiddenAbility"_cnc)}, new PkmnLib::Library::LearnableMoves(100)), 0.5f, "testGrowthRate"_cnc, 100, 100, {"testEggGroup"_cnc})); - lib->Insert("testSpecies2"_cnc.GetHash(), + lib->Insert("testSpecies2"_cnc, new PkmnLib::Library::PokemonSpecies( 2, "testSpecies2"_cnc, new PkmnLib::Library::PokemonForme( @@ -22,7 +22,7 @@ PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib:: {talentLibrary->Get("testAbility"_cnc)}, {talentLibrary->Get("testHiddenAbility"_cnc)}, new PkmnLib::Library::LearnableMoves(100)), 0.5f, "testGrowthRate"_cnc, 100, 100, {"testEggGroup"_cnc})); - lib->Insert("statTestSpecies1"_cnc.GetHash(), + lib->Insert("statTestSpecies1"_cnc, new PkmnLib::Library::PokemonSpecies( 3, "statTestSpecies1"_cnc, new PkmnLib::Library::PokemonForme( @@ -31,7 +31,7 @@ PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib:: {talentLibrary->Get("testAbility"_cnc)}, {talentLibrary->Get("testHiddenAbility"_cnc)}, new PkmnLib::Library::LearnableMoves(100)), 0.5f, "testGrowthRate"_cnc, 100, 100, {"testEggGroup"_cnc})); - lib->Insert("testSpecies3"_cnc.GetHash(), + lib->Insert("testSpecies3"_cnc, new PkmnLib::Library::PokemonSpecies( 4, "testSpecies3"_cnc, new PkmnLib::Library::PokemonForme( @@ -41,7 +41,7 @@ PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib:: new PkmnLib::Library::LearnableMoves(100)), 0.5f, "testGrowthRate"_cnc, 100, 100, {"testEggGroup"_cnc})); - lib->Insert("testCharizard"_cnc.GetHash(), + lib->Insert("testCharizard"_cnc, new PkmnLib::Library::PokemonSpecies( 5, "testCharizard"_cnc, new PkmnLib::Library::PokemonForme( @@ -50,7 +50,7 @@ PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib:: {talentLibrary->Get("testAbility"_cnc)}, {talentLibrary->Get("testHiddenAbility"_cnc)}, new PkmnLib::Library::LearnableMoves(100)), 0.5f, "testGrowthRate"_cnc, 100, 100, {"testEggGroup"_cnc})); - lib->Insert("testVenusaur"_cnc.GetHash(), + lib->Insert("testVenusaur"_cnc, new PkmnLib::Library::PokemonSpecies( 6, "testVenusaur"_cnc, new PkmnLib::Library::PokemonForme( @@ -64,11 +64,11 @@ PkmnLib::Library::SpeciesLibrary* TestLibrary::BuildSpeciesLibrary(CreatureLib:: } PkmnLib::Library::MoveLibrary* TestLibrary::BuildMoveLibrary() { auto lib = new PkmnLib::Library::MoveLibrary(); - lib->Insert("testMove"_cnc.GetHash(), + lib->Insert("testMove"_cnc, new PkmnLib::Library::MoveData("testMove"_cnc, 0, PkmnLib::Library::MoveCategory::Physical, 50, 100, 20, CreatureLib::Library::AttackTarget::Adjacent, 0, new CreatureLib::Library::SecondaryEffect(), {})); - lib->Insert("testMove2"_cnc.GetHash(), + lib->Insert("testMove2"_cnc, new PkmnLib::Library::MoveData("testMove2"_cnc, 0, PkmnLib::Library::MoveCategory::Special, 30, 100, 10, CreatureLib::Library::AttackTarget::Adjacent, 0, new CreatureLib::Library::SecondaryEffect(), {})); @@ -76,7 +76,7 @@ PkmnLib::Library::MoveLibrary* TestLibrary::BuildMoveLibrary() { } PkmnLib::Library::ItemLibrary* TestLibrary::BuildItemLibrary() { auto lib = new PkmnLib::Library::ItemLibrary(); - lib->Insert("testItem"_cnc.GetHash(), + lib->Insert("testItem"_cnc, new PkmnLib::Library::Item("testItem"_cnc, CreatureLib::Library::ItemCategory::MiscItem, CreatureLib::Library::BattleItemCategory::None, 0, nullptr, nullptr, {}, 0)); return lib;