sasalka/Code/Player/Dedugan.cs
2025-06-29 12:39:23 +03:00

211 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using Sandbox;
using Sandbox.Citizen;
using Sasalka;
using ShrimpleCharacterController;
using System.Collections.Generic;
using System.Linq;
public sealed partial class Dedugan : Component, IUseContext, Component.INetworkSpawn
{
[RequireComponent] public ShrimpleCharacterController.ShrimpleCharacterController Controller { get; set; }
[RequireComponent] public CitizenAnimationHelper AnimationHelper { get; set; }
[Property] public SkinnedModelRenderer Renderer { get; set; }
[Property] public GameObject Camera { get; set; }
[Property] public GameObject CameraPivot { get; set; }
[Property] public GameObject Eyes { get; set; }
[Property] public GameObject InventoryUI { get; set; }
[Property] public Vector3 CamOffset { get; set; }
[Property] [Range( 50f, 1200f, 10f )] public float WalkSpeed { get; set; } = 100f;
[Property] [Range( 100f, 1500f, 20f )] public float RunSpeed { get; set; } = 300f;
[Property] [Range( 25f, 1100f, 5f )] public float DuckSpeed { get; set; } = 50f;
[Property] [Range( 200f, 1500f, 20f )] public float JumpStrength { get; set; } = 350f;
[Property] [Range( 10f, 500f, 10f )] public float InteractDistance { get; set; } = 350f;
[Sync] public Angles NetworkedEyeAngles { get; set; }
public Angles EyeAngles { get; set; }
[Sync] private float IsDucking { get; set; } = 0f;
[Sync] public bool IsDancing { get; set; } = false;
[Sync] public int Health { get; set; } = 100;
private RagdollController RagdollController { get; set; }
[Property] public Vector3 OverrideGravity { get; set; } = Vector3.Zero;
private Vector3 _directionToAxis = Vector3.Up;
private Vector3 _up = Vector3.Up;
private Vector3 _forward = Vector3.Forward;
private Vector3 _right = Vector3.Right;
private Vector3 _wishDirection;
// Кэш для оптимизации
private bool _isOwner;
private float _lastBodyYaw;
private float _lastCameraYaw;
private bool _bodyRotationDirty = true;
protected override void OnStart()
{
InventoryStart();
RagdollController = Components.Get<RagdollController>();
// Renderer = Components.Get<SkinnedModelRenderer>( FindMode.EverythingInSelfAndDescendants );
var cameraComponent = Camera.GetComponent<CameraComponent>();
var listener = Components.Get<AudioListener>( true );
cameraComponent.Enabled = false;
InventoryUI.Enabled = false;
listener.Enabled = false;
if ( !Network.IsOwner ) return;
cameraComponent.Enabled = true;
listener.Enabled = true;
InventoryUI.Enabled = true;
if ( Renderer is null )
return;
Renderer.OnFootstepEvent += OnFootstepEvent;
}
protected override void OnUpdate()
{
_isOwner = Network.IsOwner;
UpdateCustomAnimations();
InventoryUpdate();
if ( _isOwner )
{
EyeAngles += Input.AnalogLook;
EyeAngles = EyeAngles.WithPitch( MathX.Clamp( EyeAngles.pitch, -89f, 89f ) );
NetworkedEyeAngles = EyeAngles;
UpdateBodyRotation();
RotateCamera();
InteractionsUpdate();
}
else
{
EyeAngles = NetworkedEyeAngles;
UpdateBodyRotation();
Camera.LocalRotation = EyeAngles.ToRotation();
var pivotOffset = CameraPivot.LocalRotation.Right * CamOffset.y +
CameraPivot.LocalRotation.Forward * CamOffset.x +
CameraPivot.LocalRotation.Up * CamOffset.z;
var rotatedOffset = pivotOffset * EyeAngles.ToRotation();
Camera.WorldPosition = CameraPivot.WorldPosition + rotatedOffset;
}
}
protected override void OnFixedUpdate()
{
UpdateMovement();
}
protected override void DrawGizmos()
{
DrawDebugGizmos();
}
/// <summary>
/// Сохраняет инвентарь при выходе из игры
/// </summary>
public void SaveInventoryOnExit()
{
if ( Network.IsOwner && Inventory != null )
{
Log.Info( "Сохраняем инвентарь при выходе из игры..." );
Sasalka.InventorySaveSystem.SaveInventory( Inventory );
}
}
/// <summary>
/// Реализация интерфейса IUseContext
/// Возвращает список используемых предметов
/// </summary>
public IEnumerable<IUseable> GetUsables()
{
// Возвращаем пустой список, так как теперь оружие управляется через новую систему
return Enumerable.Empty<IUseable>();
}
/// <summary>
/// Обновление поворота тела с учетом режима прицеливания
/// </summary>
private void UpdateBodyRotation()
{
var currentBodyYaw = Renderer.LocalRotation.Yaw();
var currentCameraYaw = EyeAngles.yaw;
// Проверяем, изменились ли углы
if ( Math.Abs( currentBodyYaw - _lastBodyYaw ) < 0.1f &&
Math.Abs( currentCameraYaw - _lastCameraYaw ) < 0.1f &&
!_bodyRotationDirty )
{
return; // Пропускаем обновление, если углы не изменились
}
_lastBodyYaw = currentBodyYaw;
_lastCameraYaw = currentCameraYaw;
_bodyRotationDirty = false;
var targetRotation = Rotation.LookAt( Rotation.FromYaw( EyeAngles.yaw ).Forward, -_directionToAxis );
var currentForward = Renderer.LocalRotation.Forward;
float angleDiff = currentForward.Angle( targetRotation.Forward );
// Проверяем, нужно ли поворачивать тело
bool shouldRotateBody = false;
if ( InAds )
{
if ( Controller.Velocity.Length > 10f )
{
// При беге - центрируем тело (угол > 15°)
if ( angleDiff > 15f )
{
shouldRotateBody = true;
}
}
else
{
// При стоянии - мертвая зона 85°
if ( angleDiff > 85f )
{
shouldRotateBody = true;
}
}
}
else
{
// В обычном режиме - поворот при движении и угле больше 15 градусов
if ( angleDiff > 15f && Controller.Velocity.Length > 10f )
{
shouldRotateBody = true;
}
}
if ( shouldRotateBody )
{
Renderer.LocalRotation = Rotation.Slerp( Renderer.LocalRotation, Rotation.FromYaw( EyeAngles.yaw ),
Time.Delta * 3f );
_bodyRotationDirty = true; // Помечаем, что тело повернулось
}
}
protected override void OnDestroy()
{
// Сохраняем инвентарь при уничтожении объекта (закрытие игры)
SaveInventoryOnExit();
}
}