Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,8 @@
|
|||
namespace MLAPI.Transports.UNET
|
||||
{
|
||||
public static class ProfilerConstants
|
||||
{
|
||||
public const string NumberOfTransportSends = nameof(NumberOfTransportSends);
|
||||
public const string NumberOfTransportSendQueues = nameof(NumberOfTransportSendQueues);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c5bc85b7565054d6295b7847967cdbd8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,442 @@
|
|||
#pragma warning disable 618
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace MLAPI.Transports.UNET
|
||||
{
|
||||
public static class RelayTransport
|
||||
{
|
||||
private enum MessageType
|
||||
{
|
||||
StartServer,
|
||||
ConnectToServer,
|
||||
Data,
|
||||
ClientDisconnect,
|
||||
AddressReport
|
||||
}
|
||||
|
||||
private static byte s_DefaultChannelId;
|
||||
private static int s_RelayConnectionId;
|
||||
private static bool s_IsClient = false;
|
||||
private static string s_Address;
|
||||
private static ushort s_Port;
|
||||
private static List<ChannelQOS> s_Channels = new List<ChannelQOS>();
|
||||
|
||||
public static bool Enabled { get; set; } = true;
|
||||
public static string RelayAddress { get; set; } = "127.0.0.1";
|
||||
public static ushort RelayPort { get; set; } = 8888;
|
||||
|
||||
public static event Action<IPEndPoint> OnRemoteEndpointReported;
|
||||
|
||||
public static int Connect(int hostId, string serverAddress, int serverPort, int exceptionConnectionId, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.Connect(hostId, serverAddress, serverPort, exceptionConnectionId, out error);
|
||||
|
||||
s_IsClient = true;
|
||||
|
||||
s_Address = serverAddress;
|
||||
s_Port = (ushort)serverPort;
|
||||
|
||||
s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(hostId, RelayAddress, RelayPort, exceptionConnectionId, out error); // Requests connection
|
||||
|
||||
return s_RelayConnectionId;
|
||||
}
|
||||
|
||||
public static int ConnectWithSimulator(int hostId, string serverAddress, int serverPort, int exceptionConnectionId, out byte error, ConnectionSimulatorConfig conf)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.ConnectWithSimulator(hostId, serverAddress, serverPort, exceptionConnectionId, out error, conf);
|
||||
|
||||
s_IsClient = true;
|
||||
|
||||
s_Address = serverAddress;
|
||||
s_Port = (ushort)serverPort;
|
||||
|
||||
s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.ConnectWithSimulator(hostId, RelayAddress, RelayPort, exceptionConnectionId, out error, conf); // Requests connection
|
||||
|
||||
return s_RelayConnectionId;
|
||||
}
|
||||
|
||||
public static int ConnectEndPoint(int hostId, EndPoint endPoint, int exceptionConnectionId, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.ConnectEndPoint(hostId, endPoint, exceptionConnectionId, out error);
|
||||
|
||||
s_IsClient = true;
|
||||
|
||||
s_Address = ((IPEndPoint)endPoint).Address.ToString();
|
||||
s_Port = (ushort)((IPEndPoint)endPoint).Port;
|
||||
|
||||
s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(hostId, RelayAddress, RelayPort, exceptionConnectionId, out error); // Requests connection
|
||||
|
||||
return s_RelayConnectionId;
|
||||
}
|
||||
|
||||
private static void SetChannelsFromTopology(HostTopology topology) => s_Channels = topology.DefaultConfig.Channels;
|
||||
|
||||
public static int AddHost(HostTopology topology, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddHost(topology, 0, null);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddHost(topology, 0, null);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddHost(HostTopology topology, int port, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddHost(topology, port);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddHost(topology, port);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddHost(HostTopology topology, int port, string ip, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddHost(topology, port, ip);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddHost(topology, port, ip);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, int port, string ip, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port, ip);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, int port, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddWebsocketHost(HostTopology topology, int port, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, port);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, port);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int AddWebsocketHost(HostTopology topology, int port, string ip, bool createServer)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, port, ip);
|
||||
|
||||
s_IsClient = !createServer;
|
||||
|
||||
s_DefaultChannelId = topology.DefaultConfig.AddChannel(QosType.ReliableSequenced);
|
||||
|
||||
SetChannelsFromTopology(topology);
|
||||
|
||||
int ret = UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, port, ip);
|
||||
|
||||
if (createServer) s_RelayConnectionId = UnityEngine.Networking.NetworkTransport.Connect(ret, RelayAddress, RelayPort, 0, out byte b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static readonly byte[] disconnectBuffer = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, (byte)MessageType.ClientDisconnect };
|
||||
|
||||
public static bool Disconnect(int hostId, int connectionId, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.Disconnect(hostId, connectionId, out error);
|
||||
|
||||
if (!s_IsClient)
|
||||
{
|
||||
for (byte i = 0; i < sizeof(ulong); i++) disconnectBuffer[i] = ((byte)((ulong)connectionId >> (i * 8)));
|
||||
|
||||
return UnityEngine.Networking.NetworkTransport.Send(hostId, s_RelayConnectionId, s_DefaultChannelId, disconnectBuffer, 9, out error);
|
||||
}
|
||||
|
||||
return UnityEngine.Networking.NetworkTransport.Disconnect(hostId, connectionId, out error);
|
||||
}
|
||||
|
||||
public static bool Send(int hostId, int connectionId, int channelId, byte[] buffer, int size, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.Send(hostId, connectionId, channelId, buffer, size, out error);
|
||||
|
||||
++size;
|
||||
|
||||
if (!s_IsClient)
|
||||
{
|
||||
size += 8;
|
||||
|
||||
int connectionIdOffset = size - 9;
|
||||
|
||||
for (byte i = 0; i < sizeof(ulong); i++) buffer[connectionIdOffset + i] = ((byte)((ulong)connectionId >> (i * 8)));
|
||||
}
|
||||
|
||||
buffer[size - 1] = (byte)MessageType.Data;
|
||||
|
||||
return UnityEngine.Networking.NetworkTransport.Send(hostId, s_RelayConnectionId, channelId, buffer, size, out error);
|
||||
}
|
||||
|
||||
public static bool QueueMessageForSending(int hostId, int connectionId, int channelId, byte[] buffer, int size, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.QueueMessageForSending(hostId, connectionId, channelId, buffer, size, out error);
|
||||
|
||||
++size;
|
||||
|
||||
if (!s_IsClient)
|
||||
{
|
||||
size += 8;
|
||||
|
||||
int connectionIdOffset = size - 9;
|
||||
|
||||
for (byte i = 0; i < sizeof(ulong); i++) buffer[connectionIdOffset + i] = ((byte)((ulong)connectionId >> (i * 8)));
|
||||
}
|
||||
|
||||
buffer[size - 1] = (byte)MessageType.Data;
|
||||
|
||||
return UnityEngine.Networking.NetworkTransport.QueueMessageForSending(hostId, s_RelayConnectionId, channelId, buffer, size, out error);
|
||||
}
|
||||
|
||||
public static bool SendQueuedMessages(int hostId, int connectionId, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.SendQueuedMessages(hostId, connectionId, out error);
|
||||
|
||||
return UnityEngine.Networking.NetworkTransport.SendQueuedMessages(hostId, s_RelayConnectionId, out error);
|
||||
}
|
||||
|
||||
public static NetworkEventType ReceiveFromHost(int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.ReceiveFromHost(hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
|
||||
|
||||
var eventType = UnityEngine.Networking.NetworkTransport.ReceiveFromHost(hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
|
||||
|
||||
return BaseReceive(eventType, hostId, ref connectionId, ref channelId, buffer, bufferSize, ref receivedSize, ref error);
|
||||
}
|
||||
|
||||
public static NetworkEventType Receive(out int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
|
||||
{
|
||||
if (!Enabled) return UnityEngine.Networking.NetworkTransport.Receive(out hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
|
||||
|
||||
var eventType = UnityEngine.Networking.NetworkTransport.Receive(out hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
|
||||
|
||||
return BaseReceive(eventType, hostId, ref connectionId, ref channelId, buffer, bufferSize, ref receivedSize, ref error);
|
||||
}
|
||||
|
||||
private static NetworkEventType BaseReceive(NetworkEventType netEvent, int hostId, ref int connectionId, ref int channelId, byte[] buffer, int bufferSize, ref int receivedSize, ref byte error)
|
||||
{
|
||||
switch (netEvent)
|
||||
{
|
||||
case NetworkEventType.DataEvent:
|
||||
{
|
||||
var messageType = (MessageType)buffer[receivedSize - 1];
|
||||
|
||||
switch (messageType)
|
||||
{
|
||||
case MessageType.AddressReport:
|
||||
{
|
||||
byte[] addressBytes = new byte[16];
|
||||
|
||||
for (int i = 0; i < addressBytes.Length; i++)
|
||||
{
|
||||
addressBytes[i] = buffer[i];
|
||||
}
|
||||
|
||||
ushort remotePort = (ushort)(((ushort)buffer[16]) |
|
||||
((ushort)buffer[17] << 8));
|
||||
|
||||
var remoteEndPoint = new IPEndPoint(new IPAddress(addressBytes), remotePort);
|
||||
|
||||
OnRemoteEndpointReported?.Invoke(remoteEndPoint);
|
||||
|
||||
break;
|
||||
}
|
||||
case MessageType.ConnectToServer: // Connection approved
|
||||
{
|
||||
if (!s_IsClient)
|
||||
{
|
||||
ulong _connectionId = (((ulong)buffer[receivedSize - 9]) |
|
||||
((ulong)buffer[receivedSize - 8] << 8) |
|
||||
((ulong)buffer[receivedSize - 7] << 16) |
|
||||
((ulong)buffer[receivedSize - 6] << 24) |
|
||||
((ulong)buffer[receivedSize - 5] << 32) |
|
||||
((ulong)buffer[receivedSize - 4] << 40) |
|
||||
((ulong)buffer[receivedSize - 3] << 48) |
|
||||
((ulong)buffer[receivedSize - 2] << 56));
|
||||
|
||||
connectionId = (int)_connectionId;
|
||||
}
|
||||
|
||||
return NetworkEventType.ConnectEvent;
|
||||
}
|
||||
case MessageType.Data:
|
||||
{
|
||||
// Implicitly remove header
|
||||
if (s_IsClient) --receivedSize;
|
||||
else
|
||||
{
|
||||
receivedSize -= 9;
|
||||
|
||||
ulong _connectionId = (((ulong)buffer[receivedSize]) |
|
||||
((ulong)buffer[receivedSize + 1] << 8) |
|
||||
((ulong)buffer[receivedSize + 2] << 16) |
|
||||
((ulong)buffer[receivedSize + 3] << 24) |
|
||||
((ulong)buffer[receivedSize + 4] << 32) |
|
||||
((ulong)buffer[receivedSize + 5] << 40) |
|
||||
((ulong)buffer[receivedSize + 6] << 48) |
|
||||
((ulong)buffer[receivedSize + 7] << 56));
|
||||
|
||||
connectionId = (int)_connectionId;
|
||||
}
|
||||
|
||||
return NetworkEventType.DataEvent;
|
||||
}
|
||||
case MessageType.ClientDisconnect:
|
||||
{
|
||||
ulong _connectionId = (((ulong)buffer[0]) |
|
||||
((ulong)buffer[1] << 8) |
|
||||
((ulong)buffer[2] << 16) |
|
||||
((ulong)buffer[3] << 24) |
|
||||
((ulong)buffer[4] << 32) |
|
||||
((ulong)buffer[5] << 40) |
|
||||
((ulong)buffer[6] << 48) |
|
||||
((ulong)buffer[7] << 56));
|
||||
|
||||
connectionId = (int)_connectionId;
|
||||
|
||||
return NetworkEventType.DisconnectEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetworkEventType.ConnectEvent:
|
||||
{
|
||||
if (s_IsClient)
|
||||
{
|
||||
//Connect via relay
|
||||
|
||||
byte[] ipv6AddressBuffer;
|
||||
var ipAddress = IPAddress.Parse(s_Address);
|
||||
|
||||
if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
|
||||
{
|
||||
ipv6AddressBuffer = ipAddress.GetAddressBytes();
|
||||
}
|
||||
else if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
||||
{
|
||||
byte[] ipv4Address = ipAddress.GetAddressBytes();
|
||||
ipv6AddressBuffer = new byte[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, ipv4Address[0], ipv4Address[1], ipv4Address[2], ipv4Address[3] };
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Throw wrong type
|
||||
ipv6AddressBuffer = null;
|
||||
}
|
||||
|
||||
// TODO: Throw if address is not 16 bytes. It should always be
|
||||
for (int i = 0; i < ipv6AddressBuffer.Length; i++) buffer[i] = ipv6AddressBuffer[i];
|
||||
|
||||
for (byte i = 0; i < sizeof(ushort); i++) buffer[16 + i] = ((byte)(s_Port >> (i * 8)));
|
||||
|
||||
buffer[16 + 2] = (byte)MessageType.ConnectToServer;
|
||||
|
||||
UnityEngine.Networking.NetworkTransport.Send(hostId, connectionId, s_DefaultChannelId, buffer, 16 + 2 + 1, out error);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Register us as a server
|
||||
buffer[0] = (byte)MessageType.StartServer;
|
||||
|
||||
UnityEngine.Networking.NetworkTransport.Send(hostId, connectionId, s_DefaultChannelId, buffer, 1, out error);
|
||||
}
|
||||
|
||||
return NetworkEventType.Nothing; // Connect event is ignored
|
||||
}
|
||||
case NetworkEventType.DisconnectEvent:
|
||||
{
|
||||
if ((NetworkError)error == NetworkError.CRCMismatch) Debug.LogError("[MLAPI.Relay] The MLAPI Relay detected a CRC mismatch. This could be due to the maxClients or other connectionConfig settings not being the same");
|
||||
|
||||
return NetworkEventType.DisconnectEvent;
|
||||
}
|
||||
}
|
||||
|
||||
return netEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public class InvalidConfigException : SystemException
|
||||
{
|
||||
public InvalidConfigException() { }
|
||||
public InvalidConfigException(string issue) : base(issue) { }
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning restore 618
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 11544f78e46198d4cb39bfb970a357aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace MLAPI.Transports
|
||||
{
|
||||
/// <summary>
|
||||
/// A transport channel used by the MLAPI
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UNetChannel
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the channel
|
||||
/// </summary>
|
||||
public NetworkChannel Id;
|
||||
|
||||
/// <summary>
|
||||
/// The type of channel
|
||||
/// </summary>
|
||||
public QosType Type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e864534da30ef604992c0ed33c75d3c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,475 @@
|
|||
#pragma warning disable 618
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MLAPI.Exceptions;
|
||||
using MLAPI.Logging;
|
||||
using MLAPI.Profiling;
|
||||
using MLAPI.Transports.Tasks;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace MLAPI.Transports.UNET
|
||||
{
|
||||
public class UNetTransport : NetworkTransport, ITransportProfilerData
|
||||
{
|
||||
public enum SendMode
|
||||
{
|
||||
Immediately,
|
||||
Queued
|
||||
}
|
||||
|
||||
private static ProfilingDataStore s_TransportProfilerData = new ProfilingDataStore();
|
||||
public static bool ProfilerEnabled;
|
||||
|
||||
// Inspector / settings
|
||||
public int MessageBufferSize = 1024 * 5;
|
||||
public int MaxConnections = 100;
|
||||
public int MaxSentMessageQueueSize = 128;
|
||||
|
||||
public string ConnectAddress = "127.0.0.1";
|
||||
public int ConnectPort = 7777;
|
||||
public int ServerListenPort = 7777;
|
||||
public int ServerWebsocketListenPort = 8887;
|
||||
public bool SupportWebsocket = false;
|
||||
|
||||
// user-definable channels. To add your own channel, do something of the form:
|
||||
// #define MY_CHANNEL 0
|
||||
// ...
|
||||
// transport.Channels.Add(
|
||||
// new UNetChannel()
|
||||
// {
|
||||
// Id = Channel.ChannelUnused + MY_CHANNEL, <<-- must offset from reserved channel offset in MLAPI SDK
|
||||
// Type = QosType.Unreliable
|
||||
// }
|
||||
// );
|
||||
public List<UNetChannel> Channels = new List<UNetChannel>();
|
||||
|
||||
// Relay
|
||||
public bool UseMLAPIRelay = false;
|
||||
public string MLAPIRelayAddress = "184.72.104.138";
|
||||
public int MLAPIRelayPort = 8888;
|
||||
|
||||
public SendMode MessageSendMode = SendMode.Immediately;
|
||||
|
||||
// Runtime / state
|
||||
private byte[] m_MessageBuffer;
|
||||
private WeakReference m_TemporaryBufferReference;
|
||||
|
||||
// Lookup / translation
|
||||
private readonly Dictionary<NetworkChannel, int> m_ChannelNameToId = new Dictionary<NetworkChannel, int>();
|
||||
private readonly Dictionary<int, NetworkChannel> m_ChannelIdToName = new Dictionary<int, NetworkChannel>();
|
||||
private int m_ServerConnectionId;
|
||||
private int m_ServerHostId;
|
||||
|
||||
private SocketTask m_ConnectTask;
|
||||
public override ulong ServerClientId => GetMLAPIClientId(0, 0, true);
|
||||
|
||||
protected void LateUpdate()
|
||||
{
|
||||
if (UnityEngine.Networking.NetworkTransport.IsStarted && MessageSendMode == SendMode.Queued)
|
||||
{
|
||||
if (NetworkManager.Singleton.IsServer)
|
||||
{
|
||||
for (int i = 0; i < NetworkManager.Singleton.ConnectedClientsList.Count; i++)
|
||||
{
|
||||
SendQueued(NetworkManager.Singleton.ConnectedClientsList[i].ClientId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SendQueued(NetworkManager.Singleton.LocalClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(ulong clientId, ArraySegment<byte> data, NetworkChannel networkChannel)
|
||||
{
|
||||
if (ProfilerEnabled)
|
||||
{
|
||||
s_TransportProfilerData.Increment(ProfilerConstants.NumberOfTransportSends);
|
||||
}
|
||||
|
||||
GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);
|
||||
|
||||
int channelId = 0;
|
||||
|
||||
if (m_ChannelNameToId.ContainsKey(networkChannel))
|
||||
{
|
||||
channelId = m_ChannelNameToId[networkChannel];
|
||||
}
|
||||
else
|
||||
{
|
||||
channelId = m_ChannelNameToId[NetworkChannel.Internal];
|
||||
}
|
||||
|
||||
byte[] buffer;
|
||||
|
||||
if (data.Offset > 0)
|
||||
{
|
||||
// UNET cant handle this, do a copy
|
||||
|
||||
if (m_MessageBuffer.Length >= data.Count)
|
||||
{
|
||||
buffer = m_MessageBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
object bufferRef = null;
|
||||
if (m_TemporaryBufferReference != null && ((bufferRef = m_TemporaryBufferReference.Target) != null) && ((byte[])bufferRef).Length >= data.Count)
|
||||
{
|
||||
buffer = (byte[])bufferRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = new byte[data.Count];
|
||||
m_TemporaryBufferReference = new WeakReference(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(data.Array, data.Offset, buffer, 0, data.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = data.Array;
|
||||
}
|
||||
|
||||
if (MessageSendMode == SendMode.Queued)
|
||||
{
|
||||
RelayTransport.QueueMessageForSending(hostId, connectionId, channelId, buffer, data.Count, out byte error);
|
||||
}
|
||||
else
|
||||
{
|
||||
RelayTransport.Send(hostId, connectionId, channelId, buffer, data.Count, out byte error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SendQueued(ulong clientId)
|
||||
{
|
||||
if (ProfilerEnabled)
|
||||
{
|
||||
s_TransportProfilerData.Increment(ProfilerConstants.NumberOfTransportSendQueues);
|
||||
}
|
||||
|
||||
GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);
|
||||
|
||||
RelayTransport.SendQueuedMessages(hostId, connectionId, out byte error);
|
||||
}
|
||||
|
||||
public override NetworkEvent PollEvent(out ulong clientId, out NetworkChannel networkChannel, out ArraySegment<byte> payload, out float receiveTime)
|
||||
{
|
||||
var eventType = RelayTransport.Receive(out int hostId, out int connectionId, out int channelId, m_MessageBuffer, m_MessageBuffer.Length, out int receivedSize, out byte error);
|
||||
|
||||
clientId = GetMLAPIClientId((byte)hostId, (ushort)connectionId, false);
|
||||
receiveTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
|
||||
var networkError = (NetworkError)error;
|
||||
if (networkError == NetworkError.MessageToLong)
|
||||
{
|
||||
byte[] tempBuffer;
|
||||
|
||||
if (m_TemporaryBufferReference != null && m_TemporaryBufferReference.IsAlive && ((byte[])m_TemporaryBufferReference.Target).Length >= receivedSize)
|
||||
{
|
||||
tempBuffer = (byte[])m_TemporaryBufferReference.Target;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer = new byte[receivedSize];
|
||||
m_TemporaryBufferReference = new WeakReference(tempBuffer);
|
||||
}
|
||||
|
||||
eventType = RelayTransport.Receive(out hostId, out connectionId, out channelId, tempBuffer, tempBuffer.Length, out receivedSize, out error);
|
||||
payload = new ArraySegment<byte>(tempBuffer, 0, receivedSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload = new ArraySegment<byte>(m_MessageBuffer, 0, receivedSize);
|
||||
}
|
||||
|
||||
if (m_ChannelIdToName.ContainsKey(channelId))
|
||||
{
|
||||
networkChannel = m_ChannelIdToName[channelId];
|
||||
}
|
||||
else
|
||||
{
|
||||
networkChannel = NetworkChannel.Internal;
|
||||
}
|
||||
|
||||
if (m_ConnectTask != null && hostId == m_ServerHostId && connectionId == m_ServerConnectionId)
|
||||
{
|
||||
if (eventType == NetworkEventType.ConnectEvent)
|
||||
{
|
||||
// We just got a response to our connect request.
|
||||
m_ConnectTask.Message = null;
|
||||
m_ConnectTask.SocketError = networkError == NetworkError.Ok ? System.Net.Sockets.SocketError.Success : System.Net.Sockets.SocketError.SocketError;
|
||||
m_ConnectTask.State = null;
|
||||
m_ConnectTask.Success = networkError == NetworkError.Ok;
|
||||
m_ConnectTask.TransportCode = (byte)networkError;
|
||||
m_ConnectTask.TransportException = null;
|
||||
m_ConnectTask.IsDone = true;
|
||||
|
||||
m_ConnectTask = null;
|
||||
}
|
||||
else if (eventType == NetworkEventType.DisconnectEvent)
|
||||
{
|
||||
// We just got a response to our connect request.
|
||||
m_ConnectTask.Message = null;
|
||||
m_ConnectTask.SocketError = System.Net.Sockets.SocketError.SocketError;
|
||||
m_ConnectTask.State = null;
|
||||
m_ConnectTask.Success = false;
|
||||
m_ConnectTask.TransportCode = (byte)networkError;
|
||||
m_ConnectTask.TransportException = null;
|
||||
m_ConnectTask.IsDone = true;
|
||||
|
||||
m_ConnectTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (networkError == NetworkError.Timeout)
|
||||
{
|
||||
// In UNET. Timeouts are not disconnects. We have to translate that here.
|
||||
eventType = NetworkEventType.DisconnectEvent;
|
||||
}
|
||||
|
||||
// Translate NetworkEventType to NetEventType
|
||||
switch (eventType)
|
||||
{
|
||||
case NetworkEventType.DataEvent:
|
||||
return NetworkEvent.Data;
|
||||
case NetworkEventType.ConnectEvent:
|
||||
return NetworkEvent.Connect;
|
||||
case NetworkEventType.DisconnectEvent:
|
||||
return NetworkEvent.Disconnect;
|
||||
case NetworkEventType.Nothing:
|
||||
return NetworkEvent.Nothing;
|
||||
case NetworkEventType.BroadcastEvent:
|
||||
return NetworkEvent.Nothing;
|
||||
}
|
||||
|
||||
return NetworkEvent.Nothing;
|
||||
}
|
||||
|
||||
public override SocketTasks StartClient()
|
||||
{
|
||||
var socketTask = SocketTask.Working;
|
||||
|
||||
m_ServerHostId = RelayTransport.AddHost(new HostTopology(GetConfig(), 1), false);
|
||||
m_ServerConnectionId = RelayTransport.Connect(m_ServerHostId, ConnectAddress, ConnectPort, 0, out byte error);
|
||||
|
||||
var connectError = (NetworkError)error;
|
||||
|
||||
switch (connectError)
|
||||
{
|
||||
case NetworkError.Ok:
|
||||
socketTask.Success = true;
|
||||
socketTask.TransportCode = error;
|
||||
socketTask.SocketError = System.Net.Sockets.SocketError.Success;
|
||||
socketTask.IsDone = false;
|
||||
|
||||
// We want to continue to wait for the successful connect
|
||||
m_ConnectTask = socketTask;
|
||||
break;
|
||||
default:
|
||||
socketTask.Success = false;
|
||||
socketTask.TransportCode = error;
|
||||
socketTask.SocketError = System.Net.Sockets.SocketError.SocketError;
|
||||
socketTask.IsDone = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return socketTask.AsTasks();
|
||||
}
|
||||
|
||||
public override SocketTasks StartServer()
|
||||
{
|
||||
var topology = new HostTopology(GetConfig(), MaxConnections);
|
||||
|
||||
if (SupportWebsocket)
|
||||
{
|
||||
if (!UseMLAPIRelay)
|
||||
{
|
||||
int websocketHostId = UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, ServerWebsocketListenPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkLog.CurrentLogLevel <= LogLevel.Error) NetworkLog.LogError("Cannot create websocket host when using MLAPI relay");
|
||||
}
|
||||
}
|
||||
|
||||
int normalHostId = RelayTransport.AddHost(topology, ServerListenPort, true);
|
||||
|
||||
return SocketTask.Done.AsTasks();
|
||||
}
|
||||
|
||||
public override void DisconnectRemoteClient(ulong clientId)
|
||||
{
|
||||
GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);
|
||||
|
||||
RelayTransport.Disconnect((int)hostId, (int)connectionId, out byte error);
|
||||
}
|
||||
|
||||
public override void DisconnectLocalClient()
|
||||
{
|
||||
RelayTransport.Disconnect(m_ServerHostId, m_ServerConnectionId, out byte error);
|
||||
}
|
||||
|
||||
public override ulong GetCurrentRtt(ulong clientId)
|
||||
{
|
||||
GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);
|
||||
|
||||
if (UseMLAPIRelay)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ulong)UnityEngine.Networking.NetworkTransport.GetCurrentRTT((int)hostId, (int)connectionId, out byte error);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
m_ChannelIdToName.Clear();
|
||||
m_ChannelNameToId.Clear();
|
||||
UnityEngine.Networking.NetworkTransport.Shutdown();
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
UpdateRelay();
|
||||
|
||||
m_MessageBuffer = new byte[MessageBufferSize];
|
||||
|
||||
s_TransportProfilerData.Clear();
|
||||
|
||||
UnityEngine.Networking.NetworkTransport.Init();
|
||||
}
|
||||
|
||||
public ulong GetMLAPIClientId(byte hostId, ushort connectionId, bool isServer)
|
||||
{
|
||||
if (isServer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((ulong)connectionId | (ulong)hostId << 16) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void GetUNetConnectionDetails(ulong clientId, out byte hostId, out ushort connectionId)
|
||||
{
|
||||
if (clientId == 0)
|
||||
{
|
||||
hostId = (byte)m_ServerHostId;
|
||||
connectionId = (ushort)m_ServerConnectionId;
|
||||
}
|
||||
else
|
||||
{
|
||||
hostId = (byte)((clientId - 1) >> 16);
|
||||
connectionId = (ushort)((clientId - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionConfig GetConfig()
|
||||
{
|
||||
var connectionConfig = new ConnectionConfig();
|
||||
|
||||
// MLAPI built-in channels
|
||||
for (int i = 0; i < MLAPI_CHANNELS.Length; i++)
|
||||
{
|
||||
int channelId = AddMLAPIChannel(MLAPI_CHANNELS[i].Delivery, connectionConfig);
|
||||
|
||||
m_ChannelIdToName.Add(channelId, MLAPI_CHANNELS[i].Channel);
|
||||
m_ChannelNameToId.Add(MLAPI_CHANNELS[i].Channel, channelId);
|
||||
}
|
||||
|
||||
// Custom user-added channels
|
||||
for (int i = 0; i < Channels.Count; i++)
|
||||
{
|
||||
int channelId = AddUNETChannel(Channels[i].Type, connectionConfig);
|
||||
|
||||
if (m_ChannelNameToId.ContainsKey(Channels[i].Id))
|
||||
{
|
||||
throw new InvalidChannelException($"Channel {channelId} already exists");
|
||||
}
|
||||
|
||||
m_ChannelIdToName.Add(channelId, Channels[i].Id);
|
||||
m_ChannelNameToId.Add(Channels[i].Id, channelId);
|
||||
}
|
||||
|
||||
connectionConfig.MaxSentMessageQueueSize = (ushort)MaxSentMessageQueueSize;
|
||||
|
||||
return connectionConfig;
|
||||
}
|
||||
|
||||
public int AddMLAPIChannel(NetworkDelivery type, ConnectionConfig config)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NetworkDelivery.Unreliable:
|
||||
return config.AddChannel(QosType.Unreliable);
|
||||
case NetworkDelivery.Reliable:
|
||||
return config.AddChannel(QosType.Reliable);
|
||||
case NetworkDelivery.ReliableSequenced:
|
||||
return config.AddChannel(QosType.ReliableSequenced);
|
||||
case NetworkDelivery.ReliableFragmentedSequenced:
|
||||
return config.AddChannel(QosType.ReliableFragmentedSequenced);
|
||||
case NetworkDelivery.UnreliableSequenced:
|
||||
return config.AddChannel(QosType.UnreliableSequenced);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int AddUNETChannel(QosType type, ConnectionConfig config)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case QosType.Unreliable:
|
||||
return config.AddChannel(QosType.Unreliable);
|
||||
case QosType.UnreliableFragmented:
|
||||
return config.AddChannel(QosType.UnreliableFragmented);
|
||||
case QosType.UnreliableSequenced:
|
||||
return config.AddChannel(QosType.UnreliableSequenced);
|
||||
case QosType.Reliable:
|
||||
return config.AddChannel(QosType.Reliable);
|
||||
case QosType.ReliableFragmented:
|
||||
return config.AddChannel(QosType.ReliableFragmented);
|
||||
case QosType.ReliableSequenced:
|
||||
return config.AddChannel(QosType.ReliableSequenced);
|
||||
case QosType.StateUpdate:
|
||||
return config.AddChannel(QosType.StateUpdate);
|
||||
case QosType.ReliableStateUpdate:
|
||||
return config.AddChannel(QosType.ReliableStateUpdate);
|
||||
case QosType.AllCostDelivery:
|
||||
return config.AddChannel(QosType.AllCostDelivery);
|
||||
case QosType.UnreliableFragmentedSequenced:
|
||||
return config.AddChannel(QosType.UnreliableFragmentedSequenced);
|
||||
case QosType.ReliableFragmentedSequenced:
|
||||
return config.AddChannel(QosType.ReliableFragmentedSequenced);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void UpdateRelay()
|
||||
{
|
||||
RelayTransport.Enabled = UseMLAPIRelay;
|
||||
RelayTransport.RelayAddress = MLAPIRelayAddress;
|
||||
RelayTransport.RelayPort = (ushort)MLAPIRelayPort;
|
||||
}
|
||||
|
||||
public void BeginNewTick()
|
||||
{
|
||||
s_TransportProfilerData.Clear();
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, int> GetTransportProfilerData()
|
||||
{
|
||||
return s_TransportProfilerData.GetReadonly();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning restore 618
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b84c2d8dfe509a34fb59e2b81f8e1319
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue