341 lines
12 KiB
C#
Executable File
341 lines
12 KiB
C#
Executable File
using RebootKit.Engine.Extensions;
|
|
using RebootKit.Engine.Foundation;
|
|
using RebootKit.Engine.Main;
|
|
using RebootKit.Engine.Services.Simulation;
|
|
using RebootKit.Engine.Simulation;
|
|
using Unity.Collections;
|
|
using Unity.Mathematics;
|
|
using Unity.Netcode;
|
|
using UnityEngine;
|
|
using Logger = RebootKit.Engine.Foundation.Logger;
|
|
|
|
namespace RebootReality.jelycho.Player {
|
|
public struct PlayerActorState : INetworkSerializable {
|
|
public Vector3 Position;
|
|
public Vector3 Velocity;
|
|
public float LookPitch;
|
|
public float LookYaw;
|
|
public bool IsGrounded;
|
|
|
|
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter {
|
|
serializer.SerializeValue(ref Position);
|
|
serializer.SerializeValue(ref Velocity);
|
|
serializer.SerializeValue(ref LookPitch);
|
|
serializer.SerializeValue(ref LookYaw);
|
|
serializer.SerializeValue(ref IsGrounded);
|
|
}
|
|
}
|
|
|
|
public class PlayerActor : NetworkBehaviour {
|
|
static readonly Logger s_Logger = new Logger(nameof(PlayerActor));
|
|
|
|
[SerializeField] Animator m_Animator;
|
|
|
|
[Header("Movement")]
|
|
[SerializeField] PlayerFPPLocomotion m_Locomotion;
|
|
|
|
[Header("Camera")]
|
|
[SerializeField] FPPCamera m_Camera;
|
|
[SerializeField] CameraSpring m_CameraSpring;
|
|
|
|
[SerializeField, Range(0.0f, 1.0f), Tooltip("Percentage of run speed")]
|
|
float m_EnableCameraBobbingPercentThreshold = 0.5f;
|
|
|
|
[SerializeField] float m_SprintCameraBobbing = 1.0f;
|
|
[SerializeField] float m_RunCameraBobbing = 0.5f;
|
|
[SerializeField] float m_IdleCameraBobbing = 0.0f;
|
|
[SerializeField] float m_CameraBobbingTransitionSpeed = 5.0f;
|
|
|
|
float m_TargetCameraBobbing = 0.0f;
|
|
float m_CurrentCameraBobbing = 0.0f;
|
|
|
|
[Header("Character")]
|
|
[SerializeField] Transform m_CharacterRootTransform;
|
|
[SerializeField] Transform m_HeadBoneTransform;
|
|
[SerializeField] Transform m_HeadAimTargetTransform;
|
|
[SerializeField] Transform m_CharacterForwardTransform;
|
|
|
|
[SerializeField, Range(0.0f, 90.0f)] float m_CharacterRotateDeadAngle = 5.0f;
|
|
[SerializeField, Range(0.0f, 90.0f)] float m_CharacterRotateSoftAngle = 90.0f;
|
|
|
|
[SerializeField] float m_CharacterRotateSpeed = 180.0f;
|
|
[SerializeField] float m_CharacterRotateFastSpeed = 720.0f;
|
|
|
|
float m_CharacterTurnVelocity = 0.0f;
|
|
|
|
[Header("Dragging")]
|
|
[SerializeField] Transform m_DragGutStartPosition;
|
|
[SerializeField] PhysicsObjectDragger m_PhysicsDragger;
|
|
[SerializeField] FloatRange m_DragDistanceRange = new FloatRange(1.0f, 5.0f);
|
|
|
|
[Header("Network")]
|
|
[SerializeField] float m_MinTeleportDistance = 0.5f;
|
|
|
|
public float3 LookDirection {
|
|
get {
|
|
float pitchRad = math.radians(-m_Camera.Pitch);
|
|
float yawRad = math.radians(m_Camera.Yaw);
|
|
return new float3(math.sin(yawRad) * math.cos(pitchRad),
|
|
math.sin(pitchRad),
|
|
math.cos(yawRad) * math.cos(pitchRad));
|
|
}
|
|
}
|
|
|
|
void Start() {
|
|
m_CameraSpring.Initialize();
|
|
}
|
|
|
|
public override void OnNetworkSpawn() {
|
|
base.OnNetworkSpawn();
|
|
|
|
if (IsOwner) {
|
|
SetupAsLocalPlayer();
|
|
|
|
RR.ClientTick += OnClientTick;
|
|
} else {
|
|
SetupAsRemotePlayer();
|
|
}
|
|
}
|
|
|
|
public override void OnNetworkDespawn() {
|
|
base.OnNetworkDespawn();
|
|
|
|
if (IsOwner) {
|
|
RR.ClientTick -= OnClientTick;
|
|
}
|
|
}
|
|
|
|
void SetupAsLocalPlayer() {
|
|
m_Camera.enabled = true;
|
|
m_Camera.Camera.enabled = true;
|
|
m_Locomotion.enabled = true;
|
|
|
|
if (TryGetComponent(out Rigidbody rbody)) {
|
|
rbody.isKinematic = false;
|
|
}
|
|
}
|
|
|
|
void SetupAsRemotePlayer() {
|
|
m_Camera.enabled = false;
|
|
m_Camera.Camera.enabled = false;
|
|
m_Locomotion.enabled = false;
|
|
|
|
if (TryGetComponent(out Rigidbody rbody)) {
|
|
rbody.isKinematic = true;
|
|
}
|
|
}
|
|
|
|
public override void OnGainedOwnership() {
|
|
base.OnGainedOwnership();
|
|
SetupAsLocalPlayer();
|
|
}
|
|
|
|
public override void OnLostOwnership() {
|
|
base.OnLostOwnership();
|
|
SetupAsRemotePlayer();
|
|
}
|
|
|
|
void Update() {
|
|
if (!IsSpawned) {
|
|
return;
|
|
}
|
|
|
|
if (IsOwner) {
|
|
OwnerTick();
|
|
} else {
|
|
RemoteTick();
|
|
}
|
|
|
|
// Character rotation
|
|
float3 targetCharacterForward = math.normalize(LookDirection.With(y: 0.0f));
|
|
float3 currentCharacterForward = math.normalize(m_CharacterForwardTransform.forward.With(y: 0.0f));
|
|
|
|
float angleRad =
|
|
math.acos(math.clamp(math.dot(targetCharacterForward, currentCharacterForward) / (math.length(targetCharacterForward) * math.length(currentCharacterForward)),
|
|
-1f, 1f));
|
|
float angleDeg = math.degrees(angleRad);
|
|
|
|
bool rotateCharacter = false;
|
|
float rotateCharacterSpeed = m_CharacterRotateSpeed;
|
|
m_CharacterTurnVelocity = 0.0f;
|
|
|
|
if (math.abs(angleDeg) > m_CharacterRotateDeadAngle) {
|
|
if (math.abs(angleDeg) < m_CharacterRotateSoftAngle) {
|
|
rotateCharacter = true;
|
|
} else {
|
|
rotateCharacter = true;
|
|
rotateCharacterSpeed = m_CharacterRotateFastSpeed;
|
|
}
|
|
}
|
|
|
|
float velocityForward = m_Locomotion.Velocity.z;
|
|
|
|
if (!rotateCharacter && math.abs(velocityForward) > 0.01f) {
|
|
rotateCharacter = true;
|
|
}
|
|
|
|
if (rotateCharacter) {
|
|
m_CharacterTurnVelocity = rotateCharacterSpeed * Time.deltaTime;
|
|
|
|
Vector3 newForward = Vector3.RotateTowards(currentCharacterForward,
|
|
targetCharacterForward,
|
|
math.radians(m_CharacterTurnVelocity),
|
|
0.0f);
|
|
m_CharacterForwardTransform.forward = newForward;
|
|
}
|
|
|
|
// Aim Target adjustment
|
|
m_HeadAimTargetTransform.position = (float3) m_HeadBoneTransform.position + LookDirection * 5.0f;
|
|
}
|
|
|
|
void OwnerTick() {
|
|
// Camera Stuff
|
|
m_Camera.Tick();
|
|
|
|
if (m_Locomotion.IsGrounded &&
|
|
m_Locomotion.SpeedXZ >= m_Locomotion.runSpeed * m_EnableCameraBobbingPercentThreshold) {
|
|
if (m_Locomotion.IsSprinting) {
|
|
m_TargetCameraBobbing = m_SprintCameraBobbing;
|
|
} else {
|
|
m_TargetCameraBobbing = m_RunCameraBobbing;
|
|
}
|
|
} else {
|
|
m_TargetCameraBobbing = m_IdleCameraBobbing;
|
|
}
|
|
|
|
m_CurrentCameraBobbing = Mathf.MoveTowards(m_CurrentCameraBobbing,
|
|
m_TargetCameraBobbing,
|
|
m_CameraBobbingTransitionSpeed * Time.deltaTime);
|
|
m_Camera.SetBobbing(m_CurrentCameraBobbing);
|
|
|
|
m_CameraSpring.UpdateSpring(Time.deltaTime,
|
|
m_CharacterForwardTransform.up,
|
|
m_CharacterForwardTransform.right,
|
|
m_CharacterForwardTransform.forward);
|
|
|
|
|
|
UpdateAnimator(m_Locomotion.Velocity);
|
|
}
|
|
|
|
void RemoteTick() {
|
|
Vector3 targetPosition = m_NetworkState.Position;
|
|
|
|
if ((transform.position - m_NetworkState.Position).sqrMagnitude <
|
|
m_MinTeleportDistance * m_MinTeleportDistance) {
|
|
targetPosition = Vector3.MoveTowards(transform.position,
|
|
m_NetworkState.Position,
|
|
m_Locomotion.runSpeed * Time.deltaTime);
|
|
}
|
|
|
|
m_Locomotion.WarpTo(targetPosition);
|
|
|
|
m_Camera.Pitch = m_NetworkState.LookPitch;
|
|
m_Camera.Yaw = m_NetworkState.LookYaw;
|
|
|
|
UpdateAnimator(m_NetworkState.Velocity);
|
|
}
|
|
|
|
void OnClientTick() {
|
|
PlayerActorState state = new PlayerActorState {
|
|
Position = transform.position,
|
|
LookPitch = m_Camera.Pitch,
|
|
LookYaw = m_Camera.Yaw,
|
|
IsGrounded = m_Locomotion.IsGrounded,
|
|
Velocity = m_Locomotion.Velocity
|
|
};
|
|
|
|
UpdatePlayerStateRpc(state);
|
|
}
|
|
|
|
PlayerActorState m_NetworkState;
|
|
|
|
[Rpc(SendTo.NotMe)]
|
|
void UpdatePlayerStateRpc(PlayerActorState state) {
|
|
if (IsOwner) {
|
|
return;
|
|
}
|
|
|
|
m_NetworkState = state;
|
|
}
|
|
|
|
[ServerRpc(RequireOwnership = false)]
|
|
public void WarpToServerRpc(Vector3 position) {
|
|
WarpToClientRpc(position);
|
|
}
|
|
|
|
[ClientRpc]
|
|
void WarpToClientRpc(Vector3 position) {
|
|
if (IsOwner) {
|
|
m_Locomotion.WarpTo(position);
|
|
} else {
|
|
transform.position = position;
|
|
}
|
|
}
|
|
|
|
public void SetSprint(bool isSprinting) {
|
|
m_Locomotion.SetSprint(isSprinting);
|
|
}
|
|
|
|
public void Jump() {
|
|
m_Locomotion.Jump();
|
|
}
|
|
|
|
public void Look(Vector2 input) {
|
|
m_Camera.Rotate(input.x, input.y);
|
|
}
|
|
|
|
public void SetMoveInput(Vector2 input) {
|
|
float3 direction = Quaternion.AngleAxis(m_Camera.Yaw, Vector3.up) *
|
|
new float3(input.x, 0.0f, input.y);
|
|
m_Locomotion.SetWishDirection(direction);
|
|
}
|
|
|
|
public void StartDrag() {
|
|
GameObject pickedGameObject = m_Camera.Sensor.Sense();
|
|
if (pickedGameObject != null && pickedGameObject.TryGetComponent(out Rigidbody rigidbody)) {
|
|
m_PhysicsDragger.Grab(rigidbody);
|
|
}
|
|
}
|
|
|
|
public void StopDrag() {
|
|
m_PhysicsDragger.Drop();
|
|
}
|
|
|
|
public void PrimaryAction() {
|
|
m_Animator.SetTrigger(AnimatorParamHashes.Attack);
|
|
}
|
|
|
|
public void SecondaryAction() {
|
|
m_Animator.SetTrigger(AnimatorParamHashes.Block);
|
|
}
|
|
|
|
struct AnimatorParamHashes {
|
|
public static readonly int VelocityForwardNormalized = Animator.StringToHash("VelocityForwardNormalized");
|
|
public static readonly int VelocityRightNormalized = Animator.StringToHash("VelocityRightNormalized");
|
|
public static readonly int TurnVelocity = Animator.StringToHash("TurnVelocity");
|
|
public static readonly int IsGrounded = Animator.StringToHash("IsGrounded");
|
|
|
|
public static readonly int Attack = Animator.StringToHash("Attack");
|
|
public static readonly int Block = Animator.StringToHash("Block");
|
|
}
|
|
|
|
void UpdateAnimator(Vector3 velocity) {
|
|
Vector3 localVelocity = m_CharacterForwardTransform.InverseTransformDirection(velocity);
|
|
float forwardNormalized = localVelocity.z / m_Locomotion.runSpeed;
|
|
float rightNormalized = localVelocity.x / m_Locomotion.runSpeed;
|
|
|
|
float turnVelocity = m_CharacterTurnVelocity;
|
|
if (math.abs(forwardNormalized) > 0.01f ||
|
|
math.abs(rightNormalized) > 0.01f ||
|
|
!m_Locomotion.IsGrounded) {
|
|
turnVelocity = 0.0f;
|
|
}
|
|
|
|
m_Animator.SetFloat(AnimatorParamHashes.VelocityForwardNormalized, forwardNormalized);
|
|
m_Animator.SetFloat(AnimatorParamHashes.VelocityRightNormalized, rightNormalized);
|
|
m_Animator.SetFloat(AnimatorParamHashes.TurnVelocity, turnVelocity);
|
|
|
|
m_Animator.SetBool(AnimatorParamHashes.IsGrounded, m_Locomotion.IsGrounded);
|
|
}
|
|
}
|
|
} |