mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2025-03-04 10:45:23 +01:00
Implement actor extension data and use it for transform tagging
This commit is contained in:
parent
8f85fb74db
commit
277cb5d7d3
@ -153,6 +153,7 @@ 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/rom_decompression.cpp
|
||||
|
||||
${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp
|
||||
|
9
include/recomp_data.h
Normal file
9
include/recomp_data.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __RECOMP_DATA_H__
|
||||
#define __RECOMP_DATA_H__
|
||||
|
||||
namespace recomp {
|
||||
void init_extended_actor_data();
|
||||
void reset_actor_data();
|
||||
}
|
||||
|
||||
#endif
|
91
patches/actor_data.c
Normal file
91
patches/actor_data.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include "patches.h"
|
||||
#include "extended_actors.h"
|
||||
#include "transform_ids.h"
|
||||
#include "mem_funcs.h"
|
||||
|
||||
// Use 32 bits of compiler-inserted padding to hold the actor's slot.
|
||||
// 0x22 between halfDaysBits and world
|
||||
#define actorIdByte0(actor) ((u8*)(actor))[0x22]
|
||||
// 0x23 between halfDaysBits and world
|
||||
#define actorIdByte1(actor) ((u8*)(actor))[0x23]
|
||||
// 0x3A between audioFlags and focus
|
||||
#define actorIdByte2(actor) ((u8*)(actor))[0x3A]
|
||||
// 0x3B between audioFlags and focus
|
||||
#define actorIdByte3(actor) ((u8*)(actor))[0x3B]
|
||||
|
||||
u32 actor_get_slot(Actor* actor) {
|
||||
return (actorIdByte0(actor) << 24) | (actorIdByte1(actor) << 16) | (actorIdByte2(actor) << 8) | (actorIdByte3(actor) << 0);
|
||||
}
|
||||
|
||||
void actor_set_slot(Actor* actor, ActorExtensionId slot) {
|
||||
u32 b0 = (slot >> 24) & 0xFF;
|
||||
u32 b1 = (slot >> 16) & 0xFF;
|
||||
u32 b2 = (slot >> 8) & 0xFF;
|
||||
u32 b3 = (slot >> 0) & 0xFF;
|
||||
|
||||
actorIdByte0(actor) = b0;
|
||||
actorIdByte1(actor) = b1;
|
||||
actorIdByte2(actor) = b2;
|
||||
actorIdByte3(actor) = b3;
|
||||
}
|
||||
|
||||
RECOMP_EXPORT ActorExtensionId z64recomp_extend_actor(s16 actor_id, u32 size) {
|
||||
return recomp_register_actor_extension(actor_id, size);
|
||||
}
|
||||
|
||||
RECOMP_EXPORT ActorExtensionId z64recomp_extend_actor_all(u32 size) {
|
||||
return recomp_register_actor_extension_generic(size);
|
||||
}
|
||||
|
||||
RECOMP_EXPORT void* z64recomp_get_extended_actor_data(Actor* actor, ActorExtensionId extension) {
|
||||
return recomp_get_actor_data(actor_get_slot(actor), extension, actor->id);
|
||||
}
|
||||
|
||||
RECOMP_EXPORT u32 z64recomp_get_actor_spawn_index(Actor* actor) {
|
||||
return recomp_get_actor_spawn_index(actor_get_slot(actor));
|
||||
}
|
||||
|
||||
RECOMP_EXPORT u32 actor_transform_id(Actor* actor) {
|
||||
u32 spawn_index = z64recomp_get_actor_spawn_index(actor);
|
||||
|
||||
return (spawn_index * ACTOR_TRANSFORM_ID_COUNT) + ACTOR_TRANSFORM_ID_START;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED = 1 << 0,
|
||||
ACTOR_CUSTOM_FLAG_1 = 1 << 1,
|
||||
} CustomActorFlags;
|
||||
|
||||
typedef struct {
|
||||
CustomActorFlags flags;
|
||||
} BaseActorExtensionData;
|
||||
|
||||
ActorExtensionId base_actor_extension_handle;
|
||||
|
||||
void register_base_actor_extensions() {
|
||||
base_actor_extension_handle = z64recomp_extend_actor_all(sizeof(BaseActorExtensionData));
|
||||
}
|
||||
|
||||
BaseActorExtensionData* get_base_extension_data(Actor* actor) {
|
||||
return (BaseActorExtensionData*)z64recomp_get_extended_actor_data(actor, base_actor_extension_handle);
|
||||
}
|
||||
|
||||
RECOMP_EXPORT u32 actor_get_interpolation_skipped(Actor* actor) {
|
||||
return (get_base_extension_data(actor)->flags & ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED) != 0;
|
||||
}
|
||||
|
||||
RECOMP_EXPORT void actor_set_interpolation_skipped(Actor* actor) {
|
||||
get_base_extension_data(actor)->flags |= ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED;
|
||||
}
|
||||
|
||||
RECOMP_EXPORT void actor_clear_interpolation_skipped(Actor* actor) {
|
||||
get_base_extension_data(actor)->flags &= ~ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED;
|
||||
}
|
||||
|
||||
void actor_set_custom_flag_1(Actor* actor) {
|
||||
get_base_extension_data(actor)->flags |= ACTOR_CUSTOM_FLAG_1;
|
||||
}
|
||||
|
||||
bool actor_get_custom_flag_1(Actor* actor) {
|
||||
return (get_base_extension_data(actor)->flags & ACTOR_CUSTOM_FLAG_1) != 0;
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
#include "patches.h"
|
||||
#include "fault.h"
|
||||
#include "transform_ids.h"
|
||||
#include "extended_actors.h"
|
||||
#include "z64actor.h"
|
||||
|
||||
u16 next_actor_transform = 0;
|
||||
#include "mem_funcs.h"
|
||||
|
||||
extern FaultClient sActorFaultClient;
|
||||
void Actor_Destroy(Actor* actor, PlayState* play);
|
||||
Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play);
|
||||
void ZeldaArena_Free(void* ptr);
|
||||
Actor* Actor_RemoveFromCategory(PlayState* play, ActorContext* actorCtx, Actor* actorToRemove);
|
||||
void Actor_FreeOverlay(ActorOverlay* entry);
|
||||
|
||||
RECOMP_PATCH void Actor_CleanupContext(ActorContext* actorCtx, PlayState* play) {
|
||||
s32 i;
|
||||
@ -34,26 +37,22 @@ RECOMP_PATCH void Actor_CleanupContext(ActorContext* actorCtx, PlayState* play)
|
||||
actorCtx->absoluteSpace = NULL;
|
||||
}
|
||||
|
||||
// @recomp Reset the actor transform IDs as all actors have been deleted.
|
||||
next_actor_transform = 0;
|
||||
// @recomp Reset the actor extension data.
|
||||
recomp_clear_all_actor_data();
|
||||
|
||||
Play_SaveCycleSceneFlags(&play->state);
|
||||
ActorOverlayTable_Cleanup();
|
||||
}
|
||||
|
||||
u32 create_actor_transform_id() {
|
||||
u32 ret = next_actor_transform;
|
||||
next_actor_transform++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RECOMP_DECLARE_EVENT(recomp_should_actor_init(PlayState* play, Actor* actor, bool* should));
|
||||
RECOMP_DECLARE_EVENT(recomp_after_actor_init(PlayState* play, Actor* actor));
|
||||
RECOMP_DECLARE_EVENT(recomp_should_actor_update(PlayState* play, Actor* actor, bool* should));
|
||||
RECOMP_DECLARE_EVENT(recomp_after_actor_update(PlayState* play, Actor* actor));
|
||||
|
||||
RECOMP_PATCH void Actor_Init(Actor* actor, PlayState* play) {
|
||||
// @recomp Allocate the actor's extension data.
|
||||
actor_set_slot(actor, recomp_create_actor_data(actor->id));
|
||||
|
||||
Actor_SetWorldToHome(actor);
|
||||
Actor_SetShapeRotToWorld(actor);
|
||||
Actor_SetFocus(actor, 0.0f);
|
||||
@ -88,11 +87,47 @@ RECOMP_PATCH void Actor_Init(Actor* actor, PlayState* play) {
|
||||
Actor_Kill(actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @recomp Pick a transform ID for this actor and encode it into struct padding
|
||||
u32 cur_transform_id = create_actor_transform_id();
|
||||
actorIdByte0(actor) = (cur_transform_id >> 0) & 0xFF;
|
||||
actorIdByte1(actor) = (cur_transform_id >> 8) & 0xFF;;
|
||||
RECOMP_PATCH Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) {
|
||||
s32 pad;
|
||||
Player* player = GET_PLAYER(play);
|
||||
Actor* newHead;
|
||||
ActorOverlay* overlayEntry = actor->overlayEntry;
|
||||
|
||||
if ((player != NULL) && (actor == player->lockOnActor)) {
|
||||
Player_Untarget(player);
|
||||
Camera_ChangeMode(Play_GetCamera(play, Play_GetActiveCamId(play)), CAM_MODE_NORMAL);
|
||||
}
|
||||
|
||||
if (actor == actorCtx->targetCtx.fairyActor) {
|
||||
actorCtx->targetCtx.fairyActor = NULL;
|
||||
}
|
||||
|
||||
if (actor == actorCtx->targetCtx.forcedTargetActor) {
|
||||
actorCtx->targetCtx.forcedTargetActor = NULL;
|
||||
}
|
||||
|
||||
if (actor == actorCtx->targetCtx.bgmEnemy) {
|
||||
actorCtx->targetCtx.bgmEnemy = NULL;
|
||||
}
|
||||
|
||||
AudioSfx_StopByPos(&actor->projectedPos);
|
||||
Actor_Destroy(actor, play);
|
||||
|
||||
newHead = Actor_RemoveFromCategory(play, actorCtx, actor);
|
||||
|
||||
// @recomp Destroy the actor's extension data.
|
||||
recomp_destroy_actor_data(actor_get_slot(actor));
|
||||
|
||||
ZeldaArena_Free(actor);
|
||||
|
||||
if (overlayEntry->vramStart != NULL) {
|
||||
overlayEntry->numLoaded--;
|
||||
Actor_FreeOverlay(overlayEntry);
|
||||
}
|
||||
|
||||
return newHead;
|
||||
}
|
||||
|
||||
// @recomp Copied from z_actor.c
|
||||
@ -106,8 +141,6 @@ typedef struct {
|
||||
/* 0x18 */ u32 updateActorFlagsMask; // Actor will update only if at least 1 actor flag is set in this bitmask
|
||||
} UpdateActor_Params; // size = 0x1C
|
||||
|
||||
void Actor_Destroy(Actor* actor, PlayState* play);
|
||||
|
||||
RECOMP_PATCH Actor* Actor_UpdateActor(UpdateActor_Params* params) {
|
||||
PlayState* play = params->play;
|
||||
Actor* actor = params->actor;
|
||||
@ -1403,3 +1436,10 @@ RECOMP_PATCH void Actor_Draw(PlayState* play, Actor* actor) {
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
ActorExtensionId z64recomp_extend_actor(s16 actor_id, u32 size);
|
||||
ActorExtensionId z64recomp_extend_actor_all(u32 size);
|
||||
|
||||
void* z64recomp_get_extended_actor_data(Actor* actor, ActorExtensionId extension);
|
||||
u32 z64recomp_get_actor_spawn_index(Actor* actor);
|
||||
|
||||
|
14
patches/extended_actors.h
Normal file
14
patches/extended_actors.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __EXTENDED_ACTORS_H__
|
||||
#define __EXTENDED_ACTORS_H__
|
||||
|
||||
#include "global.h"
|
||||
|
||||
typedef u32 ActorExtensionId;
|
||||
|
||||
ActorExtensionId z64recomp_extend_actor(s16 actor_id, u32 size);
|
||||
ActorExtensionId z64recomp_extend_actor_all(u32 size);
|
||||
|
||||
void* z64recomp_get_extended_actor_data(Actor* actor, ActorExtensionId extension);
|
||||
u32 z64recomp_get_actor_spawn_index(Actor* actor);
|
||||
|
||||
#endif
|
14
patches/mem_funcs.h
Normal file
14
patches/mem_funcs.h
Normal file
@ -0,0 +1,14 @@
|
||||
#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,5 +1,6 @@
|
||||
#include "patches.h"
|
||||
#include "misc_funcs.h"
|
||||
#include "transform_ids.h"
|
||||
#include "loadfragment.h"
|
||||
|
||||
void Main_ClearMemory(void* begin, void* end);
|
||||
@ -16,6 +17,9 @@ RECOMP_PATCH void Main_Init(void) {
|
||||
OSMesg msg[1];
|
||||
size_t prevSize;
|
||||
|
||||
// @recomp Register base actor extensions.
|
||||
register_base_actor_extensions();
|
||||
|
||||
// @recomp_event recomp_on_init(): Allow mods to initialize themselves once.
|
||||
recomp_on_init();
|
||||
|
||||
|
@ -46,3 +46,10 @@ recomp_get_resolution_scale = 0x8F0000AC;
|
||||
recomp_get_analog_inverted_axes = 0x8F0000B0;
|
||||
recomp_get_window_resolution = 0x8F0000B4;
|
||||
recomp_run_ui_callbacks = 0x8F0000B8;
|
||||
recomp_register_actor_extension = 0x8F0000BC;
|
||||
recomp_register_actor_extension_generic = 0x8F0000C0;
|
||||
recomp_clear_all_actor_data = 0x8F0000C4;
|
||||
recomp_create_actor_data = 0x8F0000C8;
|
||||
recomp_destroy_actor_data = 0x8F0000CC;
|
||||
recomp_get_actor_data = 0x8F0000D0;
|
||||
recomp_get_actor_spawn_index = 0x8F0000D4;
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef __TRANSFORM_IDS_H__
|
||||
#define __TRANSFORM_IDS_H__
|
||||
|
||||
#include "extended_actors.h"
|
||||
|
||||
#define CAMERA_TRANSFORM_ID 0x10U
|
||||
#define CIRCLE_OVERLAY_TRANSFORM_ID 0x11U
|
||||
#define CIRCLE_OVERLAY_TRANSFORM_PROJECTION_ID 0x12U
|
||||
@ -40,55 +42,18 @@
|
||||
#define ACTOR_TRANSFORM_ID_COUNT (ACTOR_TRANSFORM_LIMB_COUNT * 2) // One ID for each limb and another for each post-draw
|
||||
#define ACTOR_TRANSFORM_ID_START 0x1000000U
|
||||
|
||||
// Use 16 bits of compiler-inserted padding to hold the actor's transform ID.
|
||||
// 0x22 between halfDaysBits and world
|
||||
#define actorIdByte0(actor) ((u8*)(actor))[0x22]
|
||||
// 0x23 between halfDaysBits and world
|
||||
#define actorIdByte1(actor) ((u8*)(actor))[0x23]
|
||||
// 0x3A between audioFlags and focus
|
||||
#define actorIdByte2(actor) ((u8*)(actor))[0x3A]
|
||||
|
||||
// Other unused padding:
|
||||
// 0x3B between audioFlags and focus
|
||||
|
||||
static inline u32 actor_transform_id(Actor* actor) {
|
||||
u32 actor_id =
|
||||
(actorIdByte0(actor) << 0) |
|
||||
(actorIdByte1(actor) << 8);
|
||||
|
||||
return (actor_id * ACTOR_TRANSFORM_ID_COUNT) + ACTOR_TRANSFORM_ID_START;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED = 1 << 0,
|
||||
ACTOR_CUSTOM_FLAG_1 = 1 << 1,
|
||||
} CustomActorFlags;
|
||||
|
||||
static inline u32 actor_get_interpolation_skipped(Actor* actor) {
|
||||
return (actorIdByte2(actor) & ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED) != 0;
|
||||
}
|
||||
|
||||
static inline void actor_set_interpolation_skipped(Actor* actor) {
|
||||
actorIdByte2(actor) |= ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED;
|
||||
}
|
||||
|
||||
static inline void actor_clear_interpolation_skipped(Actor* actor) {
|
||||
actorIdByte2(actor) &= ~ACTOR_TRANSFORM_FLAG_INTERPOLATION_SKIPPED;
|
||||
}
|
||||
|
||||
static inline void actor_set_custom_flag_1(Actor* actor) {
|
||||
actorIdByte2(actor) |= ACTOR_CUSTOM_FLAG_1;
|
||||
}
|
||||
|
||||
static inline void actor_clear_custom_flag_1(Actor* actor) {
|
||||
actorIdByte2(actor) &= ~ACTOR_CUSTOM_FLAG_1;
|
||||
}
|
||||
|
||||
static inline bool actor_get_custom_flag_1(Actor* actor) {
|
||||
return (actorIdByte2(actor) & ACTOR_CUSTOM_FLAG_1) != 0;
|
||||
}
|
||||
|
||||
u32 actor_transform_id(Actor* actor);
|
||||
u32 actor_get_interpolation_skipped(Actor* actor);
|
||||
void actor_set_interpolation_skipped(Actor* actor);
|
||||
void actor_clear_interpolation_skipped(Actor* actor);
|
||||
void actor_set_custom_flag_1(Actor* actor);
|
||||
bool actor_get_custom_flag_1(Actor* actor);
|
||||
void force_camera_interpolation();
|
||||
void force_camera_skip_interpolation();
|
||||
|
||||
ActorExtensionId actor_get_slot(Actor* actor);
|
||||
void actor_set_slot(Actor* actor, ActorExtensionId);
|
||||
|
||||
void register_base_actor_extensions();
|
||||
|
||||
#endif
|
||||
|
232
src/game/recomp_mem_api.cpp
Normal file
232
src/game/recomp_mem_api.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
#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/mem_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 recomp::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 recomp::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(2 * actor_type);
|
||||
}
|
||||
|
||||
// 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;
|
||||
recomp::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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "zelda_sound.h"
|
||||
#include "zelda_render.h"
|
||||
#include "zelda_game.h"
|
||||
#include "recomp_data.h"
|
||||
#include "ovl_patches.hpp"
|
||||
#include "librecomp/game.hpp"
|
||||
#include "librecomp/mods.hpp"
|
||||
@ -624,6 +625,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
zelda64::register_overlays();
|
||||
zelda64::register_patches();
|
||||
recomp::init_extended_actor_data();
|
||||
zelda64::load_config();
|
||||
|
||||
recomp::rsp::callbacks_t rsp_callbacks{
|
||||
|
@ -21,6 +21,7 @@ namespace recompui {
|
||||
Pointer
|
||||
};
|
||||
|
||||
// These two enums must be kept in sync with patches/recompui_event_structs.h!
|
||||
enum class EventType {
|
||||
None,
|
||||
Click,
|
||||
|
Loading…
x
Reference in New Issue
Block a user