using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using BITKit.Mod; using Cysharp.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using UnityEngine; using Object = UnityEngine.Object; namespace BITKit.Pool { public class UnityPoolService:IPoolService,IDisposable { private readonly IServiceProvider _serviceProvider; public UnityPoolService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } private static readonly ConcurrentDictionary> Pool = new(); private static readonly ConcurrentDictionary> UsingPool = new(); private static readonly ConcurrentDictionary> ReadyPool = new(); public void Dispose() { var hashset = new HashSet(); foreach (var (_,list) in Pool) { foreach (var obj in list) { if (obj is not Component component) continue; if (!hashset.Add(component.gameObject)) continue; if (component.gameObject) Object.Destroy(component.gameObject); } } Pool.Clear(); UsingPool.Clear(); ReadyPool.Clear(); } public async UniTask Spawn(string path) where T : class { if (Pool.ContainsKey(path)) { var readyQueue = ReadyPool[path]; var usingList = UsingPool[path]; if (readyQueue.TryDequeue(out var obj)) { var value = obj as T; usingList.Add(value); return obj as T; } if (usingList.Count>0) { obj = usingList[0]; usingList.RemoveAt(0); usingList.Add(obj); #if UNITY_5_3_OR_NEWER if (obj is GameObject gameObject) { gameObject.SetActive(false); gameObject.SetActive(true); } #endif return obj as T; } } var list = Pool.GetOrCreate(path); UsingPool.GetOrCreate(path); ReadyPool.GetOrCreate(path); #if UNITY_5_3_OR_NEWER if (typeof(Object).IsAssignableFrom(typeof(T))) { var asset =await ModService.LoadAsset(path); if (asset is Object o) { var instance = Object.Instantiate(o); list.Add(instance); UsingPool.GetOrCreate(path).Add(instance); ReadyPool.GetOrCreate(path); return instance as T; } } #endif //检查T的构造函数,如果有需要参数的构造函数,就从ServiceProvider中获取,如果没有,则直接通过System.Activator创建 if (typeof(T).GetConstructors().Any(constructorInfo => constructorInfo.GetParameters().Length is 0)) { var value = Activator.CreateInstance(); list.Add(value); UsingPool.GetOrCreate(path).Add(value); ReadyPool.GetOrCreate(path); return value; } { var value = _serviceProvider.GetRequiredService(); list.Add(value); UsingPool.GetOrCreate(path).Add(value); ReadyPool.GetOrCreate(path); return value; } } public void Despawn(T obj, string path) where T : class { if (UsingPool.TryGetValue(path, out var value)) { value.Remove(obj); ReadyPool[path].Enqueue(obj); #if UNITY_5_3_OR_NEWER if (obj is GameObject gameObject) { gameObject.SetActive(false); } #endif return; } if (Pool.ContainsKey(path)) return; Pool.GetOrCreate(path).Add(obj); ReadyPool.GetOrCreate(path).Enqueue(obj); } public UniTask InitializeAsync() { return UniTask.CompletedTask; } } }