164 lines
5.5 KiB
C#
164 lines
5.5 KiB
C#
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<string,List<object>> Pool = new();
|
|
private static readonly ConcurrentDictionary<string,List<object>> UsingPool = new();
|
|
private static readonly ConcurrentDictionary<string, Queue<object>> ReadyPool = new();
|
|
|
|
public void Dispose()
|
|
{
|
|
var hashset = new HashSet<GameObject>();
|
|
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 int DefaultCapacity { get; set; } = 8;
|
|
|
|
public async UniTask<T> Spawn<T>(string path,object prefab) 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>=DefaultCapacity)
|
|
{
|
|
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 =prefab as T ?? await ModService.LoadAsset<T>(path);
|
|
if (asset is Object o)
|
|
{
|
|
var instance = Object.Instantiate(o);
|
|
list.Add(instance);
|
|
UsingPool.GetOrCreate(path).Add(instance);
|
|
ReadyPool.GetOrCreate(path);
|
|
|
|
if (instance is GameObject gameObject)
|
|
{
|
|
gameObject.GetCancellationTokenOnDestroy().Register(DisposeGo);
|
|
|
|
void DisposeGo()
|
|
{
|
|
Pool.GetOrCreate(path).TryRemove(gameObject);
|
|
UsingPool.GetOrCreate(path).TryRemove(gameObject);
|
|
var queue = ReadyPool.GetOrCreate(path);
|
|
var removeObjectList = new List<object>(queue);
|
|
removeObjectList.TryRemove(gameObject);
|
|
queue.Clear();
|
|
foreach (var x in removeObjectList)
|
|
{
|
|
queue.Enqueue(x);
|
|
}
|
|
}
|
|
}
|
|
|
|
return instance as T;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//检查T的构造函数,如果有需要参数的构造函数,就从ServiceProvider中获取,如果没有,则直接通过System.Activator创建
|
|
if (typeof(T).GetConstructors().Any(constructorInfo => constructorInfo.GetParameters().Length is 0))
|
|
{
|
|
var value = Activator.CreateInstance<T>();
|
|
list.Add(value);
|
|
UsingPool.GetOrCreate(path).Add(value);
|
|
ReadyPool.GetOrCreate(path);
|
|
return value;
|
|
}
|
|
{
|
|
var value = _serviceProvider.GetRequiredService<T>();
|
|
list.Add(value);
|
|
UsingPool.GetOrCreate(path).Add(value);
|
|
ReadyPool.GetOrCreate(path);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
public void Despawn<T>(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;
|
|
}
|
|
}
|
|
|
|
}
|