From 41bcad78a3068e8ff8d0bbccb0f2d43967831f69 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Wed, 12 Oct 2022 16:20:13 -0500 Subject: [PATCH] Support for patching DLists outside of OTR (#1696) * Support for patching DLists outside of OTR, mostly for cosmetics and bug fixes * Store original dlist instruction for unpatching * Rename sandstorm patch variable * Use unordered map for originalGfx; --- soh/soh/OTRGlobals.cpp | 49 ++++++++++++++++++++++++++++++++++++++--- soh/soh/OTRGlobals.h | 3 ++- soh/src/code/z_kankyo.c | 36 ++++++++++++------------------ 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index b1e248e0e..d2986892a 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -701,11 +701,54 @@ extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) return (Gfx*)&res->instructions[0]; } -extern "C" Gfx* ResourceMgr_PatchGfxByName(const char* path, int size) { +typedef struct { + int index; + Gfx instruction; +} GfxPatch; + +std::unordered_map> originalGfx; + +// Attention! This is primarily for cosmetics & bug fixes. For things like mods and model replacement you should be using OTRs +// instead (When that is available). Index can be found using the commented out section below. +extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction) { auto res = std::static_pointer_cast( OTRGlobals::Instance->context->GetResourceManager()->LoadResource(path)); - res->instructions.resize(res->instructions.size() + size); - return (Gfx*)&res->instructions[0]; + + // Leaving this here for people attempting to find the correct Dlist index to patch + /*if (strcmp("__OTR__objects/object_gi_longsword/gGiBiggoronSwordDL", path) == 0) { + for (int i = 0; i < res->instructions.size(); i++) { + Gfx* gfx = (Gfx*)&res->instructions[i]; + // Log all commands + // SPDLOG_INFO("index:{} command:{}", i, gfx->words.w0 >> 24); + // Log only SetPrimColors + if (gfx->words.w0 >> 24 == 250) { + SPDLOG_INFO("index:{} r:{} g:{} b:{} a:{}", i, _SHIFTR(gfx->words.w1, 24, 8), _SHIFTR(gfx->words.w1, 16, 8), _SHIFTR(gfx->words.w1, 8, 8), _SHIFTR(gfx->words.w1, 0, 8)); + } + } + }*/ + + Gfx* gfx = (Gfx*)&res->instructions[index]; + + if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) { + originalGfx[path][patchName] = { + index, + *gfx + }; + } + + *gfx = instruction; +} + +extern "C" void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName) { + if (originalGfx.contains(path) && originalGfx[path].contains(patchName)) { + auto res = std::static_pointer_cast( + OTRGlobals::Instance->context->GetResourceManager()->LoadResource(path)); + + Gfx* gfx = (Gfx*)&res->instructions[originalGfx[path][patchName].index]; + *gfx = originalGfx[path][patchName].instruction; + + originalGfx[path].erase(patchName); + } } extern "C" char* ResourceMgr_LoadArrayByName(const char* path) diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 0d3f24d58..6f4715b8c 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -60,7 +60,8 @@ AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path); char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc); Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc); Gfx* ResourceMgr_LoadGfxByName(const char* path); -Gfx* ResourceMgr_PatchGfxByName(const char* path, int size); +void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction); +void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path); Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc); diff --git a/soh/src/code/z_kankyo.c b/soh/src/code/z_kankyo.c index 540e58a76..b1144d966 100644 --- a/soh/src/code/z_kankyo.c +++ b/soh/src/code/z_kankyo.c @@ -2290,27 +2290,22 @@ Color_RGB8 sSandstormEnvColors[] = { { 50, 40, 0 }, }; -Gfx* gFieldSandstormDL_Custom = NULL; +u16 previousPatchedSandstormScreenSize = 0; void Environment_PatchSandstorm(GlobalContext* globalCtx) { - if (gFieldSandstormDL_Custom) return; - - gFieldSandstormDL_Custom = ResourceMgr_PatchGfxByName(gFieldSandstormDL, -3); - - const Gfx gFSPatchDL[2] = { gsSPEndDisplayList() }; - bool patched = false; - Gfx* cmd = gFieldSandstormDL_Custom; - int id = 0; - - while (!patched) { - const uint32_t opcode = cmd->words.w0 >> 24; - if (opcode == G_TEXRECT) { - gFieldSandstormDL_Custom[id] = gFSPatchDL[0]; - patched = true; - } - ++cmd; - id++; + if (previousPatchedSandstormScreenSize == ABS(OTRGetRectDimensionFromLeftEdge(0)) + ABS(OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH))) { + return; } + + Gfx gfxPatchSandstormRect[] = { + gsSPWideTextureRectangle(OTRGetRectDimensionFromLeftEdge(0) << 2, 0, + OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH) << 2, 0x03C0, G_TX_RENDERTILE, 0, 0, 0x008C, -0x008C), + }; + ResourceMgr_PatchGfxByName(gFieldSandstormDL, "gfxPatchSandstormRect0", 48, gfxPatchSandstormRect[0]); + ResourceMgr_PatchGfxByName(gFieldSandstormDL, "gfxPatchSandstormRect1", 50, gfxPatchSandstormRect[1]); + ResourceMgr_PatchGfxByName(gFieldSandstormDL, "gfxPatchSandstormRect2", 52, gfxPatchSandstormRect[2]); + + previousPatchedSandstormScreenSize = ABS(OTRGetRectDimensionFromLeftEdge(0)) + ABS(OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH)); } void Environment_DrawSandstorm(GlobalContext* globalCtx, u8 sandstormState) { @@ -2435,10 +2430,7 @@ void Environment_DrawSandstorm(GlobalContext* globalCtx, u8 sandstormState) { 0xFFF - ((u32)sp92 % 0x1000), 0x100, 0x40)); gDPSetTextureLUT(POLY_XLU_DISP++, G_TT_NONE); - gSPDisplayList(POLY_XLU_DISP++, gFieldSandstormDL_Custom); - gSPWideTextureRectangle(POLY_XLU_DISP++, OTRGetRectDimensionFromLeftEdge(0) << 2, 0, - OTRGetRectDimensionFromRightEdge(SCREEN_WIDTH) << 2, 0x03C0, G_TX_RENDERTILE, 0, 0, 0x008C, - -0x008C); + gSPDisplayList(POLY_XLU_DISP++, gFieldSandstormDL); CLOSE_DISPS(globalCtx->state.gfxCtx); D_8015FDB0 += (s32)sp98;