156 lines
5 KiB
C#
156 lines
5 KiB
C#
using System.Collections.Immutable;
|
|
using System.Numerics;
|
|
|
|
namespace AcDream.Core.Physics;
|
|
|
|
/// <summary>
|
|
/// Retail <c>SetPositionError</c> (<c>acclient.h</c>, enum 491). This is
|
|
/// deliberately independent of <see cref="PhysicsResidenceDisposition"/>:
|
|
/// losing the destination cell is a successful SetPosition operation whose
|
|
/// residence is deferred, not a placement error.
|
|
/// </summary>
|
|
internal enum PhysicsSetPositionError
|
|
{
|
|
Ok = 0,
|
|
GeneralFailure = 1,
|
|
NoValidPosition = 2,
|
|
NoCell = 3,
|
|
Collided = 4,
|
|
InvalidArguments = 0x100,
|
|
}
|
|
|
|
internal enum PhysicsResidenceDisposition
|
|
{
|
|
Committed,
|
|
DeferredCell,
|
|
Unchanged,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shadow-list operation performed by retail's SetPosition commit tail.
|
|
/// Recalculate delegates to the canonical live shadow-shape owner (the
|
|
/// PhysicsBSP/bounding-box path cannot be reconstructed from placement
|
|
/// spheres); Replace consumes <see cref="PhysicsSetPositionResult.CrossCellIds"/>;
|
|
/// Preserve intentionally leaves the existing list untouched.
|
|
/// </summary>
|
|
internal enum PhysicsShadowCommitAction
|
|
{
|
|
None,
|
|
Recalculate,
|
|
Replace,
|
|
Preserve,
|
|
}
|
|
|
|
internal readonly record struct PhysicsSetPositionCollisionReport(
|
|
bool ContactPlaneValid,
|
|
Plane ContactPlane,
|
|
uint ContactPlaneCellId,
|
|
bool ContactPlaneIsWater,
|
|
bool LastKnownContactPlaneValid,
|
|
Plane LastKnownContactPlane,
|
|
uint LastKnownContactPlaneCellId,
|
|
bool LastKnownContactPlaneIsWater,
|
|
bool SlidingNormalValid,
|
|
Vector3 SlidingNormal,
|
|
bool CollisionNormalValid,
|
|
Vector3 CollisionNormal,
|
|
bool CollidedWithEnvironment,
|
|
int FramesStationaryFall,
|
|
Vector3 AdjustOffset,
|
|
uint? LastCollidedObjectId,
|
|
ImmutableArray<uint> CollidedObjectIds);
|
|
|
|
[Flags]
|
|
internal enum PhysicsSetPositionFlags : uint
|
|
{
|
|
None = 0,
|
|
Placement = 0x001,
|
|
Teleport = 0x002,
|
|
Restore = 0x004,
|
|
Slide = 0x010,
|
|
DoNotCreateCells = 0x020,
|
|
Scatter = 0x100,
|
|
RandomScatter = 0x200,
|
|
Line = 0x400,
|
|
SendPositionEvent = 0x1000,
|
|
}
|
|
|
|
/// <summary>
|
|
/// The three retail weenie classifications which bypass placement collision
|
|
/// in <c>CPhysicsObj::SetPositionInternal</c> after AdjustPosition succeeds.
|
|
/// Runtime derives this from the canonical object record; callers cannot use a
|
|
/// free boolean to force ordinary objects through geometry.
|
|
/// </summary>
|
|
internal enum PhysicsPlacementClass
|
|
{
|
|
Ordinary,
|
|
Hook,
|
|
Storage,
|
|
Corpse,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Complete immutable input to retail <c>CPhysicsObj::SetPosition</c>. World
|
|
/// position feeds acdream's flat collision representation; cell-local position
|
|
/// is retail's <c>Position.frame.origin</c> and is the only input to
|
|
/// <c>LandDefs::adjust_to_outside</c>.
|
|
/// </summary>
|
|
internal readonly record struct PhysicsSetPositionRequest(
|
|
Vector3 Position,
|
|
Quaternion Orientation,
|
|
uint CellId,
|
|
Vector3 CellLocalPosition,
|
|
ImmutableArray<FlatCollisionSphere> Spheres,
|
|
float Scale,
|
|
float StepUpHeight,
|
|
float StepDownHeight,
|
|
PhysicsStateFlags MoverPhysicsState = PhysicsStateFlags.None,
|
|
ObjectInfoState MoverFlags = ObjectInfoState.None,
|
|
uint MovingEntityId = 0u,
|
|
PhysicsPlacementClass PlacementClass = PhysicsPlacementClass.Ordinary,
|
|
PhysicsSetPositionFlags Flags = PhysicsSetPositionFlags.Placement,
|
|
Vector3 Line = default,
|
|
float ScatterRadiusX = 0f,
|
|
float ScatterRadiusY = 0f,
|
|
uint ScatterAttempts = 0u,
|
|
// Null models retail's distinct `this->cell == nullptr` state. The
|
|
// retained Position cell id may equal the destination while the object is
|
|
// still in the lost-cell list; that wake must change_cell and reflood.
|
|
uint? CurrentCellId = null);
|
|
|
|
/// <summary>
|
|
/// Immutable commit packet produced by the pure placement transaction. Runtime
|
|
/// installs this packet atomically into the canonical body/spatial owner before
|
|
/// publishing one presentation delta.
|
|
/// </summary>
|
|
internal readonly record struct PhysicsSetPositionResult(
|
|
PhysicsSetPositionError Error,
|
|
PhysicsResidenceDisposition Residence,
|
|
Vector3 Position,
|
|
Quaternion Orientation,
|
|
uint CellId,
|
|
Vector3 CellLocalPosition,
|
|
bool InContact = false,
|
|
bool OnWalkable = false,
|
|
Plane ContactPlane = default,
|
|
uint ContactPlaneCellId = 0u,
|
|
bool ContactPlaneIsWater = false,
|
|
bool SlidingNormalValid = false,
|
|
Vector3 SlidingNormal = default,
|
|
bool CollisionNormalValid = false,
|
|
Vector3 CollisionNormal = default,
|
|
int FramesStationaryFall = 0,
|
|
bool CollidedWithEnvironment = false,
|
|
bool CollisionHandlerResult = false,
|
|
bool CellChanged = false,
|
|
PhysicsShadowCommitAction ShadowAction = PhysicsShadowCommitAction.None,
|
|
ImmutableArray<uint> CrossCellIds = default,
|
|
ImmutableArray<uint> CollidedObjectIds = default,
|
|
ImmutableArray<uint> QueriedCellIds = default)
|
|
{
|
|
internal bool IsSuccessful => Error == PhysicsSetPositionError.Ok;
|
|
internal bool IsCommitted =>
|
|
IsSuccessful && Residence == PhysicsResidenceDisposition.Committed;
|
|
internal bool IsDeferred =>
|
|
IsSuccessful && Residence == PhysicsResidenceDisposition.DeferredCell;
|
|
}
|