Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions mm/2s2h/BenPort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,47 @@ extern "C" int ResourceMgr_OTRSigCheck(char* imgData) {
return 0;
}

// Load animation with explicit alt asset path checking.
// When Alt Assets is OFF: use original path directly (O2R or vanilla)
// When Alt Assets is ON: try alt/ prefix first, fall back to regular path if not found or invalid
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 (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;
PlayerAnimationHeader* playerAnim = (PlayerAnimationHeader*)animHeader;

// Valid if Normal animation has frameData OR Link animation has segment
if (normalAnim->frameData != NULL || playerAnim->segmentVoid != NULL) {
return animHeader;
}
}
// Alt loaded but is invalid (broken), fall through to original path
}

// Fall back to original path
return (AnimationHeaderCommon*)ResourceGetDataByName(path);
}

// Alt OFF: use original path directly
return (AnimationHeaderCommon*)ResourceGetDataByName(path);
}

Expand Down
22 changes: 20 additions & 2 deletions mm/2s2h/resource/importer/AnimationFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,33 @@ ResourceFactoryBinaryAnimationV0::ReadResource(std::shared_ptr<Ship::File> file,
}
animation->animationData.transformUpdateIndex.copyValues = animation->copyValuesArr.data();
} else if (animType == AnimationType::Link) {
// Initialize segment to nullptr (important for alt asset fallback)
animation->animationData.linkAnimationHeader.segment = nullptr;

// Read the frame count
animation->animationData.linkAnimationHeader.common.frameCount = reader->ReadInt16();

// Read the segment pointer (always 32 bit, doesn't adjust for system pointer size)
std::string path = reader->ReadString();
const auto animData = std::static_pointer_cast<Animation>(
auto animData = std::static_pointer_cast<Animation>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(path.c_str()));

animation->animationData.linkAnimationHeader.segment = animData->GetPointer();
// If direct load failed and alt assets are enabled, try with alt/ prefix
if (animData == nullptr && Ship::Context::GetInstance()->GetResourceManager()->IsAltAssetsEnabled()) {
std::string altPath = path;
if (altPath.find("__OTR__") == 0) {
altPath = altPath.substr(7); // Strip __OTR__
}
altPath = "alt/" + altPath;
animData = std::static_pointer_cast<Animation>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(altPath.c_str()));
}

if (animData != nullptr) {
animation->animationData.linkAnimationHeader.segment = animData->GetPointer();
} else {
SPDLOG_WARN("Animation data segment not found: {}", path);
}
} else if (animType == AnimationType::Legacy) {
SPDLOG_DEBUG("BEYTAH ANIMATION?!");
}
Expand Down
4 changes: 4 additions & 0 deletions mm/src/code/z_skelanime.c
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,10 @@ void AnimTaskQueue_AddLoadPlayerFrame(PlayState* play, PlayerAnimationHeader* an
if (frame < 0) {
frame = 0;
}
// 2S2H [Alt Assets] Check if animData is null (can happen if animation data segment failed to load)
if (animData == NULL) {
return;
}
memcpy(ram, (uintptr_t)animData + (((sizeof(Vec3s) * limbCount + 2) * frame)), sizeof(Vec3s) * limbCount + 2);
}
}
Expand Down
Loading