Net.Like.Xue.Tokyo/Assets/Artists/Scripts/YangdunCreateFactory.cs

178 lines
7.1 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Animancer;
using BITKit;
using BITKit.Entities;
using BITKit.GameSocket;
using BITKit.WorldNode;
using Cinemachine;
using Cysharp.Threading.Tasks;
using Lightbug.CharacterControllerPro.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Net.Project.B.Health;
using Net.Project.B.Interaction;
using Net.Project.B.Inventory;
using Net.Project.B.Weapon;
using NodeCanvas.Framework;
using Project.B.Animation;
using Project.B.CharacterController;
using Project.B.Entities;
using UnityEngine;
using YooAsset;
using Object = UnityEngine.Object;
namespace Net.Like.Xue.Tokyo
{
public class YangdunCreateFactory : IPlayerFactory
{
private readonly ILogger<PlayerFactory> _logger;
private readonly IServiceCollection _serviceCollection;
private readonly IServiceProvider _serviceProvider;
private readonly IWorldNodeService _worldNodeService;
private const string PlayerPath = "Player_Base";
private readonly List<(IEntity entity,GameObject go)> _entities = new();
private readonly IHealthService _healthService;
private GameObject _playerPrefab;
private readonly InputActionGroup _inputActionGroup=new();
private UniTaskCompletionSource<WorldInfoPlayerStart> _waitPlayerStart=new();
public YangdunCreateFactory(IServiceProvider serviceProvider, IServiceCollection serviceCollection, IWorldNodeService worldNodeService, ILogger<PlayerFactory> logger, IHealthService healthService)
{
_serviceProvider = serviceProvider;
_serviceCollection = serviceCollection;
_worldNodeService = worldNodeService;
_logger = logger;
_healthService = healthService;
_worldNodeService.OnNodeRegistered += OnNodeRegistered;
_healthService.OnHealthChanged+=OnHealthChanged;
}
private void OnNodeRegistered(IWorldNode obj)
{
if(obj is not WorldInfoPlayerStart infoPlayerStart)return;
_waitPlayerStart.TrySetResult(infoPlayerStart);
}
public IReadOnlyDictionary<int, IEntity> Entities => _entities.ToDictionary(x => x.entity.Id, x => x.entity);
public async UniTask<IEntity> CreateAsync(string addressablePath)
{
await UniTask.SwitchToMainThread();
if (_playerPrefab is not null)
{
return await Create(addressablePath);
}
var asyncHandle = YooAssets.LoadAssetAsync<GameObject>(PlayerPath);
await asyncHandle;
_playerPrefab = asyncHandle.AssetObject as GameObject;
return await Create(addressablePath);
}
public event Func<string, IEntity,UniTask> OnEntityCreate;
public event Func<string, IEntity,UniTask> OnEntityCreated;
private async UniTask<IEntity> Create(string addressablePath = null)
{
var entity = new Entity();
var startNode = await _waitPlayerStart.Task;
var startTransform = startNode.WorldObject.As<GameObject>().transform;
_waitPlayerStart = new();
var go = Object.Instantiate(_playerPrefab,startTransform.position,startTransform.rotation);
entity.ServiceCollection.Add(_serviceCollection);
go.GetCancellationTokenOnDestroy().Register(entity.Dispose);
entity.ServiceCollection.AddSingleton<IEntity>(entity);
entity.ServiceCollection.AddSingleton(go);
entity.ServiceCollection.AddSingleton(go.transform);
entity.ServiceCollection.AddSingleton(go.GetComponent<IBlackboard>());
entity.ServiceCollection.AddSingleton(go.GetComponent<CharacterActor>());
entity.ServiceCollection.AddSingleton(go.GetComponentInChildren<CinemachineVirtualCameraBase>());
entity.ServiceCollection.AddSingleton<IAnimancerComponent>(go.GetComponent<AnimancerComponent>());
entity.ServiceCollection.AddSingleton<IPlayerCharacterController, PlayerCharacterController>();
entity.ServiceCollection.AddSingleton<ICharacterController>(x=>x.GetRequiredService<IPlayerCharacterController>().CharacterController);
entity.ServiceCollection.AddSingleton(_inputActionGroup);
entity.ServiceCollection.AddSingleton<ICharacterStateWalk, CharacterWalkState>();
entity.ServiceCollection.AddSingleton<ICharacterStateIdle, CharacterIdleState>();
entity.ServiceCollection.AddSingleton<ICharacterStateCrouched, CharacterCrouchedState>();
entity.ServiceCollection.AddSingleton<ICharacterStateRun, CharacterRunState>();
entity.ServiceCollection.AddSingleton<ICharacterSprint, CharacterSprintState>();
entity.ServiceCollection.AddSingleton<ICharacterStateStepUp, CharacterStepUpState>();
entity.ServiceCollection.AddSingleton<ICharacterKnocked, CharacterKnockedState>();
entity.ServiceCollection.AddSingleton<PlayerCameraController>();
entity.ServiceCollection.AddSingleton<PlayerModelController>();
entity.ServiceCollection.AddSingleton<PlayerAnimancerController>();
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IWorldInteractionService>());
entity.ServiceCollection.AddSingleton<PlayerInteractionController>();
await OnEntityCreate.UniTaskFunc(addressablePath,entity);
entity.ServiceProvider.GetRequiredService<ICharacterStateWalk>();
entity.ServiceProvider.GetRequiredService<PlayerInteractionController>();
var characterController = entity.ServiceProvider.GetRequiredService<ICharacterController>();
characterController.TransitionState<ICharacterStateWalk>();
entity.ServiceProvider.GetRequiredService<PlayerAnimancerController>();
entity.ServiceProvider.GetRequiredService<PlayerCameraController>();
entity.ServiceProvider.GetRequiredService<PlayerModelController>();
await OnEntityCreated.UniTaskFunc(addressablePath,entity);
_entities.Add(new ValueTuple<IEntity, GameObject>(entity,go));
_logger.LogInformation($"Player Created. {entity.Id}");
return entity;
}
public async void Dispose()
{
await UniTask.SwitchToMainThread();
foreach (var (entity, go) in _entities)
{
if (entity is IDisposable disposable)
{
disposable.Dispose();
}
if (go)
Object.Destroy(go);
}
_healthService.OnHealthChanged-=OnHealthChanged;
}
private void OnHealthChanged(int arg1, int arg2, int arg3, object arg4)
{
_inputActionGroup.allowInput.SetDisableElements(this,arg3<0);
}
}
}