void CheckSendRate() { if (SendMessagesAllowed && syncInterval > 0 && sendTimer < Time.time) { sendTimer = Time.time + syncInterval; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { if (WriteParameters(writer)) { SendAnimationParametersMessage(writer.ToArray()); } } } }
private void PushLength(int length, ref PooledNetworkWriter writer) { // If length is single byte we write it if (length < 256) { writer.WriteByte((byte)length); // write the amounts of bytes that are coming up } else { // otherwise we write a two-byte length writer.WriteByte(k_LongLenMarker); // mark larger size writer.WriteByte((byte)(length % 256)); // write the length modulo 256 writer.WriteByte((byte)(length / 256)); // write the length divided by 256 } }
public void PoolCanGetMoreWritersThanPoolSize() { NetworkWriterPool.Capacity = 5; const int testWriterCount = 10; var writers = new PooledNetworkWriter[testWriterCount]; for (int i = 0; i < testWriterCount; i++) { writers[i] = NetworkWriterPool.GetWriter(); } // Make sure all writers are different Assert.That(writers.Distinct().Count(), Is.EqualTo(testWriterCount)); }
/// <summary> /// Gets a SHA256 hash of parts of the NetworkConfig instance /// </summary> /// <param name="cache"></param> /// <returns></returns> public ulong GetConfig(bool cache = true) { if (m_ConfigHash != null && cache) { return(m_ConfigHash.Value); } Sort(); using (var buffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteUInt16Packed(ProtocolVersion); writer.WriteString(NetworkConstants.PROTOCOL_VERSION); if (EnableSceneManagement && !AllowRuntimeSceneChanges) { for (int i = 0; i < RegisteredScenes.Count; i++) { writer.WriteString(RegisteredScenes[i]); } } if (ForceSamePrefabs) { var sortedDictionary = NetworkPrefabOverrideLinks.OrderBy(x => x.Key); foreach (var sortedEntry in sortedDictionary) { writer.WriteUInt32Packed(sortedEntry.Key); } } writer.WriteBool(EnableNetworkVariable); writer.WriteBool(ForceSamePrefabs); writer.WriteBool(EnableSceneManagement); writer.WriteBool(EnsureNetworkVariableLengthSafety); writer.WriteBits((byte)RpcHashSize, 2); buffer.PadBuffer(); if (cache) { m_ConfigHash = XXHash.Hash64(buffer.ToArray()); return(m_ConfigHash.Value); } return(XXHash.Hash64(buffer.ToArray())); } }
/// <summary> /// This function invokes the registered handler function for a message. /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para> /// </summary> /// <typeparam name="T">The message type to unregister.</typeparam> /// <param name="msg">The message object to process.</param> /// <returns>Returns true if the handler was successfully invoked</returns> public bool InvokeHandler<T>(T msg, int channelId) where T :struct, NetworkMessage { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // if it is a value type, just use typeof(T) to avoid boxing // this works because value types cannot be derived // if it is a reference type (for example NetworkMessage), // ask the message for the real type int msgType = MessagePacker.GetId<T>(); MessagePacker.Pack(msg, writer); ArraySegment<byte> segment = writer.ToArraySegment(); using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(segment)) return InvokeHandler(msgType, networkReader, channelId); } }
internal static void WriteNetworkVariableData(List <INetworkVariable> networkVariableList, Stream stream, ulong clientId, NetworkManager networkManager) { if (networkVariableList.Count == 0) { return; } using (var writer = PooledNetworkWriter.Get(stream)) { for (int j = 0; j < networkVariableList.Count; j++) { bool canClientRead = networkVariableList[j].CanClientRead(clientId); if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { if (!canClientRead) { writer.WriteUInt16Packed(0); } } else { writer.WriteBool(canClientRead); } if (canClientRead) { if (networkManager.NetworkConfig.EnsureNetworkVariableLengthSafety) { using (var varBuffer = PooledNetworkBuffer.Get()) { networkVariableList[j].WriteField(varBuffer); varBuffer.PadBuffer(); writer.WriteUInt16Packed((ushort)varBuffer.Length); varBuffer.CopyTo(stream); } } else { networkVariableList[j].WriteField(stream); } } } } }
/// <inheritdoc /> public void WriteDelta(Stream stream) { using (var writer = PooledNetworkWriter.Get(stream)) { writer.WriteUInt16Packed((ushort)m_DirtyEvents.Count); for (int i = 0; i < m_DirtyEvents.Count; i++) { writer.WriteBits((byte)m_DirtyEvents[i].Type, 3); switch (m_DirtyEvents[i].Type) { case NetworkDictionaryEvent <TKey, TValue> .EventType.Add: { writer.WriteObjectPacked(m_DirtyEvents[i].Key); writer.WriteObjectPacked(m_DirtyEvents[i].Value); } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.Remove: { writer.WriteObjectPacked(m_DirtyEvents[i].Key); } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.RemovePair: { writer.WriteObjectPacked(m_DirtyEvents[i].Key); writer.WriteObjectPacked(m_DirtyEvents[i].Value); } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.Clear: { //write nothing } break; case NetworkDictionaryEvent <TKey, TValue> .EventType.Value: { writer.WriteObjectPacked(m_DirtyEvents[i].Key); writer.WriteObjectPacked(m_DirtyEvents[i].Value); } break; } } } }
public void SumOnServer(byte[] serverReceivedData) { PooledNetworkReader pooledNetworkReader = NetworkReaderPool.GetReader(serverReceivedData); int a = pooledNetworkReader.Read <int>(); int b = pooledNetworkReader.Read <int>(); pooledNetworkReader.Dispose(); PooledNetworkWriter pooledNetworkWriter = NetworkWriterPool.GetWriter(); int result = a + b; pooledNetworkWriter.Write(result); pooledNetworkWriter.ToArray(); byte[] dataToSendClient = pooledNetworkWriter.ToArray(); Debug.LogWarning("Server " + result); RpcReceive(DataCommand.TEST_SumOnServer, dataToSendClient); pooledNetworkWriter.Dispose(); }
public void SendMaxBatchSizedMessageBatch() { // create a message == max batch size int max = transport.GetMaxBatchSize(Channels.DefaultReliable); byte[] message = new byte[max]; // add to batch queue PooledNetworkWriter writer = NetworkWriterPool.GetWriter(); writer.WriteBytes(message, 0, message.Length); batch.messages.Enqueue(writer); // send batch - client should receive that exact message connection.SendBatch(Channels.DefaultReliable, batch); Assert.That(transport.clientIncoming.Count, Is.EqualTo(1)); Assert.That(transport.clientIncoming.Dequeue().data.Length, Is.EqualTo(message.Length)); }
public void C2SSceneChanged(int newScene) { if (NetManager.IsHost) { ClientSceneChanged?.Invoke(NetManager.ServerClientId, newScene); } else if (NetManager.IsConnectedClient) { using (var buffer = PooledNetworkBuffer.Get()) { using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteInt32(newScene); MLAPI.Messaging.CustomMessagingManager.SendNamedMessage("C2S_SceneChanged", NetManager.ServerClientId, buffer, NetworkChannel.Internal); } } } }
/// <summary> /// Send fake values to client's <see cref="Mirror.SyncVarAttribute"/>. /// </summary> /// <param name="target">Target to send.</param> /// <param name="behaviorOwner"><see cref="Mirror.NetworkIdentity"/> of object that owns <see cref="Mirror.NetworkBehaviour"/>.</param> /// <param name="targetType"><see cref="Mirror.NetworkBehaviour"/>'s type.</param> /// <param name="propertyName">Property name starting with Network.</param> /// <param name="value">Value of send to target.</param> public static void SendFakeSyncVar(this Player target, NetworkIdentity behaviorOwner, Type targetType, string propertyName, object value) { void CustomSyncVarGenerator(NetworkWriter targetWriter) { targetWriter.WriteUInt64(SyncVarDirtyBits[$"{propertyName}"]); WriterExtensions[value.GetType()]?.Invoke(null, new object[] { targetWriter, value }); } PooledNetworkWriter writer = NetworkWriterPool.GetWriter(); PooledNetworkWriter writer2 = NetworkWriterPool.GetWriter(); MakeCustomSyncWriter(behaviorOwner, targetType, null, CustomSyncVarGenerator, writer, writer2); target.ReferenceHub.networkIdentity.connectionToClient.Send(new UpdateVarsMessage() { netId = behaviorOwner.netId, payload = writer.ToArraySegment() }); NetworkWriterPool.Recycle(writer); NetworkWriterPool.Recycle(writer2); }
public void SyncVarIsBitPacked() { serverComponent.myValue = value; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { serverComponent.SerializeSyncVars(writer, true); Assert.That(writer.BitPosition, Is.EqualTo(32)); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment(), null)) { clientComponent.DeserializeSyncVars(reader, true); Assert.That(reader.BitPosition, Is.EqualTo(32)); Assert.That(clientComponent.myValue, Is.EqualTo(value)); } } }
/// <summary> /// Hides a list of objects from a client /// </summary> /// <param name="networkObjects">The objects to hide</param> /// <param name="clientId">The client to hide the objects from</param> public static void NetworkHide(List <NetworkObject> networkObjects, ulong clientId) { if (!NetworkManager.Singleton.IsServer) { throw new NotServerException("Only server can change visibility"); } if (clientId == NetworkManager.Singleton.ServerClientId) { throw new VisibilityChangeException("Cannot hide an object from the server"); } // Do the safety loop first to prevent putting the MLAPI in an invalid state. for (int i = 0; i < networkObjects.Count; i++) { if (!networkObjects[i].IsSpawned) { throw new SpawnStateException("Object is not spawned"); } if (!networkObjects[i].m_Observers.Contains(clientId)) { throw new VisibilityChangeException($"{nameof(NetworkObject)} with {nameof(NetworkObjectId)}: {networkObjects[i].NetworkObjectId} is already hidden"); } } using (var buffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteUInt16Packed((ushort)networkObjects.Count); for (int i = 0; i < networkObjects.Count; i++) { // Send destroy call networkObjects[i].m_Observers.Remove(clientId); writer.WriteUInt64Packed(networkObjects[i].NetworkObjectId); } InternalMessageSender.Send(clientId, NetworkConstants.DESTROY_OBJECTS, NetworkChannel.Internal, buffer); } }
public void ShrinkCapacity() { NetworkWriterPool.Capacity = 2; // get writer and recycle so we have 2 in there, hence 'next' is at limit PooledNetworkWriter a = NetworkWriterPool.GetWriter(); PooledNetworkWriter b = NetworkWriterPool.GetWriter(); NetworkWriterPool.Recycle(a); NetworkWriterPool.Recycle(b); // shrink NetworkWriterPool.Capacity = 1; // get one. should return the only one which is still in there. PooledNetworkWriter c = NetworkWriterPool.GetWriter(); Assert.That(c, !Is.Null); Assert.That(c == a || c == b); }
/// <summary> /// Send fake values to client's <see cref="Mirror.ClientRpcAttribute"/>. /// </summary> /// <param name="target">Target to send.</param> /// <param name="behaviorOwner"><see cref="Mirror.NetworkIdentity"/> of object that owns <see cref="Mirror.NetworkBehaviour"/>.</param> /// <param name="targetType"><see cref="Mirror.NetworkBehaviour"/>'s type.</param> /// <param name="rpcName">Property name starting with Rpc.</param> /// <param name="values">Values of send to target.</param> public static void SendFakeTargetRpc(Player target, NetworkIdentity behaviorOwner, Type targetType, string rpcName, params object[] values) { PooledNetworkWriter writer = NetworkWriterPool.GetWriter(); foreach (object value in values) { WriterExtensions[value.GetType()].Invoke(null, new object[] { writer, value }); } RpcMessage msg = new RpcMessage { netId = behaviorOwner.netId, componentIndex = GetComponentIndex(behaviorOwner, targetType), functionHash = (targetType.FullName.GetStableHashCode() * 503) + rpcName.GetStableHashCode(), payload = writer.ToArraySegment(), }; target.Connection.Send(msg, 0); NetworkWriterPool.Recycle(writer); }
public void StartGame() { var pts = new HashSet <Transform>(_SpawnPoints.GetComponentsInChildren <Transform>()); pts.Remove(_SpawnPoints.transform); // Why does unity return parent also ? foreach (var(player, point) in _SessionManager.Zip(pts, (player, point) => (player, point.localPosition))) { var obj = Instantiate(_PlayerPrefab, point, Quaternion.identity); using var stream = PooledNetworkBuffer.Get(); using var writer = PooledNetworkWriter.Get(stream); writer.WriteByte((byte)player.Character); writer.WritePadBits(); var net = obj.GetComponent <NetworkObject>(); net.SpawnAsPlayerObject(player.ID, stream, true); } }
/// <summary> /// Sends the named message /// </summary> /// <param name="name">The message name to send</param> /// <param name="clientIds">The clients to send to, sends to everyone if null</param> /// <param name="stream">The message stream containing the data</param> /// <param name="networkChannel">The channel to send the data on</param> public static void SendNamedMessage(string name, List <ulong> clientIds, Stream stream, NetworkChannel networkChannel = NetworkChannel.Internal) { ulong hash = 0; switch (NetworkManager.Singleton.NetworkConfig.RpcHashSize) { case HashSize.VarIntTwoBytes: hash = name.GetStableHash16(); break; case HashSize.VarIntFourBytes: hash = name.GetStableHash32(); break; case HashSize.VarIntEightBytes: hash = name.GetStableHash64(); break; } using (var messageBuffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(messageBuffer)) { writer.WriteUInt64Packed(hash); messageBuffer.CopyFrom(stream); if (!NetworkManager.Singleton.IsServer) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { NetworkLog.LogWarning("Can not send named messages to multiple users as a client"); } return; } InternalMessageSender.Send(NetworkConstants.NAMED_MESSAGE, networkChannel, clientIds, messageBuffer); PerformanceDataManager.Increment(ProfilerConstants.NamedMessageSent); } }
public void BufferReturnsMutliplePacketsInTheOrderTheyWereWriten() { const string expectedMessage1 = "first Message"; const string expectedMessage2 = "second Message"; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { writer.WriteString(expectedMessage1); buffer.Write(writer.ToArraySegment()); } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { writer.WriteString(expectedMessage2); buffer.Write(writer.ToArraySegment()); } string message1; string message2; ArraySegment <byte> package1 = buffer.GetNextPacket(); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(package1)) { message1 = reader.ReadString(); } Assert.IsTrue(buffer.HasPackets()); ArraySegment <byte> package2 = buffer.GetNextPacket(); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(package2)) { message2 = reader.ReadString(); } Assert.That(message1, Is.EqualTo(expectedMessage1)); Assert.That(message2, Is.EqualTo(expectedMessage2)); }
public void SyncVarIsBitPacked([ValueSource(nameof(cases))] TestCase TestCase) { int value = TestCase.value; int expectedBitCount = TestCase.expectedBits; serverComponent.myValue = value; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { serverComponent.SerializeSyncVars(writer, true); Assert.That(writer.BitPosition, Is.EqualTo(expectedBitCount)); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment())) { clientComponent.DeserializeSyncVars(reader, true); Assert.That(reader.BitPosition, Is.EqualTo(expectedBitCount)); Assert.That(clientComponent.myValue, Is.EqualTo(value)); } } }
public void SendLargerMaxBatchSizedMessageBatch() { int maxBatch = transport.GetMaxBatchSize(Channels.Reliable); int maxPacket = transport.GetMaxPacketSize(Channels.Reliable); // we can only tested if transport max batch < max message Assert.That(maxBatch < maxPacket, Is.True); // create a message > batch size byte[] message = new byte[maxPacket]; // add to batch queue PooledNetworkWriter writer = NetworkWriterPool.GetWriter(); writer.WriteBytes(message, 0, message.Length); batch.messages.Enqueue(writer); // send batch - client should receive that exact message connection.SendBatch(Channels.Reliable, batch); Assert.That(transport.clientIncoming.Count, Is.EqualTo(1)); Assert.That(transport.clientIncoming.Dequeue().data.Length, Is.EqualTo(message.Length)); }
public IEnumerator SendMany() { Task <RunNode.Result> task = RunNode.RunAsync("ReceiveManyMessages.js", 5_000); yield return(server.WaitForConnection); const int messageCount = 100; for (int i = 0; i < messageCount; i++) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { writer.WriteByte((byte)i); writer.WriteInt32(100); ArraySegment <byte> segment = writer.ToArraySegment(); server.ServerSend(new List <int> { 1 }, Channels.DefaultReliable, segment); } } yield return(new WaitForSeconds(1)); server.ServerDisconnect(1); yield return(new WaitUntil(() => task.IsCompleted)); RunNode.Result result = task.Result; string expectedFormat = "length: 5 msg: {0:X2} 64 00 00 00"; IEnumerable <string> expected = Enumerable.Range(0, messageCount).Select(i => string.Format(expectedFormat, i)); result.AssetTimeout(false); result.AssetOutput(expected.ToArray()); result.AssetErrors(); }
/// <summary> /// Returns a base64 encoded version of the config /// </summary> /// <returns></returns> public string ToBase64() { NetworkConfig config = this; using (var buffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteUInt16Packed(config.ProtocolVersion); writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count); for (int i = 0; i < config.RegisteredScenes.Count; i++) { writer.WriteString(config.RegisteredScenes[i]); } writer.WriteInt32Packed(config.ReceiveTickrate); writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate); writer.WriteInt32Packed(config.EventTickrate); writer.WriteInt32Packed(config.ClientConnectionBufferTimeout); writer.WriteBool(config.ConnectionApproval); writer.WriteInt32Packed(config.SecondsHistory); writer.WriteInt32Packed(config.LoadSceneTimeOut); writer.WriteBool(config.EnableTimeResync); writer.WriteBool(config.EnsureNetworkVariableLengthSafety); writer.WriteBits((byte)config.RpcHashSize, 2); writer.WriteBool(ForceSamePrefabs); writer.WriteBool(UsePrefabSync); writer.WriteBool(EnableSceneManagement); writer.WriteBool(RecycleNetworkIds); writer.WriteSinglePacked(NetworkIdRecycleDelay); writer.WriteBool(EnableNetworkVariable); writer.WriteBool(AllowRuntimeSceneChanges); writer.WriteBool(EnableNetworkLogs); buffer.PadBuffer(); return(Convert.ToBase64String(buffer.ToArray())); } }
public void PoolReUsesWritersUpToSizeLimit() { NetworkWriterPool.Capacity = 1; // get 2 writers PooledNetworkWriter a = NetworkWriterPool.GetWriter(); PooledNetworkWriter b = NetworkWriterPool.GetWriter(); // recycle all NetworkWriterPool.Recycle(a); NetworkWriterPool.Recycle(b); // get 2 new ones PooledNetworkWriter c = NetworkWriterPool.GetWriter(); PooledNetworkWriter d = NetworkWriterPool.GetWriter(); // exactly one should be reused, one should be new bool cReused = c == a || c == b; bool dReused = d == a || d == b; Assert.That((cReused && !dReused) || (!cReused && dReused)); }
public void MessageIsBitPacked() { var inStruct = new BitPackStruct { myValue = value, }; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // generic write, uses generated function that should include bitPacking writer.Write(inStruct); Assert.That(writer.BitPosition, Is.EqualTo(32)); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment(), null)) { var outStruct = reader.Read <BitPackStruct>(); Assert.That(reader.BitPosition, Is.EqualTo(32)); Assert.That(outStruct, Is.EqualTo(inStruct)); } } }
/// <summary> /// Shows a list of previously hidden objects to a client /// </summary> /// <param name="networkObjects">The objects to show</param> /// <param name="clientId">The client to show the objects to</param> /// <param name="payload">An optional payload to send as part of the spawns</param> public static void NetworkShow(List <NetworkObject> networkObjects, ulong clientId, Stream payload = null) { if (!NetworkManager.Singleton.IsServer) { throw new NotServerException("Only server can change visibility"); } // Do the safety loop first to prevent putting the MLAPI in an invalid state. for (int i = 0; i < networkObjects.Count; i++) { if (!networkObjects[i].IsSpawned) { throw new SpawnStateException("Object is not spawned"); } if (networkObjects[i].m_Observers.Contains(clientId)) { throw new VisibilityChangeException($"{nameof(NetworkObject)} with NetworkId: {networkObjects[i].NetworkObjectId} is already visible"); } } using (var buffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteUInt16Packed((ushort)networkObjects.Count); for (int i = 0; i < networkObjects.Count; i++) { // Send spawn call networkObjects[i].m_Observers.Add(clientId); NetworkSpawnManager.WriteSpawnCallForObject(buffer, clientId, networkObjects[i], payload); } InternalMessageSender.Send(clientId, NetworkConstants.ADD_OBJECTS, NetworkChannel.Internal, buffer); } }
/// <summary> /// Reply to the client to inform it of this server /// </summary> /// <remarks> /// Override if you wish to ignore server requests based on /// custom criteria such as language, full server game mode or difficulty /// </remarks> /// <param name="request">Request comming from client</param> /// <param name="endpoint">Address of the client that sent the request</param> protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint) { Response info = ProcessRequest(request, endpoint); if (info == null) { return; } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { try { writer.WriteInt64(secretHandshake); writer.Write(info); ArraySegment <byte> data = writer.ToArraySegment(); // signature matches // send response serverUdpClient.Send(data.Array, data.Count, endpoint); } catch (Exception ex) { Debug.LogException(ex, this); } } }
internal void ChangeOwnership(NetworkObject networkObject, ulong clientId) { if (!NetworkManager.IsServer) { throw new NotServerException("Only the server can change ownership"); } if (!networkObject.IsSpawned) { throw new SpawnStateException("Object is not spawned"); } if (NetworkManager.ConnectedClients.TryGetValue(networkObject.OwnerClientId, out NetworkClient networkClient)) { for (int i = networkClient.OwnedObjects.Count - 1; i >= 0; i--) { if (networkClient.OwnedObjects[i] == networkObject) { networkClient.OwnedObjects.RemoveAt(i); } } networkClient.OwnedObjects.Add(networkObject); } networkObject.OwnerClientId = clientId; using (var buffer = PooledNetworkBuffer.Get()) using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteUInt64Packed(networkObject.NetworkObjectId); writer.WriteUInt64Packed(clientId); NetworkManager.MessageSender.Send(NetworkConstants.CHANGE_OWNER, NetworkChannel.Internal, buffer); } }
internal static void OnDestroyObject(ulong networkId, bool destroyGameObject) { if (ReferenceEquals(NetworkManager.Singleton, null)) { return; } //Removal of spawned object if (!SpawnedObjects.ContainsKey(networkId)) { Debug.LogWarning($"Trying to destroy object {networkId} but it doesn't seem to exist anymore!"); return; } var sobj = SpawnedObjects[networkId]; if (!sobj.IsOwnedByServer && !sobj.IsPlayerObject && NetworkManager.Singleton.ConnectedClients.ContainsKey(sobj.OwnerClientId)) { //Someone owns it. for (int i = NetworkManager.Singleton.ConnectedClients[sobj.OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkManager.Singleton.ConnectedClients[sobj.OwnerClientId].OwnedObjects[i].NetworkObjectId == networkId) { NetworkManager.Singleton.ConnectedClients[sobj.OwnerClientId].OwnedObjects.RemoveAt(i); } } } sobj.IsSpawned = false; if (NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer) { if (NetworkManager.Singleton.NetworkConfig.RecycleNetworkIds) { ReleasedNetworkObjectIds.Enqueue(new ReleasedNetworkId() { NetworkId = networkId, ReleaseTime = Time.unscaledTime }); } var rpcQueueContainer = NetworkManager.Singleton.RpcQueueContainer; if (rpcQueueContainer != null) { if (!ReferenceEquals(sobj, null)) { // As long as we have any remaining clients, then notify of the object being destroy. if (NetworkManager.Singleton.ConnectedClientsList.Count > 0) { var buffer = PooledNetworkBuffer.Get(); using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteUInt64Packed(networkId); var queueItem = new RpcFrameQueueItem { UpdateStage = NetworkUpdateStage.PostLateUpdate, QueueItemType = RpcQueueContainer.QueueItemType.DestroyObject, NetworkId = networkId, NetworkBuffer = buffer, NetworkChannel = NetworkChannel.Internal, ClientNetworkIds = NetworkManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray() }; rpcQueueContainer.AddToInternalMLAPISendQueue(queueItem); } } } } } var gobj = sobj.gameObject; if (destroyGameObject && !ReferenceEquals(gobj, null)) { if (CustomDestroyHandlers.ContainsKey(sobj.PrefabHash)) { CustomDestroyHandlers[sobj.PrefabHash](sobj); OnDestroyObject(networkId, false); } else { MonoBehaviour.Destroy(gobj); } } // for some reason, we can get down here and SpawnedObjects for this // networkId will no longer be here, even as we check this at the start // of the function if (SpawnedObjects.ContainsKey(networkId)) { SpawnedObjectsList.Remove(sobj); SpawnedObjects.Remove(networkId); } }
internal static void WriteSpawnCallForObject(Serialization.NetworkBuffer buffer, ulong clientId, NetworkObject networkObject, Stream payload) { using (var writer = PooledNetworkWriter.Get(buffer)) { writer.WriteBool(networkObject.IsPlayerObject); writer.WriteUInt64Packed(networkObject.NetworkObjectId); writer.WriteUInt64Packed(networkObject.OwnerClientId); NetworkObject parentNetworkObject = null; if (!networkObject.AlwaysReplicateAsRoot && !ReferenceEquals(networkObject.transform.parent, null)) { parentNetworkObject = networkObject.transform.parent.GetComponent <NetworkObject>(); } if (ReferenceEquals(parentNetworkObject, null)) { writer.WriteBool(false); } else { writer.WriteBool(true); writer.WriteUInt64Packed(parentNetworkObject.NetworkObjectId); } if (!NetworkManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkManager.Singleton.NetworkConfig.UsePrefabSync) { writer.WriteUInt64Packed(networkObject.PrefabHash); } else { writer.WriteBool(networkObject.IsSceneObject ?? true); if (networkObject.IsSceneObject == null || networkObject.IsSceneObject.Value) { writer.WriteUInt64Packed(networkObject.NetworkInstanceId); } else { writer.WriteUInt64Packed(networkObject.PrefabHash); } } if (networkObject.IncludeTransformWhenSpawning == null || networkObject.IncludeTransformWhenSpawning(clientId)) { writer.WriteBool(true); writer.WriteSinglePacked(networkObject.transform.position.x); writer.WriteSinglePacked(networkObject.transform.position.y); writer.WriteSinglePacked(networkObject.transform.position.z); writer.WriteSinglePacked(networkObject.transform.rotation.eulerAngles.x); writer.WriteSinglePacked(networkObject.transform.rotation.eulerAngles.y); writer.WriteSinglePacked(networkObject.transform.rotation.eulerAngles.z); } else { writer.WriteBool(false); } writer.WriteBool(payload != null); if (payload != null) { writer.WriteInt32Packed((int)payload.Length); } if (NetworkManager.Singleton.NetworkConfig.EnableNetworkVariable) { networkObject.WriteNetworkVariableData(buffer, clientId); } if (payload != null) { buffer.CopyFrom(payload); } } }
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(); }