Added support for custom scene handling, in addition to an addressable scene handler.

This commit is contained in:
Karrar
2025-03-11 07:05:45 +03:00
parent c5ebb22afd
commit ae40087bef
15 changed files with 431 additions and 251 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,166 @@
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine;
using Netick.Unity;
namespace Netick.Samples
{
[AddComponentMenu("Netick/Addressable Scene Handler")]
public class AddressableSceneHandler : NetworkSceneHandler
{
private class AddressableSceneOperation : ISceneOperation
{
AsyncOperationHandle<SceneInstance> Handle;
bool ISceneOperation.IsDone => Handle.IsDone;
float ISceneOperation.Progress => Handle.PercentComplete;
public AddressableSceneOperation(AsyncOperationHandle<SceneInstance> handle)
{
Handle = handle;
}
}
public string[] AddressableScenes = new string[0];
public override int CustomScenesCount => AddressableScenes != null ? AddressableScenes.Length : 0;
private Dictionary<string, int> _keyToIndex;
private Dictionary<int, string> _indexToKey;
private Dictionary<Scene, SceneInstance> _loadedScenes;
private void Awake()
{
_keyToIndex = new(AddressableScenes.Length);
_indexToKey = new(AddressableScenes.Length);
_loadedScenes = new(AddressableScenes.Length);
for (int i = 0; i < AddressableScenes.Length; i++)
{
_keyToIndex.Add(AddressableScenes[i], i);
_indexToKey.Add(i, AddressableScenes[i]);
}
}
protected override ISceneOperation LoadCustomSceneAsync(int index, LoadSceneParameters loadSceneParameters, out string sceneName)
{
var key = _indexToKey[index];
sceneName = key;
var handle = Addressables.LoadSceneAsync(key, loadSceneParameters);
handle.Completed += handle =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
_loadedScenes.Add(handle.Result.Scene, handle.Result);
else
Sandbox.LogError($"Addressables.LoadSceneAsync: failed to load an addressable scene {handle.DebugName}");
};
return new AddressableSceneOperation(handle);
}
protected override ISceneOperation UnloadCustomSceneAsync(Scene scene)
{
var didGetSceneInstance = _loadedScenes.TryGetValue(scene, out var sceneInstance);
if (!didGetSceneInstance || !scene.IsValid())
{
Sandbox.LogError($"Unloading scene: couldn't find a scene to unload {scene.name}");
return null;
}
var handle = Addressables.UnloadSceneAsync(sceneInstance);
handle.Completed += handle =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
_loadedScenes.Remove(handle.Result.Scene);
else
Sandbox.LogError($"Addressables.UnloadSceneAsync: failed to unload scene {scene.name}");
};
return new AddressableSceneOperation(handle);
}
// -- Addressable Scenes
public void LoadAddressableSceneAsync(string key, LoadSceneMode loadSceneMode)
{
if (_keyToIndex.TryGetValue(key, out int customIndex))
Sandbox.LoadCustomSceneAsync(customIndex, new LoadSceneParameters(loadSceneMode, Sandbox.GetDefaultPhysicsMode()));
else
Sandbox.LogError("Loading scene: failed to find the addressable scene key in the AddressableScenes array. Make sure to add all scenes keys to the array.");
}
public void LoadAddressableSceneAsync(string key, LoadSceneParameters loadSceneParameters)
{
if (_keyToIndex.TryGetValue(key, out int customIndex))
Sandbox.LoadCustomSceneAsync(customIndex, loadSceneParameters);
else
Sandbox.LogError("Loading scene: failed to find the addressable scene key in the AddressableScenes array. Make sure to add all scenes keys to the array.");
}
public void UnloadAddressableSceneAsync(string key)
{
if (_keyToIndex.TryGetValue(key, out int customIndex))
Sandbox.UnloadSceneAsync(customIndex);
else
Sandbox.LogError("Unloading scene: failed to find the addressable scene key in the AddressableScenes array. Make sure to add all scenes keys to the array.");
}
public void UnloadAddressableSceneAsync(Scene scene)
{
Sandbox.UnloadSceneAsync(scene);
}
// -- Build Scenes
// NetworkSceneHandler already implements exactly the code shown here, the reason we still included it in here is for demonstration purposes.
protected override AsyncOperation LoadBuildSceneAsync(int buildIndex, LoadSceneParameters loadSceneParameters) => SceneManager.LoadSceneAsync(buildIndex, loadSceneParameters);
protected override AsyncOperation UnloadBuildSceneAsync(Scene scene) => SceneManager.UnloadSceneAsync(scene);
}
public static class AddressableSceneHandlerSandboxExtensions
{
/// <summary>
/// <i><b>[Server Only]</b></i> Loads an addressable scene asynchronously using a key.
/// </summary>
public static void LoadAddressableSceneAsync(this NetworkSandbox sandbox, string key, LoadSceneMode loadSceneMode)
{
if (sandbox.TryGetComponent<AddressableSceneHandler>(out var defaultSceneHandler))
defaultSceneHandler.LoadAddressableSceneAsync(key, loadSceneMode);
else
sandbox.LogError($"{nameof(AddressableSceneHandler)} is not added to the sandbox. Make sure to add {nameof(AddressableSceneHandler)} to your sandbox prefab.");
}
/// <summary>
/// <i><b>[Server Only]</b></i> Loads an addressable scene asynchronously using a key.
/// </summary>
public static void LoadAddressableSceneAsync(this NetworkSandbox sandbox, string key, LoadSceneParameters loadSceneParameters)
{
if (sandbox.TryGetComponent<AddressableSceneHandler>(out var defaultSceneHandler))
defaultSceneHandler.LoadAddressableSceneAsync(key, loadSceneParameters);
else
sandbox.LogError($"{nameof(AddressableSceneHandler)} is not added to the sandbox. Make sure to add {nameof(AddressableSceneHandler)} to your sandbox prefab.");
}
/// <summary>
/// <i><b>[Server Only]</b></i> Unloads an addressable scene asynchronously using a key.
/// </summary>
public static void UnloadAddressableSceneAsync(this NetworkSandbox sandbox, string key)
{
if (sandbox.TryGetComponent<AddressableSceneHandler>(out var defaultSceneHandler))
defaultSceneHandler.UnloadAddressableSceneAsync(key);
else
sandbox.LogError($"{nameof(AddressableSceneHandler)} is not added to the sandbox. Make sure to add {nameof(AddressableSceneHandler)} to your sandbox prefab.");
}
/// <summary>
/// <i><b>[Server Only]</b></i> Unloads an addressable scene asynchronously using a Scene struct.
/// </summary>
public static void UnloadAddressableSceneAsync(this NetworkSandbox sandbox, Scene scene)
{
if (sandbox.TryGetComponent<AddressableSceneHandler>(out var defaultSceneHandler))
defaultSceneHandler.UnloadAddressableSceneAsync(scene);
else
sandbox.LogError($"{nameof(AddressableSceneHandler)} is not added to the sandbox. Make sure to add {nameof(AddressableSceneHandler)} to your sandbox prefab.");
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02be3a9e2ac6d2c45a70578c62ae81d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,7 +1,9 @@
{ {
"name": "Netick.Samples", "name": "Netick.Samples",
"rootNamespace": "",
"references": [ "references": [
"GUID:32b718c5820ccce438606ca82358f1da" "GUID:84651a3751eca9349aac36a66bba901b",
"GUID:9e24947de15b9834991c9d8411ea37cf"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

View File

@@ -48,7 +48,7 @@ namespace Netick.Samples
DrawText(3, "In Loss", (Sandbox.InPacketLoss * 100f).ToString(), "%"); DrawText(3, "In Loss", (Sandbox.InPacketLoss * 100f).ToString(), "%");
DrawText(4, "Out Loss", (Sandbox.OutPacketLoss * 100f).ToString(), "%"); DrawText(4, "Out Loss", (Sandbox.OutPacketLoss * 100f).ToString(), "%");
DrawText(5, "Interp Delay", (Sandbox.InterpolationDelay * 1000f).ToString(), "ms"); DrawText(5, "Interp Delay", (Sandbox.InterpolationDelay * 1000f).ToString(), "ms");
DrawText(6, "Resims", Sandbox.Monitor.Resimulations.Average.ToString(), "Ticks"); DrawText(6, "Resims", Sandbox.Monitor.Resimulations.Average.ToString(), "ticks");
DrawText(7, "Srv Tick Time", (Sandbox.Monitor.ServerTickTime.Max * 1000f).ToString(), "ms"); DrawText(7, "Srv Tick Time", (Sandbox.Monitor.ServerTickTime.Max * 1000f).ToString(), "ms");
DrawText(8, "Delta time", (Time.deltaTime * 1000f).ToString(), "ms"); DrawText(8, "Delta time", (Time.deltaTime * 1000f).ToString(), "ms");

View File

@@ -1,11 +1,12 @@
{ {
"name": "com.karrar.netick", "name": "com.karrar.netick",
"version": "0.13.21", "version": "0.13.24",
"displayName": "Netick", "displayName": "Netick",
"description": "A networking solution for Unity", "description": "A networking solution for Unity",
"unity": "2021.3", "unity": "2021.3",
"dependencies": { "dependencies": {
"com.unity.nuget.mono-cecil": "1.11.4" "com.unity.nuget.mono-cecil": "1.11.4",
"com.unity.addressables": "1.22.3"
}, },
"documentationUrl": "https://www.netick.net/docs.html", "documentationUrl": "https://www.netick.net/docs.html",
"samples": [ "samples": [