Files
AIC-Project/Client/Assets/Script/xmain/Manager/ResourcePoolManager.cs
T
2026-07-30 20:57:59 +08:00

288 lines
8.7 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UObject = UnityEngine.Object;
namespace XGame
{
public static class ResourcePoolManager
{
private const string MainName = "Main";
private const string PoolRootName = "Cache";
private static readonly Dictionary<string, Stack<GameObject>> Pools = new Dictionary<string, Stack<GameObject>>();
private static readonly HashSet<GameObject> PooledObjects = new HashSet<GameObject>();
public static IEnumerator coLoadGameObject(string path, Transform parent, Vector3 localPosition, Quaternion localRotation, Action<GameObject> action)
{
GameObject instance = TryGet(path, parent, localPosition, localRotation);
if (instance != null)
{
action?.Invoke(instance);
yield break;
}
UObject loaded = null;
yield return XResLoader.coLoadRes(path, typeof(GameObject), obj => loaded = obj);
GameObject prefab = loaded as GameObject;
if (prefab == null)
{
action?.Invoke(null);
yield break;
}
instance = UObject.Instantiate(prefab, parent);
instance.transform.localPosition = localPosition;
instance.transform.localRotation = localRotation;
Mark(instance, path);
RestartEffects(instance);
action?.Invoke(instance);
}
public static IEnumerator coLoadGameObjectWorld(string path, Vector3 position, Quaternion rotation, Action<GameObject> action)
{
GameObject instance = TryGetWorld(path, position, rotation);
if (instance != null)
{
action?.Invoke(instance);
yield break;
}
UObject loaded = null;
yield return XResLoader.coLoadRes(path, typeof(GameObject), obj => loaded = obj);
GameObject prefab = loaded as GameObject;
if (prefab == null)
{
action?.Invoke(null);
yield break;
}
instance = UObject.Instantiate(prefab, position, rotation);
Mark(instance, path);
RestartEffects(instance);
action?.Invoke(instance);
}
public static GameObject TryGet(string path, Transform parent, Vector3 localPosition, Quaternion localRotation)
{
GameObject instance = Pop(path);
if (instance == null)
{
return null;
}
Transform transform = instance.transform;
transform.SetParent(parent, false);
transform.localPosition = localPosition;
transform.localRotation = localRotation;
instance.SetActive(true);
RestartEffects(instance);
return instance;
}
public static GameObject TryGetWorld(string path, Vector3 position, Quaternion rotation)
{
GameObject instance = Pop(path);
if (instance == null)
{
return null;
}
Transform transform = instance.transform;
transform.SetParent(null, false);
transform.SetPositionAndRotation(position, rotation);
instance.SetActive(true);
RestartEffects(instance);
return instance;
}
public static bool Release(GameObject instance)
{
if (instance == null)
{
return false;
}
PooledResourceMarker marker = instance.GetComponent<PooledResourceMarker>();
return marker != null && Release(marker.Path, instance);
}
public static bool Release(string path, GameObject instance)
{
if (string.IsNullOrEmpty(path) || instance == null)
{
return false;
}
string key = NormalizePath(path);
if (PooledObjects.Contains(instance))
{
return true;
}
Mark(instance, key);
StopEffects(instance);
instance.SetActive(false);
instance.transform.SetParent(EnsurePoolRoot(), false);
Stack<GameObject> pool;
if (!Pools.TryGetValue(key, out pool))
{
pool = new Stack<GameObject>();
Pools.Add(key, pool);
}
pool.Push(instance);
PooledObjects.Add(instance);
return true;
}
public static int GetPooledCount(string path)
{
Stack<GameObject> pool;
return Pools.TryGetValue(NormalizePath(path), out pool) ? pool.Count : 0;
}
public static void Clear(string path)
{
string key = NormalizePath(path);
Stack<GameObject> pool;
if (!Pools.TryGetValue(key, out pool))
{
return;
}
DestroyPool(pool);
Pools.Remove(key);
}
public static void ClearAll()
{
foreach (Stack<GameObject> pool in Pools.Values)
{
DestroyPool(pool);
}
Pools.Clear();
PooledObjects.Clear();
}
private static GameObject Pop(string path)
{
Stack<GameObject> pool;
string key = NormalizePath(path);
if (!Pools.TryGetValue(key, out pool))
{
return null;
}
while (pool.Count > 0)
{
GameObject instance = pool.Pop();
PooledObjects.Remove(instance);
if (instance != null)
{
Mark(instance, key);
return instance;
}
}
Pools.Remove(key);
return null;
}
private static void Mark(GameObject instance, string path)
{
PooledResourceMarker marker = instance.GetComponent<PooledResourceMarker>();
if (marker == null)
{
marker = instance.AddComponent<PooledResourceMarker>();
}
marker.Path = NormalizePath(path);
}
private static Transform EnsurePoolRoot()
{
GameObject main = GameObject.Find(MainName);
if (main == null)
{
main = new GameObject(MainName);
}
Transform poolRoot = main.transform.Find(PoolRootName);
if (poolRoot != null)
{
return poolRoot;
}
GameObject cacheObject = new GameObject(PoolRootName);
Transform cacheTransform = cacheObject.transform;
cacheTransform.SetParent(main.transform, false);
cacheTransform.localPosition = Vector3.zero;
cacheTransform.localRotation = Quaternion.identity;
cacheTransform.localScale = Vector3.one;
return cacheTransform;
}
private static void DestroyPool(Stack<GameObject> pool)
{
while (pool.Count > 0)
{
GameObject instance = pool.Pop();
PooledObjects.Remove(instance);
DestroyUnityObject(instance);
}
}
private static void StopEffects(GameObject instance)
{
ParticleSystem[] particles = instance.GetComponentsInChildren<ParticleSystem>(true);
for (int i = 0; i < particles.Length; i++)
{
particles[i].Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
}
}
private static void RestartEffects(GameObject instance)
{
ParticleSystem[] particles = instance.GetComponentsInChildren<ParticleSystem>(true);
for (int i = 0; i < particles.Length; i++)
{
particles[i].Clear(true);
particles[i].Play(true);
}
}
private static string NormalizePath(string path)
{
return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', '/');
}
private static void DestroyUnityObject(UObject obj)
{
if (obj == null)
{
return;
}
if (Application.isPlaying)
{
UObject.Destroy(obj);
}
else
{
UObject.DestroyImmediate(obj);
}
}
private sealed class PooledResourceMarker : MonoBehaviour
{
public string Path;
}
}
}