From df27dde6cb09aa48d895d79947debe2482fd4ee5 Mon Sep 17 00:00:00 2001 From: stilnat Date: Tue, 5 Nov 2024 22:45:33 +0100 Subject: [PATCH] fully server auth ragdoll --- .../Entities/Humanoids/Human/UberHuman.prefab | 164 +++++++------ .../SS3D/Hacks/RagdollWhenPressingButton.cs | 18 +- .../Systems/Animations/PositionController.cs | 4 +- .../SS3D/Systems/Entities/Humanoid/Ragdoll.cs | 228 +++++------------- .../Humanoid/RagdollRecoverAnimator.cs | 149 ++++++++++++ .../Humanoid/RagdollRecoverAnimator.cs.meta | 11 + 6 files changed, 331 insertions(+), 243 deletions(-) create mode 100644 Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs create mode 100644 Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs.meta diff --git a/Assets/Content/WorldObjects/Entities/Humanoids/Human/UberHuman.prefab b/Assets/Content/WorldObjects/Entities/Humanoids/Human/UberHuman.prefab index 063fd698d..c72719416 100644 --- a/Assets/Content/WorldObjects/Entities/Humanoids/Human/UberHuman.prefab +++ b/Assets/Content/WorldObjects/Entities/Humanoids/Human/UberHuman.prefab @@ -1343,8 +1343,8 @@ Rigidbody: m_GameObject: {fileID: 593798233980870999} serializedVersion: 2 m_Mass: 1 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -1402,8 +1402,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -3755,8 +3755,8 @@ Rigidbody: m_GameObject: {fileID: 2612561786074311509} serializedVersion: 2 m_Mass: 1 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 0 m_Interpolate: 0 @@ -3847,8 +3847,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -5199,8 +5199,8 @@ Rigidbody: m_GameObject: {fileID: 3517261860088055723} serializedVersion: 2 m_Mass: 7.5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -5290,8 +5290,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -5479,8 +5479,8 @@ Rigidbody: m_GameObject: {fileID: 3662688532868555398} serializedVersion: 2 m_Mass: 1 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -5538,8 +5538,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -6027,8 +6027,8 @@ Rigidbody: m_GameObject: {fileID: 3814904831518035601} serializedVersion: 2 m_Mass: 5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -6118,8 +6118,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -6198,8 +6198,8 @@ Rigidbody: m_GameObject: {fileID: 3862990575774196887} serializedVersion: 2 m_Mass: 5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -6289,8 +6289,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -6914,6 +6914,7 @@ GameObject: - component: {fileID: 1954948213532107113} - component: {fileID: 7000234689394846347} - component: {fileID: 1215874948772008144} + - component: {fileID: 3128408696448578395} m_Layer: 0 m_Name: UberHuman m_TagString: Untagged @@ -6971,7 +6972,7 @@ MonoBehaviour: _teleportThreshold: 1 _scaleThreshold: 1 _clientAuthoritative: 1 - _sendToOwner: 1 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -7527,7 +7528,6 @@ MonoBehaviour: _componentIndexCache: 13 _addedNetworkObject: {fileID: 241836927429143711} _networkObjectCache: {fileID: 241836927429143711} - _armatureRoot: {fileID: 3362543718434004155} _characterCollider: {fileID: 7772018303242298867} _characterRigidBody: {fileID: 8635375509376998503} _hips: {fileID: 5433592588855148907} @@ -7551,6 +7551,7 @@ MonoBehaviour: _networkObjectCache: {fileID: 241836927429143711} _positionController: {fileID: 7568747683536695618} _timeRagdolled: 3 + _randomForce: 3 --- !u!114 &8615535220686661918 MonoBehaviour: m_ObjectHideFlags: 0 @@ -7741,6 +7742,25 @@ MonoBehaviour: _positionController: {fileID: 7568747683536695618} k__BackingField: {x: 0, y: 0, z: 0} k__BackingField: {fileID: 2856800849451305125} +--- !u!114 &3128408696448578395 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4089496606853742746} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 58b3b3c3948fc4445997581f3ebd8f5d, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 255 + _addedNetworkObject: {fileID: 241836927429143711} + _networkObjectCache: {fileID: 0} + _positionController: {fileID: 7568747683536695618} + _armatureRoot: {fileID: 3362543718434004155} + _character: {fileID: 3714097311666575904} + _hips: {fileID: 5433592588855148907} --- !u!1 &4092542307493577921 GameObject: m_ObjectHideFlags: 0 @@ -8288,8 +8308,8 @@ Rigidbody: m_GameObject: {fileID: 4559021053838536536} serializedVersion: 2 m_Mass: 12.5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -8333,8 +8353,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -9087,8 +9107,8 @@ Rigidbody: m_GameObject: {fileID: 5359021026460437030} serializedVersion: 2 m_Mass: 1 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -9178,8 +9198,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -9835,8 +9855,8 @@ Rigidbody: m_GameObject: {fileID: 6177773197948981747} serializedVersion: 2 m_Mass: 1 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -9926,8 +9946,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -10919,8 +10939,8 @@ Rigidbody: m_GameObject: {fileID: 7178378187929536671} serializedVersion: 2 m_Mass: 1 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 0 m_Interpolate: 0 @@ -11039,8 +11059,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -11256,8 +11276,8 @@ Rigidbody: m_GameObject: {fileID: 7246030806788597142} serializedVersion: 2 m_Mass: 5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -11347,8 +11367,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -11426,8 +11446,8 @@ Rigidbody: m_GameObject: {fileID: 7342014919758599328} serializedVersion: 2 m_Mass: 7.5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -11517,8 +11537,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -12390,8 +12410,8 @@ Rigidbody: m_GameObject: {fileID: 8000724491074061805} serializedVersion: 2 m_Mass: 7.5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -12481,8 +12501,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -12590,8 +12610,8 @@ Rigidbody: m_GameObject: {fileID: 8067904849068615099} serializedVersion: 2 m_Mass: 12.5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -12681,8 +12701,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -12756,7 +12776,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 8105151679370853076} m_LocalRotation: {x: 0.70356977, y: 0.006053881, z: 2.910383e-11, w: 0.7106004} - m_LocalPosition: {x: 2.0061848, y: -1.0835686, z: -1.8300675} + m_LocalPosition: {x: 2.0061848, y: -1.0835687, z: -1.8300675} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -13603,8 +13623,8 @@ Rigidbody: m_GameObject: {fileID: 8880209918821347235} serializedVersion: 2 m_Mass: 5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -13694,8 +13714,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -13918,7 +13938,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 8937338257042491703} m_LocalRotation: {x: 0.7035764, y: 0.006096695, z: -2.910383e-10, w: 0.7105935} - m_LocalPosition: {x: 1.8461, y: -1.0835686, z: -1.7800674} + m_LocalPosition: {x: 1.8461, y: -1.0835686, z: -1.7800676} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] @@ -13984,8 +14004,8 @@ Rigidbody: m_GameObject: {fileID: 8966162540359811168} serializedVersion: 2 m_Mass: 5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -14075,8 +14095,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 @@ -14873,8 +14893,8 @@ Rigidbody: m_GameObject: {fileID: 9200825884340260337} serializedVersion: 2 m_Mass: 7.5 - m_Drag: 5 - m_AngularDrag: 5 + m_Drag: 0.2 + m_AngularDrag: 0.2 m_UseGravity: 1 m_IsKinematic: 1 m_Interpolate: 0 @@ -14964,8 +14984,8 @@ MonoBehaviour: _enableTeleport: 0 _teleportThreshold: 1 _scaleThreshold: 1 - _clientAuthoritative: 1 - _sendToOwner: 1 + _clientAuthoritative: 0 + _sendToOwner: 0 _enableNetworkLod: 1 _interval: 1 _synchronizePosition: 1 diff --git a/Assets/Scripts/SS3D/Hacks/RagdollWhenPressingButton.cs b/Assets/Scripts/SS3D/Hacks/RagdollWhenPressingButton.cs index c7625ab17..7bf84ae16 100644 --- a/Assets/Scripts/SS3D/Hacks/RagdollWhenPressingButton.cs +++ b/Assets/Scripts/SS3D/Hacks/RagdollWhenPressingButton.cs @@ -1,4 +1,5 @@ -using SS3D.Core; +using FishNet.Object; +using SS3D.Core; using SS3D.Core.Behaviours; using SS3D.Systems.Animations; using SS3D.Systems.Entities.Humanoid; @@ -20,6 +21,9 @@ public class RagdollWhenPressingButton : NetworkActor [SerializeField] private float _timeRagdolled; + [SerializeField] + private float _randomForce; + private Controls.OtherActions _controls; public override void OnStartClient() @@ -31,17 +35,25 @@ public override void OnStartClient() _controls.Ragdoll.performed += HandleKnockdown; } - private void HandleKnockdown(InputAction.CallbackContext context) { if (_positionController.Position != PositionType.Ragdoll) { - _positionController.KnockDown(); + RpcKnockDown(); } else { _positionController.StopRagdoll(); } } + + [ServerRpc] + private void RpcKnockDown() + { + GetComponent().KnockDown(); + GetComponent().AddForceToAllParts(Random.insideUnitCircle * _randomForce); + } + + } } diff --git a/Assets/Scripts/SS3D/Systems/Animations/PositionController.cs b/Assets/Scripts/SS3D/Systems/Animations/PositionController.cs index eba3002f4..096c8a43d 100644 --- a/Assets/Scripts/SS3D/Systems/Animations/PositionController.cs +++ b/Assets/Scripts/SS3D/Systems/Animations/PositionController.cs @@ -165,7 +165,7 @@ public void TryToStandUp() RpcChangePosition(_standingAbility ? PositionType.Standing : PositionType.Proning); } - [Client] + [Server] public void KnockDown() { RpcChangePosition(PositionType.Ragdoll); @@ -198,7 +198,7 @@ private void RpcChangeMovement(MovementType movement) _movement = movement; } - [ServerRpc] + [ServerRpc(RequireOwnership = false)] private void RpcChangePosition(PositionType position) { _previousPosition = _position; diff --git a/Assets/Scripts/SS3D/Systems/Entities/Humanoid/Ragdoll.cs b/Assets/Scripts/SS3D/Systems/Entities/Humanoid/Ragdoll.cs index 77752f677..db9eb8bbb 100644 --- a/Assets/Scripts/SS3D/Systems/Entities/Humanoid/Ragdoll.cs +++ b/Assets/Scripts/SS3D/Systems/Entities/Humanoid/Ragdoll.cs @@ -6,6 +6,7 @@ using FishNet.Object.Synchronizing; using SS3D.Systems.Animations; using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -17,10 +18,6 @@ namespace SS3D.Systems.Entities.Humanoid /// public class Ragdoll : NetworkBehaviour { - - [SerializeField] - private Transform _armatureRoot; - [SerializeField] private Collider _characterCollider; @@ -40,221 +37,120 @@ public class Ragdoll : NetworkBehaviour private PositionController _positionController; private Transform[] _ragdollParts; - /// - /// If knockdown is supposed to expire - /// - private bool _isKnockdownTimed; - private readonly float _timeToResetBones = 0.7f; + private NetworkConnection _owner; + /// /// Determines how much higher than the lowest point character will be during AlignToHips(). This var prevent character from getting stuck in the floor /// private const float AlignmentYDelta = 0.0051f; - private class BoneTransform - { - public Vector3 Position; - public Quaternion Rotation; - } - /// - /// Bones Transforms (position and rotation) in the first frame of StandUp animation - /// - private BoneTransform[] _standUpBones; - - /// - /// Bones Transforms (position and rotation) during the Ragdoll state - /// - private BoneTransform[] _ragdollBones; - public bool IsFacingDown { get; private set; } - - public override void OnStartNetwork() + public override void OnStartServer() { - base.OnStartNetwork(); + base.OnStartServer(); _ragdollParts = (from part in GetComponentsInChildren() select part.transform.GetComponent()).ToArray(); - _standUpBones = new BoneTransform[_ragdollParts.Length]; - _ragdollBones = new BoneTransform[_ragdollParts.Length]; - - for (int boneIndex = 0; boneIndex < _ragdollParts.Length; boneIndex++) - { - _standUpBones[boneIndex] = new(); - _ragdollBones[boneIndex] = new(); - } // All rigid bodies are kinematic at start, only the owner should be able to change that afterwards. SetRagdollPhysic(false); - ToggleSyncRagdoll(false); _positionController.ChangedPosition += HandleChangedPosition; } + [Server] private void HandleChangedPosition(PositionType position, float recoverTime) { if (position == PositionType.ResetBones) { - AnimationClip recoverAnimation = _positionController.GetRecoverFromRagdollClip(); - BonesReset(recoverAnimation, recoverTime); - } - else if (position == PositionType.Ragdoll) - { - StartRagdoll(); + SetRagdollPhysic(false); } } - public override void OnOwnershipClient(NetworkConnection prevOwner) + [Server] + public void KnockDown() { - base.OnOwnershipClient(prevOwner); - //SetRagdollPhysic(IsOwner); + SetRagdollPhysic(true); + StartCoroutine(AlignToHips()); + _positionController.KnockDown(); } - - private void StartRagdoll() + [Server] + public void AddForceToAllParts(Vector3 force) { - if (!IsOwner && Owner.ClientId != -1) - return; - - SetRagdollPhysic(true); - // put that in its own method - /*foreach (Transform part in _ragdollParts) + foreach (Transform part in _ragdollParts) { - part.GetComponent().AddForce(movement, ForceMode.VelocityChange); - } */ + part.GetComponent().AddForce(force, ForceMode.VelocityChange); + } } /// /// Adjust player's position and rotation. Character's x and z coords equals hips coords, y is at lowest positon. /// Character's y rotation is aligned with hips forwards direction. /// - private void AlignToHips() - { - IsFacingDown = _hips.transform.forward.y < 0; - Vector3 originalHipsPosition = _hips.position; - Vector3 newPosition = _hips.position; - // Get the lowest position - if (Physics.Raycast(transform.position, Vector3.down, out RaycastHit hitInfo)) - { - newPosition.y = hitInfo.point.y + AlignmentYDelta; - } - _character.position = newPosition; - _hips.position = originalHipsPosition; - - Vector3 desiredDirection = _hips.up * (IsFacingDown ? 1 : -1); - desiredDirection.y = 0; - desiredDirection.Normalize(); - Quaternion originalHipsRotation = _hips.rotation; - Vector3 rotationDifference = Quaternion.FromToRotation(transform.forward, desiredDirection).eulerAngles; - // Make sure that rotation is only around Y axis - rotationDifference.x = 0; - rotationDifference.z = 0; - transform.rotation *= Quaternion.Euler(rotationDifference); - _hips.rotation = originalHipsRotation; - } - - /// - /// Switch to BonesReset state and prepare for BonesResetBehavior - /// - private void BonesReset(AnimationClip clip, float timeToResetBones) - { - SetRagdollPhysic(false); - PopulateStandUpPartsTransforms(clip); - for (int partIndex = 0; partIndex < _ragdollParts.Length; partIndex++) - { - _ragdollParts[partIndex].DOLocalMove(_standUpBones[partIndex].Position, timeToResetBones); - _ragdollParts[partIndex].DOLocalRotate(_standUpBones[partIndex].Rotation.eulerAngles, timeToResetBones); - } - } - - /// - /// Copy current ragdoll parts local positions and rotations to array. - /// - /// Array, that receives ragdoll parts positions - private void PopulatePartsTransforms(BoneTransform[] partsTransforms) + + [Server] + private IEnumerator AlignToHips() { - for (int partIndex = 0; partIndex < _ragdollParts.Length; partIndex++) + while (_positionController.Position == PositionType.Ragdoll) { - partsTransforms[partIndex].Position = _ragdollParts[partIndex].localPosition; - partsTransforms[partIndex].Rotation = _ragdollParts[partIndex].localRotation; + IsFacingDown = _hips.transform.forward.y < 0; + Vector3 originalHipsPosition = _hips.position; + Vector3 newPosition = _hips.position; + + // Get the lowest position + if (Physics.Raycast(transform.position, Vector3.down, out RaycastHit hitInfo)) + { + newPosition.y = hitInfo.point.y + AlignmentYDelta; + } + + _character.position = newPosition; + _hips.position = originalHipsPosition; + + Vector3 desiredDirection = _hips.up * (IsFacingDown ? 1 : -1); + desiredDirection.y = 0; + desiredDirection.Normalize(); + Quaternion originalHipsRotation = _hips.rotation; + Vector3 rotationDifference = Quaternion.FromToRotation(transform.forward, desiredDirection).eulerAngles; + + // Make sure that rotation is only around Y axis + rotationDifference.x = 0; + rotationDifference.z = 0; + transform.rotation *= Quaternion.Euler(rotationDifference); + _hips.rotation = originalHipsRotation; + + yield return null; } } - /// - /// Copy ragdoll parts position in first frame of StandUp animation to array - /// - /// Array, that receives ragdoll parts positions - /// - private void PopulateStandUpPartsTransforms(AnimationClip animationClip) + [Server] + private void SetRagdollPhysic(bool isOn) { - // Copy into the _ragdollBones list the local position and rotation of bones, while in the current ragdoll position - PopulatePartsTransforms(_ragdollBones); - - // Register some position and rotation before switching to the first frame of getting up animation - Vector3 originalArmaturePosition = _armatureRoot.localPosition; - Quaternion originalArmatureRotation = _armatureRoot.localRotation; - Vector3 originalPosition = _character.position; - Quaternion originalRotation = _character.rotation; - // Put character into first frame of animation - animationClip.SampleAnimation(gameObject, 0f); + UnityEngine.Debug.Log($"Owner is {Owner}"); - - // Put back character at the right place as the animation moved it - _character.position = originalPosition; - _character.rotation = originalRotation; - - // Register hips position and rotation as moving the armature will messes with the hips position - Vector3 originalHipsPosition = _hips.position; - Quaternion originalHipsRotation = _hips.rotation; - - // Put back armature at the right place as the animation moved it - _armatureRoot.localPosition = originalArmaturePosition; - _armatureRoot.localRotation = originalArmatureRotation; - - // When moving the armature, it messes with the hips position, so we also move the hips back - _hips.position = originalHipsPosition; - _hips.rotation = originalHipsRotation; - - // Populate the bones local position and rotation when in first frame of animation - PopulatePartsTransforms(_standUpBones); - - // Move bones back to the ragdolled position they were in - for (int partIndex = 0; partIndex < _ragdollParts.Length; partIndex++) + // Managing ownership here is necessary as ragdoll is fully server handled, but player movement is client authoritative. + // This should be done in an ownership manager or something, and eventually, player movement should be server auth. + if (isOn) { - _ragdollParts[partIndex].localPosition = _ragdollBones[partIndex].Position; - _ragdollParts[partIndex].localRotation = _ragdollBones[partIndex].Rotation; + _owner = Owner; + RemoveOwnership(); } - } - - /// - /// Toggle the network transform syncing of the ragdoll parts, to save up on those sweet bytes. - /// - /// true if the network transform of the ragdoll parts should sync - /// - private void ToggleSyncRagdoll(bool isActive) - { - foreach (Transform part in _ragdollParts) + else if(_owner != null) { - part.GetComponent().SetInterval(_ragdollPartSyncInterval); - part.GetComponent().SetSynchronizePosition(isActive); - part.GetComponent().SetSynchronizeRotation(isActive); + GiveOwnership(_owner); } - } - - private void SetRagdollPhysic(bool isOn) - { - ToggleSyncRagdoll(isOn); _characterRigidBody.isKinematic = isOn; - - foreach (Transform part in _ragdollParts) - { - part.GetComponent().isKinematic = !isOn; - } - _characterCollider.isTrigger = isOn; foreach (Transform part in _ragdollParts) { + part.GetComponent().isKinematic = !isOn; part.GetComponent().isTrigger = !isOn; + + part.GetComponent().SetInterval(_ragdollPartSyncInterval); + part.GetComponent().SetSynchronizePosition(isOn); + part.GetComponent().SetSynchronizeRotation(isOn); } } } diff --git a/Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs b/Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs new file mode 100644 index 000000000..051371a1b --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs @@ -0,0 +1,149 @@ +using Cysharp.Threading.Tasks; +using DG.Tweening; +using FishNet.Object; +using SS3D.Core.Behaviours; +using SS3D.Systems.Animations; +using System.Linq; +using UnityEngine; + +namespace SS3D.Systems.Entities.Humanoid +{ + public class RagdollRecoverAnimator : NetworkActor + { + + [SerializeField] + private PositionController _positionController; + + [SerializeField] + private Transform _armatureRoot; + + private Transform[] _ragdollParts; + + [SerializeField] + private Transform _character; + + [SerializeField] + private Transform _hips; + + private class BoneTransform + { + public Vector3 Position; + public Quaternion Rotation; + } + + /// + /// Bones Transforms (position and rotation) in the first frame of StandUp animation + /// + private BoneTransform[] _standUpBones; + + /// + /// Bones Transforms (position and rotation) during the Ragdoll state + /// + private BoneTransform[] _ragdollBones; + + public override void OnStartClient() + { + base.OnStartClient(); + _ragdollParts = (from part in GetComponentsInChildren() select part.transform.GetComponent()).ToArray(); + _standUpBones = new BoneTransform[_ragdollParts.Length]; + _ragdollBones = new BoneTransform[_ragdollParts.Length]; + + for (int boneIndex = 0; boneIndex < _ragdollParts.Length; boneIndex++) + { + _standUpBones[boneIndex] = new(); + _ragdollBones[boneIndex] = new(); + } + + _positionController.ChangedPosition += HandleChangedPosition; + } + + [Client] + private void HandleChangedPosition(PositionType position, float recoverTime) + { + if (position == PositionType.ResetBones) + { + AnimationClip recoverAnimation = _positionController.GetRecoverFromRagdollClip(); + BonesReset(recoverAnimation, recoverTime); + } + } + + /// + /// Switch to BonesReset state and prepare for BonesResetBehavior + /// + + [Client] + private void BonesReset(AnimationClip clip, float timeToResetBones) + { + PopulateStandUpPartsTransforms(clip); + for (int partIndex = 0; partIndex < _ragdollParts.Length; partIndex++) + { + _ragdollParts[partIndex].DOLocalMove(_standUpBones[partIndex].Position, timeToResetBones); + _ragdollParts[partIndex].DOLocalRotate(_standUpBones[partIndex].Rotation.eulerAngles, timeToResetBones); + } + } + + /// + /// Copy current ragdoll parts local positions and rotations to array. + /// + /// Array, that receives ragdoll parts positions + + [Client] + private void PopulatePartsTransforms(BoneTransform[] partsTransforms) + { + for (int partIndex = 0; partIndex < _ragdollParts.Length; partIndex++) + { + partsTransforms[partIndex].Position = _ragdollParts[partIndex].localPosition; + partsTransforms[partIndex].Rotation = _ragdollParts[partIndex].localRotation; + } + } + + /// + /// Copy ragdoll parts position in first frame of StandUp animation to array + /// + /// Array, that receives ragdoll parts positions + /// + + [Client] + private void PopulateStandUpPartsTransforms(AnimationClip animationClip) + { + // Copy into the _ragdollBones list the local position and rotation of bones, while in the current ragdoll position + PopulatePartsTransforms(_ragdollBones); + + // Register some position and rotation before switching to the first frame of getting up animation + Vector3 originalArmaturePosition = _armatureRoot.localPosition; + Quaternion originalArmatureRotation = _armatureRoot.localRotation; + Vector3 originalPosition = _character.position; + Quaternion originalRotation = _character.rotation; + + // Put character into first frame of animation + animationClip.SampleAnimation(gameObject, 0f); + + + // Put back character at the right place as the animation moved it + _character.position = originalPosition; + _character.rotation = originalRotation; + + // Register hips position and rotation as moving the armature will messes with the hips position + Vector3 originalHipsPosition = _hips.position; + Quaternion originalHipsRotation = _hips.rotation; + + // Put back armature at the right place as the animation moved it + _armatureRoot.localPosition = originalArmaturePosition; + _armatureRoot.localRotation = originalArmatureRotation; + + // When moving the armature, it messes with the hips position, so we also move the hips back + _hips.position = originalHipsPosition; + _hips.rotation = originalHipsRotation; + + // Populate the bones local position and rotation when in first frame of animation + PopulatePartsTransforms(_standUpBones); + + // Move bones back to the ragdolled position they were in + for (int partIndex = 0; partIndex < _ragdollParts.Length; partIndex++) + { + _ragdollParts[partIndex].localPosition = _ragdollBones[partIndex].Position; + _ragdollParts[partIndex].localRotation = _ragdollBones[partIndex].Rotation; + } + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs.meta b/Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs.meta new file mode 100644 index 000000000..376dde312 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Entities/Humanoid/RagdollRecoverAnimator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58b3b3c3948fc4445997581f3ebd8f5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: