187 lines
6.7 KiB
C#
187 lines
6.7 KiB
C#
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<int,IEntity> _entities = new();
|
|
private readonly IDamageService _damageService;
|
|
private readonly Dictionary<int, ValidHandle> _isBusy = new();
|
|
private IEntity _talker;
|
|
private readonly Dictionary<int, HashSet<IDialogueData>> _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);
|
|
}
|
|
}
|
|
|
|
}
|