using System.Collections.Generic; using AcDream.Core.Physics; namespace AcDream.App.Rendering.Wb; /// /// Per-entity render state for animated entities (characters, creatures, /// equipped items). Holds AC-specific per-instance customizations the WB /// atlas cache doesn't carry: AnimPartChange override map + /// HiddenParts bitmask. Also holds a reference to acdream's existing /// — Phase N.4 explicitly does not touch /// the sequencer; we just route through it at draw time. /// /// /// Lifecycle: created by EntitySpawnAdapter.OnCreate (Task 17) when /// a server CreateObject is processed; destroyed by /// EntitySpawnAdapter.OnRemove on RemoveObject. The mesh /// data backing each part is cached in WB's ObjectMeshManager; /// per-instance customizations don't go through the atlas — they overlay /// at draw time. /// /// public sealed class AnimatedEntityState { private readonly Dictionary _partGfxObjOverrides = new(); private ulong _hiddenMask = 0; /// Reference to acdream's existing animation sequencer. /// Phase N.4 doesn't touch the sequencer; the draw dispatcher consumes /// per-part transforms it produces per frame. public AnimationSequencer Sequencer { get; } public AnimatedEntityState(AnimationSequencer sequencer) { System.ArgumentNullException.ThrowIfNull(sequencer); Sequencer = sequencer; } /// Set the HiddenParts bitmask for this entity. Bit /// i set hides part i at draw time. public void HideParts(ulong hiddenMask) => _hiddenMask = hiddenMask; /// True if part partIdx should be skipped at draw /// time. Returns false for part indices outside [0, 63]. public bool IsPartHidden(int partIdx) { if (partIdx < 0 || partIdx >= 64) return false; return (_hiddenMask & (1ul << partIdx)) != 0; } /// Override the GfxObj id for a Setup part. Used for /// AnimPartChange — e.g. wielding a weapon swaps the hand-part's /// GfxObj. public void SetPartOverride(int partIdx, ulong gfxObjId) => _partGfxObjOverrides[partIdx] = gfxObjId; /// Look up the GfxObj override for a part. Returns false if /// no override is set (caller should fall back to Setup default). public bool TryGetPartOverride(int partIdx, out ulong gfxObjId) => _partGfxObjOverrides.TryGetValue(partIdx, out gfxObjId); /// Resolve the GfxObj id for : /// override if set, else . Used by the /// draw dispatcher to pick the right cached mesh data per part. public ulong ResolvePartGfxObj(int partIdx, ulong setupDefault) => TryGetPartOverride(partIdx, out var ov) ? ov : setupDefault; }