using System; using System.Collections.Generic; using System.Data; using BITKit; using BITKit.Entities; using Microsoft.Extensions.DependencyInjection; using Net.Project.B.Health; using NodeCanvas.Framework; using Project.B.CharacterController; using Unity.Mathematics; using UnityEngine; using UnityEngine.AI; namespace Net.Project.B.AI { public class NpcCharacterController : ICharacterController,IDisposable { private readonly IEntity _entity; private static readonly HashSet Created = new(); internal readonly IHealthComponent HealthComponent; internal readonly UnityNavMeshAgentController NavMeshAgentController; internal readonly Animator Animator; internal readonly NavMeshAgent Agent; internal readonly Transform Transform; public ICharacterState CurrentState { get; private set; } public event Action OnStateChanged; private readonly IServiceProvider _serviceProvider; private readonly IFixedTicker _fixedTicker; private readonly IBlackboard _blackboard; private bool _isDisposed; public NpcCharacterController(IServiceProvider serviceProvider, IFixedTicker fixedTicker, NavMeshAgent agent, Transform transform, Animator animator, IBlackboard blackboard, IHealthComponent healthComponent, IEntity entity) { if (Created.Add(entity.Id) is false) { throw new DuplicateNameException(); } _serviceProvider = serviceProvider; _fixedTicker = fixedTicker; Agent = agent; Transform = transform; Animator = animator; _blackboard = blackboard; HealthComponent = healthComponent; _entity = entity; _fixedTicker.Add(UpdateState); Agent.updateRotation = false; Agent.updatePosition = false; NavMeshAgentController = Transform.GetComponent(); AllowMovement.AddElement(8964189); HealthComponent.OnHealthChanged += (x, y) => { AllowMovement.SetDisableElements(HealthComponent,y<0); }; AllowMovement.AddListener(x => { if(x) { TransitionState(); } else { DisposeState(); } agent.isStopped = !x; }); } public ICharacterState TransitionState() where TState : ICharacterState { if (_isDisposed) return null; var state = _serviceProvider.GetRequiredService(); var newState= TransitionState(state); return newState; } public ICharacterState TransitionState(ICharacterState state) { AllowMovement.SetElements(this,state is not null); var current = CurrentState; CurrentState = state; OnStateChanged?.Invoke(current, state); return state; } public bool Enabled { get; set; } public event Action OnStateRegistered; public event Action OnStateUnRegistered; public IDictionary StateDictionary { get; } public void Initialize() { } public void UpdateState(float deltaTime) { if (AllowMovement.Allow is false) { if (HealthComponent.HealthPoint < 0) { } else { } return; } if(!Agent.isActiveAndEnabled)return; CurrentState?.OnStateUpdate(deltaTime); if (CurrentState is not null) { float3 velocity = Agent.desiredVelocity; quaternion rotation = Transform.rotation; quaternion viewRotation = rotation; float3 position = Transform.position; CurrentState.BeforeUpdateVelocity(deltaTime); CurrentState.UpdateVelocity(ref velocity, deltaTime); CurrentState.AfterUpdateVelocity(deltaTime); CurrentState.UpdateRotation(ref position, ref rotation, ref viewRotation, deltaTime); Agent.velocity = velocity; if (Agent.enabled) { Transform.position = Agent.nextPosition; } Transform.rotation = rotation; } } public void DisposeState() { TransitionState(null); Agent.velocity = Velocity= default; } public ValidHandle AllowMovement { get; } = new(); public float Height => Agent.height; public float3 Center { get; } public float3 Position { get => Transform.position; set { Agent.Warp(value); Transform.position = value; } } public float3 Velocity { get => Agent.velocity; set => Agent.velocity = value; } public float3 ViewPosition => Position + (float3)Vector3.up; public float3 AngularVelocity { get; } public quaternion Rotation { get => Transform.rotation; set => Transform.rotation = value; } public quaternion ViewRotation { get; set; } public float3 SelfVelocity { get; set; } public bool IsGrounded { get; } public event Action OnLand; public void Dispose() { _isDisposed = true; _fixedTicker.Remove(UpdateState); Created.Remove(_entity.Id); } } }