using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using Cielonos.MainGame.Inventory; using DG.Tweening; using Opsive.BehaviorDesigner.Runtime; using Sirenix.OdinInspector; using SLSUtilities.FunctionalAnimation; using SLSUtilities.General; using UniRx; using UnityEngine; using UnityEngine.AI; using Ease = DG.Tweening.Ease; namespace Cielonos.MainGame.Characters { public partial class Automata : CharacterBase { public Player player => MainGameManager.Player; [TitleGroup("Data")] public FuncAnimDataCollection fullBodyFuncAnims; [TitleGroup("Data")] public FuncAnimDataCollection upperBodyFuncAnims; [TitleGroup("Data")] public AttackData attackData; [TitleGroup("Data")] public TimerData timerData; private List _registeredFunctionNames = new List(); [TitleGroup("Submodules")] [HideInEditorMode] public ActionRecordSubmodule actionRecordSm; [TitleGroup("Subcontrollers")] public BehaviorSubcontroller behaviorSc; private float _getHitTimer; protected override void Start() { base.Start(); RegisterFuncAnims(); RegisterFunctionsToAnimSc(); } protected override void InitializeSubmodules() { base.InitializeSubmodules(); actionRecordSm = new ActionRecordSubmodule(this); foreach (KeyValuePair timer in timerData.timers) { selfTimeSm.coolDownTimers[timer.Key] = new CooldownTimer(timer.Value); } } protected override void Update() { base.Update(); UpdateGetHit(); } } public partial class Automata { public override bool GetHit(Breakthrough.Type breakthroughType, out float recoveryTime, DisruptionType disruptionType = DisruptionType.NormalExternal, Vector3 direction = default, string funcAnimName = "") { if (string.IsNullOrEmpty(funcAnimName)) { funcAnimName = GetHitFuncAnimName(breakthroughType, direction); } if (base.GetHit(breakthroughType, out recoveryTime, disruptionType, direction, funcAnimName)) { CombatManager.CoordinatorSm.ReleaseAll(this); if (_getHitTimer <= 0) { if (behaviorSc.navMeshAgent.enabled) { behaviorSc.navMeshAgent.isStopped = true; } _getHitTimer = recoveryTime; } else { _getHitTimer = Mathf.Max(_getHitTimer, recoveryTime); } return true; } return false; } protected virtual void UpdateGetHit() { _getHitTimer -= selfTimeSm.DeltaTime; if (_getHitTimer <= 0) { if (behaviorSc.navMeshAgent.enabled) { behaviorSc.navMeshAgent.isStopped = false; } } } } public partial class Automata { public override void Die() { eventSm.onDeath.Invoke(); CombatManager.CoordinatorSm.ReleaseAll(this); float deathProcessTime = 0f; var deathFuncAnim = fullBodyFuncAnims.animDataList.Find(data => data.animInfo.animationName == "Death"); if (deathFuncAnim != null) { animationSc.fullBodyFuncAnimSm.Play("Death"); behaviorSc.mainBehaviorTree.StopBehavior(); behaviorSc.navMeshAgent.enabled = false; collisionSc.DisableAllColliders(); deathProcessTime = deathFuncAnim.animationClip.length; } statusSm.isDead = true; if (deathProcessTime > 0) { Observable.Timer(TimeSpan.FromSeconds(deathProcessTime)).Subscribe(_ => { Sequence fade = DOTween.Sequence(); foreach (Material mat in renderSc.baseRenderMaterials) { fade.Join(mat.DOFloat(1, "_FadeAmount", 1f).SetEase(Ease.InQuint)); //fade.Join(mat.DOColor(Color.clear, "_FadeBurnColor", 1f).SetEase(Ease.Linear)); } fade.OnComplete(() => base.Die()); fade.Play(); }).AddTo(gameObject); } else { base.Die(); } } } public partial class Automata { public Vector3 PredictPlayerPosition(float timeAhead) { Vector3 currentPosition = player.centerPoint.position; Vector3 currentVelocity = player.landMovementSc.horizontalMovement / player.selfTimeSm.DeltaTime; return currentPosition + currentVelocity * timeAhead; } } public partial class Automata { public virtual void RegisterFuncAnims() { if (fullBodyFuncAnims != null) { foreach (FuncAnimData funcAnim in fullBodyFuncAnims.animDataList) { animationSc.fullBodyFuncAnimSm.Add(funcAnim); } } if (upperBodyFuncAnims != null) { foreach (FuncAnimData funcAnim in upperBodyFuncAnims.animDataList) { animationSc.upperBodyFuncAnimSm.Add(funcAnim); } } } protected virtual void RegisterFunctionsToAnimSc(params Action[] functions) { if (fullBodyFuncAnims == null) return; RegisterFunctionsToAnimSc(); foreach (Action function in functions) { string functionName = function.Method.Name; if (!animationSc.registeredFunctions.TryAdd(functionName, anim => function())) { Debug.LogWarning($"Function {functionName} is already registered."); } else { _registeredFunctionNames.Add(functionName); } } } protected virtual void RegisterFunctionsToAnimSc() { if (fullBodyFuncAnims == null) return; foreach (CustomFunction function in fullBodyFuncAnims.preloadFunctions) { string functionName = function.functionName; string FAPF_functionName = new StringBuilder(functionName).Insert(0, "FAPF_").ToString(); MethodInfo method = GetType().GetMethod(FAPF_functionName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { Debug.LogWarning($"Function {functionName} not found in {this.GetType().Name}. Skipping registration."); continue; } Action action = Delegate.CreateDelegate(typeof(Action), this, method) as Action; _registeredFunctionNames.Add(functionName); animationSc.registeredFunctions.TryAdd(functionName, action); } } protected void RemoveAllRegisteredFunctions() { foreach (string functionName in _registeredFunctionNames) { if (!animationSc.registeredFunctions.Remove(functionName)) { Debug.LogWarning($"Function {functionName} is not found."); } } _registeredFunctionNames.Clear(); } } #if UNITY_EDITOR public partial class Automata { protected override void CollectSubcontrollers() { base.CollectSubcontrollers(); behaviorSc ??= GetComponent(); } } #endif }