From a2090443d43fde9172cfc1e0bcf09e9cd8aa6e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= <2108U9@gmail.com> Date: Wed, 10 Jan 2018 13:26:20 +0100 Subject: [PATCH] Added first version of MessagePassthrough --- MLAPI/Data/NetworkingConfiguration.cs | 10 ++ .../MonoBehaviours/Core/NetworkedBehaviour.cs | 16 +-- .../MonoBehaviours/Core/NetworkingManager.cs | 120 ++++++++++++++++-- .../MessageManager.cs | 2 + README.md | 1 + 5 files changed, 131 insertions(+), 18 deletions(-) diff --git a/MLAPI/Data/NetworkingConfiguration.cs b/MLAPI/Data/NetworkingConfiguration.cs index 37e62a2..fb3b439 100644 --- a/MLAPI/Data/NetworkingConfiguration.cs +++ b/MLAPI/Data/NetworkingConfiguration.cs @@ -11,6 +11,8 @@ namespace MLAPI public ushort ProtocolVersion = 0; public SortedDictionary Channels = new SortedDictionary(); public List MessageTypes = new List(); + public List PassthroughMessageTypes = new List(); + internal HashSet RegisteredPassthroughMessageTypes = new HashSet(); public int MessageBufferSize = 65535; public int MaxMessagesPerFrame = 150; public int MaxConnections = 100; @@ -26,6 +28,7 @@ namespace MLAPI //Should only be used for dedicated servers and will require the servers RSA keypair being hard coded into clients in order to exchange a AES key //TODO public bool EncryptMessages = false; + public bool AllowPassthroughMessages = true; //Cached config hash private byte[] ConfigHash = null; @@ -44,13 +47,20 @@ namespace MLAPI writer.Write(pair.Key); writer.Write((int)pair.Value); } + MessageTypes.Sort(); + PassthroughMessageTypes.Sort(); for (int i = 0; i < MessageTypes.Count; i++) { writer.Write(MessageTypes[i]); } + for (int i = 0; i < PassthroughMessageTypes.Count; i++) + { + writer.Write(PassthroughMessageTypes[i]); + } writer.Write(HandleObjectSpawning); writer.Write(CompressMessages); writer.Write(EncryptMessages); + writer.Write(AllowPassthroughMessages); } using(SHA256Managed sha256 = new SHA256Managed()) { diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 5764edc..396faff 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -126,9 +126,9 @@ namespace MLAPI protected void SendToLocalClient(string messageType, string channelName, byte[] data) { - if (!isServer) + if (!isServer && (!NetworkingManager.singleton.NetworkConfig.AllowPassthroughMessages || !NetworkingManager.singleton.NetworkConfig.PassthroughMessageTypes.Contains(messageType))) { - Debug.LogWarning("MLAPI: Sending messages from client to other clients is not yet supported"); + Debug.LogWarning("MLAPI: Invalid Passthrough send. Ensure AllowPassthroughMessages are turned on and that the MessageType " + messageType + " is registered as a passthroughMessageType"); return; } NetworkingManager.singleton.Send(ownerClientId, messageType, channelName, data); @@ -136,9 +136,9 @@ namespace MLAPI protected void SendToLocalClientTarget(string messageType, string channelName, byte[] data) { - if (!isServer) + if (!isServer && (!NetworkingManager.singleton.NetworkConfig.AllowPassthroughMessages || !NetworkingManager.singleton.NetworkConfig.PassthroughMessageTypes.Contains(messageType))) { - Debug.LogWarning("MLAPI: Sending messages from client to other clients is not yet supported"); + Debug.LogWarning("MLAPI: Invalid Passthrough send. Ensure AllowPassthroughMessages are turned on and that the MessageType " + messageType + " is registered as a passthroughMessageType"); return; } NetworkingManager.singleton.Send(ownerClientId, messageType, channelName, data, networkId); @@ -166,9 +166,9 @@ namespace MLAPI protected void SendToClient(int clientId, string messageType, string channelName, byte[] data) { - if (!isServer) + if (!isServer && (!NetworkingManager.singleton.NetworkConfig.AllowPassthroughMessages || !NetworkingManager.singleton.NetworkConfig.PassthroughMessageTypes.Contains(messageType))) { - Debug.LogWarning("MLAPI: Sending messages from client to other clients is not yet supported"); + Debug.LogWarning("MLAPI: Invalid Passthrough send. Ensure AllowPassthroughMessages are turned on and that the MessageType " + messageType + " is registered as a passthroughMessageType"); return; } NetworkingManager.singleton.Send(clientId, messageType, channelName, data); @@ -176,9 +176,9 @@ namespace MLAPI protected void SendToClientTarget(int clientId, string messageType, string channelName, byte[] data) { - if (!isServer) + if (!isServer && (!NetworkingManager.singleton.NetworkConfig.AllowPassthroughMessages || !NetworkingManager.singleton.NetworkConfig.PassthroughMessageTypes.Contains(messageType))) { - Debug.LogWarning("MLAPI: Sending messages from client to other clients is not yet supported"); + Debug.LogWarning("MLAPI: Invalid Passthrough send. Ensure AllowPassthroughMessages are turned on and that the MessageType " + messageType + " is registered as a passthroughMessageType"); return; } NetworkingManager.singleton.Send(clientId, messageType, channelName, data, networkId); diff --git a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs index c992f49..1a20f3e 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkingManager.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkingManager.cs @@ -67,8 +67,17 @@ namespace MLAPI MessageManager.messageHandlerCounter = new Dictionary(); MessageManager.releasedMessageHandlerCounters = new Dictionary>(); MessageManager.targetedMessages = new Dictionary>>(); + MessageManager.reverseChannels = new Dictionary(); + MessageManager.reverseMessageTypes = new Dictionary(); SpawnManager.spawnedObjects = new Dictionary(); SpawnManager.releasedNetworkObjectIds = new Stack(); + if(NetworkConfig.AllowPassthroughMessages) + { + for (int i = 0; i < NetworkConfig.PassthroughMessageTypes.Count; i++) + { + NetworkConfig.RegisteredPassthroughMessageTypes.Add(MessageManager.messageTypes[NetworkConfig.PassthroughMessageTypes[i]]); + } + } if (NetworkConfig.HandleObjectSpawning) { NetworkedObject[] sceneObjects = FindObjectsOfType(); @@ -104,11 +113,13 @@ namespace MLAPI int channelId = cConfig.AddChannel(pair.Value); MessageManager.channels.Add(pair.Key, channelId); channelNames.Add(pair.Key); + MessageManager.reverseChannels.Add(channelId, pair.Key); } //0-32 are reserved for MLAPI messages ushort messageId = 32; for (ushort i = 0; i < NetworkConfig.MessageTypes.Count; i++) { + MessageManager.reverseMessageTypes.Add(messageId, NetworkConfig.MessageTypes[i]); MessageManager.messageTypes.Add(NetworkConfig.MessageTypes[i], messageId); messageId++; } @@ -289,7 +300,7 @@ namespace MLAPI } break; case NetworkEventType.DataEvent: - HandleIncomingData(clientId, messageBuffer); + HandleIncomingData(clientId, messageBuffer, channelId); break; case NetworkEventType.DisconnectEvent: if(isServer) @@ -319,7 +330,7 @@ namespace MLAPI } } - private void HandleIncomingData(int connectonId, byte[] data) + private void HandleIncomingData(int clientId, byte[] data, int channelId) { using(MemoryStream readStream = new MemoryStream(data)) { @@ -330,6 +341,16 @@ namespace MLAPI uint targetNetworkId = 0; if(targeted) targetNetworkId = reader.ReadUInt32(); + bool isPassthrough = reader.ReadBoolean(); + + int passthroughOrigin = 0; + int passthroughTarget = 0; + + if (isPassthrough && isServer) + passthroughTarget = reader.ReadInt32(); + else if (isPassthrough && !isServer) + passthroughOrigin = reader.ReadInt32(); + //Client tried to send a network message that was not the connection request before he was accepted. if (isServer && pendingClients.Contains(clientId) && messageType != 0) @@ -338,8 +359,30 @@ namespace MLAPI return; } + ushort bytesToRead = reader.ReadUInt16(); byte[] incommingData = reader.ReadBytes(bytesToRead); + + if (isServer && isPassthrough && !NetworkConfig.RegisteredPassthroughMessageTypes.Contains(messageType)) + { + Debug.LogWarning("MLAPI: Client " + clientId + " tried to send a passthrough message for a messageType not registered as passthrough"); + return; + } + else if(isClient && isPassthrough && !NetworkConfig.RegisteredPassthroughMessageTypes.Contains(messageType)) + { + Debug.LogWarning("MLAPI: Server tried to send a passthrough message for a messageType not registered as passthrough"); + return; + } + else if(isServer && NetworkConfig.AllowPassthroughMessages && connectedClients.ContainsKey(passthroughTarget)) + { + uint? netIdTarget = null; + if (targeted) + netIdTarget = targetNetworkId; + + PassthroughSend(passthroughTarget, clientId, messageType, channelId, incommingData, netIdTarget); + return; + } + if (messageType >= 32) { //Custom message, invoke all message handlers @@ -348,14 +391,20 @@ namespace MLAPI List handlerIds = MessageManager.targetedMessages[messageType][targetNetworkId]; for (int i = 0; i < handlerIds.Count; i++) { - MessageManager.messageCallbacks[messageType][handlerIds[i]](clientId, incommingData); + if (isPassthrough) + MessageManager.messageCallbacks[messageType][handlerIds[i]](passthroughOrigin, incommingData); + else + MessageManager.messageCallbacks[messageType][handlerIds[i]](clientId, incommingData); } } else { foreach (KeyValuePair> pair in MessageManager.messageCallbacks[messageType]) { - pair.Value(clientId, incommingData); + if (isPassthrough) + pair.Value(passthroughOrigin, incommingData); + else + pair.Value(clientId, incommingData); } } } @@ -500,6 +549,40 @@ namespace MLAPI } } + internal void PassthroughSend(int targetId, int sourceId, ushort messageType, int channelId, byte[] data, uint? networkId = null) + { + if (isHost && targetId == -1) + { + //Host trying to send data to it's own client + if (networkId == null) + MessageManager.InvokeMessageHandlers(MessageManager.reverseMessageTypes[messageType], data, sourceId); + else + MessageManager.InvokeTargetedMessageHandler(MessageManager.reverseMessageTypes[messageType], data, sourceId, networkId.Value); + return; + } + + int sizeOfStream = 10; + if (networkId != null) + sizeOfStream += 4; + sizeOfStream += data.Length; + + using (MemoryStream stream = new MemoryStream(sizeOfStream)) + { + using (BinaryWriter writer = new BinaryWriter(stream)) + { + writer.Write(messageType); + writer.Write(networkId != null); + if (networkId != null) + writer.Write(networkId.Value); + writer.Write(true); + writer.Write(sourceId); + writer.Write((ushort)data.Length); + writer.Write(data); + } + NetworkTransport.Send(hostId, targetId, channelId, stream.GetBuffer(), sizeOfStream, out error); + } + } + internal void Send(int clientId, string messageType, string channelName, byte[] data, uint? networkId = null) { if(isHost && clientId == -1) @@ -516,10 +599,19 @@ namespace MLAPI //Client trying to send data to host clientId = serverClientId; } - //2 bytes for messageType, 2 bytes for buffer length and one byte for target bool - int sizeOfStream = 5; + + bool isPassthrough = (!isServer && clientId != serverClientId && NetworkConfig.AllowPassthroughMessages); + if (isPassthrough && !NetworkConfig.RegisteredPassthroughMessageTypes.Contains(MessageManager.messageTypes[messageType])) + { + Debug.LogWarning("MLAPI: The The MessageType " + messageType + " is not registered as an allowed passthrough message type."); + return; + } + + int sizeOfStream = 6; if (networkId != null) sizeOfStream += 4; + if (isPassthrough) + sizeOfStream += 4; sizeOfStream += data.Length; using (MemoryStream stream = new MemoryStream(sizeOfStream)) @@ -530,17 +622,21 @@ namespace MLAPI writer.Write(networkId != null); if (networkId != null) writer.Write(networkId.Value); + writer.Write(isPassthrough); + if (isPassthrough) + writer.Write(clientId); writer.Write((ushort)data.Length); writer.Write(data); } + if (isPassthrough) + clientId = serverClientId; NetworkTransport.Send(hostId, clientId, MessageManager.channels[channelName], stream.GetBuffer(), sizeOfStream, out error); } } internal void Send(int[] clientIds, string messageType, string channelName, byte[] data, uint? networkId = null) { - //2 bytes for messageType, 2 bytes for buffer length and one byte for target bool - int sizeOfStream = 5; + int sizeOfStream = 6; if (networkId != null) sizeOfStream += 4; sizeOfStream += data.Length; @@ -553,6 +649,7 @@ namespace MLAPI writer.Write(networkId != null); if (networkId != null) writer.Write(networkId.Value); + writer.Write(false); writer.Write((ushort)data.Length); writer.Write(data); } @@ -581,7 +678,7 @@ namespace MLAPI internal void Send(List clientIds, string messageType, string channelName, byte[] data, uint? networkId = null) { //2 bytes for messageType, 2 bytes for buffer length and one byte for target bool - int sizeOfStream = 5; + int sizeOfStream = 6; if (networkId != null) sizeOfStream += 4; sizeOfStream += data.Length; @@ -594,6 +691,7 @@ namespace MLAPI writer.Write(networkId != null); if (networkId != null) writer.Write(networkId.Value); + writer.Write(false); writer.Write((ushort)data.Length); writer.Write(data); } @@ -622,7 +720,7 @@ namespace MLAPI internal void Send(string messageType, string channelName, byte[] data, uint? networkId = null) { //2 bytes for messageType, 2 bytes for buffer length and one byte for target bool - int sizeOfStream = 5; + int sizeOfStream = 6; if (networkId != null) sizeOfStream += 4; sizeOfStream += data.Length; @@ -635,6 +733,7 @@ namespace MLAPI writer.Write(networkId != null); if (networkId != null) writer.Write(networkId.Value); + writer.Write(false); writer.Write((ushort)data.Length); writer.Write(data); } @@ -677,6 +776,7 @@ namespace MLAPI writer.Write(networkId != null); if (networkId != null) writer.Write(networkId.Value); + writer.Write(false); writer.Write((ushort)data.Length); writer.Write(data); } diff --git a/MLAPI/NetworkingManagerComponents/MessageManager.cs b/MLAPI/NetworkingManagerComponents/MessageManager.cs index 09d8878..8f25847 100644 --- a/MLAPI/NetworkingManagerComponents/MessageManager.cs +++ b/MLAPI/NetworkingManagerComponents/MessageManager.cs @@ -7,7 +7,9 @@ namespace MLAPI.NetworkingManagerComponents internal static class MessageManager { internal static Dictionary channels; + internal static Dictionary reverseChannels; internal static Dictionary messageTypes; + internal static Dictionary reverseMessageTypes; internal static Dictionary>> messageCallbacks; internal static Dictionary messageHandlerCounter; internal static Dictionary> releasedMessageHandlerCounters; diff --git a/README.md b/README.md index 5955d5c..8742411 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ It's licenced under the MIT licence :D * ProtocolVersion to allow making different versions not talk to each other. (done) * NetworkedBehaviours does not have to be on the root, it's simply just a class that implements the send methods etc. (done) * Multiple messages processed every frame with the ability to specify a maximum to prevent freezes in the normal game logic (done) +* Passthrough messages (check the wiki for details) That's all I can think of right now. But there is more to come, especially if people show intrest in the project.