BITFALL/Assets/Artists/Scripts/Entities/Character/EntityCharacter.cs

267 lines
9.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using BITFALL.Cosmetic;
using BITFALL.Entities.Equipment;
using BITFALL.HotFix;
using BITFALL.Player.Movement;
using BITKit.PlayerCamera;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Animations.Rigging;
using UnityEngine.Rendering;
namespace BITKit.Entities.Player.Character
{
public class PlayerCharacter : EntityPlayerBehavior
{
[DictionaryReferenceConfig(nameof(Player_Mesh_Type_FPV))]
public const string Player_Mesh_Type_FPV = nameof(Player_Mesh_Type_FPV);
[DictionaryReferenceConfig(nameof(Player_Mesh_Type_TPV))]
public const string Player_Mesh_Type_TPV = nameof(Player_Mesh_Type_TPV);
[DictionaryReferenceConfig(nameof(Player_Mesh_Type_FPVOverride))]
public const string Player_Mesh_Type_FPVOverride = nameof(Player_Mesh_Type_FPVOverride);
[DictionaryReferenceConfig(nameof(Player_Mesh_Type_TPV_Group))]
public const string Player_Mesh_Type_TPV_Group = nameof(Player_Mesh_Type_TPV_Group);
private readonly List<Renderer> fpvRenderer = new();
private readonly List<Renderer> tpvRenderer = new();
private readonly List<Renderer> fpvOverrideRenderers = new();
private readonly List<Renderer> tpvOverrideRenderers = new();
[Header(Constant.Header.Reference)]
[SerializeReference, SubclassSelector] public IReference getDamage;
[Inject(true)] private ICosmeticService cosmeticService;
[Inject(true)] private IHealth _health;
[Inject(true)] private IPlayerCameraService _cameraService;
[Inject(true)] private IEntityOverride _entityOverride;
[Inject(true)] private IEntityEquipment _equipment;
[Inject(true)] private IEntityMovement _movement;
private readonly ValidHandle allowFPVOverride = new();
private readonly IntervalUpdate _freezeInterval=new (0.01f);
private bool _isDirty;
private bool _lock;
private void OnCosmeticsChange()
{
_lock = true;
}
public override void OnAwake()
{
if (cosmeticService is not null)
{
cosmeticService.OnCosmeticsChange += OnCosmeticsChange;
cosmeticService.OnCosmeticsChanged += OnCosmeticsChanged;
}
if (_health is not null)
{
_health.OnSetAlive += SetDirty;
_health.OnDamageRelease += OnDamageRelease;
}
if (_cameraService is not null)
_cameraService.OnCameraActivated += SetDirty;
if (_entityOverride is not null)
_entityOverride.OnOverride += _ =>
{
UpdateMeshState();
allowFPVOverride.SetElements(_entityOverride, _);
};
if (_equipment is not null)
{
_equipment.OnEquipAddressable += OnEquipmentOnOnEquipAddressable;
_equipment.OnUnEquipAddressable += OnEquipmentOnOnUnEquipAddressable;
void OnEquipmentOnOnUnEquipAddressable(string _)
{
allowFPVOverride.AddElement(_equipment);
allowFPVOverride.RemoveDisableElements(_equipment);
}
void OnEquipmentOnOnEquipAddressable(string _)
{
allowFPVOverride.RemoveElement(_equipment);
allowFPVOverride.AddDisableElements(_equipment);
}
}
if (_movement is not null)
{
_movement.OnStateChanged += OnNewState;
OnNewState(null, _movement.CurrentState);
void OnNewState(IEntityMovementState oldState, IEntityMovementState newState)
{
var allow = newState switch
{
IPlayerEdgeClimbState => true,
IPlayerClimbState => true,
IPlayerVaultState => true,
IPlayerKnockdownState => true,
IPlayerSlideState => true,
IPlayerFixedState => true,
IPlayerLinkState => true,
IPlayerCrawlState=>true,
_ => false,
};
allowFPVOverride.SetElements(_movement,allow);
allowFPVOverride.SetDisableElements(_movement,!allow);
}
}
allowFPVOverride.AddListener(value =>
{
foreach (var x in fpvOverrideRenderers)
{
try
{
x.enabled = value;
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
}
});
}
public override void OnDestroyComponent()
{
base.OnDestroyComponent();
if (cosmeticService is null) return;
cosmeticService.OnCosmeticsChange -= OnCosmeticsChange;
cosmeticService.OnCosmeticsChanged -= OnCosmeticsChanged;
}
public override void OnUpdate(float deltaTime)
{
if (!_isDirty || _lock || !_freezeInterval.AllowUpdateWithoutReset) return;
_isDirty = false;
UpdateMeshState();
}
private void OnDamageRelease(DamageMessage damageMessage)
{
if (getDamage is not null)
UnityEntity.Invoke<string>(Constant.Animation.Play, getDamage.Value);
}
private void UpdateMeshState()
{
allowFPVOverride.Invoke();
switch (_health, _cameraService)
{
case (null, null):
SetFPV(false);
allowFPVOverride.Invoke(false);
break;
case (null, not null):
SetFPV(_cameraService.IsCameraActivated);
break;
case (not null, null):
SetFPV(_health.IsAlive);
break;
case (not null, not null):
SetFPV(_health.IsAlive && _cameraService.IsCameraActivated);
break;
}
}
private void SetFPV(bool isFpv)
{
var shadowMode = isFpv ?
ShadowCastingMode.ShadowsOnly :
ShadowCastingMode.On;
foreach (var x in fpvRenderer)
{
x.enabled = isFpv;
}
foreach (var x in tpvRenderer)
{
x.shadowCastingMode = shadowMode;
}
foreach (var x in tpvOverrideRenderers)
{
x.shadowCastingMode =
_entityOverride is not null
? _entityOverride.IsOvering ? ShadowCastingMode.On : shadowMode
: shadowMode;
}
if (_health is not null && TryGetComponent<RigBuilder>(out var rigBuilder))
{
rigBuilder.enabled = _health.IsAlive;
}
}
[BIT]
private void OnCosmeticsChanged()
{
_lock = true;
BITAppForUnity.ThrowIfNotPlaying();
fpvRenderer.Clear();
tpvRenderer.Clear();
fpvOverrideRenderers.Clear();
tpvOverrideRenderers.Clear();
var _tpvOverrideRenderers = new List<Transform>();
foreach (var _tag in GetComponentsInChildren<Tag>(true))
{
var tags = _tag.GetTags();
if (tags.Contains(Player_Mesh_Type_TPV_Group))
_tpvOverrideRenderers.Add(_tag.transform);
if (_tag.TryGetComponent<Renderer>(out var _renderer) is false) continue;
if (tags.Contains(Player_Mesh_Type_FPV))
fpvRenderer.Add(_renderer);
if (tags.Contains(Player_Mesh_Type_TPV))
tpvRenderer.Add(_renderer);
if (tags.Contains(Player_Mesh_Type_FPVOverride))
fpvOverrideRenderers.Add(_renderer);
}
var tpvRenderers = _tpvOverrideRenderers.SelectMany(x => x.GetComponentsInChildren<Renderer>(true));
tpvOverrideRenderers.Clear();
tpvOverrideRenderers.AddRange(tpvRenderers);
UpdateMeshState();
allowFPVOverride.Invoke();
_lock = false;
_isDirty = false;
if (TryGetComponent<RigBuilder>(out var rigBuilder))
{
rigBuilder.Clear();
foreach (var rig in GetComponentsInChildren<Rig>())
{
rigBuilder.layers.Add(new RigLayer(rig));
}
rigBuilder.enabled = true;
rigBuilder.Build();
GetComponent<Animator>().Rebind();
}
}
private void SetDirty(bool any) => SetDirty();
private void SetDirty()
{
_freezeInterval.Reset();
_isDirty = true;
}
}
}