123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- using System;
- using System.Runtime.CompilerServices;
- using System.Security.Cryptography;
- using UnityEngine;
- using UnityEngine.Rendering;
- using UnityEngine.SceneManagement;
- namespace Mirror
- {
- // Handles network messages on client and server
- public delegate void NetworkMessageDelegate(NetworkConnection conn, NetworkReader reader, int channelId);
- // Handles requests to spawn objects on the client
- public delegate GameObject SpawnDelegate(Vector3 position, uint assetId);
- public delegate GameObject SpawnHandlerDelegate(SpawnMessage msg);
- // Handles requests to unspawn objects on the client
- public delegate void UnSpawnDelegate(GameObject spawned);
- // channels are const ints instead of an enum so people can add their own
- // channels (can't extend an enum otherwise).
- //
- // note that Mirror is slowly moving towards quake style networking which
- // will only require reliable for handshake, and unreliable for the rest.
- // so eventually we can change this to an Enum and transports shouldn't
- // add custom channels anymore.
- public static class Channels
- {
- public const int Reliable = 0; // ordered
- public const int Unreliable = 1; // unordered
- }
- public static class Utils
- {
- // detect headless / dedicated server mode
- // SystemInfo.graphicsDeviceType is never null in the editor.
- // UNITY_SERVER works in builds for all Unity versions 2019 LTS and later.
- // For Unity 2019 / 2020, there is no way to detect Server Build checkbox
- // state in Build Settings, so they never auto-start headless server / client.
- // UNITY_SERVER works in the editor in Unity 2021 LTS and later
- // because that's when Dedicated Server platform was added.
- // It is intentional for editor play mode to auto-start headless server / client
- // when Dedicated Server platform is selected in the editor so that editor
- // acts like a headless build to every extent possible for testing / debugging.
- public static bool IsHeadless() =>
- #if UNITY_SERVER
- true;
- #else
- SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null;
- #endif
- // detect WebGL mode
- public const bool IsWebGL =
- #if UNITY_WEBGL
- true;
- #else
- false;
- #endif
- // detect Debug mode
- public const bool IsDebug =
- #if DEBUG
- true;
- #else
- false;
- #endif
- public static uint GetTrueRandomUInt()
- {
- // use Crypto RNG to avoid having time based duplicates
- using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
- {
- byte[] bytes = new byte[4];
- rng.GetBytes(bytes);
- return BitConverter.ToUInt32(bytes, 0);
- }
- }
- public static bool IsPrefab(GameObject obj)
- {
- #if UNITY_EDITOR
- return UnityEditor.PrefabUtility.IsPartOfPrefabAsset(obj);
- #else
- return false;
- #endif
- }
- // simplified IsSceneObject check from Mirror II
- public static bool IsSceneObject(NetworkIdentity identity)
- {
- // original UNET / Mirror still had the IsPersistent check.
- // it never fires though. even for Prefabs dragged to the Scene.
- // (see Scene Objects example scene.)
- // #if UNITY_EDITOR
- // if (UnityEditor.EditorUtility.IsPersistent(identity.gameObject))
- // return false;
- // #endif
- return identity.gameObject.hideFlags != HideFlags.NotEditable &&
- identity.gameObject.hideFlags != HideFlags.HideAndDontSave &&
- identity.sceneId != 0;
- }
- public static bool IsSceneObjectWithPrefabParent(GameObject gameObject, out GameObject prefab)
- {
- prefab = null;
- #if UNITY_EDITOR
- if (!UnityEditor.PrefabUtility.IsPartOfPrefabInstance(gameObject))
- {
- return false;
- }
- prefab = UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(gameObject);
- #endif
- if (prefab == null)
- {
- Debug.LogError($"Failed to find prefab parent for scene object [name:{gameObject.name}]");
- return false;
- }
- return true;
- }
- // is a 2D point in screen? (from ummorpg)
- // (if width = 1024, then indices from 0..1023 are valid (=1024 indices)
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsPointInScreen(Vector2 point) =>
- 0 <= point.x && point.x < Screen.width &&
- 0 <= point.y && point.y < Screen.height;
- // pretty print bytes as KB/MB/GB/etc. from DOTSNET
- // long to support > 2GB
- // divides by floats to return "2.5MB" etc.
- public static string PrettyBytes(long bytes)
- {
- // bytes
- if (bytes < 1024)
- return $"{bytes} B";
- // kilobytes
- else if (bytes < 1024L * 1024L)
- return $"{(bytes / 1024f):F2} KB";
- // megabytes
- else if (bytes < 1024 * 1024L * 1024L)
- return $"{(bytes / (1024f * 1024f)):F2} MB";
- // gigabytes
- return $"{(bytes / (1024f * 1024f * 1024f)):F2} GB";
- }
- // pretty print seconds as hours:minutes:seconds(.milliseconds/100)s.
- // double for long running servers.
- public static string PrettySeconds(double seconds)
- {
- TimeSpan t = TimeSpan.FromSeconds(seconds);
- string res = "";
- if (t.Days > 0) res += $"{t.Days}d";
- if (t.Hours > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Hours}h";
- if (t.Minutes > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Minutes}m";
- // 0.5s, 1.5s etc. if any milliseconds. 1s, 2s etc. if any seconds
- if (t.Milliseconds > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Seconds}.{(t.Milliseconds / 100)}s";
- else if (t.Seconds > 0) res += $"{(res.Length > 0 ? " " : "")}{t.Seconds}s";
- // if the string is still empty because the value was '0', then at least
- // return the seconds instead of returning an empty string
- return res != "" ? res : "0s";
- }
- // universal .spawned function
- public static NetworkIdentity GetSpawnedInServerOrClient(uint netId)
- {
- // server / host mode: use the one from server.
- // host mode has access to all spawned.
- if (NetworkServer.active)
- {
- NetworkServer.spawned.TryGetValue(netId, out NetworkIdentity entry);
- return entry;
- }
- // client
- if (NetworkClient.active)
- {
- NetworkClient.spawned.TryGetValue(netId, out NetworkIdentity entry);
- return entry;
- }
- return null;
- }
- // keep a GUI window in screen.
- // for example. if it's at x=1000 and screen is resized to w=500,
- // it won't get lost in the invisible area etc.
- public static Rect KeepInScreen(Rect rect)
- {
- // ensure min
- rect.x = Math.Max(rect.x, 0);
- rect.y = Math.Max(rect.y, 0);
- // ensure max
- rect.x = Math.Min(rect.x, Screen.width - rect.width);
- rect.y = Math.Min(rect.y, Screen.width - rect.height);
- return rect;
- }
- // create local connections pair and connect them
- public static void CreateLocalConnections(
- out LocalConnectionToClient connectionToClient,
- out LocalConnectionToServer connectionToServer)
- {
- connectionToServer = new LocalConnectionToServer();
- connectionToClient = new LocalConnectionToClient();
- connectionToServer.connectionToClient = connectionToClient;
- connectionToClient.connectionToServer = connectionToServer;
- }
- public static bool IsSceneActive(string scene)
- {
- Scene activeScene = SceneManager.GetActiveScene();
- return activeScene.path == scene ||
- activeScene.name == scene;
- }
- }
- }
|