mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-14 02:27:21 -07:00
Rework ActorViewer to use hooks (#5474)
* Rework ActorViewer to use hooks * Rework ActorViewer to use hooks * Remove ResetData
This commit is contained in:
parent
f2298c6a8e
commit
8b4cad1710
6 changed files with 142 additions and 150 deletions
|
@ -7,6 +7,7 @@
|
|||
#include "soh/Enhancements/nametag.h"
|
||||
#include "soh/ShipInit.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <map>
|
||||
|
@ -45,13 +46,6 @@ typedef struct {
|
|||
Vec3s rot;
|
||||
} ActorInfo;
|
||||
|
||||
typedef enum {
|
||||
LIST,
|
||||
TARGET,
|
||||
HELD,
|
||||
INTERACT,
|
||||
} RetrievalMethod;
|
||||
|
||||
std::array<const char*, 12> acMapping = {
|
||||
"Switch", "Background (Prop type 1)",
|
||||
"Player", "Bomb",
|
||||
|
@ -873,37 +867,14 @@ void ActorViewer_AddTagForAllActors() {
|
|||
|
||||
void ActorViewerWindow::DrawElement() {
|
||||
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
|
||||
static Actor* display;
|
||||
static Actor empty{};
|
||||
static Actor* fetch = NULL;
|
||||
static ActorInfo newActor = { 0, 0, { 0, 0, 0 }, { 0, 0, 0 } };
|
||||
static bool needs_reset = false;
|
||||
static ImU16 one = 1;
|
||||
static int actor;
|
||||
static int category = 0;
|
||||
static RetrievalMethod rm;
|
||||
static std::string filler = "Please select";
|
||||
static std::vector<Actor*> list;
|
||||
static u16 lastSceneId = 0;
|
||||
static std::string searchString = "";
|
||||
static s16 currentSelectedInDropdown;
|
||||
static std::vector<u16> actors;
|
||||
static s16 currentSelectedInDropdown = -1;
|
||||
static std::vector<u16> actorSearchResults;
|
||||
|
||||
if (gPlayState != nullptr) {
|
||||
needs_reset = lastSceneId != gPlayState->sceneNum;
|
||||
if (needs_reset) {
|
||||
display = ∅
|
||||
fetch = nullptr;
|
||||
actor = category = 0;
|
||||
filler = "Please Select";
|
||||
list.clear();
|
||||
needs_reset = false;
|
||||
searchString = "";
|
||||
currentSelectedInDropdown = -1;
|
||||
actors.clear();
|
||||
}
|
||||
lastSceneId = gPlayState->sceneNum;
|
||||
|
||||
if (ImGui::BeginChild("options", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
|
||||
bool toggled = false;
|
||||
bool optionChange = false;
|
||||
|
@ -967,21 +938,19 @@ void ActorViewerWindow::DrawElement() {
|
|||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (display == nullptr) {
|
||||
filler = "Please select";
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Actor", filler.c_str())) {
|
||||
if (gPlayState != nullptr && lastSceneId != gPlayState->sceneNum) {
|
||||
PopulateActorDropdown(category, list);
|
||||
lastSceneId = gPlayState->sceneNum;
|
||||
}
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
std::string label = std::to_string(i) + ": " + ActorDB::Instance->RetrieveEntry(list[i]->id).name;
|
||||
std::string description = GetActorDescription(list[i]->id);
|
||||
if (description != "")
|
||||
label += " (" + description + ")";
|
||||
|
||||
if (ImGui::Selectable(label.c_str())) {
|
||||
rm = LIST;
|
||||
if (ImGui::Selectable(label.c_str(), list[i] == display)) {
|
||||
display = list[i];
|
||||
actor = i;
|
||||
filler = label;
|
||||
break;
|
||||
}
|
||||
|
@ -992,88 +961,76 @@ void ActorViewerWindow::DrawElement() {
|
|||
|
||||
PushStyleHeader(THEME_COLOR);
|
||||
if (ImGui::TreeNode("Selected Actor")) {
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("Name: %s", ActorDB::Instance->RetrieveEntry(display->id).name.c_str());
|
||||
ImGui::Text("Description: %s", GetActorDescription(display->id).c_str());
|
||||
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();
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
if (display != nullptr) {
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("Name: %s", ActorDB::Instance->RetrieveEntry(display->id).name.c_str());
|
||||
ImGui::Text("Description: %s", GetActorDescription(display->id).c_str());
|
||||
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();
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
PushStyleInput(THEME_COLOR);
|
||||
ImGui::Text("Actor Position");
|
||||
ImGui::InputScalar("X##CurPos", ImGuiDataType_Float, &display->world.pos.x);
|
||||
ImGui::InputScalar("Y##CurPos", ImGuiDataType_Float, &display->world.pos.y);
|
||||
ImGui::InputScalar("Z##CurPos", ImGuiDataType_Float, &display->world.pos.z);
|
||||
ImGui::PopItemWidth();
|
||||
PopStyleInput();
|
||||
},
|
||||
"Actor Position");
|
||||
ImGui::SameLine();
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
PushStyleInput(THEME_COLOR);
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
ImGui::Text("Actor Rotation");
|
||||
ImGui::InputScalar("X##CurRot", ImGuiDataType_S16, &display->world.rot.x);
|
||||
ImGui::InputScalar("Y##CurRot", ImGuiDataType_S16, &display->world.rot.y);
|
||||
ImGui::InputScalar("Z##CurRot", ImGuiDataType_S16, &display->world.rot.z);
|
||||
ImGui::PopItemWidth();
|
||||
PopStyleInput();
|
||||
},
|
||||
"Actor Rotation");
|
||||
|
||||
if (display->category == ACTORCAT_BOSS || display->category == ACTORCAT_ENEMY) {
|
||||
PushStyleInput(THEME_COLOR);
|
||||
ImGui::Text("Actor Position");
|
||||
ImGui::InputScalar("X##CurPos", ImGuiDataType_Float, &display->world.pos.x);
|
||||
ImGui::InputScalar("Y##CurPos", ImGuiDataType_Float, &display->world.pos.y);
|
||||
ImGui::InputScalar("Z##CurPos", ImGuiDataType_Float, &display->world.pos.z);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display->colChkInfo.health);
|
||||
PopStyleInput();
|
||||
},
|
||||
"Actor Position");
|
||||
ImGui::SameLine();
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
PushStyleInput(THEME_COLOR);
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
|
||||
ImGui::Text("Actor Rotation");
|
||||
ImGui::InputScalar("X##CurRot", ImGuiDataType_S16, &display->world.rot.x);
|
||||
ImGui::InputScalar("Y##CurRot", ImGuiDataType_S16, &display->world.rot.y);
|
||||
ImGui::InputScalar("Z##CurRot", ImGuiDataType_S16, &display->world.rot.z);
|
||||
ImGui::PopItemWidth();
|
||||
PopStyleInput();
|
||||
},
|
||||
"Actor Rotation");
|
||||
|
||||
if (display->category == ACTORCAT_BOSS || display->category == ACTORCAT_ENEMY) {
|
||||
PushStyleInput(THEME_COLOR);
|
||||
ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display->colChkInfo.health);
|
||||
PopStyleInput();
|
||||
UIWidgets::InsertHelpHoverText("Some actors might not use this!");
|
||||
}
|
||||
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("flags");
|
||||
UIWidgets::DrawFlagArray32("flags", display->flags);
|
||||
},
|
||||
"flags");
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("bgCheckFlags");
|
||||
UIWidgets::DrawFlagArray16("bgCheckFlags", display->bgCheckFlags);
|
||||
},
|
||||
"bgCheckFlags");
|
||||
|
||||
if (Button("Refresh", ButtonOptions().Color(THEME_COLOR))) {
|
||||
PopulateActorDropdown(category, list);
|
||||
switch (rm) {
|
||||
case INTERACT:
|
||||
case HELD:
|
||||
case TARGET:
|
||||
display = fetch;
|
||||
break;
|
||||
case LIST:
|
||||
display = list[actor];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
UIWidgets::InsertHelpHoverText("Some actors might not use this!");
|
||||
}
|
||||
}
|
||||
|
||||
if (Button("Go to Actor", ButtonOptions().Color(THEME_COLOR))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos);
|
||||
Math_Vec3f_Copy(&player->actor.home.pos, &player->actor.world.pos);
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("flags");
|
||||
UIWidgets::DrawFlagArray32("flags", display->flags);
|
||||
},
|
||||
"flags");
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
DrawGroupWithBorder(
|
||||
[&]() {
|
||||
ImGui::Text("bgCheckFlags");
|
||||
UIWidgets::DrawFlagArray16("bgCheckFlags", display->bgCheckFlags);
|
||||
},
|
||||
"bgCheckFlags");
|
||||
|
||||
if (Button("Go to Actor", ButtonOptions().Color(THEME_COLOR))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos);
|
||||
Math_Vec3f_Copy(&player->actor.home.pos, &player->actor.world.pos);
|
||||
}
|
||||
} else {
|
||||
ImGui::Text("Select an actor to display information.");
|
||||
}
|
||||
|
||||
if (Button("Fetch from Target",
|
||||
|
@ -1081,34 +1038,28 @@ void ActorViewerWindow::DrawElement() {
|
|||
.Color(THEME_COLOR)
|
||||
.Tooltip("Grabs actor with target arrow above it. You might need C-Up for enemies"))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->talkActor;
|
||||
if (fetch != NULL) {
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
if (player->talkActor != NULL) {
|
||||
display = player->talkActor;
|
||||
category = display->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = TARGET;
|
||||
}
|
||||
}
|
||||
if (Button("Fetch from Held",
|
||||
ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor that Link is holding"))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->heldActor;
|
||||
if (fetch != NULL) {
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
if (player->heldActor != NULL) {
|
||||
display = player->heldActor;
|
||||
category = display->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = HELD;
|
||||
}
|
||||
}
|
||||
if (Button("Fetch from Interaction",
|
||||
ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor from \"interaction range\""))) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
fetch = player->interactRangeActor;
|
||||
if (fetch != NULL) {
|
||||
display = fetch;
|
||||
category = fetch->category;
|
||||
if (player->interactRangeActor != NULL) {
|
||||
display = player->interactRangeActor;
|
||||
category = display->category;
|
||||
PopulateActorDropdown(category, list);
|
||||
rm = INTERACT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1119,21 +1070,22 @@ void ActorViewerWindow::DrawElement() {
|
|||
// ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
|
||||
|
||||
if (InputString("Search Actor", &searchString, InputOptions().Color(THEME_COLOR))) {
|
||||
actors = GetActorsWithDescriptionContainingString(searchString);
|
||||
actorSearchResults = GetActorsWithDescriptionContainingString(searchString);
|
||||
currentSelectedInDropdown = -1;
|
||||
}
|
||||
|
||||
if (!SohUtils::IsStringEmpty(searchString) && !actors.empty()) {
|
||||
std::string preview = currentSelectedInDropdown == -1
|
||||
? "Please Select"
|
||||
: ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc;
|
||||
if (!SohUtils::IsStringEmpty(searchString) && !actorSearchResults.empty()) {
|
||||
std::string preview =
|
||||
currentSelectedInDropdown == -1
|
||||
? "Please Select"
|
||||
: ActorDB::Instance->RetrieveEntry(actorSearchResults[currentSelectedInDropdown]).desc;
|
||||
PushStyleCombobox(THEME_COLOR);
|
||||
if (ImGui::BeginCombo("Results", preview.c_str())) {
|
||||
for (u8 i = 0; i < actors.size(); i++) {
|
||||
if (ImGui::Selectable(ActorDB::Instance->RetrieveEntry(actors[i]).desc.c_str(),
|
||||
for (u8 i = 0; i < actorSearchResults.size(); i++) {
|
||||
if (ImGui::Selectable(ActorDB::Instance->RetrieveEntry(actorSearchResults[i]).desc.c_str(),
|
||||
i == currentSelectedInDropdown)) {
|
||||
currentSelectedInDropdown = i;
|
||||
newActor.id = actors[i];
|
||||
newActor.id = actorSearchResults[i];
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
|
@ -1237,20 +1189,40 @@ void ActorViewerWindow::DrawElement() {
|
|||
PopStyleHeader();
|
||||
} else {
|
||||
ImGui::Text("Global Context needed for actor info!");
|
||||
if (needs_reset) {
|
||||
fetch = nullptr;
|
||||
actor = category = 0;
|
||||
filler = "Please Select";
|
||||
list.clear();
|
||||
needs_reset = false;
|
||||
searchString = "";
|
||||
currentSelectedInDropdown = -1;
|
||||
actors.clear();
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
void ActorViewerWindow::InitElement() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorSpawn>([this](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
|
||||
// Reload actor list if the new actor belongs to the selected category
|
||||
if (category == actor->category) {
|
||||
PopulateActorDropdown(actor->category, list);
|
||||
}
|
||||
});
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorDestroy>([this](void* refActor) {
|
||||
Actor* actor = static_cast<Actor*>(refActor);
|
||||
|
||||
// If the actor belongs to the selected category, we need to manually remove it, as it has not been removed from
|
||||
// the global actor array yet
|
||||
if (category == actor->category) {
|
||||
list.erase(std::remove(list.begin(), list.end(), actor), list.end());
|
||||
}
|
||||
if (display == actor) {
|
||||
display = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([this](int16_t sceneNum) {
|
||||
display = nullptr;
|
||||
category = ACTORCAT_SWITCH;
|
||||
list.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void ActorViewer_RegisterNameTagHooks() {
|
||||
COND_HOOK(OnActorInit, CVAR_ACTOR_NAME_TAGS_ENABLED,
|
||||
[](void* actor) { ActorViewer_AddTagForActor(static_cast<Actor*>(actor)); });
|
||||
|
|
|
@ -2,11 +2,20 @@
|
|||
|
||||
#include <libultraship/libultraship.h>
|
||||
|
||||
#include "z64actor.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ActorViewerWindow final : public Ship::GuiWindow {
|
||||
public:
|
||||
using GuiWindow::GuiWindow;
|
||||
|
||||
void DrawElement() override;
|
||||
void InitElement() override{};
|
||||
void InitElement() override;
|
||||
void UpdateElement() override{};
|
||||
|
||||
private:
|
||||
Actor* display = nullptr;
|
||||
int category = ACTORCAT_SWITCH;
|
||||
std::vector<Actor*> list;
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@ DEFINE_HOOK(OnOcarinaSongAction, ());
|
|||
DEFINE_HOOK(OnCuccoOrChickenHatch, ());
|
||||
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
|
||||
DEFINE_HOOK(OnActorInit, (void* actor));
|
||||
DEFINE_HOOK(OnActorSpawn, (void* actor));
|
||||
DEFINE_HOOK(OnActorUpdate, (void* actor));
|
||||
DEFINE_HOOK(OnActorKill, (void* actor));
|
||||
DEFINE_HOOK(OnActorDestroy, (void* actor));
|
||||
|
|
|
@ -108,6 +108,13 @@ void GameInteractor_ExecuteOnActorInit(void* actor) {
|
|||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorInit>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnActorSpawn(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnActorSpawn>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnActorSpawn>(((Actor*)actor)->id, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnActorSpawn>((uintptr_t)actor, actor);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnActorSpawn>(actor);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnActorUpdate(void* actor) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnActorUpdate>(actor);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnActorUpdate>(((Actor*)actor)->id, actor);
|
||||
|
|
|
@ -29,6 +29,7 @@ void GameInteractor_ExecuteOnSetDoAction(uint16_t action);
|
|||
void GameInteractor_ExecuteOnOcarinaSongAction();
|
||||
void GameInteractor_ExecuteOnCuccoOrChickenHatch();
|
||||
void GameInteractor_ExecuteOnActorInit(void* actor);
|
||||
void GameInteractor_ExecuteOnActorSpawn(void* actor);
|
||||
void GameInteractor_ExecuteOnActorUpdate(void* actor);
|
||||
void GameInteractor_ExecuteOnActorKill(void* actor);
|
||||
void GameInteractor_ExecuteOnActorDestroy(void* actor);
|
||||
|
|
|
@ -3401,6 +3401,8 @@ Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 pos
|
|||
Actor_Init(actor, play);
|
||||
gSegments[6] = temp;
|
||||
|
||||
GameInteractor_ExecuteOnActorSpawn(actor);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue