123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- namespace Mirror
- {
- public enum ConnectState
- {
- None,
-
- Connecting,
- Connected,
-
- Disconnecting,
- Disconnected
- }
-
- public static class NetworkClient
- {
-
- internal static readonly Dictionary<ushort, NetworkMessageDelegate> handlers =
- new Dictionary<ushort, NetworkMessageDelegate>();
-
- public static NetworkConnection connection { get; internal set; }
-
-
-
-
-
-
- public static bool ready;
-
-
-
- [Obsolete("NetworkClient.readyConnection is redundant. Use NetworkClient.connection and use NetworkClient.ready to check if it's ready.")]
- public static NetworkConnection readyConnection => ready ? connection : null;
-
- public static NetworkIdentity localPlayer { get; internal set; }
-
- internal static ConnectState connectState = ConnectState.None;
-
-
- public static string serverIp => connection.address;
-
-
- public static bool active => connectState == ConnectState.Connecting ||
- connectState == ConnectState.Connected;
-
- public static bool isConnecting => connectState == ConnectState.Connecting;
-
- public static bool isConnected => connectState == ConnectState.Connected;
-
- public static bool isHostClient => connection is LocalConnectionToServer;
-
- [Obsolete("isLocalClient was renamed to isHostClient because that's what it actually means.")]
- public static bool isLocalClient => isHostClient;
-
-
-
-
-
- public static Action OnConnectedEvent;
- public static Action OnDisconnectedEvent;
- public static Action<Exception> OnErrorEvent;
-
- public static readonly Dictionary<Guid, GameObject> prefabs =
- new Dictionary<Guid, GameObject>();
-
- internal static readonly Dictionary<Guid, SpawnHandlerDelegate> spawnHandlers =
- new Dictionary<Guid, SpawnHandlerDelegate>();
- internal static readonly Dictionary<Guid, UnSpawnDelegate> unspawnHandlers =
- new Dictionary<Guid, UnSpawnDelegate>();
-
- static bool isSpawnFinished;
-
- internal static readonly Dictionary<ulong, NetworkIdentity> spawnableObjects =
- new Dictionary<ulong, NetworkIdentity>();
- static Unbatcher unbatcher = new Unbatcher();
-
-
- public static InterestManagement aoi;
-
- public static bool isLoadingScene;
-
- static void AddTransportHandlers()
- {
- Transport.activeTransport.OnClientConnected = OnTransportConnected;
- Transport.activeTransport.OnClientDataReceived = OnTransportData;
- Transport.activeTransport.OnClientDisconnected = OnTransportDisconnected;
- Transport.activeTransport.OnClientError = OnError;
- }
- internal static void RegisterSystemHandlers(bool hostMode)
- {
-
-
-
- if (hostMode)
- {
- RegisterHandler<ObjectDestroyMessage>(OnHostClientObjectDestroy);
- RegisterHandler<ObjectHideMessage>(OnHostClientObjectHide);
- RegisterHandler<NetworkPongMessage>(msg => {}, false);
- RegisterHandler<SpawnMessage>(OnHostClientSpawn);
-
- RegisterHandler<ObjectSpawnStartedMessage>(msg => {});
-
- RegisterHandler<ObjectSpawnFinishedMessage>(msg => {});
-
- RegisterHandler<EntityStateMessage>(msg => {});
- }
- else
- {
- RegisterHandler<ObjectDestroyMessage>(OnObjectDestroy);
- RegisterHandler<ObjectHideMessage>(OnObjectHide);
- RegisterHandler<NetworkPongMessage>(NetworkTime.OnClientPong, false);
- RegisterHandler<SpawnMessage>(OnSpawn);
- RegisterHandler<ObjectSpawnStartedMessage>(OnObjectSpawnStarted);
- RegisterHandler<ObjectSpawnFinishedMessage>(OnObjectSpawnFinished);
- RegisterHandler<EntityStateMessage>(OnEntityStateMessage);
- }
- RegisterHandler<RpcMessage>(OnRPCMessage);
- }
-
-
- public static void Connect(string address)
- {
-
- Debug.Assert(Transport.activeTransport != null, "There was no active transport when calling NetworkClient.Connect, If you are calling Connect manually then make sure to set 'Transport.activeTransport' first");
- RegisterSystemHandlers(false);
- Transport.activeTransport.enabled = true;
- AddTransportHandlers();
- connectState = ConnectState.Connecting;
- Transport.activeTransport.ClientConnect(address);
- connection = new NetworkConnectionToServer();
- }
-
- public static void Connect(Uri uri)
- {
-
- Debug.Assert(Transport.activeTransport != null, "There was no active transport when calling NetworkClient.Connect, If you are calling Connect manually then make sure to set 'Transport.activeTransport' first");
- RegisterSystemHandlers(false);
- Transport.activeTransport.enabled = true;
- AddTransportHandlers();
- connectState = ConnectState.Connecting;
- Transport.activeTransport.ClientConnect(uri);
- connection = new NetworkConnectionToServer();
- }
-
-
- public static void ConnectHost()
- {
-
- RegisterSystemHandlers(true);
- connectState = ConnectState.Connected;
-
- LocalConnectionToServer connectionToServer = new LocalConnectionToServer();
- LocalConnectionToClient connectionToClient = new LocalConnectionToClient();
- connectionToServer.connectionToClient = connectionToClient;
- connectionToClient.connectionToServer = connectionToServer;
- connection = connectionToServer;
-
- NetworkServer.SetLocalConnection(connectionToClient);
- }
-
-
-
- public static void ConnectLocalServer()
- {
-
- NetworkServer.OnConnected(NetworkServer.localConnection);
-
-
-
-
-
-
-
-
- ((LocalConnectionToServer)connection).QueueConnectedEvent();
- }
-
-
- public static void Disconnect()
- {
-
-
-
- if (connectState != ConnectState.Connecting &&
- connectState != ConnectState.Connected)
- return;
-
-
-
-
-
- connectState = ConnectState.Disconnecting;
- ready = false;
-
- connection?.Disconnect();
-
-
-
- }
-
-
-
- [Obsolete("Call NetworkClient.Disconnect() instead. Nobody should use DisconnectLocalServer.")]
- public static void DisconnectLocalServer()
- {
-
- if (NetworkServer.localConnection != null)
- {
-
-
-
-
- NetworkServer.OnTransportDisconnected(NetworkServer.localConnection.connectionId);
- }
- }
-
-
- static void OnTransportConnected()
- {
- if (connection != null)
- {
-
- NetworkTime.Reset();
-
- unbatcher = new Unbatcher();
-
-
- connectState = ConnectState.Connected;
- NetworkTime.UpdateClient();
- OnConnectedEvent?.Invoke();
- }
- else Debug.LogError("Skipped Connect message handling because connection is null.");
- }
-
- static bool UnpackAndInvoke(NetworkReader reader, int channelId)
- {
- if (MessagePacking.Unpack(reader, out ushort msgType))
- {
-
- if (handlers.TryGetValue(msgType, out NetworkMessageDelegate handler))
- {
- handler.Invoke(connection, reader, channelId);
-
-
- if (connection != null)
- connection.lastMessageTime = Time.time;
- return true;
- }
- else
- {
-
- return false;
- }
- }
- else
- {
- Debug.LogError("Closed connection: " + connection + ". Invalid message header.");
- connection.Disconnect();
- return false;
- }
- }
-
- internal static void OnTransportData(ArraySegment<byte> data, int channelId)
- {
- if (connection != null)
- {
-
-
-
-
- if (!unbatcher.AddBatch(data))
- {
- Debug.LogWarning($"NetworkClient: failed to add batch, disconnecting.");
- connection.Disconnect();
- return;
- }
-
-
-
-
-
-
-
-
-
-
- while (!isLoadingScene &&
- unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimestamp))
- {
-
- if (reader.Remaining >= MessagePacking.HeaderSize)
- {
-
- connection.remoteTimeStamp = remoteTimestamp;
-
- if (!UnpackAndInvoke(reader, channelId))
- break;
- }
-
- else
- {
- Debug.LogError($"NetworkClient: received Message was too short (messages should start with message id)");
- connection.Disconnect();
- return;
- }
- }
- }
- else Debug.LogError("Skipped Data message handling because connection is null.");
- }
-
-
-
-
-
-
- internal static void OnTransportDisconnected()
- {
-
-
-
- if (connectState == ConnectState.Disconnected) return;
-
-
- if (connection != null) OnDisconnectedEvent?.Invoke();
- connectState = ConnectState.Disconnected;
- ready = false;
-
-
-
- connection = null;
- }
- static void OnError(Exception exception)
- {
- Debug.LogException(exception);
- OnErrorEvent?.Invoke(exception);
- }
-
-
- public static void Send<T>(T message, int channelId = Channels.Reliable)
- where T : struct, NetworkMessage
- {
- if (connection != null)
- {
- if (connectState == ConnectState.Connected)
- {
- connection.Send(message, channelId);
- }
- else Debug.LogError("NetworkClient Send when not connected to a server");
- }
- else Debug.LogError("NetworkClient Send with no connection");
- }
-
-
-
- [Obsolete("Use RegisterHandler<T> version without NetworkConnection parameter. It always points to NetworkClient.connection anyway.")]
- public static void RegisterHandler<T>(Action<NetworkConnection, T> handler, bool requireAuthentication = true)
- where T : struct, NetworkMessage
- {
- ushort msgType = MessagePacking.GetId<T>();
- if (handlers.ContainsKey(msgType))
- {
- Debug.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning.");
- }
- handlers[msgType] = MessagePacking.WrapHandler(handler, requireAuthentication);
- }
-
- public static void RegisterHandler<T>(Action<T> handler, bool requireAuthentication = true)
- where T : struct, NetworkMessage
- {
- ushort msgType = MessagePacking.GetId<T>();
- if (handlers.ContainsKey(msgType))
- {
- Debug.LogWarning($"NetworkClient.RegisterHandler replacing handler for {typeof(T).FullName}, id={msgType}. If replacement is intentional, use ReplaceHandler instead to avoid this warning.");
- }
-
-
-
- void HandlerWrapped(NetworkConnection _, T value) => handler(value);
- handlers[msgType] = MessagePacking.WrapHandler((Action<NetworkConnection, T>) HandlerWrapped, requireAuthentication);
- }
-
-
- public static void ReplaceHandler<T>(Action<NetworkConnection, T> handler, bool requireAuthentication = true)
- where T : struct, NetworkMessage
- {
- ushort msgType = MessagePacking.GetId<T>();
- handlers[msgType] = MessagePacking.WrapHandler(handler, requireAuthentication);
- }
-
-
- public static void ReplaceHandler<T>(Action<T> handler, bool requireAuthentication = true)
- where T : struct, NetworkMessage
- {
- ReplaceHandler((NetworkConnection _, T value) => { handler(value); }, requireAuthentication);
- }
-
- public static bool UnregisterHandler<T>()
- where T : struct, NetworkMessage
- {
-
- ushort msgType = MessagePacking.GetId<T>();
- return handlers.Remove(msgType);
- }
-
-
-
- public static bool GetPrefab(Guid assetId, out GameObject prefab)
- {
- prefab = null;
- return assetId != Guid.Empty &&
- prefabs.TryGetValue(assetId, out prefab) && prefab != null;
- }
-
- static void RegisterPrefabIdentity(NetworkIdentity prefab)
- {
- if (prefab.assetId == Guid.Empty)
- {
- Debug.LogError($"Can not Register '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
- return;
- }
- if (prefab.sceneId != 0)
- {
- Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
- return;
- }
- NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
- if (identities.Length > 1)
- {
- Debug.LogError($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
- }
- if (prefabs.ContainsKey(prefab.assetId))
- {
- GameObject existingPrefab = prefabs[prefab.assetId];
- Debug.LogWarning($"Replacing existing prefab with assetId '{prefab.assetId}'. Old prefab '{existingPrefab.name}', New prefab '{prefab.name}'");
- }
- if (spawnHandlers.ContainsKey(prefab.assetId) || unspawnHandlers.ContainsKey(prefab.assetId))
- {
- Debug.LogWarning($"Adding prefab '{prefab.name}' with assetId '{prefab.assetId}' when spawnHandlers with same assetId already exists.");
- }
-
- prefabs[prefab.assetId] = prefab.gameObject;
- }
-
-
-
-
- public static void RegisterPrefab(GameObject prefab, Guid newAssetId)
- {
- if (prefab == null)
- {
- Debug.LogError("Could not register prefab because it was null");
- return;
- }
- if (newAssetId == Guid.Empty)
- {
- Debug.LogError($"Could not register '{prefab.name}' with new assetId because the new assetId was empty");
- return;
- }
- NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
- return;
- }
- if (identity.assetId != Guid.Empty && identity.assetId != newAssetId)
- {
- Debug.LogError($"Could not register '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}");
- return;
- }
- identity.assetId = newAssetId;
- RegisterPrefabIdentity(identity);
- }
-
- public static void RegisterPrefab(GameObject prefab)
- {
- if (prefab == null)
- {
- Debug.LogError("Could not register prefab because it was null");
- return;
- }
- NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError($"Could not register '{prefab.name}' since it contains no NetworkIdentity component");
- return;
- }
- RegisterPrefabIdentity(identity);
- }
-
-
-
-
-
- public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
- {
-
- if (spawnHandler == null)
- {
- Debug.LogError($"Can not Register null SpawnHandler for {newAssetId}");
- return;
- }
- RegisterPrefab(prefab, newAssetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
- }
-
-
- public static void RegisterPrefab(GameObject prefab, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
- {
- if (prefab == null)
- {
- Debug.LogError("Could not register handler for prefab because the prefab was null");
- return;
- }
- NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
- return;
- }
- if (identity.sceneId != 0)
- {
- Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
- return;
- }
- Guid assetId = identity.assetId;
- if (assetId == Guid.Empty)
- {
- Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
- return;
- }
-
- if (spawnHandler == null)
- {
- Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
- return;
- }
- RegisterPrefab(prefab, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
- }
-
-
-
-
-
- public static void RegisterPrefab(GameObject prefab, Guid newAssetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
- {
- if (newAssetId == Guid.Empty)
- {
- Debug.LogError($"Could not register handler for '{prefab.name}' with new assetId because the new assetId was empty");
- return;
- }
- if (prefab == null)
- {
- Debug.LogError("Could not register handler for prefab because the prefab was null");
- return;
- }
- NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
- return;
- }
- if (identity.assetId != Guid.Empty && identity.assetId != newAssetId)
- {
- Debug.LogError($"Could not register Handler for '{prefab.name}' to {newAssetId} because it already had an AssetId, Existing assetId {identity.assetId}");
- return;
- }
- if (identity.sceneId != 0)
- {
- Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
- return;
- }
- identity.assetId = newAssetId;
- Guid assetId = identity.assetId;
- if (spawnHandler == null)
- {
- Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
- return;
- }
- if (unspawnHandler == null)
- {
- Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
- return;
- }
- if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
- {
- Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'");
- }
- if (prefabs.ContainsKey(assetId))
- {
-
- Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler");
- }
- NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
- if (identities.Length > 1)
- {
- Debug.LogError($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
- }
-
- spawnHandlers[assetId] = spawnHandler;
- unspawnHandlers[assetId] = unspawnHandler;
- }
-
-
- public static void RegisterPrefab(GameObject prefab, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
- {
- if (prefab == null)
- {
- Debug.LogError("Could not register handler for prefab because the prefab was null");
- return;
- }
- NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError("Could not register handler for '" + prefab.name + "' since it contains no NetworkIdentity component");
- return;
- }
- if (identity.sceneId != 0)
- {
- Debug.LogError($"Can not Register '{prefab.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
- return;
- }
- Guid assetId = identity.assetId;
- if (assetId == Guid.Empty)
- {
- Debug.LogError($"Can not Register handler for '{prefab.name}' because it had empty assetid. If this is a scene Object use RegisterSpawnHandler instead");
- return;
- }
- if (spawnHandler == null)
- {
- Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
- return;
- }
- if (unspawnHandler == null)
- {
- Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
- return;
- }
- if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
- {
- Debug.LogWarning($"Replacing existing spawnHandlers for prefab '{prefab.name}' with assetId '{assetId}'");
- }
- if (prefabs.ContainsKey(assetId))
- {
-
- Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}', unregister the prefab first before trying to add handler");
- }
- NetworkIdentity[] identities = prefab.GetComponentsInChildren<NetworkIdentity>();
- if (identities.Length > 1)
- {
- Debug.LogError($"Prefab '{prefab.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
- }
-
- spawnHandlers[assetId] = spawnHandler;
- unspawnHandlers[assetId] = unspawnHandler;
- }
-
- public static void UnregisterPrefab(GameObject prefab)
- {
- if (prefab == null)
- {
- Debug.LogError("Could not unregister prefab because it was null");
- return;
- }
- NetworkIdentity identity = prefab.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError("Could not unregister '" + prefab.name + "' since it contains no NetworkIdentity component");
- return;
- }
- Guid assetId = identity.assetId;
- prefabs.Remove(assetId);
- spawnHandlers.Remove(assetId);
- unspawnHandlers.Remove(assetId);
- }
-
-
-
-
-
-
-
- public static void RegisterSpawnHandler(Guid assetId, SpawnDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
- {
-
- if (spawnHandler == null)
- {
- Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
- return;
- }
- RegisterSpawnHandler(assetId, msg => spawnHandler(msg.position, msg.assetId), unspawnHandler);
- }
-
-
-
-
-
-
- public static void RegisterSpawnHandler(Guid assetId, SpawnHandlerDelegate spawnHandler, UnSpawnDelegate unspawnHandler)
- {
- if (spawnHandler == null)
- {
- Debug.LogError($"Can not Register null SpawnHandler for {assetId}");
- return;
- }
- if (unspawnHandler == null)
- {
- Debug.LogError($"Can not Register null UnSpawnHandler for {assetId}");
- return;
- }
- if (assetId == Guid.Empty)
- {
- Debug.LogError("Can not Register SpawnHandler for empty Guid");
- return;
- }
- if (spawnHandlers.ContainsKey(assetId) || unspawnHandlers.ContainsKey(assetId))
- {
- Debug.LogWarning($"Replacing existing spawnHandlers for {assetId}");
- }
- if (prefabs.ContainsKey(assetId))
- {
-
- Debug.LogError($"assetId '{assetId}' is already used by prefab '{prefabs[assetId].name}'");
- }
-
- spawnHandlers[assetId] = spawnHandler;
- unspawnHandlers[assetId] = unspawnHandler;
- }
-
- public static void UnregisterSpawnHandler(Guid assetId)
- {
- spawnHandlers.Remove(assetId);
- unspawnHandlers.Remove(assetId);
- }
-
- public static void ClearSpawners()
- {
- prefabs.Clear();
- spawnHandlers.Clear();
- unspawnHandlers.Clear();
- }
- internal static bool InvokeUnSpawnHandler(Guid assetId, GameObject obj)
- {
- if (unspawnHandlers.TryGetValue(assetId, out UnSpawnDelegate handler) && handler != null)
- {
- handler(obj);
- return true;
- }
- return false;
- }
-
-
-
-
-
-
- public static bool Ready()
- {
-
- if (ready)
- {
- Debug.LogError("NetworkClient is already ready. It shouldn't be called twice.");
- return false;
- }
-
- if (connection == null)
- {
- Debug.LogError("Ready() called with invalid connection object: conn=null");
- return false;
- }
-
-
-
- ready = true;
- connection.isReady = true;
-
- connection.Send(new ReadyMessage());
- return true;
- }
-
- [Obsolete("NetworkClient.Ready doesn't need a NetworkConnection parameter anymore. It always uses NetworkClient.connection anyway.")]
- public static bool Ready(NetworkConnection conn) => Ready();
-
-
- internal static void InternalAddPlayer(NetworkIdentity identity)
- {
-
-
-
- localPlayer = identity;
-
-
-
-
-
- if (ready && connection != null)
- {
- connection.identity = identity;
- }
- else Debug.LogWarning("No ready connection found for setting player controller during InternalAddPlayer");
- }
-
- public static bool AddPlayer()
- {
-
- if (connection == null)
- {
- Debug.LogError("AddPlayer requires a valid NetworkClient.connection.");
- return false;
- }
-
-
- if (!ready)
- {
- Debug.LogError("AddPlayer requires a ready NetworkClient.");
- return false;
- }
- if (connection.identity != null)
- {
- Debug.LogError("NetworkClient.AddPlayer: a PlayerController was already added. Did you call AddPlayer twice?");
- return false;
- }
-
- connection.Send(new AddPlayerMessage());
- return true;
- }
-
- [Obsolete("NetworkClient.AddPlayer doesn't need a NetworkConnection parameter anymore. It always uses NetworkClient.connection anyway.")]
- public static bool AddPlayer(NetworkConnection readyConn) => AddPlayer();
-
- internal static void ApplySpawnPayload(NetworkIdentity identity, SpawnMessage message)
- {
- if (message.assetId != Guid.Empty)
- identity.assetId = message.assetId;
- if (!identity.gameObject.activeSelf)
- {
- identity.gameObject.SetActive(true);
- }
-
- identity.transform.localPosition = message.position;
- identity.transform.localRotation = message.rotation;
- identity.transform.localScale = message.scale;
- identity.hasAuthority = message.isOwner;
- identity.netId = message.netId;
- if (message.isLocalPlayer)
- InternalAddPlayer(identity);
-
-
- if (message.payload.Count > 0)
- {
- using (PooledNetworkReader payloadReader = NetworkReaderPool.GetReader(message.payload))
- {
- identity.OnDeserializeAllSafely(payloadReader, true);
- }
- }
- NetworkIdentity.spawned[message.netId] = identity;
-
- if (isSpawnFinished)
- {
- identity.NotifyAuthority();
- identity.OnStartClient();
- CheckForLocalPlayer(identity);
- }
- }
-
- internal static bool FindOrSpawnObject(SpawnMessage message, out NetworkIdentity identity)
- {
-
- identity = GetExistingObject(message.netId);
-
- if (identity != null)
- {
- return true;
- }
- if (message.assetId == Guid.Empty && message.sceneId == 0)
- {
- Debug.LogError($"OnSpawn message with netId '{message.netId}' has no AssetId or sceneId");
- return false;
- }
- identity = message.sceneId == 0 ? SpawnPrefab(message) : SpawnSceneObject(message);
- if (identity == null)
- {
- Debug.LogError($"Could not spawn assetId={message.assetId} scene={message.sceneId:X} netId={message.netId}");
- return false;
- }
- return true;
- }
- static NetworkIdentity GetExistingObject(uint netid)
- {
- NetworkIdentity.spawned.TryGetValue(netid, out NetworkIdentity localObject);
- return localObject;
- }
- static NetworkIdentity SpawnPrefab(SpawnMessage message)
- {
- if (GetPrefab(message.assetId, out GameObject prefab))
- {
- GameObject obj = GameObject.Instantiate(prefab, message.position, message.rotation);
-
- return obj.GetComponent<NetworkIdentity>();
- }
- if (spawnHandlers.TryGetValue(message.assetId, out SpawnHandlerDelegate handler))
- {
- GameObject obj = handler(message);
- if (obj == null)
- {
- Debug.LogError($"Spawn Handler returned null, Handler assetId '{message.assetId}'");
- return null;
- }
- NetworkIdentity identity = obj.GetComponent<NetworkIdentity>();
- if (identity == null)
- {
- Debug.LogError($"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{message.assetId}'");
- return null;
- }
- return identity;
- }
- Debug.LogError($"Failed to spawn server object, did you forget to add it to the NetworkManager? assetId={message.assetId} netId={message.netId}");
- return null;
- }
- static NetworkIdentity SpawnSceneObject(SpawnMessage message)
- {
- NetworkIdentity identity = GetAndRemoveSceneObject(message.sceneId);
- if (identity == null)
- {
- Debug.LogError($"Spawn scene object not found for {message.sceneId:X}. Make sure that client and server use exactly the same project. This only happens if the hierarchy gets out of sync.");
-
-
-
- }
-
- return identity;
- }
- static NetworkIdentity GetAndRemoveSceneObject(ulong sceneId)
- {
- if (spawnableObjects.TryGetValue(sceneId, out NetworkIdentity identity))
- {
- spawnableObjects.Remove(sceneId);
- return identity;
- }
- return null;
- }
-
- static bool ConsiderForSpawning(NetworkIdentity identity)
- {
-
- return !identity.gameObject.activeSelf &&
- identity.gameObject.hideFlags != HideFlags.NotEditable &&
- identity.gameObject.hideFlags != HideFlags.HideAndDontSave &&
- identity.sceneId != 0;
- }
-
- public static void PrepareToSpawnSceneObjects()
- {
-
- spawnableObjects.Clear();
-
- NetworkIdentity[] allIdentities = Resources.FindObjectsOfTypeAll<NetworkIdentity>();
- foreach (NetworkIdentity identity in allIdentities)
- {
-
- if (ConsiderForSpawning(identity))
- {
- spawnableObjects.Add(identity.sceneId, identity);
- }
- }
- }
- internal static void OnObjectSpawnStarted(ObjectSpawnStartedMessage _)
- {
-
- PrepareToSpawnSceneObjects();
- isSpawnFinished = false;
- }
- internal static void OnObjectSpawnFinished(ObjectSpawnFinishedMessage _)
- {
-
- ClearNullFromSpawned();
-
-
-
- foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values.OrderBy(uv => uv.netId))
- {
- identity.NotifyAuthority();
- identity.OnStartClient();
- CheckForLocalPlayer(identity);
- }
- isSpawnFinished = true;
- }
- static readonly List<uint> removeFromSpawned = new List<uint>();
- static void ClearNullFromSpawned()
- {
-
-
-
-
-
- foreach (KeyValuePair<uint, NetworkIdentity> kvp in NetworkIdentity.spawned)
- {
- if (kvp.Value == null)
- {
- removeFromSpawned.Add(kvp.Key);
- }
- }
-
- foreach (uint id in removeFromSpawned)
- {
- NetworkIdentity.spawned.Remove(id);
- }
- removeFromSpawned.Clear();
- }
-
- static void OnHostClientObjectDestroy(ObjectDestroyMessage message)
- {
-
-
-
-
-
- NetworkIdentity.spawned.Remove(message.netId);
- }
- static void OnHostClientObjectHide(ObjectHideMessage message)
- {
-
- if (NetworkIdentity.spawned.TryGetValue(message.netId, out NetworkIdentity localObject) &&
- localObject != null)
- {
-
- #pragma warning disable 618
- if (localObject.visibility != null)
- localObject.visibility.OnSetHostVisibility(false);
- #pragma warning restore 618
- else if (aoi != null)
- aoi.SetHostVisibility(localObject, false);
- }
- }
- internal static void OnHostClientSpawn(SpawnMessage message)
- {
- if (NetworkIdentity.spawned.TryGetValue(message.netId, out NetworkIdentity localObject) && localObject != null)
- {
- if (message.isLocalPlayer)
- InternalAddPlayer(localObject);
- localObject.hasAuthority = message.isOwner;
- localObject.NotifyAuthority();
- localObject.OnStartClient();
-
- #pragma warning disable 618
- if (localObject.visibility != null)
- localObject.visibility.OnSetHostVisibility(true);
- #pragma warning restore 618
- else if (aoi != null)
- aoi.SetHostVisibility(localObject, true);
- CheckForLocalPlayer(localObject);
- }
- }
-
- static void OnEntityStateMessage(EntityStateMessage message)
- {
-
- if (NetworkIdentity.spawned.TryGetValue(message.netId, out NetworkIdentity localObject) && localObject != null)
- {
- using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(message.payload))
- localObject.OnDeserializeAllSafely(networkReader, false);
- }
- else Debug.LogWarning("Did not find target for sync message for " + message.netId + " . Note: this can be completely normal because UDP messages may arrive out of order, so this message might have arrived after a Destroy message.");
- }
- static void OnRPCMessage(RpcMessage message)
- {
-
- if (NetworkIdentity.spawned.TryGetValue(message.netId, out NetworkIdentity identity))
- {
- using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(message.payload))
- identity.HandleRemoteCall(message.componentIndex, message.functionHash, MirrorInvokeType.ClientRpc, networkReader);
- }
- }
- static void OnObjectHide(ObjectHideMessage message) => DestroyObject(message.netId);
- internal static void OnObjectDestroy(ObjectDestroyMessage message) => DestroyObject(message.netId);
- internal static void OnSpawn(SpawnMessage message)
- {
-
- if (FindOrSpawnObject(message, out NetworkIdentity identity))
- {
- ApplySpawnPayload(identity, message);
- }
- }
- internal static void CheckForLocalPlayer(NetworkIdentity identity)
- {
- if (identity == localPlayer)
- {
-
-
- identity.connectionToServer = connection;
- identity.OnStartLocalPlayer();
-
- }
- }
-
- static void DestroyObject(uint netId)
- {
-
- if (NetworkIdentity.spawned.TryGetValue(netId, out NetworkIdentity localObject) && localObject != null)
- {
- localObject.OnStopClient();
-
- if (InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject))
- {
-
- localObject.Reset();
- }
-
- else if (localObject.sceneId == 0)
- {
-
- GameObject.Destroy(localObject.gameObject);
- }
-
- else
- {
- localObject.gameObject.SetActive(false);
- spawnableObjects[localObject.sceneId] = localObject;
-
- localObject.Reset();
- }
-
- NetworkIdentity.spawned.Remove(netId);
- }
-
- }
-
-
-
- internal static void NetworkEarlyUpdate()
- {
-
- if (Transport.activeTransport != null)
- Transport.activeTransport.ClientEarlyUpdate();
- }
-
-
- internal static void NetworkLateUpdate()
- {
-
- if (connection is LocalConnectionToServer localConnection)
- {
- localConnection.Update();
- }
-
- else if (connection is NetworkConnectionToServer remoteConnection)
- {
-
- if (active && connectState == ConnectState.Connected)
- {
-
- NetworkTime.UpdateClient();
-
- remoteConnection.Update();
- }
- }
-
- if (Transport.activeTransport != null)
- Transport.activeTransport.ClientLateUpdate();
- }
-
-
- [Obsolete("NetworkClient.Update is now called internally from our custom update loop. No need to call Update manually anymore.")]
- public static void Update() => NetworkLateUpdate();
-
-
-
- public static void DestroyAllClientObjects()
- {
-
-
-
- try
- {
- foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values)
- {
- if (identity != null && identity.gameObject != null)
- {
- identity.OnStopClient();
- bool wasUnspawned = InvokeUnSpawnHandler(identity.assetId, identity.gameObject);
- if (!wasUnspawned)
- {
-
-
- if (identity.sceneId != 0)
- {
- identity.Reset();
- identity.gameObject.SetActive(false);
- }
-
- else
- {
- GameObject.Destroy(identity.gameObject);
- }
- }
- }
- }
- NetworkIdentity.spawned.Clear();
- }
- catch (InvalidOperationException e)
- {
- Debug.LogException(e);
- Debug.LogError("Could not DestroyAllClientObjects because spawned list was modified during loop, make sure you are not modifying NetworkIdentity.spawned by calling NetworkServer.Destroy or NetworkServer.Spawn in OnDestroy or OnDisable.");
- }
- }
-
- public static void Shutdown()
- {
-
- ClearSpawners();
- spawnableObjects.Clear();
- ready = false;
- isSpawnFinished = false;
- DestroyAllClientObjects();
- connectState = ConnectState.None;
- handlers.Clear();
-
-
-
-
- if (Transport.activeTransport != null)
- Transport.activeTransport.ClientDisconnect();
- connection = null;
-
-
- OnConnectedEvent = null;
- OnDisconnectedEvent = null;
- }
- }
- }
|