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

@@ -5,141 +5,141 @@ using Network = Netick.Unity.Network;
namespace Netick.Samples
{
/// <summary>
/// This is a helper script for quick prototyping, used to start Netick.
/// </summary>
[AddComponentMenu("Netick/Game Starter")]
public class GameStarter : NetworkEventsListener
/// <summary>
/// This is a helper script for quick prototyping, used to start Netick.
/// </summary>
[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);
}
}
}

View File

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

View File

@@ -5,91 +5,91 @@ using Network = Netick.Unity.Network;
namespace Netick.Samples
{
/// <summary>
/// This is a helper script for quick prototyping, used to show useful network information of Netick.
/// </summary>
[AddComponentMenu("Netick/Network Info")]
public class NetworkInfo : NetworkEventsListener
/// <summary>
/// This is a helper script for quick prototyping, used to show useful network information of Netick.
/// </summary>
[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;
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 void Awake()
{
[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;
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 void Awake()
{
_packetLossIcon = Resources.Load<Texture>("Network Icons/PacketLoss");
_latencyIcon = Resources.Load<Texture>("Network Icons/Latency");
_serverLagIcon = Resources.Load<Texture>("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);
}
}
_packetLossIcon = Resources.Load<Texture>("Network Icons/PacketLoss");
_latencyIcon = Resources.Load<Texture>("Network Icons/Latency");
_serverLagIcon = Resources.Load<Texture>("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);
}
}
}
}

View File

@@ -5,37 +5,37 @@ using Network = Netick.Unity.Network;
namespace Netick.Samples
{
/// <summary>
/// This is a helper script for quick prototyping, used to spawn/despawn a player prefab when a player (client or host) has connected/disconnected.
/// </summary>
[AddComponentMenu("Netick/Player Spawner")]
public class PlayerSpawner : NetworkEventsListener
/// <summary>
/// This is a helper script for quick prototyping, used to spawn/despawn a player prefab when a player (client or host) has connected/disconnected.
/// </summary>
[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);
}
}
}

View File

@@ -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": [