private void MessageHandler_Server_SendPlayerEjectionCommand(ulong senderClientId, Stream dataStream) { using (PooledNetworkReader reader = PooledNetworkReader.Get(dataStream)) { string userId = reader.ReadStringPacked().ToString(); MLAPIExtension.NetworkClientUser networkClientUser = new MLAPIExtension.NetworkClientUser(); networkClientUser.ClientId = 0; networkClientUser.UserId = userId; _OnReceivedSystemUserIdSubject.OnNext(networkClientUser); } }
/// <inheritdoc /> public void ReadField(Stream stream, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { m_Set.Clear(); ushort count = reader.ReadUInt16Packed(); for (int i = 0; i < count; i++) { m_Set.Add((T)reader.ReadObjectPacked(typeof(T))); //BOX } } }
internal static void HandleTimeSync(ulong clientId, Stream stream, float receiveTime) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleTimeSync.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { float netTime = reader.ReadSinglePacked(); NetworkManager.Singleton.UpdateNetworkTime(clientId, netTime, receiveTime); } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleTimeSync.End(); #endif }
/// <inheritdoc /> public void ReadField(Stream stream, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { m_Dictionary.Clear(); ushort entryCount = reader.ReadUInt16Packed(); for (int i = 0; i < entryCount; i++) { var key = (TKey)reader.ReadObjectPacked(typeof(TKey)); var value = (TValue)reader.ReadObjectPacked(typeof(TValue)); m_Dictionary.Add(key, value); } } }
internal static void HandleDestroyObject(ulong clientId, Stream stream) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleDestroyObject.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { ulong networkId = reader.ReadUInt64Packed(); NetworkSpawnManager.OnDestroyObject(networkId, true); } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleDestroyObject.End(); #endif }
public void HandleAllClientsSwitchSceneCompleted(ulong clientId, Stream stream) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleAllClientsSwitchSceneCompleted.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { var clientIds = reader.ReadULongArray(); var timedOutClientIds = reader.ReadULongArray(); NetworkManager.SceneManager.AllClientsReady(clientIds, timedOutClientIds); } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleAllClientsSwitchSceneCompleted.End(); #endif }
/// <summary> /// Creates a ProfilerTick from data in the provided stream /// </summary> /// <param name="stream">The stream containing the ProfilerTick data</param> /// <returns>The ProfilerTick with data read from the stream</returns> public static ProfilerTick FromStream(Stream stream) { var tick = new ProfilerTick(); using (var reader = PooledNetworkReader.Get(stream)) { ushort count = reader.ReadUInt16Packed(); for (int i = 0; i < count; i++) { tick.Events.Add(TickEvent.FromStream(stream)); } return(tick); } }
/// <summary> /// Creates a TickEvent from data in the provided stream /// </summary> /// <param name="stream">The stream containing the TickEvent data</param> /// <returns>The TickEvent with data read from the stream</returns> public static TickEvent FromStream(Stream stream) { using (var reader = PooledNetworkReader.Get(stream)) { var tickEvent = new TickEvent { EventType = (TickType)reader.ReadByte(), Bytes = reader.ReadUInt32Packed(), ChannelName = reader.ReadStringPacked(), MessageType = reader.ReadStringPacked(), Closed = reader.ReadBool() }; return(tickEvent); } }
internal static void HandleNamedMessage(ulong clientId, Stream stream) { PerformanceDataManager.Increment(ProfilerConstants.NumberOfNamedMessages); ProfilerStatManager.NamedMessage.Record(); #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleNamedMessage.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { ulong hash = reader.ReadUInt64Packed(); CustomMessagingManager.InvokeNamedMessage(hash, clientId, stream); } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleNamedMessage.End(); #endif }
internal static void HandleDestroyObjects(ulong clientId, Stream stream) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleDestroyObjects.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { ushort objectCount = reader.ReadUInt16Packed(); for (int i = 0; i < objectCount; i++) { HandleDestroyObject(clientId, stream); } } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleDestroyObjects.End(); #endif }
internal static void HandleSwitchScene(ulong clientId, Stream stream) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleSwitchScene.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { uint sceneIndex = reader.ReadUInt32Packed(); Guid switchSceneGuid = new Guid(reader.ReadByteArray()); var objectBuffer = new NetworkBuffer(); objectBuffer.CopyUnreadFrom(stream); objectBuffer.Position = 0; NetworkSceneManager.OnSceneSwitch(sceneIndex, switchSceneGuid, objectBuffer); } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleSwitchScene.End(); #endif }
public void HandleConnectionRequest(ulong clientId, Stream stream) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleConnectionRequest.Begin(); #endif if (NetworkManager.PendingClients.TryGetValue(clientId, out PendingClient client)) { // Set to pending approval to prevent future connection requests from being approved client.ConnectionState = PendingClient.State.PendingApproval; } using (var reader = PooledNetworkReader.Get(stream)) { ulong configHash = reader.ReadUInt64Packed(); if (!NetworkManager.NetworkConfig.CompareConfig(configHash)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"{nameof(NetworkConfig)} mismatch. The configuration between the server and client does not match"); } NetworkManager.DisconnectClient(clientId); return; } if (NetworkManager.NetworkConfig.ConnectionApproval) { byte[] connectionBuffer = reader.ReadByteArray(); NetworkManager.InvokeConnectionApproval(connectionBuffer, clientId, (createPlayerObject, playerPrefabHash, approved, position, rotation) => NetworkManager.HandleApproval(clientId, createPlayerObject, playerPrefabHash, approved, position, rotation)); } else { NetworkManager.HandleApproval(clientId, NetworkManager.NetworkConfig.PlayerPrefab != null, null, true, null, null); } } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleConnectionRequest.End(); #endif }
// This method is responsible for unwrapping a message, that is extracting the messagebody. internal static NetworkBuffer UnwrapMessage(NetworkBuffer inputBuffer, out byte messageType) { using (var inputHeaderReader = PooledNetworkReader.Get(inputBuffer)) { if (inputBuffer.Length < 1) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogError("The incoming message was too small"); } messageType = NetworkConstants.INVALID; return(null); } messageType = inputHeaderReader.ReadByteDirect(); // The input stream is now ready to be read from. It's "safe" and has the correct position return(inputBuffer); } }
/// <summary> /// Sets the NetworkConfig data with that from a base64 encoded version /// </summary> /// <param name="base64">The base64 encoded version</param> public void FromBase64(string base64) { NetworkConfig config = this; byte[] binary = Convert.FromBase64String(base64); using (var buffer = new NetworkBuffer(binary)) using (var reader = PooledNetworkReader.Get(buffer)) { config.ProtocolVersion = reader.ReadUInt16Packed(); ushort sceneCount = reader.ReadUInt16Packed(); config.RegisteredScenes.Clear(); for (int i = 0; i < sceneCount; i++) { config.RegisteredScenes.Add(reader.ReadString().ToString()); } config.ReceiveTickrate = reader.ReadInt32Packed(); config.MaxReceiveEventsPerTickRate = reader.ReadInt32Packed(); config.EventTickrate = reader.ReadInt32Packed(); config.ClientConnectionBufferTimeout = reader.ReadInt32Packed(); config.ConnectionApproval = reader.ReadBool(); config.SecondsHistory = reader.ReadInt32Packed(); config.LoadSceneTimeOut = reader.ReadInt32Packed(); config.EnableTimeResync = reader.ReadBool(); config.EnsureNetworkVariableLengthSafety = reader.ReadBool(); config.RpcHashSize = (HashSize)reader.ReadBits(2); config.ForceSamePrefabs = reader.ReadBool(); config.UsePrefabSync = reader.ReadBool(); config.EnableSceneManagement = reader.ReadBool(); config.RecycleNetworkIds = reader.ReadBool(); config.NetworkIdRecycleDelay = reader.ReadSinglePacked(); config.EnableNetworkVariable = reader.ReadBool(); config.AllowRuntimeSceneChanges = reader.ReadBool(); config.EnableNetworkLogs = reader.ReadBool(); } }
/// <summary> /// AddQueueItemToInboundFrame /// Adds an RPC queue item to the outbound frame /// </summary> /// <param name="qItemType">type of rpc (client or server)</param> /// <param name="timeStamp">when it was received</param> /// <param name="sourceNetworkId">who sent the rpc</param> /// <param name="message">the message being received</param> internal void AddQueueItemToInboundFrame(QueueItemType qItemType, float timeStamp, ulong sourceNetworkId, NetworkBuffer message) { long originalPosition = message.Position; NetworkUpdateStage updateStage; using (var reader = PooledNetworkReader.Get(message)) { var longValue = reader.ReadUInt64Packed(); // NetworkObjectId (temporary, we reset position just below) var shortValue = reader.ReadUInt16Packed(); // NetworkBehaviourId (temporary, we reset position just below) updateStage = (NetworkUpdateStage)reader.ReadByteDirect(); } message.Position = originalPosition; var rpcQueueHistoryItem = GetQueueHistoryFrame(RpcQueueHistoryFrame.QueueFrameType.Inbound, updateStage); rpcQueueHistoryItem.IsDirty = true; long StartPosition = rpcQueueHistoryItem.QueueBuffer.Position; //Write the packed version of the queueItem to our current queue history buffer rpcQueueHistoryItem.QueueWriter.WriteUInt16((ushort)qItemType); rpcQueueHistoryItem.QueueWriter.WriteSingle(timeStamp); rpcQueueHistoryItem.QueueWriter.WriteUInt64(sourceNetworkId); //Inbound we copy the entire packet and store the position offset long streamSize = message.Length; rpcQueueHistoryItem.QueueWriter.WriteInt64(streamSize); rpcQueueHistoryItem.QueueWriter.WriteInt64(message.Position); rpcQueueHistoryItem.QueueWriter.WriteBytes(message.GetBuffer(), streamSize); //Add the packed size to the offsets for parsing over various entries rpcQueueHistoryItem.QueueItemOffsets.Add((uint)rpcQueueHistoryItem.QueueBuffer.Position); //Calculate the packed size based on stream progression rpcQueueHistoryItem.TotalSize += (uint)(rpcQueueHistoryItem.QueueBuffer.Position - StartPosition); }
public void HandleConnectionApproved(ulong clientId, Stream stream, float receiveTime) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleConnectionApproved.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { NetworkManager.LocalClientId = reader.ReadUInt64Packed(); uint sceneIndex = 0; var sceneSwitchProgressGuid = new Guid(); if (NetworkManager.NetworkConfig.EnableSceneManagement) { sceneIndex = reader.ReadUInt32Packed(); sceneSwitchProgressGuid = new Guid(reader.ReadByteArray()); } bool sceneSwitch = NetworkManager.NetworkConfig.EnableSceneManagement && NetworkManager.SceneManager.HasSceneMismatch(sceneIndex); float netTime = reader.ReadSinglePacked(); NetworkManager.UpdateNetworkTime(clientId, netTime, receiveTime, true); NetworkManager.ConnectedClients.Add(NetworkManager.LocalClientId, new NetworkClient { ClientId = NetworkManager.LocalClientId }); void DelayedSpawnAction(Stream continuationStream) { using (var continuationReader = PooledNetworkReader.Get(continuationStream)) { if (!NetworkManager.NetworkConfig.EnableSceneManagement) { NetworkManager.SpawnManager.DestroySceneObjects(); } else { NetworkManager.SpawnManager.ClientCollectSoftSyncSceneObjectSweep(null); } var objectCount = continuationReader.ReadUInt32Packed(); for (int i = 0; i < objectCount; i++) { NetworkObject.DeserializeSceneObject(continuationStream as NetworkBuffer, continuationReader, m_NetworkManager); } NetworkManager.SpawnManager.CleanDiffedSceneObjects(); NetworkManager.IsConnectedClient = true; NetworkManager.InvokeOnClientConnectedCallback(NetworkManager.LocalClientId); } } if (sceneSwitch) { UnityAction <Scene, Scene> onSceneLoaded = null; var continuationBuffer = new NetworkBuffer(); continuationBuffer.CopyUnreadFrom(stream); continuationBuffer.Position = 0; void OnSceneLoadComplete() { SceneManager.activeSceneChanged -= onSceneLoaded; NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad = false; DelayedSpawnAction(continuationBuffer); } onSceneLoaded = (oldScene, newScene) => { OnSceneLoadComplete(); }; SceneManager.activeSceneChanged += onSceneLoaded; m_NetworkManager.SceneManager.OnFirstSceneSwitchSync(sceneIndex, sceneSwitchProgressGuid); } else { DelayedSpawnAction(stream); } } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleConnectionApproved.End(); #endif }
/// <inheritdoc /> public void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { ushort deltaCount = reader.ReadUInt16Packed(); for (int i = 0; i < deltaCount; i++) { var eventType = (NetworkSetEvent <T> .EventType)reader.ReadBits(2); switch (eventType) { case NetworkSetEvent <T> .EventType.Add: { var value = (T)reader.ReadObjectPacked(typeof(T)); //BOX m_Set.Add(value); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent <T> { Type = eventType, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent <T>() { Type = eventType, Value = value }); } } break; case NetworkSetEvent <T> .EventType.Remove: { var value = (T)reader.ReadObjectPacked(typeof(T)); //BOX m_Set.Remove(value); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent <T> { Type = eventType, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent <T>() { Type = eventType, Value = value }); } } break; case NetworkSetEvent <T> .EventType.Clear: { //Read nothing m_Set.Clear(); if (OnSetChanged != null) { OnSetChanged(new NetworkSetEvent <T> { Type = eventType, }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkSetEvent <T>() { Type = eventType }); } } break; } } } }
internal static void HandleAddObject(ulong clientId, Stream stream) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleAddObject.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { bool isPlayerObject = reader.ReadBool(); ulong networkId = reader.ReadUInt64Packed(); ulong ownerId = reader.ReadUInt64Packed(); bool hasParent = reader.ReadBool(); ulong?parentNetworkId = null; if (hasParent) { parentNetworkId = reader.ReadUInt64Packed(); } ulong prefabHash; ulong instanceId; bool softSync; if (!NetworkManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkManager.Singleton.NetworkConfig.UsePrefabSync) { softSync = false; instanceId = 0; prefabHash = reader.ReadUInt64Packed(); } else { softSync = reader.ReadBool(); if (softSync) { instanceId = reader.ReadUInt64Packed(); prefabHash = 0; } else { prefabHash = reader.ReadUInt64Packed(); instanceId = 0; } } Vector3? pos = null; Quaternion?rot = null; if (reader.ReadBool()) { pos = new Vector3(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); rot = Quaternion.Euler(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); } bool hasPayload = reader.ReadBool(); int payLoadLength = hasPayload ? reader.ReadInt32Packed() : 0; var networkObject = NetworkSpawnManager.CreateLocalNetworkObject(softSync, instanceId, prefabHash, parentNetworkId, pos, rot); NetworkSpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, softSync, isPlayerObject, ownerId, stream, hasPayload, payLoadLength, true, false); Queue <BufferManager.BufferedMessage> bufferQueue = BufferManager.ConsumeBuffersForNetworkId(networkId); // Apply buffered messages if (bufferQueue != null) { while (bufferQueue.Count > 0) { BufferManager.BufferedMessage message = bufferQueue.Dequeue(); NetworkManager.Singleton.HandleIncomingData(message.SenderClientId, message.NetworkChannel, new ArraySegment <byte>(message.NetworkBuffer.GetBuffer(), (int)message.NetworkBuffer.Position, (int)message.NetworkBuffer.Length), message.ReceiveTime, false); BufferManager.RecycleConsumedBufferedMessage(message); } } } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleAddObject.End(); #endif }
/// <inheritdoc /> public void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { ushort deltaCount = reader.ReadUInt16Packed(); for (int i = 0; i < deltaCount; i++) { var eventType = (NetworkDictionaryEvent <TKey, TValue> .EventType)reader.ReadBits(3); switch (eventType) { case NetworkDictionaryEvent <TKey, TValue> .EventType.Add: { var key = (TKey)reader.ReadObjectPacked(typeof(TKey)); var value = (TValue)reader.ReadObjectPacked(typeof(TValue)); m_Dictionary.Add(key, value); if (OnDictionaryChanged != null) { OnDictionaryChanged(new NetworkDictionaryEvent <TKey, TValue> { Type = eventType, Key = key, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkDictionaryEvent <TKey, TValue>() { Type = eventType, Key = key, Value = value }); } } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.Remove: { var key = (TKey)reader.ReadObjectPacked(typeof(TKey)); TValue value; m_Dictionary.TryGetValue(key, out value); m_Dictionary.Remove(key); if (OnDictionaryChanged != null) { OnDictionaryChanged(new NetworkDictionaryEvent <TKey, TValue> { Type = eventType, Key = key, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkDictionaryEvent <TKey, TValue>() { Type = eventType, Key = key, Value = value }); } } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.RemovePair: { var key = (TKey)reader.ReadObjectPacked(typeof(TKey)); var value = (TValue)reader.ReadObjectPacked(typeof(TValue)); m_Dictionary.Remove(new KeyValuePair <TKey, TValue>(key, value)); if (OnDictionaryChanged != null) { OnDictionaryChanged(new NetworkDictionaryEvent <TKey, TValue> { Type = eventType, Key = key, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkDictionaryEvent <TKey, TValue>() { Type = eventType, Key = key, Value = value }); } } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.Clear: { //read nothing m_Dictionary.Clear(); if (OnDictionaryChanged != null) { OnDictionaryChanged(new NetworkDictionaryEvent <TKey, TValue> { Type = eventType }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkDictionaryEvent <TKey, TValue> { Type = eventType }); } } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.Value: { var key = (TKey)reader.ReadObjectPacked(typeof(TKey)); var value = (TValue)reader.ReadObjectPacked(typeof(TValue)); m_Dictionary[key] = value; if (OnDictionaryChanged != null) { OnDictionaryChanged(new NetworkDictionaryEvent <TKey, TValue> { Type = eventType, Key = key, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkDictionaryEvent <TKey, TValue>() { Type = eventType, Key = key, Value = value }); } } break; } } } }
private static void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) { if (!NetworkManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkManager.Singleton.NetworkConfig.UsePrefabSync) { NetworkSpawnManager.DestroySceneObjects(); using (var reader = PooledNetworkReader.Get(objectStream)) { uint newObjectsCount = reader.ReadUInt32Packed(); for (int i = 0; i < newObjectsCount; i++) { bool isPlayerObject = reader.ReadBool(); ulong networkId = reader.ReadUInt64Packed(); ulong owner = reader.ReadUInt64Packed(); bool hasParent = reader.ReadBool(); ulong?parentNetworkId = null; if (hasParent) { parentNetworkId = reader.ReadUInt64Packed(); } ulong prefabHash = reader.ReadUInt64Packed(); Vector3? position = null; Quaternion?rotation = null; if (reader.ReadBool()) { position = new Vector3(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); rotation = Quaternion.Euler(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); } var networkObject = NetworkSpawnManager.CreateLocalNetworkObject(false, 0, prefabHash, parentNetworkId, position, rotation); NetworkSpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, true, isPlayerObject, owner, objectStream, false, 0, true, false); var bufferQueue = BufferManager.ConsumeBuffersForNetworkId(networkId); // Apply buffered messages if (bufferQueue != null) { while (bufferQueue.Count > 0) { BufferManager.BufferedMessage message = bufferQueue.Dequeue(); NetworkManager.Singleton.HandleIncomingData(message.SenderClientId, message.NetworkChannel, new ArraySegment <byte>(message.NetworkBuffer.GetBuffer(), (int)message.NetworkBuffer.Position, (int)message.NetworkBuffer.Length), message.ReceiveTime, false); BufferManager.RecycleConsumedBufferedMessage(message); } } } } } else { var networkObjects = MonoBehaviour.FindObjectsOfType <NetworkObject>(); NetworkSpawnManager.ClientCollectSoftSyncSceneObjectSweep(networkObjects); using (var reader = PooledNetworkReader.Get(objectStream)) { uint newObjectsCount = reader.ReadUInt32Packed(); for (int i = 0; i < newObjectsCount; i++) { bool isPlayerObject = reader.ReadBool(); ulong networkId = reader.ReadUInt64Packed(); ulong owner = reader.ReadUInt64Packed(); bool hasParent = reader.ReadBool(); ulong?parentNetworkId = null; if (hasParent) { parentNetworkId = reader.ReadUInt64Packed(); } ulong instanceId = reader.ReadUInt64Packed(); var networkObject = NetworkSpawnManager.CreateLocalNetworkObject(true, instanceId, 0, parentNetworkId, null, null); NetworkSpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, true, isPlayerObject, owner, objectStream, false, 0, true, false); var bufferQueue = BufferManager.ConsumeBuffersForNetworkId(networkId); // Apply buffered messages if (bufferQueue != null) { while (bufferQueue.Count > 0) { BufferManager.BufferedMessage message = bufferQueue.Dequeue(); NetworkManager.Singleton.HandleIncomingData(message.SenderClientId, message.NetworkChannel, new ArraySegment <byte>(message.NetworkBuffer.GetBuffer(), (int)message.NetworkBuffer.Position, (int)message.NetworkBuffer.Length), message.ReceiveTime, false); BufferManager.RecycleConsumedBufferedMessage(message); } } } } } using (var buffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteByteArray(switchSceneGuid.ToByteArray()); InternalMessageSender.Send(NetworkManager.Singleton.ServerClientId, NetworkConstants.CLIENT_SWITCH_SCENE_COMPLETED, NetworkChannel.Internal, buffer); } s_IsSwitching = false; OnSceneSwitched?.Invoke(); }
public void NetworkObjectSceneSerializationFailure() { var networkObjectsToTest = new List <GameObject>(); var pooledBuffer = PooledNetworkBuffer.Get(); var writer = PooledNetworkWriter.Get(pooledBuffer); var reader = PooledNetworkReader.Get(pooledBuffer); var invalidNetworkObjectOffsets = new List <long>(); var invalidNetworkObjectIdCount = new List <int>(); var invalidNetworkObjects = new List <GameObject>(); var invalidNetworkObjectFrequency = 3; // Construct 50 NetworkObjects for (int i = 0; i < 50; i++) { // Inject an invalid NetworkObject every [invalidNetworkObjectFrequency] entry if ((i % invalidNetworkObjectFrequency) == 0) { // Create the invalid NetworkObject var gameObject = new GameObject($"InvalidTestObject{i}"); Assert.IsNotNull(gameObject); var networkObject = gameObject.AddComponent <NetworkObject>(); Assert.IsNotNull(networkObject); var networkVariableComponent = gameObject.AddComponent <NetworkBehaviourWithNetworkVariables>(); Assert.IsNotNull(networkVariableComponent); // Add invalid NetworkObject's starting position before serialization to handle trapping for the Debug.LogError message // that we know will be thrown invalidNetworkObjectOffsets.Add(pooledBuffer.Position); networkObject.GlobalObjectIdHash = (uint)(i); invalidNetworkObjectIdCount.Add(i); invalidNetworkObjects.Add(gameObject); // Serialize the invalid NetworkObject networkObject.SerializeSceneObject(writer, 0); Debug.Log($"Invalid {nameof(NetworkObject)} Size {pooledBuffer.Position - invalidNetworkObjectOffsets[invalidNetworkObjectOffsets.Count - 1]}"); // Now adjust how frequent we will inject invalid NetworkObjects invalidNetworkObjectFrequency = Random.Range(2, 5); } else { // Create a valid NetworkObject var gameObject = new GameObject($"TestObject{i}"); Assert.IsNotNull(gameObject); var networkObject = gameObject.AddComponent <NetworkObject>(); var networkVariableComponent = gameObject.AddComponent <NetworkBehaviourWithNetworkVariables>(); Assert.IsNotNull(networkVariableComponent); Assert.IsNotNull(networkObject); networkObject.GlobalObjectIdHash = (uint)(i + 4096); networkObjectsToTest.Add(gameObject); // Serialize the valid NetworkObject networkObject.SerializeSceneObject(writer, 0); // Add this valid NetworkObject into the PendinigSoftSyncObjects list NetworkManagerHelper.NetworkManagerObject.SpawnManager.PendingSoftSyncObjects.Add(networkObject.GlobalObjectIdHash, networkObject); } } var totalBufferSize = pooledBuffer.Position; // Reset the position for reading this information pooledBuffer.Position = 0; var networkObjectsDeSerialized = new List <NetworkObject>(); var currentLogLevel = NetworkManager.Singleton.LogLevel; var invalidNetworkObjectCount = 0; while (pooledBuffer.Position != totalBufferSize) { // If we reach the point where we expect it to fail, then make sure we let TestRunner know it should expect this log error message if (invalidNetworkObjectOffsets.Count > 0 && pooledBuffer.Position == invalidNetworkObjectOffsets[0]) { invalidNetworkObjectOffsets.RemoveAt(0); // Turn off Network Logging to avoid other errors that we know will happen after the below LogAssert.Expect message occurs. NetworkManager.Singleton.LogLevel = Logging.LogLevel.Nothing; // Trap for this specific error message so we don't make Test Runner think we failed (it will fail on Debug.LogError) UnityEngine.TestTools.LogAssert.Expect(LogType.Error, $"Failed to spawn {nameof(NetworkObject)} for Hash {invalidNetworkObjectIdCount[invalidNetworkObjectCount]}."); invalidNetworkObjectCount++; } var deserializedNetworkObject = NetworkObject.DeserializeSceneObject(pooledBuffer, reader, NetworkManagerHelper.NetworkManagerObject); if (deserializedNetworkObject != null) { networkObjectsDeSerialized.Add(deserializedNetworkObject); } else { // Under this condition, we are expecting null (i.e. no NetworkObject instantiated) // and will set our log level back to the original value to assure the valid NetworkObjects // aren't causing any log Errors to occur NetworkManager.Singleton.LogLevel = currentLogLevel; } } reader.Dispose(); writer.Dispose(); NetworkBufferPool.PutBackInPool(pooledBuffer); // Now validate all NetworkObjects returned against the original NetworkObjects we created // after they validate, destroy the objects foreach (var entry in networkObjectsToTest) { var entryNetworkObject = entry.GetComponent <NetworkObject>(); Assert.IsTrue(networkObjectsDeSerialized.Contains(entryNetworkObject)); Object.Destroy(entry); } // Destroy the invalid network objects foreach (var entry in invalidNetworkObjects) { Object.Destroy(entry); } }
/// <summary> /// This will allocate [maxFrameHistory] + [1 currentFrame] number of PooledNetworkBuffers and keep them open until the session ends /// Note: For zero frame history set maxFrameHistory to zero /// </summary> /// <param name="maxFrameHistory"></param> private void Initialize(uint maxFrameHistory) { //This makes sure that we don't exceed a ridiculous value by capping the number of queue history frames to ushort.MaxValue //If this value is exceeded, then it will be kept at the ceiling of ushort.Maxvalue. //Note: If running at a 60pps rate (16ms update frequency) this would yield 17.47 minutes worth of queue frame history. if (maxFrameHistory > ushort.MaxValue) { if (NetworkLog.CurrentLogLevel == LogLevel.Developer) { NetworkLog.LogWarning($"The {nameof(RpcQueueHistoryFrame)} size cannot exceed {ushort.MaxValue} {nameof(RpcQueueHistoryFrame)}s! Capping at {ushort.MaxValue} {nameof(RpcQueueHistoryFrame)}s."); } maxFrameHistory = ushort.MaxValue; } ClearParameters(); m_RpcQueueProcessor = new RpcQueueProcessor(this, NetworkManager); m_MaxFrameHistory = maxFrameHistory + k_MinQueueHistory; if (!m_QueueHistory.ContainsKey(RpcQueueHistoryFrame.QueueFrameType.Inbound)) { m_QueueHistory.Add(RpcQueueHistoryFrame.QueueFrameType.Inbound, new Dictionary <int, Dictionary <NetworkUpdateStage, RpcQueueHistoryFrame> >()); } if (!m_QueueHistory.ContainsKey(RpcQueueHistoryFrame.QueueFrameType.Outbound)) { m_QueueHistory.Add(RpcQueueHistoryFrame.QueueFrameType.Outbound, new Dictionary <int, Dictionary <NetworkUpdateStage, RpcQueueHistoryFrame> >()); } for (int i = 0; i < m_MaxFrameHistory; i++) { if (!m_QueueHistory[RpcQueueHistoryFrame.QueueFrameType.Outbound].ContainsKey(i)) { m_QueueHistory[RpcQueueHistoryFrame.QueueFrameType.Outbound].Add(i, new Dictionary <NetworkUpdateStage, RpcQueueHistoryFrame>()); var queueHistoryFrame = new RpcQueueHistoryFrame(RpcQueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateStage.PostLateUpdate); queueHistoryFrame.QueueBuffer = PooledNetworkBuffer.Get(); queueHistoryFrame.QueueBuffer.Position = 0; queueHistoryFrame.QueueWriter = PooledNetworkWriter.Get(queueHistoryFrame.QueueBuffer); queueHistoryFrame.QueueReader = PooledNetworkReader.Get(queueHistoryFrame.QueueBuffer); queueHistoryFrame.QueueItemOffsets = new List <uint>(); //For now all outbound, we will always have a single update in which they are processed (LATEUPDATE) m_QueueHistory[RpcQueueHistoryFrame.QueueFrameType.Outbound][i].Add(NetworkUpdateStage.PostLateUpdate, queueHistoryFrame); } if (!m_QueueHistory[RpcQueueHistoryFrame.QueueFrameType.Inbound].ContainsKey(i)) { m_QueueHistory[RpcQueueHistoryFrame.QueueFrameType.Inbound].Add(i, new Dictionary <NetworkUpdateStage, RpcQueueHistoryFrame>()); //For inbound, we create a queue history frame per update stage foreach (NetworkUpdateStage netUpdateStage in Enum.GetValues(typeof(NetworkUpdateStage))) { var rpcQueueHistoryFrame = new RpcQueueHistoryFrame(RpcQueueHistoryFrame.QueueFrameType.Inbound, netUpdateStage); rpcQueueHistoryFrame.QueueBuffer = PooledNetworkBuffer.Get(); rpcQueueHistoryFrame.QueueBuffer.Position = 0; rpcQueueHistoryFrame.QueueWriter = PooledNetworkWriter.Get(rpcQueueHistoryFrame.QueueBuffer); rpcQueueHistoryFrame.QueueReader = PooledNetworkReader.Get(rpcQueueHistoryFrame.QueueBuffer); rpcQueueHistoryFrame.QueueItemOffsets = new List <uint>(); m_QueueHistory[RpcQueueHistoryFrame.QueueFrameType.Inbound][i].Add(netUpdateStage, rpcQueueHistoryFrame); } } } //As long as this instance is using the pre-defined update stages if (!m_ProcessUpdateStagesExternally) { //Register with the network update loop system this.RegisterAllNetworkUpdates(); } }
internal static void SetNetworkVariableData(List <INetworkVariable> networkVariableList, Stream stream, NetworkManager networkManager) { if (networkVariableList.Count == 0) { return; } using (var reader = PooledNetworkReader.Get(stream)) { for (int j = 0; j < networkVariableList.Count; j++) { ushort varSize = 0; if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { varSize = reader.ReadUInt16Packed(); if (varSize == 0) { continue; } } else { if (!reader.ReadBool()) { continue; } } long readStartPos = stream.Position; networkVariableList[j].ReadField(stream, NetworkTickSystem.NoTick, NetworkTickSystem.NoTick); if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (stream is NetworkBuffer networkBuffer) { networkBuffer.SkipPadBits(); } if (stream.Position > (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Var data read too far. {stream.Position - (readStartPos + varSize)} bytes."); } stream.Position = readStartPos + varSize; } else if (stream.Position < (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Var data read too little. {(readStartPos + varSize) - stream.Position} bytes."); } stream.Position = readStartPos + varSize; } } } } }
internal static void HandleNetworkVariableUpdate(List <INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkBehaviour logInstance, NetworkManager networkManager) { using (var reader = PooledNetworkReader.Get(stream)) { for (int i = 0; i < networkVariableList.Count; i++) { ushort varSize = 0; if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { varSize = reader.ReadUInt16Packed(); if (varSize == 0) { continue; } } else { if (!reader.ReadBool()) { continue; } } if (networkManager.IsServer && !networkVariableList[i].CanClientWrite(clientId)) { if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Client wrote to {nameof(NetworkVariable)} without permission. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}"); } stream.Position += varSize; continue; } //This client wrote somewhere they are not allowed. This is critical //We can't just skip this field. Because we don't actually know how to dummy read //That is, we don't know how many bytes to skip. Because the interface doesn't have a //Read that gives us the value. Only a Read that applies the value straight away //A dummy read COULD be added to the interface for this situation, but it's just being too nice. //This is after all a developer fault. A critical error should be fine. // - TwoTen if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { NetworkLog.LogError($"Client wrote to {nameof(NetworkVariable)} without permission. No more variables can be read. This is critical. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}"); } return; } long readStartPos = stream.Position; networkVariableList[i].ReadField(stream, NetworkTickSystem.NoTick, NetworkTickSystem.NoTick); PerformanceDataManager.Increment(ProfilerConstants.NetworkVarUpdates); ProfilerStatManager.NetworkVarsRcvd.Record(); if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (stream is NetworkBuffer networkBuffer) { networkBuffer.SkipPadBits(); } if (stream.Position > (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Var update read too far. {stream.Position - (readStartPos + varSize)} bytes. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}"); } stream.Position = readStartPos + varSize; } else if (stream.Position < (readStartPos + varSize)) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"Var update read too little. {(readStartPos + varSize) - stream.Position} bytes. => {(logInstance != null ? ($"{nameof(NetworkObjectId)}: {logInstance.NetworkObjectId} - {nameof(NetworkObject.GetNetworkBehaviourOrderIndex)}(): {logInstance.NetworkObject.GetNetworkBehaviourOrderIndex(logInstance)} - VariableIndex: {i}") : string.Empty)}"); } stream.Position = readStartPos + varSize; } } } } }
internal static void HandleConnectionApproved(ulong clientId, Stream stream, float receiveTime) { #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleConnectionApproved.Begin(); #endif using (var reader = PooledNetworkReader.Get(stream)) { NetworkManager.Singleton.LocalClientId = reader.ReadUInt64Packed(); uint sceneIndex = 0; Guid sceneSwitchProgressGuid = new Guid(); if (NetworkManager.Singleton.NetworkConfig.EnableSceneManagement) { sceneIndex = reader.ReadUInt32Packed(); sceneSwitchProgressGuid = new Guid(reader.ReadByteArray()); } bool sceneSwitch = NetworkManager.Singleton.NetworkConfig.EnableSceneManagement && NetworkSceneManager.HasSceneMismatch(sceneIndex); float netTime = reader.ReadSinglePacked(); NetworkManager.Singleton.UpdateNetworkTime(clientId, netTime, receiveTime, true); NetworkManager.Singleton.ConnectedClients.Add(NetworkManager.Singleton.LocalClientId, new NetworkClient { ClientId = NetworkManager.Singleton.LocalClientId }); void DelayedSpawnAction(Stream continuationStream) { using (var continuationReader = PooledNetworkReader.Get(continuationStream)) { if (!NetworkManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkManager.Singleton.NetworkConfig.UsePrefabSync) { NetworkSpawnManager.DestroySceneObjects(); } else { NetworkSpawnManager.ClientCollectSoftSyncSceneObjectSweep(null); } uint objectCount = continuationReader.ReadUInt32Packed(); for (int i = 0; i < objectCount; i++) { bool isPlayerObject = continuationReader.ReadBool(); ulong networkId = continuationReader.ReadUInt64Packed(); ulong ownerId = continuationReader.ReadUInt64Packed(); bool hasParent = continuationReader.ReadBool(); ulong?parentNetworkId = null; if (hasParent) { parentNetworkId = continuationReader.ReadUInt64Packed(); } ulong prefabHash; ulong instanceId; bool softSync; if (!NetworkManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkManager.Singleton.NetworkConfig.UsePrefabSync) { softSync = false; instanceId = 0; prefabHash = continuationReader.ReadUInt64Packed(); } else { softSync = continuationReader.ReadBool(); if (softSync) { instanceId = continuationReader.ReadUInt64Packed(); prefabHash = 0; } else { prefabHash = continuationReader.ReadUInt64Packed(); instanceId = 0; } } Vector3? pos = null; Quaternion?rot = null; if (continuationReader.ReadBool()) { pos = new Vector3(continuationReader.ReadSinglePacked(), continuationReader.ReadSinglePacked(), continuationReader.ReadSinglePacked()); rot = Quaternion.Euler(continuationReader.ReadSinglePacked(), continuationReader.ReadSinglePacked(), continuationReader.ReadSinglePacked()); } var networkObject = NetworkSpawnManager.CreateLocalNetworkObject(softSync, instanceId, prefabHash, parentNetworkId, pos, rot); NetworkSpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, softSync, isPlayerObject, ownerId, continuationStream, false, 0, true, false); Queue <BufferManager.BufferedMessage> bufferQueue = BufferManager.ConsumeBuffersForNetworkId(networkId); // Apply buffered messages if (bufferQueue != null) { while (bufferQueue.Count > 0) { BufferManager.BufferedMessage message = bufferQueue.Dequeue(); NetworkManager.Singleton.HandleIncomingData(message.SenderClientId, message.NetworkChannel, new ArraySegment <byte>(message.NetworkBuffer.GetBuffer(), (int)message.NetworkBuffer.Position, (int)message.NetworkBuffer.Length), message.ReceiveTime, false); BufferManager.RecycleConsumedBufferedMessage(message); } } } NetworkSpawnManager.CleanDiffedSceneObjects(); NetworkManager.Singleton.IsConnectedClient = true; NetworkManager.Singleton.InvokeOnClientConnectedCallback(NetworkManager.Singleton.LocalClientId); } } if (sceneSwitch) { UnityAction <Scene, Scene> onSceneLoaded = null; var continuationBuffer = new NetworkBuffer(); continuationBuffer.CopyUnreadFrom(stream); continuationBuffer.Position = 0; void OnSceneLoadComplete() { SceneManager.activeSceneChanged -= onSceneLoaded; NetworkSceneManager.IsSpawnedObjectsPendingInDontDestroyOnLoad = false; DelayedSpawnAction(continuationBuffer); } onSceneLoaded = (oldScene, newScene) => { OnSceneLoadComplete(); }; SceneManager.activeSceneChanged += onSceneLoaded; NetworkSceneManager.OnFirstSceneSwitchSync(sceneIndex, sceneSwitchProgressGuid); } else { DelayedSpawnAction(stream); } } #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleConnectionApproved.End(); #endif }
/// <inheritdoc /> public void ReadDelta(Stream stream, bool keepDirtyDelta, ushort localTick, ushort remoteTick) { using (var reader = PooledNetworkReader.Get(stream)) { ushort deltaCount = reader.ReadUInt16Packed(); for (int i = 0; i < deltaCount; i++) { NetworkListEvent <T> .EventType eventType = (NetworkListEvent <T> .EventType)reader.ReadBits(3); switch (eventType) { case NetworkListEvent <T> .EventType.Add: { m_List.Add((T)reader.ReadObjectPacked(typeof(T))); //BOX if (OnListChanged != null) { OnListChanged(new NetworkListEvent <T> { Type = eventType, Index = m_List.Count - 1, Value = m_List[m_List.Count - 1] }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkListEvent <T>() { Type = eventType, Index = m_List.Count - 1, Value = m_List[m_List.Count - 1] }); } } break; case NetworkListEvent <T> .EventType.Insert: { int index = reader.ReadInt32Packed(); m_List.Insert(index, (T)reader.ReadObjectPacked(typeof(T))); //BOX if (OnListChanged != null) { OnListChanged(new NetworkListEvent <T> { Type = eventType, Index = index, Value = m_List[index] }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkListEvent <T>() { Type = eventType, Index = index, Value = m_List[index] }); } } break; case NetworkListEvent <T> .EventType.Remove: { T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX int index = m_List.IndexOf(value); m_List.RemoveAt(index); if (OnListChanged != null) { OnListChanged(new NetworkListEvent <T> { Type = eventType, Index = index, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkListEvent <T>() { Type = eventType, Index = index, Value = value }); } } break; case NetworkListEvent <T> .EventType.RemoveAt: { int index = reader.ReadInt32Packed(); T value = m_List[index]; m_List.RemoveAt(index); if (OnListChanged != null) { OnListChanged(new NetworkListEvent <T> { Type = eventType, Index = index, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkListEvent <T>() { Type = eventType, Index = index, Value = value }); } } break; case NetworkListEvent <T> .EventType.Value: { int index = reader.ReadInt32Packed(); T value = (T)reader.ReadObjectPacked(typeof(T)); //BOX if (index < m_List.Count) { m_List[index] = value; } if (OnListChanged != null) { OnListChanged(new NetworkListEvent <T> { Type = eventType, Index = index, Value = value }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkListEvent <T>() { Type = eventType, Index = index, Value = value }); } } break; case NetworkListEvent <T> .EventType.Clear: { //Read nothing m_List.Clear(); if (OnListChanged != null) { OnListChanged(new NetworkListEvent <T> { Type = eventType, }); } if (keepDirtyDelta) { m_DirtyEvents.Add(new NetworkListEvent <T>() { Type = eventType }); } } break; } } } }