Reclassify animations based on performer mask instead of character index

The engine derives characterIndex from the last 2 chars of the animation
filename, which misses animations with suffixes like "in" (infoman), "p1",
"sl". These were incorrectly categorized as e_otherAnim and hidden from
multiplayer despite having valid named character performers.

Categorize based on whether the animation has at least one named character
in its performer mask (g_actorInfoInit indices 0-47 + 54-57) instead of
requiring characterIndex >= 0. This adds 23 animations to the catalog.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Christian Semmler 2026-03-27 17:50:44 -07:00
parent 2bdbb594da
commit 734623cdd7
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
2 changed files with 22 additions and 14 deletions

View File

@ -11,9 +11,9 @@ namespace Multiplayer::Animation
{ {
enum AnimCategory : uint8_t { enum AnimCategory : uint8_t {
e_npcAnim, // characterIndex >= 0 && location == -1 e_npcAnim, // has named character performer && location == -1
e_camAnim, // characterIndex >= 0 && location >= 0 e_camAnim, // has named character performer && location >= 0
e_otherAnim // characterIndex < 0 (ambient, non-character) e_otherAnim // no named character performers (ambient/prop-only)
}; };
// Number of core playable characters (Pepper, Mama, Papa, Nick, Laura) = g_characters indices 0-4 // Number of core playable characters (Pepper, Mama, Papa, Nick, Laura) = g_characters indices 0-4

View File

@ -65,16 +65,6 @@ void Catalog::Refresh(LegoAnimationManager* p_am)
entry.characterIndex = m_animsBase[i].m_characterIndex; entry.characterIndex = m_animsBase[i].m_characterIndex;
entry.modelCount = m_animsBase[i].m_modelCount; entry.modelCount = m_animsBase[i].m_modelCount;
if (entry.characterIndex < 0) {
entry.category = e_otherAnim;
}
else if (entry.location == -1) {
entry.category = e_npcAnim;
}
else {
entry.category = e_camAnim;
}
// Compute performerMask by matching models against g_actorInfoInit[].m_name // Compute performerMask by matching models against g_actorInfoInit[].m_name
entry.performerMask = 0; entry.performerMask = 0;
for (uint8_t m = 0; m < entry.modelCount; m++) { for (uint8_t m = 0; m < entry.modelCount; m++) {
@ -86,13 +76,31 @@ void Catalog::Refresh(LegoAnimationManager* p_am)
} }
} }
// Categorize based on whether the animation has named character performers.
// g_actorInfoInit layout:
// 0-47: named characters (pepper through jk)
// 48-53: ghosts
// 54-57: named characters (hg, pntgy, pep, cop01)
// 58-65: generic extras (actor_01-05, vehicle riders)
static const uint64_t NAMED_CHARACTER_MASK = ((uint64_t(1) << 48) - 1) | (uint64_t(0xF) << 54);
bool hasNamedPerformer = (entry.performerMask & NAMED_CHARACTER_MASK) != 0;
if (!hasNamedPerformer) {
entry.category = e_otherAnim;
}
else if (entry.location == -1) {
entry.category = e_npcAnim;
}
else {
entry.category = e_camAnim;
}
size_t idx = m_entries.size(); size_t idx = m_entries.size();
m_entries.push_back(entry); m_entries.push_back(entry);
// Build location index // Build location index
m_locationIndex[entry.location].push_back(idx); m_locationIndex[entry.location].push_back(idx);
} }
} }
const AnimInfo* Catalog::GetAnimInfo(uint16_t p_animIndex) const const AnimInfo* Catalog::GetAnimInfo(uint16_t p_animIndex) const