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