/// <summary> /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance /// </summary> /// <param name="cache"></param> /// <returns></returns> public byte[] GetConfig(bool cache = true) { if (ConfigHash != null && cache) { return(ConfigHash); } using (BitWriter writer = new BitWriter()) { writer.WriteUShort(ProtocolVersion); for (int i = 0; i < Channels.Count; i++) { writer.WriteString(Channels[i].Name); writer.WriteByte((byte)Channels[i].Type); if (EnableEncryption) { writer.WriteBool(Channels[i].Encrypted); } } for (int i = 0; i < MessageTypes.Count; i++) { writer.WriteString(MessageTypes[i].Name); if (AllowPassthroughMessages) { writer.WriteBool(MessageTypes[i].Passthrough); } } if (EnableSceneSwitching) { for (int i = 0; i < RegisteredScenes.Count; i++) { writer.WriteString(RegisteredScenes[i]); } } if (HandleObjectSpawning) { for (int i = 0; i < NetworkedPrefabs.Count; i++) { writer.WriteString(NetworkedPrefabs[i].name); } } writer.WriteBool(HandleObjectSpawning); writer.WriteBool(EnableEncryption); writer.WriteBool(AllowPassthroughMessages); writer.WriteBool(EnableSceneSwitching); writer.WriteBool(SignKeyExchange); //using (SHA256Managed sha256 = new SHA256Managed()) //{ // Returns a 160 bit / 20 byte / 5 int checksum of the config if (cache) { ConfigHash = MessageDigest.SHA1_Opt(writer.Finalize()).ToArray(); //sha256.ComputeHash(writer.Finalize()); return(ConfigHash); } return(MessageDigest.SHA1_Opt(writer.Finalize()).ToArray()); //sha256.ComputeHash(writer.Finalize()); //} } }
/// <summary> /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance /// </summary> /// <param name="cache"></param> /// <returns></returns> public ulong GetConfig(bool cache = true) { if (ConfigHash != null && cache) { return(ConfigHash.Value); } using (BitWriter writer = BitWriter.Get()) { writer.WriteUShort(ProtocolVersion); for (int i = 0; i < Channels.Count; i++) { writer.WriteString(Channels[i].Name); writer.WriteByte((byte)Channels[i].Type); if (EnableEncryption) { writer.WriteBool(Channels[i].Encrypted); } } for (int i = 0; i < MessageTypes.Count; i++) { writer.WriteString(MessageTypes[i].Name); if (AllowPassthroughMessages) { writer.WriteBool(MessageTypes[i].Passthrough); } } if (EnableSceneSwitching) { for (int i = 0; i < RegisteredScenes.Count; i++) { writer.WriteString(RegisteredScenes[i]); } } if (HandleObjectSpawning) { for (int i = 0; i < NetworkedPrefabs.Count; i++) { writer.WriteString(NetworkedPrefabs[i].name); } } writer.WriteBool(HandleObjectSpawning); writer.WriteBool(EnableEncryption); writer.WriteBool(AllowPassthroughMessages); writer.WriteBool(EnableSceneSwitching); writer.WriteBool(SignKeyExchange); writer.WriteBits((byte)AttributeMessageMode, 3); // Returns a 160 bit / 20 byte / 5 int checksum of the config if (cache) { ConfigHash = writer.Finalize().GetStableHash64(); return(ConfigHash.Value); } return(writer.Finalize().GetStableHash64()); } }
/// <summary> /// Switches to a scene with a given name. Can only be called from Server /// </summary> /// <param name="sceneName">The name of the scene to switch to</param> public static void SwitchScene(string sceneName) { if (!NetworkingManager.singleton.NetworkConfig.EnableSceneSwitching) { Debug.LogWarning("MLAPI: Scene switching is not enabled"); return; } else if (isSwitching) { Debug.LogWarning("MLAPI: Scene switch already in progress"); return; } else if (!registeredSceneNames.Contains(sceneName)) { Debug.LogWarning("MLAPI: The scene " + sceneName + " is not registered as a switchable scene."); return; } SpawnManager.DestroySceneObjects(); //Destroy current scene objects before switching. CurrentSceneIndex = sceneNameToIndex[sceneName]; isSwitching = true; lastScene = SceneManager.GetActiveScene(); AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); sceneLoad.completed += OnSceneLoaded; using (BitWriter writer = new BitWriter()) { writer.WriteUInt(sceneNameToIndex[sceneName]); InternalMessageHandler.Send("MLAPI_SWITCH_SCENE", "MLAPI_INTERNAL", writer.Finalize(), null); } }
internal static void PassthroughSend(uint targetId, uint sourceId, ushort messageType, int channelId, BitReader reader, uint?networkId = null, ushort?orderId = null) { if (netManager.isHost && targetId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Host trying to send data to it's own client return; } using (BitWriter writer = BitWriter.Get()) { writer.WriteGenericMessageHeader(messageType, networkId != null, networkId.GetValueOrDefault(), orderId.GetValueOrDefault(), true, null, sourceId); #if !DISABLE_CRYPTOGRAPHY if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(MessageManager.reverseChannels[channelId])) { writer.WriteByteArray(CryptographyHelper.Encrypt(reader.ReadByteArray(), netManager.ConnectedClients[targetId].AesKey)); } else #endif writer.WriteByteArray(reader.ReadByteArray()); writer.Finalize(ref FinalMessageBuffer); netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), channelId, false, out byte error); } }
/// <summary> /// Returns a base64 encoded version of the config /// </summary> /// <returns></returns> public string ToBase64() { NetworkConfig config = this; using (BitWriter writer = BitWriter.Get()) { writer.WriteUShort(config.ProtocolVersion); writer.WriteBits((byte)config.Transport, 5); writer.WriteUShort((ushort)config.Channels.Count); for (int i = 0; i < config.Channels.Count; i++) { writer.WriteString(config.Channels[i].Name); writer.WriteBool(config.Channels[i].Encrypted); writer.WriteBits((byte)config.Channels[i].Type, 5); } writer.WriteUShort((ushort)config.MessageTypes.Count); for (int i = 0; i < config.MessageTypes.Count; i++) { writer.WriteString(config.MessageTypes[i].Name); writer.WriteBool(config.MessageTypes[i].Passthrough); } writer.WriteUShort((ushort)config.RegisteredScenes.Count); for (int i = 0; i < config.RegisteredScenes.Count; i++) { writer.WriteString(config.RegisteredScenes[i]); } writer.WriteUShort((ushort)config.NetworkedPrefabs.Count); for (int i = 0; i < config.NetworkedPrefabs.Count; i++) { writer.WriteBool(config.NetworkedPrefabs[i].playerPrefab); writer.WriteString(config.NetworkedPrefabs[i].name); } writer.WriteInt(config.MessageBufferSize); writer.WriteInt(config.ReceiveTickrate); writer.WriteInt(config.MaxReceiveEventsPerTickRate); writer.WriteInt(config.SendTickrate); writer.WriteInt(config.EventTickrate); writer.WriteInt(config.MaxConnections); writer.WriteInt(config.ConnectPort); writer.WriteString(config.ConnectAddress); writer.WriteInt(config.ClientConnectionBufferTimeout); writer.WriteBool(config.ConnectionApproval); writer.WriteInt(config.SecondsHistory); writer.WriteBool(config.HandleObjectSpawning); writer.WriteBool(config.EnableEncryption); writer.WriteBool(config.SignKeyExchange); writer.WriteBool(config.AllowPassthroughMessages); writer.WriteBool(config.EnableSceneSwitching); writer.WriteBool(config.EnableTimeResync); writer.WriteBits((byte)config.AttributeMessageMode, 3); return(Convert.ToBase64String(writer.Finalize())); } }
public byte[] GetPublicKey() { using (BitWriter writer = new BitWriter()) { writer.WriteByteArray(pub.X.ToByteArray()); writer.WriteByteArray(pub.Y.ToByteArray(), true); return(writer.Finalize()); } }
//RETURNS THE CLIENTIDS WHICH WAS NOT BEING OBSERVED internal static ref List <uint> Send(string messageType, string channelName, BitWriter messageWriter, uint clientIdToIgnore, uint?fromNetId, uint?networkId = null, ushort?orderId = null) { failedObservers.Clear(); if (netManager.NetworkConfig.EncryptedChannels.Contains(channelName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot send messages over encrypted channel to multiple clients"); } return(ref failedObservers); } using (BitWriter writer = BitWriter.Get()) { writer.WriteGenericMessageHeader(MessageManager.messageTypes[messageType], networkId != null, networkId.GetValueOrDefault(), orderId.GetValueOrDefault(), false, 0, 0); writer.WriteWriter(messageWriter); int channel = MessageManager.channels[channelName]; foreach (KeyValuePair <uint, NetworkedClient> pair in netManager.connectedClients) { if (pair.Key == clientIdToIgnore) { continue; } uint targetClientId = pair.Key; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. continue; } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we continue if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(pair.Key)) { failedObservers.Add(pair.Key); continue; } writer.Finalize(ref FinalMessageBuffer); NetworkProfiler.StartEvent(TickType.Send, (uint)messageWriter.GetFinalizeSize(), channelName, messageType); byte error; int byteCount = (int)writer.GetFinalizeSize(); NetworkProfiler.addBytesSent((uint)byteCount); netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, byteCount, channel, false, out error); NetworkProfiler.EndEvent(); } return(ref failedObservers); } }
internal static void Send(List <uint> clientIds, string messageType, string channelName, byte[] data, uint?fromNetId, uint?networkId = null, ushort?orderId = null) { if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName)) { Debug.LogWarning("MLAPI: Cannot send messages over encrypted channel to multiple clients."); return; } using (BitWriter writer = new BitWriter()) { writer.WriteUShort(MessageManager.messageTypes[messageType]); writer.WriteBool(networkId != null); if (networkId != null) { writer.WriteUInt(networkId.Value); } if (orderId != null) { writer.WriteUShort(orderId.Value); } writer.WriteBool(false); writer.WriteAlignBits(); writer.WriteByteArray(data); int channel = MessageManager.channels[channelName]; for (int i = 0; i < clientIds.Count; i++) { uint targetClientId = clientIds[i]; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. continue; } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we continue if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(clientIds[i])) { continue; } writer.Finalize(ref FinalMessageBuffer); byte error; netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), channel, false, out error); } } }
internal string ToBase64() { using (BitWriter writer = BitWriter.Get()) { writer.WriteUShort(ProtocolVersion); writer.WriteBits((byte)Transport, 5); writer.WriteUShort((ushort)Channels.Count); for (int i = 0; i < Channels.Count; i++) { writer.WriteString(Channels[i].Name); writer.WriteBool(Channels[i].Encrypted); writer.WriteBits((byte)Channels[i].Type, 5); } writer.WriteUShort((ushort)MessageTypes.Count); for (int i = 0; i < MessageTypes.Count; i++) { writer.WriteString(MessageTypes[i].Name); writer.WriteBool(MessageTypes[i].Passthrough); } writer.WriteUShort((ushort)RegisteredScenes.Count); for (int i = 0; i < RegisteredScenes.Count; i++) { writer.WriteString(RegisteredScenes[i]); } writer.WriteUShort((ushort)NetworkedPrefabs.Count); for (int i = 0; i < NetworkedPrefabs.Count; i++) { writer.WriteBool(NetworkedPrefabs[i].playerPrefab); writer.WriteString(NetworkedPrefabs[i].name); } writer.WriteInt(MessageBufferSize); writer.WriteInt(ReceiveTickrate); writer.WriteInt(MaxReceiveEventsPerTickRate); writer.WriteInt(SendTickrate); writer.WriteInt(EventTickrate); writer.WriteInt(MaxConnections); writer.WriteInt(ConnectPort); writer.WriteString(ConnectAddress); writer.WriteInt(ClientConnectionBufferTimeout); writer.WriteBool(ConnectionApproval); writer.WriteInt(SecondsHistory); writer.WriteBool(HandleObjectSpawning); writer.WriteBool(EnableEncryption); writer.WriteBool(SignKeyExchange); writer.WriteBool(AllowPassthroughMessages); writer.WriteBool(EnableSceneSwitching); writer.WriteBool(EnableTimeResync); writer.WriteBits((byte)AttributeMessageMode, 3); return(Convert.ToBase64String(writer.Finalize())); } }
internal static void SpawnPrefabIndexServer(NetworkedObject netObject, uint?clientOwnerId = null) { if (netObject.isSpawned) { Debug.LogWarning("MLAPI: Object already spawned"); return; } else if (!netManager.isServer) { Debug.LogWarning("MLAPI: Only server can spawn objects"); return; } else if (!netManager.NetworkConfig.NetworkPrefabIds.ContainsKey(netObject.NetworkedPrefabName)) { Debug.LogWarning("MLAPI: The prefab name " + netObject.NetworkedPrefabName + " does not exist as a networkedPrefab"); return; } else if (!netManager.NetworkConfig.HandleObjectSpawning) { Debug.LogWarning("MLAPI: NetworkConfig is set to not handle object spawning"); return; } uint netId = GetNetworkObjectId(); netObject.networkId = netId; spawnedObjects.Add(netId, netObject); netObject._isSpawned = true; netObject.sceneObject = false; netObject.InvokeBehaviourNetworkSpawn(); if (clientOwnerId != null) { netObject.ownerClientId = clientOwnerId.Value; NetworkingManager.singleton.connectedClients[clientOwnerId.Value].OwnedObjects.Add(netObject); } using (BitWriter writer = new BitWriter()) { writer.WriteBool(false); writer.WriteUInt(netObject.NetworkId); writer.WriteUInt(netObject.OwnerClientId); writer.WriteInt(netManager.NetworkConfig.NetworkPrefabIds[netObject.NetworkedPrefabName]); writer.WriteBool(netObject.sceneObject == null ? true : netObject.sceneObject.Value); writer.WriteFloat(netObject.transform.position.x); writer.WriteFloat(netObject.transform.position.y); writer.WriteFloat(netObject.transform.position.z); writer.WriteFloat(netObject.transform.rotation.eulerAngles.x); writer.WriteFloat(netObject.transform.rotation.eulerAngles.y); writer.WriteFloat(netObject.transform.rotation.eulerAngles.z); InternalMessageHandler.Send("MLAPI_ADD_OBJECT", "MLAPI_INTERNAL", writer.Finalize(), null); } }
public void TestWritingTrue() { BitWriter bitWriter = BitWriter.Get(); bitWriter.WriteBool(true); byte[] result = bitWriter.Finalize(); Assert.That(result.Length, Is.EqualTo(1)); Assert.That(result[0], Is.EqualTo(1)); }
internal static void RemoveOwnership(uint netId) { NetworkedObject netObject = SpawnManager.spawnedObjects[netId]; NetworkingManager.singleton.connectedClients[netObject.OwnerClientId].OwnedObjects.RemoveAll(x => x.NetworkId == netId); netObject.ownerClientId = NetworkingManager.singleton.NetworkConfig.NetworkTransport.InvalidDummyId; using (BitWriter writer = new BitWriter()) { writer.WriteUInt(netId); writer.WriteUInt(netObject.ownerClientId); InternalMessageHandler.Send("MLAPI_CHANGE_OWNER", "MLAPI_INTERNAL", writer.Finalize(), null); } }
private static byte[] Compress(byte[] data, Compression method = Compression.int32) { int size = method == Compression.int16 ? 2 : method == Compression.int32 ? 4 : 8; int count = (data.Length / size) + (data.Length % size == 0 ? 0 : 1); WriteFunc func = size == 2 ? func16 : size == 4 ? func32 : func64; using (BitWriter writer = new BitWriter()) { writer.WriteUInt((uint)data.Length); for (int i = 0; i < count; ++i) { func(writer, data, i); } return(writer.Finalize()); } }
internal static void Send(uint[] clientIds, string messageType, string channelName, BitWriter messageWriter, uint?fromNetId, uint?networkId = null, ushort?orderId = null) { if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot send messages over encrypted channel to multiple clients"); } return; } using (BitWriter writer = BitWriter.Get()) { writer.WriteGenericMessageHeader(MessageManager.messageTypes[messageType], networkId != null, networkId.GetValueOrDefault(), orderId.GetValueOrDefault(), false, 0, 0); writer.WriteWriter(messageWriter); int channel = MessageManager.channels[channelName]; for (int i = 0; i < clientIds.Length; i++) { uint targetClientId = clientIds[i]; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. continue; } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we continue if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(clientIds[i])) { continue; } writer.Finalize(ref FinalMessageBuffer); NetworkProfiler.StartEvent(TickType.Send, (uint)messageWriter.GetFinalizeSize(), channelName, messageType); byte error; netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), channel, false, out error); NetworkProfiler.EndEvent(); } } }
internal static void PassthroughSend(uint targetId, uint sourceId, ushort messageType, int channelId, byte[] data, uint?networkId = null, ushort?orderId = null) { if (netManager.isHost && targetId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Host trying to send data to it's own client Debug.LogWarning("MLAPI: Send method got message aimed at server from the server?"); return; } using (BitWriter writer = new BitWriter()) { writer.WriteUShort(messageType); writer.WriteBool(networkId != null); if (networkId != null) { writer.WriteUInt(networkId.Value); } if (orderId != null) { writer.WriteUShort(orderId.Value); } writer.WriteBool(true); writer.WriteUInt(sourceId); writer.WriteAlignBits(); if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(MessageManager.reverseChannels[channelId])) { writer.WriteByteArray(CryptographyHelper.Encrypt(data, netManager.connectedClients[targetId].AesKey)); } else { writer.WriteByteArray(data); } writer.Finalize(ref FinalMessageBuffer); byte error; netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), channelId, false, out error); } }
private void OnGUI() { int y = 25; if (isServer && isLocalPlayer) { y += 25; if (GUI.Button(new Rect(200, y, 200, 20), "Change Text with SyncVar")) { MySyncedName = "SyncVarTest: " + Random.Range(50, 10000); } y += 25; if (GUI.Button(new Rect(200, y, 200, 20), "Spawn cube")) { GameObject go = Instantiate(cubePrefab); go.transform.position = transform.position + new Vector3(0, 3f, 0); go.GetComponent <NetworkedObject>().Spawn(); } y += 25; if (GUI.Button(new Rect(200, y, 200, 20), "Spawn sphere")) { GameObject go = Instantiate(spherePrefab); go.transform.position = transform.position + new Vector3(0, 3f, 0); go.GetComponent <NetworkedObject>().Spawn(); } y += 25; if (GUI.Button(new Rect(200, y, 200, 20), "Set random plane color")) { planeMaterial.color = Random.ColorHSV(); using (BitWriter writer = new BitWriter()) { writer.WriteFloat(planeMaterial.color.r); writer.WriteFloat(planeMaterial.color.g); writer.WriteFloat(planeMaterial.color.b); SendToClientsTarget("OnChangeColor", "ColorChannel", writer.Finalize()); } } } }
internal static void FlushSceneObjects() { if (!NetworkingManager.singleton.isServer) { return; } List <NetworkedObject> sceneObjectsToSync = new List <NetworkedObject>(); foreach (KeyValuePair <uint, NetworkedObject> pair in SpawnManager.spawnedObjects) { if (pair.Value.sceneObject == null || pair.Value.sceneObject == true) { sceneObjectsToSync.Add(pair.Value); } } using (BitWriter writer = new BitWriter()) { writer.WriteUShort((ushort)sceneObjectsToSync.Count); for (int i = 0; i < sceneObjectsToSync.Count; i++) { writer.WriteBool(false); //isLocalPlayer writer.WriteUInt(sceneObjectsToSync[i].NetworkId); writer.WriteUInt(sceneObjectsToSync[i].OwnerClientId); writer.WriteInt(NetworkingManager.singleton.NetworkConfig.NetworkPrefabIds[sceneObjectsToSync[i].NetworkedPrefabName]); writer.WriteBool(sceneObjectsToSync[i].sceneObject == null ? true : sceneObjectsToSync[i].sceneObject.Value); writer.WriteFloat(sceneObjectsToSync[i].transform.position.x); writer.WriteFloat(sceneObjectsToSync[i].transform.position.y); writer.WriteFloat(sceneObjectsToSync[i].transform.position.z); writer.WriteFloat(sceneObjectsToSync[i].transform.rotation.eulerAngles.x); writer.WriteFloat(sceneObjectsToSync[i].transform.rotation.eulerAngles.y); writer.WriteFloat(sceneObjectsToSync[i].transform.rotation.eulerAngles.z); } InternalMessageHandler.Send("MLAPI_ADD_OBJECTS", "MLAPI_INTERNAL", writer.Finalize(), null); } }
//RETURNS IF IT SUCCEDED OR FAILED BECAUSE OF NON-OBSERVER. ANY OTHER FAIL WILL RETURN TRUE internal static bool Send(uint clientId, string messageType, string channelName, byte[] data, uint?fromNetId, uint?networkId = null, ushort?orderId = null, bool skipQueue = false) { uint targetClientId = clientId; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. Debug.LogWarning("MLAPI: Cannot send message to own client"); return(true); } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we return if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(clientId)) { return(false); } bool isPassthrough = (!netManager.isServer && clientId != netManager.NetworkConfig.NetworkTransport.ServerNetId && netManager.NetworkConfig.AllowPassthroughMessages); if (isPassthrough && !netManager.NetworkConfig.PassthroughMessageHashSet.Contains(MessageManager.messageTypes[messageType])) { Debug.LogWarning("MLAPI: The The MessageType " + messageType + " is not registered as an allowed passthrough message type."); return(true); } using (BitWriter writer = new BitWriter()) { writer.WriteUShort(MessageManager.messageTypes[messageType]); writer.WriteBool(networkId != null); if (networkId != null) { writer.WriteUInt(networkId.Value); } if (orderId != null) { writer.WriteUShort(orderId.Value); } writer.WriteBool(isPassthrough); if (isPassthrough) { writer.WriteUInt(clientId); } writer.WriteAlignBits(); if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName)) { //This is an encrypted message. byte[] encrypted; if (netManager.isServer) { encrypted = CryptographyHelper.Encrypt(data, netManager.connectedClients[clientId].AesKey); } else { encrypted = CryptographyHelper.Encrypt(data, netManager.clientAesKey); } writer.WriteByteArray(encrypted); } else { writer.WriteByteArray(data); } if (isPassthrough) { targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } writer.Finalize(ref FinalMessageBuffer); byte error; if (skipQueue) { netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), MessageManager.channels[channelName], true, out error); } else { netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), MessageManager.channels[channelName], false, out error); } return(true); } }
//RETURNS IF IT SUCCEDED OR FAILED BECAUSE OF NON-OBSERVER. ANY OTHER FAIL WILL RETURN TRUE internal static bool Send(uint clientId, string messageType, string channelName, BitWriter messageWriter, uint?fromNetId, uint?networkId = null, ushort?orderId = null, bool skipQueue = false) { uint targetClientId = clientId; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. return(true); } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we return if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(clientId)) { return(false); } bool isPassthrough = (!netManager.isServer && clientId != netManager.NetworkConfig.NetworkTransport.ServerNetId && netManager.NetworkConfig.AllowPassthroughMessages); if (isPassthrough && !netManager.NetworkConfig.PassthroughMessageHashSet.Contains(MessageManager.messageTypes[messageType])) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The The MessageType " + messageType + " is not registered as an allowed passthrough message type"); } return(true); } using (BitWriter writer = BitWriter.Get()) { writer.WriteGenericMessageHeader(MessageManager.messageTypes[messageType], networkId != null, networkId.GetValueOrDefault(), orderId.GetValueOrDefault(), isPassthrough, clientId, null); #if !DISABLE_CRYPTOGRAPHY if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName)) { //This is an encrypted message. byte[] encrypted; if (netManager.isServer) { encrypted = CryptographyHelper.Encrypt(messageWriter.Finalize(), netManager.ConnectedClients[clientId].AesKey); } else { encrypted = CryptographyHelper.Encrypt(messageWriter.Finalize(), netManager.clientAesKey); } writer.WriteByteArray(encrypted); } else #endif writer.WriteWriter(messageWriter); if (isPassthrough) { targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } writer.Finalize(ref FinalMessageBuffer); NetworkProfiler.StartEvent(TickType.Send, (uint)messageWriter.GetFinalizeSize(), channelName, messageType); byte error; if (skipQueue) { netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), MessageManager.channels[channelName], true, out error); } else { netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), MessageManager.channels[channelName], false, out error); } NetworkProfiler.EndEvent(); return(true); } }
/// <summary> /// Destroys a NetworkedObject if it's part of a pool. Use this instead of the MonoBehaviour Destroy method. Can only be called from Server. /// </summary> /// <param name="netObject">The NetworkedObject instance to destroy</param> public static void DestroyPoolObject(NetworkedObject netObject) { if (!NetworkingManager.singleton.isServer) { Debug.LogWarning("MLAPI: Objects can only be destroyed on the server"); return; } netObject.gameObject.SetActive(false); using (BitWriter writer = new BitWriter()) { writer.WriteUInt(netObject.NetworkId); InternalMessageHandler.Send("MLAPI_DESTROY_POOL_OBJECT", "MLAPI_INTERNAL", writer.Finalize(), null); } }
/// <summary> /// Spawns a object from the pool at a given position and rotation. Can only be called from server. /// </summary> /// <param name="poolName">The name of the pool</param> /// <param name="position">The position to spawn the object at</param> /// <param name="rotation">The rotation to spawn the object at</param> /// <returns></returns> public static GameObject SpawnPoolObject(string poolName, Vector3 position, Quaternion rotation) { if (!NetworkingManager.singleton.isServer) { Debug.LogWarning("MLAPI: Object spawning can only occur on server"); return(null); } GameObject go = Pools[PoolNamesToIndexes[poolName]].SpawnObject(position, rotation); using (BitWriter writer = new BitWriter()) { writer.WriteUInt(go.GetComponent <NetworkedObject>().NetworkId); writer.WriteFloat(position.x); writer.WriteFloat(position.y); writer.WriteFloat(position.z); writer.WriteFloat(rotation.eulerAngles.x); writer.WriteFloat(rotation.eulerAngles.y); writer.WriteFloat(rotation.eulerAngles.z); InternalMessageHandler.Send("MLAPI_SPAWN_POOL_OBJECT", "MLAPI_INTERNAL", writer.Finalize(), null); } return(go); }
internal void RebuildObservers(uint?clientId = null) { bool initial = clientId != null; if (initial) { bool shouldBeAdded = true; for (int i = 0; i < childNetworkedBehaviours.Count; i++) { bool state = childNetworkedBehaviours[i].OnCheckObserver(clientId.Value); if (state == false) { shouldBeAdded = false; break; } } if (shouldBeAdded) { observers.Add(clientId.Value); } } else { HashSet <uint> previousObservers = new HashSet <uint>(observers); HashSet <uint> newObservers = new HashSet <uint>(); bool update = false; for (int i = 0; i < childNetworkedBehaviours.Count; i++) { bool changed = childNetworkedBehaviours[i].OnRebuildObservers(newObservers); if (changed) { observers = newObservers; update = true; break; } } if (update) { foreach (KeyValuePair <uint, NetworkedClient> pair in NetworkingManager.singleton.connectedClients) { if (pair.Key == NetworkingManager.singleton.NetworkConfig.NetworkTransport.HostDummyId) { continue; } if ((previousObservers.Contains(pair.Key) && !newObservers.Contains(pair.Key)) || (!previousObservers.Contains(pair.Key) && newObservers.Contains(pair.Key))) { //Something changed for this client. using (BitWriter writer = new BitWriter()) { writer.WriteUInt(networkId); writer.WriteBool(observers.Contains(pair.Key)); InternalMessageHandler.Send(pair.Key, "MLAPI_SET_VISIBILITY", "MLAPI_INTERNAL", writer.Finalize(), null); } FlushToClient(pair.Key); } } } } }
internal static void SpawnObject(NetworkedObject netObject, uint?clientOwnerId = null, BitWriter 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); 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 { using (BitReader payloadReader = BitReader.Get(payload.Finalize())) netObject.InvokeBehaviourNetworkSpawn(payloadReader); } foreach (var client in netManager.connectedClients) { netObject.RebuildObservers(client.Key); using (BitWriter writer = BitWriter.Get()) { writer.WriteBool(false); writer.WriteUInt(netObject.NetworkId); writer.WriteUInt(netObject.OwnerClientId); writer.WriteInt(netManager.NetworkConfig.NetworkPrefabIds[netObject.NetworkedPrefabName]); writer.WriteBool(netObject.sceneObject == null ? true : netObject.sceneObject.Value); writer.WriteBool(netObject.observers.Contains(client.Key)); writer.WriteFloat(netObject.transform.position.x); writer.WriteFloat(netObject.transform.position.y); writer.WriteFloat(netObject.transform.position.z); writer.WriteFloat(netObject.transform.rotation.eulerAngles.x); writer.WriteFloat(netObject.transform.rotation.eulerAngles.y); writer.WriteFloat(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); if (netObject.observers.Contains(client.Key)) { netObject.WriteFormattedSyncedVarData(writer); } if (payload != null) { writer.WriteWriter(payload); } InternalMessageHandler.Send(client.Key, "MLAPI_ADD_OBJECT", "MLAPI_INTERNAL", writer, null); } } }
internal static void OnDestroyObject(uint networkId, bool destroyGameObject) { if (!spawnedObjects.ContainsKey(networkId) || (netManager != null && !netManager.NetworkConfig.HandleObjectSpawning)) { return; } if (spawnedObjects[networkId].OwnerClientId != NetworkingManager.singleton.NetworkConfig.NetworkTransport.InvalidDummyId && !spawnedObjects[networkId].isPlayerObject) { //Someone owns it. NetworkingManager.singleton.connectedClients[spawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAll(x => x.NetworkId == networkId); } GameObject go = spawnedObjects[networkId].gameObject; if (netManager != null && netManager.isServer) { releasedNetworkObjectIds.Push(networkId); if (spawnedObjects[networkId] != null) { using (BitWriter writer = new BitWriter()) { writer.WriteUInt(networkId); InternalMessageHandler.Send("MLAPI_DESTROY_OBJECT", "MLAPI_INTERNAL", writer.Finalize(), null); } } } if (destroyGameObject && go != null) { MonoBehaviour.Destroy(go); } spawnedObjects.Remove(networkId); }