Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/Cosmetics/PlayerCosmeticsService.cs
2025-06-24 23:49:13 +08:00

260 lines
9.4 KiB
C#

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using BITKit;
using BITKit.Entities;
using Cysharp.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Net.Project.B.Inventory;
using Net.Project.B.Item;
using NodeCanvas.Framework;
using Project.B.CharacterController;
using Project.B.Item;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Net.Project.B.Cosmetics
{
public class PlayerCosmeticsService:IDisposable
{
private readonly IPlayerInventory _playerInventory;
private readonly IServiceProvider _serviceProvider;
private readonly Animator _animator;
private readonly IWrapper<CosmeticsCustomizeComponent> _cosmeticsCustomize;
private readonly IManagedItemService _managedItemService;
private readonly IEntitiesService _entitiesService;
private readonly IBlackboard _blackboard;
private readonly ConcurrentDictionary<int, GameObject> _instanced = new();
private readonly ConcurrentDictionary<int, GameObject> _cosmeticsInstances = new();
private readonly ConcurrentDictionary<int, ScriptableItem> _scriptableItems = new();
private Transform _weapon;
private readonly UniTaskCompletionSource _waitUntilInitialized = new();
public UniTask.Awaiter GetAwaiter() => _waitUntilInitialized.Task.GetAwaiter();
public PlayerCosmeticsService(IEntitiesService entitiesService, IBlackboard blackboard, IWrapper<CosmeticsCustomizeComponent> cosmeticsCustomize, Animator animator, IManagedItemService managedItemService, IServiceProvider serviceProvider, IPlayerInventory playerInventory)
{
_entitiesService = entitiesService;
_blackboard = blackboard;
_cosmeticsCustomize = cosmeticsCustomize;
_animator = animator;
_managedItemService = managedItemService;
_serviceProvider = serviceProvider;
_playerInventory = playerInventory;
_cosmeticsCustomize.OnValueChanged += OnCosmeticsChanged;
foreach (var x in _entitiesService.QueryComponents<ScriptableItem>())
{
_scriptableItems.TryAdd(x.Id, x);
}
Init();
}
private async void Init()
{
var arg2 = _cosmeticsCustomize.Value;
var cosmetics = _entitiesService
.QueryComponents<ScriptableCosmetics>()
.ToArray().Where(x => arg2.ComponentIds.Contains(x.ScriptableId))
.ToArray();
foreach (var x in _cosmeticsInstances.Values)
{
SetupModel(x, false);
Object.Destroy(x);
}
_cosmeticsInstances.Clear();
foreach (var cosmetic in cosmetics)
{
switch (cosmetic.CosmeticsClass)
{
case CosmeticsModel:
{
var model = _blackboard.GetVariable<GameObject>("player_model").value;
model.DestoryChilds();
var newModel = Object.Instantiate(cosmetic.Model, model.transform);
newModel.localPosition = default;
newModel.localRotation = default;
if (newModel.TryGetComponent<IBlackboard>(out var newBlackboard))
{
foreach (var (name, variable) in newBlackboard.variables)
{
_blackboard.SetVariableValue(name, variable.value);
}
}
_animator.Rebind();
}
break;
}
}
await UniTask.NextFrame();
_animator.Rebind();
OnCosmeticsChanged(null,_cosmeticsCustomize.Value);
_waitUntilInitialized.TrySetResult();
var equipmentInventory = _serviceProvider.GetRequiredService<IPlayerEquipmentInventory>();
equipmentInventory.OnItemAdded += OnAdded;
equipmentInventory.OnItemRemoved += OnRemoved;
equipmentInventory.OnItemConsumed += OnRemoved;
_serviceProvider.GetRequiredService<IPlayerWeaponInventory>().StateMachine.OnStateChanged += OnStateChanged;
}
private void OnStateChanged(IPlayerWeaponController arg1, IPlayerWeaponController arg2)
{
if (_weapon)
{
SetupModel(_weapon.gameObject,false);
Object.Destroy(_weapon.gameObject);
}
if (arg2 is null)
{
_weapon = null;
return;
}
if(_managedItemService.Items.TryGetValue(arg2.Identifier,out var item) is false && _playerInventory.Container.ItemDictionary.TryGetValue(arg2.Identifier,out item) is false)return;
if(_scriptableItems.TryGetValue(item.ScriptableId,out var scriptableItem) is false)return;
if(!scriptableItem.Model)return;
if( _blackboard.GetVariable<Transform>("player_weapon").value is not {} playerWeapon || !playerWeapon)return;
_weapon = Object.Instantiate(scriptableItem.Model, playerWeapon);
_weapon.localPosition = _weapon.localEulerAngles = default;
SetupModel(_weapon.gameObject,true);
_serviceProvider.GetRequiredService<IPlayerCharacterController>().AllowTpsCamera.Invoke();
}
private void OnRemoved(int arg1, IRuntimeItem arg2)
{
if(_instanced.TryRemove(arg2.ScriptableId,out var model) is false)return;
if(!model)return;
SetupModel(model, false);
Object.Destroy(model);
}
private void OnAdded(int arg1, IRuntimeItem arg2)
{
if(_entitiesService.QueryComponents<ScriptableItem>().ToArray().FirstOrDefault(x=>x.Id == arg2.ScriptableId) is not ScriptableCloth scriptableCloth)return;
if(!scriptableCloth.ClothModel)return;
var bone = _animator.GetBoneTransform(scriptableCloth.Bone);
var newModel = Object.Instantiate(scriptableCloth.ClothModel,bone);
foreach (var x in newModel.GetComponentsInChildren<Collider>())
{
Object.Destroy(x);
}
SetupModel(newModel.gameObject, true);
_instanced.TryAdd(arg2.ScriptableId, newModel.gameObject);
}
public void Dispose()
{
_cosmeticsCustomize.OnValueChanged -= OnCosmeticsChanged;
}
private void OnCosmeticsChanged(CosmeticsCustomizeComponent arg1, CosmeticsCustomizeComponent arg2)
{
var cosmetics = _entitiesService
.QueryComponents<ScriptableCosmetics>()
.ToArray().Where(x=>arg2.ComponentIds.Contains(x.ScriptableId))
.ToArray();
foreach (var x in _cosmeticsInstances.Values)
{
SetupModel(x, false);
Object.Destroy(x);
}
_cosmeticsInstances.Clear();
foreach (var cosmetic in cosmetics)
{
switch (cosmetic.CosmeticsClass)
{
case CosmeticsHat:
{
var bone = _animator.GetBoneTransform(cosmetic.Bone);
if (!bone)
{
Debug.LogWarning(_animator.name + "没有找到" + cosmetic.Bone + "骨骼");
continue;
}
var newModel = Object.Instantiate(cosmetic.Model,bone);
foreach (var x in newModel.GetComponentsInChildren<Collider>())
{
Object.Destroy(x);
}
newModel.localPosition = default;
newModel.localRotation = default;
_cosmeticsInstances.TryAdd(cosmetic.ScriptableId, newModel.gameObject);
SetupModel(newModel.gameObject, true);
}
break;
}
}
}
private void SetupModel(GameObject model,bool isRegister)
{
foreach (var collider in model.GetComponentsInChildren<Collider>())
{
Object.Destroy(collider);
}
foreach (var rigidbody in model.GetComponentsInChildren<Rigidbody>())
{
Object.Destroy(rigidbody);
}
var list = _blackboard.GetVariable<List<Renderer>>("tps_model").GetValue();
foreach (var renderer in model.GetComponentsInChildren<Renderer>())
{
if (isRegister)
{
list.Add(renderer);
}
else
{
list.Remove(renderer);
}
}
_blackboard.GetVariable<List<Renderer>>("tps_model").SetValue(list);
}
}
}