优化
This commit is contained in:
parent
9756674342
commit
722dc7c251
@ -9,6 +9,14 @@ namespace AlicizaX
|
|||||||
{
|
{
|
||||||
public sealed class GameObjectPool : MonoServiceBehaviour<GameObjectPool>
|
public sealed class GameObjectPool : MonoServiceBehaviour<GameObjectPool>
|
||||||
{
|
{
|
||||||
|
private static readonly Comparison<GameObjectPoolSnapshot> SnapshotComparer = (left, right) =>
|
||||||
|
{
|
||||||
|
if (left == null && right == null) return 0;
|
||||||
|
if (left == null) return 1;
|
||||||
|
if (right == null) return -1;
|
||||||
|
int groupCompare = string.Compare(left.group, right.group, StringComparison.Ordinal);
|
||||||
|
return groupCompare != 0 ? groupCompare : string.Compare(left.assetPath, right.assetPath, StringComparison.Ordinal);
|
||||||
|
};
|
||||||
[Header("检查间隔")]
|
[Header("检查间隔")]
|
||||||
public float checkInterval = 10f;
|
public float checkInterval = 10f;
|
||||||
|
|
||||||
@ -25,6 +33,7 @@ namespace AlicizaX
|
|||||||
|
|
||||||
private readonly Dictionary<string, RuntimePrefabPool> _poolsByKey = new Dictionary<string, RuntimePrefabPool>(StringComparer.Ordinal);
|
private readonly Dictionary<string, RuntimePrefabPool> _poolsByKey = new Dictionary<string, RuntimePrefabPool>(StringComparer.Ordinal);
|
||||||
private readonly Dictionary<string, PoolConfig> _resolvedConfigCache = new Dictionary<string, PoolConfig>(StringComparer.Ordinal);
|
private readonly Dictionary<string, PoolConfig> _resolvedConfigCache = new Dictionary<string, PoolConfig>(StringComparer.Ordinal);
|
||||||
|
private readonly Dictionary<string, PoolResourceLoaderType> _groupLoaderCache = new Dictionary<string, PoolResourceLoaderType>(StringComparer.Ordinal);
|
||||||
private readonly Dictionary<GameObject, RuntimePrefabPool> _ownersByObject = new Dictionary<GameObject, RuntimePrefabPool>();
|
private readonly Dictionary<GameObject, RuntimePrefabPool> _ownersByObject = new Dictionary<GameObject, RuntimePrefabPool>();
|
||||||
private readonly Dictionary<PoolResourceLoaderType, IResourceLoader> _resourceLoaders = new Dictionary<PoolResourceLoaderType, IResourceLoader>();
|
private readonly Dictionary<PoolResourceLoaderType, IResourceLoader> _resourceLoaders = new Dictionary<PoolResourceLoaderType, IResourceLoader>();
|
||||||
private readonly List<PoolConfig> _configs = new List<PoolConfig>();
|
private readonly List<PoolConfig> _configs = new List<PoolConfig>();
|
||||||
@ -36,6 +45,8 @@ namespace AlicizaX
|
|||||||
private Exception _initializationException;
|
private Exception _initializationException;
|
||||||
private float _lastCleanupTime;
|
private float _lastCleanupTime;
|
||||||
|
|
||||||
|
private bool _isShuttingDown;
|
||||||
|
|
||||||
public bool IsReady => _initializationCompleted && _initializationException == null;
|
public bool IsReady => _initializationCompleted && _initializationException == null;
|
||||||
|
|
||||||
protected override void OnServiceInitialize()
|
protected override void OnServiceInitialize()
|
||||||
@ -202,15 +213,18 @@ namespace AlicizaX
|
|||||||
|
|
||||||
public void ClearAllPools()
|
public void ClearAllPools()
|
||||||
{
|
{
|
||||||
|
_isShuttingDown = true;
|
||||||
foreach (RuntimePrefabPool pool in _poolsByKey.Values)
|
foreach (RuntimePrefabPool pool in _poolsByKey.Values)
|
||||||
{
|
{
|
||||||
pool.Shutdown();
|
pool.Shutdown();
|
||||||
MemoryPool.Release(pool);
|
MemoryPool.Release(pool);
|
||||||
}
|
}
|
||||||
|
_isShuttingDown = false;
|
||||||
|
|
||||||
_poolsByKey.Clear();
|
_poolsByKey.Clear();
|
||||||
_ownersByObject.Clear();
|
_ownersByObject.Clear();
|
||||||
_resolvedConfigCache.Clear();
|
_resolvedConfigCache.Clear();
|
||||||
|
_groupLoaderCache.Clear();
|
||||||
ReleaseDebugSnapshots();
|
ReleaseDebugSnapshots();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,31 +237,7 @@ namespace AlicizaX
|
|||||||
_debugSnapshots.Add(pool.CreateSnapshot());
|
_debugSnapshots.Add(pool.CreateSnapshot());
|
||||||
}
|
}
|
||||||
|
|
||||||
_debugSnapshots.Sort((left, right) =>
|
_debugSnapshots.Sort(SnapshotComparer);
|
||||||
{
|
|
||||||
if (left == null && right == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left == null)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int groupCompare = string.Compare(left.group, right.group, StringComparison.Ordinal);
|
|
||||||
if (groupCompare != 0)
|
|
||||||
{
|
|
||||||
return groupCompare;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Compare(left.assetPath, right.assetPath, StringComparison.Ordinal);
|
|
||||||
});
|
|
||||||
|
|
||||||
return _debugSnapshots;
|
return _debugSnapshots;
|
||||||
}
|
}
|
||||||
@ -264,7 +254,7 @@ namespace AlicizaX
|
|||||||
|
|
||||||
internal void UnregisterOwnedObject(GameObject gameObject)
|
internal void UnregisterOwnedObject(GameObject gameObject)
|
||||||
{
|
{
|
||||||
if (gameObject == null)
|
if (gameObject == null || _isShuttingDown)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -375,7 +365,7 @@ namespace AlicizaX
|
|||||||
{
|
{
|
||||||
if (!_resourceLoaders.ContainsKey(PoolResourceLoaderType.AssetBundle))
|
if (!_resourceLoaders.ContainsKey(PoolResourceLoaderType.AssetBundle))
|
||||||
{
|
{
|
||||||
_resourceLoaders[PoolResourceLoaderType.AssetBundle] = new AlicizaResourceLoader();
|
_resourceLoaders[PoolResourceLoaderType.AssetBundle] = new AssetBundleResourceLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_resourceLoaders.ContainsKey(PoolResourceLoaderType.Resources))
|
if (!_resourceLoaders.ContainsKey(PoolResourceLoaderType.Resources))
|
||||||
@ -400,9 +390,11 @@ namespace AlicizaX
|
|||||||
{
|
{
|
||||||
_configs.Clear();
|
_configs.Clear();
|
||||||
_resolvedConfigCache.Clear();
|
_resolvedConfigCache.Clear();
|
||||||
|
_groupLoaderCache.Clear();
|
||||||
|
|
||||||
|
IResourceModule resourceModule = ModuleSystem.GetModule<IResourceModule>();
|
||||||
PoolConfigScriptableObject configAsset =
|
PoolConfigScriptableObject configAsset =
|
||||||
ModuleSystem.GetModule<IResourceModule>().LoadAsset<PoolConfigScriptableObject>(poolConfigPath);
|
resourceModule.LoadAsset<PoolConfigScriptableObject>(poolConfigPath);
|
||||||
|
|
||||||
if (configAsset == null || configAsset.configs == null)
|
if (configAsset == null || configAsset.configs == null)
|
||||||
{
|
{
|
||||||
@ -429,6 +421,17 @@ namespace AlicizaX
|
|||||||
|
|
||||||
_configs.Sort(PoolConfig.CompareByPriority);
|
_configs.Sort(PoolConfig.CompareByPriority);
|
||||||
LogConfigWarnings();
|
LogConfigWarnings();
|
||||||
|
|
||||||
|
for (int i = 0; i < _configs.Count; i++)
|
||||||
|
{
|
||||||
|
PoolConfig config = _configs[i];
|
||||||
|
if (!_groupLoaderCache.ContainsKey(config.group))
|
||||||
|
{
|
||||||
|
_groupLoaderCache[config.group] = config.resourceLoaderType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceModule.UnloadAsset(configAsset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async UniTask PrewarmConfiguredPoolsAsync(CancellationToken cancellationToken)
|
private async UniTask PrewarmConfiguredPoolsAsync(CancellationToken cancellationToken)
|
||||||
@ -460,7 +463,8 @@ namespace AlicizaX
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string cacheKey = $"{group ?? string.Empty}|{assetPath}";
|
bool hasGroup = !string.IsNullOrEmpty(group);
|
||||||
|
string cacheKey = hasGroup ? string.Concat(group, "|", assetPath) : assetPath;
|
||||||
if (_resolvedConfigCache.TryGetValue(cacheKey, out PoolConfig cachedConfig))
|
if (_resolvedConfigCache.TryGetValue(cacheKey, out PoolConfig cachedConfig))
|
||||||
{
|
{
|
||||||
return cachedConfig;
|
return cachedConfig;
|
||||||
@ -516,16 +520,10 @@ namespace AlicizaX
|
|||||||
|
|
||||||
private IResourceLoader GetDirectLoadResourceLoader(string group)
|
private IResourceLoader GetDirectLoadResourceLoader(string group)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(group))
|
if (!string.IsNullOrWhiteSpace(group) &&
|
||||||
|
_groupLoaderCache.TryGetValue(group, out PoolResourceLoaderType loaderType))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _configs.Count; i++)
|
return GetResourceLoader(loaderType);
|
||||||
{
|
|
||||||
PoolConfig config = _configs[i];
|
|
||||||
if (string.Equals(config.group, group, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return GetResourceLoader(config.resourceLoaderType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetResourceLoader(DefaultDirectLoadResourceLoaderType);
|
return GetResourceLoader(DefaultDirectLoadResourceLoaderType);
|
||||||
@ -567,28 +565,14 @@ namespace AlicizaX
|
|||||||
|
|
||||||
private void LogConfigWarnings()
|
private void LogConfigWarnings()
|
||||||
{
|
{
|
||||||
|
var seen = new HashSet<(string group, string assetPath)>();
|
||||||
for (int i = 0; i < _configs.Count; i++)
|
for (int i = 0; i < _configs.Count; i++)
|
||||||
{
|
{
|
||||||
PoolConfig left = _configs[i];
|
PoolConfig config = _configs[i];
|
||||||
for (int j = i + 1; j < _configs.Count; j++)
|
var key = (config.group, config.assetPath);
|
||||||
|
if (!seen.Add(key))
|
||||||
{
|
{
|
||||||
PoolConfig right = _configs[j];
|
Log.Warning($"Duplicate pool config detected: '{config.group}:{config.assetPath}'.");
|
||||||
if (!string.Equals(left.group, right.group, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left.matchMode != right.matchMode)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.Equals(left.assetPath, right.assetPath, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Warning($"Duplicate pool config detected: '{left.group}:{left.assetPath}'.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,11 +56,12 @@ namespace AlicizaX
|
|||||||
|
|
||||||
public void UnloadAsset(GameObject gameObject)
|
public void UnloadAsset(GameObject gameObject)
|
||||||
{
|
{
|
||||||
Resources.UnloadAsset(gameObject);
|
// Resources.UnloadAsset cannot unload GameObjects.
|
||||||
|
// The prefab reference is nulled by the caller; Unity handles cleanup via UnloadUnusedAssets.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AlicizaResourceLoader : IResourceLoader
|
public class AssetBundleResourceLoader : IResourceLoader
|
||||||
{
|
{
|
||||||
private IResourceModule _resourceModule;
|
private IResourceModule _resourceModule;
|
||||||
|
|
||||||
|
|||||||
@ -117,6 +117,14 @@ namespace AlicizaX
|
|||||||
|
|
||||||
internal sealed class RuntimePrefabPool : IMemory
|
internal sealed class RuntimePrefabPool : IMemory
|
||||||
{
|
{
|
||||||
|
private static readonly Comparison<GameObjectPoolInstanceSnapshot> InstanceSnapshotComparer = (left, right) =>
|
||||||
|
{
|
||||||
|
if (left == null && right == null) return 0;
|
||||||
|
if (left == null) return 1;
|
||||||
|
if (right == null) return -1;
|
||||||
|
if (left.isActive != right.isActive) return left.isActive ? -1 : 1;
|
||||||
|
return string.Compare(left.instanceName, right.instanceName, StringComparison.Ordinal);
|
||||||
|
};
|
||||||
private PoolConfig _config;
|
private PoolConfig _config;
|
||||||
private string _assetPath;
|
private string _assetPath;
|
||||||
private IResourceLoader _loader;
|
private IResourceLoader _loader;
|
||||||
@ -124,6 +132,7 @@ namespace AlicizaX
|
|||||||
private CancellationToken _shutdownToken;
|
private CancellationToken _shutdownToken;
|
||||||
private Dictionary<GameObject, RuntimePooledInstance> _instancesByObject;
|
private Dictionary<GameObject, RuntimePooledInstance> _instancesByObject;
|
||||||
private LinkedList<RuntimePooledInstance> _inactiveInstances;
|
private LinkedList<RuntimePooledInstance> _inactiveInstances;
|
||||||
|
private List<RuntimePooledInstance> _shutdownBuffer;
|
||||||
private Transform _root;
|
private Transform _root;
|
||||||
|
|
||||||
private GameObject _prefab;
|
private GameObject _prefab;
|
||||||
@ -135,6 +144,7 @@ namespace AlicizaX
|
|||||||
{
|
{
|
||||||
_instancesByObject = new Dictionary<GameObject, RuntimePooledInstance>();
|
_instancesByObject = new Dictionary<GameObject, RuntimePooledInstance>();
|
||||||
_inactiveInstances = new LinkedList<RuntimePooledInstance>();
|
_inactiveInstances = new LinkedList<RuntimePooledInstance>();
|
||||||
|
_shutdownBuffer = new List<RuntimePooledInstance>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(
|
public void Initialize(
|
||||||
@ -221,12 +231,13 @@ namespace AlicizaX
|
|||||||
instance.LastReleaseTime = Time.time;
|
instance.LastReleaseTime = Time.time;
|
||||||
_activeCount = Mathf.Max(0, _activeCount - 1);
|
_activeCount = Mathf.Max(0, _activeCount - 1);
|
||||||
|
|
||||||
|
gameObject.SetActive(false);
|
||||||
|
|
||||||
Transform transform = gameObject.transform;
|
Transform transform = gameObject.transform;
|
||||||
transform.SetParent(_root, false);
|
transform.SetParent(_root, false);
|
||||||
transform.localPosition = Vector3.zero;
|
transform.localPosition = Vector3.zero;
|
||||||
transform.localRotation = Quaternion.identity;
|
transform.localRotation = Quaternion.identity;
|
||||||
transform.localScale = Vector3.one;
|
transform.localScale = Vector3.one;
|
||||||
gameObject.SetActive(false);
|
|
||||||
|
|
||||||
instance.InactiveNode = _inactiveInstances.AddLast(instance);
|
instance.InactiveNode = _inactiveInstances.AddLast(instance);
|
||||||
TouchPrefab();
|
TouchPrefab();
|
||||||
@ -296,41 +307,19 @@ namespace AlicizaX
|
|||||||
snapshot.instances.Add(instanceSnapshot);
|
snapshot.instances.Add(instanceSnapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot.instances.Sort((left, right) =>
|
snapshot.instances.Sort(InstanceSnapshotComparer);
|
||||||
{
|
|
||||||
if (left == null && right == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left == null)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (right == null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (left.isActive != right.isActive)
|
|
||||||
{
|
|
||||||
return left.isActive ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Compare(left.instanceName, right.instanceName, StringComparison.Ordinal);
|
|
||||||
});
|
|
||||||
|
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
var instances = new List<RuntimePooledInstance>(_instancesByObject.Values);
|
_shutdownBuffer.AddRange(_instancesByObject.Values);
|
||||||
foreach (RuntimePooledInstance instance in instances)
|
foreach (RuntimePooledInstance instance in _shutdownBuffer)
|
||||||
{
|
{
|
||||||
DestroyInstance(instance);
|
DestroyInstance(instance);
|
||||||
}
|
}
|
||||||
|
_shutdownBuffer.Clear();
|
||||||
|
|
||||||
_inactiveInstances.Clear();
|
_inactiveInstances.Clear();
|
||||||
_instancesByObject.Clear();
|
_instancesByObject.Clear();
|
||||||
@ -455,7 +444,7 @@ namespace AlicizaX
|
|||||||
GameObject gameObject = instance.GameObject;
|
GameObject gameObject = instance.GameObject;
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
gameObject.transform.SetParent(parent);
|
gameObject.transform.SetParent(parent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
gameObject.SetActive(true);
|
gameObject.SetActive(true);
|
||||||
@ -566,6 +555,7 @@ namespace AlicizaX
|
|||||||
_shutdownToken = default;
|
_shutdownToken = default;
|
||||||
_instancesByObject.Clear();
|
_instancesByObject.Clear();
|
||||||
_inactiveInstances.Clear();
|
_inactiveInstances.Clear();
|
||||||
|
_shutdownBuffer.Clear();
|
||||||
_root = null;
|
_root = null;
|
||||||
_prefab = null;
|
_prefab = null;
|
||||||
_prefabLoadSource = null;
|
_prefabLoadSource = null;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user