mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 02:23:56 +00:00
32b2834c0b
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
32b2834c0b
|
Remove dead code hiding spectator ROIs during camera animations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
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> |