From d2c84291009c3bcd802ef722e78bed84d4eed644 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Thu, 3 Apr 2025 02:35:59 -0400 Subject: [PATCH] Implement data structure mod APIs --- CMakeLists.txt | 3 +- include/recomp_data.h | 4 +- patches/actor_data.c | 2 +- patches/{mem_funcs.h => actor_funcs.h} | 0 patches/actor_transform_tagging.c | 2 +- ...ecomp_mem_api.cpp => recomp_actor_api.cpp} | 8 +- src/game/recomp_data_api.cpp | 722 ++++++++++++++++++ src/main/main.cpp | 3 +- src/ui/core/ui_context.cpp | 2 +- 9 files changed, 736 insertions(+), 10 deletions(-) rename patches/{mem_funcs.h => actor_funcs.h} (100%) rename src/game/{recomp_mem_api.cpp => recomp_actor_api.cpp} (98%) create mode 100644 src/game/recomp_data_api.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a32d38..5cde068 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,7 +163,8 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/src/game/debug.cpp ${CMAKE_SOURCE_DIR}/src/game/quicksaving.cpp ${CMAKE_SOURCE_DIR}/src/game/recomp_api.cpp - ${CMAKE_SOURCE_DIR}/src/game/recomp_mem_api.cpp + ${CMAKE_SOURCE_DIR}/src/game/recomp_actor_api.cpp + ${CMAKE_SOURCE_DIR}/src/game/recomp_data_api.cpp ${CMAKE_SOURCE_DIR}/src/game/rom_decompression.cpp ${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp diff --git a/include/recomp_data.h b/include/recomp_data.h index 87693c7..6891d85 100644 --- a/include/recomp_data.h +++ b/include/recomp_data.h @@ -1,9 +1,11 @@ #ifndef __RECOMP_DATA_H__ #define __RECOMP_DATA_H__ -namespace recomp { +namespace recomputil { void init_extended_actor_data(); void reset_actor_data(); + + void register_data_api_exports(); } #endif diff --git a/patches/actor_data.c b/patches/actor_data.c index 33c4d9f..64214ff 100644 --- a/patches/actor_data.c +++ b/patches/actor_data.c @@ -1,7 +1,7 @@ #include "patches.h" #include "extended_actors.h" #include "transform_ids.h" -#include "mem_funcs.h" +#include "actor_funcs.h" // Use 32 bits of compiler-inserted padding to hold the actor's slot. // 0x22 between halfDaysBits and world diff --git a/patches/mem_funcs.h b/patches/actor_funcs.h similarity index 100% rename from patches/mem_funcs.h rename to patches/actor_funcs.h diff --git a/patches/actor_transform_tagging.c b/patches/actor_transform_tagging.c index c38d0a3..796f10c 100644 --- a/patches/actor_transform_tagging.c +++ b/patches/actor_transform_tagging.c @@ -3,7 +3,7 @@ #include "transform_ids.h" #include "extended_actors.h" #include "z64actor.h" -#include "mem_funcs.h" +#include "actor_funcs.h" extern FaultClient sActorFaultClient; void Actor_Destroy(Actor* actor, PlayState* play); diff --git a/src/game/recomp_mem_api.cpp b/src/game/recomp_actor_api.cpp similarity index 98% rename from src/game/recomp_mem_api.cpp rename to src/game/recomp_actor_api.cpp index 6ee6a05..8cbe5a6 100644 --- a/src/game/recomp_mem_api.cpp +++ b/src/game/recomp_actor_api.cpp @@ -8,7 +8,7 @@ #include "ultramodern/error_handling.hpp" #include "recomp_ui.h" #include "recomp_data.h" -#include "../patches/mem_funcs.h" +#include "../patches/actor_funcs.h" struct ExtensionInfo { // Either the actor's type ID, or 0xFFFFFFFF if this is for generic data. @@ -41,7 +41,7 @@ bool can_register = false; size_t alloc_count = 0; size_t free_count = 0; -void recomp::init_extended_actor_data() { +void recomputil::init_extended_actor_data() { std::lock_guard lock{ actor_data_mutex }; actor_data_sizes.clear(); @@ -54,7 +54,7 @@ void recomp::init_extended_actor_data() { actor_extensions.push_back({}); } -void recomp::reset_actor_data() { +void recomputil::reset_actor_data() { std::lock_guard lock{ actor_data_mutex }; actor_data.reset(); actor_spawn_count = 0; @@ -113,7 +113,7 @@ extern "C" void recomp_register_actor_extension_generic(uint8_t* rdram, recomp_c extern "C" void recomp_clear_all_actor_data(uint8_t* rdram, recomp_context* ctx) { (void)rdram; (void)ctx; - recomp::reset_actor_data(); + recomputil::reset_actor_data(); } extern "C" void recomp_create_actor_data(uint8_t* rdram, recomp_context* ctx) { diff --git a/src/game/recomp_data_api.cpp b/src/game/recomp_data_api.cpp new file mode 100644 index 0000000..9b13c57 --- /dev/null +++ b/src/game/recomp_data_api.cpp @@ -0,0 +1,722 @@ +#include +#include +#include +#include + +#include "slot_map.h" +#include "recomp_data.h" +#include "recomp_ui.h" +#include "librecomp/helpers.hpp" +#include "librecomp/overlays.hpp" +#include "librecomp/addresses.hpp" +#include "ultramodern/error_handling.hpp" + +template +class LockedMap { +private: + std::mutex mutex{}; + std::unordered_map map{}; +public: + bool get(const KeyType& key, ValueType& out) { + std::lock_guard lock{mutex}; + auto find_it = map.find(key); + if (find_it == map.end()) { + return false; + } + out = find_it->second; + return true; + } + + bool insert(const KeyType& key, ValueType val) { + std::lock_guard lock{mutex}; + auto ret = map.insert_or_assign(key, val); + return ret.second; + } + + bool erase(const KeyType& key) { + std::lock_guard lock{mutex}; + size_t num_erased = map.erase(key); + return num_erased != 0; + } + + void clear() { + std::lock_guard lock{mutex}; + map.clear(); + } + + bool erase_first(ValueType& out) { + std::lock_guard lock{mutex}; + auto it = map.begin(); + + if (it == map.end()) { + return false; + } + + out = it->second; + map.erase(it); + return true; + } + + bool contains(const KeyType& key) { + std::lock_guard lock{mutex}; + + return map.contains(key); + } + + size_t size() { + std::lock_guard lock{mutex}; + + return map.size(); + } +}; + +template +class LockedSet { +private: + std::mutex mutex{}; + std::unordered_set set{}; +public: + bool contains(const KeyType& key) { + std::lock_guard lock{mutex}; + return set.contains(key); + } + + bool insert(const KeyType& key) { + std::lock_guard lock{mutex}; + auto it = set.insert(key); + return it.second; + } + + bool erase(const KeyType& key) { + std::lock_guard lock{mutex}; + size_t num_erased = set.erase(key); + return num_erased != 0; + } + + void clear() { + std::lock_guard lock{mutex}; + set.clear(); + } + + size_t size() { + std::lock_guard lock{mutex}; + return set.size(); + } +}; + +template +class LockedSlotmap { +private: + std::mutex mutex{}; + dod::slot_map32 map{}; + using key_t = dod::slot_map32::key; +public: + bool get(uint32_t key, ValueType** out) { + std::lock_guard lock{mutex}; + ValueType* ret = map.get(key_t{key}); + *out = ret; + return ret != nullptr; + } + + uint32_t create() { + std::lock_guard lock{mutex}; + return map.emplace().raw; + } + + bool erase(uint32_t key) { + std::lock_guard lock{mutex}; + if (!map.has_key(key_t{ key })) { + return false; + } + + map.erase(key_t{ key }); + return true; + } + + void clear() { + std::lock_guard lock{mutex}; + map.clear(); + } + + bool erase_first(ValueType& out) { + std::lock_guard lock{mutex}; + auto it = map.items().begin(); + + if (it == map.items().end()) { + return false; + } + + out = it->second; + map.erase(it->first); + return true; + } + + size_t size() { + std::lock_guard lock{mutex}; + + return map.size(); + } +}; + +using U32ValueMap = LockedMap; +using U32MemoryMap = std::pair, u32>; +using U32HashSet = LockedSet; +using U32Slotmap = LockedSlotmap; +using MemorySlotmap = std::pair, u32>; + +LockedSlotmap u32_value_hashmaps{}; +LockedSlotmap u32_memory_hashmaps{}; +LockedSlotmap u32_hashsets{}; +LockedSlotmap u32_slotmaps{}; +LockedSlotmap memory_slotmaps{}; + +#define REGISTER_FUNC(name) recomp::overlays::register_base_export(#name, name) + +#define HANDLE_INVALID_ERROR() \ + recompui::message_box("Fatal error in mod - " __FUNCTION__ " : handle is invalid"); \ + assert(false); \ + ultramodern::error_handling::quick_exit(__FILE__, __LINE__, __FUNCTION__); + +#define SLOTMAP_KEY_INVALID_ERROR() \ + recompui::message_box("Fatal error in mod - " __FUNCTION__ " : slotmap key is invalid"); \ + assert(false); \ + ultramodern::error_handling::quick_exit(__FILE__, __LINE__, __FUNCTION__); + +// u32 -> 32-bit value hashmap. + +void recomputil_create_u32_value_hashmap(uint8_t* rdram, recomp_context* ctx) { + (void)rdram; + _return(ctx, u32_value_hashmaps.create()); +} + +void recomputil_destroy_u32_value_hashmap(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + if (!u32_value_hashmaps.erase(mapkey)) { + HANDLE_INVALID_ERROR(); + } +} + +void recomputil_u32_value_hashmap_contains(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32ValueMap* map; + if (!u32_value_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, map->contains(key)); +} + +void recomputil_u32_value_hashmap_insert(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + uint32_t value = _arg<2, uint32_t>(rdram, ctx); + + U32ValueMap* map; + if (!u32_value_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, map->insert(key, value)); +} + +void recomputil_u32_value_hashmap_get(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + PTR(uint32_t) val_out = _arg<2, PTR(uint32_t)>(rdram, ctx); + + U32ValueMap* map; + if (!u32_value_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + uint32_t ret; + if (map->get(key, ret)) { + MEM_W(0, val_out) = ret; + _return(ctx, 1); + return; + } + else { + _return(ctx, 0); + return; + } +} + +void recomputil_u32_value_hashmap_erase(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32ValueMap* map; + if (!u32_value_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, map->erase(key)); +} + +void recomputil_u32_value_hashmap_size(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + U32ValueMap* map; + if (!u32_value_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, static_cast(map->size())); +} + +// u32 -> memory hashmap. + +void recomputil_create_u32_memory_hashmap(uint8_t* rdram, recomp_context* ctx) { + uint32_t element_size = _arg<0, uint32_t>(rdram, ctx); + + // Create the map. + uint32_t map_key = u32_memory_hashmaps.create(); + + // Retrieve the map and set its element size to the provided value. + U32MemoryMap* map; + u32_memory_hashmaps.get(map_key, &map); + map->second = element_size; + + // Return the created map's key. + _return(ctx, map_key); +} + +void recomputil_destroy_u32_memory_hashmap(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + // Retrieve the map. + U32MemoryMap* map; + if (!u32_memory_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + // Free all of the entries in the map. + PTR(void) cur_mem; + while (map->first.erase_first(cur_mem)) { + recomp::free(rdram, TO_PTR(void, cur_mem)); + } + + // Destroy the map itself. + u32_memory_hashmaps.erase(mapkey); +} + +void recomputil_u32_memory_hashmap_contains(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32MemoryMap* map; + if (!u32_memory_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, map->first.contains(key)); +} + +void recomputil_u32_memory_hashmap_create(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32MemoryMap* map; + if (!u32_memory_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + // Check if the map contains the key already to prevent inserting it twice. + PTR(void) dummy; + if (map->first.get(key, dummy)) { + _return(ctx, 0); + return; + } + + // Allocate the map's size and return the pointer. + void* mem = recomp::alloc(rdram, map->second); + gpr addr = reinterpret_cast(mem) - rdram + 0xFFFFFFFF80000000ULL; + + // Zero the memory. + for (size_t i = 0; i < map->second; i++) { + MEM_B(i, addr) = 0; + } + + PTR(void) ret = static_cast(addr); + map->first.insert(key, ret); + _return(ctx, 1); +} + +void recomputil_u32_memory_hashmap_get(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32MemoryMap* map; + if (!u32_memory_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + PTR(void) ret; + if (map->first.get(key, ret)) { + _return(ctx, ret); + return; + } + else { + _return(ctx, NULLPTR); + return; + } +} + +void recomputil_u32_memory_hashmap_erase(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32MemoryMap* map; + if (!u32_memory_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + // Free the memory for this key if the key exists. + PTR(void) addr; + bool has_value = map->first.get(key, addr); + if (has_value) { + void* mem = TO_PTR(void, addr); + recomp::free(rdram, mem); + } + + _return(ctx, map->first.erase(key)); +} + +void recomputil_u32_memory_hashmap_size(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + U32MemoryMap* map; + if (!u32_memory_hashmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, static_cast(map->first.size())); +} + +// u32 hashset. + +void recomputil_create_u32_hashset(uint8_t* rdram, recomp_context* ctx) { + (void)rdram; + _return(ctx, u32_hashsets.create()); +} + +void recomputil_destroy_u32_hashset(uint8_t* rdram, recomp_context* ctx) { + uint32_t setkey = _arg<0, uint32_t>(rdram, ctx); + + if (!u32_hashsets.erase(setkey)) { + HANDLE_INVALID_ERROR(); + } +} + +void recomputil_u32_hashset_contains(uint8_t* rdram, recomp_context* ctx) { + uint32_t setkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32HashSet* set; + if (!u32_hashsets.get(setkey, &set)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, set->contains(key)); +} + +void recomputil_u32_hashset_insert(uint8_t* rdram, recomp_context* ctx) { + uint32_t setkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32HashSet* set; + if (!u32_hashsets.get(setkey, &set)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, set->insert(key)); +} + +void recomputil_u32_hashset_erase(uint8_t* rdram, recomp_context* ctx) { + uint32_t setkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32HashSet* set; + if (!u32_hashsets.get(setkey, &set)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, set->erase(key)); +} + +void recomputil_u32_hashset_size(uint8_t* rdram, recomp_context* ctx) { + uint32_t setkey = _arg<0, uint32_t>(rdram, ctx); + + U32HashSet* set; + if (!u32_hashsets.get(setkey, &set)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, static_cast(set->size())); +} + +// u32 value slotmap. + +void recomputil_create_u32_slotmap(uint8_t* rdram, recomp_context* ctx) { + (void)rdram; + _return(ctx, u32_slotmaps.create()); +} + +void recomputil_destroy_u32_slotmap(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + if (!u32_slotmaps.erase(mapkey)) { + HANDLE_INVALID_ERROR(); + } +} + +void recomputil_u32_slotmap_contains(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32Slotmap* map; + if (!u32_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + uint32_t* dummy_ptr; + _return(ctx, map->get(key, &dummy_ptr)); +} + +void recomputil_u32_slotmap_create(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + U32Slotmap* map; + if (!u32_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, map->create()); +} + +void recomputil_u32_slotmap_get(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + PTR(uint32_t) val_out = _arg<2, PTR(uint32_t)>(rdram, ctx); + + U32Slotmap* map; + if (!u32_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + uint32_t* ret; + if (!map->get(key, &ret)) { + _return(ctx, 0); + } + MEM_W(0, val_out) = *ret; + _return(ctx, 1); +} + +void recomputil_u32_slotmap_set(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + uint32_t value = _arg<2, uint32_t>(rdram, ctx); + + U32Slotmap* map; + if (!u32_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + uint32_t* value_ptr; + if (!map->get(key, &value_ptr)) { + _return(ctx, 0); + } + + *value_ptr = value; + _return(ctx, 1); +} + +void recomputil_u32_slotmap_erase(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + U32Slotmap* map; + if (!u32_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + if (!map->erase(key)) { + _return(ctx, 0); + } + + _return(ctx, 1); +} + +void recomputil_u32_slotmap_size(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + U32Slotmap* map; + if (!u32_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, static_cast(map->size())); +} + +// memory slotmap. + +void recomputil_create_memory_slotmap(uint8_t* rdram, recomp_context* ctx) { + (void)rdram; + _return(ctx, memory_slotmaps.create()); +} + +void recomputil_destroy_memory_slotmap(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + // Retrieve the map. + MemorySlotmap* map; + if (!memory_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + // Free all of the entries in the map. + PTR(void) cur_mem; + while (map->first.erase_first(cur_mem)) { + recomp::free(rdram, TO_PTR(void, cur_mem)); + } + + // Destroy the map itself. + memory_slotmaps.erase(mapkey); +} + +void recomputil_memory_slotmap_contains(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + MemorySlotmap* map; + if (!memory_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + PTR(void)* dummy_ptr; + _return(ctx, map->first.get(key, &dummy_ptr)); +} + +void recomputil_memory_slotmap_create(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + MemorySlotmap* map; + if (!memory_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + // Create the slotmap element. + u32 key = map->first.create(); + + // Allocate the map's element size. + void* mem = recomp::alloc(rdram, map->second); + gpr addr = reinterpret_cast(mem) - rdram + 0xFFFFFFFF80000000ULL; + + // Zero the memory. + for (size_t i = 0; i < map->second; i++) { + MEM_B(i, addr) = 0; + } + + // Store the allocated pointer. + PTR(void)* value_ptr; + map->first.get(key, &value_ptr); + MEM_W(0, *value_ptr) = addr; + + // Return the key. + _return(ctx, key); +} + +void recomputil_memory_slotmap_get(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + PTR(uint32_t) val_out = _arg<2, PTR(uint32_t)>(rdram, ctx); + + MemorySlotmap* map; + if (!memory_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + PTR(void)* ret; + if (!map->first.get(key, &ret)) { + SLOTMAP_KEY_INVALID_ERROR(); + } + MEM_W(0, val_out) = *ret; +} + +void recomputil_memory_slotmap_erase(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + uint32_t key = _arg<1, uint32_t>(rdram, ctx); + + MemorySlotmap* map; + if (!memory_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + // Free the memory for this key if the key exists. + PTR(void)* addr; + bool has_value = map->first.get(key, &addr); + if (has_value) { + void* mem = TO_PTR(void, addr); + recomp::free(rdram, mem); + } + + _return(ctx, map->first.erase(key)); +} + +void recomputil_memory_slotmap_size(uint8_t* rdram, recomp_context* ctx) { + uint32_t mapkey = _arg<0, uint32_t>(rdram, ctx); + + MemorySlotmap* map; + if (!memory_slotmaps.get(mapkey, &map)) { + HANDLE_INVALID_ERROR(); + } + + _return(ctx, static_cast(map->first.size())); +} + +// Exports. + +void recomputil::register_data_api_exports() { + REGISTER_FUNC(recomputil_create_u32_value_hashmap); + REGISTER_FUNC(recomputil_destroy_u32_value_hashmap); + REGISTER_FUNC(recomputil_u32_value_hashmap_contains); + REGISTER_FUNC(recomputil_u32_value_hashmap_insert); + REGISTER_FUNC(recomputil_u32_value_hashmap_get); + REGISTER_FUNC(recomputil_u32_value_hashmap_erase); + REGISTER_FUNC(recomputil_u32_value_hashmap_size); + + REGISTER_FUNC(recomputil_create_u32_memory_hashmap); + REGISTER_FUNC(recomputil_destroy_u32_memory_hashmap); + REGISTER_FUNC(recomputil_u32_memory_hashmap_contains); + REGISTER_FUNC(recomputil_u32_memory_hashmap_create); + REGISTER_FUNC(recomputil_u32_memory_hashmap_get); + REGISTER_FUNC(recomputil_u32_memory_hashmap_erase); + REGISTER_FUNC(recomputil_u32_memory_hashmap_size); + + REGISTER_FUNC(recomputil_create_u32_hashset); + REGISTER_FUNC(recomputil_destroy_u32_hashset); + REGISTER_FUNC(recomputil_u32_hashset_contains); + REGISTER_FUNC(recomputil_u32_hashset_insert); + REGISTER_FUNC(recomputil_u32_hashset_erase); + REGISTER_FUNC(recomputil_u32_hashset_size); + + REGISTER_FUNC(recomputil_create_u32_slotmap); + REGISTER_FUNC(recomputil_destroy_u32_slotmap); + REGISTER_FUNC(recomputil_u32_slotmap_contains); + REGISTER_FUNC(recomputil_u32_slotmap_create); + REGISTER_FUNC(recomputil_u32_slotmap_get); + REGISTER_FUNC(recomputil_u32_slotmap_set); + REGISTER_FUNC(recomputil_u32_slotmap_erase); + REGISTER_FUNC(recomputil_u32_slotmap_size); + + REGISTER_FUNC(recomputil_create_memory_slotmap); + REGISTER_FUNC(recomputil_destroy_memory_slotmap); + REGISTER_FUNC(recomputil_memory_slotmap_contains); + REGISTER_FUNC(recomputil_memory_slotmap_create); + REGISTER_FUNC(recomputil_memory_slotmap_get); + REGISTER_FUNC(recomputil_memory_slotmap_erase); + REGISTER_FUNC(recomputil_memory_slotmap_size); +} diff --git a/src/main/main.cpp b/src/main/main.cpp index 77ea68b..99b95af 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -629,10 +629,11 @@ int main(int argc, char** argv) { REGISTER_FUNC(recomp_get_inverted_axes); REGISTER_FUNC(recomp_get_analog_inverted_axes); recompui::register_ui_exports(); + recomputil::register_data_api_exports(); zelda64::register_overlays(); zelda64::register_patches(); - recomp::init_extended_actor_data(); + recomputil::init_extended_actor_data(); zelda64::load_config(); recomp::rsp::callbacks_t rsp_callbacks{ diff --git a/src/ui/core/ui_context.cpp b/src/ui/core/ui_context.cpp index c3f5b3e..69214e8 100644 --- a/src/ui/core/ui_context.cpp +++ b/src/ui/core/ui_context.cpp @@ -43,7 +43,7 @@ namespace recompui { using context_slotmap = dod::slot_map32; static struct { - std::mutex all_contexts_lock; + std::recursive_mutex all_contexts_lock; context_slotmap all_contexts; std::unordered_set opened_contexts; std::unordered_map documents_to_contexts;