using System; using System.Collections; using System.Collections.Generic; using System.Linq; using BITKit; using BITKit.Entities; using Cysharp.Threading.Tasks; using Net.Project.B.Damage; using Net.Project.B.Dialogue; using Net.Project.B.Health; using Net.Project.B.Interaction; using Project.B.CharacterController; using UnityEngine; namespace Net.Project.B.AI { public class AIHumanService:IDisposable { public int DamageOnBreakDialogue = 0; private readonly IDialogueService _dialogueService; private readonly IWorldInteractionService _interactionService; private readonly IEntitiesService _entitiesService; private readonly ITicker _ticker; private readonly Dictionary _entities = new(); private readonly IDamageService _damageService; private readonly Dictionary _isBusy = new(); private IEntity _talker; private readonly Dictionary> _inDialogue = new(); public AIHumanService(ITicker ticker, IEntitiesService entitiesService, IWorldInteractionService interactionService, IDialogueService dialogueService, IDamageService damageService) { _ticker = ticker; _entitiesService = entitiesService; _interactionService = interactionService; _dialogueService = dialogueService; _damageService = damageService; _ticker.Add(OnTick); _entitiesService.OnAdd += OnAdd; _entitiesService.OnRemove += OnRemove; _interactionService.OnInteraction += OnInteraction; _dialogueService.OnDialogueStart += OnDialogueStart; _dialogueService.OnDialogueEnd += OnDialogueEnd; } private void OnRemove(IEntity obj) { _entities.TryRemove(obj.Id); _inDialogue.TryRemove(obj.Id); _isBusy.TryRemove(obj.Id); } private void OnDialogueEnd(IDialogueData obj) { if (_isBusy.TryGetValue(obj.ActorIdentity, out var isBusy) is false) return; isBusy.RemoveElement(obj.Identity); _inDialogue.GetOrCreate(obj.ActorIdentity).Remove(obj); } private UniTask OnDialogueStart(IDialogueData arg) { if (_isBusy.TryGetValue(arg.ActorIdentity, out var isBusy) is false) return UniTask.CompletedTask; isBusy.AddElement(arg.Identity); _inDialogue.GetOrCreate(arg.ActorIdentity).Add(arg); return UniTask.CompletedTask; } private void OnInteraction(object arg1, IWorldInteractable arg2, WorldInteractionProcess arg3, object arg4) { if(arg3 is not WorldInteractionProcess.Performed)return; if(_entities.TryGetValue(arg2.Id,out var entity) is false)return; if(_isBusy[entity.Id] is {Allow:false} isBusy is false ) return; _dialogueService.CreateDialogue(new DialogueData() { ActorIdentity = entity.Id, Text = "Hi there", }).Forget(); isBusy.AddElement(this); if (arg1 is IEntity talker) { talker.ServiceProvider.QueryComponents(out _talker,out Transform talkerTransform); if (entity.ServiceProvider.QueryComponents(out ICharacterController characterController,out AIBlackBoard blackBoard)) { blackBoard.Dialogue = talker; entity.ServiceProvider.QueryComponents(out Transform transform); var dir = Vector3.ProjectOnPlane(talkerTransform.position - transform.position, Vector3.up); characterController.Rotation = Quaternion.LookRotation(dir); } } } private void OnAdd(IEntity obj) { if(obj.ServiceProvider.QueryComponents(out AIHuman _,out ICharacterController characterController,out DynamicInteractable interactable) is false)return; interactable.Allow.AddElement(this); _entities[obj.Id]=obj; var isBusy =_isBusy[obj.Id] = new ValidHandle(); isBusy.AddListener(x => { obj.ServiceProvider.QueryComponents(out AIBlackBoard blackBoard); if (x) { characterController.AllowMovement.AddDisableElements(this); interactable.Allow.RemoveElement(this); } else { characterController.AllowMovement.RemoveDisableElements(this); interactable.Allow.AddElement(this); blackBoard.Dialogue = null; } }); } private void OnTick(float obj) { foreach (var entity in _entities.Values) { if(_isBusy[entity.Id] is not {Allow:true} isBusy)continue; entity.ServiceProvider.QueryComponents(out Transform transform); _talker.ServiceProvider.QueryComponents(out Transform talker); if (Vector3.Distance(talker.position, transform.position) < 3)continue; isBusy.RemoveElement(this); if (isBusy.Allow) { var dialogues = _inDialogue.GetOrCreate(entity.Id); if (dialogues.Count > 0) { foreach (var dialogue in dialogues.ToArray()) { dialogue.CancellationTokenSource.Cancel(); } _dialogueService.CreateDialogue(new DialogueData() { ActorIdentity = entity.Id, Text = "#Dialogue_Run_Away" }); if (DamageOnBreakDialogue > 0) { _damageService.CreateDamageAsync(entity.Id, _talker.Id, DamageOnBreakDialogue,null,transform.position); } } entity.ServiceProvider.QueryComponents(out AIBlackBoard blackBoard); blackBoard.Dialogue = null; isBusy.Clear(); } } } public void Dispose() { _ticker.Remove(OnTick); } } }