using AcDream.App.Physics; using AcDream.App.Rendering; using AcDream.Core.Net; using AcDream.Core.Physics.Motion; using AcDream.Core.World; namespace AcDream.App.Physics; /// /// Narrow reverse seam for collaborators constructed before the live network /// owner. It carries no state or identity: every call resolves the one bound /// update-thread owner, and use before bind fails immediately. /// internal interface ILiveEntityMotionRuntimeBindings { (float Radius, float Height) GetSetupCylinder(uint serverGuid, WorldEntity entity); bool RouteServerMoveTo( MovementManager movement, uint cellId, WorldSession.EntityMotionUpdate update); void StickToObjectFromWire(IPhysicsObjHost? host, uint targetGuid); void ClearTargetForHiddenEntity(uint serverGuid); IPhysicsObjHost? ResolvePhysicsHost(uint serverGuid); } internal sealed class DeferredLiveEntityMotionRuntimeBindings : ILiveEntityMotionRuntimeBindings { private ILiveEntityMotionRuntimeBindings? _target; public void Bind(ILiveEntityMotionRuntimeBindings target) { ArgumentNullException.ThrowIfNull(target); if (_target is not null) { throw new InvalidOperationException( "Live entity motion runtime bindings are already bound."); } _target = target; } private ILiveEntityMotionRuntimeBindings Target => _target ?? throw new InvalidOperationException( "Live entity motion runtime bindings were used before binding."); public (float Radius, float Height) GetSetupCylinder( uint serverGuid, WorldEntity entity) => Target.GetSetupCylinder(serverGuid, entity); public bool RouteServerMoveTo( MovementManager movement, uint cellId, WorldSession.EntityMotionUpdate update) => Target.RouteServerMoveTo(movement, cellId, update); public void StickToObjectFromWire(IPhysicsObjHost? host, uint targetGuid) => Target.StickToObjectFromWire(host, targetGuid); public void ClearTargetForHiddenEntity(uint serverGuid) => Target.ClearTargetForHiddenEntity(serverGuid); public IPhysicsObjHost? ResolvePhysicsHost(uint serverGuid) => Target.ResolvePhysicsHost(serverGuid); }