using System.Collections.Immutable;
using System.Numerics;
namespace AcDream.Core.Physics;
///
/// Retail SetPositionError (acclient.h, enum 491). This is
/// deliberately independent of :
/// losing the destination cell is a successful SetPosition operation whose
/// residence is deferred, not a placement error.
///
internal enum PhysicsSetPositionError
{
Ok = 0,
GeneralFailure = 1,
NoValidPosition = 2,
NoCell = 3,
Collided = 4,
InvalidArguments = 0x100,
}
internal enum PhysicsResidenceDisposition
{
Committed,
DeferredCell,
Unchanged,
}
///
/// 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 ;
/// Preserve intentionally leaves the existing list untouched.
///
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 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,
}
///
/// The three retail weenie classifications which bypass placement collision
/// in CPhysicsObj::SetPositionInternal after AdjustPosition succeeds.
/// Runtime derives this from the canonical object record; callers cannot use a
/// free boolean to force ordinary objects through geometry.
///
internal enum PhysicsPlacementClass
{
Ordinary,
Hook,
Storage,
Corpse,
}
///
/// Complete immutable input to retail CPhysicsObj::SetPosition. World
/// position feeds acdream's flat collision representation; cell-local position
/// is retail's Position.frame.origin and is the only input to
/// LandDefs::adjust_to_outside.
///
internal readonly record struct PhysicsSetPositionRequest(
Vector3 Position,
Quaternion Orientation,
uint CellId,
Vector3 CellLocalPosition,
ImmutableArray 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);
///
/// 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.
///
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 CrossCellIds = default,
ImmutableArray CollidedObjectIds = default,
ImmutableArray QueriedCellIds = default)
{
internal bool IsSuccessful => Error == PhysicsSetPositionError.Ok;
internal bool IsCommitted =>
IsSuccessful && Residence == PhysicsResidenceDisposition.Committed;
internal bool IsDeferred =>
IsSuccessful && Residence == PhysicsResidenceDisposition.DeferredCell;
}