Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/AI/AIHumanService.cs

187 lines
6.7 KiB
C#
Raw Normal View History

2025-06-24 23:49:13 +08:00
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);
}
}
}