diff --git a/Netick/Editor/Netick.CodeGen.dll b/Netick/Editor/Netick.CodeGen.dll index 250cf14..71b7bb2 100644 Binary files a/Netick/Editor/Netick.CodeGen.dll and b/Netick/Editor/Netick.CodeGen.dll differ diff --git a/Netick/Editor/Netick.Unity.Editor.dll b/Netick/Editor/Netick.Unity.Editor.dll index ea77b73..b4adce5 100644 Binary files a/Netick/Editor/Netick.Unity.Editor.dll and b/Netick/Editor/Netick.Unity.Editor.dll differ diff --git a/Netick/Editor/Netick.Unity.Pro.Editor.dll b/Netick/Editor/Netick.Unity.Pro.Editor.dll index 3b85db6..11b1d21 100644 Binary files a/Netick/Editor/Netick.Unity.Pro.Editor.dll and b/Netick/Editor/Netick.Unity.Pro.Editor.dll differ diff --git a/Netick/Editor/Unity.Netick.CodeGen.dll b/Netick/Editor/Unity.Netick.CodeGen.dll index c592595..6a988c8 100644 Binary files a/Netick/Editor/Unity.Netick.CodeGen.dll and b/Netick/Editor/Unity.Netick.CodeGen.dll differ diff --git a/Netick/Runtime/Netick.Pro.dll b/Netick/Runtime/Netick.Pro.dll index e2e1dca..20ecfdc 100644 Binary files a/Netick/Runtime/Netick.Pro.dll and b/Netick/Runtime/Netick.Pro.dll differ diff --git a/Netick/Runtime/Netick.Unity.Pro.dll b/Netick/Runtime/Netick.Unity.Pro.dll index fa0bbde..5c43a6f 100644 Binary files a/Netick/Runtime/Netick.Unity.Pro.dll and b/Netick/Runtime/Netick.Unity.Pro.dll differ diff --git a/Netick/Runtime/Netick.Unity.dll b/Netick/Runtime/Netick.Unity.dll index 4b87d26..ce23f07 100644 Binary files a/Netick/Runtime/Netick.Unity.dll and b/Netick/Runtime/Netick.Unity.dll differ diff --git a/Netick/Runtime/Netick.dll b/Netick/Runtime/Netick.dll index 88af4d6..f2a07ff 100644 Binary files a/Netick/Runtime/Netick.dll and b/Netick/Runtime/Netick.dll differ diff --git a/Scripts/AddressableSceneHandler.cs b/Scripts/AddressableSceneHandler.cs new file mode 100644 index 0000000..71ffc2d --- /dev/null +++ b/Scripts/AddressableSceneHandler.cs @@ -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 Handle; + bool ISceneOperation.IsDone => Handle.IsDone; + float ISceneOperation.Progress => Handle.PercentComplete; + public AddressableSceneOperation(AsyncOperationHandle handle) + { + Handle = handle; + } + } + + public string[] AddressableScenes = new string[0]; + public override int CustomScenesCount => AddressableScenes != null ? AddressableScenes.Length : 0; + + private Dictionary _keyToIndex; + private Dictionary _indexToKey; + private Dictionary _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 + { + /// + /// [Server Only] Loads an addressable scene asynchronously using a key. + /// + public static void LoadAddressableSceneAsync(this NetworkSandbox sandbox, string key, LoadSceneMode loadSceneMode) + { + if (sandbox.TryGetComponent(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."); + } + + /// + /// [Server Only] Loads an addressable scene asynchronously using a key. + /// + public static void LoadAddressableSceneAsync(this NetworkSandbox sandbox, string key, LoadSceneParameters loadSceneParameters) + { + if (sandbox.TryGetComponent(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."); + } + + /// + /// [Server Only] Unloads an addressable scene asynchronously using a key. + /// + public static void UnloadAddressableSceneAsync(this NetworkSandbox sandbox, string key) + { + if (sandbox.TryGetComponent(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."); + } + + /// + /// [Server Only] Unloads an addressable scene asynchronously using a Scene struct. + /// + public static void UnloadAddressableSceneAsync(this NetworkSandbox sandbox, Scene scene) + { + if (sandbox.TryGetComponent(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."); + } + } +} \ No newline at end of file diff --git a/Scripts/AddressableSceneHandler.cs.meta b/Scripts/AddressableSceneHandler.cs.meta new file mode 100644 index 0000000..c2ceb97 --- /dev/null +++ b/Scripts/AddressableSceneHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02be3a9e2ac6d2c45a70578c62ae81d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/GameStarter.cs b/Scripts/GameStarter.cs index dbde984..f899eef 100644 --- a/Scripts/GameStarter.cs +++ b/Scripts/GameStarter.cs @@ -5,141 +5,141 @@ using Network = Netick.Unity.Network; namespace Netick.Samples { - /// - /// This is a helper script for quick prototyping, used to start Netick. - /// - [AddComponentMenu("Netick/Game Starter")] - public class GameStarter : NetworkEventsListener + /// + /// This is a helper script for quick prototyping, used to start Netick. + /// + [AddComponentMenu("Netick/Game Starter")] + public class GameStarter : NetworkEventsListener + { + public GameObject SandboxPrefab; + public NetworkTransportProvider Transport; + public StartMode Mode = StartMode.MultiplePeers; + [Range(1, 5)] + public int Clients = 1; + public bool StartServerInMultiplePeersMode = true; + + public bool AutoStart; + public bool AutoConnect; + + [Header("Network")] + [Range(0, 65535)] + public int Port; + public string ServerIPAddress = "127.0.0.1"; + + [Header("Headless Server FPS")] + public bool Cap = true; + public int FPS = 450; + + [Header("UI")] + public bool ShowDisconnectButton = true; + public bool ShowConnectButton = true; + public Vector2 Offset = new Vector2(36, 0); + + private void Reset() { - public GameObject SandboxPrefab; - public NetworkTransportProvider Transport; - public StartMode Mode = StartMode.MultiplePeers; - [Range(1, 5)] - public int Clients = 1; - public bool StartServerInMultiplePeersMode = true; - - public bool AutoStart; - public bool AutoConnect; - - [Header("Network")] - [Range(0, 65535)] - public int Port; - public string ServerIPAddress = "127.0.0.1"; - - [Header("Headless Server FPS")] - public bool Cap = true; - public int FPS = 450; - - [Header("UI")] - public bool ShowDisconnectButton = true; - public bool ShowConnectButton = true; - public Vector2 Offset = new Vector2(36, 0); - - private void Reset() - { - if (Port == 0) - Port = Random.Range(4000, 65535); - } - - private void Awake() - { - if (Application.isBatchMode) - { - Application.targetFrameRate = FPS; - Network.StartAsServer(Transport, Port, SandboxPrefab); - } - - else if (AutoStart) - { - if (Network.Instance == null) - { - switch (Mode) - { - case StartMode.Server: - Network.StartAsServer(Transport, Port, SandboxPrefab); - break; - case StartMode.Client: - Network.StartAsClient(Transport, Port, SandboxPrefab).Connect(Port, ServerIPAddress); - break; - case StartMode.MultiplePeers: - var sandboxes = Network.StartAsMultiplePeers(Transport, Port, SandboxPrefab, StartServerInMultiplePeersMode, true, Clients); - - if (AutoConnect) - { - for (int i = 0; i < sandboxes.Clients.Length; i++) - sandboxes.Clients[i].Connect(Port, ServerIPAddress); - } - - - break; - } - } - } - } - - private void OnGUI() - { - if (Network.IsRunning) - { - if (Sandbox != null && Sandbox.IsClient) - { - if (!Sandbox.IsVisible) - return; - - if (Sandbox.IsConnected) - { - if (ShowDisconnectButton) - { - GUI.Label(new Rect(Offset.x, Offset.y + 170, 200, 50), $"Connected to {Sandbox.ServerEndPoint}"); - - if (GUI.Button(new Rect(Offset.x, Offset.y + 220, 200, 50), "Disconnect")) - Sandbox.DisconnectFromServer(); - } - - } - else if (ShowConnectButton) - { - if (GUI.Button(new Rect(Offset.x, Offset.y + 40, 200, 50), "Connect")) - Sandbox.Connect(Port, ServerIPAddress); - - ServerIPAddress = GUI.TextField(new Rect(Offset.x, Offset.y + 100, 200, 50), ServerIPAddress); - Port = int.Parse(GUI.TextField(new Rect(Offset.x, Offset.y+ 160, 200, 50), Port.ToString())); - } - } - - - return; - } - - if (GUI.Button(new Rect(Offset.x, Offset.y + 40, 200, 50), "Run Host")) - { - Network.StartAsHost(Transport, Port, SandboxPrefab); - } - - if (GUI.Button(new Rect(Offset.x, Offset.y + 100, 200, 50), "Run Client")) - { - var sandbox = Network.StartAsClient(Transport, Port, SandboxPrefab); - sandbox.Connect(Port, ServerIPAddress); - } - - if (GUI.Button(new Rect(Offset.x, Offset.y + 160, 200, 50), "Run Server")) - { - Network.StartAsServer(Transport, Port, SandboxPrefab); - } - - if (GUI.Button(new Rect(Offset.x, Offset.y + 220, 200, 50), "Run Host + Client")) - { - var sandboxes = Network.StartAsMultiplePeers(Transport, Port, SandboxPrefab, StartServerInMultiplePeersMode, true, Clients); - - if (AutoConnect) - { - for (int i = 0; i < Clients; i++) - sandboxes.Clients[i].Connect(Port, ServerIPAddress); - } - } - - ServerIPAddress = GUI.TextField(new Rect(Offset.x, Offset.y + 280, 200, 50), ServerIPAddress); - - } + if (Port == 0) + Port = Random.Range(4000, 65535); } + + private void Awake() + { + if (Application.isBatchMode) + { + Application.targetFrameRate = FPS; + Network.StartAsServer(Transport, Port, SandboxPrefab); + } + + else if (AutoStart) + { + if (Network.Instance == null) + { + switch (Mode) + { + case StartMode.Server: + Network.StartAsServer(Transport, Port, SandboxPrefab); + break; + case StartMode.Client: + Network.StartAsClient(Transport, Port, SandboxPrefab).Connect(Port, ServerIPAddress); + break; + case StartMode.MultiplePeers: + var sandboxes = Network.StartAsMultiplePeers(Transport, Port, SandboxPrefab, StartServerInMultiplePeersMode, true, Clients); + + if (AutoConnect) + { + for (int i = 0; i < sandboxes.Clients.Length; i++) + sandboxes.Clients[i].Connect(Port, ServerIPAddress); + } + + + break; + } + } + } + } + + private void OnGUI() + { + if (Network.IsRunning) + { + if (Sandbox != null && Sandbox.IsClient) + { + if (!Sandbox.IsVisible) + return; + + if (Sandbox.IsConnected) + { + if (ShowDisconnectButton) + { + GUI.Label(new Rect(Offset.x, Offset.y + 170, 200, 50), $"Connected to {Sandbox.ServerEndPoint}"); + + if (GUI.Button(new Rect(Offset.x, Offset.y + 220, 200, 50), "Disconnect")) + Sandbox.DisconnectFromServer(); + } + + } + else if (ShowConnectButton) + { + if (GUI.Button(new Rect(Offset.x, Offset.y + 40, 200, 50), "Connect")) + Sandbox.Connect(Port, ServerIPAddress); + + ServerIPAddress = GUI.TextField(new Rect(Offset.x, Offset.y + 100, 200, 50), ServerIPAddress); + Port = int.Parse(GUI.TextField(new Rect(Offset.x, Offset.y + 160, 200, 50), Port.ToString())); + } + } + + + return; + } + + if (GUI.Button(new Rect(Offset.x, Offset.y + 40, 200, 50), "Run Host")) + { + Network.StartAsHost(Transport, Port, SandboxPrefab); + } + + if (GUI.Button(new Rect(Offset.x, Offset.y + 100, 200, 50), "Run Client")) + { + var sandbox = Network.StartAsClient(Transport, Port, SandboxPrefab); + sandbox.Connect(Port, ServerIPAddress); + } + + if (GUI.Button(new Rect(Offset.x, Offset.y + 160, 200, 50), "Run Server")) + { + Network.StartAsServer(Transport, Port, SandboxPrefab); + } + + if (GUI.Button(new Rect(Offset.x, Offset.y + 220, 200, 50), "Run Host + Client")) + { + var sandboxes = Network.StartAsMultiplePeers(Transport, Port, SandboxPrefab, StartServerInMultiplePeersMode, true, Clients); + + if (AutoConnect) + { + for (int i = 0; i < Clients; i++) + sandboxes.Clients[i].Connect(Port, ServerIPAddress); + } + } + + ServerIPAddress = GUI.TextField(new Rect(Offset.x, Offset.y + 280, 200, 50), ServerIPAddress); + + } + } } diff --git a/Scripts/Netick.Samples.asmdef b/Scripts/Netick.Samples.asmdef index 7708f29..0d79ac5 100644 --- a/Scripts/Netick.Samples.asmdef +++ b/Scripts/Netick.Samples.asmdef @@ -1,7 +1,9 @@ { "name": "Netick.Samples", + "rootNamespace": "", "references": [ - "GUID:32b718c5820ccce438606ca82358f1da" + "GUID:84651a3751eca9349aac36a66bba901b", + "GUID:9e24947de15b9834991c9d8411ea37cf" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Scripts/NetworkInfo.cs b/Scripts/NetworkInfo.cs index 5f7badd..c25cec3 100644 --- a/Scripts/NetworkInfo.cs +++ b/Scripts/NetworkInfo.cs @@ -5,91 +5,91 @@ using Network = Netick.Unity.Network; namespace Netick.Samples { - /// - /// This is a helper script for quick prototyping, used to show useful network information of Netick. - /// - [AddComponentMenu("Netick/Network Info")] - public class NetworkInfo : NetworkEventsListener - { - [Header("Network Stats")] - public Vector2 Offset = new Vector2(27, 20); + /// + /// This is a helper script for quick prototyping, used to show useful network information of Netick. + /// + [AddComponentMenu("Netick/Network Info")] + public class NetworkInfo : NetworkEventsListener + { + [Header("Network Stats")] + public Vector2 Offset = new Vector2(27, 20); - [Header("Network Conditions Icons")] - public float MediumLatencyThreshold = 150; - public float HighLatencyThreshold = 250; - public float MediumPacketLossThreshold = 1; - public float HighPacketLossThreshold = 10; + [Header("Network Conditions Icons")] + public float MediumLatencyThreshold = 150; + public float HighLatencyThreshold = 250; + public float MediumPacketLossThreshold = 1; + public float HighPacketLossThreshold = 10; - public Vector2 PacketLossIconOffset = new Vector2(-80, 30); - public Vector2 LatencyIconOffset = new Vector2(-80, 70); - public Vector2 ServerLagIconOffset = new Vector2(-80, 110); - public float IconSize = 30; + public Vector2 PacketLossIconOffset = new Vector2(-80, 30); + public Vector2 LatencyIconOffset = new Vector2(-80, 70); + public Vector2 ServerLagIconOffset = new Vector2(-80, 110); + public float IconSize = 30; - private Texture _packetLossIcon; - private Texture _latencyIcon; - private Texture _serverLagIcon; + private Texture _packetLossIcon; + private Texture _latencyIcon; + private Texture _serverLagIcon; - private void Awake() - { - _packetLossIcon = Resources.Load("Network Icons/PacketLoss"); - _latencyIcon = Resources.Load("Network Icons/Latency"); - _serverLagIcon = Resources.Load("Network Icons/ServerLag"); - } - - private void OnGUI() - { - if (Network.IsRunning) - { - if (Sandbox != null && Sandbox.IsConnected && Sandbox.IsVisible) - { - DrawText(0, "RTT", (Sandbox.RTT * 1000f).ToString(), "ms"); - DrawText(1, "In", Sandbox.InKBps.ToString(), "KB/s"); - DrawText(2, "Out", Sandbox.OutKBps.ToString(), "KB/s"); - DrawText(3, "In Loss", (Sandbox.InPacketLoss * 100f).ToString(), "%"); - DrawText(4, "Out Loss", (Sandbox.OutPacketLoss * 100f).ToString(), "%"); - DrawText(5, "Interp Delay", (Sandbox.InterpolationDelay * 1000f).ToString(), "ms"); - DrawText(6, "Resims", Sandbox.Monitor.Resimulations.Average.ToString(), "Ticks"); - DrawText(7, "Srv Tick Time", (Sandbox.Monitor.ServerTickTime.Max * 1000f).ToString(), "ms"); - DrawText(8, "Delta time", (Time.deltaTime * 1000f).ToString(), "ms"); - - DrawIcons(); - } - } - } - - private void DrawText(int offset, string title, string content, string unit) - { - GUI.Label(new Rect(Offset.x + 10, Offset.y + 10 + (15 * offset), 200, 50), $"{title}: "); - GUI.Label(new Rect(Offset.x + 130, Offset.y + 10 + (15 * offset), 200, 50), $"{content} {unit}"); - } - - public void DrawIcons() - { - var pktLossIconPos = PacketLossIconOffset + (Screen.width * Vector2.right); - var latencyIconPos = LatencyIconOffset + (Screen.width * Vector2.right); - var serverLagIconPos = ServerLagIconOffset + (Screen.width * Vector2.right); - - var pktLoss = Mathf.Max(Sandbox.InPacketLoss, Sandbox.OutPacketLoss) * 100; // multiplying by 100 to convert from a decimal to a percentage. - var rtt = Sandbox.RTT * 1000f; // multiplying by 1000 to convert from seconds to milliseconds. - - if (pktLoss >= MediumPacketLossThreshold) - { - Color color = pktLoss < HighPacketLossThreshold ? Color.yellow : Color.red; - GUI.DrawTexture(new Rect(pktLossIconPos, Vector2.one * IconSize), _packetLossIcon, ScaleMode.ScaleToFit, true, 1f, color, 0f, 0f); - } - - if (rtt >= MediumLatencyThreshold) - { - Color color = rtt >= HighLatencyThreshold ? Color.red : Color.yellow; - GUI.DrawTexture(new Rect(latencyIconPos, Vector2.one * IconSize), _latencyIcon, ScaleMode.ScaleToFit, true, 1f, color, 0f, 0f); - } - - if (Sandbox.Monitor.ServerTickTime.Max >= Sandbox.FixedDeltaTime) - { - Color color = Sandbox.Monitor.ServerTickTime.Average >= Sandbox.FixedDeltaTime ? Color.red : Color.yellow; - GUI.DrawTexture(new Rect(serverLagIconPos, Vector2.one * IconSize), _serverLagIcon, ScaleMode.ScaleToFit, true, 1f, color, 0f, 0f); - } - - } + private void Awake() + { + _packetLossIcon = Resources.Load("Network Icons/PacketLoss"); + _latencyIcon = Resources.Load("Network Icons/Latency"); + _serverLagIcon = Resources.Load("Network Icons/ServerLag"); } + + private void OnGUI() + { + if (Network.IsRunning) + { + if (Sandbox != null && Sandbox.IsConnected && Sandbox.IsVisible) + { + DrawText(0, "RTT", (Sandbox.RTT * 1000f).ToString(), "ms"); + DrawText(1, "In", Sandbox.InKBps.ToString(), "KB/s"); + DrawText(2, "Out", Sandbox.OutKBps.ToString(), "KB/s"); + DrawText(3, "In Loss", (Sandbox.InPacketLoss * 100f).ToString(), "%"); + DrawText(4, "Out Loss", (Sandbox.OutPacketLoss * 100f).ToString(), "%"); + DrawText(5, "Interp Delay", (Sandbox.InterpolationDelay * 1000f).ToString(), "ms"); + DrawText(6, "Resims", Sandbox.Monitor.Resimulations.Average.ToString(), "ticks"); + DrawText(7, "Srv Tick Time", (Sandbox.Monitor.ServerTickTime.Max * 1000f).ToString(), "ms"); + DrawText(8, "Delta time", (Time.deltaTime * 1000f).ToString(), "ms"); + + DrawIcons(); + } + } + } + + private void DrawText(int offset, string title, string content, string unit) + { + GUI.Label(new Rect(Offset.x + 10, Offset.y + 10 + (15 * offset), 200, 50), $"{title}: "); + GUI.Label(new Rect(Offset.x + 130, Offset.y + 10 + (15 * offset), 200, 50), $"{content} {unit}"); + } + + public void DrawIcons() + { + var pktLossIconPos = PacketLossIconOffset + (Screen.width * Vector2.right); + var latencyIconPos = LatencyIconOffset + (Screen.width * Vector2.right); + var serverLagIconPos = ServerLagIconOffset + (Screen.width * Vector2.right); + + var pktLoss = Mathf.Max(Sandbox.InPacketLoss, Sandbox.OutPacketLoss) * 100; // multiplying by 100 to convert from a decimal to a percentage. + var rtt = Sandbox.RTT * 1000f; // multiplying by 1000 to convert from seconds to milliseconds. + + if (pktLoss >= MediumPacketLossThreshold) + { + Color color = pktLoss < HighPacketLossThreshold ? Color.yellow : Color.red; + GUI.DrawTexture(new Rect(pktLossIconPos, Vector2.one * IconSize), _packetLossIcon, ScaleMode.ScaleToFit, true, 1f, color, 0f, 0f); + } + + if (rtt >= MediumLatencyThreshold) + { + Color color = rtt >= HighLatencyThreshold ? Color.red : Color.yellow; + GUI.DrawTexture(new Rect(latencyIconPos, Vector2.one * IconSize), _latencyIcon, ScaleMode.ScaleToFit, true, 1f, color, 0f, 0f); + } + + if (Sandbox.Monitor.ServerTickTime.Max >= Sandbox.FixedDeltaTime) + { + Color color = Sandbox.Monitor.ServerTickTime.Average >= Sandbox.FixedDeltaTime ? Color.red : Color.yellow; + GUI.DrawTexture(new Rect(serverLagIconPos, Vector2.one * IconSize), _serverLagIcon, ScaleMode.ScaleToFit, true, 1f, color, 0f, 0f); + } + + } + } } diff --git a/Scripts/PlayerSpawner.cs b/Scripts/PlayerSpawner.cs index d868f6d..e20f2a5 100644 --- a/Scripts/PlayerSpawner.cs +++ b/Scripts/PlayerSpawner.cs @@ -5,37 +5,37 @@ using Network = Netick.Unity.Network; namespace Netick.Samples { - /// - /// This is a helper script for quick prototyping, used to spawn/despawn a player prefab when a player (client or host) has connected/disconnected. - /// - [AddComponentMenu("Netick/Player Spawner")] - public class PlayerSpawner : NetworkEventsListener + /// + /// This is a helper script for quick prototyping, used to spawn/despawn a player prefab when a player (client or host) has connected/disconnected. + /// + [AddComponentMenu("Netick/Player Spawner")] + public class PlayerSpawner : NetworkEventsListener + { + public GameObject PlayerPrefab; + public Transform SpawnPosition; + public float HorizontalOffset = 5f; + public bool StaggerSpawns = true; + public bool DestroyPlayerObjectWhenLeaving = true; + + // This is called on the server when a player has connected. + public override void OnPlayerConnected(NetworkSandbox sandbox, Netick.NetworkPlayer client) { - public GameObject PlayerPrefab; - public Transform SpawnPosition; - public float HorizontalOffset = 5f; - public bool StaggerSpawns = true; - public bool DestroyPlayerObjectWhenLeaving = true; - - // This is called on the server when a player has connected. - public override void OnPlayerConnected(NetworkSandbox sandbox, Netick.NetworkPlayer client) - { - var spawnPos = SpawnPosition.position; - if (StaggerSpawns) - spawnPos += (HorizontalOffset * Vector3.left) * (sandbox.ConnectedPlayers.Count - 1); - var player = sandbox.NetworkInstantiate(PlayerPrefab, spawnPos, SpawnPosition.rotation, client); - client.PlayerObject = player; - } - - // This is called on the server when a player has disconnected. - public override void OnPlayerDisconnected(NetworkSandbox sandbox, Netick.NetworkPlayer client, TransportDisconnectReason transportDisconnectReason) - { - if (!DestroyPlayerObjectWhenLeaving) - return; - - var netObj = client.PlayerObject as NetworkObject; - if (netObj != null) - Sandbox.Destroy(netObj); - } + var spawnPos = SpawnPosition.position; + if (StaggerSpawns) + spawnPos += (HorizontalOffset * Vector3.left) * (sandbox.ConnectedPlayers.Count - 1); + var player = sandbox.NetworkInstantiate(PlayerPrefab, spawnPos, SpawnPosition.rotation, client); + client.PlayerObject = player; } + + // This is called on the server when a player has disconnected. + public override void OnPlayerDisconnected(NetworkSandbox sandbox, Netick.NetworkPlayer client, TransportDisconnectReason transportDisconnectReason) + { + if (!DestroyPlayerObjectWhenLeaving) + return; + + var netObj = client.PlayerObject as NetworkObject; + if (netObj != null) + Sandbox.Destroy(netObj); + } + } } diff --git a/package.json b/package.json index 03eb23b..01d8508 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "com.karrar.netick", - "version": "0.13.21", + "version": "0.13.24", "displayName": "Netick", "description": "A networking solution for Unity", "unity": "2021.3", "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", "samples": [