Optimize the scene unload logic.

优化场景卸载逻辑,在加载新的主场景的时候自动卸载已经加载的所有场景。
pull/4/head
hevinci 2022-04-21 21:11:11 +08:00
parent 20d2c517b2
commit f3ab8f63e7
7 changed files with 112 additions and 58 deletions

View File

@ -10,6 +10,7 @@ namespace YooAsset
{
private static readonly List<AssetBundleLoaderBase> _loaders = new List<AssetBundleLoaderBase>(1000);
private static readonly List<ProviderBase> _providers = new List<ProviderBase>(1000);
private static readonly Dictionary<string, SceneOperationHandle> _sceneHandles = new Dictionary<string, SceneOperationHandle>(100);
/// <summary>
/// 在编辑器下模拟运行
@ -132,6 +133,14 @@ namespace YooAsset
/// </summary>
public static SceneOperationHandle LoadSceneAsync(string scenePath, LoadSceneMode sceneMode, bool activateOnLoad, int priority)
{
// 注意:场景句柄永远保持唯一
if (_sceneHandles.ContainsKey(scenePath))
return _sceneHandles[scenePath];
// 如果加载的是主场景,则卸载所有缓存的场景
if (sceneMode == LoadSceneMode.Single)
UnloadAllScene();
ProviderBase provider = TryGetProvider(scenePath);
if (provider == null)
{
@ -141,7 +150,9 @@ namespace YooAsset
provider = new BundledSceneProvider(scenePath, sceneMode, activateOnLoad, priority);
_providers.Add(provider);
}
return provider.CreateHandle() as SceneOperationHandle;
var handle = provider.CreateHandle() as SceneOperationHandle;
_sceneHandles.Add(scenePath, handle);
return handle;
}
/// <summary>
@ -179,6 +190,48 @@ namespace YooAsset
}
internal static void UnloadSubScene(ProviderBase provider)
{
string scenePath = provider.AssetPath;
if (_sceneHandles.ContainsKey(scenePath) == false)
throw new Exception("Should never get here !");
// 释放子场景句柄
_sceneHandles[scenePath].ReleaseInternal();
_sceneHandles.Remove(scenePath);
// 卸载未被使用的资源(包括场景)
AssetSystem.UnloadUnusedAssets();
// 检验子场景是否销毁
if (provider.IsDestroyed == false)
{
throw new Exception("Should never get here !");
}
}
internal static void UnloadAllScene()
{
// 释放所有场景句柄
foreach (var valuePair in _sceneHandles)
{
valuePair.Value.ReleaseInternal();
}
_sceneHandles.Clear();
// 卸载未被使用的资源(包括场景)
AssetSystem.UnloadUnusedAssets();
// 检验所有场景是否销毁
foreach (var provider in _providers)
{
if (provider.IsSceneProvider())
{
if (provider.IsDestroyed == false)
throw new Exception("Should never get here !");
}
}
}
internal static AssetBundleLoaderBase CreateOwnerAssetBundleLoader(string assetPath)
{
string bundleName = BundleServices.GetBundleName(assetPath);
@ -254,6 +307,7 @@ namespace YooAsset
return provider;
}
#region 调试专属方法
internal static void GetDebugReport(DebugReport report)
{

View File

@ -2,7 +2,7 @@
namespace YooAsset
{
public class AssetOperationHandle : OperationHandleBase
public sealed class AssetOperationHandle : OperationHandleBase
{
private System.Action<AssetOperationHandle> _callback;

View File

@ -4,11 +4,13 @@ namespace YooAsset
{
public abstract class OperationHandleBase : IEnumerator
{
private readonly string _cachedAssetPath;
internal ProviderBase _provider { private set; get; }
internal OperationHandleBase(ProviderBase provider)
{
_provider = provider;
_cachedAssetPath = provider.AssetPath;
}
internal abstract void InvokeCallback();
@ -63,7 +65,18 @@ namespace YooAsset
{
get
{
return _provider != null && _provider.IsDestroyed == false;
if (_provider != null && _provider.IsDestroyed == false)
{
return true;
}
else
{
if (_provider == null)
YooLogger.Warning($"Operation handle is released : {_cachedAssetPath}");
else if (_provider.IsDestroyed)
YooLogger.Warning($"Provider is destroyed : {_cachedAssetPath}");
return false;
}
}
}

View File

@ -69,10 +69,35 @@ namespace YooAsset
}
/// <summary>
/// 异步卸载场景
/// 是否为主场景
/// </summary>
public bool IsMainScene()
{
if (IsValid == false)
return false;
if (_provider is DatabaseSceneProvider)
{
var temp = _provider as DatabaseSceneProvider;
return temp.SceneMode == LoadSceneMode.Single;
}
else if (_provider is BundledSceneProvider)
{
var temp = _provider as BundledSceneProvider;
return temp.SceneMode == LoadSceneMode.Single;
}
else
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 异步卸载子场景
/// </summary>
public UnloadSceneOperation UnloadAsync()
{
// 如果句柄无效
if (IsValid == false)
{
string error = $"{nameof(SceneOperationHandle)} is invalid.";
@ -81,54 +106,23 @@ namespace YooAsset
return operation;
}
ProviderBase provider = _provider;
// 释放场景句柄
ReleaseInternal();
// 卸载未被使用的资源(包括场景)
AssetSystem.UnloadUnusedAssets();
// 返回场景卸载异步操作类
if (provider.IsDestroyed == false)
// 如果是主场景
if (IsMainScene())
{
YooLogger.Warning($"Scene can not unload. The provider not destroyed : {provider.AssetPath}");
var operation = new UnloadSceneOperation();
string error = $"Cannot unload main scene. Use {nameof(YooAssets.LoadSceneAsync)} method to change the main scene !";
YooLogger.Error(error);
var operation = new UnloadSceneOperation(error);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else
{
if (IsAdditiveScene(provider))
{
var operation = new UnloadSceneOperation(provider.SceneObject);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
else
{
var operation = new UnloadSceneOperation();
OperationSystem.ProcessOperaiton(operation);
return operation;
}
}
}
private bool IsAdditiveScene(ProviderBase provider)
// 卸载子场景
Scene sceneObject = SceneObject;
AssetSystem.UnloadSubScene(_provider);
{
if (provider is DatabaseSceneProvider)
{
var temp = provider as DatabaseSceneProvider;
return temp.SceneMode == LoadSceneMode.Additive;
}
else if (provider is BundledSceneProvider)
{
var temp = provider as BundledSceneProvider;
return temp.SceneMode == LoadSceneMode.Additive;
}
else
{
throw new System.NotImplementedException();
var operation = new UnloadSceneOperation(sceneObject);
OperationSystem.ProcessOperaiton(operation);
return operation;
}
}
}

View File

@ -1,7 +1,7 @@

namespace YooAsset
{
public class SubAssetsOperationHandle : OperationHandleBase
public sealed class SubAssetsOperationHandle : OperationHandleBase
{
private System.Action<SubAssetsOperationHandle> _callback;

View File

@ -48,12 +48,15 @@ namespace YooAsset
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle)} is invalid.";
return;
}
if (_handle.AssetObject == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle.AssetObject)} is null.";
return;
}
if(_setPositionRotation)

View File

@ -12,7 +12,6 @@ namespace YooAsset
{
Normal,
Error,
Skip,
}
private enum ESteps
{
@ -40,10 +39,6 @@ namespace YooAsset
}
}
internal UnloadSceneOperation()
{
_flag = EFlag.Skip;
}
internal UnloadSceneOperation(string error)
{
_flag = EFlag.Error;
@ -60,11 +55,6 @@ namespace YooAsset
{
_steps = ESteps.UnLoad;
}
else if (_flag == EFlag.Skip)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else if (_flag == EFlag.Error)
{
_steps = ESteps.Done;