feat(vfx): port retail hidden and teleport presentation
Preserve canonical live-object ownership across Hidden transitions and remote teleport placement so effects, collision, streaming, and targeting remain synchronized.
This commit is contained in:
parent
a51ebc66e9
commit
1e98d81448
46 changed files with 4883 additions and 127 deletions
|
|
@ -219,6 +219,7 @@ public sealed class EquippedChildRenderController : IDisposable
|
|||
child.Entity.SetIndexedPartPoses(pose.PartLocal, child.PartAvailability);
|
||||
if (!ApplyParentWorldPose(child.Entity, parentWorld))
|
||||
return false;
|
||||
ApplyParentDrawVisibility(child.Entity, parent);
|
||||
child.Entity.ParentCellId = parent.ParentCellId;
|
||||
PublishChildPose(child.Entity, parentWorld, parent.ParentCellId, pose);
|
||||
if (parent.ParentCellId is { } parentCellId)
|
||||
|
|
@ -317,6 +318,7 @@ public sealed class EquippedChildRenderController : IDisposable
|
|||
if (entity is null)
|
||||
return false;
|
||||
ApplyParentWorldPose(entity, parentWorld);
|
||||
ApplyParentDrawVisibility(entity, parentEntity);
|
||||
entity.ParentCellId = parentCellId;
|
||||
entity.ApplyAppearance(
|
||||
pose.AttachedParts,
|
||||
|
|
@ -338,6 +340,14 @@ public sealed class EquippedChildRenderController : IDisposable
|
|||
pose.AttachedParts,
|
||||
scale,
|
||||
entity);
|
||||
if (_liveEntities.TryGetRecord(pending.ParentGuid, out LiveEntityRecord parentRecord)
|
||||
&& (parentRecord.FinalPhysicsState & PhysicsStateFlags.Hidden) != 0)
|
||||
{
|
||||
// A child attached while its parent is already Hidden inherits
|
||||
// the same direct child NoDraw mutation retail applies from
|
||||
// CPhysicsObj::set_hidden (0x00514C60).
|
||||
_liveEntities.SetAttachedChildNoDraw(childGuid, noDraw: true);
|
||||
}
|
||||
PublishChildPose(entity, parentWorld, parentEntity.ParentCellId, pose);
|
||||
Console.WriteLine(
|
||||
$"equipment: attached child=0x{childGuid:X8} parent=0x{pending.ParentGuid:X8} " +
|
||||
|
|
@ -376,6 +386,18 @@ public sealed class EquippedChildRenderController : IDisposable
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Preserve retail attachment-tree draw inheritance after adapting every
|
||||
/// child CPhysicsObj into an independent retained draw entry. This does not
|
||||
/// alter the child's own NoDraw state; parent-first ticking propagates an
|
||||
/// ancestor's suppression through arbitrarily deep attachment chains.
|
||||
/// </summary>
|
||||
internal static void ApplyParentDrawVisibility(WorldEntity child, WorldEntity parent)
|
||||
{
|
||||
child.IsAncestorDrawVisible =
|
||||
parent.IsDrawVisible && parent.IsAncestorDrawVisible;
|
||||
}
|
||||
|
||||
private static bool TryDecomposeWorldPose(
|
||||
Matrix4x4 world,
|
||||
out Vector3 position,
|
||||
|
|
@ -425,6 +447,20 @@ public sealed class EquippedChildRenderController : IDisposable
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>CPhysicsObj::set_hidden</c> walks the direct CHILDLIST and
|
||||
/// sets/clears each child's NoDraw bit before changing root collision/cell
|
||||
/// presentation. Descendants are not recursively rewritten here.
|
||||
/// </summary>
|
||||
public void SetDirectChildrenNoDraw(uint parentGuid, bool noDraw)
|
||||
{
|
||||
foreach (AttachedChild child in _attachedByChild.Values)
|
||||
{
|
||||
if (child.ParentGuid == parentGuid)
|
||||
_liveEntities.SetAttachedChildNoDraw(child.ChildGuid, noDraw);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveRelations(uint childGuid)
|
||||
{
|
||||
Relations.Resolve(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue