360 lines
15 KiB
C#
360 lines
15 KiB
C#
![]() |
using System;
|
||
|
using System.Collections.Concurrent;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Threading;
|
||
|
using Animancer;
|
||
|
using BITFALL.Bullet;
|
||
|
using BITKit;
|
||
|
using BITKit.Entities;
|
||
|
using BITKit.Mod;
|
||
|
using BITKit.Pool;
|
||
|
using BITKit.StateMachine;
|
||
|
using BITKit.UX.Hotkey;
|
||
|
using BITKit.WorldNode;
|
||
|
using Cinemachine;
|
||
|
using Cysharp.Threading.Tasks;
|
||
|
using Kinemation.MotionWarping.Runtime.Core;
|
||
|
using Lightbug.CharacterControllerPro.Core;
|
||
|
using Microsoft.Extensions.DependencyInjection;
|
||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||
|
using Microsoft.Extensions.Logging;
|
||
|
using Net.Project.B.AI;
|
||
|
using Net.Project.B.Buff;
|
||
|
using Net.Project.B.Cosmetics;
|
||
|
using Net.Project.B.Damage;
|
||
|
using Net.Project.B.Emoji;
|
||
|
using Net.Project.B.Faction;
|
||
|
using Net.Project.B.Health;
|
||
|
using Net.Project.B.Interaction;
|
||
|
using Net.Project.B.Inventory;
|
||
|
using Net.Project.B.Level;
|
||
|
using Net.Project.B.Mark;
|
||
|
using Net.Project.B.Melee;
|
||
|
using Net.Project.B.PDA;
|
||
|
using Net.Project.B.Weapon;
|
||
|
using NodeCanvas.Framework;
|
||
|
using Project.B.Animation;
|
||
|
using Project.B.CharacterController;
|
||
|
using Project.B.Player;
|
||
|
using UnityEngine;
|
||
|
using YooAsset;
|
||
|
using Object = UnityEngine.Object;
|
||
|
|
||
|
namespace Project.B.Entities
|
||
|
{
|
||
|
public class PlayerFactory:IPlayerFactory
|
||
|
{
|
||
|
private readonly ILogger<PlayerFactory> _logger;
|
||
|
private readonly IServiceCollection _serviceCollection;
|
||
|
private readonly IServiceProvider _serviceProvider;
|
||
|
private const string PlayerPath = "Player_Base";
|
||
|
private readonly List<(IEntity entity,GameObject go)> _entities = new();
|
||
|
private readonly IHealthService _healthService;
|
||
|
private readonly IEntitiesService _entitiesService;
|
||
|
private GameObject _playerPrefab;
|
||
|
|
||
|
|
||
|
private UniTaskCompletionSource<Transform> _waitPlayerStart=new();
|
||
|
|
||
|
public PlayerFactory(IServiceProvider serviceProvider, IServiceCollection serviceCollection, ILogger<PlayerFactory> logger, IHealthService healthService, IEntitiesService entitiesService)
|
||
|
{
|
||
|
_serviceProvider = serviceProvider;
|
||
|
_serviceCollection = serviceCollection;
|
||
|
_logger = logger;
|
||
|
_healthService = healthService;
|
||
|
_entitiesService = entitiesService;
|
||
|
|
||
|
_entitiesService.OnAdd+= OnNodeRegistered;
|
||
|
}
|
||
|
|
||
|
private void OnNodeRegistered(IEntity entity)
|
||
|
{
|
||
|
if(entity.ServiceProvider.GetService<WorldInfoPlayerStart>() is not {}infoPlayerStart)return;
|
||
|
_waitPlayerStart.TrySetResult(entity.ServiceProvider.GetService<Transform>());
|
||
|
}
|
||
|
|
||
|
public IReadOnlyDictionary<int, IEntity> Entities => _entities.ToDictionary(x => x.entity.Id, x => x.entity);
|
||
|
|
||
|
public async UniTask<IEntity> CreateAsync(string addressablePath,object model)
|
||
|
{
|
||
|
await UniTask.SwitchToMainThread();
|
||
|
if (_playerPrefab is not null)
|
||
|
{
|
||
|
return await Create(addressablePath);
|
||
|
}
|
||
|
|
||
|
_playerPrefab =await ModService.LoadAsset<GameObject>(PlayerPath);
|
||
|
|
||
|
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 cts = new CancellationTokenSource();
|
||
|
cts.CancelAfter(1000);
|
||
|
|
||
|
Vector3 position = default;
|
||
|
Quaternion rotation = default;
|
||
|
try
|
||
|
{
|
||
|
var startNode = await _waitPlayerStart.Task.AttachExternalCancellation(cts.Token);
|
||
|
|
||
|
position = startNode.position;
|
||
|
rotation = startNode.rotation;
|
||
|
|
||
|
_logger.LogInformation($"找到出生点:{position}");
|
||
|
}
|
||
|
catch (OperationCanceledException)
|
||
|
{
|
||
|
_logger.LogInformation("没有找到出生点,在默认位置开始");
|
||
|
await UniTask.SwitchToMainThread();
|
||
|
}
|
||
|
|
||
|
_waitPlayerStart = new();
|
||
|
|
||
|
InputActionGroup inputActionGroup = new();
|
||
|
|
||
|
var go = Object.Instantiate(_playerPrefab, position, rotation);
|
||
|
|
||
|
entity.ServiceCollection.Add(_serviceCollection);
|
||
|
|
||
|
entity.CancellationToken = go.GetCancellationTokenOnDestroy();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<LocalPlayerComponent>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(new IdComponent()
|
||
|
{
|
||
|
Id = entity.Id = go.GetInstanceID() ,
|
||
|
Name = Environment.UserName,
|
||
|
});
|
||
|
|
||
|
var blackboard = go.GetComponent<IBlackboard>();
|
||
|
|
||
|
var animancer = go.GetComponent<AnimancerComponent>();
|
||
|
|
||
|
var entityCancellationToken = go.GetCancellationTokenOnDestroy();
|
||
|
|
||
|
entityCancellationToken.Register(entity.Dispose);
|
||
|
|
||
|
if (go.TryGetComponent<MotionWarping>(out var motionWarping) is false)
|
||
|
{
|
||
|
motionWarping = go.AddComponent<MotionWarping>();
|
||
|
}
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(motionWarping);
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<Net.Project.B.Faction.Player>();
|
||
|
entity.ServiceCollection.AddSingleton<IFactionType,Net.Project.B.Faction.Player>();
|
||
|
entity.ServiceCollection.AddSingleton<Human>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IEntitiesService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IPoolService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(typeof(IMicroStateMachine<IPlayerControlMode>),_serviceProvider.GetRequiredService(typeof(IMicroStateMachine<IPlayerControlMode>)));
|
||
|
entity.ServiceCollection.AddSingleton(typeof(IWrapper<PlayerSettings>), _serviceProvider.GetRequiredService<IWrapper<PlayerSettings>>());
|
||
|
entity.ServiceCollection.AddSingleton<IEntity>(entity);
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(go);
|
||
|
entity.ServiceCollection.AddSingleton(go.transform);
|
||
|
|
||
|
if (go.TryGetComponent<ITag>(out var tag))
|
||
|
{
|
||
|
entity.ServiceCollection.AddSingleton(tag);
|
||
|
}
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(blackboard);
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(go.GetComponent<CharacterActor>());
|
||
|
entity.ServiceCollection.AddSingleton(go.GetComponentInChildren<CinemachineVirtualCameraBase>());
|
||
|
entity.ServiceCollection.AddSingleton(go.GetComponent<Animator>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(animancer);
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IWrapper<CosmeticsCustomizeComponent>>());
|
||
|
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<IPlayerCharacterController, PlayerCharacterController>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterController>(x =>
|
||
|
x.GetRequiredService<IPlayerCharacterController>().CharacterController);
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(inputActionGroup);
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_healthService);
|
||
|
entity.ServiceCollection.AddSingleton<IHealthComponent, HealthComponent>();
|
||
|
entity.ServiceCollection.AddSingleton<IKnockedComponent, KnockedComponent>();
|
||
|
entity.ServiceCollection.AddSingleton(
|
||
|
_serviceProvider.GetRequiredService<IKnockedService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterInitialize, CharacterInitialize>();
|
||
|
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<ICharacterSliding, CharacterSlidingState>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterStateClimb, CharacterClimbState>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterSeating, CharacterSeating>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterStateAnimation, CharacterAnimationState>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterLadder, CharacterLadderState>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterParachute, CharacterParachute>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterFreeFall, CharacterFreeFall>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterSwimming, CharacterSwimming>();
|
||
|
entity.ServiceCollection.AddSingleton<ICharacterStateVault, CharacterVaultState>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<PlayerCameraController>();
|
||
|
entity.ServiceCollection.AddSingleton<PlayerModelController>();
|
||
|
|
||
|
entity.ServiceCollection.AddKeyedSingleton<PlayerAnimancerController>(0);
|
||
|
entity.ServiceCollection.AddKeyedSingleton<PlayerAnimancerController>(2);
|
||
|
entity.ServiceCollection.AddKeyedScoped<PlayerAnimancerController>(nameof(PlayerHandAnimancer));
|
||
|
entity.ServiceCollection.AddSingleton<PlayerAnimancerEmoji>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<PlayerHandAnimancer>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IWorldInteractionService>());
|
||
|
entity.ServiceCollection.AddSingleton<IHotkeyCollection,PlayerInteractionController>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<IPlayerInventory, PlayerInventory>();
|
||
|
entity.ServiceCollection.AddSingleton<IPlayerWeaponInventory, PlayerWeaponInventory>();
|
||
|
entity.ServiceCollection.AddSingleton<IPlayerEquipmentInventory, PlayerEquipmentInventory>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<PlayerClothInventory>();
|
||
|
|
||
|
entity.ServiceCollection.AddTransient<IPlayerWeaponController, PlayerWeaponController>();
|
||
|
entity.ServiceCollection.AddTransient<IPlayerWeaponController<PlayerGunControllerClass>, PlayerGunController>();
|
||
|
entity.ServiceCollection.AddTransient<IPlayerWeaponController<PlayerMeleeControllerClass>, PlayerMeleeController>();
|
||
|
entity.ServiceCollection.AddTransient<IPlayerWeaponController<PlayerSpotterScopeControllerClass>, PlayerSpotterScopeController>();
|
||
|
entity.ServiceCollection.AddTransient<IPlayerWeaponController<PlayerHandheldControllerClass>, PlayerHandheldController>();
|
||
|
entity.ServiceCollection.AddTransient<IPlayerWeaponController<AppControllerClass>,PlayerHandheldController>();
|
||
|
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<IEmojiService<AnimationClip>, UnityEmojiService>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<PlayerCosmeticsService>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IBulletService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IDamageService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IMeleeService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton(_serviceProvider.GetRequiredService<IMarkService>());
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<PlayerFootstepController>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<IBuffComponent,BuffComponent>();
|
||
|
|
||
|
entity.ServiceCollection.AddSingleton<LevelComponent>();
|
||
|
|
||
|
await OnEntityCreate.UniTaskFunc(addressablePath, entity);
|
||
|
|
||
|
await entity.ServiceProvider.GetRequiredService<PlayerCosmeticsService>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<ICharacterStateWalk>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<IHotkeyCollection>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<PlayerClothInventory>();
|
||
|
|
||
|
var characterController = entity.ServiceProvider.GetRequiredService<ICharacterController>();
|
||
|
{
|
||
|
var layer0 = entity.ServiceProvider.GetRequiredKeyedService<PlayerAnimancerController>(0);
|
||
|
|
||
|
animancer.Layers[1].SetMask(blackboard.GetVariable<AvatarMask>("avatar_mask_upper").value);
|
||
|
animancer.Layers[2].SetMask(blackboard.GetVariable<AvatarMask>("avatar_mask_lower").value);
|
||
|
|
||
|
animancer.Layers[3].IsAdditive = true;
|
||
|
|
||
|
var layer2 = entity.ServiceProvider.GetRequiredKeyedService<PlayerAnimancerController>(2);
|
||
|
|
||
|
layer0.Layer = 0;
|
||
|
layer2.Layer = 2;
|
||
|
}
|
||
|
|
||
|
characterController.TransitionState<ICharacterInitialize>();
|
||
|
|
||
|
|
||
|
entity.ServiceProvider.QueryComponents(out IBuffComponent buffComponent);
|
||
|
buffComponent.AddBuff(new Hunger()
|
||
|
{
|
||
|
Value = 32
|
||
|
});
|
||
|
buffComponent.AddBuff(new Thirsty()
|
||
|
{
|
||
|
Value = 64
|
||
|
});
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<PlayerCameraController>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<PlayerModelController>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<PlayerAnimancerEmoji>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<IPlayerInventory>();
|
||
|
entity.ServiceProvider.GetRequiredService<IPlayerWeaponInventory>();
|
||
|
|
||
|
entity.ServiceProvider.GetRequiredService<LevelComponent>();
|
||
|
|
||
|
var footstep = entity.ServiceProvider.GetRequiredService<PlayerFootstepController>();
|
||
|
|
||
|
var handController = entity.ServiceProvider.GetRequiredService<PlayerHandAnimancer>();
|
||
|
|
||
|
await OnEntityCreated.UniTaskFunc(addressablePath, entity);
|
||
|
|
||
|
_entities.Add(new ValueTuple<IEntity, GameObject>(entity, go));
|
||
|
|
||
|
_logger.LogInformation($"Player Created. {entity.Id}");
|
||
|
|
||
|
_healthService.OnHealthChanged+=OnHealthChanged;
|
||
|
entityCancellationToken.Register(DisposeEntity);
|
||
|
|
||
|
_entitiesService.Register(entity);
|
||
|
|
||
|
return entity;
|
||
|
|
||
|
void OnHealthChanged(int arg1, int arg2, int arg3, object arg4)
|
||
|
{
|
||
|
if(entity.Id!=arg1)return;
|
||
|
inputActionGroup.allowInput.SetDisableElements(this, arg3 < 0);
|
||
|
}
|
||
|
void DisposeEntity()
|
||
|
{
|
||
|
inputActionGroup.Dispose();
|
||
|
|
||
|
handController.Dispose();
|
||
|
|
||
|
footstep.Dispose();
|
||
|
|
||
|
_entitiesService.UnRegister(entity);
|
||
|
|
||
|
_healthService.OnHealthChanged-=OnHealthChanged;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|