diff --git a/soh/soh/ActorExtension/ActorExtension.cpp b/soh/soh/ActorExtension/ActorExtension.cpp new file mode 100644 index 000000000..df82cd769 --- /dev/null +++ b/soh/soh/ActorExtension/ActorExtension.cpp @@ -0,0 +1,78 @@ +#include "ActorExtension.h" + +static ActorExtensionId sNextId = 0; + +struct ActorExtensionKeyHash { + std::size_t operator()(const std::pair& key) const { + return std::hash{}(key.first) ^ (std::hash{}(key.second) << 1); + } +}; + +static std::unordered_map sGlobalSizes; +static std::unordered_map> sSizes; +static std::unordered_map, void*, ActorExtensionKeyHash> sData; + +void* ActorExtension_Get(Actor* actor, ActorExtensionId id) { + if (actor == nullptr) { + return nullptr; + } + + auto it = sData.find(std::make_pair(actor, id)); + if (it == sData.end()) { + return nullptr; + } + + return it->second; +} + +ActorExtensionId ActorExtension_CreateForId(int16_t actorId, size_t size) { + ActorExtensionId id = ++sNextId; + sSizes[actorId][id] = size; + return id; +} + +ActorExtensionId ActorExtension_CreateForAll(size_t size) { + ActorExtensionId id = ++sNextId; + sGlobalSizes[id] = size; + return id; +} + +void ActorExtension_Alloc(Actor* actor, int16_t actorId) { + if (actor == nullptr) { + return; + } + + for (auto& [id, size] : sGlobalSizes) { + void* data = malloc(size); + memset(data, 0, size); + sData[std::make_pair(actor, id)] = data; + } + + for (auto& [id, size] : sSizes[actorId]) { + void* data = malloc(size); + memset(data, 0, size); + sData[std::make_pair(actor, id)] = data; + } +} + +void ActorExtension_Free(Actor* actor) { + if (actor == nullptr) { + return; + } + + for (auto& [id, size] : sGlobalSizes) { + auto it = sData.find(std::make_pair(actor, id)); + if (it != sData.end()) { + free(it->second); + sData.erase(it); + } + } + + for (auto& [id, size] : sSizes[actor->id]) { + auto it = sData.find(std::make_pair(actor, id)); + if (it != sData.end()) { + free(it->second); + sData.erase(it); + } + } +} \ No newline at end of file diff --git a/soh/soh/ActorExtension/ActorExtension.h b/soh/soh/ActorExtension/ActorExtension.h new file mode 100644 index 000000000..01441f76d --- /dev/null +++ b/soh/soh/ActorExtension/ActorExtension.h @@ -0,0 +1,27 @@ +#ifndef ACTOR_EXTENSION_H +#define ACTOR_EXTENSION_H + +#include + +#ifdef __cplusplus +extern "C" { +#include +#endif + +typedef uint32_t ActorExtensionId; + +void* ActorExtension_Get(Actor* actor, ActorExtensionId id); + +// These should only ever be called once, before any actors are spawned +ActorExtensionId ActorExtension_CreateForId(int16_t actorId, size_t size); +ActorExtensionId ActorExtension_CreateForAll(size_t size); + +// Internal, you shouldn't have to touch these +void ActorExtension_Alloc(Actor* actor, int16_t actorId); +void ActorExtension_Free(Actor* actor); + +#ifdef __cplusplus +} +#endif + +#endif // ACTOR_EXTENSION_H \ No newline at end of file diff --git a/soh/soh/ActorExtension/ActorListIndex.cpp b/soh/soh/ActorExtension/ActorListIndex.cpp new file mode 100644 index 000000000..e46436d85 --- /dev/null +++ b/soh/soh/ActorExtension/ActorListIndex.cpp @@ -0,0 +1,32 @@ +#include "ActorListIndex.h" +#include "soh/ShipInit.hpp" +#include "soh/Enhancements/game-interactor/GameInteractor.h" + +ActorExtensionId actorListIndexActorExt = 0; +int16_t currentActorListIndex = -1; + +static RegisterShipInitFunc initFunc( + []() { + if (actorListIndexActorExt == 0) { + actorListIndexActorExt = ActorExtension_CreateForAll(sizeof(int16_t)); + } + }, + {}); + +int16_t GetActorListIndex(Actor* actor) { + int16_t* listIndex = (int16_t*)ActorExtension_Get(actor, actorListIndexActorExt); + if (listIndex == nullptr) { + return -1; + } + return *listIndex; +} + +void SetActorListIndex(Actor* actor, int16_t index) { + int16_t* listIndex = (int16_t*)ActorExtension_Get(actor, actorListIndexActorExt); + + if (listIndex == nullptr) { + assert(false); + } else { + *listIndex = index; + } +} \ No newline at end of file diff --git a/soh/soh/ActorExtension/ActorListIndex.h b/soh/soh/ActorExtension/ActorListIndex.h new file mode 100644 index 000000000..397cc7e37 --- /dev/null +++ b/soh/soh/ActorExtension/ActorListIndex.h @@ -0,0 +1,22 @@ +#ifndef ACTOR_LIST_INDEX_H +#define ACTOR_LIST_INDEX_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#include "z64actor.h" +#endif + +extern ActorExtensionId actorListIndexActorExt; +extern int16_t currentActorListIndex; + +int16_t GetActorListIndex(Actor* actor); +void SetActorListIndex(Actor* actor, int16_t index); + +#ifdef __cplusplus +} +#endif + +#endif // ACTOR_LIST_INDEX_H \ No newline at end of file diff --git a/soh/soh/Enhancements/debugger/actorViewer.cpp b/soh/soh/Enhancements/debugger/actorViewer.cpp index 515da6491..883fb795c 100644 --- a/soh/soh/Enhancements/debugger/actorViewer.cpp +++ b/soh/soh/Enhancements/debugger/actorViewer.cpp @@ -26,6 +26,7 @@ extern PlayState* gPlayState; #include "textures/icon_item_static/icon_item_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h" +#include } #define DEKUNUTS_FLOWER 10 @@ -925,6 +926,7 @@ void ActorViewerWindow::DrawElement() { ImGui::Text("Category: %s", acMapping[display->category]); ImGui::Text("ID: %d", display->id); ImGui::Text("Parameters: %d", display->params); + ImGui::Text("Actor List Index: %d", GetActorListIndex(display)); }, "Selected Actor"); ImGui::SameLine(); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 3ca67ad3b..56f65516c 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -1,4 +1,5 @@ #include "global.h" +#include "soh/ActorExtension/ActorExtension.h" #include "vt.h" #include "overlays/actors/ovl_Arms_Hook/z_arms_hook.h" @@ -80,6 +81,7 @@ #include "textures/place_title_cards/g_pn_56.h" #include "textures/place_title_cards/g_pn_57.h" #endif +#include static CollisionPoly* sCurCeilingPoly; static s32 sCurCeilingBgId; @@ -2574,8 +2576,14 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) { if (play->numSetupActors != 0) { actorEntry = &play->setupActorList[0]; for (i = 0; i < play->numSetupActors; i++) { + // #region SOH [ActorExtension] ActorListIndex tracking + currentActorListIndex = i; + // #endregion Actor_SpawnEntry(&play->actorCtx, actorEntry++, play); } + // #region SOH [ActorExtension] ActorListIndex tracking + currentActorListIndex = -1; + // #endregion play->numSetupActors = 0; GameInteractor_ExecuteOnSceneSpawnActors(); } @@ -3352,6 +3360,12 @@ Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 pos return NULL; } + // #region SOH [ActorExtension] + ActorExtension_Alloc(actor, dbEntry->id); + SetActorListIndex(actor, currentActorListIndex); + currentActorListIndex = -1; + // #endregion + assert(dbEntry->numLoaded < 255); dbEntry->numLoaded++; @@ -3494,6 +3508,10 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) { newHead = Actor_RemoveFromCategory(play, actorCtx, actor); + // #region SOH [ActorExtension] + ActorExtension_Free(actor); + // #endregion + ZELDA_ARENA_FREE_DEBUG(actor); dbEntry->numLoaded--;