isle-portable/LEGO1/lego/legoomni/include/legoanimationmanager.h
foxtacles 647bd28a07
Claude/npc animations local playback (#20)
* WIP: NPC animation local playback

Add NpcAnimCatalog and NpcAnimPlayer for playing NPC interaction
animations directly on player ROIs in multiplayer, bypassing the
singleplayer streaming pipeline.

- NpcAnimCatalog: reads animation entries from LegoAnimationManager
  with eligibility filtering per actor
- NpcAnimPlayer: minimal SI file reader (header + offset table only,
  then single MxSt read per object), extracts animation/audio/phoneme
  data from ISLE.SI composite objects
- Skeletal animation with position rebasing (absolute world coords
  converted to player-relative deltas)
- Audio via LegoCacheSound with proper WaveFormat parsing from SI
  chunks, wall-clock sync via SDL_GetTicks
- Phoneme lip sync with FLC decode, palette update, and proper
  texture restore on cleanup
- Movement lock via Controller::m_npcAnimPlaying flag
- Test trigger: emote 0 plays first eligible NPC animation

Still WIP: debug logging present, network sync not implemented,
needs testing with more animations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Fix NPC animation playback, props, crash safety, and movement lock

- Fix SI file reading: use declared offset count, handle RIFF word-alignment
  for odd-sized MxCh chunks, parse WaveFormat struct directly (not RIFF WAV)
- Fix animation type matching: use presenter name instead of MxOb::Type enum
  (skeletal anim is type Object=0x0B, phoneme is type Video=0x03)
- Fix animation positioning: compute full rigid-body rebase transform
  (savedTransform * inverse(animPose0)) so all motion, rotation, and extra
  actor positions are preserved relative to the player's current pose
- Add extra character support: use CharacterCloner::Clone for root-level
  characters (RHODA, RD, BD, PG), extend AssignROIIndices to match
  non-*-prefixed root-level nodes against extra ROIs
- Fix phoneme: update palette via SetEntries after FLC decode, restore
  original texture by passing saved pointer (not NULL), initialize
  filetype_/volume_ to avoid UBSan errors
- Fix sync: use SDL_GetTicks (wall-clock) instead of Timer()->GetTime()
  (game timer stalls during freezes), defer clock start to first Tick
- Fix crash on camera transition: add NPC anim stop callback in
  Controller::Deactivate and OnWorldDisabled (fires before ROI destruction)
- Block camera toggle and scroll/zoom disable during NPC animation
- Block player movement and camera-relative input during NPC animation
- Add StopNpcAnimation() public API on NetworkManager
- Add EnsureROIMapVisibility in Tick for prop visibility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Fix rebase for nested camera nodes, revert test to eligible[0]

Accumulate parent transforms when computing the player's animation-
space world pose at time 0. Fixes position offset for animations with
nested '-' nodes (e.g. -SBA001BU -> -TILT -> BU) where the local
transform alone didn't account for parent TILT offset.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Catalog filtering, prop LOD trimming, click anim blocking

- Split NpcAnimCatalog into NPC (location==-1) and cam (location>=0) buckets
- Filter by display actor's character index (not actorId)
- Eligibility: require all 5 main actor bits set (no counterpart for now)
- DisplayActorToCharacterIndex maps display actor -> g_characters index
- Trim trailing digits/underscores from prop LOD names matching original
  game's e_managedInvisibleRoiTrimmed logic (LETR12 -> letr)
- Handle *-prefixed non-actor root siblings as props via CreateAutoROI
- Block click animations during NPC animation playback (both local and
  remote player paths)
- Remove verbose per-entry catalog logging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Actor metadata ROI creation, vehicle reuse, AssignROIIndices fix

- Replace scanForCharacters heuristic with LegoAnimActorEntry metadata
  loop (GetNumActors/GetActorType/GetActorName) matching original game
- Player identified by animation name suffix, not tree position
- Handle all actor types: managed actors (2), trimmed props (3),
  exact props (4), scene ROIs (5/6), and scene actors (0/1)
- Vehicle ROI reuse: borrow existing ride vehicle ROI for type 0/1
  actors when CreateAutoROI fails, restore name on Stop
- Fix AssignROIIndices: check extras before claiming root to handle
  tree ordering (BIKESY before SY)
- Use GetRefCount(ROI*) for cleanup instead of name-based Exists()
- Block click animations during NPC anim playback
- Vehicle animation not yet fully working (known issue)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Fix vehicle animation, skip Controller tick during NPC anim

The ride animation and SyncTransformFromNative in Controller::Tick
were overwriting ROI transforms set by NpcAnimPlayer every frame.
Skip the entire ride animation path and non-vehicle character
animation path when m_npcAnimPlaying is true, so only NpcAnimPlayer
controls ROI positioning during NPC animations.

Also add comprehensive ROI map and tree assignment debug logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Move SI parsing from NpcAnimPlayer into libweaver

Replace ~300 lines of custom RIFF/MxOb/MxCh parsing in NpcAnimPlayer
with libweaver's new HeaderOnly read mode and slot-based ReadObject API.
This reuses ReadChunk's existing logic for the full MxSt->MxOb->MxCh
chain, eliminating code duplication.

Extract HD/CD path resolution into a shared ResolveGamePath utility
(extensions/common/pathutils), replacing the duplicated pattern in
NpcAnimPlayer, SiLoader, and TextureLoader.

Update libweaver to 17c7736 (HeaderOnly + ReadObject support).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Refactor animation playback into Multiplayer::Animation namespace

Split the monolithic NpcAnimPlayer and NpcAnimCatalog into five focused
components under extensions/multiplayer/animation/:

- Catalog: AnimInfo index with category enum, stores all animations
- Loader: SI file I/O, parsing, AnimData cache
- Controller: Play/Tick/Stop orchestrator, ROI creation, rebase matrix
- AudioPlayer: LegoCacheSound timed playback
- PhonemePlayer: FLC decoding, texture swap, lip sync

Also removes ~50 SDL_Log debug calls, renames all NpcAnim* references
to match the new structure, simplifies the camera animation callback
API, and documents AnimUtils divergences from the original game.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* DRY: Extract TrimLODSuffix helper and AnimData::ReleaseTracks

- controller.cpp: Extract repeated digit/underscore trimming loop into
  static TrimLODSuffix() (was duplicated 3 times in CreateExtraROIs)
- loader.cpp: Extract duplicated track cleanup loops into
  AnimData::ReleaseTracks() (was in both destructor and move-assignment)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Updates

* Clarify animation system separation with renames and DRY extractions

Rename Controller → ScenePlayer to distinguish multi-actor scene
animations from simple character poses. Rename AnimData → SceneAnimData
to avoid confusion with the character lookup tables. Rename
animdata.h/cpp → charactertables.h/cpp to reflect their actual content
(walk/idle/emote/vehicle tables).

Extract ApplyTree, TrimLODSuffix, and ResolvePropLODName into AnimUtils
to reduce duplication across CharacterAnimator and ScenePlayer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove dta.py accidentally committed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix CleanupProps corrupting global NPC actor state

ReleaseActor looks up g_actorInfo[] by ROI name, which for renamed
clones (e.g. "ma") matches the real global NPC and deletes its actor
entity. Since all props are independent clones (not obtained via
GetActorROI), use ReleaseAutoROI unconditionally — it performs
identical map/ROI cleanup without touching g_actorInfo[].

Also removes the redundant explicit Remove() call since ReleaseAutoROI
already calls RemoveROI() internally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Add animation catalog rework, location proximity, and coordinator

Prerequisite systems for cooperative animation reenactment feature:

- Catalog: expanded CatalogEntry with performerMask, spectatorMask,
  location index. Exact character matching (replaces engine's lossy
  2-char prefix). New CanTrigger() checks collective player eligibility
  (spectator + all performers, mutually exclusive roles).

- LocationProximity: 2D XZ distance to nearest g_locations entry,
  integrated into Tickle with OnNearestLocationChanged callback.
  Remote player locations derived from ROI positions.

- Coordinator: state machine (idle/interested/countdown/playing/completed),
  ComputeEligibility for frontend consumption (pre-filtered to local
  player's participable animations). Networking hooks are stubs.

- NetworkManager: location proximity + coordinator integration, atomic
  request pattern for anim interest/cancel, state resets on all
  transition paths (world disable, disconnect, reconnect, stop).

- Bridge: OnNearestLocationChanged callback (Emscripten + Native),
  mp_set_anim_interest / mp_cancel_anim_interest WASM exports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Add push-based animation state bridge and slot fill computation

Add OnAnimationsAvailable callback that pushes full animation eligibility
state (location, coordinator state, per-animation slot fill status) to
the frontend whenever relevant state changes. Uses a dirty flag system
with 250ms cooldown (bypassed for interest changes) to batch updates.

- Add CanTriggerDetailed to Catalog (refactor CanTrigger as wrapper)
- Enrich EligibilityInfo with SlotInfo vector and CatalogEntry pointer
- Add Coordinator::OnLocationChanged for auto-clearing stale interest
- Add dirty flag triggers at all 7 state change points in NetworkManager
- Build JSON payload with unified slots (performers + spectator)
- Remove OnNearestLocationChanged (superseded by push-based approach)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Ghastly

* WIP

* Fix animation session sync, camera-cancel, and state management bugs

- Add m_cancelPending to coordinator to prevent stale session re-enrollment
- Allow ClearInterest during countdown/playing for camera-cancel support
- Camera toggle now cancels animation in any active state instead of blocking
- Safety net: cancel animation when camera is disabled by any source
- Push idle JSON when camera unavailable so frontend clears countdown UI
- HandleCancel includes playing sessions and erases them (explicit cancel stops all)
- HandleAnimCancel/HandleAnimUpdate detect playing→idle to stop local scenes
- SendAnimUpdateToPlayer for targeted session sync to newly joined players
- HandleHostAssign: skip ResetAnimationState on initial assignment to avoid race
- IsPeerNearby helper for shared proximity checks
- HandleAnimInterest: evict far-away participants when session is full
- PushAnimationState: suppress session display when no participant is nearby
- World filter in UpdateRemotePlayers and PushAnimationState
- Set m_animStateDirty on camera change and remote player world change
- Use anyInIsle instead of anyNearby for continuous proximity-based push

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Clean up animation code: extract DRY helpers, remove debug logging

- Extract BuildAnimUpdateMsg() and ExtractSlotPeerIds() to deduplicate
  message-building logic in BroadcastAnimUpdate/SendAnimUpdateToPlayer
- Replace manual tree iteration in controller.cpp with AnimUtils::ApplyTree
- Remove all [Anim]/[SessionHost] SDL_Log debug calls and unused includes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: ScenePlayer multi-participant support and cam_anim playback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* WIP: Vehicle ROI support, alias-based ROI mapping, audio fix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Refactor animation infrastructure: remove dead code, DRY, tighten data

Remove all debug logging (~20 SDL_Log calls), dead fields (m_savedVehicleName,
m_debugFirstTickLogged, boundingRadius, centerPoint), dead methods
(RestoreVehicleROI, HasActiveSounds), and unused parameters (Tick's deltaTime).

Tighten data structures: replace raw m_propROIs array with vector, derive
isSpectator from charIndex via IsSpectator() method (SessionSlot,
ParticipantROI), group action transform fields into sub-struct, replace
vehicle category magic numbers with VehicleCategory enum.

Extract DRY helpers: addAlias/createProp lambdas in SetupROIs,
StopScenePlayback() in NetworkManager (5 call sites), combine dual slot
iteration into single loop in HandleAnimStartLocally. Simplify Play()
signature by removing redundant p_localROI/p_vehicleROI params.

Fix bug: HandleAnimCancel now unlocks remote player ROIs when stopping
during playback (was skipping unlock, leaving remotes permanently locked).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Async SI asset preloading during animation countdown

Preload animation data from isle.si on a background thread when the
countdown starts (4s window), so ScenePlayer::Play() finds the data
already cached and avoids a 500ms-1s main-thread stall.

Adds Loader::PreloadAsync() with a one-shot MxThread subclass that
opens its own si::File/Interleaf, parses the object, and inserts into
the cache under MxCriticalSection. EnsureCached() joins any in-progress
preload before falling back to synchronous load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Refactor animation system: fix dangling pointer, DRY extractions, correctness

- Fix dangling .c_str() in ScenePlayer::SetupROIs by using std::deque
  for aliasNames (vector reallocation invalidated stored pointers)
- Push idle JSON fallback when userActor is null in PushAnimationState
  instead of silently returning with stale frontend state
- Extract GetPerformerIndices() to eliminate 3 duplicate bit-iteration
  loops across coordinator.cpp and sessionhost.cpp
- Promote CheckSpectatorMask to public Catalog method, replacing
  inlined duplicate in sessionhost.cpp
- Extract Loader::OpenSIHeaderOnly() to consolidate duplicated SI file
  open/parse between OpenSI() and PreloadThread::Run()
- Extract IDLE_ANIM_STATE_JSON constant to avoid string duplication
- Clarify proximity radius distinction with comment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Observer mode: uninvolved players see animations play out locally

Non-participant players in the same world now see scene animations
(cam_anim, npc_anim) play out on the performing players' ROIs as an
ambient background scene. The observer's camera, movement, and vehicle
are completely unaffected.

Key changes:
- HandleAnimStartLocally always runs (not just for session participants)
- ScenePlayer gains observer mode: skips camera control, spectator
  hiding, and vehicle hiding
- Preload during countdown for all clients, not just participants
- Fix 1st person camera: skip display ROI check for observers (the
  display clone is destroyed in 1st person mode)
- Track m_playingAnimIndex for observer early-stop detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 22:40:15 +01:00

315 lines
9.4 KiB
C++

#ifndef LEGOANIMATIONMANAGER_H
#define LEGOANIMATIONMANAGER_H
#include "decomp.h"
#include "extensions/fwd.h"
#include "lego1_export.h"
#include "legolocations.h"
#include "legomain.h"
#include "legostate.h"
#include "legotraninfolist.h"
#include "mxcore.h"
#include "mxgeometry/mxquaternion.h"
class LegoAnimPresenter;
class LegoEntity;
class LegoExtraActor;
class LegoFile;
class LegoPathActor;
class LegoPathBoundary;
class LegoROIList;
struct LegoOrientedEdge;
class LegoWorld;
class MxDSAction;
// SIZE 0x30
struct ModelInfo {
char* m_name; // 0x00
MxU8 m_unk0x04; // 0x04
float m_location[3]; // 0x08
float m_direction[3]; // 0x14
float m_up[3]; // 0x20
MxU8 m_unk0x2c; // 0x2c
};
// SIZE 0x30
struct AnimInfo {
char* m_name; // 0x00
MxU32 m_objectId; // 0x04
MxS16 m_location; // 0x08
MxBool m_unk0x0a; // 0x0a
MxU8 m_unk0x0b; // 0x0b
MxU8 m_unk0x0c; // 0x0c
MxU8 m_unk0x0d; // 0x0d
float m_unk0x10[4]; // 0x10
MxU8 m_modelCount; // 0x20
MxU16 m_unk0x22; // 0x22
ModelInfo* m_models; // 0x24
MxS8 m_characterIndex; // 0x28
MxBool m_unk0x29; // 0x29
MxS8 m_unk0x2a[3]; // 0x2a
};
// VTABLE: LEGO1 0x100d8d80
// VTABLE: BETA10 0x101bae58
// SIZE 0x1c
class AnimState : public LegoState {
public:
AnimState();
~AnimState() override; // vtable+0x00
// FUNCTION: LEGO1 0x10065070
// FUNCTION: BETA10 0x1004afe0
const char* ClassName() const override // vtable+0x0c
{
// STRING: LEGO1 0x100f0460
return "AnimState";
}
// FUNCTION: LEGO1 0x10065080
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, AnimState::ClassName()) || LegoState::IsA(p_name);
}
MxBool Reset() override; // vtable+0x18
MxResult Serialize(LegoStorage* p_storage) override; // vtable+0x1c
void CopyToAnims(MxU32, AnimInfo* p_anims, MxU32& p_outExtraCharacterId);
void InitFromAnims(MxU32 p_animsLength, AnimInfo* p_anims, MxU32 p_extraCharacterId);
// SYNTHETIC: LEGO1 0x10065130
// AnimState::`scalar deleting destructor'
private:
MxU32 m_extraCharacterId; // 0x08
// appears to store the length of m_unk0x10
MxU32 m_unk0x0c; // 0x0c
// dynamically sized array of MxU16, corresponding to AnimInfo::m_unk0x22
MxU16* m_unk0x10; // 0x10
MxU32 m_locationsFlagsLength; // 0x14
// dynamically sized array of bools, corresponding to LegoLocation.m_unk0x5c
MxBool* m_locationsFlags; // 0x18
};
// VTABLE: LEGO1 0x100d8c18
// VTABLE: BETA10 0x101bab60
// SIZE 0x500
class LegoAnimationManager : public MxCore {
public:
// SIZE 0x18
struct Character {
const char* m_name; // 0x00
MxBool m_inExtras; // 0x04
MxS8 m_vehicleId; // 0x05
undefined m_unk0x06; // 0x06 (unused?)
MxBool m_unk0x07; // 0x07
MxBool m_unk0x08; // 0x08
MxBool m_unk0x09; // 0x09
MxS32 m_unk0x0c; // 0x0c
MxS32 m_unk0x10; // 0x10
MxBool m_active; // 0x14
MxU8 m_unk0x15; // 0x15
MxS8 m_unk0x16; // 0x16
};
// SIZE 0x08
struct Vehicle {
const char* m_name; // 0x00
MxBool m_unk0x04; // 0x04
MxBool m_unk0x05; // 0x05
};
// SIZE 0x18
struct Extra {
LegoROI* m_roi; // 0x00
MxS32 m_characterId; // 0x04
MxLong m_unk0x08; // 0x08
MxBool m_unk0x0c; // 0x0c
MxBool m_unk0x0d; // 0x0d
float m_speed; // 0x10
MxBool m_unk0x14; // 0x14
};
enum PlayMode {
e_unk0 = 0,
e_unk1,
e_unk2
};
LegoAnimationManager();
~LegoAnimationManager() override;
MxLong Notify(MxParam& p_param) override; // vtable+0x04
MxResult Tickle() override; // vtable+0x08
// FUNCTION: LEGO1 0x1005ec80
// FUNCTION: BETA10 0x100483d0
const char* ClassName() const override // vtable+0x0c
{
// STRING: LEGO1 0x100f7508
return "LegoAnimationManager";
}
// FUNCTION: LEGO1 0x1005ec90
MxBool IsA(const char* p_name) const override // vtable+0x10
{
return !strcmp(p_name, ClassName()) || MxCore::IsA(p_name);
}
void Reset(MxBool p_und);
void Suspend();
void Resume();
void FUN_1005f6d0(MxBool p_unk0x400);
void EnableCamAnims(MxBool p_enableCamAnims);
MxResult LoadWorldInfo(LegoOmni::World p_worldId);
MxBool FindVehicle(const char* p_name, MxU32& p_index);
MxResult ReadAnimInfo(LegoStorage* p_storage, AnimInfo* p_info);
MxResult ReadModelInfo(LegoStorage* p_storage, ModelInfo* p_info);
void FUN_10060480(const LegoChar* p_characterNames[], MxU32 p_numCharacterNames);
void FUN_100604d0(MxBool p_unk0x08);
void FUN_100604f0(MxS32 p_objectIds[], MxU32 p_numObjectIds);
void FUN_10060540(MxBool p_unk0x29);
void FUN_10060570(MxBool p_unk0x1a);
MxResult StartEntityAction(MxDSAction& p_dsAction, LegoEntity* p_entity);
MxResult FUN_10060dc0(
MxU32 p_objectId,
MxMatrix* p_matrix,
MxBool p_param3,
MxU8 p_param4,
LegoROI* p_roi,
MxBool p_param6,
MxBool p_param7,
MxBool p_param8,
MxBool p_param9
);
void CameraTriggerFire(LegoPathActor* p_actor, MxBool, MxU32 p_location, MxBool p_bool);
void FUN_10061010(MxBool p_und);
LegoTranInfo* GetTranInfo(MxU32 p_index);
void FUN_10062770();
void PurgeExtra(MxBool p_und);
void AddExtra(MxS32 p_location, MxBool p_und);
void FUN_10063270(LegoROIList* p_list, LegoAnimPresenter* p_presenter);
void FUN_10063780(LegoROIList* p_list);
MxResult FUN_10064670(Vector3* p_position);
MxResult FUN_10064740(Vector3* p_position);
MxResult FUN_10064880(const char* p_name, MxS32 p_unk0x0c, MxS32 p_unk0x10);
MxBool FUN_10064ee0(MxU32 p_objectId);
LEGO1_EXPORT static void configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig);
// SYNTHETIC: LEGO1 0x1005ed10
// LegoAnimationManager::`scalar deleting destructor'
private:
friend class Multiplayer::NetworkManager;
friend class Multiplayer::Animation::Catalog;
void Init();
MxResult FUN_100605e0(
MxU32 p_index,
MxBool p_unk0x0a,
MxMatrix* p_matrix,
MxBool p_bool1,
LegoROI* p_roi,
MxBool p_bool2,
MxBool p_bool3,
MxBool p_bool4,
MxBool p_bool5
);
MxResult FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix, MxBool p_und1, MxBool p_und2);
void DeleteAnimations();
void FUN_10061530();
MxResult FUN_100617c0(MxS32 p_unk0x08, MxU16& p_unk0x0e, MxU16& p_unk0x10);
MxU16 FUN_10062110(
LegoROI* p_roi,
Vector3& p_direction,
Vector3& p_position,
LegoPathBoundary* p_boundary,
float p_speed,
MxU8 p_unk0x0c,
MxBool p_unk0x14
);
MxS8 GetCharacterIndex(const char* p_name);
MxBool FUN_100623a0(AnimInfo& p_info);
MxBool ModelExists(AnimInfo& p_info, const char* p_name);
void FUN_10062580(AnimInfo& p_info);
MxBool FUN_10062650(Mx3DPointFloat& p_position, float p_und, LegoROI* p_roi);
MxBool FUN_10062710(AnimInfo& p_info);
MxBool FUN_10062e20(LegoROI* p_roi, LegoAnimPresenter* p_presenter);
void FUN_10063950(LegoROI* p_roi);
void FUN_10063aa0();
MxBool FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_actor, MxU8 p_mood, MxU32 p_characterId);
void FUN_10063d10();
void FUN_10063e40(LegoAnimPresenter* p_presenter);
MxBool FUN_10063fb0(LegoLocation::Boundary* p_boundary, LegoWorld* p_world);
MxBool FUN_10064010(LegoPathBoundary* p_boundary, LegoOrientedEdge* p_edge, float p_destScale);
MxBool FUN_10064120(LegoLocation::Boundary* p_boundary, MxBool p_bool1, MxBool p_bool2);
MxResult FUN_10064380(
const char* p_name,
const char* p_boundaryName,
MxS32 p_src,
float p_srcScale,
MxS32 p_dest,
float p_destScale,
MxU32 p_undIdx1,
MxS32 p_unk0x0c,
MxU32 p_undIdx2,
MxS32 p_unk0x10,
float p_speed
);
void FUN_100648f0(LegoTranInfo* p_tranInfo, MxLong p_unk0x404);
void FUN_10064b50(MxLong p_time);
LegoOmni::World m_worldId; // 0x08
MxU16 m_animCount; // 0x0c
MxU16 m_unk0x0e; // 0x0e
MxU16 m_unk0x10; // 0x10
AnimInfo* m_anims; // 0x14
undefined2 m_unk0x18; // 0x18
MxBool m_unk0x1a; // 0x1a
MxU32 m_unk0x1c; // 0x1c
LegoTranInfoList* m_tranInfoList; // 0x20
LegoTranInfoList* m_tranInfoList2; // 0x24
MxPresenter* m_unk0x28[2]; // 0x28
MxLong m_unk0x30[2]; // 0x30
MxBool m_unk0x38; // 0x38
MxBool m_animRunning; // 0x39
MxBool m_enableCamAnims; // 0x3a
Extra m_extras[40]; // 0x3c
MxU32 m_lastExtraCharacterId; // 0x3fc
MxBool m_unk0x400; // 0x400
MxBool m_unk0x401; // 0x401
MxBool m_unk0x402; // 0x402
MxLong m_unk0x404; // 0x404
MxLong m_unk0x408; // 0x408
MxLong m_unk0x40c; // 0x40c
MxLong m_unk0x410; // 0x410
MxU32 m_unk0x414; // 0x414
MxU32 m_numAllowedExtras; // 0x418
MxU32 m_maxAllowedExtras; // 0x41c
AnimState* m_animState; // 0x420
LegoROIList* m_unk0x424; // 0x424
MxBool m_suspendedEnableCamAnims; // 0x428
MxBool m_unk0x429; // 0x429
MxBool m_unk0x42a; // 0x42a
MxBool m_suspended; // 0x42b
LegoTranInfo* m_unk0x42c; // 0x42c
MxBool m_unk0x430; // 0x430
MxLong m_unk0x434; // 0x434
MxLong m_unk0x438; // 0x438
MxMatrix m_unk0x43c; // 0x43c
MxMatrix m_unk0x484; // 0x484
MxQuaternionTransformer m_unk0x4cc; // 0x4cc
};
// TEMPLATE: LEGO1 0x10061750
// MxListCursor<LegoTranInfo *>::MxListCursor<LegoTranInfo *>
// TEMPLATE: BETA10 0x1004b5d0
// MxListCursor<LegoTranInfo *>::Next
#endif // LEGOANIMATIONMANAGER_H