Added first version of MessagePassthrough

This commit is contained in:
Albin Corén 2018-01-10 13:26:20 +01:00
parent 1f14ded9cf
commit a2090443d4
5 changed files with 131 additions and 18 deletions

View File

@ -11,6 +11,8 @@ namespace MLAPI
public ushort ProtocolVersion = 0; public ushort ProtocolVersion = 0;
public SortedDictionary<string, QosType> Channels = new SortedDictionary<string, QosType>(); public SortedDictionary<string, QosType> Channels = new SortedDictionary<string, QosType>();
public List<string> MessageTypes = new List<string>(); public List<string> MessageTypes = new List<string>();
public List<string> PassthroughMessageTypes = new List<string>();
internal HashSet<ushort> RegisteredPassthroughMessageTypes = new HashSet<ushort>();
public int MessageBufferSize = 65535; public int MessageBufferSize = 65535;
public int MaxMessagesPerFrame = 150; public int MaxMessagesPerFrame = 150;
public int MaxConnections = 100; 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 //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 //TODO
public bool EncryptMessages = false; public bool EncryptMessages = false;
public bool AllowPassthroughMessages = true;
//Cached config hash //Cached config hash
private byte[] ConfigHash = null; private byte[] ConfigHash = null;
@ -44,13 +47,20 @@ namespace MLAPI
writer.Write(pair.Key); writer.Write(pair.Key);
writer.Write((int)pair.Value); writer.Write((int)pair.Value);
} }
MessageTypes.Sort();
PassthroughMessageTypes.Sort();
for (int i = 0; i < MessageTypes.Count; i++) for (int i = 0; i < MessageTypes.Count; i++)
{ {
writer.Write(MessageTypes[i]); writer.Write(MessageTypes[i]);
} }
for (int i = 0; i < PassthroughMessageTypes.Count; i++)
{
writer.Write(PassthroughMessageTypes[i]);
}
writer.Write(HandleObjectSpawning); writer.Write(HandleObjectSpawning);
writer.Write(CompressMessages); writer.Write(CompressMessages);
writer.Write(EncryptMessages); writer.Write(EncryptMessages);
writer.Write(AllowPassthroughMessages);
} }
using(SHA256Managed sha256 = new SHA256Managed()) using(SHA256Managed sha256 = new SHA256Managed())
{ {

View File

@ -126,9 +126,9 @@ namespace MLAPI
protected void SendToLocalClient(string messageType, string channelName, byte[] data) 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; return;
} }
NetworkingManager.singleton.Send(ownerClientId, messageType, channelName, data); NetworkingManager.singleton.Send(ownerClientId, messageType, channelName, data);
@ -136,9 +136,9 @@ namespace MLAPI
protected void SendToLocalClientTarget(string messageType, string channelName, byte[] data) 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; return;
} }
NetworkingManager.singleton.Send(ownerClientId, messageType, channelName, data, networkId); 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) 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; return;
} }
NetworkingManager.singleton.Send(clientId, messageType, channelName, data); NetworkingManager.singleton.Send(clientId, messageType, channelName, data);
@ -176,9 +176,9 @@ namespace MLAPI
protected void SendToClientTarget(int clientId, string messageType, string channelName, byte[] data) 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; return;
} }
NetworkingManager.singleton.Send(clientId, messageType, channelName, data, networkId); NetworkingManager.singleton.Send(clientId, messageType, channelName, data, networkId);

View File

