r2mods/ilspy_dump/ror2_csproj/RoR2/CharacterMotor.cs

810 lines
19 KiB
C#

using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using KinematicCharacterController;
using RoR2.ConVar;
using Unity;
using UnityEngine;
using UnityEngine.Networking;
namespace RoR2;
[RequireComponent(typeof(CharacterBody))]
public class CharacterMotor : BaseCharacterController, IPhysMotor, ILifeBehavior, IDisplacementReceiver, ICharacterGravityParameterProvider, ICharacterFlightParameterProvider
{
[Serializable]
public struct HitGroundInfo
{
public Vector3 velocity;
public Vector3 position;
public bool isValidForEffect;
public override string ToString()
{
return $"velocity={velocity} position={position}";
}
}
public delegate void HitGroundDelegate(ref HitGroundInfo hitGroundInfo);
public struct MovementHitInfo
{
public Vector3 velocity;
public Collider hitCollider;
}
public delegate void MovementHitDelegate(ref MovementHitInfo movementHitInfo);
[HideInInspector]
public float walkSpeedPenaltyCoefficient = 1f;
[Tooltip("The character direction component to supply a move vector to.")]
public CharacterDirection characterDirection;
[Tooltip("Whether or not a move vector supplied to this component can cause movement. Use this when the object is driven by root motion.")]
public bool muteWalkMotion;
[Tooltip("The mass of this character.")]
public float mass = 1f;
[Tooltip("The air control value of this character as a fraction of ground control.")]
public float airControl = 0.25f;
[Tooltip("Disables Air Control for things like jumppads")]
public bool disableAirControlUntilCollision;
[Tooltip("Auto-assigns parameters skin width, slope angle, and step offset as a function of the Character Motor's radius and height")]
public bool generateParametersOnAwake = true;
[Tooltip("Ignores JumpVolumes")]
public bool doNotTriggerJumpVolumes;
private NetworkIdentity networkIdentity;
private CharacterBody body;
private CapsuleCollider capsuleCollider;
private static readonly bool enableMotorWithoutAuthority;
private bool alive = true;
private const float restDuration = 1f;
private const float restVelocityThreshold = 0.025f;
private const float restVelocityThresholdSqr = 0.00062500004f;
public const float slipStartAngle = 70f;
public const float slipEndAngle = 55f;
private float restStopwatch;
private Vector3 previousPosition;
private bool isAirControlForced;
[NonSerialized]
public int jumpCount;
[NonSerialized]
public bool netIsGrounded;
[NonSerialized]
public Vector3 netGroundNormal;
[NonSerialized]
public Vector3 velocity;
private Vector3 lastVelocity;
[NonSerialized]
public Vector3 rootMotion;
private Vector3 _moveDirection;
private static readonly FloatConVar cvCMotorSafeCollisionStepThreshold;
private int _safeCollisionEnableCount;
[SerializeField]
[Tooltip("Determins how gravity affects this character.")]
private CharacterGravityParameters _gravityParameters;
[Tooltip("Determines whether this character has three-dimensional or two-dimensional movement capabilities.")]
[SerializeField]
private CharacterFlightParameters _flightParameters;
private static int kRpcRpcApplyForceImpulse;
private static int kRpcRpcOnHitGroundSFX;
private static int kCmdCmdReportHitGround;
public float walkSpeed => body.moveSpeed * walkSpeedPenaltyCoefficient;
public float acceleration => body.acceleration;
public bool atRest => restStopwatch > 1f;
public bool hasEffectiveAuthority { get; private set; }
public Vector3 estimatedGroundNormal
{
get
{
if (!hasEffectiveAuthority)
{
return netGroundNormal;
}
return base.Motor.GroundingStatus.GroundNormal;
}
}
private bool canWalk
{
get
{
if (!muteWalkMotion)
{
return alive;
}
return false;
}
}
public bool isGrounded
{
get
{
if (!hasEffectiveAuthority)
{
return netIsGrounded;
}
return base.Motor.GroundingStatus.IsStableOnGround;
}
}
float IPhysMotor.mass => mass;
Vector3 IPhysMotor.velocity => velocity;
Vector3 IPhysMotor.velocityAuthority
{
get
{
return velocity;
}
set
{
velocity = value;
}
}
public Vector3 moveDirection
{
get
{
return _moveDirection;
}
set
{
_moveDirection = value;
}
}
private float slopeLimit
{
get
{
return base.Motor.MaxStableSlopeAngle;
}
set
{
base.Motor.MaxStableSlopeAngle = value;
}
}
public float stepOffset
{
get
{
return base.Motor.MaxStepHeight;
}
set
{
base.Motor.MaxStepHeight = value;
}
}
public float capsuleHeight => capsuleCollider.height;
public float capsuleRadius => capsuleCollider.radius;
public StepHandlingMethod stepHandlingMethod
{
get
{
return base.Motor.StepHandling = StepHandlingMethod.None;
}
set
{
base.Motor.StepHandling = value;
}
}
public bool ledgeHandling
{
get
{
return base.Motor.LedgeAndDenivelationHandling;
}
set
{
base.Motor.LedgeAndDenivelationHandling = value;
}
}
public bool interactiveRigidbodyHandling
{
get
{
return base.Motor.InteractiveRigidbodyHandling;
}
set
{
base.Motor.InteractiveRigidbodyHandling = value;
}
}
public Run.FixedTimeStamp lastGroundedTime { get; private set; } = Run.FixedTimeStamp.negativeInfinity;
public CharacterGravityParameters gravityParameters
{
get
{
return _gravityParameters;
}
set
{
if (!_gravityParameters.Equals(value))
{
_gravityParameters = value;
useGravity = _gravityParameters.CheckShouldUseGravity();
}
}
}
public bool useGravity { get; private set; }
public CharacterFlightParameters flightParameters
{
get
{
return _flightParameters;
}
set
{
if (!_flightParameters.Equals(value))
{
_flightParameters = value;
isFlying = _flightParameters.CheckShouldUseFlight();
}
}
}
public bool isFlying { get; private set; }
[Obsolete("Use '.onHitGroundAuthority' instead, which this is just a backwards-compatibility wrapper for. Or, use '.onHitGroundAuthority' if that is more appropriate to your use case.", false)]
public event HitGroundDelegate onHitGround
{
add
{
onHitGroundAuthority += value;
}
remove
{
onHitGroundAuthority -= value;
}
}
public event HitGroundDelegate onHitGroundAuthority;
public event Action<CharacterBody> onMotorStart;
public event MovementHitDelegate onMovementHit;
private void UpdateInnerMotorEnabled()
{
base.Motor.enabled = enableMotorWithoutAuthority || hasEffectiveAuthority;
}
private void UpdateAuthority()
{
hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
UpdateInnerMotorEnabled();
}
private void Awake()
{
networkIdentity = GetComponent<NetworkIdentity>();
body = GetComponent<CharacterBody>();
capsuleCollider = GetComponent<CapsuleCollider>();
}
private void Start()
{
previousPosition = base.transform.position;
if (base.Motor == null)
{
SetupCharacterMotor(GetComponent<KinematicCharacterMotor>());
}
if (base.Motor.AttachedRigidbody != null)
{
base.Motor.AttachedRigidbody.mass = mass;
}
base.Motor.MaxStableSlopeAngle = 70f;
base.Motor.MaxStableDenivelationAngle = 55f;
base.Motor.RebuildCollidableLayers();
if (generateParametersOnAwake)
{
GenerateParameters();
}
useGravity = gravityParameters.CheckShouldUseGravity();
isFlying = flightParameters.CheckShouldUseFlight();
UpdateAuthority();
this.onMotorStart?.Invoke(body);
}
public override void OnStartAuthority()
{
UpdateAuthority();
}
public override void OnStopAuthority()
{
UpdateAuthority();
}
private void OnEnable()
{
UpdateInnerMotorEnabled();
}
private void OnDisable()
{
base.Motor.enabled = false;
}
private void PreMove(float deltaTime)
{
if (!hasEffectiveAuthority)
{
return;
}
float num = acceleration;
if (isAirControlForced || !isGrounded)
{
num *= (disableAirControlUntilCollision ? 0f : airControl);
}
Vector3 vector = moveDirection;
if (!isFlying)
{
vector.y = 0f;
}
if (body.isSprinting)
{
float magnitude = vector.magnitude;
if (magnitude < 1f && magnitude > 0f)
{
float num2 = 1f / vector.magnitude;
vector *= num2;
}
}
Vector3 target = vector * walkSpeed;
if (!isFlying)
{
target.y = velocity.y;
}
velocity = Vector3.MoveTowards(velocity, target, num * deltaTime);
if (useGravity)
{
ref float y = ref velocity.y;
y += Physics.gravity.y * deltaTime;
if (isGrounded)
{
y = Mathf.Max(y, 0f);
}
}
}
public void OnDeathStart()
{
alive = false;
}
private void FixedUpdate()
{
float fixedDeltaTime = Time.fixedDeltaTime;
if (fixedDeltaTime != 0f)
{
Vector3 position = base.transform.position;
if ((previousPosition - position).sqrMagnitude < 0.00062500004f * fixedDeltaTime)
{
restStopwatch += fixedDeltaTime;
}
else
{
restStopwatch = 0f;
}
previousPosition = position;
if (netIsGrounded)
{
lastGroundedTime = Run.FixedTimeStamp.now;
}
}
}
private void GenerateParameters()
{
slopeLimit = 70f;
stepOffset = Mathf.Min(capsuleHeight * 0.1f, 0.2f);
stepHandlingMethod = StepHandlingMethod.None;
ledgeHandling = false;
interactiveRigidbodyHandling = true;
}
public void ApplyForce(Vector3 force, bool alwaysApply = false, bool disableAirControlUntilCollision = false)
{
PhysForceInfo forceInfo = PhysForceInfo.Create();
forceInfo.force = force;
forceInfo.ignoreGroundStick = alwaysApply;
forceInfo.disableAirControlUntilCollision = disableAirControlUntilCollision;
forceInfo.massIsOne = false;
ApplyForceImpulse(in forceInfo);
}
public void ApplyForceImpulse(in PhysForceInfo forceInfo)
{
if (NetworkServer.active && !hasEffectiveAuthority)
{
CallRpcApplyForceImpulse(forceInfo);
return;
}
Vector3 force = forceInfo.force;
if (!forceInfo.massIsOne)
{
_ = force.magnitude;
force *= 1f / mass;
}
if (mass != 0f)
{
if (force.y < 6f && isGrounded && !forceInfo.ignoreGroundStick)
{
force.y = 0f;
}
if (force.y > 0f)
{
base.Motor.ForceUnground();
}
velocity += force;
if (forceInfo.disableAirControlUntilCollision)
{
disableAirControlUntilCollision = true;
}
}
}
[ClientRpc]
private void RpcApplyForceImpulse(PhysForceInfo physForceInfo)
{
if (!NetworkServer.active)
{
ApplyForceImpulse(in physForceInfo);
}
}
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
{
currentRotation = Quaternion.identity;
}
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{
currentVelocity = velocity;
}
public override void BeforeCharacterUpdate(float deltaTime)
{
_ = cvCMotorSafeCollisionStepThreshold.value;
_ = cvCMotorSafeCollisionStepThreshold.value;
if (rootMotion != Vector3.zero)
{
Vector3 vector = rootMotion;
rootMotion = Vector3.zero;
base.Motor.MoveCharacter(base.transform.position + vector);
}
PreMove(deltaTime);
_ = (velocity * deltaTime).sqrMagnitude;
}
public override void PostGroundingUpdate(float deltaTime)
{
if (base.Motor.GroundingStatus.IsStableOnGround != base.Motor.LastGroundingStatus.IsStableOnGround)
{
netIsGrounded = base.Motor.GroundingStatus.IsStableOnGround;
if (base.Motor.GroundingStatus.IsStableOnGround)
{
OnLanded();
}
else
{
OnLeaveStableGround();
}
}
}
private void OnLanded()
{
jumpCount = 0;
HitGroundInfo hitGroundInfo = default(HitGroundInfo);
hitGroundInfo.velocity = lastVelocity;
hitGroundInfo.position = base.Motor.GroundingStatus.GroundPoint;
hitGroundInfo.isValidForEffect = Run.FixedTimeStamp.now - lastGroundedTime > 0.2f;
HitGroundInfo hitGroundInfo2 = hitGroundInfo;
if (hasEffectiveAuthority)
{
try
{
this.onHitGroundAuthority?.Invoke(ref hitGroundInfo2);
}
catch (Exception message)
{
Debug.LogError(message);
}
if (NetworkServer.active)
{
GlobalEventManager.instance.OnCharacterHitGroundServer(body, hitGroundInfo2);
}
else
{
CallCmdReportHitGround(hitGroundInfo2);
}
}
}
[ClientRpc]
public void RpcOnHitGroundSFX(HitGroundInfo hitGroundInfo, bool tookFallDamage)
{
if (!NetworkServer.active)
{
GlobalEventManager.instance.OnCharacterHitGroundSFX(body, hitGroundInfo, tookFallDamage);
}
}
[Command]
private void CmdReportHitGround(HitGroundInfo hitGroundInfo)
{
GlobalEventManager.instance.OnCharacterHitGroundServer(body, hitGroundInfo);
}
private void OnLeaveStableGround()
{
if (jumpCount < 1)
{
jumpCount = 1;
}
body.SetInLava(b: false);
}
public override void AfterCharacterUpdate(float deltaTime)
{
lastVelocity = velocity;
velocity = base.Motor.BaseVelocity;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool IsColliderValidForCollisions(Collider coll)
{
if (!coll.isTrigger)
{
return coll != base.Motor.Capsule;
}
return false;
}
public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
{
isAirControlForced = false;
SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitCollider, hitPoint);
if ((bool)objectSurfaceDef)
{
isAirControlForced = objectSurfaceDef.isSlippery;
body.SetInLava(objectSurfaceDef.isLava);
}
}
public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
{
disableAirControlUntilCollision = false;
if (this.onMovementHit != null)
{
MovementHitInfo movementHitInfo = default(MovementHitInfo);
movementHitInfo.velocity = velocity;
movementHitInfo.hitCollider = hitCollider;
MovementHitInfo movementHitInfo2 = movementHitInfo;
this.onMovementHit(ref movementHitInfo2);
SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitCollider, hitPoint);
if ((bool)objectSurfaceDef)
{
body.SetInLava(objectSurfaceDef.isLava);
}
}
}
public override void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
{
}
public void Jump(float horizontalMultiplier, float verticalMultiplier, bool vault = false)
{
Vector3 vector = moveDirection;
if (vault)
{
velocity = vector;
}
else
{
vector.y = 0f;
float magnitude = vector.magnitude;
if (magnitude > 0f)
{
vector /= magnitude;
}
Vector3 vector2 = vector * body.moveSpeed * horizontalMultiplier;
vector2.y = body.jumpPower * verticalMultiplier;
velocity = vector2;
}
base.Motor.ForceUnground();
}
public void AddDisplacement(Vector3 displacement)
{
rootMotion += displacement;
}
static CharacterMotor()
{
enableMotorWithoutAuthority = false;
cvCMotorSafeCollisionStepThreshold = new FloatConVar("cmotor_safe_collision_step_threshold", ConVarFlags.Cheat, 1.0833334f.ToString(CultureInfo.InvariantCulture), "How large of a movement in meters/fixedTimeStep is needed to trigger more expensive \"safe\" collisions to prevent tunneling.");
kCmdCmdReportHitGround = 1796547162;
NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterMotor), kCmdCmdReportHitGround, InvokeCmdCmdReportHitGround);
kRpcRpcApplyForceImpulse = 1042934326;
NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMotor), kRpcRpcApplyForceImpulse, InvokeRpcRpcApplyForceImpulse);
kRpcRpcOnHitGroundSFX = -1661136052;
NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMotor), kRpcRpcOnHitGroundSFX, InvokeRpcRpcOnHitGroundSFX);
NetworkCRC.RegisterBehaviour("CharacterMotor", 0);
}
void IPhysMotor.ApplyForceImpulse(in PhysForceInfo physForceInfo)
{
ApplyForceImpulse(in physForceInfo);
}
private void UNetVersion()
{
}
protected static void InvokeCmdCmdReportHitGround(NetworkBehaviour obj, NetworkReader reader)
{
if (!NetworkServer.active)
{
Debug.LogError("Command CmdReportHitGround called on client.");
}
else
{
((CharacterMotor)obj).CmdReportHitGround(GeneratedNetworkCode._ReadHitGroundInfo_CharacterMotor(reader));
}
}
public void CallCmdReportHitGround(HitGroundInfo hitGroundInfo)
{
if (!NetworkClient.active)
{
Debug.LogError("Command function CmdReportHitGround called on server.");
return;
}
if (base.isServer)
{
CmdReportHitGround(hitGroundInfo);
return;
}
NetworkWriter networkWriter = new NetworkWriter();
networkWriter.Write((short)0);
networkWriter.Write((short)5);
networkWriter.WritePackedUInt32((uint)kCmdCmdReportHitGround);
networkWriter.Write(GetComponent<NetworkIdentity>().netId);
GeneratedNetworkCode._WriteHitGroundInfo_CharacterMotor(networkWriter, hitGroundInfo);
SendCommandInternal(networkWriter, 0, "CmdReportHitGround");
}
protected static void InvokeRpcRpcApplyForceImpulse(NetworkBehaviour obj, NetworkReader reader)
{
if (!NetworkClient.active)
{
Debug.LogError("RPC RpcApplyForceImpulse called on server.");
}
else
{
((CharacterMotor)obj).RpcApplyForceImpulse(GeneratedNetworkCode._ReadPhysForceInfo_None(reader));
}
}
protected static void InvokeRpcRpcOnHitGroundSFX(NetworkBehaviour obj, NetworkReader reader)
{
if (!NetworkClient.active)
{
Debug.LogError("RPC RpcOnHitGroundSFX called on server.");
}
else
{
((CharacterMotor)obj).RpcOnHitGroundSFX(GeneratedNetworkCode._ReadHitGroundInfo_CharacterMotor(reader), reader.ReadBoolean());
}
}
public void CallRpcApplyForceImpulse(PhysForceInfo physForceInfo)
{
if (!NetworkServer.active)
{
Debug.LogError("RPC Function RpcApplyForceImpulse called on client.");
return;
}
NetworkWriter networkWriter = new NetworkWriter();
networkWriter.Write((short)0);
networkWriter.Write((short)2);
networkWriter.WritePackedUInt32((uint)kRpcRpcApplyForceImpulse);
networkWriter.Write(GetComponent<NetworkIdentity>().netId);
GeneratedNetworkCode._WritePhysForceInfo_None(networkWriter, physForceInfo);
SendRPCInternal(networkWriter, 0, "RpcApplyForceImpulse");
}
public void CallRpcOnHitGroundSFX(HitGroundInfo hitGroundInfo, bool tookFallDamage)
{
if (!NetworkServer.active)
{
Debug.LogError("RPC Function RpcOnHitGroundSFX called on client.");
return;
}
NetworkWriter networkWriter = new NetworkWriter();
networkWriter.Write((short)0);
networkWriter.Write((short)2);
networkWriter.WritePackedUInt32((uint)kRpcRpcOnHitGroundSFX);
networkWriter.Write(GetComponent<NetworkIdentity>().netId);
GeneratedNetworkCode._WriteHitGroundInfo_CharacterMotor(networkWriter, hitGroundInfo);
networkWriter.Write(tookFallDamage);
SendRPCInternal(networkWriter, 0, "RpcOnHitGroundSFX");
}
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
{
bool flag = base.OnSerialize(writer, forceAll);
bool flag2 = default(bool);
return flag2 || flag;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
base.OnDeserialize(reader, initialState);
}
public override void PreStartClient()
{
base.PreStartClient();
}
}