using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using BITKit; using BITKit.Animations; using BITKit.StateMachine; using System.Linq; using System.Security.Permissions; using Animancer; using AYellowpaper.SerializedCollections; using BITFALL; using BITFALL.Entities.Equipment; using BITFALL.Entities.Inventory; using BITFALL.Guns.Modify; using BITFALL.Player.Equip; using BITFALL.Props; using BITKit.Entities.Melee; using BITKit.Entities.VFX; using BITKit.UX; using Cinemachine; using Cysharp.Threading.Tasks; using Unity.Mathematics; namespace BITKit.Entities { public abstract class BITEquipBase : StateBasedMonoBehaviour, IEquipBase where T : IState { public const string C_Weapon = "c_weapon"; public string[] SearchKey { get; set; } [Header(Constant.Header.Settings)] [SerializeField] protected ScriptableItem item; //[Header(Constant.Header.Property)] //[SerializeField] public SerializedDictionary animationProperties; [Header(Constant.Header.Components)] [SerializeField] private AnimancerComponent animancerComponent; [SerializeField] private AnimancerComponent additionalAnimancerComponent; [SerializeField] protected EntityVFXPlayer vfxPlayer; [SerializeField] private Renderer[] renderers; [SerializeField] protected Transform cameraTransform; [SerializeField] protected Prop_Modify _modify; [Header(Constant.Header.Services)] [SerializeReference,SubclassSelector] protected IMeleeService meleeService; [Inject] private IMotionMatchingService motionMatchingService = new ScriptableMotionMatchingSingleton(); public IEntity Entity { get; set; } public Entity UnityEntity=>Entity as Entity; public AnimancerComponent AnimancerComponent=>animancerComponent; public AnimancerComponent AdditionalAnimancerComponent=>additionalAnimancerComponent; public IMotionMatchingService MotionMatchingService=>motionMatchingService; public IBasicItem Item { get => _item; set { OnApply?.Invoke(_item = value); OnItemApplied(value); } } public ScriptableItem ScriptableItem => item; private IBasicItem _item; //public IDictionary AnimationProperties = null; [Inject(true),NonSerialized] public InputActionGroup inputActionGroup; protected readonly ValidHandle AllowRendering = new(); public virtual string AddressablePath => item.AddressablePath; protected virtual Vector3 meleeForce => Transform.forward; public bool IsEntered { get; set; } private Quaternion _initialCameraRotation; protected event Action OnApply; [Inject] protected IEntityOverride _entityOverride; [Inject(true)] protected IEntityInventory _inventory; [Inject(true)] protected IUXPopup _uxPopup; public IEntityInventory Inventory=>_inventory; public IUXPopup UXPopup=>_uxPopup; public override void Initialize() { SearchKey = new []{C_Weapon,item.Name}; base.Initialize(); } public virtual void Entry() { if (animancerComponent) { animancerComponent.enabled = true; animancerComponent.Animator.enabled = true; } if (additionalAnimancerComponent) { additionalAnimancerComponent.enabled = true; additionalAnimancerComponent.Animator.enabled = true; } AllowRendering.AddElement(this); //inputActionGroup.allowInput.AddElement(this); if (vfxPlayer) vfxPlayer.enabled = true; } public virtual UniTask EntryAsync() { return UniTask.CompletedTask; } public virtual void Entered() { } public virtual void Exit() { if (vfxPlayer) vfxPlayer.enabled = false; } public virtual async UniTask ExitAsync() { while (AnimancerComponent && AnimancerComponent.IsPlaying()) { await UniTask.NextFrame(); if (destroyCancellationToken.IsCancellationRequested) return; } } public virtual async void Exited() { AllowRendering.RemoveElement(this); if (cameraTransform) { cameraTransform.localPosition = default; cameraTransform.localRotation = _initialCameraRotation; } await UniTask.NextFrame(destroyCancellationToken); if (animancerComponent) { animancerComponent.enabled = false; animancerComponent.Animator.enabled = false; } if(AdditionalAnimancerComponent) { AdditionalAnimancerComponent.enabled = false; AdditionalAnimancerComponent.Stop(); AdditionalAnimancerComponent.Animator.enabled = false; } } public virtual void OnAwake() { //AnimationProperties= animationProperties.ToDictionary(x=>x.Key,x=>x.Value.Value); if (renderers is null or { Length: 0 }) { renderers = GetComponentsInChildren(true); } foreach (var x in StateDictionary.Values) { Entity.Inject(x); } AllowRendering.AddListener(x => { renderers.ForEach(y => { y.enabled = x; }); if (_modify) _modify.AllowModify.SetDisableElements(this, !x); }); if (animancerComponent) { animancerComponent.Animator.enabled = false; animancerComponent.enabled = false; } AllowRendering.Invoke(); if (cameraTransform) _initialCameraRotation = cameraTransform.localRotation; Initialize(); inputActionGroup?.allowInput.Invoke(); if (vfxPlayer) vfxPlayer.enabled = false; _entityOverride.OnOverride += OnOverride; OnApply += (x) => { if (!_modify) return; if (x is not null && x.TryGetProperty(out var modify)) { _modify.Modify(modify); } else { _modify.ClearModify(); } }; if (_modify) _modify.ClearModify(); } private void OnOverride(bool obj) { if (inputActionGroup is not null) inputActionGroup.allowInput.SetDisableElements("Override", obj); AllowRendering.SetDisableElements("Override", obj); } public virtual void OnDestroy() { inputActionGroup?.Dispose(); } public virtual void OnStart() { } public virtual void OnUpdate(float deltaTime) { // foreach (var pair in animationProperties) // { // AnimationProperties[pair.Key] = pair.Value.Value; // } } public virtual bool IsSupportItem(IBasicItem item) =>item is not null && item.AddressablePath == AddressablePath; public virtual void PlayAudio(string eventName) { } public virtual void EquipEvent(string eventName){} public virtual void AnimationEvent(string eventName) { if (IsEntered is false) return; if (item is not ScriptableEquip equip) return; UnityEntity.Invoke(Constant.Animation.OnEvent, eventName); switch (eventName) { case "Melee": case "Attack": meleeService.Melee(new MeleeCommand { PlayerId = Entity.Id, Position = Transform.position, Force = meleeForce * equip.MeleeForce, Range = equip.MeleeRange, Damage = equip.MeleeDamage, Forward = UnityEntity.transform.forward }); break; case "HeavyAttack": meleeService.Melee(new MeleeCommand { PlayerId = Entity.Id, Position = Transform.position, Force = meleeForce * equip.HeavyMeleeForce, Range = equip.HeavyMeleeRange, Damage = equip.HeavyMeleeDamage, Forward = UnityEntity.transform.forward }); break; } } protected virtual void OnItemApplied(IBasicItem item) { } } [CustomType(typeof(IEquipService))] [CustomType(typeof(IEntityEquipment))] public class EntityEquipment : EntityBehavior,IEquipService,IEntityEquipment { public IOptional Zoom { get; } = new Optional(){Value = 1}; [SerializeField] protected Optional allowAnimationFOV; [SerializeField] private int layer; public float Stable { get; set; } public float Aim { get; set; } public bool AllowAttack { get; set; } public bool AllowScope { get; set; } [SerializeField] private CinemachineVirtualCamera virtualCamera; [SerializeField] private Optional overrideIndex; [SerializeField] private Optional optionalScope; public IBasicItem CurrentItem { get; private set; } public event Action OnEquip; public event Action OnUnEquip; public event Action OnEquipAddressable; public event Action OnUnEquipAddressable; private readonly EntryGroup equips = new(); protected IEquipBase entryComplete; [Inject(true)] private IHealth _health; [Inject(true)] private IEntityOverride _entityOverride; public IValidHandle AllowEquip { get; } =new ValidHandle(); private readonly PrioritySelector _prioritySelector = new(); public override void OnAwake() { base.OnAwake(); foreach (var x in GetComponentsInChildren(true)) { Register(x); } equips.OnEntry += OnEntry; equips.OnExit += OnExit; AllowEquip.AddListener(OnAllowEquip); if (_health is not null) { _health.OnSetAlive += x => { AllowEquip.SetElements(this,x); if (x is false) { CurrentItem = null; EntryEquip(-1); } }; } } private void OnAllowEquip(bool allow) { if (allow) { EntryEquip(CurrentItem); } else { EntryEquip(-1); } } public override void OnStart() { base.OnStart(); foreach (var x in equips.list) { x.OnStart(); } if (overrideIndex.Allow && (_health?.IsAlive ?? true)) { EntryEquip(overrideIndex.Value); } } private void OnExit(IEquipBase obj) { OnUnEquipAddressable?.Invoke(obj.AddressablePath); OnUnEquip?.Invoke(obj.Item); //Debug.Log($"已退出:{obj.Item.Name}"); } private void OnEntry(IEquipBase obj) { OnEquipAddressable?.Invoke(obj.AddressablePath); obj.Item = CurrentItem; OnEquip?.Invoke(obj.Item); //Debug.Log($"已进入:{obj.Item.Name}"); } public override void OnUpdate(float deltaTime) { equips.Entry(_prioritySelector.Current); if (equips.index is not -1) { //equips.list[equips.index].Item = CurrentItem; } if (equips.TryGetEntried(out entryComplete)) { entryComplete.OnUpdate(deltaTime); } if (virtualCamera is not null) { var targetFov = Mathf.Lerp( virtualCamera.m_Lens.FieldOfView, Zoom.Allow ? Mathf.Rad2Deg * CalcZoomFOV(Mathf.Deg2Rad * 60f, Zoom.Value) : PlayerConfig.Singleton.Fov, 16*deltaTime ); if (_entityOverride is {IsOvering:true} && allowAnimationFOV.Allow) { virtualCamera.m_Lens.FieldOfView = Mathf.Lerp(virtualCamera.m_Lens.FieldOfView,allowAnimationFOV.Value,5*deltaTime); } else { virtualCamera.m_Lens.FieldOfView = Mathf.Lerp(PlayerConfig.Singleton.Fov, targetFov, Aim); } float CalcZoomFOV(float baseFOV, float zoom) { return 2.0f * Mathf.Atan(Mathf.Tan(baseFOV / 2.0f) / zoom); } } if (optionalScope.Allow) { optionalScope.Value.SetActive(AllowScope); } } public int FindIndex(Func factory) { return equips.list.FindIndex(x => factory.Invoke(x.AddressablePath)); } public bool IsSupportItem(IBasicItem item)=> equips.list.Any(x => x.IsSupportItem(item)); //public void EntryEquip(int index)=> equips.Entry(index); public void EntryEquip(int index) => _prioritySelector.Set(0, index); public void EntryEquip(IBasicItem item) { CurrentItem = item; //equips.Entry(x=>x.IsSupportItem(item)); // if (equips.list.TryGetAny(x => x.IsSupportItem(item), out var nextEquip)) // { // nextEquip.Item = item; // } var index = equips.list.FindIndex(x => x.IsSupportItem(item)); _prioritySelector.Set(0, index); } public void SetEquipPriority(int priority, IBasicItem item) { var index = equips.list.FindIndex(x => x.IsSupportItem(item)); _prioritySelector.Set(priority, index); } public void SetEquipPriority(int priority, int index) { _prioritySelector.Set(priority, index); } public void RemoveEquipPriority(int priority) { _prioritySelector.Remove(priority); } public void Register(IEquipBase equipBase) { equips.list.Add(equipBase); Entity.Inject(equipBase); equipBase.Entity = Entity; equipBase.OnAwake(); foreach (var x in equipBase.As().GetComponentsInChildren()) { x.gameObject.layer = layer; } foreach (var x in equipBase.As().GetComponentsInChildren()) { if (x is SkinnedMeshRenderer skinnedMeshRenderer) { skinnedMeshRenderer.updateWhenOffscreen = true; } x.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } } public void UnRegister(IEquipBase equipBase) { equips.list.Remove(equipBase); } } }