Skip to content

Commit

Permalink
feat: improve server scene loading, it will continue to load offline …
Browse files Browse the repository at this point in the history
…scene if it is disconnected while loading online scene, improve addressable asset loading function, make it a bit easier to use, improve addressable loading progress updating
  • Loading branch information
insthync committed Jul 3, 2024
1 parent 466f9e4 commit e90ede2
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 35 deletions.
36 changes: 22 additions & 14 deletions Scripts/AddressableAssets/AddressableAssetDownloadManager.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
Expand Down Expand Up @@ -27,6 +28,7 @@ public partial class AddressableAssetDownloadManager : MonoBehaviour

private async void Start()
{
await UniTask.Yield();
onStart?.Invoke();
AsyncOperationHandle<AddressableAssetDownloadManagerSettings> settingsAsyncOp = settingsAssetReference.LoadAssetAsync();
await settingsAsyncOp.Task;
Expand Down Expand Up @@ -82,15 +84,16 @@ await Download(
}
LoadedCount++;
}
await UniTask.Yield();
onDownloadedAll?.Invoke();
// Instantiates
for (int i = 0; i < settings.InitialObjects.Count; ++i)
{
try
{
AsyncOperationHandle<GameObject> getSizeOp = Addressables.InstantiateAsync(settings.InitialObjects[i].RuntimeKey);
await getSizeOp.Task;
Logging.Log($"Initialized {getSizeOp.Result.name}");
AsyncOperationHandle<GameObject> instantiateOp = Addressables.InstantiateAsync(settings.InitialObjects[i].RuntimeKey);
await instantiateOp.Task;
Logging.Log($"Initialized {instantiateOp.Result.name}");
}
catch (System.Exception ex)
{
Expand Down Expand Up @@ -158,12 +161,12 @@ public static async Task<SceneInstance> DownloadAndLoadScene(
System.Action onDepsDownloaded)
{
await Download(runtimeKey, onFileSizeRetrieving, onFileSizeRetrieved, onDepsDownloading, onDepsFileDownloading, onDepsDownloaded);
AsyncOperationHandle<SceneInstance> getSizeOp = Addressables.LoadSceneAsync(runtimeKey, loadSceneParameters);
while (!getSizeOp.IsDone)
AsyncOperationHandle<SceneInstance> loadSceneOp = Addressables.LoadSceneAsync(runtimeKey, loadSceneParameters);
while (!loadSceneOp.IsDone)
{
await Task.Yield();
await UniTask.Yield();
}
return getSizeOp.Result;
return loadSceneOp.Result;
}

public static async Task<GameObject> DownloadAndInstantiate(
Expand All @@ -175,12 +178,12 @@ public static async Task<GameObject> DownloadAndInstantiate(
System.Action onDepsDownloaded)
{
await Download(runtimeKey, onFileSizeRetrieving, onFileSizeRetrieved, onDepsDownloading, onDepsFileDownloading, onDepsDownloaded);
AsyncOperationHandle<GameObject> getSizeOp = Addressables.InstantiateAsync(runtimeKey);
while (!getSizeOp.IsDone)
AsyncOperationHandle<GameObject> instantiateOp = Addressables.InstantiateAsync(runtimeKey);
while (!instantiateOp.IsDone)
{
await Task.Yield();
await UniTask.Yield();
}
return getSizeOp.Result;
return instantiateOp.Result;
}

public static async Task Download(
Expand All @@ -193,23 +196,28 @@ public static async Task Download(
{
// Get download size
AsyncOperationHandle<long> getSizeOp = Addressables.GetDownloadSizeAsync(runtimeKey);
await UniTask.Yield();
onFileSizeRetrieving?.Invoke();
while (!getSizeOp.IsDone)
{
await Task.Yield();
await UniTask.Yield();
}
long fileSize = getSizeOp.Result;
await UniTask.Yield();
onFileSizeRetrieved.Invoke(fileSize);
// Download dependencies
if (fileSize > 0)
{
AsyncOperationHandle downloadOp = Addressables.DownloadDependenciesAsync(runtimeKey);
await UniTask.Yield();
onDepsDownloading?.Invoke();
while (!downloadOp.IsDone)
{
onDepsFileDownloading?.Invoke((long)(downloadOp.PercentComplete * fileSize), fileSize, downloadOp.PercentComplete);
await Task.Yield();
await UniTask.Yield();
float percentageComplete = downloadOp.GetDownloadStatus().Percent;
onDepsFileDownloading?.Invoke((long)(percentageComplete * fileSize), fileSize, percentageComplete);
}
await UniTask.Yield();
onDepsDownloaded?.Invoke();
Addressables.ReleaseInstance(downloadOp);
}
Expand Down
30 changes: 26 additions & 4 deletions Scripts/AddressableAssets/AddressableAssetsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ public static class AddressableAssetsManager
private static Dictionary<object, GameObject> s_loadedAssets = new Dictionary<object, GameObject>();
private static Dictionary<object, AsyncOperationHandle> s_assetRefs = new Dictionary<object, AsyncOperationHandle>();

public static async Task<TType> GetOrLoadAssetAsync<TAssetRef, TType>(this TAssetRef assetRef, System.Action<AsyncOperationHandle> handlerCallback = null)
where TAssetRef : AssetReference
public static async Task<TType> GetOrLoadAssetAsync<TType>(this AssetReference assetRef, System.Action<AsyncOperationHandle> handlerCallback = null)
where TType : Component
{
if (s_loadedAssets.TryGetValue(assetRef.RuntimeKey, out GameObject result))
Expand All @@ -25,8 +24,7 @@ public static async Task<TType> GetOrLoadAssetAsync<TAssetRef, TType>(this TAsse
return handlerResult.GetComponent<TType>();
}

public static TType GetOrLoadAsset<TAssetRef, TType>(this TAssetRef assetRef, System.Action<AsyncOperationHandle> handlerCallback = null)
where TAssetRef : AssetReference
public static TType GetOrLoadAsset<TType>(this AssetReference assetRef, System.Action<AsyncOperationHandle> handlerCallback = null)
where TType : Component
{
if (s_loadedAssets.TryGetValue(assetRef.RuntimeKey, out GameObject result))
Expand All @@ -39,6 +37,30 @@ public static TType GetOrLoadAsset<TAssetRef, TType>(this TAssetRef assetRef, Sy
return handlerResult.GetComponent<TType>();
}

public static async Task<GameObject> GetOrLoadAssetAsync(this AssetReference assetRef, System.Action<AsyncOperationHandle> handlerCallback = null)
{
if (s_loadedAssets.TryGetValue(assetRef.RuntimeKey, out GameObject result))
return result;
AsyncOperationHandle<GameObject> handler = Addressables.LoadAssetAsync<GameObject>(assetRef.RuntimeKey);
handlerCallback?.Invoke(handler);
GameObject handlerResult = await handler.Task;
s_loadedAssets[assetRef.RuntimeKey] = handlerResult;
s_assetRefs[assetRef.RuntimeKey] = handler;
return handlerResult;
}

public static GameObject GetOrLoadAsset(this AssetReference assetRef, System.Action<AsyncOperationHandle> handlerCallback = null)
{
if (s_loadedAssets.TryGetValue(assetRef.RuntimeKey, out GameObject result))
return result;
AsyncOperationHandle<GameObject> handler = Addressables.LoadAssetAsync<GameObject>(assetRef.RuntimeKey);
handlerCallback?.Invoke(handler);
GameObject handlerResult = handler.WaitForCompletion();
s_loadedAssets[assetRef.RuntimeKey] = handlerResult;
s_assetRefs[assetRef.RuntimeKey] = handler;
return handlerResult;
}

public static void Release<TAssetRef>(this TAssetRef assetRef)
where TAssetRef : AssetReference
{
Expand Down
15 changes: 11 additions & 4 deletions Scripts/GameApi/LiteNetLibAdditiveSceneLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,19 @@ public async UniTask<int> LoadAll(LiteNetLibGameManager manager, string sceneNam
{
string loadingName = $"{sceneName}_{loadCount++}";
// Load the scene
await UniTask.Yield();
manager.Assets.onLoadSceneStart.Invoke(loadingName, true, isOnline, 0f);
var op = SceneManager.LoadSceneAsync(
scenes[i].SceneName,
new LoadSceneParameters(LoadSceneMode.Additive));
while (!op.isDone)
op.allowSceneActivation = false;
while (op.progress < 0.9f)
{
await UniTask.NextFrame();
await UniTask.Yield();
manager.Assets.onLoadSceneProgress.Invoke(loadingName, true, isOnline, op.progress);
}
op.allowSceneActivation = true;
await UniTask.Yield();
manager.Assets.onLoadSceneFinish.Invoke(loadingName, true, isOnline, 1f);
manager.LoadedAdditiveScenesCount++;
manager.Assets.onLoadAdditiveSceneProgress.Invoke(manager.LoadedAdditiveScenesCount, manager.TotalAdditiveScensCount);
Expand All @@ -78,6 +82,7 @@ public async UniTask<int> LoadAll(LiteNetLibGameManager manager, string sceneNam
{
string loadingName = $"{sceneName}_{loadCount++}";
// Download the scene
await UniTask.Yield();
await AddressableAssetDownloadManager.Download(
addressableScenes[i].RuntimeKey,
manager.Assets.onSceneFileSizeRetrieving.Invoke,
Expand All @@ -92,9 +97,11 @@ await AddressableAssetDownloadManager.Download(
new LoadSceneParameters(LoadSceneMode.Additive));
while (!op.IsDone)
{
await UniTask.NextFrame();
manager.Assets.onLoadSceneProgress.Invoke(loadingName, true, isOnline, op.PercentComplete);
await UniTask.Yield();
float percentageComplete = op.GetDownloadStatus().Percent;
manager.Assets.onLoadSceneProgress.Invoke(loadingName, true, isOnline, percentageComplete);
}
await UniTask.Yield();
manager.Assets.onLoadSceneFinish.Invoke(loadingName, true, isOnline, 1f);
manager.LoadedAdditiveScenesCount++;
manager.Assets.onLoadAdditiveSceneProgress.Invoke(manager.LoadedAdditiveScenesCount, manager.TotalAdditiveScensCount);
Expand Down
29 changes: 20 additions & 9 deletions Scripts/GameApi/LiteNetLibAssets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

namespace LiteNetLibManager
{
Expand Down Expand Up @@ -162,7 +163,7 @@ public async Task<LiteNetLibIdentity> RegisterAddressablePrefabAsync(AssetRefere
return null;
}
if (Manager.LogDev) Logging.Log(LogTag, $"RegisterAddressablePrefab [{addressablePrefab.HashAssetId}]");
LiteNetLibIdentity prefab = await addressablePrefab.GetOrLoadAssetAsync<AssetReferenceLiteNetLibIdentity, LiteNetLibIdentity>();
LiteNetLibIdentity prefab = await addressablePrefab.GetOrLoadAssetAsync<LiteNetLibIdentity>();
GuidToPrefabs[addressablePrefab.HashAssetId] = prefab;
return prefab;
}
Expand All @@ -175,7 +176,7 @@ public LiteNetLibIdentity RegisterAddressablePrefab(AssetReferenceLiteNetLibIden
return null;
}
if (Manager.LogDev) Logging.Log(LogTag, $"RegisterAddressablePrefab [{addressablePrefab.HashAssetId}]");
LiteNetLibIdentity prefab = addressablePrefab.GetOrLoadAsset<AssetReferenceLiteNetLibIdentity, LiteNetLibIdentity>();
LiteNetLibIdentity prefab = addressablePrefab.GetOrLoadAsset<LiteNetLibIdentity>();
GuidToPrefabs[addressablePrefab.HashAssetId] = prefab;
return prefab;
}
Expand Down Expand Up @@ -334,15 +335,25 @@ public void PushInstanceBack(LiteNetLibIdentity instance)
public void RegisterSceneObjects()
{
SceneObjects.Clear();
LiteNetLibIdentity[] sceneObjects = FindObjectsOfType<LiteNetLibIdentity>();
for (int i = 0; i < sceneObjects.Length; ++i)
for (int i = 0; i < SceneManager.sceneCount; ++i)
{
LiteNetLibIdentity sceneObject = sceneObjects[i];
if (sceneObject.ObjectId > 0)
Scene scene = SceneManager.GetSceneAt(i);
if (!scene.isLoaded)
continue;
GameObject[] rootObjects = scene.GetRootGameObjects();
for (int j = 0; j < rootObjects.Length; ++j)
{
sceneObject.gameObject.SetActive(false);
SceneObjects[sceneObject.ObjectId] = sceneObject;
LiteNetLibIdentity.UpdateHighestObjectId(sceneObject.ObjectId);
LiteNetLibIdentity[] sceneObjects = rootObjects[j].GetComponentsInChildren<LiteNetLibIdentity>(true);
for (int k = 0; k < sceneObjects.Length; ++k)
{
LiteNetLibIdentity sceneObject = sceneObjects[k];
if (sceneObject.ObjectId > 0)
{
sceneObject.gameObject.SetActive(false);
SceneObjects[sceneObject.ObjectId] = sceneObject;
LiteNetLibIdentity.UpdateHighestObjectId(sceneObject.ObjectId);
}
}
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions Scripts/GameApi/LiteNetLibGameManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,9 @@ await AddressableAssetDownloadManager.Download(
// Wait until scene loaded
while (!asyncOp.IsDone)
{
await UniTask.NextFrame();
Assets.onLoadSceneProgress.Invoke(serverSceneInfo.sceneName, false, isOnline, asyncOp.PercentComplete);
await UniTask.Yield();
float percentageComplete = asyncOp.GetDownloadStatus().Percent;
Assets.onLoadSceneProgress.Invoke(serverSceneInfo.sceneName, false, isOnline, percentageComplete);
}
}
else
Expand All @@ -329,12 +330,14 @@ await AddressableAssetDownloadManager.Download(
AsyncOperation asyncOp = SceneManager.LoadSceneAsync(
serverSceneInfo.sceneName,
new LoadSceneParameters(LoadSceneMode.Single));
asyncOp.allowSceneActivation = false;
// Wait until scene loaded
while (asyncOp != null && !asyncOp.isDone)
while (asyncOp.progress < 0.9f)
{
await UniTask.NextFrame();
await UniTask.Yield();
Assets.onLoadSceneProgress.Invoke(serverSceneInfo.sceneName, false, isOnline, asyncOp.progress);
}
asyncOp.allowSceneActivation = true;
}

// If scene changed while loading, have to load the new one
Expand Down

0 comments on commit e90ede2

Please sign in to comment.