@ -67,8 +67,17 @@ namespace MLAPI
MessageManager.messageHandlerCounter = new Dictionary<ushort, int>(); MessageManager.messageHandlerCounter = new Dictionary<ushort, int>();
MessageManager.releasedMessageHandlerCounters = new Dictionary<ushort, Stack<int>>(); MessageManager.releasedMessageHandlerCounters = new Dictionary<ushort, Stack<int>>();
MessageManager.targetedMessages = new Dictionary<ushort, Dictionary<uint, List<int>>>(); MessageManager.targetedMessages = new Dictionary<ushort, Dictionary<uint, List<int>>>();
MessageManager.reverseChannels = new Dictionary<int, string>();
MessageManager.reverseMessageTypes = new Dictionary<ushort, string>();
SpawnManager.spawnedObjects = new Dictionary<uint, NetworkedObject>(); SpawnManager.spawnedObjects = new Dictionary<uint, NetworkedObject>();
SpawnManager.releasedNetworkObjectIds = new Stack<uint>(); SpawnManager.releasedNetworkObjectIds = new Stack<uint>();
if(NetworkConfig.AllowPassthroughMessages)
{
for (int i = 0; i < NetworkConfig.PassthroughMessageTypes.Count; i++)
{
NetworkConfig.RegisteredPassthroughMessageTypes.Add(MessageManager.messageTypes[NetworkConfig.PassthroughMessageTypes[i]]);
}
}
if (NetworkConfig.HandleObjectSpawning) if (NetworkConfig.HandleObjectSpawning)
{ {
NetworkedObject[] sceneObjects = FindObjectsOfType<NetworkedObject>(); NetworkedObject[] sceneObjects = FindObjectsOfType<NetworkedObject>();
@ -104,11 +113,13 @@ namespace MLAPI
int channelId = cConfig.AddChannel(pair.Value); int channelId = cConfig.AddChannel(pair.Value);
MessageManager.channels.Add(pair.Key, channelId); MessageManager.channels.Add(pair.Key, channelId);
channelNames.Add(pair.Key); channelNames.Add(pair.Key);
MessageManager.reverseChannels.Add(channelId, pair.Key);
} }
//0-32 are reserved for MLAPI messages //0-32 are reserved for MLAPI messages
ushort messageId = 32; ushort messageId = 32;
for (ushort i = 0; i < NetworkConfig.MessageTypes.Count; i++) for (ushort i = 0; i < NetworkConfig.MessageTypes.Count; i++)
{ {
MessageManager.reverseMessageTypes.Add(messageId, NetworkConfig.MessageTypes[i]);
MessageManager.messageTypes.Add(NetworkConfig.MessageTypes[i], messageId); MessageManager.messageTypes.Add(NetworkConfig.MessageTypes[i], messageId);
messageId++; messageId++;
} }
@ -289,7 +300,7 @@ namespace MLAPI
} }
break; break;
case NetworkEventType.DataEvent: case NetworkEventType.DataEvent:
HandleIncomingData(clientId, messageBuffer); HandleIncomingData(clientId, messageBuffer, channelId);
break; break;
case NetworkEventType.DisconnectEvent: case NetworkEventType.DisconnectEvent:
if(isServer) 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)) using(MemoryStream readStream = new MemoryStream(data))
{ {
@ -330,6 +341,16 @@ namespace MLAPI
uint targetNetworkId = 0; uint targetNetworkId = 0;
if(targeted) if(targeted)
targetNetworkId = reader.ReadUInt32(); 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. //Client tried to send a network message that was not the connection request before he was accepted.
if (isServer && pendingClients.Contains(clientId) && messageType != 0) if (isServer && pendingClients.Contains(clientId) && messageType != 0)
@ -338,8 +359,30 @@ namespace MLAPI
return; return;
} }
ushort bytesToRead = reader.ReadUInt16(); ushort bytesToRead = reader.ReadUInt16();
byte[] incommingData = reader.ReadBytes(bytesToRead); 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) if (messageType >= 32)
{ {
//Custom message, invoke all message handlers //Custom message, invoke all message handlers
@ -348,14 +391,20 @@ namespace MLAPI
List<int> handlerIds = MessageManager.targetedMessages[messageType][targetNetworkId]; List<int> handlerIds = MessageManager.targetedMessages[messageType][targetNetworkId];
for (int i = 0; i < handlerIds.Count; i++) 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 else
{ {
foreach (KeyValuePair<int, Action<int, byte[]>> pair in MessageManager.messageCallbacks[messageType]) foreach (KeyValuePair<int, Action<int, byte[]>> 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) internal void Send(int clientId, string messageType, string channelName, byte[] data, uint? networkId = null)
{ {
if(isHost && clientId == -1) if(isHost && clientId == -1)
@ -516,10 +599,19 @@ namespace MLAPI
//Client trying to send data to host //Client trying to send data to host
clientId = serverClientId; 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) if (networkId != null)
sizeOfStream += 4; sizeOfStream += 4;
if (isPassthrough)
sizeOfStream += 4;
sizeOfStream += data.Length; sizeOfStream += data.Length;
using (MemoryStream stream = new MemoryStream(sizeOfStream)) using (MemoryStream stream = new MemoryStream(sizeOfStream))
@ -530,17 +622,21 @@ namespace MLAPI
writer.Write(networkId != null); writer.Write(networkId != null);
if (networkId != null) if (networkId != null)
writer.Write(networkId.Value); writer.Write(networkId.Value);
writer.Write(isPassthrough);
if (isPassthrough)
writer.Write(clientId);
writer.Write((ushort)data.Length); writer.Write((ushort)data.Length);
writer.Write(data); writer.Write(data);
} }
if (isPassthrough)
clientId = serverClientId;
NetworkTransport.Send(hostId, clientId, MessageManager.channels[channelName], stream.GetBuffer(), sizeOfStream, out error); 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) 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 = 6;
int sizeOfStream = 5;
if (networkId != null) if (networkId != null)
sizeOfStream += 4; sizeOfStream += 4;
sizeOfStream += data.Length; sizeOfStream += data.Length;
@ -553,6 +649,7 @@ namespace MLAPI
writer.Write(networkId != null); writer.Write(networkId != null);
if (networkId != null) if (networkId != null)
writer.Write(networkId.Value); writer.Write(networkId.Value);
writer.Write(false);
writer.Write((ushort)data.Length); writer.Write((ushort)data.Length);
writer.Write(data); writer.Write(data);
} }
@ -581,7 +678,7 @@ namespace MLAPI
internal void Send(List<int> clientIds, string messageType, string channelName, byte[] data, uint? networkId = null) internal void Send(List<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 //2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
int sizeOfStream = 5; int sizeOfStream = 6;
if (networkId != null) if (networkId != null)
sizeOfStream += 4; sizeOfStream += 4;
sizeOfStream += data.Length; sizeOfStream += data.Length;
@ -594,6 +691,7 @@ namespace MLAPI
writer.Write(networkId != null); writer.Write(networkId != null);
if (networkId != null) if (networkId != null)
writer.Write(networkId.Value); writer.Write(networkId.Value);
writer.Write(false);
writer.Write((ushort)data.Length); writer.Write((ushort)data.Length);
writer.Write(data); writer.Write(data);
} }
@ -622,7 +720,7 @@ namespace MLAPI
internal void Send(string messageType, string channelName, byte[] data, uint? networkId = null) 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 //2 bytes for messageType, 2 bytes for buffer length and one byte for target bool
int sizeOfStream = 5; int sizeOfStream = 6;
if (networkId != null) if (networkId != null)
sizeOfStream += 4; sizeOfStream += 4;
sizeOfStream += data.Length; sizeOfStream += data.Length;
@ -635,6 +733,7 @@ namespace MLAPI
writer.Write(networkId != null); writer.Write(networkId != null);
if (networkId != null) if (networkId != null)
writer.Write(networkId.Value); writer.Write(networkId.Value);
writer.Write(false);
writer.Write((ushort)data.Length); writer.Write((ushort)data.Length);
writer.Write(data); writer.Write(data);
} }
@ -677,6 +776,7 @@ namespace MLAPI
writer.Write(networkId != null); writer.Write(networkId != null);
if (networkId != null) if (networkId != null)
writer.Write(networkId.Value); writer.Write(networkId.Value);
writer.Write(false);
writer.Write((ushort)data.Length); writer.Write((ushort)data.Length);
writer.Write(data); writer.Write(data);
} }

View File

@ -7,7 +7,9 @@ namespace MLAPI.NetworkingManagerComponents
internal static class MessageManager internal static class MessageManager
{ {
internal static Dictionary<string, int> channels; internal static Dictionary<string, int> channels;
internal static Dictionary<int, string> reverseChannels;
internal static Dictionary<string, ushort> messageTypes; internal static Dictionary<string, ushort> messageTypes;
internal static Dictionary<ushort, string> reverseMessageTypes;
internal static Dictionary<ushort, Dictionary<int, Action<int, byte[]>>> messageCallbacks; internal static Dictionary<ushort, Dictionary<int, Action<int, byte[]>>> messageCallbacks;
internal static Dictionary<ushort, int> messageHandlerCounter; internal static Dictionary<ushort, int> messageHandlerCounter;
internal static Dictionary<ushort, Stack<int>> releasedMessageHandlerCounters; internal static Dictionary<ushort, Stack<int>> releasedMessageHandlerCounters;

View File

@ -25,6 +25,7 @@ It's licenced under the MIT licence :D
* ProtocolVersion to allow making different versions not talk to each other. (done) * 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) * 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) * 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. That's all I can think of right now. But there is more to come, especially if people show intrest in the project.