diff --git a/CMakeLists.txt b/CMakeLists.txt index e0ab362..82093fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,7 +160,7 @@ set (SOURCES ${CMAKE_SOURCE_DIR}/src/game/config.cpp ${CMAKE_SOURCE_DIR}/src/game/debug.cpp ${CMAKE_SOURCE_DIR}/src/game/recomp_api.cpp - ${CMAKE_SOURCE_DIR}/src/game/recomp_actor_api.cpp + ${CMAKE_SOURCE_DIR}/src/game/recomp_extension_api.cpp ${CMAKE_SOURCE_DIR}/src/game/recomp_data_api.cpp ${CMAKE_SOURCE_DIR}/src/game/rom_decompression.cpp diff --git a/include/recomp_data.h b/include/recomp_data.h index 6891d85..51cad67 100644 --- a/include/recomp_data.h +++ b/include/recomp_data.h @@ -2,8 +2,8 @@ #define __RECOMP_DATA_H__ namespace recomputil { - void init_extended_actor_data(); - void reset_actor_data(); + void init_extended_object_data(size_t num_types); + void clear_all_object_data(size_t type_index); void register_data_api_exports(); } diff --git a/patches/actor_funcs.h b/patches/actor_funcs.h deleted file mode 100644 index 6c091e1..0000000 --- a/patches/actor_funcs.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __MEM_FUNCS_H__ -#define __MEM_FUNCS_H__ - -#include "patch_helpers.h" - -DECLARE_FUNC(u32, recomp_register_actor_extension, u32 actor_type, u32 size); -DECLARE_FUNC(u32, recomp_register_actor_extension_generic, u32 size); -DECLARE_FUNC(void, recomp_clear_all_actor_data); -DECLARE_FUNC(u32, recomp_create_actor_data, u32 actor_type); -DECLARE_FUNC(void, recomp_destroy_actor_data, u32 actor_handle); -DECLARE_FUNC(void*, recomp_get_actor_data, u32 actor_handle, u32 extension_handle, u32 actor_type); -DECLARE_FUNC(u32, recomp_get_actor_spawn_index, u32 actor_handle); - -#endif diff --git a/patches/mem_funcs.h b/patches/mem_funcs.h deleted file mode 100644 index 6c091e1..0000000 --- a/patches/mem_funcs.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __MEM_FUNCS_H__ -#define __MEM_FUNCS_H__ - -#include "patch_helpers.h" - -DECLARE_FUNC(u32, recomp_register_actor_extension, u32 actor_type, u32 size); -DECLARE_FUNC(u32, recomp_register_actor_extension_generic, u32 size); -DECLARE_FUNC(void, recomp_clear_all_actor_data); -DECLARE_FUNC(u32, recomp_create_actor_data, u32 actor_type); -DECLARE_FUNC(void, recomp_destroy_actor_data, u32 actor_handle); -DECLARE_FUNC(void*, recomp_get_actor_data, u32 actor_handle, u32 extension_handle, u32 actor_type); -DECLARE_FUNC(u32, recomp_get_actor_spawn_index, u32 actor_handle); - -#endif diff --git a/patches/object_extension_funcs.h b/patches/object_extension_funcs.h new file mode 100644 index 0000000..92d489a --- /dev/null +++ b/patches/object_extension_funcs.h @@ -0,0 +1,14 @@ +#ifndef __MEM_FUNCS_H__ +#define __MEM_FUNCS_H__ + +#include "patch_helpers.h" + +DECLARE_FUNC(u32, recomp_register_object_extension, u32 type_index, u32 subtype_index, u32 size); +DECLARE_FUNC(u32, recomp_register_object_extension_generic, u32 type_index, u32 size); +DECLARE_FUNC(void, recomp_clear_all_object_data, u32 type_index); +DECLARE_FUNC(u32, recomp_create_object_data, u32 type_index, u32 subtype_index); +DECLARE_FUNC(void, recomp_destroy_object_data, u32 type_index, u32 object_handle); +DECLARE_FUNC(void*, recomp_get_object_data, u32 type_index, u32 subtype_index, u32 object_handle, u32 extension_handle); +DECLARE_FUNC(u32, recomp_get_object_spawn_index, u32 type_index, u32 object_handle); + +#endif diff --git a/patches/actor_patches.c b/patches/object_extension_patches.c similarity index 83% rename from patches/actor_patches.c rename to patches/object_extension_patches.c index f79b8fe..fdc968d 100644 --- a/patches/actor_patches.c +++ b/patches/object_extension_patches.c @@ -2,9 +2,14 @@ #include "prop.h" #include "actor.h" #include "functions.h" -#include "mem_funcs.h" +#include "object_extension_funcs.h" #include "bk_api.h" +typedef enum { + EXTENSION_TYPE_MARKER, + EXTENSION_TYPE_PROP, +} ExtensionType; + // Array of handles for ActorMarker instances. // Normally the game only has at most 0xE0 ActorMarker instances, but this is larger to account for mods increasing // the ActorMarker count. @@ -30,7 +35,7 @@ RECOMP_PATCH void func_803329AC(void){ } // @recomp Reset all actor data. - recomp_clear_all_actor_data(); + recomp_clear_all_object_data(EXTENSION_TYPE_MARKER); } // @recomp Patched to create extension data for the marker. @@ -81,7 +86,7 @@ RECOMP_PATCH ActorMarker * marker_init(s32 *pos, MarkerDrawFunc draw_func, int a // @recomp Set the marker's handle. u32 index = marker - D_8036E7C8; - marker_handles[index] = recomp_create_actor_data(marker_id); + marker_handles[index] = recomp_create_object_data(EXTENSION_TYPE_MARKER, marker_id); return marker; } @@ -95,26 +100,26 @@ RECOMP_PATCH void func_80332B2C(ActorMarker * arg0){ D_80383428[index >> 3] = D_80383428[index >> 3] & D_8036E804[index & 7]; // @recomp Delete the handle for this marker. - recomp_destroy_actor_data(marker_handles[index]); + recomp_destroy_object_data(EXTENSION_TYPE_MARKER, marker_handles[index]); marker_handles[index] = 0; } RECOMP_EXPORT MarkerExtensionId bkrecomp_extend_marker(enum marker_e type, u32 size) { - return recomp_register_actor_extension(type, size); + return recomp_register_object_extension(EXTENSION_TYPE_MARKER, type, size); } RECOMP_EXPORT MarkerExtensionId bkrecomp_extend_marker_all(u32 size) { - return recomp_register_actor_extension_generic(size); + return recomp_register_object_extension_generic(EXTENSION_TYPE_MARKER, size); } RECOMP_EXPORT void* bkrecomp_get_extended_marker_data(ActorMarker* marker, MarkerExtensionId extension) { s32 index = (marker - D_8036E7C8); u32 handle = marker_handles[index]; - return recomp_get_actor_data(handle, extension, marker->id); + return recomp_get_object_data(EXTENSION_TYPE_MARKER, marker->id, handle, extension); } RECOMP_EXPORT u32 bkrecomp_get_marker_spawn_index(ActorMarker* marker) { s32 index = (marker - D_8036E7C8); u32 handle = marker_handles[index]; - return recomp_get_actor_spawn_index(handle); + return recomp_get_object_spawn_index(EXTENSION_TYPE_MARKER, handle); } diff --git a/patches/prop_transform_tagging.c b/patches/prop_transform_tagging.c new file mode 100644 index 0000000..95435d1 --- /dev/null +++ b/patches/prop_transform_tagging.c @@ -0,0 +1,3 @@ +#include "patches.h" +#include "bk_api.h" + diff --git a/patches/syms.ld b/patches/syms.ld index ea24ce2..997b588 100644 --- a/patches/syms.ld +++ b/patches/syms.ld @@ -18,13 +18,13 @@ osDpSetStatus_recomp = 0x8F000034; malloc_recomp = 0x8F000038; free_recomp = 0x8F00003C; realloc_recomp = 0x8F000040; -recomp_register_actor_extension = 0x8F000044; -recomp_register_actor_extension_generic = 0x8F000048; -recomp_clear_all_actor_data = 0x8F00004C; -recomp_create_actor_data = 0x8F000050; -recomp_destroy_actor_data = 0x8F000054; -recomp_get_actor_data = 0x8F000058; -recomp_get_actor_spawn_index = 0x8F00005C; +recomp_register_object_extension = 0x8F000044; +recomp_register_object_extension_generic = 0x8F000048; +recomp_clear_all_object_data = 0x8F00004C; +recomp_create_object_data = 0x8F000050; +recomp_destroy_object_data = 0x8F000054; +recomp_get_object_data = 0x8F000058; +recomp_get_object_spawn_index = 0x8F00005C; recomp_error = 0x8F000060; memcpy_recomp = 0x8F000064; __divdi3_recomp = 0x8F000068; diff --git a/src/game/recomp_actor_api.cpp b/src/game/recomp_actor_api.cpp deleted file mode 100644 index 759b9a0..0000000 --- a/src/game/recomp_actor_api.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include - -#include "slot_map.h" - -#include "librecomp/helpers.hpp" -#include "librecomp/addresses.hpp" -#include "ultramodern/error_handling.hpp" -#include "recomp_ui.h" -#include "recomp_data.h" -#include "../patches/actor_funcs.h" - -struct ExtensionInfo { - // Either the actor's type ID, or 0xFFFFFFFF if this is for generic data. - uint32_t actor_type; - // The offset from either the start of the actor's data or the start of the actor's specific extension data depending on the value of actor_type. - uint32_t data_offset; -}; - -struct ExtensionData { - uint32_t actor_spawn_index; - PTR(void) data_addr; -}; - -std::mutex actor_data_mutex{}; -// The total size of actor-specific extension data for each actor type. -std::vector actor_data_sizes{}; -// The total size of all generic actor extension data. -uint32_t generic_data_size; -// The registered actor extensions. -std::vector actor_extensions{}; -// The extension data for every actor. -using actor_data_map_t = dod::slot_map32; -actor_data_map_t actor_data{}; -// The number of actors spawned since the last reset. -uint32_t actor_spawn_count = 0; -// Whether or not extensions can be registered at this time. -bool can_register = false; - -// Debug counters. -size_t alloc_count = 0; -size_t free_count = 0; - -void recomputil::init_extended_actor_data() { - std::lock_guard lock{ actor_data_mutex }; - - actor_data_sizes.clear(); - generic_data_size = 0; - actor_extensions.clear(); - actor_data.reset(); - actor_spawn_count = 0; - can_register = true; - // Create a dummy extension so the first extension handle is nonzero, should help catch bugs. - actor_extensions.push_back({}); -} - -void recomputil::reset_actor_data() { - std::lock_guard lock{ actor_data_mutex }; - actor_data.reset(); - actor_spawn_count = 0; - - assert(alloc_count == free_count); - alloc_count = 0; - free_count = 0; -} - -constexpr uint32_t round_up_16(uint32_t value) { - return (value + 15) & (~15); -} - -extern "C" void recomp_register_actor_extension(uint8_t* rdram, recomp_context* ctx) { - u32 actor_type = _arg<0, u32>(rdram, ctx); - u32 size = _arg<1, u32>(rdram, ctx); - - if (!can_register) { - recompui::message_box("Fatal error in mod - attempted to register actor extension data after actors have been spawned."); - assert(false); - ultramodern::error_handling::quick_exit(__FILE__, __LINE__, __FUNCTION__); - } - - if (actor_data_sizes.size() <= actor_type) { - actor_data_sizes.resize(actor_type + 1); - } - - // Increase the actor type's extension data size by the provided size (rounded up to a multiple of 16). - uint32_t data_offset = actor_data_sizes[actor_type]; - actor_data_sizes[actor_type] += round_up_16(size); - - // Register the extension. - uint32_t ret = static_cast(actor_extensions.size()); - actor_extensions.emplace_back(ExtensionInfo{.actor_type = actor_type, .data_offset = data_offset}); - - // printf("Registered actor extension data for type %u (size 0x%08X, offset 0x%08X)\n", actor_type, size, data_offset); - - _return(ctx, ret); -} - -extern "C" void recomp_register_actor_extension_generic(uint8_t* rdram, recomp_context* ctx) { - u32 size = _arg<0, u32>(rdram, ctx); - - // Increase the generic extension data size by the provided size (rounded up to a multiple of 16). - uint32_t data_offset = generic_data_size; - generic_data_size += round_up_16(size); - - // Register the extension. - uint32_t ret = static_cast(actor_extensions.size()); - actor_extensions.emplace_back(ExtensionInfo{.actor_type = 0xFFFFFFFFU, .data_offset = data_offset}); - - // printf("Registered generic actor extension data (size 0x%08X, offset 0x%08X)\n", size, data_offset); - _return(ctx, ret); -} - -extern "C" void recomp_clear_all_actor_data(uint8_t* rdram, recomp_context* ctx) { - (void)rdram; - (void)ctx; - recomputil::reset_actor_data(); -} - -extern "C" void recomp_create_actor_data(uint8_t* rdram, recomp_context* ctx) { - std::lock_guard lock{ actor_data_mutex }; - - can_register = false; - - // Determine the number of bytes to allocate based on the actor type's extensions and the generic extensions. - u32 actor_type = _arg<0, u32>(rdram, ctx); - u32 alloc_size = generic_data_size; - [[maybe_unused]] u32 type_data_size = 0; - - if (actor_type < actor_data_sizes.size()) { - type_data_size = actor_data_sizes[actor_type]; - alloc_size += type_data_size; - } - - // Allocate the extension data if it's of nonzero size. - PTR(void) data_ptr = NULLPTR; - if (alloc_size != 0) { - void* data = recomp::alloc(rdram, alloc_size); - alloc_count++; - data_ptr = reinterpret_cast(data) - rdram + 0xFFFFFFFF80000000U; - // Zero the allocated memory. - // A memset should be fine here since this data is aligned, but use a byteswapped loop just to be safe. - for (size_t i = 0; i < alloc_size; i++) { - MEM_B(i, data_ptr) = 0; - } - } - - // Add the actor's fields to the actor data slotmap. - u32 spawn_index = actor_spawn_count++; - dod::slot_map_key32 key = actor_data.emplace(ExtensionData{.actor_spawn_index = spawn_index, .data_addr = data_ptr}); - - // printf("Allocated actor data: address 0x%08X with 0x%08X bytes total (0x%08X bytes generic and 0x%08X bytes specific), handle 0x%08X, spawn index %d\n", - // data_ptr, alloc_size, generic_data_size, type_data_size, key.raw, spawn_index); - - _return(ctx, key.raw); -} - -extern "C" void recomp_destroy_actor_data(uint8_t* rdram, recomp_context* ctx) { - std::lock_guard lock{ actor_data_mutex }; - - u32 actor_handle = _arg<0, u32>(rdram, ctx); - actor_data_map_t::key actor_key{actor_handle}; - - ExtensionData* data = actor_data.get(actor_key); - if (data != nullptr) { - // printf("Freeing actor data: address 0x%08X handle 0x%08X\n", data->data_addr, actor_handle); - if (data->data_addr != NULLPTR) { - recomp::free(rdram, TO_PTR(void, data->data_addr)); - free_count++; - } - actor_data.erase(actor_data_map_t::key{actor_handle}); - } - else { - // Not an irrecoverable error, but catch it in debug mode with an assert to help find bugs. - assert(false); - } -} - -extern "C" void recomp_get_actor_data(uint8_t* rdram, recomp_context* ctx) { - std::lock_guard lock{ actor_data_mutex }; - - u32 actor_handle = _arg<0, u32>(rdram, ctx); - u32 extension_handle = _arg<1, u32>(rdram, ctx); - u32 actor_type = _arg<2, u32>(rdram, ctx); - - // Check if the extension handle is valid. - if (extension_handle == 0 || extension_handle >= actor_extensions.size()) { - _return(ctx, NULLPTR); - return; - } - - ExtensionInfo& extension = actor_extensions[extension_handle]; - bool generic_extension = extension.actor_type == 0xFFFFFFFFU; - - // Check if the extension is generic or for the provided actor type. - if (!generic_extension && extension.actor_type != actor_type) { - _return(ctx, NULLPTR); - return; - } - - actor_data_map_t::key actor_key{actor_handle}; - ExtensionData* data = actor_data.get(actor_key); - - // Check if actor handle is valid. - if (data == nullptr) { - _return(ctx, NULLPTR); - return; - } - - // Calculate the address for this specific extension's data. - PTR(void) base_address = data->data_addr; - u32 offset = extension.data_offset; - // Specific actor data is after generic actor data, so increase the offset by the total generic actor data if this isn't generic data. - if (!generic_extension) { - offset += generic_data_size; - } - - PTR(void) ret = base_address + offset; - _return(ctx, ret); -} - -extern "C" void recomp_get_actor_spawn_index(uint8_t* rdram, recomp_context* ctx) { - std::lock_guard lock{ actor_data_mutex }; - - u32 actor_handle = _arg<0, u32>(rdram, ctx); - - actor_data_map_t::key actor_key{actor_handle}; - ExtensionData* data = actor_data.get(actor_key); - - // Check if actor handle is valid. - if (data == nullptr) { - _return(ctx, 0xFFFFFFFFU); - return; - } - - _return(ctx, data->actor_spawn_index); -} - diff --git a/src/game/recomp_extension_api.cpp b/src/game/recomp_extension_api.cpp new file mode 100644 index 0000000..1ba0e92 --- /dev/null +++ b/src/game/recomp_extension_api.cpp @@ -0,0 +1,260 @@ +#include +#include +#include + +#include "slot_map.h" + +#include "librecomp/helpers.hpp" +#include "librecomp/addresses.hpp" +#include "ultramodern/error_handling.hpp" +#include "recomp_ui.h" +#include "recomp_data.h" +#include "../patches/object_extension_funcs.h" + +struct ExtensionInfo { + // Either the object's subtype ID, or 0xFFFFFFFF if this is for generic data. + uint32_t subtype_index; + // The offset from either the start of the object's extension data (for generic extensions) or from the start of the objects's specific extension data. + uint32_t data_offset; +}; + +struct ExtensionData { + uint32_t object_spawn_index; + PTR(void) data_addr; +}; + +using extension_data_map_t = dod::slot_map32; + +std::mutex extension_mutex; +struct ExtensionContext { + // The total size of subtype-specific extension data for each subtype. + std::vector data_sizes{}; + // The total size of all generic extension data. + uint32_t generic_data_size = 0; + // The registered extensions. + std::vector extensions{}; + // The extension data for every object. + extension_data_map_t extension_data{}; + // The number of objects spawned since the last reset. + uint32_t spawn_count = 0; + // Debug counters. + size_t alloc_count = 0; + size_t free_count = 0; +}; + +// The extension contexts for each object type. This must be a deque instead of a vector due to a lack of a copy constructor. +std::deque type_contexts{}; +// Whether or not extensions can be registered at this time. +bool can_register = false; + +void recomputil::init_extended_object_data(size_t num_types) { + type_contexts.clear(); + + can_register = true; + // Create a dummy extension so the first extension handle is nonzero, should help catch bugs. + for (size_t i = 0; i < num_types; i++) { + type_contexts.emplace_back(ExtensionContext{}); + type_contexts[i].extensions.push_back({}); + } +} + +void recomputil::clear_all_object_data(size_t type_index) { + ExtensionContext& context = type_contexts[type_index]; + std::lock_guard lock{ extension_mutex }; + context.extension_data.reset(); + context.spawn_count = 0; + + assert(context.alloc_count == context.free_count); + context.alloc_count = 0; + context.free_count = 0; +} + +constexpr uint32_t round_up_16(uint32_t value) { + return (value + 15) & (~15); +} + +extern "C" void recomp_register_object_extension(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + u32 subtype_index = _arg<1, u32>(rdram, ctx); + u32 size = _arg<2, u32>(rdram, ctx); + + ExtensionContext& context = type_contexts[type_index]; + + if (!can_register) { + recompui::message_box("Fatal error in mod - attempted to register object extension data after objects have been spawned."); + assert(false); + ultramodern::error_handling::quick_exit(__FILE__, __LINE__, __FUNCTION__); + } + + if (context.data_sizes.size() <= subtype_index) { + context.data_sizes.resize(subtype_index + 1); + } + + // Increase the object subtype's extension data size by the provided size (rounded up to a multiple of 16). + uint32_t data_offset = context.data_sizes[subtype_index]; + context.data_sizes[subtype_index] += round_up_16(size); + + // Register the extension. + uint32_t ret = static_cast(context.extensions.size()); + context.extensions.emplace_back(ExtensionInfo{.subtype_index = subtype_index, .data_offset = data_offset}); + + // printf("Registered object extension data for type %u subtype %u (size 0x%08X, offset 0x%08X)\n", type_index, subtype_index, size, data_offset); + + _return(ctx, ret); +} + +extern "C" void recomp_register_object_extension_generic(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + u32 size = _arg<1, u32>(rdram, ctx); + + ExtensionContext& context = type_contexts[type_index]; + + // Increase the generic extension data size by the provided size (rounded up to a multiple of 16). + uint32_t data_offset = context.generic_data_size; + context.generic_data_size += round_up_16(size); + + // Register the extension. + uint32_t ret = static_cast(context.extensions.size()); + context.extensions.emplace_back(ExtensionInfo{.subtype_index = 0xFFFFFFFFU, .data_offset = data_offset}); + + // printf("Registered generic object extension data for type %u (size 0x%08X, offset 0x%08X)\n", type_index, size, data_offset); + _return(ctx, ret); +} + +extern "C" void recomp_clear_all_object_data(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + recomputil::clear_all_object_data(type_index); +} + +extern "C" void recomp_create_object_data(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + u32 subtype_index = _arg<1, u32>(rdram, ctx); + + ExtensionContext& context = type_contexts[type_index]; + + std::lock_guard lock{ extension_mutex }; + + can_register = false; + + // Determine the number of bytes to allocate based on the subtype's extensions and the generic extensions. + u32 alloc_size = context.generic_data_size; + [[maybe_unused]] u32 subtype_data_size = 0; + + if (subtype_index < context.data_sizes.size()) { + subtype_data_size = context.data_sizes[subtype_index]; + alloc_size += subtype_data_size; + } + + // Allocate the extension data if it's of nonzero size. + PTR(void) data_ptr = NULLPTR; + if (alloc_size != 0) { + void* data = recomp::alloc(rdram, alloc_size); + context.alloc_count++; + data_ptr = reinterpret_cast(data) - rdram + 0xFFFFFFFF80000000U; + // Zero the allocated memory. + // A memset should be fine here since this data is aligned, but use a byteswapped loop just to be safe. + for (size_t i = 0; i < alloc_size; i++) { + MEM_B(i, data_ptr) = 0; + } + } + + // Add the object's data to the type's data slotmap. + u32 spawn_index = context.spawn_count++; + dod::slot_map_key32 key = context.extension_data.emplace(ExtensionData{.object_spawn_index = spawn_index, .data_addr = data_ptr}); + + // printf("Allocated object data: type %u address 0x%08X with 0x%08X bytes total (0x%08X bytes generic and 0x%08X bytes specific), handle 0x%08X, spawn index %d\n", + // type_index, data_ptr, alloc_size, generic_data_size, type_data_size, key.raw, spawn_index); + + _return(ctx, key.raw); +} + +extern "C" void recomp_destroy_object_data(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + u32 object_handle = _arg<1, u32>(rdram, ctx); + ExtensionContext& context = type_contexts[type_index]; + + std::lock_guard lock{ extension_mutex }; + + extension_data_map_t::key object_key{object_handle}; + + ExtensionData* data = context.extension_data.get(object_key); + if (data != nullptr) { + // printf("Freeing object data: address 0x%08X handle 0x%08X\n", data->data_addr, object_handle); + if (data->data_addr != NULLPTR) { + recomp::free(rdram, TO_PTR(void, data->data_addr)); + context.free_count++; + } + context.extension_data.erase(extension_data_map_t::key{object_handle}); + } + else { + // Not an irrecoverable error, but catch it in debug mode with an assert to help find bugs. + // *(volatile int*)object_handle = 0; + assert(false); + } +} + +extern "C" void recomp_get_object_data(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + u32 subtype_index = _arg<1, u32>(rdram, ctx); + u32 object_handle = _arg<2, u32>(rdram, ctx); + u32 extension_handle = _arg<3, u32>(rdram, ctx); + + ExtensionContext& context = type_contexts[type_index]; + std::lock_guard lock{ extension_mutex }; + + // Check if the extension handle is valid. + if (extension_handle == 0 || extension_handle >= context.extensions.size()) { + _return(ctx, NULLPTR); + return; + } + + ExtensionInfo& extension = context.extensions[extension_handle]; + bool generic_extension = extension.subtype_index == 0xFFFFFFFFU; + + // Check if the extension is generic or for the provided subtype. + if (!generic_extension && extension.subtype_index != subtype_index) { + _return(ctx, NULLPTR); + return; + } + + extension_data_map_t::key object_key{object_handle}; + ExtensionData* data = context.extension_data.get(object_key); + + // Check if object handle is valid. + if (data == nullptr) { + _return(ctx, NULLPTR); + return; + } + + // Calculate the address for this specific extension's data. + PTR(void) base_address = data->data_addr; + u32 offset = extension.data_offset; + // Specific object data is after generic object data, so increase the offset by the total generic object data if this isn't generic data. + if (!generic_extension) { + offset += context.generic_data_size; + } + + PTR(void) ret = base_address + offset; + _return(ctx, ret); +} + +extern "C" void recomp_get_object_spawn_index(uint8_t* rdram, recomp_context* ctx) { + u32 type_index = _arg<0, u32>(rdram, ctx); + u32 object_handle = _arg<1, u32>(rdram, ctx); + ExtensionContext& context = type_contexts[type_index]; + + std::lock_guard lock{ extension_mutex }; + + + extension_data_map_t::key object_key{object_handle}; + ExtensionData* data = context.extension_data.get(object_key); + + // Check if object handle is valid. + if (data == nullptr) { + _return(ctx, 0xFFFFFFFFU); + return; + } + + _return(ctx, data->object_spawn_index); +} + diff --git a/src/main/main.cpp b/src/main/main.cpp index 10d2902..984b44b 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -607,7 +607,8 @@ int main(int argc, char** argv) { banjo::register_bk_overlays(); banjo::register_bk_patches(); - recomputil::init_extended_actor_data(); + // Register extensions for two types: Props and ActorMarkers. + recomputil::init_extended_object_data(2); banjo::load_config(); recomp::rsp::callbacks_t rsp_callbacks{