Files
2ship2harkinian-Android/mm/2s2h/DeveloperTools/ActorViewer.cpp
briaguya 6da0031295 run clang format (#448)
* add linux clang format script

* first shot at powershell

* whoops

* webrequest is slow, try webclient

* just get the one file

* simplify and maybe make it work?

* whoops again

* try a different suggestion

* why is it always windows

* again

* try again

* bit of path stuff

* chmod +x

* add action to check

* fix workflow name

* run clang format
2024-05-22 09:05:05 -05:00

319 lines
13 KiB
C++

#include "ActorViewer.h"
#include "2s2h/BenGui/UIWidgets.hpp"
#include "global.h"
#include "2s2h/Enhancements/GameInteractor/GameInteractor.h"
typedef struct ActorInfo {
u16 id;
u16 params;
Vec3f pos;
Vec3s rot;
} ActorInfo;
typedef enum Method {
LIST,
TARGET,
HOLD,
} Method;
std::array<const char*, 12> acMapping = { "Switch", "Background", "Player", "Explosive", "NPC", "Enemy",
"Prop", "Item/Action", "Misc.", "Boss", "Door", "Chest" };
#define DEFINE_ACTOR(name, _enumValue, _allocType, _debugName, _humanName) { _enumValue, _humanName },
#define DEFINE_ACTOR_INTERNAL(_name, _enumValue, _allocType, _debugName, _humanName) { _enumValue, _humanName },
#define DEFINE_ACTOR_UNSET(_enumValue) { _enumValue, "Unset" },
std::unordered_map<s16, const char*> actorDescriptions = {
#include "tables/actor_table.h"
};
#undef DEFINE_ACTOR
#undef DEFINE_ACTOR_INTERNAL
#undef DEFINE_ACTOR_UNSET
std::string GetActorDescription(u16 actorNum) {
return actorDescriptions.contains(actorNum) ? actorDescriptions[actorNum] : "???";
}
std::vector<Actor*> GetCurrentSceneActors() {
if (!gPlayState)
return {};
std::vector<Actor*> sceneActors;
for (size_t category = ACTORCAT_SWITCH; category < ACTORCAT_MAX; category++) {
Actor* currentActor = gPlayState->actorCtx.actorLists[category].first;
if (currentActor != nullptr) {
while (currentActor != nullptr) {
sceneActors.push_back(currentActor);
currentActor = currentActor->next;
}
}
}
return sceneActors;
}
static bool needs_reset = false;
static Actor* display{};
static Actor* fetch;
static ActorInfo newActor;
static std::vector<Actor*> list;
static s16 lastSceneId = 0;
static s16 newActorId = 0;
static u8 category = 0;
static s8 method = -1;
static std::string filler = "Please select";
static HOOK_ID preventActorDrawHookId = 0;
static HOOK_ID preventActorUpdateHookId = 0;
void ResetVariables() {
display = fetch = {};
newActor = {};
filler = "Please select";
GameInteractor::Instance->UnregisterGameHookForPtr<GameInteractor::ShouldActorDraw>(preventActorDrawHookId);
GameInteractor::Instance->UnregisterGameHookForPtr<GameInteractor::ShouldActorUpdate>(preventActorUpdateHookId);
preventActorDrawHookId = 0;
preventActorUpdateHookId = 0;
}
void ActorViewerWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Actor Viewer", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
return;
}
if (gPlayState != nullptr) {
needs_reset = lastSceneId != gPlayState->sceneId;
if (needs_reset) {
ResetVariables();
lastSceneId = gPlayState->sceneId;
needs_reset = false;
}
if (ImGui::BeginCombo("Actor", filler.c_str())) {
if (gPlayState != nullptr) {
list = GetCurrentSceneActors();
lastSceneId = gPlayState->sceneId;
}
if (!list.empty()) {
u8 count = 0;
u8 prev_category = 0xff;
for (size_t i = 0; i < list.size(); i++) {
std::string label = acMapping[list[i]->category];
if (list[i]->category != prev_category) {
prev_category = list[i]->category;
count = 1;
} else {
count++;
}
label += " " + std::to_string(count) + ": " + GetActorDescription(list[i]->id);
if (ImGui::Selectable(label.c_str())) {
method = LIST;
display = list[i];
newActorId = i;
filler = label;
GameInteractor::Instance->UnregisterGameHookForPtr<GameInteractor::ShouldActorDraw>(
preventActorDrawHookId);
GameInteractor::Instance->UnregisterGameHookForPtr<GameInteractor::ShouldActorUpdate>(
preventActorUpdateHookId);
preventActorDrawHookId = 0;
preventActorUpdateHookId = 0;
break;
}
}
}
ImGui::EndCombo();
}
if (ImGui::TreeNode("Selected Actor")) {
if (display != nullptr) {
ImGui::BeginGroup();
ImGui::Text("ID: %hd", display->id);
ImGui::Text("Description: %s", GetActorDescription(display->id).c_str());
ImGui::Text("Category: %s", acMapping[display->category]);
ImGui::Text("Params: %hd", display->params);
ImGui::EndGroup();
ImGui::BeginGroup();
if (preventActorDrawHookId) {
if (ImGui::Button("Continue Drawing", ImVec2(ImGui::GetFontSize() * 10, 0))) {
GameInteractor::Instance->UnregisterGameHookForPtr<GameInteractor::ShouldActorDraw>(
preventActorDrawHookId);
preventActorDrawHookId = 0;
}
} else {
if (ImGui::Button("Stop Drawing", ImVec2(ImGui::GetFontSize() * 10, 0))) {
preventActorDrawHookId =
GameInteractor::Instance->RegisterGameHookForPtr<GameInteractor::ShouldActorDraw>(
(uintptr_t)display, [](Actor* _, bool* result) { *result = false; });
}
}
ImGui::SameLine();
if (preventActorUpdateHookId) {
if (ImGui::Button("Continue Updating", ImVec2(ImGui::GetFontSize() * 10, 0))) {
GameInteractor::Instance->UnregisterGameHookForPtr<GameInteractor::ShouldActorUpdate>(
preventActorUpdateHookId);
preventActorUpdateHookId = 0;
}
} else {
if (ImGui::Button("Stop Updating", ImVec2(ImGui::GetFontSize() * 10, 0))) {
preventActorUpdateHookId =
GameInteractor::Instance->RegisterGameHookForPtr<GameInteractor::ShouldActorUpdate>(
(uintptr_t)display, [](Actor* _, bool* result) { *result = false; });
}
}
ImGui::EndGroup();
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
ImGui::BeginGroup();
ImGui::Text("Actor Position");
ImGui::InputScalar("x", ImGuiDataType_Float, &display->world.pos.x);
ImGui::SameLine();
ImGui::InputScalar("y", ImGuiDataType_Float, &display->world.pos.y);
ImGui::SameLine();
ImGui::InputScalar("z", ImGuiDataType_Float, &display->world.pos.z);
ImGui::EndGroup();
ImGui::BeginGroup();
ImGui::Text("Actor Rotation");
ImGui::InputScalar("rx", ImGuiDataType_S16, &display->world.rot.x);
ImGui::SameLine();
ImGui::InputScalar("ry", ImGuiDataType_S16, &display->world.rot.y);
ImGui::SameLine();
ImGui::InputScalar("rz", ImGuiDataType_S16, &display->world.rot.z);
ImGui::EndGroup();
ImGui::PopItemWidth();
ImGui::PushItemWidth(ImGui::GetFontSize() * 5);
if ((display->category == ACTORCAT_BOSS || display->category == ACTORCAT_ENEMY) &&
display->colChkInfo.health > 0) {
ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display->colChkInfo.health);
}
ImGui::PopItemWidth();
ImGui::BeginGroup();
ImGui::Text("Flags");
UIWidgets::DrawFlagArray32("flags", display->flags);
ImGui::EndGroup();
ImGui::BeginGroup();
ImGui::Text("BG Check");
UIWidgets::DrawFlagArray16("bgCheckFlags", display->bgCheckFlags);
ImGui::EndGroup();
}
if (UIWidgets::Button("Refresh")) {
list = GetCurrentSceneActors();
display = list[newActorId];
}
if (UIWidgets::Button("Go to Actor")) {
Player* player = GET_PLAYER(gPlayState);
if (display != nullptr) {
Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos);
Math_Vec3f_Copy(&player->actor.home.pos, &display->world.pos);
}
}
if (UIWidgets::Button("Fetch: Target", { .tooltip = "Grabs actor with target arrow above it." })) {
Player* player = GET_PLAYER(gPlayState);
fetch = player->lockOnActor;
if (fetch != nullptr) {
display = fetch;
category = fetch->category;
list = GetCurrentSceneActors();
method = TARGET;
} else {
display = {};
}
}
if (UIWidgets::Button("Fetch: Held", { .tooltip = "Grabs actor Link is currently holding." })) {
Player* player = GET_PLAYER(gPlayState);
fetch = player->heldActor;
if (fetch != nullptr) {
display = fetch;
category = fetch->category;
list = GetCurrentSceneActors();
method = HOLD;
} else {
display = {};
}
}
if (UIWidgets::Button("Kill", { .color = UIWidgets::Colors::Red }) && display != nullptr &&
display->id != ACTOR_PLAYER) {
Actor_Kill(display);
}
ImGui::TreePop();
}
if (ImGui::TreeNode("New...")) {
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
ImU16 one = 1;
ImGui::Text("%s", GetActorDescription(newActor.id).c_str());
ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one);
ImGui::InputScalar("Params", ImGuiDataType_S16, &newActor.params, &one);
ImGui::BeginGroup();
ImGui::Text("New Actor Position");
ImGui::InputScalar("x", ImGuiDataType_Float, &newActor.pos.x);
ImGui::SameLine();
ImGui::InputScalar("y", ImGuiDataType_Float, &newActor.pos.y);
ImGui::SameLine();
ImGui::InputScalar("z", ImGuiDataType_Float, &newActor.pos.z);
ImGui::EndGroup();
ImGui::BeginGroup();
ImGui::Text("New Actor Rotation");
ImGui::InputScalar("rX", ImGuiDataType_S16, &newActor.rot.x);
ImGui::SameLine();
ImGui::InputScalar("rY", ImGuiDataType_S16, &newActor.rot.y);
ImGui::SameLine();
ImGui::InputScalar("rZ", ImGuiDataType_S16, &newActor.rot.z);
ImGui::EndGroup();
UIWidgets::CVarCheckbox("Remove Obj Dep?", "gObjDep",
{ .tooltip = "Allows actors to spawn where/when they normally wouldn't." });
if (UIWidgets::Button("Fetch from Link")) {
Player* player = GET_PLAYER(gPlayState);
newActor.pos = player->actor.world.pos;
newActor.rot = player->actor.world.rot;
}
if (UIWidgets::Button("Spawn", { .color = UIWidgets::Colors::Green })) {
Actor_Spawn(&gPlayState->actorCtx, gPlayState, newActor.id, newActor.pos.x, newActor.pos.y,
newActor.pos.z, newActor.rot.x, newActor.rot.y, newActor.rot.z, newActor.params);
}
if (UIWidgets::Button("Spawn as Child", { .color = UIWidgets::Colors::Green })) {
Actor* parent = display;
if (parent != nullptr) {
Actor_SpawnAsChild(&gPlayState->actorCtx, parent, gPlayState, newActor.id, newActor.pos.x,
newActor.pos.y, newActor.pos.z, newActor.rot.x, newActor.rot.y, newActor.rot.z,
newActor.params);
} else {
Audio_PlaySfx(NA_SE_SY_ERROR);
}
}
if (UIWidgets::Button("Reset")) {
newActor = {};
}
ImGui::TreePop();
}
} else {
ImGui::Text("Playstate needed for actors!");
}
ImGui::End();
}
void ActorViewerWindow::InitElement() {
}