diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a9f97d..aac9644 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,6 +151,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_mem_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 new file mode 100644 index 0000000..87693c7 --- /dev/null +++ b/include/recomp_data.h @@ -0,0 +1,9 @@ +#ifndef __RECOMP_DATA_H__ +#define __RECOMP_DATA_H__ + +namespace recomp { + void init_extended_actor_data(); + void reset_actor_data(); +} + +#endif diff --git a/patches/Makefile b/patches/Makefile index 80639e9..da9ba10 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -6,7 +6,7 @@ LD ?= ld.lld CFLAGS := -target mips -mips2 -mabi=32 -O2 -G0 -mno-abicalls -mno-odd-spreg -mno-check-zero-division \ -fomit-frame-pointer -ffast-math -fno-unsafe-math-optimizations -fno-builtin-memset \ -Wall -Wextra -Wno-incompatible-library-redeclaration -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-variable -Wno-missing-braces -Wno-unsupported-floating-point-opt -CPPFLAGS := -nostdinc -D_LANGUAGE_C -DMIPS -I ../lib/bk-decomp/include -I ../lib/bk-decomp/include/2.0L -I../lib/rt64/include +CPPFLAGS := -nostdinc -D_LANGUAGE_C -DMIPS -I ../lib/bk-decomp/include -I ../lib/bk-decomp/include/2.0L -I ../lib/bk-decomp/include/2.0L/PR -I../lib/rt64/include LDFLAGS := -nostdlib -T patches.ld -T syms.ld -Map patches.map --unresolved-symbols=ignore-all --emit-relocs C_SRCS := $(wildcard *.c) diff --git a/patches/actor_patches.c b/patches/actor_patches.c new file mode 100644 index 0000000..27a7c85 --- /dev/null +++ b/patches/actor_patches.c @@ -0,0 +1,379 @@ +#include "patches.h" +#include "prop.h" +#include "actor.h" +#include "functions.h" +#include "mem_funcs.h" +#include "bk_api.h" + +extern ActorArray *suBaddieActorArray; +extern Actor *suLastBaddie; + +void func_803255FC(Actor *this); +void func_8032B5C0(ActorMarker *arg0, ActorMarker *arg1, struct5Cs *arg2); +s32 func_80326C18(void); +void func_8032FFD4(ActorMarker *this, s32 arg1); +void marker_setModelId(ActorMarker *this, enum asset_e modelIndex); +s32 func_80306DDC(s32 *position); +s32 func_80307258(f32 arg0[3], s32 arg1, s32 arg2); +struct5Bs *func_8034A2C8(void); +void func_8033F738(ActorMarker *arg0); +void func_8034BFF8(ActorMarker *marker); +Struct83s *func_803406B0(void); + +// @recomp Patched to create extension data for the actor. +RECOMP_PATCH Actor *actor_new(s32 position[3], s32 yaw, ActorInfo* actorInfo, u32 flags){ + ActorAnimationInfo * sp54; + s32 i; + f32 sp44[3]; + + if(suBaddieActorArray == NULL){ + // @recomp Reset actor data when suBaddieActorArray is initially allocated. + recomp_clear_all_actor_data(); + suBaddieActorArray = (ActorArray *)malloc(sizeof(ActorArray) + 20*sizeof(Actor)); + suBaddieActorArray->cnt = 0; + suBaddieActorArray->max_cnt = 20; + } + + if(suBaddieActorArray->cnt + 1 > suBaddieActorArray->max_cnt){ + suBaddieActorArray->max_cnt = suBaddieActorArray->cnt + 5; + suBaddieActorArray = (ActorArray *)realloc(suBaddieActorArray, sizeof(ActorArray) + suBaddieActorArray->max_cnt*sizeof(Actor)); + } + + ++suBaddieActorArray->cnt; + suLastBaddie = &suBaddieActorArray->data[suBaddieActorArray->cnt - 1]; + + suLastBaddie->actor_info = actorInfo; + suLastBaddie->unk10_25 = 0; + suLastBaddie->unk10_18 = 0; + suLastBaddie->state = actorInfo->startAnimation; + suLastBaddie->position_x = (f32)position[0]; + suLastBaddie->position_y = (f32)position[1]; + suLastBaddie->position_z = (f32)position[2]; + suLastBaddie->unkF4_8 = 0; + suLastBaddie->yaw = (f32) yaw; + suLastBaddie->yaw_ideal = (f32) yaw; + suLastBaddie->pitch = 0.0f; + suLastBaddie->roll = 0.0f; + suLastBaddie->unk6C = 0.0f; + suLastBaddie->actor_specific_1_f = 0.0f; + suLastBaddie->unk10_12 = 0; + suLastBaddie->unk38_0 = 0; + suLastBaddie->unk38_31 = 0; + suLastBaddie->unk58_0 = 1; + suLastBaddie->unk40 = 0; + suLastBaddie->unk44_31 = 0; + suLastBaddie->despawn_flag = 0; + suLastBaddie->unk44_14 = -1; + suLastBaddie->unk48 = 0.0f; + suLastBaddie->unk4C = 100.0f; + suLastBaddie->unk10_1 = 1; + suLastBaddie->unkF4_30 = 0; + suLastBaddie->unkF4_29 = 0; + suLastBaddie->scale = 1.0f; + suLastBaddie->unk124_7 = 0; + suLastBaddie->unk124_6 = 1; + suLastBaddie->modelCacheIndex = actorInfo->actorId; + suLastBaddie->unk44_2 = func_80326C18(); + suLastBaddie->marker = marker_init(position, actorInfo->draw_func, (asset_getFlag(actorInfo->modelId) == 1) ? 0 : 1, actorInfo->markerId, (flags & 0x400) ? 1 : 0); + suLastBaddie->marker->unk3E_0 = 1; + suLastBaddie->unk138_28 = 1; + suLastBaddie->unk10_3 = -1; + suLastBaddie->unk10_4 = 0; + suLastBaddie->unk10_8 = 0; + suLastBaddie->unk10_7 = 0; + suLastBaddie->unk10_6 = 0; + suLastBaddie->unk54 = 0.0f; + suLastBaddie->anctrl_asset_id = 0; + suLastBaddie->unk5C = 0.0f; + suLastBaddie->unkF4_31 = 0; + suLastBaddie->unk138_30 = 0; + suLastBaddie->unk138_3 = 0; + suLastBaddie->unk38_21 = 0; + suLastBaddie->unk38_13 = 0; + suLastBaddie->unk78_22 = 0; + suLastBaddie->unk78_31 = 0; + suLastBaddie->unk74 = 0.0f; + suLastBaddie->unk70 = 0.0f; + suLastBaddie->unkF4_24 = 0; + suLastBaddie->unk140 = 0.0f; + suLastBaddie->unk144 = 0.0f; + suLastBaddie->unk44_1 = 0; + suLastBaddie->unk44_0 = 0; + suLastBaddie->initialized = FALSE; + suLastBaddie->volatile_initialized = FALSE; + suLastBaddie->lifetime_value = 0.0f; + suLastBaddie->is_bundle = FALSE; + suLastBaddie->unk104 = NULL; + suLastBaddie->unk100 = NULL; + suLastBaddie->unk158[0] = NULL; + suLastBaddie->unk158[1] = NULL; + suLastBaddie->unk78_13 = 0; + suLastBaddie->unk124_31 = 0; + suLastBaddie->unkF4_20 = 0; + suLastBaddie->sound_timer = 0.0f; + func_8032FFD4(suLastBaddie->marker, suBaddieActorArray->cnt - 1); + marker_setModelId(suLastBaddie->marker, actorInfo->modelId); + marker_setActorUpdateFunc(suLastBaddie->marker, actorInfo->update_func); + marker_setActorUpdate2Func(suLastBaddie->marker, actorInfo->update2_func); + ml_vec3f_clear(suLastBaddie->unk1C); + ml_vec3f_clear(suLastBaddie->velocity); + ml_vec3f_clear(suLastBaddie->spawn_position); + suLastBaddie->stored_anctrl_index = 0; + suLastBaddie->unk58_2 = 1; + suLastBaddie->stored_anctrl_playbackType_ = 0; + suLastBaddie->stored_anctrl_forwards = 0; + suLastBaddie->stored_anctrl_smoothTransistion = 0; + suLastBaddie->stored_anctrl_duration = 0.0f; + suLastBaddie->stored_anctrl_timer = 0.0f; + suLastBaddie->unk138_19 = 0; + suLastBaddie->stored_anctrl_subrangeMin = 0.0f; + suLastBaddie->stored_anctrl_subrangeMax = 1.0f; + suLastBaddie->unkF4_22 = 0; + suLastBaddie->unk58_1 = 0; + suLastBaddie->unk138_29 = 0; + suLastBaddie->unk18 = actorInfo->animations; + suLastBaddie->anctrl = NULL; + suLastBaddie->stored_anctrl_timer = 0.0f; + suLastBaddie->unk130 = 0; + suLastBaddie->unk124_5 = 0; + suLastBaddie->unk124_3 = 0; + suLastBaddie->unk138_9 = 0; + suLastBaddie->unk138_8 = 0; + suLastBaddie->unk138_25 = 0; + suLastBaddie->unk16C_3 = 0; + suLastBaddie->unk16C_2 = 0; + suLastBaddie->unk16C_1 = 0; + suLastBaddie->unk16C_0 = 0; + suLastBaddie->unk17C_31 = 0; + suLastBaddie->unk14C[0] = NULL; + suLastBaddie->unk14C[1] = NULL; + suLastBaddie->unk138_27 = 0; + suLastBaddie->has_met_before = FALSE; + suLastBaddie->unk138_23 = 0; + suLastBaddie->unk138_22 = 0; + suLastBaddie->unk138_21 = 0; + suLastBaddie->unk138_20 = 0; + suLastBaddie->unk174 = 0.0f; + suLastBaddie->unk178 = 0.0f; + if( actorInfo->animations){ + sp54 = &suLastBaddie->unk18[suLastBaddie->state]; + if(sp54->index != 0){ + suLastBaddie->anctrl = anctrl_new(0); + anctrl_reset(suLastBaddie->anctrl); + anctrl_setIndex(suLastBaddie->anctrl, sp54->index); + anctrl_setDuration(suLastBaddie->anctrl, sp54->duration); + anctrl_start(suLastBaddie->anctrl, "subaddie.c", 0x4A5); + } + }//L80327BA8 + suLastBaddie->unk124_11 = 0; + suLastBaddie->alpha_124_19 = 0xff; + suLastBaddie->depth_mode = MODEL_RENDER_DEPTH_FULL; + suLastBaddie->unk124_0 = suLastBaddie->unk138_31 = 1; + for(i = 0; i < 0x10; i++){ + ((s32 *)suLastBaddie->unk7C)[i] = 0; + } + for(i = 0; i < 0x0C; i++){ + ((s32 *)suLastBaddie->unkBC)[i] = 0; + } + if(flags & ACTOR_FLAG_UNKNOWN_0){ + suLastBaddie->unk10_25 = func_80306DDC(position) + 1; + if(suLastBaddie->unk10_25 == 0){ + suLastBaddie->unk10_25 = 0; + }else{ + sp44[0] = (f32)position[0]; + sp44[1] = (f32)position[1]; + sp44[2] = (f32)position[2]; + suLastBaddie->unk10_18 = func_80307258(sp44, suLastBaddie->unk10_25 - 1, 0) + 1; + } + }//L80327D30 + + if(flags & ACTOR_FLAG_UNKNOWN_2){ + suLastBaddie->unk10_1 = 0; + } + + if(flags & ACTOR_FLAG_UNKNOWN_3){ + suLastBaddie->unkF4_30 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_1){ + suLastBaddie->marker->unk44 = (struct5Bs*)1; + } + else if(flags & ACTOR_FLAG_UNKNOWN_6){ + suLastBaddie->marker->unk44 = func_8034A2C8(); + } + + if(flags & ACTOR_FLAG_UNKNOWN_12){ + func_8033F738(suLastBaddie->marker); + func_8034BFF8(suLastBaddie->marker); + } + + suLastBaddie->unk148 = 0; + if(flags & ACTOR_FLAG_UNKNOWN_11){ + suLastBaddie->unk148 = skeletalAnim_new(); + } + + if(flags & ACTOR_FLAG_UNKNOWN_14){ + suLastBaddie->marker->unk50 = (s32)func_803406B0(); + } + + if(flags & ACTOR_FLAG_UNKNOWN_4){ + suLastBaddie->unk124_31 = -1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_7){ + suLastBaddie->unkF4_22 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_19){ + suLastBaddie->unk58_1 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_8){ + suLastBaddie->unk130 = func_803255FC; + } + + if(flags & ACTOR_FLAG_UNKNOWN_9){ + suLastBaddie->marker->unk40_21 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_15){ + suLastBaddie->marker->unk40_20 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_17){ + suLastBaddie->marker->unk40_22 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_22){ + suLastBaddie->marker->unk40_19 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_16){ + suLastBaddie->unk138_9 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_18){ + suLastBaddie->unk138_8 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_21){ + suLastBaddie->unk138_25 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_23){ + suLastBaddie->unk16C_3 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_24){ + suLastBaddie->unk16C_2 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_25){ + suLastBaddie->unk16C_1 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_26){ + suLastBaddie->unk17C_31 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_13){ + suLastBaddie->unk138_29 = 1; + } + + if(flags & ACTOR_FLAG_UNKNOWN_20){ + suLastBaddie->unk58_2 = 0; + } + + suLastBaddie->unk154 = 0x005e0000; + suLastBaddie->marker->unk54 = (void (*)(struct actorMarker_s *, struct actorMarker_s *, u16 *))func_8032B5C0; + + + for(i = 0; i < 3; ++i){ + suLastBaddie->unk164[i] = 0x63; + } + + suLastBaddie->unk170 = -10.0f; + suLastBaddie->unk138_7 = 0; + suLastBaddie->unk3C = flags; + + // @recomp Allocate extension data for this actor and place it in padding. + suLastBaddie->pad17C_30 = recomp_create_actor_data(actorInfo->actorId) & 0x7FFFFFFFU; + + return suLastBaddie; +} + +void func_8032BB88(Actor *this, s32 arg1, s32 arg2); +void func_8033E7CC(ActorMarker *arg0); +void func_8034A2A8(struct5Bs *this); +void func_8034BF54(ActorMarker *marker); +void func_8033F784(ActorMarker *arg0); +void func_80340690(Struct83s *self); +void func_8032ACA8(Actor *arg0); + +// @recomp Patched to destroy the extended actor data. +RECOMP_PATCH void func_80325FE8(Actor *this) { + ActorMarker *marker; + u8 temp_v0; + + // @recomp Destroy the extended actor data. + recomp_destroy_actor_data(this->pad17C_30); + + marker = this->marker; + marker->id = 0; + if (this->anctrl != NULL) { + anctrl_free(this->anctrl); + } + temp_v0 = this->unk44_31; + if (temp_v0 != 0) { + sfxsource_freeSfxsourceByIndex(temp_v0); + } + this->anctrl = NULL; + this->unk44_31 = 0; + + if (this->unk138_7 != 0) { + func_8032BB88(this, -1, 8000); + this->unk138_7 = 0; + } + if (marker->actorFreeFunc != NULL) { + marker->actorFreeFunc(this); + marker->actorFreeFunc = NULL; + } + if ((s32)marker->unk44 < 0) { + func_8033E7CC(marker); + func_8034A2A8(marker->unk44); + marker->unk44 = 0; + } + if (marker->unk4C != 0) { + func_8034BF54(this->marker); + marker->unk4C = 0; + } + if (marker->unk48 != 0) { + func_8033F784(marker); + marker->unk48 = 0; + } + if (this->unk148 != NULL) { + skeletalAnim_free(this->unk148); + this->unk148 = NULL; + } + if (marker->unk50 != 0) { + func_80340690((Struct83s *)marker->unk50); + marker->unk50 = 0; + } + func_8032ACA8(this); +} + +RECOMP_EXPORT ActorExtensionId bkrecomp_extend_actor(enum actor_e type, u32 size) { + return recomp_register_actor_extension(type, size); +} + +RECOMP_EXPORT ActorExtensionId bkrecomp_extend_actor_all(u32 size) { + return recomp_register_actor_extension_generic(size); +} + +RECOMP_EXPORT void* bkrecomp_get_extended_actor_data(Actor* actor, ActorExtensionId extension) { + return recomp_get_actor_data(actor->pad17C_30, extension, actor->actor_info->actorId); +} + +RECOMP_EXPORT u32 bkrecomp_get_actor_spawn_index(Actor* actor) { + return recomp_get_actor_spawn_index(actor->pad17C_30); +} diff --git a/patches/bk_api.h b/patches/bk_api.h new file mode 100644 index 0000000..2f06fb6 --- /dev/null +++ b/patches/bk_api.h @@ -0,0 +1,16 @@ +#ifndef __BK_API_H__ +#define __BK_API_H__ + +#include "ultra64.h" +#include "enums.h" +#include "prop.h" + +typedef u32 ActorExtensionId; + +ActorExtensionId bkrecomp_extend_actor(enum actor_e type, u32 size); +ActorExtensionId bkrecomp_extend_actor_all(u32 size); + +void* bkrecomp_get_extended_actor_data(Actor* actor, ActorExtensionId extension); +u32 bkrecomp_get_actor_spawn_index(Actor* actor); + +#endif diff --git a/patches/init_patches.c b/patches/init_patches.c new file mode 100644 index 0000000..4a43d84 --- /dev/null +++ b/patches/init_patches.c @@ -0,0 +1,21 @@ +#include "patches.h" +#include "bk_api.h" +#include "misc_funcs.h" + +RECOMP_DECLARE_EVENT(recomp_on_init()); + +void core1_init(); +void sns_write_payload_over_heap(); +void mainLoop(); + +RECOMP_PATCH void mainThread_entry(void *arg) { + // @recomp Register actor extension data and call the init event. + recomp_on_init(); + + core1_init(); + sns_write_payload_over_heap(); + + while (1) { + mainLoop(); + } +} diff --git a/patches/mem_funcs.h b/patches/mem_funcs.h new file mode 100644 index 0000000..6c091e1 --- /dev/null +++ b/patches/mem_funcs.h @@ -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 diff --git a/patches/n64_types.h b/patches/n64_types.h deleted file mode 100644 index 00c8e38..0000000 --- a/patches/n64_types.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __N64_TYPES_H__ -#define __N64_TYPES_H__ - -#define va_list __builtin_va_list -#define va_start __builtin_va_start -#define va_arg __builtin_va_arg -#define va_end __builtin_va_end - -typedef unsigned int size_t; - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned long u32; -typedef unsigned long long u64; - -typedef signed char s8; -typedef short s16; -typedef long s32; -typedef long long s64; - -typedef volatile unsigned char vu8; -typedef volatile unsigned short vu16; -typedef volatile unsigned long vu32; -typedef volatile unsigned long long vu64; - -typedef volatile signed char vs8; -typedef volatile short vs16; -typedef volatile long vs32; -typedef volatile long long vs64; - -typedef float f32; -typedef double f64; - -#define TRUE 1 -#define FALSE 0 -#define NULL 0 - -#endif diff --git a/patches/patches.h b/patches/patches.h index b04e77f..6de2186 100644 --- a/patches/patches.h +++ b/patches/patches.h @@ -21,9 +21,15 @@ void osWriteBackDCacheAll(void); #define bzero bzero_recomp #define osDpSetStatus osDpSetStatus_recomp +#define malloc malloc_recomp +#define free free_recomp +#define realloc realloc_recomp +#define memcpy memcpy_recomp #include "ultra64.h" typedef int bool; +int recomp_printf(const char* fmt, ...); + #endif diff --git a/patches/syms.ld b/patches/syms.ld index c732ca6..269a63c 100644 --- a/patches/syms.ld +++ b/patches/syms.ld @@ -15,3 +15,13 @@ osGetCount_recomp = 0x8F000028; osCreateMesgQueue_recomp = 0x8F00002C; osRecvMesg_recomp = 0x8F000030; 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; diff --git a/src/game/recomp_mem_api.cpp b/src/game/recomp_mem_api.cpp new file mode 100644 index 0000000..e0426b4 --- /dev/null +++ b/src/game/recomp_mem_api.cpp @@ -0,0 +1,232 @@ +#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/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 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 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(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; + 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(data) - rdram + 0xFFFFFFFF80000000U; + } + + // 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/rom_decompression.cpp b/src/game/rom_decompression.cpp index 6282f86..11f4ee9 100644 --- a/src/game/rom_decompression.cpp +++ b/src/game/rom_decompression.cpp @@ -4,6 +4,7 @@ #include "librecomp/game.hpp" #include "banjo_game.h" +#include "recomp_data.h" #ifdef _MSC_VER inline uint32_t byteswap(uint32_t val) { @@ -120,4 +121,5 @@ std::vector banjo::decompress_bk(std::span compressed_ro void banjo::bk_on_init(uint8_t* rdram, recomp_context* ctx) { MEM_W(0, (int32_t)0x80000310) = 6103; recomp::do_rom_read(rdram, (int32_t)0x80000000, 0x100004C0, 0x2A4); + recomp::init_extended_actor_data(); }