mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-04-28 13:17:58 +03:00
port over nametag improvements from 2ship
This commit is contained in:
parent
8f126344a4
commit
5b14cf5f69
9 changed files with 193 additions and 70 deletions
|
@ -5,6 +5,7 @@
|
|||
#include "soh/ActorDB.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/nametag.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include <string>
|
||||
#include <libultraship/bridge.h>
|
||||
#include <libultraship/libultraship.h>
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/cvar_prefixes.h"
|
||||
|
||||
|
@ -31,6 +33,10 @@ extern PlayState* gPlayState;
|
|||
#define DEKUNUTS_FLOWER 10
|
||||
#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer"
|
||||
|
||||
#define CVAR_ACTOR_NAME_TAGS(val) CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags." val)
|
||||
#define CVAR_ACTOR_NAME_TAGS_ENABLED_NAME CVAR_ACTOR_NAME_TAGS("Enabled")
|
||||
#define CVAR_ACTOR_NAME_TAGS_ENABLED CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0)
|
||||
|
||||
typedef struct {
|
||||
u16 id;
|
||||
u16 params;
|
||||
|
@ -67,6 +73,10 @@ const std::string GetActorDescription(u16 id) {
|
|||
return ActorDB::Instance->RetrieveEntry(id).entry.valid ? ActorDB::Instance->RetrieveEntry(id).entry.desc : "???";
|
||||
}
|
||||
|
||||
const std::string GetActorDebugName(u16 id) {
|
||||
return ActorDB::Instance->RetrieveEntry(id).entry.valid ? ActorDB::Instance->RetrieveEntry(id).entry.name : "???";
|
||||
}
|
||||
|
||||
template <typename T> void DrawGroupWithBorder(T&& drawFunc, std::string section) {
|
||||
// First group encapsulates the inner portion and border
|
||||
ImGui::BeginChild(std::string("##" + section).c_str(), ImVec2(0, 0),
|
||||
|
@ -812,25 +822,37 @@ std::vector<u16> GetActorsWithDescriptionContainingString(std::string s) {
|
|||
}
|
||||
|
||||
void ActorViewer_AddTagForActor(Actor* actor) {
|
||||
int val = CVarGetInteger(CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), ACTORVIEWER_NAMETAGS_NONE);
|
||||
auto entry = ActorDB::Instance->RetrieveEntry(actor->id);
|
||||
std::string tag;
|
||||
|
||||
if (val > 0 && entry.entry.valid) {
|
||||
switch (val) {
|
||||
case ACTORVIEWER_NAMETAGS_DESC:
|
||||
tag = entry.desc;
|
||||
break;
|
||||
case ACTORVIEWER_NAMETAGS_NAME:
|
||||
tag = entry.name;
|
||||
break;
|
||||
case ACTORVIEWER_NAMETAGS_BOTH:
|
||||
tag = entry.name + '\n' + entry.desc;
|
||||
break;
|
||||
if (!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NameTag_RegisterForActorWithOptions(actor, tag.c_str(), { .tag = DEBUG_ACTOR_NAMETAG_TAG });
|
||||
std::vector<std::string> parts;
|
||||
|
||||
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 0)) {
|
||||
parts.push_back(GetActorDebugName(actor->id));
|
||||
}
|
||||
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayDescription"), 0)) {
|
||||
parts.push_back(GetActorDescription(actor->id));
|
||||
}
|
||||
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayCategory"), 0)) {
|
||||
parts.push_back(acMapping[actor->category]);
|
||||
}
|
||||
if (CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayParams"), 0)) {
|
||||
parts.push_back(fmt::format("0x{:04X} ({})", (u16)actor->params, actor->params));
|
||||
}
|
||||
|
||||
std::string tag = "";
|
||||
for (size_t i = 0; i < parts.size(); i++) {
|
||||
if (i != 0) {
|
||||
tag += "\n";
|
||||
}
|
||||
tag += parts.at(i);
|
||||
}
|
||||
|
||||
bool withZBuffer = CVarGetInteger(CVAR_ACTOR_NAME_TAGS("WithZBuffer"), 0);
|
||||
|
||||
NameTag_RegisterForActorWithOptions(actor, tag.c_str(),
|
||||
{ .tag = DEBUG_ACTOR_NAMETAG_TAG, .noZBuffer = !withZBuffer });
|
||||
}
|
||||
|
||||
void ActorViewer_AddTagForAllActors() {
|
||||
|
@ -880,6 +902,57 @@ void ActorViewerWindow::DrawElement() {
|
|||
}
|
||||
lastSceneId = gPlayState->sceneNum;
|
||||
|
||||
if (ImGui::BeginChild("options", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
|
||||
bool toggled = false;
|
||||
bool optionChange = false;
|
||||
|
||||
ImGui::SeparatorText("Options");
|
||||
|
||||
toggled = UIWidgets::CVarCheckbox("Actor Name Tags", CVAR_ACTOR_NAME_TAGS("Enabled"),
|
||||
{ { .tooltip = "Adds \"name tags\" above actors for identification" } });
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
UIWidgets::Button("Display Items", { { .tooltip = "Click to add display items on the name tags" } });
|
||||
|
||||
if (ImGui::BeginPopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonLeft | ImGuiPopupFlags_NoReopen)) {
|
||||
optionChange |= UIWidgets::CVarCheckbox("ID", CVAR_ACTOR_NAME_TAGS("DisplayID"));
|
||||
optionChange |= UIWidgets::CVarCheckbox("Description", CVAR_ACTOR_NAME_TAGS("DisplayDescription"));
|
||||
optionChange |= UIWidgets::CVarCheckbox("Category", CVAR_ACTOR_NAME_TAGS("DisplayCategory"));
|
||||
optionChange |= UIWidgets::CVarCheckbox("Params", CVAR_ACTOR_NAME_TAGS("DisplayParams"));
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
optionChange |= UIWidgets::CVarCheckbox(
|
||||
"Name tags with Z-Buffer", CVAR_ACTOR_NAME_TAGS("WithZBuffer"),
|
||||
{ { .tooltip = "Allow name tags to be obstructed when behind geometry and actors" } });
|
||||
|
||||
if (toggled || optionChange) {
|
||||
bool tagsEnabled = CVarGetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0);
|
||||
bool noOptionsEnabled = !CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 0) &&
|
||||
!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayDescription"), 0) &&
|
||||
!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayCategory"), 0) &&
|
||||
!CVarGetInteger(CVAR_ACTOR_NAME_TAGS("DisplayParams"), 0);
|
||||
|
||||
// Save the user an extra click and prevent adding "empty" tags by enabling,
|
||||
// disabling, or setting an option based on what changed
|
||||
if (tagsEnabled && noOptionsEnabled) {
|
||||
if (toggled) {
|
||||
CVarSetInteger(CVAR_ACTOR_NAME_TAGS("DisplayID"), 1);
|
||||
} else {
|
||||
CVarSetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 0);
|
||||
}
|
||||
} else if (optionChange && !tagsEnabled && !noOptionsEnabled) {
|
||||
CVarSetInteger(CVAR_ACTOR_NAME_TAGS("Enabled"), 1);
|
||||
}
|
||||
|
||||
NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG);
|
||||
ActorViewer_AddTagForAllActors();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
PushStyleCombobox(THEME_COLOR);
|
||||
if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
|
||||
for (int i = 0; i < acMapping.size(); i++) {
|
||||
|
@ -1159,20 +1232,6 @@ void ActorViewerWindow::DrawElement() {
|
|||
ImGui::TreePop();
|
||||
}
|
||||
PopStyleHeader();
|
||||
|
||||
static std::unordered_map<int32_t, const char*> nameTagOptions = {
|
||||
{ 0, "None" },
|
||||
{ 1, "Short Description" },
|
||||
{ 2, "Actor ID" },
|
||||
{ 3, "Both" },
|
||||
};
|
||||
|
||||
if (CVarCombobox(
|
||||
"Actor Name Tags", CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), nameTagOptions,
|
||||
ComboboxOptions().Color(THEME_COLOR).Tooltip("Adds \"name tags\" above actors for identification"))) {
|
||||
NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG);
|
||||
ActorViewer_AddTagForAllActors();
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Global Context needed for actor info!");
|
||||
if (needs_reset) {
|
||||
|
@ -1188,9 +1247,9 @@ void ActorViewerWindow::DrawElement() {
|
|||
}
|
||||
}
|
||||
|
||||
void ActorViewerWindow::InitElement() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
ActorViewer_AddTagForActor(actor);
|
||||
});
|
||||
void ActorViewer_RegisterNameTagHooks() {
|
||||
COND_HOOK(OnActorInit, CVAR_ACTOR_NAME_TAGS_ENABLED,
|
||||
[](void* actor) { ActorViewer_AddTagForActor(static_cast<Actor*>(actor)); });
|
||||
}
|
||||
|
||||
RegisterShipInitFunc nametagInit(ActorViewer_RegisterNameTagHooks, { CVAR_ACTOR_NAME_TAGS_ENABLED_NAME });
|
||||
|
|
|
@ -7,6 +7,6 @@ class ActorViewerWindow : public Ship::GuiWindow {
|
|||
using GuiWindow::GuiWindow;
|
||||
|
||||
void DrawElement() override;
|
||||
void InitElement() override;
|
||||
void InitElement() override{};
|
||||
void UpdateElement() override{};
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@ DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
|
|||
DEFINE_HOOK(OnActorInit, (void* actor));
|
||||
DEFINE_HOOK(OnActorUpdate, (void* actor));
|
||||
DEFINE_HOOK(OnActorKill, (void* actor));
|
||||
DEFINE_HOOK(OnActorDestroy, (void* actor));
|
||||
DEFINE_HOOK(OnEnemyDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnBossDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnTimestamp, (u8 item));
|
||||
|
|
|
@ -112,6 +112,13 @@ void GameInteractor_ExecuteOnActorKill(void* actor) {
|
|||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorKill>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnActorDestroy(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnActorDestroy>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnActorDestroy>(((Actor*)actor)->id, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnActorDestroy>((uintptr_t)actor, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorDestroy>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnEnemyDefeat(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnEnemyDefeat>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnEnemyDefeat>(((Actor*)actor)->id, actor);
|
||||
|
|
|
@ -29,6 +29,7 @@ void GameInteractor_ExecuteOnCuccoOrChickenHatch();
|
|||
void GameInteractor_ExecuteOnActorInit(void* actor);
|
||||
void GameInteractor_ExecuteOnActorUpdate(void* actor);
|
||||
void GameInteractor_ExecuteOnActorKill(void* actor);
|
||||
void GameInteractor_ExecuteOnActorDestroy(void* actor);
|
||||
void GameInteractor_ExecuteOnEnemyDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnBossDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnTimestamp(u8 item);
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "soh/Enhancements/randomizer/3drando/random.hpp"
|
||||
#include "soh/Enhancements/cosmetics/authenticGfxPatches.h"
|
||||
#include <soh/Enhancements/item-tables/ItemTableManager.h>
|
||||
#include "soh/Enhancements/nametag.h"
|
||||
#include "soh/Enhancements/timesaver_hook_handlers.h"
|
||||
#include "soh/Enhancements/TimeSavers/TimeSavers.h"
|
||||
#include "soh/Enhancements/randomizer/hook_handlers.h"
|
||||
|
@ -1090,7 +1089,6 @@ void InitMods() {
|
|||
RegisterRandomizedEnemySizes();
|
||||
RegisterOpenAllHours();
|
||||
RegisterToTMedallions();
|
||||
NameTag_RegisterHooks();
|
||||
RegisterFloorSwitchesHook();
|
||||
RegisterPatchHandHandler();
|
||||
RegisterHurtContainerModeHandler();
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Enhancements/custom-message/CustomMessageInterfaceAddon.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/ShipUtils.h"
|
||||
|
||||
extern "C" {
|
||||
#include "z64.h"
|
||||
|
@ -26,12 +26,16 @@ typedef struct {
|
|||
int16_t height; // Textbox height
|
||||
int16_t width; // Textbox width
|
||||
int16_t yOffset; // Addition Y offset
|
||||
uint8_t noZBuffer; // Allow rendering over geometry
|
||||
Mtx* mtx; // Allocated Mtx for rendering
|
||||
Vtx* vtx; // Allocated Vtx for rendering
|
||||
} NameTag;
|
||||
|
||||
static std::vector<NameTag> nameTags;
|
||||
static std::vector<Gfx> nameTagDl;
|
||||
static bool sMirrorWorldActive = false;
|
||||
|
||||
void NameTag_RegisterHooks();
|
||||
|
||||
void FreeNameTag(NameTag* nameTag) {
|
||||
if (nameTag->vtx != nullptr) {
|
||||
|
@ -51,14 +55,14 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
|
|||
}
|
||||
|
||||
// Name tag is too far away to meaningfully read, don't bother rendering it
|
||||
if (nameTag->actor->xyzDistToPlayerSq > 200000.0f) {
|
||||
if (nameTag->actor->xyzDistToPlayerSq > 440000.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fade out name tags that are far away
|
||||
float alpha = 1.0f;
|
||||
if (nameTag->actor->xyzDistToPlayerSq > 160000.0f) {
|
||||
alpha = (200000.0f - nameTag->actor->xyzDistToPlayerSq) / 40000.0f;
|
||||
if (nameTag->actor->xyzDistToPlayerSq > 360000.0f) {
|
||||
alpha = (440000.0f - nameTag->actor->xyzDistToPlayerSq) / 80000.0f;
|
||||
}
|
||||
|
||||
float scale = 75.0f / 100.f;
|
||||
|
@ -79,7 +83,7 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
|
|||
textColor = CVarGetColor(CVAR_COSMETIC("HUD.NameTagActorText.Value"), textColor);
|
||||
}
|
||||
|
||||
FrameInterpolation_RecordOpenChild(nameTag->actor, 10);
|
||||
FrameInterpolation_RecordOpenChild(nameTag->actor, 0);
|
||||
|
||||
// Prefer the highest between world position and focus position if targetable
|
||||
float posY = nameTag->actor->world.pos.y;
|
||||
|
@ -92,7 +96,7 @@ void DrawNameTag(PlayState* play, const NameTag* nameTag) {
|
|||
// Set position, billboard effect, scale (with mirror mode), then center nametag
|
||||
Matrix_Translate(nameTag->actor->world.pos.x, posY, nameTag->actor->world.pos.z, MTXMODE_NEW);
|
||||
Matrix_ReplaceRotation(&play->billboardMtxF);
|
||||
Matrix_Scale(scale * (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? -1 : 1), -scale, 1.0f, MTXMODE_APPLY);
|
||||
Matrix_Scale(scale * (sMirrorWorldActive ? -1.0f : 1.0f), -scale, 1.0f, MTXMODE_APPLY);
|
||||
Matrix_Translate(-(float)nameTag->width / 2, -nameTag->height, 0, MTXMODE_APPLY);
|
||||
Matrix_ToMtx(nameTag->mtx, (char*)__FILE__, __LINE__);
|
||||
|
||||
|
@ -154,15 +158,27 @@ void DrawNameTags() {
|
|||
OPEN_DISPS(gPlayState->state.gfxCtx);
|
||||
|
||||
// Setup before rendering name tags
|
||||
Gfx_SetupDL_38Xlu(gPlayState->state.gfxCtx);
|
||||
nameTagDl.push_back(gsDPSetAlphaDither(G_AD_DISABLE));
|
||||
nameTagDl.push_back(gsSPClearGeometryMode(G_SHADE));
|
||||
POLY_XLU_DISP = Gfx_SetupDL_39(POLY_XLU_DISP);
|
||||
|
||||
nameTagDl.push_back(gsDPSetAlphaCompare(G_AC_NONE));
|
||||
nameTagDl.push_back(
|
||||
gsDPSetCombineLERP(0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0));
|
||||
|
||||
bool zbufferEnabled = false;
|
||||
|
||||
// Add all the name tags
|
||||
for (const auto& nameTag : nameTags) {
|
||||
// Toggle ZBuffer mode based on last state and next tag
|
||||
if (zbufferEnabled == nameTag.noZBuffer) {
|
||||
if (nameTag.noZBuffer) {
|
||||
nameTagDl.push_back(gsSPClearGeometryMode(G_ZBUFFER));
|
||||
zbufferEnabled = false;
|
||||
} else {
|
||||
nameTagDl.push_back(gsSPSetGeometryMode(G_ZBUFFER));
|
||||
zbufferEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
DrawNameTag(gPlayState, &nameTag);
|
||||
}
|
||||
|
||||
|
@ -189,22 +205,22 @@ void UpdateNameTags() {
|
|||
|
||||
return aDistToCamera > bDistToCamera;
|
||||
});
|
||||
|
||||
sMirrorWorldActive = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0);
|
||||
}
|
||||
|
||||
extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* text, NameTagOptions options) {
|
||||
std::string processedText = std::string(Interface_ReplaceSpecialCharacters((char*)text));
|
||||
|
||||
// Strip out unsupported characters
|
||||
processedText.erase(std::remove_if(processedText.begin(), processedText.end(),
|
||||
[](const char& c) {
|
||||
// 172 is max supported texture for the in-game font system,
|
||||
// and filter anything less than a space but not the newline or nul
|
||||
// characters
|
||||
return (unsigned char)c > 172 || (c < ' ' && c != '\n' && c != '\0');
|
||||
}),
|
||||
// and filter anything less than a space but not the newline or nul characters
|
||||
processedText.erase(
|
||||
std::remove_if(processedText.begin(), processedText.end(),
|
||||
[](const char& c) { return (uint8_t)c > 172 || (c < ' ' && c != '\n' && c != '\0'); }),
|
||||
processedText.end());
|
||||
|
||||
int16_t numChar = processedText.length();
|
||||
size_t numChar = processedText.length();
|
||||
int16_t numLines = 1;
|
||||
int16_t offsetX = 0;
|
||||
int16_t maxOffsetX = 0;
|
||||
|
@ -213,7 +229,7 @@ extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* te
|
|||
Vtx* vertices = (Vtx*)calloc(sizeof(Vtx[4]), numChar + 1);
|
||||
|
||||
// Set all the char vtx first to get the total size for the textbox
|
||||
for (int16_t i = 0; i < numChar; i++) {
|
||||
for (size_t i = 0; i < numChar; i++) {
|
||||
if (processedText[i] == '\n') {
|
||||
offsetX = 0;
|
||||
numLines++;
|
||||
|
@ -249,10 +265,13 @@ extern "C" void NameTag_RegisterForActorWithOptions(Actor* actor, const char* te
|
|||
nameTag.height = height;
|
||||
nameTag.width = width;
|
||||
nameTag.yOffset = options.yOffset;
|
||||
nameTag.noZBuffer = options.noZBuffer;
|
||||
nameTag.mtx = new Mtx();
|
||||
nameTag.vtx = vertices;
|
||||
|
||||
nameTags.push_back(nameTag);
|
||||
|
||||
NameTag_RegisterHooks();
|
||||
}
|
||||
|
||||
extern "C" void NameTag_RegisterForActor(Actor* actor, const char* text) {
|
||||
|
@ -268,6 +287,8 @@ extern "C" void NameTag_RemoveAllForActor(Actor* actor) {
|
|||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
NameTag_RegisterHooks();
|
||||
}
|
||||
|
||||
extern "C" void NameTag_RemoveAllByTag(const char* tag) {
|
||||
|
@ -279,6 +300,8 @@ extern "C" void NameTag_RemoveAllByTag(const char* tag) {
|
|||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
NameTag_RegisterHooks();
|
||||
}
|
||||
|
||||
void RemoveAllNameTags() {
|
||||
|
@ -287,23 +310,49 @@ void RemoveAllNameTags() {
|
|||
}
|
||||
|
||||
nameTags.clear();
|
||||
|
||||
NameTag_RegisterHooks();
|
||||
}
|
||||
|
||||
static bool sRegisteredHooks = false;
|
||||
|
||||
void NameTag_RegisterHooks() {
|
||||
if (sRegisteredHooks) {
|
||||
static HOOK_ID gameStatUpdateHookID = 0;
|
||||
static HOOK_ID drawHookID = 0;
|
||||
static HOOK_ID playDestroyHookID = 0;
|
||||
static HOOK_ID actorDestroyHookID = 0;
|
||||
static bool sRegisteredHooks = false;
|
||||
|
||||
// Hooks already (un)registered based on nametags
|
||||
if ((nameTags.size() > 0) == sRegisteredHooks) {
|
||||
return;
|
||||
}
|
||||
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnGameFrameUpdate>(gameStatUpdateHookID);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnPlayDrawEnd>(drawHookID);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnPlayDestroy>(playDestroyHookID);
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorDestroy>(actorDestroyHookID);
|
||||
gameStatUpdateHookID = 0;
|
||||
drawHookID = 0;
|
||||
playDestroyHookID = 0;
|
||||
actorDestroyHookID = 0;
|
||||
sRegisteredHooks = false;
|
||||
|
||||
if (nameTags.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
sRegisteredHooks = true;
|
||||
|
||||
// Reorder tags every frame to mimic depth rendering
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() { UpdateNameTags(); });
|
||||
gameStatUpdateHookID =
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>(UpdateNameTags);
|
||||
|
||||
// Render name tags at the end of player draw to avoid overflowing the display buffers
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDrawEnd>([]() { DrawNameTags(); });
|
||||
// Render name tags at the end of the Play World drawing
|
||||
drawHookID = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDrawEnd>(DrawNameTags);
|
||||
|
||||
// Remove all name tags on play state destroy as all actors are removed anyways
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDestroy>([]() { RemoveAllNameTags(); });
|
||||
playDestroyHookID = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPlayDestroy>(RemoveAllNameTags);
|
||||
|
||||
// Remove all name tags for actor on destroy
|
||||
actorDestroyHookID = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorDestroy>(
|
||||
[](void* actor) { NameTag_RemoveAllForActor((Actor*)actor); });
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
#ifndef _NAMETAG_H_
|
||||
#define _NAMETAG_H_
|
||||
#include <z64.h>
|
||||
#ifndef NAMETAG_H
|
||||
#define NAMETAG_H
|
||||
|
||||
#include <libultraship/color.h>
|
||||
#include <libultraship/libultra.h>
|
||||
|
||||
struct Actor;
|
||||
|
||||
typedef struct {
|
||||
const char* tag; // Tag identifier to filter/remove multiple tags
|
||||
int16_t yOffset; // Additional Y offset to apply for the name tag
|
||||
Color_RGBA8 textColor; // Text color override. Global color is used if alpha is 0
|
||||
uint8_t noZBuffer; // Allow rendering over geometry
|
||||
} NameTagOptions;
|
||||
|
||||
// Register required hooks for nametags on startup
|
||||
|
@ -28,4 +33,4 @@ void NameTag_RemoveAllByTag(const char* tag);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif // _NAMETAG_H_
|
||||
#endif // NAMETAG_H
|
||||
|
|
|
@ -3466,6 +3466,9 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) {
|
|||
|
||||
player = GET_PLAYER(play);
|
||||
|
||||
// Execute before actor memory is freed
|
||||
GameInteractor_ExecuteOnActorDestroy(actor);
|
||||
|
||||
dbEntry = ActorDB_Retrieve(actor->id);
|
||||
|
||||
if (HREG(20) != 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue