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 _cosmeticsCustomize; private readonly IManagedItemService _managedItemService; private readonly IEntitiesService _entitiesService; private readonly IBlackboard _blackboard; private readonly ConcurrentDictionary _instanced = new(); private readonly ConcurrentDictionary _cosmeticsInstances = new(); private readonly ConcurrentDictionary _scriptableItems = new(); private Transform _weapon; private readonly UniTaskCompletionSource _waitUntilInitialized = new(); public UniTask.Awaiter GetAwaiter() => _waitUntilInitialized.Task.GetAwaiter(); public PlayerCosmeticsService(IEntitiesService entitiesService, IBlackboard blackboard, IWrapper 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()) { _scriptableItems.TryAdd(x.Id, x); } Init(); } private async void Init() { var arg2 = _cosmeticsCustomize.Value; var cosmetics = _entitiesService .QueryComponents() .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("player_model").value; model.DestoryChilds(); var newModel = Object.Instantiate(cosmetic.Model, model.transform); newModel.localPosition = default; newModel.localRotation = default; if (newModel.TryGetComponent(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(); equipmentInventory.OnItemAdded += OnAdded; equipmentInventory.OnItemRemoved += OnRemoved; equipmentInventory.OnItemConsumed += OnRemoved; _serviceProvider.GetRequiredService().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("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().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().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()) { 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() .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()) { 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()) { Object.Destroy(collider); } foreach (var rigidbody in model.GetComponentsInChildren()) { Object.Destroy(rigidbody); } var list = _blackboard.GetVariable>("tps_model").GetValue(); foreach (var renderer in model.GetComponentsInChildren()) { if (isRegister) { list.Add(renderer); } else { list.Remove(renderer); } } _blackboard.GetVariable>("tps_model").SetValue(list); } } }