Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/Dialogue/UnityDialogueCameraControll...

180 lines
5.5 KiB
C#

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using BITKit;
using BITKit.Entities;
using Cinemachine;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using ParadoxNotion;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Net.Project.B.Dialogue
{
public class UnityDialogueCameraController : MonoBehaviour
{
[SerializeField] private CinemachineVirtualCameraBase virtualCamera;
[SerializeField] private bool allowPlayerInput;
[SerializeField] private bool isFixedCameraPosition;
private readonly ValidHandle _allowCamera = new();
private readonly Dictionary<int, IDialogueData> _dialogues = new();
private CancellationTokenSource _dialogueCancel;
private CinemachineTargetGroup _targetGroup;
private readonly ConcurrentDictionary<int, Transform> _actors = new();
private async void Start()
{
virtualCamera.enabled = false;
if (isFixedCameraPosition)
{
var newGameObject = new
GameObject(nameof(CinemachineTargetGroup))
{
transform =
{
parent = transform.parent
}
};
_targetGroup =newGameObject.AddComponent<CinemachineTargetGroup>();
virtualCamera.LookAt = _targetGroup.transform;
}
try
{
await BITApp.WalkUntilInitialize.Task.AttachExternalCancellation(destroyCancellationToken);
}
catch (OperationCanceledException)
{
}
var dialogueService = BITApp.ServiceProvider.GetRequiredService<IDialogueService>();
dialogueService.OnDialogueStart += OnDialogueStart;
dialogueService.OnDialogueEnd += OnDialogueEnd;
_allowCamera.AddListener(x=>virtualCamera.enabled=x);
if (allowPlayerInput is false)
{
_allowCamera.AddListener(x => { BITInputSystem.AllowInput.SetDisableElements(this, x); });
}
await destroyCancellationToken.WaitUntilCanceled();
dialogueService.OnDialogueStart -= OnDialogueStart;
dialogueService.OnDialogueEnd -= OnDialogueEnd;
}
private async void OnDialogueEnd(IDialogueData arg)
{
_allowCamera.AddElement(64);
_dialogueCancel?.Cancel();
_dialogueCancel = new CancellationTokenSource();
_dialogues.TryRemove(arg.Identity);
_allowCamera.RemoveElement(arg.Identity);
try
{
await UniTask.Delay(512, cancellationToken: _dialogueCancel.Token);
}
catch (OperationCanceledException)
{
if (_dialogues.Count is not 0)
return;
}
_allowCamera.RemoveElement(64);
try
{
if (isFixedCameraPosition)
{
if (_actors.TryGetValue(arg.ActorIdentity, out var actor))
{
await UniTask.Delay(1000, cancellationToken: destroyCancellationToken);
if (actor)
{
_targetGroup.RemoveMember(actor);
}
}
}
}
catch ( OperationCanceledException)
{
}
}
private UniTask OnDialogueStart(IDialogueData arg)
{
_allowCamera.AddElement(arg.Identity);
SetCameraLook(arg);
_dialogues.TryAdd(arg.Identity, arg);
return UniTask.CompletedTask;
}
private void SetCameraLook(IDialogueData arg)
{
var entitiesService = BITApp.ServiceProvider.GetRequiredService<IEntitiesService>();
if (_allowCamera.Allow)
{
if (_actors.TryGetValue(arg.ActorIdentity, out var actor))
{
if (isFixedCameraPosition)
{
_targetGroup.AddMember(actor,1,1);
}
else
{
virtualCamera.LookAt = actor;
}
return;
}
if (entitiesService.TryGetEntity(arg.ActorIdentity, out var entity) is false)
{
foreach (var (id,localPlayer) in entitiesService.QueryComponents<IdComponent,LocalPlayerComponent>())
{
entitiesService.TryGetEntity(id.Id, out entity);
}
}
if (entity.ServiceProvider.GetService<Transform>() is { } entityTransform)
{
if (isFixedCameraPosition)
{
_targetGroup.AddMember(entityTransform,1,1);
}
else
{
virtualCamera.LookAt = virtualCamera.Follow = entityTransform;
}
_actors.TryAdd(arg.ActorIdentity, entityTransform);
}
}
}
}
}