mirror of
https://github.com/BanjoRecomp/BanjoRecomp
synced 2026-05-23 06:34:20 -04:00
Genericize object extension to allow for multiple extension contexts (e.g. Props and ActorMarkers)
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "patches.h"
|
||||
#include "bk_api.h"
|
||||
|
||||
+7
-7
@@ -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;
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#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<uint32_t> actor_data_sizes{};
|
||||
// The total size of all generic actor extension data.
|
||||
uint32_t generic_data_size;
|
||||
// The registered actor extensions.
|
||||
std::vector<ExtensionInfo> actor_extensions{};
|
||||
// The extension data for every actor.
|
||||
using actor_data_map_t = dod::slot_map32<ExtensionData>;
|
||||
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<uint32_t>(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<u32>(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<uint32_t>(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<u32>(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<uint8_t*>(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<ExtensionData> 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<u32>(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<PTR(void)>(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<PTR(void)>(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<PTR(void)>(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<PTR(void)>(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<u32>(ctx, 0xFFFFFFFFU);
|
||||
return;
|
||||
}
|
||||
|
||||
_return<u32>(ctx, data->actor_spawn_index);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <deque>
|
||||
|
||||
#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<ExtensionData>;
|
||||
|
||||
std::mutex extension_mutex;
|
||||
struct ExtensionContext {
|
||||
// The total size of subtype-specific extension data for each subtype.
|
||||
std::vector<uint32_t> data_sizes{};
|
||||
// The total size of all generic extension data.
|
||||
uint32_t generic_data_size = 0;
|
||||
// The registered extensions.
|
||||
std::vector<ExtensionInfo> 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<ExtensionContext> 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<uint32_t>(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<u32>(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<uint32_t>(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<u32>(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<uint8_t*>(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<ExtensionData> 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<u32>(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<PTR(void)>(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<PTR(void)>(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<PTR(void)>(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<PTR(void)>(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<u32>(ctx, 0xFFFFFFFFU);
|
||||
return;
|
||||
}
|
||||
|
||||
_return<u32>(ctx, data->object_spawn_index);
|
||||
}
|
||||
|
||||
+2
-1
@@ -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{
|
||||
|
||||
Reference in New Issue
Block a user