1 Cache + Fix logical errors (#6862)

So this fixes some logical errors with loading the resources so its checking they exist before trying to test-load them... It also added a cache for the alt skeleton by tunic type so we arent constantly trying to reassign the tunic (This change in particular may prevent instant model swapping depending how the model swap with custom content is handled if loaded in a menu like NEI does)... Current system was just spamming that check over and over and trying to reload skeletons constantly so I opted for detecting if the tunic actually changes THEN allow a recheck here, otherwise exit out early. The  skeleton.cpp and skeleton.h files can be reverted if suspected that will interfere with intended custom model usage.
This commit is contained in:
Amber Burton
2026-07-05 07:17:57 -04:00
committed by GitHub
parent 015440fdff
commit 3c48ccd705
4 changed files with 70 additions and 35 deletions
+1 -1
View File
@@ -54,7 +54,7 @@ static Gfx* LoadCustomGfx(const char* path) {
if (!path)
return nullptr;
path = ResolveCustomFPSHand(path);
if (!ResourceGetIsCustomByName(path) && !ResourceMgr_FileAltExists(path))
if (!ResourceMgr_FileAltExists(path) || !ResourceGetIsCustomByName(path))
return nullptr;
return ResourceMgr_LoadGfxByName(path);
}
+30 -27
View File
@@ -76,8 +76,8 @@ static const char* ResourceMgr_ResolveLinkTunicDListPath(const char* path) {
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()))) {
if (!ResourceMgr_IsAltAssetsEnabled() || !ResourceMgr_FileAltExists(candidate.c_str()) ||
!ResourceGetIsCustomByName(candidate.c_str())) {
return path;
}
@@ -602,33 +602,36 @@ extern "C" AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path) {
bool isAlt = ResourceMgr_IsAltAssetsEnabled();
if (isAlt) {
std::string pathStr = std::string(path);
static const std::string sOtr = "__OTR__";
if (ResourceMgr_FileAltExists(path)) {
std::string pathStr = std::string(path);
static const std::string sOtr = "__OTR__";
if (pathStr.starts_with(sOtr)) {
pathStr = pathStr.substr(sOtr.length());
}
// Try alt/ first
pathStr = Ship::IResource::gAltAssetPrefix + pathStr;
AnimationHeaderCommon* animHeader = (AnimationHeaderCommon*)ResourceGetDataByName(pathStr.c_str());
// If alt loaded successfully, verify it has valid data
if (animHeader != NULL) {
// Check for valid frame count (> 0)
if (animHeader->frameCount > 0) {
// For Normal animations: check frameData (comes after frameCount in AnimationHeader)
// For Link animations: check segment (comes after frameCount in LinkAnimationHeader)
// We check both to be safe - if either is valid, the animation is usable
AnimationHeader* normalAnim = (AnimationHeader*)animHeader;
LinkAnimationHeader* linkAnim = (LinkAnimationHeader*)animHeader;
// Valid if Normal animation has frameData OR Link animation has segment
if (normalAnim->frameData != NULL || linkAnim->segment != NULL) {
return animHeader;
}
if (pathStr.starts_with(sOtr)) {
pathStr = pathStr.substr(sOtr.length());
}
// Try alt/ first
pathStr = Ship::IResource::gAltAssetPrefix + pathStr;
AnimationHeaderCommon* animHeader = (AnimationHeaderCommon*)ResourceGetDataByName(pathStr.c_str());
// If alt loaded successfully, verify it has valid data
if (animHeader != NULL) {
// Check for valid frame count (> 0)
if (animHeader->frameCount > 0) {
// For Normal animations: check frameData (comes after frameCount in AnimationHeader)
// For Link animations: check segment (comes after frameCount in LinkAnimationHeader)
// We check both to be safe - if either is valid, the animation is usable
AnimationHeader* normalAnim = (AnimationHeader*)animHeader;
LinkAnimationHeader* linkAnim = (LinkAnimationHeader*)animHeader;
// Valid if Normal animation has frameData OR Link animation has segment
if (normalAnim->frameData != NULL || linkAnim->segment != NULL) {
return animHeader;
}
}
// Alt loaded but is invalid (broken), fall through to original path
}
// Alt loaded but is invalid (broken), fall through to original path
}
// Fall back to original path
+37 -7
View File
@@ -135,43 +135,73 @@ void SkeletonPatcher::UpdateCustomSkeletons() {
void SkeletonPatcher::UpdateTunicSkeletons(SkeletonPatchInfo& skel) {
std::string skeletonPath = "";
s32 tunicID = TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC));
s32 ageID = 0;
// Check if this is one of Link's skeletons
if (sOtr + skel.vanillaSkeletonPath == std::string(gLinkAdultSkel)) {
// Adult skeleton
ageID = 2;
} else if (sOtr + skel.vanillaSkeletonPath == std::string(gLinkChildSkel)) {
// Child skeleton
ageID = 1;
} else {
// Incompatible?
return;
}
// Check if we even need updating
s32 skelID = ageID << 4 | tunicID;
if (skelID == skel.lastSkeletonId)
return;
skel.lastSkeletonId = skelID;
// Check if this is one of Link's skeletons
if (ageID == 2) {
// Check what Link's current tunic is
switch (TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC))) {
switch (tunicID) {
case PLAYER_TUNIC_KOKIRI:
if (skel.lastSkeletonId == (ageID << 4 | PLAYER_TUNIC_KOKIRI))
return;
skeletonPath = std::string(gLinkAdultKokiriTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_GORON:
if (skel.lastSkeletonId == (ageID << 4 | PLAYER_TUNIC_GORON))
return;
skeletonPath = std::string(gLinkAdultGoronTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_ZORA:
if (skel.lastSkeletonId == (ageID << 4 | PLAYER_TUNIC_ZORA))
return;
skeletonPath = std::string(gLinkAdultZoraTunicSkel).substr(sOtr.length());
break;
default:
return;
}
UpdateCustomSkeletonFromPath(skeletonPath, skel);
} else if (sOtr + skel.vanillaSkeletonPath == std::string(gLinkChildSkel)) {
} else if (skelID == 1) {
// Check what Link's current tunic is
switch (TUNIC_EQUIP_TO_PLAYER(CUR_EQUIP_VALUE(EQUIP_TYPE_TUNIC))) {
switch (tunicID) {
case PLAYER_TUNIC_KOKIRI:
if (skel.lastSkeletonId == (ageID << 4 | PLAYER_TUNIC_KOKIRI))
return;
skeletonPath = std::string(gLinkChildKokiriTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_GORON:
if (skel.lastSkeletonId == (ageID << 4 | PLAYER_TUNIC_GORON))
return;
skeletonPath = std::string(gLinkChildGoronTunicSkel).substr(sOtr.length());
break;
case PLAYER_TUNIC_ZORA:
if (skel.lastSkeletonId == (ageID << 4 | PLAYER_TUNIC_ZORA))
return;
skeletonPath = std::string(gLinkChildZoraTunicSkel).substr(sOtr.length());
break;
default:
return;
}
UpdateCustomSkeletonFromPath(skeletonPath, skel);
}
UpdateCustomSkeletonFromPath(skeletonPath, skel);
}
void SkeletonPatcher::UpdateCustomSkeletonFromPath(const std::string& skeletonPath, SkeletonPatchInfo& skel) {
+2
View File
@@ -78,6 +78,8 @@ class Skeleton : public Ship::Resource<SkeletonData> {
struct SkeletonPatchInfo {
SkelAnime* skelAnime;
std::string vanillaSkeletonPath;
u8 lastSkeletonId;
bool isLocalPlayer;
};