// Ran on both server and client internal static void SpawnNetworkedObjectLocally(NetworkedObject netObject, ulong networkId, bool sceneObject, bool playerObject, ulong?ownerClientId, Stream dataStream, bool readPayload, int payloadLength, bool readNetworkedVar, bool destroyWithScene) { if (netObject == null) { throw new ArgumentNullException(nameof(netObject), "Cannot spawn null object"); } if (netObject.IsSpawned) { throw new SpawnStateException("Object is already spawned"); } if (readNetworkedVar && NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar) { netObject.SetNetworkedVarData(dataStream); netObject.SetSyncedVarData(dataStream); } netObject.IsSpawned = true; netObject.IsSceneObject = sceneObject; netObject.NetworkId = networkId; netObject.DestroyWithScene = sceneObject || destroyWithScene; netObject._ownerClientId = ownerClientId; netObject.IsPlayerObject = playerObject; SpawnedObjects.Add(netObject.NetworkId, netObject); SpawnedObjectsList.Add(netObject); if (ownerClientId != null) { if (NetworkingManager.Singleton.IsServer) { if (playerObject) { NetworkingManager.Singleton.ConnectedClients[ownerClientId.Value].PlayerObject = netObject; } else { NetworkingManager.Singleton.ConnectedClients[ownerClientId.Value].OwnedObjects.Add(netObject); } } else if (playerObject && ownerClientId.Value == NetworkingManager.Singleton.LocalClientId) { NetworkingManager.Singleton.ConnectedClients[ownerClientId.Value].PlayerObject = netObject; } } if (NetworkingManager.Singleton.IsServer) { for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++) { if (netObject.CheckObjectVisibility == null || netObject.CheckObjectVisibility(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId)) { netObject.observers.Add(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId); } } } netObject.ResetNetworkedStartInvoked(); if (readPayload) { using (PooledBitStream payloadStream = PooledBitStream.Get()) { payloadStream.CopyUnreadFrom(dataStream, payloadLength); dataStream.Position += payloadLength; payloadStream.Position = 0; netObject.InvokeBehaviourNetworkSpawn(payloadStream); } } else { netObject.InvokeBehaviourNetworkSpawn(null); } }
internal static void OnDestroyObject(ulong networkId, bool destroyGameObject) { if (NetworkingManager.Singleton == null) { return; } //Removal of spawned object if (!SpawnedObjects.ContainsKey(networkId)) { return; } if (!SpawnedObjects[networkId].IsOwnedByServer && !SpawnedObjects[networkId].IsPlayerObject && NetworkingManager.Singleton.ConnectedClients.ContainsKey(SpawnedObjects[networkId].OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAt(i); } } } SpawnedObjects[networkId].IsSpawned = false; if (NetworkingManager.Singleton != null && NetworkingManager.Singleton.IsServer) { if (NetworkingManager.Singleton.NetworkConfig.RecycleNetworkIds) { releasedNetworkObjectIds.Enqueue(new ReleasedNetworkId() { NetworkId = networkId, ReleaseTime = Time.unscaledTime }); } if (SpawnedObjects[networkId] != null) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt64Packed(networkId); InternalMessageSender.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, SpawnedObjects[networkId]); } } } } GameObject go = SpawnedObjects[networkId].gameObject; if (destroyGameObject && go != null) { if (customDestroyHandlers.ContainsKey(SpawnedObjects[networkId].PrefabHash)) { customDestroyHandlers[SpawnedObjects[networkId].PrefabHash](SpawnedObjects[networkId]); SpawnManager.OnDestroyObject(networkId, false); } else { MonoBehaviour.Destroy(go); } } SpawnedObjects.Remove(networkId); for (int i = SpawnedObjectsList.Count - 1; i > -1; i--) { if (SpawnedObjectsList[i].NetworkId == networkId) { SpawnedObjectsList.RemoveAt(i); } } }
private static void OnSceneUnloadServer(Guid switchSceneGuid) { // Justification: Rare alloc, could(should?) reuse List <NetworkedObject> newSceneObjects = new List <NetworkedObject>(); { NetworkedObject[] networkedObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); for (int i = 0; i < networkedObjects.Length; i++) { if (networkedObjects[i].IsSceneObject == null) { SpawnManager.SpawnNetworkedObjectLocally(networkedObjects[i], SpawnManager.GetNetworkObjectId(), true, false, null, null, false, 0, false, true); newSceneObjects.Add(networkedObjects[i]); } } } for (int j = 0; j < NetworkingManager.Singleton.ConnectedClientsList.Count; j++) { if (NetworkingManager.Singleton.ConnectedClientsList[j].ClientId != NetworkingManager.Singleton.ServerClientId) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(CurrentActiveSceneIndex); writer.WriteByteArray(switchSceneGuid.ToByteArray()); uint sceneObjectsToSpawn = 0; for (int i = 0; i < newSceneObjects.Count; i++) { if (newSceneObjects[i].observers.Contains(NetworkingManager.Singleton.ConnectedClientsList[j].ClientId)) { sceneObjectsToSpawn++; } } writer.WriteUInt32Packed(sceneObjectsToSpawn); for (int i = 0; i < newSceneObjects.Count; i++) { if (newSceneObjects[i].observers.Contains(NetworkingManager.Singleton.ConnectedClientsList[j].ClientId)) { writer.WriteBool(newSceneObjects[i].IsPlayerObject); writer.WriteUInt64Packed(newSceneObjects[i].NetworkId); writer.WriteUInt64Packed(newSceneObjects[i].OwnerClientId); NetworkedObject parent = null; if (!newSceneObjects[i].AlwaysReplicateAsRoot && newSceneObjects[i].transform.parent != null) { parent = newSceneObjects[i].transform.parent.GetComponent <NetworkedObject>(); } if (parent == null) { writer.WriteBool(false); } else { writer.WriteBool(true); writer.WriteUInt64Packed(parent.NetworkId); } if (!NetworkingManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkingManager.Singleton.NetworkConfig.UsePrefabSync) { writer.WriteUInt64Packed(newSceneObjects[i].PrefabHash); writer.WriteSinglePacked(newSceneObjects[i].transform.position.x); writer.WriteSinglePacked(newSceneObjects[i].transform.position.y); writer.WriteSinglePacked(newSceneObjects[i].transform.position.z); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.x); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.y); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.z); } else { writer.WriteUInt64Packed(newSceneObjects[i].NetworkedInstanceId); } if (NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar) { newSceneObjects[i].WriteNetworkedVarData(stream, NetworkingManager.Singleton.ConnectedClientsList[j].ClientId); } } } } InternalMessageSender.Send(NetworkingManager.Singleton.ConnectedClientsList[j].ClientId, MLAPIConstants.MLAPI_SWITCH_SCENE, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null); } } } //Tell server that scene load is completed if (NetworkingManager.Singleton.IsHost) { OnClientSwitchSceneCompleted(NetworkingManager.Singleton.LocalClientId, switchSceneGuid); } isSwitching = false; if (OnSceneSwitched != null) { OnSceneSwitched(); } }
private static void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) { if (!NetworkingManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkingManager.Singleton.NetworkConfig.UsePrefabSync) { SpawnManager.DestroySceneObjects(); using (PooledBitReader reader = PooledBitReader.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()); } NetworkedObject networkedObject = SpawnManager.CreateLocalNetworkedObject(false, 0, prefabHash, parentNetworkId, position, rotation); SpawnManager.SpawnNetworkedObjectLocally(networkedObject, networkId, true, isPlayerObject, owner, objectStream, false, 0, true, false); } } } else { NetworkedObject[] networkedObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); SpawnManager.ClientCollectSoftSyncSceneObjectSweep(networkedObjects); using (PooledBitReader reader = PooledBitReader.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(); NetworkedObject networkedObject = SpawnManager.CreateLocalNetworkedObject(true, instanceId, 0, parentNetworkId, null, null); SpawnManager.SpawnNetworkedObjectLocally(networkedObject, networkId, true, isPlayerObject, owner, objectStream, false, 0, true, false); } } } using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteByteArray(switchSceneGuid.ToByteArray()); NetworkedObject networkedObject = null; InternalMessageSender.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CLIENT_SWITCH_SCENE_COMPLETED, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, networkedObject); } } isSwitching = false; if (OnSceneSwitched != null) { OnSceneSwitched(); } }
// This method is responsible for unwrapping a message, that is extracting the messagebody. // Could include decrypting and/or authentication. internal static BitStream UnwrapMessage(BitStream inputStream, uint clientId, out byte messageType) { using (PooledBitReader inputHeaderReader = PooledBitReader.Get(inputStream)) { try { bool isEncrypted = inputHeaderReader.ReadBit(); bool isAuthenticated = inputHeaderReader.ReadBit(); #if !DISABLE_CRYPTOGRAPHY if (isEncrypted || isAuthenticated) { if (!NetworkingManager.singleton.NetworkConfig.EnableEncryption) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Got a encrypted and/or authenticated message but key exchange (\"encryption\") was not enabled"); } messageType = MLAPIConstants.INVALID; return(null); } // Skip last bits in first byte inputHeaderReader.SkipPadBits(); if (isAuthenticated) { long hmacStartPos = inputStream.Position; int readHmacLength = inputStream.Read(HMAC_BUFFER, 0, HMAC_BUFFER.Length); if (readHmacLength != HMAC_BUFFER.Length) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("HMAC length was invalid"); } messageType = MLAPIConstants.INVALID; return(null); } // Now we have read the HMAC, we need to set the hmac in the input to 0s to perform the HMAC. inputStream.Position = hmacStartPos; inputStream.Write(HMAC_PLACEHOLDER, 0, HMAC_PLACEHOLDER.Length); byte[] key = NetworkingManager.singleton.isServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey(); if (key == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Failed to grab key"); } messageType = MLAPIConstants.INVALID; return(null); } using (HMACSHA256 hmac = new HMACSHA256(key)) { byte[] computedHmac = hmac.ComputeHash(inputStream.GetBuffer(), 0, (int)inputStream.Length); for (int i = 0; i < computedHmac.Length; i++) { if (computedHmac[i] != HMAC_BUFFER[i]) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Received HMAC at position [" + i + "] did not match the computed HMAC"); } messageType = MLAPIConstants.INVALID; return(null); } } } } if (isEncrypted) { inputStream.Read(IV_BUFFER, 0, IV_BUFFER.Length); PooledBitStream outputStream = PooledBitStream.Get(); using (RijndaelManaged rijndael = new RijndaelManaged()) { rijndael.IV = IV_BUFFER; rijndael.Padding = PaddingMode.PKCS7; byte[] key = NetworkingManager.singleton.isServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey(); if (key == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Failed to grab key"); } messageType = MLAPIConstants.INVALID; return(null); } rijndael.Key = key; using (CryptoStream cryptoStream = new CryptoStream(outputStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(inputStream.GetBuffer(), (int)inputStream.Position, (int)(inputStream.Length - inputStream.Position)); } outputStream.Position = 0; int msgType = outputStream.ReadByte(); messageType = msgType == -1 ? MLAPIConstants.INVALID : (byte)msgType; } return(outputStream); } else { int msgType = inputStream.ReadByte(); messageType = msgType == -1 ? MLAPIConstants.INVALID : (byte)msgType; return(inputStream); } } else { #endif messageType = inputHeaderReader.ReadByteBits(6); // The input stream is now ready to be read from. It's "safe" and has the correct position return(inputStream); #if !DISABLE_CRYPTOGRAPHY } #endif } catch (Exception e) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogError("Error while unwrapping headers"); } if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError(e.ToString()); } messageType = MLAPIConstants.INVALID; return(null); } } }
// Runs on client internal static void HandleHailRequest(ulong clientId, Stream stream) { X509Certificate2 certificate = null; byte[] serverDiffieHellmanPublicPart = null; using (PooledBitReader reader = PooledBitReader.Get(stream)) { if (NetworkingManager.Singleton.NetworkConfig.EnableEncryption) { // Read the certificate if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange) { // Allocation justification: This runs on client and only once, at initial connection certificate = new X509Certificate2(reader.ReadByteArray()); if (CryptographyHelper.VerifyCertificate(certificate, NetworkingManager.Singleton.ConnectedHostname)) { // The certificate is not valid :( // Man in the middle. if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Invalid certificate. Disconnecting"); } NetworkingManager.Singleton.StopClient(); return; } else { NetworkingManager.Singleton.NetworkConfig.ServerX509Certificate = certificate; } } // Read the ECDH // Allocation justification: This runs on client and only once, at initial connection serverDiffieHellmanPublicPart = reader.ReadByteArray(); // Verify the key exchange if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange) { int signatureType = reader.ReadByte(); byte[] serverDiffieHellmanPublicPartSignature = reader.ReadByteArray(); if (signatureType == 0) { RSACryptoServiceProvider rsa = certificate.PublicKey.Key as RSACryptoServiceProvider; if (rsa != null) { using (SHA256Managed sha = new SHA256Managed()) { if (!rsa.VerifyData(serverDiffieHellmanPublicPart, sha, serverDiffieHellmanPublicPartSignature)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Invalid RSA signature. Disconnecting"); } NetworkingManager.Singleton.StopClient(); return; } } } else { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("No RSA key found in certificate. Disconnecting"); } NetworkingManager.Singleton.StopClient(); return; } } else if (signatureType == 1) { DSACryptoServiceProvider dsa = certificate.PublicKey.Key as DSACryptoServiceProvider; if (dsa != null) { using (SHA256Managed sha = new SHA256Managed()) { if (!dsa.VerifyData(sha.ComputeHash(serverDiffieHellmanPublicPart), serverDiffieHellmanPublicPartSignature)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Invalid DSA signature. Disconnecting"); } NetworkingManager.Singleton.StopClient(); return; } } } else { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("No DSA key found in certificate. Disconnecting"); } NetworkingManager.Singleton.StopClient(); return; } } else { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Invalid signature type. Disconnecting"); } NetworkingManager.Singleton.StopClient(); return; } } } } using (PooledBitStream outStream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(outStream)) { if (NetworkingManager.Singleton.NetworkConfig.EnableEncryption) { // Create a ECDH key EllipticDiffieHellman diffieHellman = new EllipticDiffieHellman(EllipticDiffieHellman.DEFAULT_CURVE, EllipticDiffieHellman.DEFAULT_GENERATOR, EllipticDiffieHellman.DEFAULT_ORDER); NetworkingManager.Singleton.clientAesKey = diffieHellman.GetSharedSecret(serverDiffieHellmanPublicPart); byte[] diffieHellmanPublicKey = diffieHellman.GetPublicKey(); writer.WriteByteArray(diffieHellmanPublicKey); } } // Send HailResponse InternalMessageSender.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CERTIFICATE_HAIL_RESPONSE, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, null, true); } }
// Ran on server internal static void HandleHailResponse(ulong clientId, Stream stream) { if (!NetworkingManager.Singleton.PendingClients.ContainsKey(clientId) || NetworkingManager.Singleton.PendingClients[clientId].ConnectionState != PendingClient.State.PendingHail) { return; } if (!NetworkingManager.Singleton.NetworkConfig.EnableEncryption) { return; } using (PooledBitReader reader = PooledBitReader.Get(stream)) { if (NetworkingManager.Singleton.PendingClients[clientId].KeyExchange != null) { byte[] diffieHellmanPublic = reader.ReadByteArray(); NetworkingManager.Singleton.PendingClients[clientId].AesKey = NetworkingManager.Singleton.PendingClients[clientId].KeyExchange.GetSharedSecret(diffieHellmanPublic); if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange) { byte[] diffieHellmanPublicSignature = reader.ReadByteArray(); X509Certificate2 certificate = NetworkingManager.Singleton.NetworkConfig.ServerX509Certificate; RSACryptoServiceProvider rsa = certificate.PrivateKey as RSACryptoServiceProvider; if (rsa != null) { using (SHA256Managed sha = new SHA256Managed()) { byte[] clientHash = rsa.Decrypt(diffieHellmanPublicSignature, false); byte[] serverHash = sha.ComputeHash(diffieHellmanPublic); if (!CryptographyHelper.ConstTimeArrayEqual(clientHash, serverHash)) { //Man in the middle. if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Signature doesnt match for the key exchange public part. Disconnecting"); } } NetworkingManager.Singleton.DisconnectClient(clientId); return; } } } else { throw new CryptographicException("[MLAPI] Only RSA certificates are supported. No valid RSA key was found"); } } } } NetworkingManager.Singleton.PendingClients[clientId].ConnectionState = PendingClient.State.PendingConnection; NetworkingManager.Singleton.PendingClients[clientId].KeyExchange = null; // Give to GC // Send greetings, they have passed all the handshakes using (PooledBitStream outStream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(outStream)) { writer.WriteInt64Packed(DateTime.Now.Ticks); // This serves no purpose. } InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_GREETINGS, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, null, true); } }
internal static BitStream WrapMessage(byte messageType, uint clientId, BitStream messageBody, SecuritySendFlags flags) { try { bool encrypted = ((flags & SecuritySendFlags.Encrypted) == SecuritySendFlags.Encrypted) && NetworkingManager.singleton.NetworkConfig.EnableEncryption; bool authenticated = (flags & SecuritySendFlags.Authenticated) == SecuritySendFlags.Authenticated && NetworkingManager.singleton.NetworkConfig.EnableEncryption; PooledBitStream outStream = PooledBitStream.Get(); using (PooledBitWriter outWriter = PooledBitWriter.Get(outStream)) { outWriter.WriteBit(encrypted); outWriter.WriteBit(authenticated); #if !DISABLE_CRYPTOGRAPHY if (authenticated || encrypted) { outWriter.WritePadBits(); long hmacWritePos = outStream.Position; if (authenticated) { outStream.Write(HMAC_PLACEHOLDER, 0, HMAC_PLACEHOLDER.Length); } if (encrypted) { using (RijndaelManaged rijndael = new RijndaelManaged()) { rijndael.GenerateIV(); rijndael.Padding = PaddingMode.PKCS7; byte[] key = NetworkingManager.singleton.isServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey(); if (key == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Failed to grab key"); } return(null); } rijndael.Key = key; outStream.Write(rijndael.IV); using (CryptoStream encryptionStream = new CryptoStream(outStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write)) { encryptionStream.WriteByte(messageType); encryptionStream.Write(messageBody.GetBuffer(), 0, (int)messageBody.Length); } } } else { outStream.WriteByte(messageType); outStream.Write(messageBody.GetBuffer(), 0, (int)messageBody.Length); } if (authenticated) { byte[] key = NetworkingManager.singleton.isServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey(); if (key == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Failed to grab key"); } return(null); } using (HMACSHA256 hmac = new HMACSHA256(key)) { byte[] computedHmac = hmac.ComputeHash(outStream.GetBuffer(), 0, (int)outStream.Length); outStream.Position = hmacWritePos; outStream.Write(computedHmac, 0, computedHmac.Length); } } } else { #endif outWriter.WriteBits(messageType, 6); outStream.Write(messageBody.GetBuffer(), 0, (int)messageBody.Length); #if !DISABLE_CRYPTOGRAPHY } #endif } return(outStream); } catch (Exception e) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogError("Error while wrapping headers"); } if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError(e.ToString()); } return(null); } }
internal static void SpawnObject(NetworkedObject netObject, uint?clientOwnerId = null, Stream payload = null, bool destroyWithScene = false) { if (netObject.IsSpawned) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Object already spawned"); } return; } else if (!netManager.IsServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Only server can spawn objects"); } return; } else if (SpawnManager.GetNetworkedPrefabIndexOfName(netObject.NetworkedPrefabName) == -1) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The prefab name " + netObject.NetworkedPrefabName + " does not exist as a networkedPrefab"); } return; } else if (!netManager.NetworkConfig.HandleObjectSpawning) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("NetworkConfig is set to not handle object spawning"); } return; } uint netId = GetNetworkObjectId(); netObject.NetworkId = netId; SpawnedObjects.Add(netId, netObject); SpawnedObjectsList.Add(netObject); netObject.IsSpawned = true; netObject.destroyWithScene = destroyWithScene; netObject.sceneSpawnedInIndex = NetworkSceneManager.CurrentActiveSceneIndex; if (clientOwnerId != null) { netObject.OwnerClientId = clientOwnerId.Value; NetworkingManager.Singleton.ConnectedClients[clientOwnerId.Value].OwnedObjects.Add(netObject); } if (payload == null) { netObject.InvokeBehaviourNetworkSpawn(null); } else { netObject.InvokeBehaviourNetworkSpawn(payload); } foreach (var client in netManager.ConnectedClients) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteBool(false); writer.WriteUInt32Packed(netObject.NetworkId); writer.WriteUInt32Packed(netObject.OwnerClientId); writer.WriteUInt64Packed(netObject.NetworkedPrefabHash); writer.WriteBool(netObject.destroyWithScene == null ? true : netObject.destroyWithScene.Value); writer.WriteBool(netObject.SceneDelayedSpawn); writer.WriteUInt32Packed(netObject.sceneSpawnedInIndex); writer.WriteSinglePacked(netObject.transform.position.x); writer.WriteSinglePacked(netObject.transform.position.y); writer.WriteSinglePacked(netObject.transform.position.z); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); if (payload != null) { writer.WriteInt32Packed((int)payload.Length); } netObject.WriteNetworkedVarData(stream, client.Key); if (payload != null) { stream.CopyFrom(payload); } InternalMessageHandler.Send(client.Key, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } } }
internal static void OnDestroyObject(uint networkId, bool destroyGameObject) { if ((netManager == null || !netManager.NetworkConfig.HandleObjectSpawning)) { return; } //Removal of pending object //Even though pending objects is marked with DontDestroyOnLoad, the OnDestroy method is invoked on pending objects. They are however not //destroyed (probably a unity bug for having an gameobject spawned as inactive). Therefore we only actual remove it from the list if //destroyGameObject is set to true, meaning MLAPI decided to destroy it, not unity. if (destroyGameObject == true && PendingSpawnObjects.ContainsKey(networkId)) { if (!PendingSpawnObjects[networkId].netObject.IsOwnedByServer && !PendingSpawnObjects[networkId].netObject.IsPlayerObject && netManager.ConnectedClients.ContainsKey(PendingSpawnObjects[networkId].netObject.OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.Singleton.ConnectedClients[PendingSpawnObjects[networkId].netObject.OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.Singleton.ConnectedClients[PendingSpawnObjects[networkId].netObject.OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.Singleton.ConnectedClients[PendingSpawnObjects[networkId].netObject.OwnerClientId].OwnedObjects.RemoveAt(i); } } } GameObject pendingGameObject = PendingSpawnObjects[networkId].netObject.gameObject; if (pendingGameObject != null) { MonoBehaviour.Destroy(pendingGameObject); } PendingSpawnObjects.Remove(networkId); } //Removal of spawned object if (!SpawnedObjects.ContainsKey(networkId)) { return; } if (!SpawnedObjects[networkId].IsOwnedByServer && !SpawnedObjects[networkId].IsPlayerObject && netManager.ConnectedClients.ContainsKey(SpawnedObjects[networkId].OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAt(i); } } } SpawnedObjects[networkId].IsSpawned = false; if (netManager != null && netManager.IsServer) { releasedNetworkObjectIds.Push(networkId); if (SpawnedObjects[networkId] != null) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(networkId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } } } GameObject go = SpawnedObjects[networkId].gameObject; if (destroyGameObject && go != null) { MonoBehaviour.Destroy(go); } SpawnedObjects.Remove(networkId); for (int i = SpawnedObjectsList.Count - 1; i > -1; i--) { if (SpawnedObjectsList[i].NetworkId == networkId) { SpawnedObjectsList.RemoveAt(i); } } }
internal static NetworkedObject CreateSpawnedObject(int networkedPrefabId, uint networkId, uint owner, bool playerObject, uint sceneSpawnedInIndex, bool sceneDelayedSpawn, bool destroyWithScene, Vector3?position, Quaternion?rotation, bool isActive, Stream stream, bool readPayload, int payloadLength, bool readNetworkedVar) { if (networkedPrefabId >= netManager.NetworkConfig.NetworkedPrefabs.Count || networkedPrefabId < 0) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot spawn the object, invalid prefabIndex: " + networkedPrefabId); } return(null); } //Delayed spawning if (sceneDelayedSpawn && sceneSpawnedInIndex != NetworkSceneManager.CurrentActiveSceneIndex) { GameObject prefab = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab; bool prefabActive = prefab.activeSelf; prefab.SetActive(false); GameObject go = (position == null && rotation == null) ? MonoBehaviour.Instantiate(prefab) : MonoBehaviour.Instantiate(prefab, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity)); prefab.SetActive(prefabActive); //Appearantly some wierd behavior when switching scenes can occur that destroys this object even though the scene is //not destroyed, therefor we set it to DontDestroyOnLoad here, to prevent that problem. MonoBehaviour.DontDestroyOnLoad(go); NetworkedObject netObject = go.GetComponent <NetworkedObject>(); if (netObject == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Please add a NetworkedObject component to the root of all spawnable objects"); } netObject = go.AddComponent <NetworkedObject>(); } netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].name; netObject.IsSpawned = false; netObject.IsPooledObject = false; if (netManager.IsServer) { netObject.NetworkId = GetNetworkObjectId(); } else { netObject.NetworkId = networkId; } netObject.destroyWithScene = destroyWithScene; netObject.OwnerClientId = owner; netObject.IsPlayerObject = playerObject; netObject.SceneDelayedSpawn = sceneDelayedSpawn; netObject.sceneSpawnedInIndex = sceneSpawnedInIndex; Dictionary <ushort, List <INetworkedVar> > dummyNetworkedVars = new Dictionary <ushort, List <INetworkedVar> >(); List <NetworkedBehaviour> networkedBehaviours = new List <NetworkedBehaviour>(netObject.GetComponentsInChildren <NetworkedBehaviour>()); for (ushort i = 0; i < networkedBehaviours.Count; i++) { dummyNetworkedVars.Add(i, networkedBehaviours[i].GetDummyNetworkedVars()); } PendingSpawnObject pso = new PendingSpawnObject() { netObject = netObject, dummyNetworkedVars = dummyNetworkedVars, sceneSpawnedInIndex = sceneSpawnedInIndex, playerObject = playerObject, owner = owner, isActive = isActive, payload = null }; PendingSpawnObjects.Add(netObject.NetworkId, pso); pso.SetNetworkedVarData(stream); if (readPayload) { MLAPI.Serialization.BitStream payloadStream = new MLAPI.Serialization.BitStream(); payloadStream.CopyUnreadFrom(stream, payloadLength); stream.Position += payloadLength; pso.payload = payloadStream; } return(netObject); } //Normal spawning { GameObject prefab = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab; GameObject go = (position == null && rotation == null) ? MonoBehaviour.Instantiate(prefab) : MonoBehaviour.Instantiate(prefab, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity)); NetworkedObject netObject = go.GetComponent <NetworkedObject>(); if (netObject == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Please add a NetworkedObject component to the root of all spawnable objects"); } netObject = go.AddComponent <NetworkedObject>(); } if (readNetworkedVar) { netObject.SetNetworkedVarData(stream); } netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].name; netObject.IsSpawned = true; netObject.IsPooledObject = false; if (netManager.IsServer) { netObject.NetworkId = GetNetworkObjectId(); } else { netObject.NetworkId = networkId; } netObject.destroyWithScene = destroyWithScene; netObject.OwnerClientId = owner; netObject.IsPlayerObject = playerObject; netObject.SceneDelayedSpawn = sceneDelayedSpawn; netObject.sceneSpawnedInIndex = sceneSpawnedInIndex; SpawnedObjects.Add(netObject.NetworkId, netObject); SpawnedObjectsList.Add(netObject); if (playerObject) { NetworkingManager.Singleton.ConnectedClients[owner].PlayerObject = netObject; } if (readPayload) { using (PooledBitStream payloadStream = PooledBitStream.Get()) { payloadStream.CopyUnreadFrom(stream, payloadLength); stream.Position += payloadLength; netObject.InvokeBehaviourNetworkSpawn(payloadStream); } } else { netObject.InvokeBehaviourNetworkSpawn(null); } netObject.gameObject.SetActive(isActive); return(netObject); } }
void InvokeApplyTransformOnEveryone(Vector3 position, Quaternion rotation, string channelName) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { if (TransformTypeToSync == TransformType.Transform2D) { if (SyncPosition && SyncRotation) { writer.WriteVector2Packed(position); writer.WriteSinglePacked(rotation.eulerAngles.z); } else if (SyncPosition) { writer.WriteVector2Packed(position); } else if (SyncRotation) { writer.WriteSinglePacked(rotation.eulerAngles.z); } } else if (TransformTypeToSync == TransformType.Transform3D) { if (SyncPosition && SyncRotation) { writer.WriteVector3Packed(position); if (FullRotation) { writer.WriteVector3Packed(rotation.eulerAngles); } else { writer.WriteSinglePacked(rotation.eulerAngles.y); } } else if (SyncPosition) { writer.WriteVector3Packed(position); } else if (SyncRotation) { if (FullRotation) { writer.WriteVector3Packed(rotation.eulerAngles); } else { writer.WriteSinglePacked(rotation.eulerAngles.y); } } } if (EnableMinDistanceBetweenClients) { Vector3?senderPosition = transform.position; for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++) { Vector3?receiverPosition = NetworkingManager.Singleton.ConnectedClientsList[i].PlayerObject == null ? null : new Vector3?(NetworkingManager.Singleton.ConnectedClientsList[i].PlayerObject.transform.position); if (receiverPosition == null || senderPosition == null || Vector3.Distance((Vector3)senderPosition, (Vector3)receiverPosition) < MinDistanceBetweenClients) { InvokeClientRpcOnClientPerformance(TransformTypeToSync == TransformType.Transform2D ? "ApplyTransform2D" : "ApplyTransform", NetworkingManager.Singleton.ConnectedClientsList[i].ClientId, stream, channelName, Security.SecuritySendFlags.None); } } } else { InvokeClientRpcOnEveryonePerformance(TransformTypeToSync == TransformType.Transform2D ? "ApplyTransform2D" : "ApplyTransform", stream, channelName, Security.SecuritySendFlags.None); } } } }
private void Update() { if (!isOwner) { return; } if (agent.destination != lastDestination) { lastDestination = agent.destination; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteSinglePacked(agent.destination.x); writer.WriteSinglePacked(agent.destination.y); writer.WriteSinglePacked(agent.destination.z); writer.WriteSinglePacked(agent.velocity.x); writer.WriteSinglePacked(agent.velocity.y); writer.WriteSinglePacked(agent.velocity.z); writer.WriteSinglePacked(transform.position.x); writer.WriteSinglePacked(transform.position.y); writer.WriteSinglePacked(transform.position.z); if (!EnableProximity) { InvokeClientRpcOnEveryone(OnNavMeshStateUpdate, stream); } else { List <uint> proximityClients = new List <uint>(); foreach (KeyValuePair <uint, NetworkedClient> client in NetworkingManager.singleton.ConnectedClients) { if (Vector3.Distance(client.Value.PlayerObject.transform.position, transform.position) <= ProximityRange) { proximityClients.Add(client.Key); } } InvokeClientRpc(OnNavMeshStateUpdate, proximityClients, stream); } } } } if (NetworkingManager.singleton.NetworkTime - lastCorrectionTime >= CorrectionDelay) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteSinglePacked(agent.velocity.x); writer.WriteSinglePacked(agent.velocity.y); writer.WriteSinglePacked(agent.velocity.z); writer.WriteSinglePacked(transform.position.x); writer.WriteSinglePacked(transform.position.y); writer.WriteSinglePacked(transform.position.z); if (!EnableProximity) { InvokeClientRpcOnEveryone(OnNavMeshCorrectionUpdate, stream); } else { List <uint> proximityClients = new List <uint>(); foreach (KeyValuePair <uint, NetworkedClient> client in NetworkingManager.singleton.ConnectedClients) { if (Vector3.Distance(client.Value.PlayerObject.transform.position, transform.position) <= ProximityRange) { proximityClients.Add(client.Key); } } InvokeClientRpc(OnNavMeshCorrectionUpdate, proximityClients, stream); } } } lastCorrectionTime = NetworkingManager.singleton.NetworkTime; } }
internal static void SpawnObject(NetworkedObject netObject, uint?clientOwnerId = null, Stream payload = null) { if (netObject.isSpawned) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Object already spawned"); } return; } else if (!netManager.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Only server can spawn objects"); } return; } else if (!netManager.NetworkConfig.NetworkPrefabIds.ContainsKey(netObject.NetworkedPrefabName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The prefab name " + netObject.NetworkedPrefabName + " does not exist as a networkedPrefab"); } return; } else if (!netManager.NetworkConfig.HandleObjectSpawning) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("NetworkConfig is set to not handle object spawning"); } return; } uint netId = GetNetworkObjectId(); netObject.NetworkId = netId; SpawnedObjects.Add(netId, netObject); SpawnedObjectsList.Add(netObject); netObject.isSpawned = true; netObject.sceneObject = false; if (clientOwnerId != null) { netObject.OwnerClientId = clientOwnerId.Value; NetworkingManager.singleton.ConnectedClients[clientOwnerId.Value].OwnedObjects.Add(netObject); } if (payload == null) { netObject.InvokeBehaviourNetworkSpawn(null); } else { netObject.InvokeBehaviourNetworkSpawn(payload); } foreach (var client in netManager.ConnectedClients) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteBool(false); writer.WriteUInt32Packed(netObject.NetworkId); writer.WriteUInt32Packed(netObject.OwnerClientId); writer.WriteInt32Packed(netManager.NetworkConfig.NetworkPrefabIds[netObject.NetworkedPrefabName]); writer.WriteBool(netObject.sceneObject == null ? true : netObject.sceneObject.Value); writer.WriteSinglePacked(netObject.transform.position.x); writer.WriteSinglePacked(netObject.transform.position.y); writer.WriteSinglePacked(netObject.transform.position.z); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); netObject.WriteNetworkedVarData(stream, client.Key); if (payload != null) { stream.CopyFrom(payload); } InternalMessageHandler.Send(client.Key, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream); } } } }
private static void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) { if (!NetworkingManager.Singleton.NetworkConfig.EnableSceneManagement || NetworkingManager.Singleton.NetworkConfig.UsePrefabSync) { SpawnManager.DestroySceneObjects(); using (PooledBitReader reader = PooledBitReader.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()); } NetworkedObject networkedObject = SpawnManager.CreateLocalNetworkedObject(false, 0, prefabHash, parentNetworkId, position, rotation); SpawnManager.SpawnNetworkedObjectLocally(networkedObject, networkId, true, isPlayerObject, owner, objectStream, 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(); NetworkingManager.Singleton.HandleIncomingData(message.sender, message.channelName, new ArraySegment <byte>(message.payload.GetBuffer(), (int)message.payload.Position, (int)message.payload.Length), message.receiveTime, false); BufferManager.RecycleConsumedBufferedMessage(message); } } } } } else { NetworkedObject[] networkedObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); SpawnManager.ClientCollectSoftSyncSceneObjectSweep(networkedObjects); using (PooledBitReader reader = PooledBitReader.Get(objectStream)) { uint newObjectsCount = reader.ReadUInt32Packed(); if (LogHelper.CurrentLogLevel <= LogLevel.Developer) { LogHelper.LogInfo("Received " + newObjectsCount + " scene network objects"); } 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(); if (LogHelper.CurrentLogLevel <= LogLevel.Developer) { LogHelper.LogInfo("Creating scene object #" + i + " - " + networkId + ", " + instanceId + ", " + parentNetworkId); } NetworkedObject networkedObject = SpawnManager.CreateLocalNetworkedObject(true, instanceId, 0, parentNetworkId, null, null); SpawnManager.SpawnNetworkedObjectLocally(networkedObject, networkId, true, isPlayerObject, owner, objectStream, 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(); NetworkingManager.Singleton.HandleIncomingData(message.sender, message.channelName, new ArraySegment <byte>(message.payload.GetBuffer(), (int)message.payload.Position, (int)message.payload.Length), message.receiveTime, false); BufferManager.RecycleConsumedBufferedMessage(message); } } } } } using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteByteArray(switchSceneGuid.ToByteArray()); NetworkedObject networkedObject = null; InternalMessageSender.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CLIENT_SWITCH_SCENE_COMPLETED, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, networkedObject); } } isSwitching = false; if (OnSceneSwitched != null) { OnSceneSwitched(); } }