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.

2221 lines
86 KiB
C#

2 weeks ago
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Unity.Profiling;
using UnityEngine;
namespace Fusion.Addons.SimpleKCC
{
[DisallowMultipleComponent]
[RequireComponent(typeof(Rigidbody))]
public sealed class KCC : NetworkTRSP, IAfterSpawned, IAfterClientPredictionReset, IBeforeTick, IAfterTick
{
internal const int CACHE_SIZE = 64;
internal const int HISTORY_SIZE = 60;
[SerializeField]
private KCCSettings _settings = new KCCSettings();
private Transform _transform;
private Rigidbody _rigidbody;
private bool _isSpawned;
private bool _isInFixedUpdate;
private KCCCollider _collider = new KCCCollider();
private KCCData _fixedData = new KCCData();
private KCCData _renderData = new KCCData();
private KCCData[] _historyData = new KCCData[60];
private KCCSettings _defaultSettings = new KCCSettings();
private KCCOverlapInfo _extendedOverlapInfo = new KCCOverlapInfo(64);
private KCCOverlapInfo _trackOverlapInfo = new KCCOverlapInfo(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 KCCResolver(64);
private float _lastRenderTime;
private Vector3 _lastRenderPosition;
private Vector3 _lastAntiJitterPosition;
private Vector3 _predictionError;
private static ProfilerMarker _fixedUpdateMarker = new ProfilerMarker("KCC.FixedUpdate");
private static ProfilerMarker _renderUpdateMarker = new ProfilerMarker("KCC.RenderUpdate");
private static ProfilerMarker _restoreStateMarker = new ProfilerMarker("KCC.RestoreState");
private static ProfilerMarker _afterTickMarker = new ProfilerMarker("KCC.AfterTick");
public Func<KCC, Collider, bool> ResolveCollision;
private KCCNetworkContext _networkContext;
private IKCCNetworkProperty[] _networkProperties;
private int _interpolationTick;
private int _interpolationAttempts;
public override int? DynamicWordCount => GetNetworkDataWordCount();
internal bool IsSpawned => _isSpawned;
public bool IsActive => Data.IsActive;
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 Vector3 RealVelocity => Data.RealVelocity;
public bool HasJumped => Data.HasJumped;
public bool IsGrounded => Data.IsGrounded;
public Vector3 GroundNormal => Data.GroundNormal;
internal new KCCData Data
{
get
{
if (!IsInFixedUpdate)
{
return _renderData;
}
return _fixedData;
}
}
internal KCCData FixedData => _fixedData;
internal KCCData RenderData => _renderData;
public KCCSettings Settings => _settings;
public Transform Transform => _transform;
public CapsuleCollider Collider => _collider.Collider;
public Rigidbody Rigidbody => _rigidbody;
internal bool IsInFixedUpdate
{
get
{
if (!_isInFixedUpdate)
{
if (_isSpawned)
{
return base.Runner.Stage != (SimulationStages)0;
}
return false;
}
return true;
}
}
internal bool IsInForwardUpdate
{
get
{
if (_isSpawned && base.Runner.Stage != 0)
{
return base.Runner.IsForward;
}
return false;
}
}
internal bool IsInResimulationUpdate
{
get
{
if (_isSpawned && base.Runner.Stage != 0)
{
return base.Runner.IsResimulation;
}
return false;
}
}
internal Vector3 PredictionError => _predictionError;
private event Action<KCC> _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<KCC> 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();
}
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 override 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 KCCData();
_fixedData.Frame = Time.frameCount;
_fixedData.Tick = base.Runner.Tick.Raw;
_fixedData.Time = base.Runner.SimulationTime;
_fixedData.DeltaTime = base.Runner.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 KCCData();
_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;
}
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
if (_isSpawned)
{
SetDefaults(cleanup: true);
}
}
public override void Render()
{
_renderUpdateMarker.Begin();
OnRenderUpdateInternal();
_renderUpdateMarker.End();
}
void IAfterSpawned.AfterSpawned()
{
_renderData.CopyFromOther(_fixedData);
if (base.Object.IsInSimulation)
{
WriteNetworkData();
}
_isInFixedUpdate = false;
}
void IAfterClientPredictionReset.AfterClientPredictionReset()
{
int num = base.Runner.LatestServerTick;
_restoreStateMarker.Begin();
KCCData kCCData = _historyData[num % 60];
if (kCCData != null && kCCData.Tick == num)
{
_fixedData.CopyFromOther(kCCData);
_fixedData.Frame = Time.frameCount;
}
ReadNetworkData();
if (kCCData != null)
{
RestoreHistoryData(kCCData);
}
RefreshCollider();
if (_fixedData.IsActive)
{
SynchronizeTransform(_fixedData, synchronizePosition: true, synchronizeRotation: true, allowAntiJitter: false);
}
_restoreStateMarker.End();
}
void IBeforeTick.BeforeTick()
{
_isInFixedUpdate = true;
_fixedData.Frame = Time.frameCount;
_fixedData.Tick = base.Runner.Tick.Raw;
_fixedData.Alpha = 0f;
_fixedData.Time = base.Runner.SimulationTime;
_fixedData.DeltaTime = base.Runner.DeltaTime;
_fixedData.UpdateDeltaTime = _fixedData.DeltaTime;
}
void IAfterTick.AfterTick()
{
_afterTickMarker.Begin();
PublishFixedData();
WriteNetworkData();
_isInFixedUpdate = false;
_afterTickMarker.End();
}
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 OnRenderUpdateInternal()
{
if (IsInFixedUpdate)
{
throw new InvalidOperationException("[" + base.name + "] KCC render update called from fixed update! This is not allowed.");
}
int frameCount = Time.frameCount;
float deltaTime = base.Runner.DeltaTime;
_renderData.Frame = frameCount;
if (base.Object.IsInSimulation)
{
_renderData.Tick = base.Runner.Tick;
_renderData.Alpha = base.Runner.LocalAlpha;
float num = _renderData.Time;
_renderData.Time = base.Runner.SimulationTime + _renderData.Alpha * deltaTime;
_renderData.Tick--;
_renderData.Time -= deltaTime;
if (_renderData.Frame == _fixedData.Frame)
{
num -= deltaTime;
}
_renderData.DeltaTime = _renderData.Time - num;
_renderData.UpdateDeltaTime = _renderData.DeltaTime;
UpdatePredictionError();
MoveInterpolated(_renderData);
if (_renderData.IsActive)
{
SynchronizeTransform(_renderData, synchronizePosition: true, synchronizeRotation: true, allowAntiJitter: true);
}
}
else if (_settings.ProxyInterpolationMode == EKCCInterpolationMode.Transform)
{
InterpolateNetworkTransform();
}
else
{
_fixedData.Frame = frameCount;
_fixedData.Tick = base.Object.LastReceiveTick;
_fixedData.Alpha = 1f;
_fixedData.Time = (float)_fixedData.Tick * deltaTime;
_fixedData.DeltaTime = deltaTime;
_fixedData.UpdateDeltaTime = deltaTime;
ReadNetworkData();
InterpolateNetworkData(RenderSource.Interpolated, RenderTimeframe.Remote);
if (_renderData.IsActive)
{
RefreshCollider();
SynchronizeTransform(_renderData, synchronizePosition: true, synchronizeRotation: true, allowAntiJitter: false);
}
}
_lastRenderPosition = _renderData.TargetPosition;
_lastRenderTime = _renderData.Time;
}
private void UpdatePredictionError()
{
if (_renderData.Frame == _fixedData.Frame)
{
KCCData kCCData = GetHistoryData(_renderData.Tick);
if (kCCData != null && _lastRenderTime <= kCCData.Time)
{
for (int i = 0; i < 5; i++)
{
KCCData historyData = GetHistoryData(kCCData.Tick - 1);
if (historyData == null)
{
break;
}
if (_lastRenderTime >= historyData.Time)
{
if (kCCData.HasTeleported || historyData.HasTeleported)
{
_predictionError = default(Vector3);
return;
}
float num = kCCData.Time - historyData.Time;
if (num <= 1E-06f)
{
_predictionError = default(Vector3);
return;
}
float t = (_lastRenderTime - historyData.Time) / num;
Vector3 vector = Vector3.Lerp(historyData.TargetPosition, kCCData.TargetPosition, t);
_predictionError = _lastRenderPosition - vector;
if (_predictionError.sqrMagnitude >= _settings.TeleportThreshold * _settings.TeleportThreshold)
{
_predictionError = default(Vector3);
return;
}
_predictionError = Vector3.Lerp(_predictionError, Vector3.zero, _settings.PredictionCorrectionSpeed * Time.deltaTime);
_renderData.BasePosition += _predictionError;
_renderData.DesiredPosition += _predictionError;
_renderData.TargetPosition += _predictionError;
return;
}
kCCData = historyData;
}
}
}
if (_predictionError.IsAlmostZero(1E-06f))
{
_predictionError = default(Vector3);
return;
}
_renderData.BasePosition -= _predictionError;
_renderData.DesiredPosition -= _predictionError;
_renderData.TargetPosition -= _predictionError;
_predictionError = Vector3.Lerp(_predictionError, Vector3.zero, _settings.PredictionCorrectionSpeed * Time.deltaTime);
_renderData.BasePosition += _predictionError;
_renderData.DesiredPosition += _predictionError;
_renderData.TargetPosition += _predictionError;
}
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 MoveInterpolated(KCCData data)
{
if (!data.IsActive)
{
return;
}
KCCData fixedData = _fixedData;
if (fixedData.HasTeleported)
{
return;
}
KCCData historyData = GetHistoryData(fixedData.Tick - 1);
if (historyData != null)
{
float alpha = data.Alpha;
data.BasePosition = Vector3.Lerp(historyData.BasePosition, fixedData.BasePosition, alpha) + _predictionError;
data.DesiredPosition = Vector3.Lerp(historyData.DesiredPosition, fixedData.DesiredPosition, alpha) + _predictionError;
data.TargetPosition = Vector3.Lerp(historyData.TargetPosition, fixedData.TargetPosition, alpha) + _predictionError;
data.RealVelocity = Vector3.Lerp(historyData.RealVelocity, fixedData.RealVelocity, alpha);
data.RealSpeed = Mathf.Lerp(historyData.RealSpeed, fixedData.RealSpeed, alpha);
if (!_settings.ForcePredictedLookRotation)
{
data.LookPitch = Mathf.Lerp(historyData.LookPitch, fixedData.LookPitch, alpha);
data.LookYaw = KCCUtility.InterpolateRange(historyData.LookYaw, fixedData.LookYaw, -180f, 180f, alpha);
}
}
}
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();
_historyData.Clear();
_extendedOverlapInfo.Reset(deep: true);
_trackOverlapInfo.Reset(deep: true);
_childColliders.Clear();
_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;
}
}
private void PublishFixedData()
{
_renderData.CopyFromOther(_fixedData);
KCCData kCCData = _historyData[_fixedData.Tick % 60];
if (kCCData == null)
{
kCCData = new KCCData();
_historyData[_fixedData.Tick % 60] = kCCData;
}
kCCData.CopyFromOther(_fixedData);
}
public void Log(params object[] messages)
{
KCCUtility.Log(this, null, EKCCLogType.Info, messages);
}
internal void LogWarning(params object[] messages)
{
KCCUtility.Log(this, null, EKCCLogType.Warning, messages);
}
internal void LogError(params object[] messages)
{
KCCUtility.Log(this, null, EKCCLogType.Error, messages);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool CheckSpawned()
{
if (!_isSpawned)
{
LogError("KCC.Spawned() has not been called yet! Use KCC.InvokeOnSpawn() to register a callback.", this);
return false;
}
return true;
}
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)
{
if (CheckSpawned())
{
_renderData.IsActive = isActive;
if (IsInFixedUpdate)
{
_fixedData.IsActive = isActive;
}
}
}
public Vector2 GetLookRotation(bool pitch = true, bool yaw = true)
{
return Data.GetLookRotation(pitch, yaw);
}
public void AddLookRotation(float pitchDelta, float yawDelta)
{
KCCData kCCData = _renderData;
kCCData.AddLookRotation(pitchDelta, yawDelta);
if (IsInFixedUpdate)
{
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 = _renderData;
kCCData.AddLookRotation(pitchDelta, yawDelta, minPitch, maxPitch);
if (IsInFixedUpdate)
{
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 = _renderData;
kCCData.SetLookRotation(pitch, yaw);
if (IsInFixedUpdate)
{
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 = _renderData;
kCCData.SetLookRotation(lookRotation, preservePitch, preserveYaw);
if (IsInFixedUpdate)
{
kCCData = _fixedData;
kCCData.SetLookRotation(lookRotation, preservePitch, preserveYaw);
}
SynchronizeTransform(kCCData, synchronizePosition: false, synchronizeRotation: true, allowAntiJitter: false);
}
public void SetPosition(Vector3 position)
{
KCCData kCCData = _renderData;
kCCData.BasePosition = position;
kCCData.DesiredPosition = position;
kCCData.TargetPosition = position;
kCCData.HasTeleported = true;
kCCData.IsSteppingUp = false;
kCCData.IsSnappingToGround = false;
if (IsInFixedUpdate)
{
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 RenderTimeframe GetInterpolationTimeframe()
{
if (!base.Object.IsInSimulation)
{
return RenderTimeframe.Remote;
}
return RenderTimeframe.Local;
}
private unsafe Vector3 GetNetworkBufferPosition()
{
fixed (int* ptr = &ReinterpretState<int>())
{
return ((NetworkTRSPData*)ptr)->Position + KCCNetworkUtility.ReadVector3(ptr + 14);
}
}
private bool GetInterpolatedNetworkBufferPosition(out Vector3 interpolatedPosition)
{
interpolatedPosition = default(Vector3);
RenderSource renderSource = base.Object.RenderSource;
RenderTimeframe renderTimeframe = base.Object.RenderTimeframe;
base.Object.RenderSource = RenderSource.Interpolated;
base.Object.RenderTimeframe = GetInterpolationTimeframe();
NetworkBehaviourBuffer from;
NetworkBehaviourBuffer to;
float alpha;
bool num = TryGetSnapshotsBuffers(out from, out to, out alpha);
base.Object.RenderSource = renderSource;
base.Object.RenderTimeframe = renderTimeframe;
if (!num)
{
return false;
}
KCCNetworkProperties.ReadPositions(from, to, out var fromTargetPosition, out var toTargetPosition);
interpolatedPosition = Vector3.Lerp(fromTargetPosition, toTargetPosition, alpha);
return true;
}
private int GetNetworkDataWordCount()
{
InitializeNetworkProperties();
int num = 0;
int i = 0;
for (int num2 = _networkProperties.Length; i < num2; i++)
{
IKCCNetworkProperty iKCCNetworkProperty = _networkProperties[i];
num += iKCCNetworkProperty.WordCount;
}
return num;
}
private unsafe void ReadNetworkData()
{
_networkContext.Data = _fixedData;
fixed (int* ptr = &ReinterpretState<int>())
{
int* ptr2 = ptr;
int i = 0;
for (int num = _networkProperties.Length; i < num; i++)
{
IKCCNetworkProperty iKCCNetworkProperty = _networkProperties[i];
iKCCNetworkProperty.Read(ptr2);
ptr2 += iKCCNetworkProperty.WordCount;
}
}
}
private unsafe void WriteNetworkData()
{
_networkContext.Data = _fixedData;
fixed (int* ptr = &ReinterpretState<int>())
{
int* ptr2 = ptr;
int i = 0;
for (int num = _networkProperties.Length; i < num; i++)
{
IKCCNetworkProperty iKCCNetworkProperty = _networkProperties[i];
iKCCNetworkProperty.Write(ptr2);
ptr2 += iKCCNetworkProperty.WordCount;
}
}
}
private void InterpolateNetworkData(RenderSource renderSource, RenderTimeframe renderTimeframe, float interpolationAlpha = -1f)
{
RenderSource renderSource2 = base.Object.RenderSource;
RenderTimeframe renderTimeframe2 = base.Object.RenderTimeframe;
base.Object.RenderSource = renderSource;
base.Object.RenderTimeframe = renderTimeframe;
NetworkBehaviourBuffer from;
NetworkBehaviourBuffer to;
float alpha;
bool num = TryGetSnapshotsBuffers(out from, out to, out alpha);
base.Object.RenderSource = renderSource2;
base.Object.RenderTimeframe = renderTimeframe2;
if (num && UpdateInterpolationTick(from.Tick, to.Tick))
{
if (interpolationAlpha >= 0f && interpolationAlpha <= 1f)
{
alpha = interpolationAlpha;
}
float deltaTime = base.Runner.DeltaTime;
float num2 = (float)(int)from.Tick + alpha * (float)((int)to.Tick - (int)from.Tick);
_renderData.CopyFromOther(_fixedData);
_renderData.Frame = Time.frameCount;
_renderData.Tick = Mathf.RoundToInt(num2);
_renderData.Alpha = alpha;
_renderData.DeltaTime = deltaTime;
_renderData.UpdateDeltaTime = deltaTime;
_renderData.Time = num2 * deltaTime;
_networkContext.Data = _renderData;
KCCInterpolationInfo interpolationInfo = default(KCCInterpolationInfo);
interpolationInfo.FromBuffer = from;
interpolationInfo.ToBuffer = to;
interpolationInfo.Alpha = alpha;
int i = 0;
for (int num3 = _networkProperties.Length; i < num3; i++)
{
IKCCNetworkProperty iKCCNetworkProperty = _networkProperties[i];
iKCCNetworkProperty.Interpolate(interpolationInfo);
interpolationInfo.Offset += iKCCNetworkProperty.WordCount;
}
}
}
private void InterpolateNetworkTransform()
{
RenderSource renderSource = base.Object.RenderSource;
RenderTimeframe renderTimeframe = base.Object.RenderTimeframe;
base.Object.RenderSource = RenderSource.Interpolated;
base.Object.RenderTimeframe = RenderTimeframe.Remote;
NetworkBehaviourBuffer from;
NetworkBehaviourBuffer to;
float alpha;
bool num = TryGetSnapshotsBuffers(out from, out to, out alpha);
base.Object.RenderSource = renderSource;
base.Object.RenderTimeframe = renderTimeframe;
if (num && UpdateInterpolationTick(from.Tick, to.Tick))
{
KCCNetworkProperties.ReadTransforms(from, to, out var fromTargetPosition, out var toTargetPosition, out var fromLookPitch, out var toLookPitch, out var fromLookYaw, out var toLookYaw);
_fixedData.BasePosition = fromTargetPosition;
_fixedData.DesiredPosition = toTargetPosition;
_fixedData.TargetPosition = Vector3.Lerp(fromTargetPosition, toTargetPosition, alpha);
_fixedData.LookPitch = Mathf.Lerp(fromLookPitch, toLookPitch, alpha);
_fixedData.LookYaw = KCCUtility.InterpolateRange(fromLookYaw, toLookYaw, -180f, 180f, alpha);
_renderData.BasePosition = _fixedData.BasePosition;
_renderData.DesiredPosition = _fixedData.DesiredPosition;
_renderData.TargetPosition = _fixedData.TargetPosition;
_renderData.LookPitch = _fixedData.LookPitch;
_renderData.LookYaw = _fixedData.LookYaw;
_transform.SetPositionAndRotation(_renderData.TargetPosition, _renderData.TransformRotation);
}
}
private bool UpdateInterpolationTick(int fromTick, int toTick)
{
if (toTick - fromTick <= 0 && _interpolationTick == fromTick)
{
_interpolationAttempts = 30;
return false;
}
if (_interpolationAttempts > 0)
{
if (toTick == base.Runner.Tick)
{
_interpolationAttempts--;
return false;
}
_interpolationAttempts = 0;
}
_interpolationTick = fromTick;
return true;
}
private void RestoreHistoryData(KCCData historyData)
{
if (_fixedData.IsGrounded)
{
_fixedData.IsGrounded = historyData.IsGrounded;
_fixedData.WasGrounded = historyData.WasGrounded;
}
}
private void InitializeNetworkProperties()
{
if (_networkContext == null)
{
_networkContext = new KCCNetworkContext();
_networkContext.KCC = this;
_networkContext.Settings = _settings;
List<IKCCNetworkProperty> list = new List<IKCCNetworkProperty>(32);
list.Add(new KCCNetworkProperties(_networkContext));
_networkProperties = list.ToArray();
}
}
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;
int num = base.Runner.GetPhysicsScene().OverlapSphere(position, radius + extent, hitColliders, layerMask, triggerInteraction);
for (int i = 0; i < num; 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;
int num = base.Runner.GetPhysicsScene().OverlapCapsule(point2, point, radius + extent, hitColliders, layerMask, triggerInteraction);
for (int i = 0; i < num; 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;
int num = base.Runner.GetPhysicsScene().Raycast(position, direction, raycastHits, maxDistance, layerMask, triggerInteraction);
for (int i = 0; i < num; i++)
{
RaycastHit raycastHit = raycastHits[i];
if (IsValidHitColliderUnsafe(data, raycastHit.collider))
{
shapeCastInfo.AddHit(raycastHit);
}
}
return shapeCastInfo.AllHitCount > 0;
}
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;
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;
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;
}
}
}