You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1645 lines
65 KiB
C#
1645 lines
65 KiB
C#
//Shady
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Unity.Profiling;
|
|
using UnityEngine;
|
|
|
|
namespace Fusion.Addons.SimpleKCC
|
|
{
|
|
[DisallowMultipleComponent]
|
|
[RequireComponent(typeof(Rigidbody))]
|
|
public sealed class KCCOffline : MonoBehaviour
|
|
{
|
|
internal const int CACHE_SIZE = 64;
|
|
|
|
internal const int HISTORY_SIZE = 60;
|
|
|
|
[SerializeField]
|
|
private KCCSettings _settings = new();
|
|
|
|
private Transform _transform;
|
|
|
|
private Rigidbody _rigidbody;
|
|
|
|
private bool _isSpawned;
|
|
|
|
private KCCCollider _collider = new();
|
|
|
|
private KCCData _fixedData = new();
|
|
|
|
private KCCData[] _historyData = new KCCData[60];
|
|
|
|
private KCCSettings _defaultSettings = new();
|
|
|
|
private KCCOverlapInfo _extendedOverlapInfo = new(64);
|
|
|
|
private KCCOverlapInfo _trackOverlapInfo = new(64);
|
|
|
|
private List<Collider> _childColliders = new List<Collider>();
|
|
|
|
private RaycastHit[] _raycastHits = new RaycastHit[64];
|
|
|
|
private Collider[] _hitColliders = new Collider[64];
|
|
|
|
private Collider[] _addColliders = new Collider[64];
|
|
|
|
private Collider[] _removeColliders = new Collider[64];
|
|
|
|
private KCCResolver _resolver = new(64);
|
|
|
|
private Vector3 _lastAntiJitterPosition;
|
|
|
|
private Vector3 _predictionError;
|
|
|
|
private static ProfilerMarker _fixedUpdateMarker = new ProfilerMarker("KCC.FixedUpdate");
|
|
|
|
public Func<KCCOffline, Collider, bool> ResolveCollision;
|
|
|
|
internal bool IsSpawned => _isSpawned;
|
|
|
|
public bool IsGrounded => Data.IsGrounded;
|
|
|
|
public Vector3 RealVelocity => Data.RealVelocity;
|
|
|
|
public Vector3 Position => Data.TargetPosition;
|
|
|
|
public Quaternion LookRotation => Data.LookRotation;
|
|
|
|
public Vector3 LookDirection => Data.LookDirection;
|
|
|
|
public Quaternion TransformRotation => Data.TransformRotation;
|
|
|
|
public Vector3 TransformDirection => Data.TransformDirection;
|
|
|
|
public float RealSpeed => Data.RealSpeed;
|
|
|
|
public bool HasJumped => Data.HasJumped;
|
|
|
|
public bool IsActive => Data.IsActive;
|
|
|
|
internal KCCData Data => _fixedData;
|
|
|
|
internal KCCData FixedData => _fixedData;
|
|
|
|
public KCCSettings Settings => _settings;
|
|
|
|
public Transform Transform => _transform;
|
|
|
|
public CapsuleCollider Collider => _collider.Collider;
|
|
|
|
public Rigidbody Rigidbody => _rigidbody;
|
|
|
|
internal bool IsInFixedUpdate => true;
|
|
|
|
internal Vector3 PredictionError => _predictionError;
|
|
|
|
private event Action<KCCOffline> _onSpawn;
|
|
|
|
internal void SynchronizeTransform(bool synchronizePosition, bool synchronizeRotation, bool allowAntiJitter = true)
|
|
{
|
|
if (IsInFixedUpdate)
|
|
{
|
|
allowAntiJitter = false;
|
|
}
|
|
|
|
SynchronizeTransform(Data, synchronizePosition, synchronizeRotation, allowAntiJitter);
|
|
}
|
|
|
|
public void RefreshChildColliders()
|
|
{
|
|
_childColliders.Clear();
|
|
GetComponentsInChildren(includeInactive: true, _childColliders);
|
|
int num = 0;
|
|
int num2 = _childColliders.Count - 1;
|
|
while (num <= num2)
|
|
{
|
|
Collider collider = _childColliders[num];
|
|
if (collider.isTrigger || collider == _collider.Collider)
|
|
{
|
|
_childColliders[num] = _childColliders[num2];
|
|
_childColliders.RemoveAt(num2);
|
|
num2--;
|
|
}
|
|
else
|
|
{
|
|
num++;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal KCCData GetHistoryData(int tick)
|
|
{
|
|
if (tick < 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
KCCData kCCData = _historyData[tick % 60];
|
|
if (kCCData != null && kCCData.Tick == tick)
|
|
{
|
|
return kCCData;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
internal void InvokeOnSpawn(Action<KCCOffline> callback)
|
|
{
|
|
if (_isSpawned)
|
|
{
|
|
callback(this);
|
|
return;
|
|
}
|
|
|
|
_onSpawn -= callback;
|
|
_onSpawn += callback;
|
|
}
|
|
|
|
internal void ManualFixedUpdate()
|
|
{
|
|
if (_isSpawned)
|
|
{
|
|
_fixedUpdateMarker.Begin();
|
|
OnFixedUpdateInternal();
|
|
_fixedUpdateMarker.End();
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
_transform = base.transform;
|
|
_rigidbody = GetComponent<Rigidbody>();
|
|
_rigidbody.isKinematic = true;
|
|
RefreshCollider();
|
|
Spawned();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
SetDefaults(cleanup: true);
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (_settings != null)
|
|
{
|
|
float num = Mathf.Max(0.01f, _settings.Radius);
|
|
float num2 = Mathf.Max(num * 2f, _settings.Height);
|
|
Vector3 position = base.transform.position;
|
|
Color color = Gizmos.color;
|
|
Vector3 vector = position + Vector3.up * num;
|
|
Vector3 vector2 = position + Vector3.up * (num2 - num);
|
|
Vector3 vector3 = Vector3.forward * num;
|
|
Vector3 vector4 = Vector3.back * num;
|
|
Vector3 vector5 = Vector3.left * num;
|
|
Vector3 vector6 = Vector3.right * num;
|
|
Gizmos.color = Color.green;
|
|
Gizmos.DrawWireSphere(vector, num);
|
|
Gizmos.DrawWireSphere(vector2, num);
|
|
Gizmos.DrawLine(vector + vector3, vector2 + vector3);
|
|
Gizmos.DrawLine(vector + vector4, vector2 + vector4);
|
|
Gizmos.DrawLine(vector + vector5, vector2 + vector5);
|
|
Gizmos.DrawLine(vector + vector6, vector2 + vector6);
|
|
if (_settings.Extent > 0f)
|
|
{
|
|
float radius = num + _settings.Extent;
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawWireSphere(vector, radius);
|
|
Gizmos.DrawWireSphere(vector2, radius);
|
|
}
|
|
|
|
Gizmos.color = color;
|
|
}
|
|
}
|
|
|
|
public void Spawned()
|
|
{
|
|
if (_isSpawned)
|
|
{
|
|
throw new InvalidOperationException("[" + base.name + "] KCC is already spawned!");
|
|
}
|
|
|
|
_defaultSettings.CopyFromOther(_settings);
|
|
SetDefaults(cleanup: false);
|
|
_isSpawned = true;
|
|
// _isInFixedUpdate = true;
|
|
KCCUtility.GetClampedLookRotationAngles(_transform.rotation, out var pitch, out var yaw);
|
|
_fixedData = new();
|
|
_fixedData.Frame = Time.frameCount;
|
|
// _fixedData.Tick = base.Runner.Tick.Raw;
|
|
// _fixedData.Time = base.Runner.SimulationTime;
|
|
_fixedData.DeltaTime = Time.deltaTime;
|
|
_fixedData.UpdateDeltaTime = _fixedData.DeltaTime;
|
|
_fixedData.Gravity = Physics.gravity;
|
|
_fixedData.MaxGroundAngle = 60f;
|
|
_fixedData.MaxWallAngle = 5f;
|
|
_fixedData.MaxHangAngle = 30f;
|
|
_fixedData.BasePosition = _transform.position;
|
|
_fixedData.DesiredPosition = _transform.position;
|
|
_fixedData.TargetPosition = _transform.position;
|
|
_fixedData.LookPitch = pitch;
|
|
_fixedData.LookYaw = yaw;
|
|
|
|
// if (!base.Object.HasStateAuthority)
|
|
// {
|
|
// ReadNetworkData();
|
|
SynchronizeTransform(_fixedData, synchronizePosition: true, synchronizeRotation: true, allowAntiJitter: false);
|
|
// }
|
|
|
|
// _renderData = new();
|
|
// _renderData.CopyFromOther(_fixedData);
|
|
// _lastRenderPosition = _renderData.TargetPosition;
|
|
// _lastAntiJitterPosition = _renderData.TargetPosition;
|
|
RefreshCollider();
|
|
RefreshChildColliders();
|
|
if (this._onSpawn != null)
|
|
{
|
|
try
|
|
{
|
|
this._onSpawn(this);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Debug.LogException(exception);
|
|
}
|
|
|
|
this._onSpawn = null;
|
|
}
|
|
}
|
|
|
|
private void OnFixedUpdateInternal()
|
|
{
|
|
if (!IsInFixedUpdate)
|
|
{
|
|
throw new InvalidOperationException("[" + base.name + "] KCC fixed update called from render update! This is not allowed.");
|
|
}
|
|
|
|
RefreshCollider();
|
|
MovePredicted(_fixedData);
|
|
if (_fixedData.IsActive)
|
|
{
|
|
SynchronizeTransform(_fixedData, synchronizePosition: true, synchronizeRotation: true, allowAntiJitter: false);
|
|
}
|
|
}
|
|
|
|
private void MovePredicted(KCCData data)
|
|
{
|
|
float time = data.Time;
|
|
float deltaTime = data.DeltaTime;
|
|
Vector3 targetPosition = data.TargetPosition;
|
|
Vector3 targetPosition2 = data.TargetPosition;
|
|
bool isGrounded = data.IsGrounded;
|
|
bool isSteppingUp = data.IsSteppingUp;
|
|
bool isSnappingToGround = data.IsSnappingToGround;
|
|
data.DeltaTime = deltaTime;
|
|
data.BasePosition = targetPosition;
|
|
data.DesiredPosition = targetPosition2;
|
|
if (!data.IsActive)
|
|
{
|
|
data.ClearTransientProperties();
|
|
ForceRemoveAllHits(data);
|
|
return;
|
|
}
|
|
|
|
SetBaseProperties(data);
|
|
if (!data.IsActive)
|
|
{
|
|
data.ClearTransientProperties();
|
|
ForceRemoveAllHits(data);
|
|
return;
|
|
}
|
|
|
|
deltaTime = data.DeltaTime;
|
|
targetPosition = data.BasePosition;
|
|
if (deltaTime < KCCSettings.ExtrapolationDeltaTimeThreshold)
|
|
{
|
|
Vector3 vector = data.DesiredVelocity;
|
|
if (data.RealVelocity.sqrMagnitude <= vector.sqrMagnitude)
|
|
{
|
|
vector = data.RealVelocity;
|
|
}
|
|
|
|
targetPosition2 = targetPosition + vector * deltaTime;
|
|
data.BasePosition = targetPosition;
|
|
data.DesiredPosition = targetPosition2;
|
|
data.TargetPosition = targetPosition2;
|
|
return;
|
|
}
|
|
|
|
EnvironmentProcessor.SetDynamicVelocity(this, data);
|
|
ForceRemoveAllHits(data);
|
|
float num = Mathf.Clamp01(deltaTime);
|
|
Vector3 vector2 = data.DesiredVelocity * num + data.ExternalDelta;
|
|
targetPosition2 = (data.DesiredPosition = data.BasePosition + vector2);
|
|
data.TargetPosition = data.BasePosition;
|
|
data.ExternalDelta = default(Vector3);
|
|
bool flag = false;
|
|
float num2 = Mathf.Clamp(_settings.CCDRadiusMultiplier, 0.25f, 0.75f);
|
|
float num3 = _settings.Radius * (num2 + 0.1f);
|
|
float num4 = _settings.Radius * num2;
|
|
Vector3 targetPosition3 = data.TargetPosition;
|
|
while (!flag && !data.HasTeleported)
|
|
{
|
|
data.BasePosition = data.TargetPosition;
|
|
float num5 = num;
|
|
Vector3 vector3 = vector2;
|
|
float magnitude = vector3.magnitude;
|
|
if (magnitude > num3)
|
|
{
|
|
float num6 = num4 / magnitude;
|
|
num5 *= num6;
|
|
vector3 *= num6;
|
|
}
|
|
else
|
|
{
|
|
flag = true;
|
|
}
|
|
|
|
num -= num5;
|
|
vector2 -= vector3;
|
|
if (num <= 0f)
|
|
{
|
|
num = 0f;
|
|
}
|
|
|
|
data.Time = time - num;
|
|
data.DeltaTime = num5;
|
|
data.DesiredPosition = data.BasePosition + vector3;
|
|
data.TargetPosition = data.DesiredPosition;
|
|
data.WasGrounded = data.IsGrounded;
|
|
data.WasSteppingUp = data.IsSteppingUp;
|
|
data.WasSnappingToGround = data.IsSnappingToGround;
|
|
ProcessMoveStep(data);
|
|
if (!data.HasTeleported)
|
|
{
|
|
targetPosition3 = data.TargetPosition;
|
|
}
|
|
|
|
if (data.HasTeleported)
|
|
{
|
|
UpdateHits(data, null, EKCCHitsOverlapQuery.New);
|
|
}
|
|
|
|
if (flag && !data.ExternalDelta.IsZero())
|
|
{
|
|
vector2 += data.ExternalDelta;
|
|
data.ExternalDelta = default(Vector3);
|
|
flag = false;
|
|
}
|
|
}
|
|
|
|
data.Time = time;
|
|
data.DeltaTime = deltaTime;
|
|
data.BasePosition = targetPosition;
|
|
data.DesiredPosition = targetPosition2;
|
|
data.WasGrounded = isGrounded;
|
|
data.WasSteppingUp = isSteppingUp;
|
|
data.WasSnappingToGround = isSnappingToGround;
|
|
data.RealVelocity = (targetPosition3 - data.BasePosition) / data.DeltaTime;
|
|
data.RealSpeed = data.RealVelocity.magnitude;
|
|
Vector3 targetPosition4 = data.TargetPosition;
|
|
if (!data.TargetPosition.IsEqual(targetPosition4))
|
|
{
|
|
UpdateHits(data, null, EKCCHitsOverlapQuery.New);
|
|
}
|
|
|
|
targetPosition4 = data.TargetPosition;
|
|
if (!data.TargetPosition.IsEqual(targetPosition4))
|
|
{
|
|
UpdateHits(data, null, EKCCHitsOverlapQuery.New);
|
|
}
|
|
}
|
|
|
|
private void SetBaseProperties(KCCData data)
|
|
{
|
|
data.HasTeleported = false;
|
|
data.MaxPenetrationSteps = _settings.MaxPenetrationSteps;
|
|
if (data.Frame == _fixedData.Frame)
|
|
{
|
|
data.JumpFrames = 0;
|
|
}
|
|
}
|
|
|
|
private void ProcessMoveStep(KCCData data)
|
|
{
|
|
data.IsGrounded = false;
|
|
data.IsSteppingUp = false;
|
|
data.IsSnappingToGround = false;
|
|
data.GroundNormal = default(Vector3);
|
|
data.GroundTangent = default(Vector3);
|
|
data.GroundPosition = default(Vector3);
|
|
data.GroundDistance = 0f;
|
|
data.GroundAngle = 0f;
|
|
ForceRemoveAllHits(data);
|
|
bool flag = data.JumpFrames > 0;
|
|
if ((int)_settings.CollisionLayerMask != 0 && _collider.IsSpawned)
|
|
{
|
|
float radius = _settings.Radius;
|
|
EKCCHitsOverlapQuery overlapQuery = EKCCHitsOverlapQuery.Default;
|
|
CapsuleOverlap(_extendedOverlapInfo, data, data.TargetPosition, _settings.Radius, _settings.Height, radius, _settings.CollisionLayerMask, QueryTriggerInteraction.Collide);
|
|
data.TargetPosition = ResolvePenetration(_extendedOverlapInfo, data, data.BasePosition, data.TargetPosition, !flag, data.MaxPenetrationSteps, 3, resolveTriggers: true);
|
|
UpdateHits(data, _extendedOverlapInfo, overlapQuery);
|
|
}
|
|
|
|
if (flag)
|
|
{
|
|
data.IsGrounded = false;
|
|
}
|
|
|
|
EnvironmentProcessor.AfterMoveStep(this, data);
|
|
StepUpProcessor.AfterMoveStep(this, data, _extendedOverlapInfo);
|
|
GroundSnapProcessor.AfterMoveStep(this, data, _extendedOverlapInfo);
|
|
}
|
|
|
|
private void SynchronizeTransform(KCCData data, bool synchronizePosition, bool synchronizeRotation, bool allowAntiJitter)
|
|
{
|
|
if (synchronizePosition)
|
|
{
|
|
Vector3 vector = data.TargetPosition;
|
|
_rigidbody.position = vector;
|
|
if (allowAntiJitter && !_settings.AntiJitterDistance.IsZero())
|
|
{
|
|
Vector3 vector2 = vector - _lastAntiJitterPosition;
|
|
if (vector2.sqrMagnitude < _settings.TeleportThreshold * _settings.TeleportThreshold)
|
|
{
|
|
vector = _lastAntiJitterPosition;
|
|
float num = Mathf.Abs(vector2.y);
|
|
if (num > 1E-06f)
|
|
{
|
|
vector.y += vector2.y * Mathf.Clamp01((num - _settings.AntiJitterDistance.y) / num);
|
|
}
|
|
|
|
Vector3 vector3 = vector2.OnlyXZ();
|
|
float num2 = Vector3.Magnitude(vector3);
|
|
if (num2 > 1E-06f)
|
|
{
|
|
vector += vector3 * Mathf.Clamp01((num2 - _settings.AntiJitterDistance.x) / num2);
|
|
}
|
|
}
|
|
|
|
_lastAntiJitterPosition = vector;
|
|
}
|
|
|
|
if (synchronizeRotation)
|
|
{
|
|
_transform.SetPositionAndRotation(vector, data.TransformRotation);
|
|
}
|
|
else
|
|
{
|
|
_transform.position = vector;
|
|
}
|
|
}
|
|
else if (synchronizeRotation)
|
|
{
|
|
_transform.rotation = data.TransformRotation;
|
|
}
|
|
}
|
|
|
|
private void RefreshCollider()
|
|
{
|
|
if (_settings.Shape == EKCCShape.None)
|
|
{
|
|
_collider.Destroy();
|
|
return;
|
|
}
|
|
|
|
_settings.Radius = Mathf.Max(0.01f, _settings.Radius);
|
|
_settings.Height = Mathf.Max(_settings.Radius * 2f, _settings.Height);
|
|
_settings.Extent = Mathf.Max(0f, _settings.Extent);
|
|
_collider.Update(this);
|
|
}
|
|
|
|
private void SetDefaults(bool cleanup)
|
|
{
|
|
_fixedData.Clear();
|
|
// _renderData.Clear();
|
|
Array.Clear(_historyData, 0, _historyData.Length);
|
|
_extendedOverlapInfo.Reset(deep: true);
|
|
_trackOverlapInfo.Reset(deep: true);
|
|
_childColliders.Clear();
|
|
Array.Clear(_raycastHits, 0, _raycastHits.Length);
|
|
Array.Clear(_hitColliders, 0, _hitColliders.Length);
|
|
Array.Clear(_addColliders, 0, _addColliders.Length);
|
|
Array.Clear(_removeColliders, 0, _removeColliders.Length);
|
|
|
|
// _raycastHits.Clear();
|
|
// _hitColliders.Clear();
|
|
// _addColliders.Clear();
|
|
// _removeColliders.Clear();
|
|
_rigidbody.isKinematic = true;
|
|
// _lastRenderTime = 0f;
|
|
// _lastRenderPosition = default(Vector3);
|
|
_lastAntiJitterPosition = default(Vector3);
|
|
_predictionError = default(Vector3);
|
|
if (cleanup)
|
|
{
|
|
_isSpawned = false;
|
|
// _isInFixedUpdate = false;
|
|
_settings.CopyFromOther(_defaultSettings);
|
|
_collider.Destroy();
|
|
this._onSpawn = null;
|
|
ResolveCollision = null;
|
|
}
|
|
}
|
|
|
|
internal Vector3 ResolvePenetration(KCCOverlapInfo overlapInfo, KCCData data, Vector3 basePosition, Vector3 targetPosition, bool probeGrounding, int maxSteps, int resolverIterations, bool resolveTriggers)
|
|
{
|
|
if (_settings.SuppressConvexMeshColliders)
|
|
{
|
|
overlapInfo.ToggleConvexMeshColliders(convex: false);
|
|
}
|
|
|
|
if (overlapInfo.ColliderHitCount == 1)
|
|
{
|
|
targetPosition = DepenetrateSingle(overlapInfo, data, basePosition, targetPosition, probeGrounding, maxSteps);
|
|
}
|
|
else if (overlapInfo.ColliderHitCount > 1)
|
|
{
|
|
targetPosition = DepenetrateMultiple(overlapInfo, data, basePosition, targetPosition, probeGrounding, maxSteps, resolverIterations);
|
|
}
|
|
|
|
RecalculateGroundProperties(data);
|
|
if (resolveTriggers)
|
|
{
|
|
for (int i = 0; i < overlapInfo.TriggerHitCount; i++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit = overlapInfo.TriggerHits[i];
|
|
kCCOverlapHit.Transform.GetPositionAndRotation(out kCCOverlapHit.CachedPosition, out kCCOverlapHit.CachedRotation);
|
|
kCCOverlapHit.CollisionType = ((kCCOverlapHit.IsWithinExtent = (kCCOverlapHit.HasPenetration = Physics.ComputePenetration(_collider.Collider, data.TargetPosition, Quaternion.identity, kCCOverlapHit.Collider, kCCOverlapHit.CachedPosition, kCCOverlapHit.CachedRotation, out var _, out var distance))) ? ECollisionType.Trigger : ECollisionType.None);
|
|
if (distance > kCCOverlapHit.MaxPenetration)
|
|
{
|
|
kCCOverlapHit.MaxPenetration = distance;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_settings.SuppressConvexMeshColliders)
|
|
{
|
|
overlapInfo.ToggleConvexMeshColliders(convex: true);
|
|
}
|
|
|
|
return targetPosition;
|
|
}
|
|
|
|
private Vector3 DepenetrateSingle(KCCOverlapInfo overlapInfo, KCCData data, Vector3 basePosition, Vector3 targetPosition, bool probeGrounding, int maxSteps)
|
|
{
|
|
float num = Mathf.Cos(Mathf.Clamp(data.MaxGroundAngle, 0f, 90f) * (MathF.PI / 180f));
|
|
float num2 = 0f - Mathf.Cos(Mathf.Clamp(90f - data.MaxWallAngle, 0f, 90f) * (MathF.PI / 180f));
|
|
float num3 = 0f - Mathf.Cos(Mathf.Clamp(90f - data.MaxHangAngle, 0f, 90f) * (MathF.PI / 180f));
|
|
Vector3 vector = Vector3.up;
|
|
float num4 = 0f;
|
|
KCCOverlapHit kCCOverlapHit = overlapInfo.ColliderHits[0];
|
|
kCCOverlapHit.UpDirectionDot = float.MinValue;
|
|
kCCOverlapHit.Transform.GetPositionAndRotation(out kCCOverlapHit.CachedPosition, out kCCOverlapHit.CachedRotation);
|
|
if (maxSteps > 1)
|
|
{
|
|
float num5 = 0.001f;
|
|
float num6 = Vector3.Distance(basePosition, targetPosition);
|
|
if (num6 < (float)maxSteps * num5)
|
|
{
|
|
maxSteps = Mathf.Max(1, (int)(num6 / num5));
|
|
}
|
|
}
|
|
|
|
if (maxSteps <= 1)
|
|
{
|
|
kCCOverlapHit.HasPenetration = Physics.ComputePenetration(_collider.Collider, targetPosition, Quaternion.identity, kCCOverlapHit.Collider, kCCOverlapHit.CachedPosition, kCCOverlapHit.CachedRotation, out var direction, out var distance);
|
|
if (kCCOverlapHit.HasPenetration)
|
|
{
|
|
kCCOverlapHit.IsWithinExtent = true;
|
|
if (distance > kCCOverlapHit.MaxPenetration)
|
|
{
|
|
kCCOverlapHit.MaxPenetration = distance;
|
|
}
|
|
|
|
float num7 = Vector3.Dot(direction, Vector3.up);
|
|
if (num7 > kCCOverlapHit.UpDirectionDot)
|
|
{
|
|
kCCOverlapHit.UpDirectionDot = num7;
|
|
if (num7 >= num)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Ground;
|
|
data.IsGrounded = true;
|
|
vector = direction;
|
|
}
|
|
else if (num7 > 0f - num2)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Slope;
|
|
}
|
|
else if (num7 >= num2)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Wall;
|
|
}
|
|
else if (num7 >= num3)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Hang;
|
|
}
|
|
else
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Top;
|
|
}
|
|
}
|
|
|
|
if (num7 > 0f && num7 < num && distance >= 1E-06f && data.DynamicVelocity.y <= 0f && Vector3.Dot((targetPosition - basePosition).OnlyXZ(), direction.OnlyXZ()) < 0f)
|
|
{
|
|
KCCPhysicsUtility.ProjectVerticalPenetration(ref direction, ref distance);
|
|
}
|
|
|
|
targetPosition += direction * distance;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector3 vector2 = (targetPosition - basePosition) / maxSteps;
|
|
Vector3 vector3 = basePosition;
|
|
int num8 = maxSteps;
|
|
while (num8 > 0)
|
|
{
|
|
num8--;
|
|
vector3 += vector2;
|
|
kCCOverlapHit.HasPenetration = Physics.ComputePenetration(_collider.Collider, vector3, Quaternion.identity, kCCOverlapHit.Collider, kCCOverlapHit.CachedPosition, kCCOverlapHit.CachedRotation, out var direction2, out var distance2);
|
|
if (!kCCOverlapHit.HasPenetration)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
kCCOverlapHit.IsWithinExtent = true;
|
|
if (distance2 > kCCOverlapHit.MaxPenetration)
|
|
{
|
|
kCCOverlapHit.MaxPenetration = distance2;
|
|
}
|
|
|
|
float num9 = Vector3.Dot(direction2, Vector3.up);
|
|
if (num9 > kCCOverlapHit.UpDirectionDot)
|
|
{
|
|
kCCOverlapHit.UpDirectionDot = num9;
|
|
if (num9 >= num)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Ground;
|
|
data.IsGrounded = true;
|
|
vector = direction2;
|
|
}
|
|
else if (num9 > 0f - num2)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Slope;
|
|
}
|
|
else if (num9 >= num2)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Wall;
|
|
}
|
|
else if (num9 >= num3)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Hang;
|
|
}
|
|
else
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Top;
|
|
}
|
|
}
|
|
|
|
if (num9 > 0f && num9 < num && distance2 >= 1E-06f && data.DynamicVelocity.y <= 0f && Vector3.Dot(vector2.OnlyXZ(), direction2.OnlyXZ()) < 0f)
|
|
{
|
|
KCCPhysicsUtility.ProjectVerticalPenetration(ref direction2, ref distance2);
|
|
}
|
|
|
|
vector3 += direction2 * distance2;
|
|
}
|
|
|
|
targetPosition = vector3;
|
|
}
|
|
|
|
if (kCCOverlapHit.UpDirectionDot == float.MinValue)
|
|
{
|
|
kCCOverlapHit.UpDirectionDot = 0f;
|
|
}
|
|
|
|
if (probeGrounding && !data.IsGrounded)
|
|
{
|
|
if (KCCPhysicsUtility.CheckGround(_collider.Collider, targetPosition, kCCOverlapHit.Collider, kCCOverlapHit.CachedPosition, kCCOverlapHit.CachedRotation, _settings.Radius, _settings.Height, _settings.Extent, num, out var groundNormal, out var groundDistance, out var isWithinExtent))
|
|
{
|
|
data.IsGrounded = true;
|
|
vector = groundNormal;
|
|
num4 = groundDistance;
|
|
kCCOverlapHit.IsWithinExtent = true;
|
|
kCCOverlapHit.CollisionType = ECollisionType.Ground;
|
|
}
|
|
else if (isWithinExtent)
|
|
{
|
|
kCCOverlapHit.IsWithinExtent = true;
|
|
if (kCCOverlapHit.CollisionType == ECollisionType.None)
|
|
{
|
|
kCCOverlapHit.CollisionType = ECollisionType.Slope;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data.IsGrounded)
|
|
{
|
|
data.GroundNormal = vector;
|
|
data.GroundAngle = Vector3.Angle(vector, Vector3.up);
|
|
data.GroundPosition = targetPosition + new Vector3(0f, _settings.Radius, 0f) - vector * (_settings.Radius + num4);
|
|
data.GroundDistance = num4;
|
|
}
|
|
|
|
return targetPosition;
|
|
}
|
|
|
|
private Vector3 DepenetrateMultiple(KCCOverlapInfo overlapInfo, KCCData data, Vector3 basePosition, Vector3 targetPosition, bool probeGrounding, int maxSteps, int resolverIterations)
|
|
{
|
|
float num = Mathf.Cos(Mathf.Clamp(data.MaxGroundAngle, 0f, 90f) * (MathF.PI / 180f));
|
|
float num2 = 0f - Mathf.Cos(Mathf.Clamp(90f - data.MaxWallAngle, 0f, 90f) * (MathF.PI / 180f));
|
|
float num3 = 0f - Mathf.Cos(Mathf.Clamp(90f - data.MaxHangAngle, 0f, 90f) * (MathF.PI / 180f));
|
|
float num4 = 0f;
|
|
float num5 = 0f;
|
|
Vector3 other = default(Vector3);
|
|
Vector3 vector = default(Vector3);
|
|
Vector3 lhs = (targetPosition - basePosition).OnlyXZ();
|
|
for (int i = 0; i < overlapInfo.ColliderHitCount; i++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit = overlapInfo.ColliderHits[i];
|
|
kCCOverlapHit.UpDirectionDot = float.MinValue;
|
|
kCCOverlapHit.Transform.GetPositionAndRotation(out kCCOverlapHit.CachedPosition, out kCCOverlapHit.CachedRotation);
|
|
}
|
|
|
|
if (maxSteps > 1)
|
|
{
|
|
float num6 = 0.001f;
|
|
float num7 = Vector3.Distance(basePosition, targetPosition);
|
|
if (num7 < (float)maxSteps * num6)
|
|
{
|
|
maxSteps = Mathf.Max(1, (int)(num7 / num6));
|
|
}
|
|
}
|
|
|
|
if (maxSteps <= 1)
|
|
{
|
|
_resolver.Reset();
|
|
for (int j = 0; j < overlapInfo.ColliderHitCount; j++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit2 = overlapInfo.ColliderHits[j];
|
|
kCCOverlapHit2.HasPenetration = Physics.ComputePenetration(_collider.Collider, targetPosition, Quaternion.identity, kCCOverlapHit2.Collider, kCCOverlapHit2.CachedPosition, kCCOverlapHit2.CachedRotation, out var direction, out var distance);
|
|
if (!kCCOverlapHit2.HasPenetration)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
kCCOverlapHit2.IsWithinExtent = true;
|
|
if (distance > kCCOverlapHit2.MaxPenetration)
|
|
{
|
|
kCCOverlapHit2.MaxPenetration = distance;
|
|
}
|
|
|
|
float num8 = Vector3.Dot(direction, Vector3.up);
|
|
if (num8 > kCCOverlapHit2.UpDirectionDot)
|
|
{
|
|
kCCOverlapHit2.UpDirectionDot = num8;
|
|
if (num8 >= num)
|
|
{
|
|
kCCOverlapHit2.CollisionType = ECollisionType.Ground;
|
|
data.IsGrounded = true;
|
|
if (num8 >= num5)
|
|
{
|
|
num5 = num8;
|
|
other = direction;
|
|
}
|
|
|
|
vector += direction * num8;
|
|
}
|
|
else if (num8 > 0f - num2)
|
|
{
|
|
kCCOverlapHit2.CollisionType = ECollisionType.Slope;
|
|
}
|
|
else if (num8 >= num2)
|
|
{
|
|
kCCOverlapHit2.CollisionType = ECollisionType.Wall;
|
|
}
|
|
else if (num8 >= num3)
|
|
{
|
|
kCCOverlapHit2.CollisionType = ECollisionType.Hang;
|
|
}
|
|
else
|
|
{
|
|
kCCOverlapHit2.CollisionType = ECollisionType.Top;
|
|
}
|
|
}
|
|
|
|
if (num8 > 0f && num8 < num && distance >= 1E-06f && data.DynamicVelocity.y <= 0f && Vector3.Dot(lhs, direction.OnlyXZ()) < 0f)
|
|
{
|
|
KCCPhysicsUtility.ProjectVerticalPenetration(ref direction, ref distance);
|
|
}
|
|
|
|
_resolver.AddCorrection(direction, distance);
|
|
}
|
|
|
|
int num9 = Mathf.Max(0, resolverIterations);
|
|
float num10 = 1f - (float)Mathf.Min(num9, 2) * 0.25f;
|
|
if (_resolver.Size == 2)
|
|
{
|
|
_resolver.GetCorrection(0, out var direction2);
|
|
_resolver.GetCorrection(1, out var direction3);
|
|
if (Vector3.Dot(direction2, direction3) >= 0f)
|
|
{
|
|
targetPosition += _resolver.CalculateMinMax() * num10;
|
|
}
|
|
else
|
|
{
|
|
targetPosition += _resolver.CalculateBinary() * num10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
targetPosition += _resolver.CalculateGradientDescent(12, 0.0001f) * num10;
|
|
}
|
|
|
|
while (num9 > 0)
|
|
{
|
|
num9--;
|
|
_resolver.Reset();
|
|
for (int k = 0; k < overlapInfo.ColliderHitCount; k++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit3 = overlapInfo.ColliderHits[k];
|
|
if (!Physics.ComputePenetration(_collider.Collider, targetPosition, Quaternion.identity, kCCOverlapHit3.Collider, kCCOverlapHit3.CachedPosition, kCCOverlapHit3.CachedRotation, out var direction4, out var distance2))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
kCCOverlapHit3.IsWithinExtent = true;
|
|
kCCOverlapHit3.HasPenetration = true;
|
|
if (distance2 > kCCOverlapHit3.MaxPenetration)
|
|
{
|
|
kCCOverlapHit3.MaxPenetration = distance2;
|
|
}
|
|
|
|
float num11 = Vector3.Dot(direction4, Vector3.up);
|
|
if (num11 > kCCOverlapHit3.UpDirectionDot)
|
|
{
|
|
kCCOverlapHit3.UpDirectionDot = num11;
|
|
if (num11 >= num)
|
|
{
|
|
kCCOverlapHit3.CollisionType = ECollisionType.Ground;
|
|
data.IsGrounded = true;
|
|
if (num11 >= num5)
|
|
{
|
|
num5 = num11;
|
|
other = direction4;
|
|
}
|
|
|
|
vector += direction4 * num11;
|
|
}
|
|
else if (num11 > 0f - num2)
|
|
{
|
|
kCCOverlapHit3.CollisionType = ECollisionType.Slope;
|
|
}
|
|
else if (num11 >= num2)
|
|
{
|
|
kCCOverlapHit3.CollisionType = ECollisionType.Wall;
|
|
}
|
|
else if (num11 >= num3)
|
|
{
|
|
kCCOverlapHit3.CollisionType = ECollisionType.Hang;
|
|
}
|
|
else
|
|
{
|
|
kCCOverlapHit3.CollisionType = ECollisionType.Top;
|
|
}
|
|
}
|
|
|
|
if (num11 > 0f && num11 < num && distance2 >= 1E-06f && data.DynamicVelocity.y <= 0f && Vector3.Dot(lhs, direction4.OnlyXZ()) < 0f)
|
|
{
|
|
KCCPhysicsUtility.ProjectVerticalPenetration(ref direction4, ref distance2);
|
|
}
|
|
|
|
_resolver.AddCorrection(direction4, distance2);
|
|
}
|
|
|
|
if (_resolver.Size == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch (num9)
|
|
{
|
|
case 0:
|
|
if (_resolver.Size == 2)
|
|
{
|
|
_resolver.GetCorrection(0, out var direction5);
|
|
_resolver.GetCorrection(1, out var direction6);
|
|
if (Vector3.Dot(direction5, direction6) >= 0f)
|
|
{
|
|
targetPosition += _resolver.CalculateGradientDescent(12, 0.0001f);
|
|
}
|
|
else
|
|
{
|
|
targetPosition += _resolver.CalculateBinary();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
targetPosition += _resolver.CalculateGradientDescent(12, 0.0001f);
|
|
}
|
|
|
|
break;
|
|
case 1:
|
|
targetPosition += _resolver.CalculateMinMax() * 0.75f;
|
|
break;
|
|
default:
|
|
targetPosition += _resolver.CalculateMinMax() * 0.5f;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector3 vector2 = (targetPosition - basePosition) / maxSteps;
|
|
Vector3 vector3 = basePosition;
|
|
int num12 = maxSteps;
|
|
while (num12 > 1)
|
|
{
|
|
num12--;
|
|
vector3 += vector2;
|
|
_resolver.Reset();
|
|
for (int l = 0; l < overlapInfo.ColliderHitCount; l++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit4 = overlapInfo.ColliderHits[l];
|
|
kCCOverlapHit4.HasPenetration = Physics.ComputePenetration(_collider.Collider, vector3, Quaternion.identity, kCCOverlapHit4.Collider, kCCOverlapHit4.CachedPosition, kCCOverlapHit4.CachedRotation, out var direction7, out var distance3);
|
|
if (!kCCOverlapHit4.HasPenetration)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
kCCOverlapHit4.IsWithinExtent = true;
|
|
if (distance3 > kCCOverlapHit4.MaxPenetration)
|
|
{
|
|
kCCOverlapHit4.MaxPenetration = distance3;
|
|
}
|
|
|
|
float num13 = Vector3.Dot(direction7, Vector3.up);
|
|
if (num13 > kCCOverlapHit4.UpDirectionDot)
|
|
{
|
|
kCCOverlapHit4.UpDirectionDot = num13;
|
|
if (num13 >= num)
|
|
{
|
|
kCCOverlapHit4.CollisionType = ECollisionType.Ground;
|
|
data.IsGrounded = true;
|
|
if (num13 >= num5)
|
|
{
|
|
num5 = num13;
|
|
other = direction7;
|
|
}
|
|
|
|
vector += direction7 * num13;
|
|
}
|
|
else if (num13 > 0f - num2)
|
|
{
|
|
kCCOverlapHit4.CollisionType = ECollisionType.Slope;
|
|
}
|
|
else if (num13 >= num2)
|
|
{
|
|
kCCOverlapHit4.CollisionType = ECollisionType.Wall;
|
|
}
|
|
else if (num13 >= num3)
|
|
{
|
|
kCCOverlapHit4.CollisionType = ECollisionType.Hang;
|
|
}
|
|
else
|
|
{
|
|
kCCOverlapHit4.CollisionType = ECollisionType.Top;
|
|
}
|
|
}
|
|
|
|
if (num13 > 0f && num13 < num && distance3 >= 1E-06f && data.DynamicVelocity.y <= 0f && Vector3.Dot(vector2.OnlyXZ(), direction7.OnlyXZ()) < 0f)
|
|
{
|
|
KCCPhysicsUtility.ProjectVerticalPenetration(ref direction7, ref distance3);
|
|
}
|
|
|
|
_resolver.AddCorrection(direction7, distance3);
|
|
}
|
|
|
|
if (_resolver.Size == 2)
|
|
{
|
|
_resolver.GetCorrection(0, out var direction8);
|
|
_resolver.GetCorrection(1, out var direction9);
|
|
if (Vector3.Dot(direction8, direction9) >= 0f)
|
|
{
|
|
vector3 += _resolver.CalculateMinMax();
|
|
}
|
|
else
|
|
{
|
|
vector3 += _resolver.CalculateBinary();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vector3 += _resolver.CalculateMinMax();
|
|
}
|
|
}
|
|
|
|
num12--;
|
|
vector3 += vector2;
|
|
_resolver.Reset();
|
|
for (int m = 0; m < overlapInfo.ColliderHitCount; m++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit5 = overlapInfo.ColliderHits[m];
|
|
kCCOverlapHit5.HasPenetration = Physics.ComputePenetration(_collider.Collider, vector3, Quaternion.identity, kCCOverlapHit5.Collider, kCCOverlapHit5.CachedPosition, kCCOverlapHit5.CachedRotation, out var direction10, out var distance4);
|
|
if (!kCCOverlapHit5.HasPenetration)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
kCCOverlapHit5.IsWithinExtent = true;
|
|
if (distance4 > kCCOverlapHit5.MaxPenetration)
|
|
{
|
|
kCCOverlapHit5.MaxPenetration = distance4;
|
|
}
|
|
|
|
float num14 = Vector3.Dot(direction10, Vector3.up);
|
|
if (num14 > kCCOverlapHit5.UpDirectionDot)
|
|
{
|
|
kCCOverlapHit5.UpDirectionDot = num14;
|
|
if (num14 >= num)
|
|
{
|
|
kCCOverlapHit5.CollisionType = ECollisionType.Ground;
|
|
data.IsGrounded = true;
|
|
if (num14 >= num5)
|
|
{
|
|
num5 = num14;
|
|
other = direction10;
|
|
}
|
|
|
|
vector += direction10 * num14;
|
|
}
|
|
else if (num14 > 0f - num2)
|
|
{
|
|
kCCOverlapHit5.CollisionType = ECollisionType.Slope;
|
|
}
|
|
else if (num14 >= num2)
|
|
{
|
|
kCCOverlapHit5.CollisionType = ECollisionType.Wall;
|
|
}
|
|
else if (num14 >= num3)
|
|
{
|
|
kCCOverlapHit5.CollisionType = ECollisionType.Hang;
|
|
}
|
|
else
|
|
{
|
|
kCCOverlapHit5.CollisionType = ECollisionType.Top;
|
|
}
|
|
}
|
|
|
|
if (num14 > 0f && num14 < num && distance4 >= 1E-06f && data.DynamicVelocity.y <= 0f && Vector3.Dot(vector2.OnlyXZ(), direction10.OnlyXZ()) < 0f)
|
|
{
|
|
KCCPhysicsUtility.ProjectVerticalPenetration(ref direction10, ref distance4);
|
|
}
|
|
|
|
_resolver.AddCorrection(direction10, distance4);
|
|
}
|
|
|
|
if (_resolver.Size == 2)
|
|
{
|
|
_resolver.GetCorrection(0, out var direction11);
|
|
_resolver.GetCorrection(1, out var direction12);
|
|
if (Vector3.Dot(direction11, direction12) >= 0f)
|
|
{
|
|
vector3 += _resolver.CalculateMinMax();
|
|
}
|
|
else
|
|
{
|
|
vector3 += _resolver.CalculateBinary();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vector3 += _resolver.CalculateGradientDescent(12, 0.0001f);
|
|
}
|
|
|
|
targetPosition = vector3;
|
|
}
|
|
|
|
for (int n = 0; n < overlapInfo.ColliderHitCount; n++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit6 = overlapInfo.ColliderHits[n];
|
|
if (kCCOverlapHit6.UpDirectionDot == float.MinValue)
|
|
{
|
|
kCCOverlapHit6.UpDirectionDot = 0f;
|
|
}
|
|
}
|
|
|
|
if (probeGrounding && !data.IsGrounded)
|
|
{
|
|
Vector3 vector4 = Vector3.up;
|
|
float num15 = 1000f;
|
|
for (int num16 = 0; num16 < overlapInfo.ColliderHitCount; num16++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit7 = overlapInfo.ColliderHits[num16];
|
|
if (KCCPhysicsUtility.CheckGround(_collider.Collider, targetPosition, kCCOverlapHit7.Collider, kCCOverlapHit7.CachedPosition, kCCOverlapHit7.CachedRotation, _settings.Radius, _settings.Height, _settings.Extent, num, out var groundNormal, out var groundDistance, out var isWithinExtent))
|
|
{
|
|
data.IsGrounded = true;
|
|
if (groundDistance < num15)
|
|
{
|
|
vector4 = groundNormal;
|
|
num15 = groundDistance;
|
|
}
|
|
|
|
kCCOverlapHit7.IsWithinExtent = true;
|
|
kCCOverlapHit7.CollisionType = ECollisionType.Ground;
|
|
}
|
|
else if (isWithinExtent)
|
|
{
|
|
kCCOverlapHit7.IsWithinExtent = true;
|
|
if (kCCOverlapHit7.CollisionType == ECollisionType.None)
|
|
{
|
|
kCCOverlapHit7.CollisionType = ECollisionType.Slope;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data.IsGrounded)
|
|
{
|
|
other = vector4;
|
|
vector = vector4;
|
|
num4 = num15;
|
|
}
|
|
}
|
|
|
|
if (data.IsGrounded)
|
|
{
|
|
if (!vector.IsEqual(other))
|
|
{
|
|
vector.Normalize();
|
|
}
|
|
|
|
data.GroundNormal = vector;
|
|
data.GroundAngle = Vector3.Angle(data.GroundNormal, Vector3.up);
|
|
data.GroundPosition = targetPosition + new Vector3(0f, _settings.Radius, 0f) - data.GroundNormal * (_settings.Radius + num4);
|
|
data.GroundDistance = num4;
|
|
}
|
|
|
|
return targetPosition;
|
|
}
|
|
|
|
private static void RecalculateGroundProperties(KCCData data)
|
|
{
|
|
if (data.IsGrounded)
|
|
{
|
|
Vector3 projectedVector2;
|
|
if (KCCPhysicsUtility.ProjectOnGround(data.GroundNormal, data.GroundNormal.OnlyXZ(), out var projectedVector))
|
|
{
|
|
data.GroundTangent = projectedVector.normalized;
|
|
}
|
|
else if (KCCPhysicsUtility.ProjectOnGround(data.GroundNormal, data.DesiredVelocity.OnlyXZ(), out projectedVector2))
|
|
{
|
|
data.GroundTangent = projectedVector2.normalized;
|
|
}
|
|
else
|
|
{
|
|
data.GroundTangent = data.TransformDirection;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetActive(bool isActive) => _fixedData.IsActive = isActive;
|
|
|
|
public Vector2 GetLookRotation(bool pitch = true, bool yaw = true) => Data.GetLookRotation(pitch, yaw);
|
|
|
|
public void AddLookRotation(float pitchDelta, float yawDelta)
|
|
{
|
|
KCCData kCCData = _fixedData;
|
|
kCCData.AddLookRotation(pitchDelta, yawDelta);
|
|
SynchronizeTransform(kCCData, synchronizePosition: false, synchronizeRotation: true, allowAntiJitter: false);
|
|
}
|
|
|
|
public void AddLookRotation(float pitchDelta, float yawDelta, float minPitch, float maxPitch)
|
|
{
|
|
KCCData kCCData = _fixedData;
|
|
kCCData.AddLookRotation(pitchDelta, yawDelta, minPitch, maxPitch);
|
|
SynchronizeTransform(kCCData, synchronizePosition: false, synchronizeRotation: true, allowAntiJitter: false);
|
|
}
|
|
|
|
public void AddLookRotation(Vector2 lookRotationDelta)
|
|
{
|
|
AddLookRotation(lookRotationDelta.x, lookRotationDelta.y);
|
|
}
|
|
|
|
public void AddLookRotation(Vector2 lookRotationDelta, float minPitch, float maxPitch)
|
|
{
|
|
AddLookRotation(lookRotationDelta.x, lookRotationDelta.y, minPitch, maxPitch);
|
|
}
|
|
|
|
public void SetLookRotation(float pitch, float yaw)
|
|
{
|
|
KCCData kCCData = _fixedData;
|
|
kCCData.SetLookRotation(pitch, yaw);
|
|
SynchronizeTransform(kCCData, synchronizePosition: false, synchronizeRotation: true, allowAntiJitter: false);
|
|
}
|
|
|
|
public void SetLookRotation(Vector2 lookRotation) => SetLookRotation(lookRotation.x, lookRotation.y);
|
|
|
|
public void SetLookRotation(Quaternion lookRotation, bool preservePitch = false, bool preserveYaw = false)
|
|
{
|
|
KCCData kCCData = _fixedData;
|
|
kCCData.SetLookRotation(lookRotation, preservePitch, preserveYaw);
|
|
SynchronizeTransform(kCCData, synchronizePosition: false, synchronizeRotation: true, allowAntiJitter: false);
|
|
}
|
|
|
|
public void SetPosition(Vector3 position)
|
|
{
|
|
KCCData kCCData = _fixedData;
|
|
kCCData.BasePosition = position;
|
|
kCCData.DesiredPosition = position;
|
|
kCCData.TargetPosition = position;
|
|
kCCData.HasTeleported = true;
|
|
kCCData.IsSteppingUp = false;
|
|
kCCData.IsSnappingToGround = false;
|
|
SynchronizeTransform(kCCData, synchronizePosition: true, synchronizeRotation: false, allowAntiJitter: false);
|
|
}
|
|
|
|
public void SetShape(EKCCShape shape, float radius = 0f, float height = 0f)
|
|
{
|
|
_settings.Shape = shape;
|
|
if (radius > 0f)
|
|
{
|
|
_settings.Radius = radius;
|
|
}
|
|
|
|
if (height > 0f)
|
|
{
|
|
_settings.Height = height;
|
|
}
|
|
|
|
RefreshCollider();
|
|
}
|
|
|
|
public void SetTrigger(bool isTrigger)
|
|
{
|
|
_settings.IsTrigger = isTrigger;
|
|
RefreshCollider();
|
|
}
|
|
|
|
public void SetRadius(float radius)
|
|
{
|
|
if (!(radius <= 0f))
|
|
{
|
|
_settings.Radius = radius;
|
|
RefreshCollider();
|
|
}
|
|
}
|
|
|
|
public void SetHeight(float height)
|
|
{
|
|
if (!(height <= 0f))
|
|
{
|
|
_settings.Height = height;
|
|
RefreshCollider();
|
|
}
|
|
}
|
|
|
|
public void SetColliderLayer(int layer)
|
|
{
|
|
_settings.ColliderLayer = layer;
|
|
RefreshCollider();
|
|
}
|
|
|
|
public void SetCollisionLayerMask(LayerMask layerMask)
|
|
{
|
|
_settings.CollisionLayerMask = layerMask;
|
|
}
|
|
|
|
private void RestoreHistoryData(KCCData historyData)
|
|
{
|
|
if (_fixedData.IsGrounded)
|
|
{
|
|
_fixedData.IsGrounded = historyData.IsGrounded;
|
|
_fixedData.WasGrounded = historyData.WasGrounded;
|
|
}
|
|
}
|
|
|
|
internal bool SphereOverlap(KCCOverlapInfo overlapInfo, Vector3 position, float radius, QueryTriggerInteraction triggerInteraction)
|
|
{
|
|
return SphereOverlap(overlapInfo, Data, position, radius, 0f, _settings.CollisionLayerMask, triggerInteraction);
|
|
}
|
|
|
|
internal bool CapsuleOverlap(KCCOverlapInfo overlapInfo, Vector3 position, float radius, float height, QueryTriggerInteraction triggerInteraction)
|
|
{
|
|
return CapsuleOverlap(overlapInfo, Data, position, radius, height, 0f, _settings.CollisionLayerMask, triggerInteraction);
|
|
}
|
|
|
|
internal bool RayCast(KCCShapeCastInfo shapeCastInfo, Vector3 position, Vector3 direction, float maxDistance, QueryTriggerInteraction triggerInteraction)
|
|
{
|
|
return RayCast(shapeCastInfo, Data, position, direction, maxDistance, _settings.CollisionLayerMask, triggerInteraction);
|
|
}
|
|
|
|
internal bool SphereCast(KCCShapeCastInfo shapeCastInfo, Vector3 position, float radius, Vector3 direction, float maxDistance, QueryTriggerInteraction triggerInteraction, bool trackInitialOverlaps = true)
|
|
{
|
|
return SphereCast(shapeCastInfo, Data, position, radius, 0f, direction, maxDistance, _settings.CollisionLayerMask, triggerInteraction, trackInitialOverlaps);
|
|
}
|
|
|
|
internal bool CapsuleCast(KCCShapeCastInfo shapeCastInfo, Vector3 position, float radius, float height, Vector3 direction, float maxDistance, QueryTriggerInteraction triggerInteraction, bool trackInitialOverlaps = true)
|
|
{
|
|
return CapsuleCast(shapeCastInfo, Data, position, radius, height, 0f, direction, maxDistance, _settings.CollisionLayerMask, triggerInteraction, trackInitialOverlaps);
|
|
}
|
|
|
|
internal void UpdateHits(KCCOverlapInfo baseOverlapInfo, EKCCHitsOverlapQuery overlapQuery)
|
|
{
|
|
UpdateHits(Data, baseOverlapInfo, overlapQuery);
|
|
}
|
|
|
|
internal bool IsValidHitCollider(Collider hitCollider)
|
|
{
|
|
if (hitCollider == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return IsValidHitCollider(Data, hitCollider);
|
|
}
|
|
|
|
private bool SphereOverlap(KCCOverlapInfo overlapInfo, KCCData data, Vector3 position, float radius, float extent, LayerMask layerMask, QueryTriggerInteraction triggerInteraction)
|
|
{
|
|
overlapInfo.Reset(deep: false);
|
|
overlapInfo.Position = position;
|
|
overlapInfo.Radius = radius;
|
|
overlapInfo.Height = 0f;
|
|
overlapInfo.Extent = extent;
|
|
overlapInfo.LayerMask = layerMask;
|
|
overlapInfo.TriggerInteraction = triggerInteraction;
|
|
// Collider[] hitColliders = _hitColliders;
|
|
Collider[] hitColliders = Physics.OverlapSphere(position, radius + extent, layerMask, triggerInteraction);
|
|
for (int i = 0; i < hitColliders.Length; i++)
|
|
{
|
|
Collider overlapCollider = hitColliders[i];
|
|
if (IsValidHitColliderUnsafe(data, overlapCollider))
|
|
{
|
|
overlapInfo.AddHit(overlapCollider);
|
|
}
|
|
}
|
|
|
|
return overlapInfo.AllHitCount > 0;
|
|
}
|
|
|
|
private bool CapsuleOverlap(KCCOverlapInfo overlapInfo, KCCData data, Vector3 position, float radius, float height, float extent, LayerMask layerMask, QueryTriggerInteraction triggerInteraction)
|
|
{
|
|
overlapInfo.Reset(deep: false);
|
|
overlapInfo.Position = position;
|
|
overlapInfo.Radius = radius;
|
|
overlapInfo.Height = height;
|
|
overlapInfo.Extent = extent;
|
|
overlapInfo.LayerMask = layerMask;
|
|
overlapInfo.TriggerInteraction = triggerInteraction;
|
|
Vector3 point = position + new Vector3(0f, height - radius, 0f);
|
|
Vector3 point2 = position + new Vector3(0f, radius, 0f);
|
|
// Collider[] hitColliders = _hitColliders;
|
|
Collider[] hitColliders = Physics.OverlapCapsule(point2, point, radius + extent, layerMask, triggerInteraction);
|
|
for (int i = 0; i < hitColliders.Length; i++)
|
|
{
|
|
Collider overlapCollider = hitColliders[i];
|
|
if (IsValidHitColliderUnsafe(data, overlapCollider))
|
|
{
|
|
overlapInfo.AddHit(overlapCollider);
|
|
}
|
|
}
|
|
|
|
return overlapInfo.AllHitCount > 0;
|
|
}
|
|
|
|
private bool RayCast(KCCShapeCastInfo shapeCastInfo, KCCData data, Vector3 position, Vector3 direction, float maxDistance, LayerMask layerMask, QueryTriggerInteraction triggerInteraction)
|
|
{
|
|
shapeCastInfo.Reset(deep: false);
|
|
shapeCastInfo.Position = position;
|
|
shapeCastInfo.Direction = direction;
|
|
shapeCastInfo.MaxDistance = maxDistance;
|
|
shapeCastInfo.LayerMask = layerMask;
|
|
shapeCastInfo.TriggerInteraction = triggerInteraction;
|
|
// RaycastHit[] raycastHits = _raycastHits;
|
|
// if(Physics.Raycast(position, direction, out RaycastHit hit, maxDistance, layerMask, triggerInteraction))
|
|
// // int num = base.Runner.GetPhysicsScene().Raycast(position, direction, raycastHits, maxDistance, layerMask, triggerInteraction);
|
|
// for (int i = 0; i < hit.; i++)
|
|
// {
|
|
// RaycastHit raycastHit = raycastHits[i];
|
|
// if (IsValidHitColliderUnsafe(data, raycastHit.collider))
|
|
// {
|
|
// shapeCastInfo.AddHit(raycastHit);
|
|
// }
|
|
// }
|
|
|
|
// return shapeCastInfo.AllHitCount > 0;
|
|
return Physics.Raycast(position, direction, maxDistance, layerMask, triggerInteraction);
|
|
}
|
|
|
|
private bool SphereCast(KCCShapeCastInfo shapeCastInfo, KCCData data, Vector3 position, float radius, float extent, Vector3 direction, float maxDistance, LayerMask layerMask, QueryTriggerInteraction triggerInteraction, bool trackInitialOverlaps)
|
|
{
|
|
shapeCastInfo.Reset(deep: false);
|
|
shapeCastInfo.Position = position;
|
|
shapeCastInfo.Radius = radius;
|
|
shapeCastInfo.Extent = extent;
|
|
shapeCastInfo.Direction = direction;
|
|
shapeCastInfo.MaxDistance = maxDistance;
|
|
shapeCastInfo.LayerMask = layerMask;
|
|
shapeCastInfo.TriggerInteraction = triggerInteraction;
|
|
RaycastHit[] raycastHits = _raycastHits;
|
|
return Physics.SphereCast(position, radius + extent, direction, out RaycastHit info, maxDistance, layerMask, triggerInteraction);
|
|
|
|
// int num = base.Runner.GetPhysicsScene().SphereCast(position, radius + extent, direction, raycastHits, maxDistance, layerMask, triggerInteraction);
|
|
// for (int i = 0; i < num; i++)
|
|
// {
|
|
// RaycastHit raycastHit = raycastHits[i];
|
|
// if ((trackInitialOverlaps || !(raycastHit.distance <= 0f) || !raycastHit.point.Equals(default(Vector3))) && IsValidHitColliderUnsafe(data, raycastHit.collider))
|
|
// {
|
|
// shapeCastInfo.AddHit(raycastHit);
|
|
// }
|
|
// }
|
|
|
|
// return shapeCastInfo.AllHitCount > 0;
|
|
}
|
|
|
|
private bool CapsuleCast(KCCShapeCastInfo shapeCastInfo, KCCData data, Vector3 position, float radius, float height, float extent, Vector3 direction, float maxDistance, LayerMask layerMask, QueryTriggerInteraction triggerInteraction, bool trackInitialOverlaps)
|
|
{
|
|
shapeCastInfo.Reset(deep: false);
|
|
shapeCastInfo.Position = position;
|
|
shapeCastInfo.Radius = radius;
|
|
shapeCastInfo.Height = height;
|
|
shapeCastInfo.Extent = extent;
|
|
shapeCastInfo.Position = position;
|
|
shapeCastInfo.Direction = direction;
|
|
shapeCastInfo.MaxDistance = maxDistance;
|
|
shapeCastInfo.LayerMask = layerMask;
|
|
shapeCastInfo.TriggerInteraction = triggerInteraction;
|
|
Vector3 point = position + new Vector3(0f, height - radius, 0f);
|
|
Vector3 point2 = position + new Vector3(0f, radius, 0f);
|
|
// RaycastHit[] raycastHits = _raycastHits;
|
|
|
|
return Physics.CapsuleCast(point2, point, radius + extent, direction, out RaycastHit info, maxDistance, layerMask, triggerInteraction);
|
|
|
|
// int num = base.Runner.GetPhysicsScene().CapsuleCast(point2, point, radius + extent, direction, raycastHits, maxDistance, layerMask, triggerInteraction);
|
|
// for (int i = 0; i < num; i++)
|
|
// {
|
|
// RaycastHit raycastHit = raycastHits[i];
|
|
// if ((trackInitialOverlaps || !(raycastHit.distance <= 0f) || !raycastHit.point.Equals(default(Vector3))) && IsValidHitColliderUnsafe(data, raycastHit.collider))
|
|
// {
|
|
// shapeCastInfo.AddHit(raycastHit);
|
|
// }
|
|
// }
|
|
|
|
// return shapeCastInfo.AllHitCount > 0;
|
|
}
|
|
|
|
private void UpdateHits(KCCData data, KCCOverlapInfo baseOverlapInfo, EKCCHitsOverlapQuery overlapQuery)
|
|
{
|
|
if (overlapQuery switch
|
|
{
|
|
EKCCHitsOverlapQuery.Default => baseOverlapInfo?.AllHitsWithinExtent() ?? false,
|
|
EKCCHitsOverlapQuery.Reuse => baseOverlapInfo != null,
|
|
EKCCHitsOverlapQuery.New => false,
|
|
_ => throw new NotImplementedException("overlapQuery"),
|
|
})
|
|
{
|
|
_trackOverlapInfo.CopyFromOther(baseOverlapInfo);
|
|
}
|
|
else
|
|
{
|
|
CapsuleOverlap(_trackOverlapInfo, data, data.TargetPosition, _settings.Radius, _settings.Height, _settings.Extent, _settings.CollisionLayerMask, QueryTriggerInteraction.Collide);
|
|
if (baseOverlapInfo != null)
|
|
{
|
|
for (int i = 0; i < _trackOverlapInfo.AllHitCount; i++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit = _trackOverlapInfo.AllHits[i];
|
|
for (int j = 0; j < baseOverlapInfo.AllHitCount; j++)
|
|
{
|
|
KCCOverlapHit kCCOverlapHit2 = baseOverlapInfo.AllHits[j];
|
|
if ((object)kCCOverlapHit.Collider == kCCOverlapHit2.Collider)
|
|
{
|
|
kCCOverlapHit.CopyFromOther(kCCOverlapHit2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
data.Hits.Clear();
|
|
int k = 0;
|
|
for (int allHitCount = _trackOverlapInfo.AllHitCount; k < allHitCount; k++)
|
|
{
|
|
data.Hits.Add(_trackOverlapInfo.AllHits[k]);
|
|
}
|
|
}
|
|
|
|
private void ForceRemoveAllHits(KCCData data)
|
|
{
|
|
_trackOverlapInfo.Reset(deep: false);
|
|
_extendedOverlapInfo.Reset(deep: false);
|
|
data.Hits.Clear();
|
|
}
|
|
|
|
private bool IsValidHitCollider(KCCData data, Collider hitCollider)
|
|
{
|
|
if (hitCollider == _collider.Collider)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int i = 0;
|
|
for (int count = _childColliders.Count; i < count; i++)
|
|
{
|
|
if (hitCollider == _childColliders[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int num = 1 << hitCollider.gameObject.layer;
|
|
if (((int)_settings.CollisionLayerMask & num) != num)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ResolveCollision != null)
|
|
{
|
|
try
|
|
{
|
|
return ResolveCollision(this, hitCollider);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Debug.LogException(exception);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool IsValidHitColliderUnsafe(KCCData data, Collider overlapCollider)
|
|
{
|
|
if ((object)overlapCollider == _collider.Collider)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int i = 0;
|
|
for (int count = _childColliders.Count; i < count; i++)
|
|
{
|
|
if ((object)overlapCollider == _childColliders[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (ResolveCollision != null)
|
|
{
|
|
try
|
|
{
|
|
return ResolveCollision(this, overlapCollider);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Debug.LogException(exception);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void SetMaxGroundAngle(float maxGroundAngle)
|
|
{
|
|
if (IsSpawned)
|
|
{
|
|
Data.MaxGroundAngle = maxGroundAngle;
|
|
}
|
|
}
|
|
|
|
public void SetGravity(float gravity)
|
|
{
|
|
if (IsSpawned)
|
|
{
|
|
Data.Gravity = Vector3.up * gravity;
|
|
}
|
|
}
|
|
|
|
public void Move(Vector3 kinematicVelocity = default(Vector3), float jumpImpulse = 0f)
|
|
{
|
|
if (IsSpawned)
|
|
{
|
|
if (!IsInFixedUpdate)
|
|
{
|
|
throw new InvalidOperationException("[" + base.name + "] Move can be invoked only from within fixed update!");
|
|
}
|
|
|
|
FixedData.KinematicVelocity = kinematicVelocity;
|
|
FixedData.JumpImpulse += Vector3.up * jumpImpulse;
|
|
ManualFixedUpdate();
|
|
}
|
|
}
|
|
|
|
public bool ProjectOnGround(Vector3 vector, out Vector3 projectedVector)
|
|
{
|
|
KCCData data = Data;
|
|
if (data.IsGrounded)
|
|
{
|
|
return KCCPhysicsUtility.ProjectOnGround(data.GroundNormal, vector, out projectedVector);
|
|
}
|
|
|
|
projectedVector = default(Vector3);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|