Fix catalog actor index

This commit is contained in:
Christian Semmler 2026-03-27 16:42:44 -07:00
parent f92967735f
commit 2bdbb594da
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
5 changed files with 16 additions and 28 deletions

View File

@ -191,7 +191,7 @@ struct AnimStartMsg {
// Per-participant data in AnimCompleteMsg
struct AnimCompletionParticipant {
uint32_t peerId;
int8_t charIndex; // Participant's character (g_characters index)
int8_t charIndex; // Participant's character (g_actorInfoInit index)
char displayName[8]; // 7 chars + null
};

View File

@ -1,25 +1,23 @@
#include "extensions/multiplayer/animation/catalog.h"
#include "decomp.h"
#include "legoactors.h"
#include "legoanimationmanager.h"
#include "legocharactermanager.h"
#include "misc.h"
#include <SDL3/SDL_stdinc.h>
using namespace Multiplayer::Animation;
// Defined in legoanimationmanager.cpp
extern LegoAnimationManager::Character g_characters[47];
// Exact-match a model name against g_characters[].m_name.
// Exact-match a model name against g_actorInfoInit[].m_name.
// The engine's LegoAnimationManager::GetCharacterIndex uses 2-char prefix matching,
// which causes false positives (e.g. "ladder" matching "laura"). We need exact
// matching to correctly identify character performers vs props.
// Capped at 64 because performerMask is uint64_t.
static int8_t GetCharacterIndex(const char* p_name)
{
for (int8_t i = 0; i < (int8_t) sizeOfArray(g_characters); i++) {
if (!SDL_strcasecmp(p_name, g_characters[i].m_name)) {
for (int8_t i = 0; i < (int8_t) SDL_min(sizeOfArray(g_actorInfoInit), (size_t) 64); i++) {
if (!SDL_strcasecmp(p_name, g_actorInfoInit[i].m_name)) {
return i;
}
}
@ -77,7 +75,7 @@ void Catalog::Refresh(LegoAnimationManager* p_am)
entry.category = e_camAnim;
}
// Compute performerMask by matching models against g_characters[].m_name
// Compute performerMask by matching models against g_actorInfoInit[].m_name
entry.performerMask = 0;
for (uint8_t m = 0; m < entry.modelCount; m++) {
if (m_animsBase[i].m_models && m_animsBase[i].m_models[m].m_name) {
@ -107,12 +105,10 @@ const AnimInfo* Catalog::GetAnimInfo(uint16_t p_animIndex) const
int8_t Catalog::DisplayActorToCharacterIndex(uint8_t p_displayActorIndex)
{
const char* actorName = CharacterManager()->GetActorName(p_displayActorIndex);
if (!actorName) {
if (p_displayActorIndex >= SDL_min(sizeOfArray(g_actorInfoInit), (size_t) 64)) {
return -1;
}
return GetCharacterIndex(actorName);
return static_cast<int8_t>(p_displayActorIndex);
}
const CatalogEntry* Catalog::FindEntry(uint16_t p_animIndex) const

View File

@ -1,15 +1,12 @@
#include "extensions/multiplayer/animation/coordinator.h"
#include "extensions/multiplayer/animation/catalog.h"
#include "legoanimationmanager.h"
#include "legoactors.h"
#include <SDL3/SDL_timer.h>
using namespace Multiplayer::Animation;
// Defined in legoanimationmanager.cpp
extern LegoAnimationManager::Character g_characters[47];
Coordinator::Coordinator()
: m_catalog(nullptr), m_state(CoordinationState::e_idle), m_currentAnimIndex(ANIM_INDEX_NONE), m_localPeerId(0),
m_cancelPending(false)
@ -59,8 +56,8 @@ static void BuildSlots(
// One slot per performer bit in performerMask
for (int8_t i : GetPerformerIndices(p_entry->performerMask)) {
SlotInfo slot;
if (i < (int8_t) sizeOfArray(g_characters)) {
slot.names.push_back(g_characters[i].m_name);
if (i < (int8_t) sizeOfArray(g_actorInfoInit)) {
slot.names.push_back(g_actorInfoInit[i].m_name);
}
slot.filled = (p_filledPerformers & (uint64_t(1) << i)) != 0;
p_slots.push_back(std::move(slot));
@ -74,7 +71,7 @@ static void BuildSlots(
else {
for (int8_t i = 0; i < CORE_CHARACTER_COUNT; i++) {
if ((p_entry->spectatorMask >> i) & 1) {
spectatorSlot.names.push_back(g_characters[i].m_name);
spectatorSlot.names.push_back(g_actorInfoInit[i].m_name);
}
}
}

View File

@ -4,6 +4,7 @@
#include "anim/legoanim.h"
#include "extensions/common/animutils.h"
#include "extensions/common/charactercloner.h"
#include "legoactors.h"
#include "legoanimationmanager.h"
#include "legocameracontroller.h"
#include "legocharactermanager.h"
@ -28,9 +29,6 @@ using namespace Multiplayer::Animation;
namespace AnimUtils = Extensions::Common::AnimUtils;
using Extensions::Common::CharacterCloner;
// Defined in legoanimationmanager.cpp
extern LegoAnimationManager::Character g_characters[47];
enum VehicleCategory {
e_bike,
e_motorcycle,
@ -54,10 +52,10 @@ static VehicleCategory GetVehicleCategory(MxU32 p_vehicleIdx)
static bool MatchesCharacter(const std::string& p_actorName, int8_t p_charIndex)
{
if (p_charIndex < 0 || p_charIndex >= (int8_t) sizeOfArray(g_characters)) {
if (p_charIndex < 0 || p_charIndex >= (int8_t) sizeOfArray(g_actorInfoInit)) {
return false;
}
return !SDL_strcasecmp(p_actorName.c_str(), g_characters[p_charIndex].m_name);
return !SDL_strcasecmp(p_actorName.c_str(), g_actorInfoInit[p_charIndex].m_name);
}
ScenePlayer::ScenePlayer()

View File

@ -33,9 +33,6 @@ using Common::IsMultiPartEmote;
using Common::IsRestrictedArea;
using Common::WORLD_NOT_VISIBLE;
// Defined in legoanimationmanager.cpp
extern LegoAnimationManager::Character g_characters[47];
// Slightly larger than NPC_ANIM_PROXIMITY to catch transitions
static constexpr float NPC_ANIM_NEARBY_RADIUS_SQ =
(Animation::NPC_ANIM_PROXIMITY + 5.0f) * (Animation::NPC_ANIM_PROXIMITY + 5.0f);