diff options
| author | Jameriquiah <42100286+Jameriquiah@users.noreply.github.com> | 2026-06-21 16:46:47 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-06-21 21:46:47 +0000 |
| commit | 6a51720194a6ffca9d059c60bfe0b48debd45d05 (patch) | |
| tree | 0d3e353c2437b734cb0e8e97c20f684524a10557 | |
| parent | e4b6f1ab87040f3ce7eb8c02c103c9a642364d1e (diff) | |
Custom Hand DL's for each tunic take 3 (#6754)
| -rw-r--r-- | soh/assets/objects/object_custom_equip/object_custom_equip.h | 12 | ||||
| -rw-r--r-- | soh/soh/Enhancements/customequipment.cpp | 21 | ||||
| -rw-r--r-- | soh/soh/ResourceManagerHelpers.cpp | 64 |
3 files changed, 97 insertions, 0 deletions
diff --git a/soh/assets/objects/object_custom_equip/object_custom_equip.h b/soh/assets/objects/object_custom_equip/object_custom_equip.h index dd4cfb1f7..f86061a9a 100644 --- a/soh/assets/objects/object_custom_equip/object_custom_equip.h +++ b/soh/assets/objects/object_custom_equip/object_custom_equip.h @@ -128,9 +128,21 @@ static const ALIGN_ASSET(2) char gCustomMirrorShieldOnBackDL[] = dgCustomMirrorS #define dgCustomAdultFPSHandDL "__OTR__objects/object_custom_equip/gCustomAdultFPSHandDL" static const ALIGN_ASSET(2) char gCustomAdultFPSHandDL[] = dgCustomAdultFPSHandDL; +#define dgCustomAdultGoronFPSHandDL "__OTR__objects/object_custom_equip/gCustomAdultGoronFPSHandDL" +static const ALIGN_ASSET(2) char gCustomAdultGoronFPSHandDL[] = dgCustomAdultGoronFPSHandDL; + +#define dgCustomAdultZoraFPSHandDL "__OTR__objects/object_custom_equip/gCustomAdultZoraFPSHandDL" +static const ALIGN_ASSET(2) char gCustomAdultZoraFPSHandDL[] = dgCustomAdultZoraFPSHandDL; + #define dgCustomChildFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildFPSHandDL" static const ALIGN_ASSET(2) char gCustomChildFPSHandDL[] = dgCustomChildFPSHandDL; +#define dgCustomChildGoronFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildGoronFPSHandDL" +static const ALIGN_ASSET(2) char gCustomChildGoronFPSHandDL[] = dgCustomChildGoronFPSHandDL; + +#define dgCustomChildZoraFPSHandDL "__OTR__objects/object_custom_equip/gCustomChildZoraFPSHandDL" +static const ALIGN_ASSET(2) char gCustomChildZoraFPSHandDL[] = dgCustomChildZoraFPSHandDL; + #endif // OBJECTS_OBJECT_CUSTOM_EQUIP_H diff --git a/soh/soh/Enhancements/customequipment.cpp b/soh/soh/Enhancements/customequipment.cpp index 282bccc2e..4038c5bc8 100644 --- a/soh/soh/Enhancements/customequipment.cpp +++ b/soh/soh/Enhancements/customequipment.cpp @@ -25,6 +25,26 @@ static const char* ResolveCustomChain(std::initializer_list<const char*> paths) return fallback; } +static const char* ResolveCustomFPSHand(const char* path) { + const bool isAdult = path == gCustomAdultFPSHandDL; + const bool isChild = path == gCustomChildFPSHandDL; + + if (!isAdult && !isChild) { + return path; + } + + switch (TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC))) { + case PLAYER_TUNIC_GORON: + return ResolveCustomChain( + { isAdult ? gCustomAdultGoronFPSHandDL : gCustomChildGoronFPSHandDL, path, nullptr }); + case PLAYER_TUNIC_ZORA: + return ResolveCustomChain( + { isAdult ? gCustomAdultZoraFPSHandDL : gCustomChildZoraFPSHandDL, path, nullptr }); + default: + return path; + } +} + static Gfx* LoadGfxByName(const char* path) { return path ? ResourceMgr_LoadGfxByName(path) : nullptr; } @@ -32,6 +52,7 @@ static Gfx* LoadGfxByName(const char* path) { static Gfx* LoadCustomGfx(const char* path) { if (!path) return nullptr; + path = ResolveCustomFPSHand(path); if (!ResourceGetIsCustomByName(path) && !ResourceMgr_FileAltExists(path)) return nullptr; return ResourceMgr_LoadGfxByName(path); diff --git a/soh/soh/ResourceManagerHelpers.cpp b/soh/soh/ResourceManagerHelpers.cpp index 618ac98f6..0d745dd08 100644 --- a/soh/soh/ResourceManagerHelpers.cpp +++ b/soh/soh/ResourceManagerHelpers.cpp @@ -2,6 +2,7 @@ #include "OTRGlobals.h" #include "variables.h" #include "z64.h" +#include "macros.h" #include "cvar_prefixes.h" #include "Enhancements/enhancementTypes.h" #include "Enhancements/randomizer/dungeon.h" @@ -20,6 +21,68 @@ extern "C" PlayState* gPlayState; +struct LinkTunicDListCacheKey { + size_t operator()(const std::pair<std::string, const char*>& key) const { + return std::hash<std::string>{}(key.first) ^ std::hash<const char*>{}(key.second); + } +}; + +static const char* ResourceMgr_ResolveLinkTunicDListPath(const char* path) { + if (path == nullptr) { + return nullptr; + } + + const char* originalPath = path; + constexpr std::string_view adultPrefix = "__OTR__objects/object_link_boy/"; + constexpr std::string_view childPrefix = "__OTR__objects/object_link_child/"; + + std::string_view objectPrefix; + const char* objectFolder; + + if (std::string_view(originalPath).starts_with(adultPrefix)) { + objectPrefix = adultPrefix; + objectFolder = "object_link_boy"; + } else if (std::string_view(originalPath).starts_with(childPrefix)) { + objectPrefix = childPrefix; + objectFolder = "object_link_child"; + } else { + return path; + } + + const char* tunicSuffix = nullptr; + switch (TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC))) { + case PLAYER_TUNIC_KOKIRI: + tunicSuffix = "kokiri"; + break; + case PLAYER_TUNIC_GORON: + tunicSuffix = "goron"; + break; + case PLAYER_TUNIC_ZORA: + tunicSuffix = "zora"; + break; + default: + return path; + } + + static std::unordered_map<std::pair<std::string, const char*>, std::string, LinkTunicDListCacheKey> + sResolvedLinkTunicDListPaths; + std::pair<std::string, const char*> cacheKey{ originalPath, tunicSuffix }; + if (auto it = sResolvedLinkTunicDListPaths.find(cacheKey); it != sResolvedLinkTunicDListPaths.end()) { + return it->second.c_str(); + } + + const std::string candidate = + fmt::format("__OTR__objects/{}_{}/{}", objectFolder, tunicSuffix, originalPath + objectPrefix.size()); + + if (!ResourceGetIsCustomByName(candidate.c_str()) && !ResourceMgr_FileExists(candidate.c_str()) && + !(ResourceMgr_IsAltAssetsEnabled() && ResourceMgr_FileAltExists(candidate.c_str()))) { + return path; + } + + auto it = sResolvedLinkTunicDListPaths.emplace(std::move(cacheKey), candidate).first; + return it->second.c_str(); +} + extern "C" uint32_t ResourceMgr_GetNumGameVersions() { return static_cast<u32>( Ship::Context::GetRawInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions().size()); @@ -307,6 +370,7 @@ extern "C" void ResourceMgr_PushCurrentDirectory(char* path) { } extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) { + path = ResourceMgr_ResolveLinkTunicDListPath(path); // When an alt resource exists for the DL, we need to unload the original asset // to clear the cache so the alt asset will be loaded instead // OTRTODO: If Alt loading over original cache is fixed, this line can most likely be removed |
