using Code.Game.Gameplay.Player; using UnityEngine; namespace Code.OfficeGame.BattleMode.Actions { public struct EntitySnapshot { public Vector3 Position; public Quaternion Rotation; public AnimatorSnapshot AnimatorSnapshot; public MovementControllerSnapshot ControllerSnapshot; public static EntitySnapshot GetSnapshot(EntityProperties entityProperties) { return new EntitySnapshot { Position = entityProperties.KinematicCharacterMotor.TransientPosition, Rotation = entityProperties.KinematicCharacterMotor.TransientRotation, AnimatorSnapshot = AnimatorSnapshot.GetSnapshot(entityProperties.animator), ControllerSnapshot = MovementControllerSnapshot.GetSnapshot(entityProperties.MovementController) }; } public static void RestoreSnapshot(EntityProperties entityProperties, EntitySnapshot snapshot) { // 1. Возвращаем капсулу KCC entityProperties.KinematicCharacterMotor.SetPositionAndRotation(snapshot.Position, snapshot.Rotation); entityProperties.KinematicCharacterMotor.BaseVelocity = Vector3.zero; snapshot.ControllerSnapshot.RestoreSnapshot(entityProperties.MovementController); // 2. Возвращаем позу и локальное смещение меша snapshot.AnimatorSnapshot.RestoreTo(entityProperties.animator); // 3. Синхронизируем физику Physics.SyncTransforms(); } } public struct AnimatorSnapshot { public struct LayerStateSnapshot { public int FullPathHash; public float NormalizedTime; public float LayerWeight; } public struct ParameterSnapshot { public int NameHash; public AnimatorControllerParameterType Type; public float FloatValue; public int IntValue; public bool BoolValue; } private LayerStateSnapshot[] _layers; private ParameterSnapshot[] _parameters; private Vector3 _localPosition; private Quaternion _localRotation; private float _speed; public static AnimatorSnapshot GetSnapshot(Animator animator) { var snapshot = new AnimatorSnapshot(); snapshot.CaptureFrom(animator); return snapshot; } public void CaptureFrom(Animator animator) { if (animator == null) return; Transform animTransform = animator.transform; _localPosition = animTransform.localPosition; _localRotation = animTransform.localRotation; _speed = animator.speed; int layerCount = animator.layerCount; if (_layers == null || _layers.Length != layerCount) _layers = new LayerStateSnapshot[layerCount]; for (int i = 0; i < layerCount; i++) { AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(i); _layers[i] = new LayerStateSnapshot { FullPathHash = stateInfo.fullPathHash, NormalizedTime = stateInfo.normalizedTime, LayerWeight = animator.GetLayerWeight(i) }; } int paramCount = animator.parameterCount; if (_parameters == null || _parameters.Length != paramCount) _parameters = new ParameterSnapshot[paramCount]; for (int i = 0; i < paramCount; i++) { AnimatorControllerParameter param = animator.GetParameter(i); int hash = param.nameHash; var paramSnapshot = new ParameterSnapshot { NameHash = hash, Type = param.type }; switch (param.type) { case AnimatorControllerParameterType.Float: paramSnapshot.FloatValue = animator.GetFloat(hash); break; case AnimatorControllerParameterType.Int: paramSnapshot.IntValue = animator.GetInteger(hash); break; case AnimatorControllerParameterType.Bool: case AnimatorControllerParameterType.Trigger: paramSnapshot.BoolValue = animator.GetBool(hash); break; } _parameters[i] = paramSnapshot; } } public void RestoreTo(Animator targetAnimator) { if (targetAnimator == null || _layers == null) return; targetAnimator.Rebind(); bool prevRootMotion = targetAnimator.applyRootMotion; targetAnimator.applyRootMotion = false; targetAnimator.speed = _speed; if (_parameters != null) { for (int i = 0; i < _parameters.Length; i++) { var p = _parameters[i]; if (targetAnimator.IsParameterControlledByCurve(p.NameHash)) continue; switch (p.Type) { case AnimatorControllerParameterType.Float: targetAnimator.SetFloat(p.NameHash, p.FloatValue); break; case AnimatorControllerParameterType.Int: targetAnimator.SetInteger(p.NameHash, p.IntValue); break; case AnimatorControllerParameterType.Bool: targetAnimator.SetBool(p.NameHash, p.BoolValue); break; case AnimatorControllerParameterType.Trigger: if (p.BoolValue) targetAnimator.SetTrigger(p.NameHash); else targetAnimator.ResetTrigger(p.NameHash); break; } } } int layerCount = Mathf.Min(_layers.Length, targetAnimator.layerCount); for (int i = 0; i < layerCount; i++) { var layer = _layers[i]; targetAnimator.SetLayerWeight(i, layer.LayerWeight); targetAnimator.Play(layer.FullPathHash, i, layer.NormalizedTime); } targetAnimator.Update(0f); Transform targetTransform = targetAnimator.transform; targetTransform.localPosition = _localPosition; targetTransform.localRotation = _localRotation; targetAnimator.applyRootMotion = prevRootMotion; } } public struct MovementControllerSnapshot { public Vector3 Velocity; public Vector3 LookInput; public Vector3 MoveInput; public static MovementControllerSnapshot GetSnapshot(MovementController movementController) { return new() { Velocity = movementController.InternalVelocityAdd, MoveInput = movementController.MoveInputVector, LookInput = movementController.LookInputVector }; } public void RestoreSnapshot(MovementController movementController) { movementController.InternalVelocityAdd = Velocity; movementController.MoveInputVector = MoveInput; movementController.LookInputVector = LookInput; } } }