Skip to content

Commit 336884d

Browse files
committed
Added MLAPI.Relay support
1 parent ee57831 commit 336884d

File tree

6 files changed

+535
-5
lines changed

6 files changed

+535
-5
lines changed

MLAPI/Data/NetworkConfig.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ public class NetworkConfig
2727
/// </summary>
2828
public IUDPTransport NetworkTransport = null;
2929
/// <summary>
30+
/// Only used if the transport is MLPAI-Relay
31+
/// </summary>
32+
public string RelayAddress;
33+
/// <summary>
34+
/// Only used if the transport is MLPAI-Relay
35+
/// </summary>
36+
public ushort RelayPort;
37+
/// <summary>
3038
/// Channels used by the NetworkedTransport
3139
/// </summary>
3240
public List<Channel> Channels = new List<Channel>();

MLAPI/Data/Transports/DefaultTransport.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ public enum DefaultTransport
1010
/// </summary>
1111
UNET,
1212
/// <summary>
13-
/// LiteNetLib transport
13+
/// MLAPI.Relay transport (UNET internally)
14+
/// </summary>
15+
MLAPI_Relay,
16+
/// <summary>
17+
/// Custom transport
1418
/// </summary>
1519
Custom
1620
}
Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net;
5+
using System.Text;
6+
using UnityEngine;
7+
using UnityEngine.Networking;
8+
9+
namespace MLAPI.Data.Transports.UNET
10+
{
11+
public static class RelayTransport
12+
{
13+
private enum MessageType
14+
{
15+
StartServer,
16+
ConnectToServer,
17+
Data,
18+
ClientDisconnect
19+
}
20+
21+
//State
22+
private static int relayConnectionId;
23+
private static bool isClient = false;
24+
private static string address;
25+
private static ushort port;
26+
private static List<ChannelQOS> channels = new List<ChannelQOS>();
27+
28+
public static int Connect(int hostId, string serverAddress, int serverPort, string relayAddress, int relayPort, int exceptionConnectionId, out byte error)
29+
{
30+
isClient = true;
31+
RelayTransport.address = serverAddress;
32+
RelayTransport.port = (ushort)serverPort;
33+
relayConnectionId = NetworkTransport.Connect(hostId, relayAddress, relayPort, exceptionConnectionId, out error); // Requests connection
34+
return relayConnectionId;
35+
// Wait here until connect event is accepted
36+
}
37+
38+
public static int ConnectWithSimulator(int hostId, string serverAddress, int serverPort, string relayAddress, int relayPort, int exceptionConnectionId, out byte error, ConnectionSimulatorConfig conf)
39+
{
40+
isClient = true;
41+
RelayTransport.address = serverAddress;
42+
RelayTransport.port = (ushort)serverPort;
43+
relayConnectionId = NetworkTransport.ConnectWithSimulator(hostId, relayAddress, relayPort, exceptionConnectionId, out error, conf); // Requests connection
44+
return relayConnectionId;
45+
}
46+
47+
public static int ConnectEndPoint(int hostId, EndPoint endPoint, string relayAddress, int relayPort, int exceptionConnectionId, out byte error)
48+
{
49+
isClient = true;
50+
RelayTransport.address = ((IPEndPoint)endPoint).Address.ToString();
51+
RelayTransport.port = (ushort)((IPEndPoint)endPoint).Port;
52+
relayConnectionId = NetworkTransport.Connect(hostId, relayAddress, relayPort, exceptionConnectionId, out error); // Requests connection
53+
return relayConnectionId;
54+
}
55+
56+
private static void SetChannelsFromTopology(HostTopology topology) => channels = topology.DefaultConfig.Channels;
57+
58+
public static int AddHost(HostTopology topology, bool createServer, string relayAddress, int relayPort)
59+
{
60+
isClient = !createServer;
61+
SetChannelsFromTopology(topology);
62+
int ret = NetworkTransport.AddHost(topology);
63+
if (createServer)
64+
{
65+
relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
66+
Debug.Log((NetworkError)b);
67+
}
68+
return ret;
69+
}
70+
public static int AddHost(HostTopology topology, int port, bool createServer, string relayAddress, int relayPort)
71+
{
72+
isClient = !createServer;
73+
SetChannelsFromTopology(topology);
74+
int ret = NetworkTransport.AddHost(topology, port);
75+
if (createServer)
76+
{
77+
relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
78+
Debug.Log((NetworkError)b);
79+
}
80+
return ret;
81+
}
82+
public static int AddHost(HostTopology topology, int port, string ip, bool createServer, string relayAddress, int relayPort)
83+
{
84+
isClient = !createServer;
85+
SetChannelsFromTopology(topology);
86+
int ret = NetworkTransport.AddHost(topology, port, ip);
87+
if (createServer)
88+
{
89+
relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
90+
Debug.Log((NetworkError)b);
91+
}
92+
return ret;
93+
}
94+
95+
public static int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, int port, string ip, bool createServer, string relayAddress, int relayPort)
96+
{
97+
isClient = !createServer;
98+
SetChannelsFromTopology(topology);
99+
int ret = NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port, ip);
100+
if (createServer) relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
101+
return ret;
102+
}
103+
104+
public static int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, bool createServer, string relayAddress, int relayPort)
105+
{
106+
isClient = !createServer;
107+
SetChannelsFromTopology(topology);
108+
int ret = NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout);
109+
if (createServer) relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
110+
return ret;
111+
}
112+
113+
public static int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, int port, bool createServer, string relayAddress, int relayPort)
114+
{
115+
isClient = !createServer;
116+
SetChannelsFromTopology(topology);
117+
int ret = NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port);
118+
if (createServer) relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
119+
return ret;
120+
}
121+
122+
public static int AddWebsocketHost(HostTopology topology, int port, bool createServer, string relayAddress, int relayPort)
123+
{
124+
isClient = !createServer;
125+
SetChannelsFromTopology(topology);
126+
int ret = NetworkTransport.AddWebsocketHost(topology, port);
127+
if (createServer) relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
128+
return ret;
129+
}
130+
131+
public static int AddWebsocketHost(HostTopology topology, int port, string ip, bool createServer, string relayAddress, int relayPort)
132+
{
133+
isClient = !createServer;
134+
SetChannelsFromTopology(topology);
135+
int ret = NetworkTransport.AddWebsocketHost(topology, port, ip);
136+
if (createServer) relayConnectionId = NetworkTransport.Connect(ret, relayAddress, relayPort, 0, out byte b);
137+
return ret;
138+
}
139+
140+
private static byte[] disconnectBuffer = new byte[3] { (byte)MessageType.ClientDisconnect, 0, 0 };
141+
public static bool Disconnect(int hostId, int connectionId, out byte error)
142+
{
143+
if (!isClient)
144+
{
145+
disconnectBuffer.ToBytes((ushort)connectionId, 1);
146+
return NetworkTransport.Send(hostId, relayConnectionId, GetReliableChannel(), disconnectBuffer, 3, out error);
147+
}
148+
else
149+
{
150+
return NetworkTransport.Disconnect(hostId, connectionId, out error);
151+
}
152+
}
153+
154+
public static bool Send(int hostId, int connectionId, int channelId, byte[] buffer, int size, out byte error)
155+
{
156+
if (isClient)
157+
{
158+
ForwardOffset(buffer, 1, size); // Offsets just the bytes we're sending
159+
++size;
160+
}
161+
else
162+
{
163+
ForwardOffset(buffer, 3, size); // Offsets just the bytes we're sending
164+
size += 3;
165+
166+
buffer[1] = (byte)connectionId;
167+
buffer[2] = (byte)(connectionId >> 8);
168+
}
169+
buffer[0] = (byte)MessageType.Data;
170+
171+
return NetworkTransport.Send(hostId, relayConnectionId, channelId, buffer, size, out error);
172+
}
173+
174+
public static bool QueueMessageForSending(int hostId, int connectionId, int channelId, byte[] buffer, int size, out byte error)
175+
{
176+
if (isClient)
177+
{
178+
ForwardOffset(buffer, 1, size); // Offsets just the bytes we're sending
179+
++size;
180+
}
181+
else
182+
{
183+
ForwardOffset(buffer, 3, size); // Offsets just the bytes we're sending
184+
size += 3;
185+
186+
buffer[1] = (byte)connectionId;
187+
buffer[2] = (byte)(connectionId >> 8);
188+
}
189+
buffer[0] = (byte)MessageType.Data;
190+
191+
return NetworkTransport.QueueMessageForSending(hostId, relayConnectionId, channelId, buffer, size, out error);
192+
}
193+
194+
public static bool SendQueuedMessages(int hostId, int connectionId, out byte error)
195+
{
196+
return NetworkTransport.SendQueuedMessages(hostId, relayConnectionId, out error);
197+
}
198+
199+
public static NetworkEventType ReceiveFromHost(int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
200+
{
201+
NetworkEventType @event = NetworkTransport.ReceiveFromHost(hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
202+
return BaseReceive(@event, hostId, ref connectionId, ref channelId, buffer, bufferSize, ref receivedSize, ref error);
203+
}
204+
205+
public static NetworkEventType Receive(out int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
206+
{
207+
NetworkEventType @event = NetworkTransport.Receive(out hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
208+
return BaseReceive(@event, hostId, ref connectionId, ref channelId, buffer, bufferSize, ref receivedSize, ref error);
209+
}
210+
211+
private static NetworkEventType BaseReceive(NetworkEventType @event, int hostId, ref int connectionId, ref int channelId, byte[] buffer, int bufferSize, ref int receivedSize, ref byte error)
212+
{
213+
switch (@event)
214+
{
215+
case NetworkEventType.DataEvent:
216+
MessageType messageType = (MessageType)buffer[0];
217+
switch (messageType)
218+
{
219+
case MessageType.ConnectToServer: // Connection approved
220+
{
221+
if (!isClient)
222+
{
223+
connectionId = (ushort)(buffer[1] | (buffer[2] << 8)); // Parse connection id
224+
}
225+
return NetworkEventType.ConnectEvent;
226+
}
227+
case MessageType.Data:
228+
{
229+
if (isClient)
230+
{
231+
// Remove our headers
232+
ReverseOffset(buffer, 1, receivedSize);
233+
--receivedSize;
234+
}
235+
else
236+
{
237+
// Remove our headers
238+
connectionId = buffer.FromBytes(1);
239+
ReverseOffset(buffer, 3, receivedSize);
240+
receivedSize -= 3;
241+
}
242+
return NetworkEventType.DataEvent;
243+
}
244+
case MessageType.ClientDisconnect:
245+
{
246+
connectionId = (ushort)(buffer[1] | (buffer[2] << 8)); // Parse connection id
247+
return NetworkEventType.DisconnectEvent;
248+
}
249+
}
250+
break;
251+
case NetworkEventType.ConnectEvent:
252+
{
253+
if (isClient)
254+
{
255+
//Connect via relay
256+
string s = new StringBuilder(address).Append(':').Append(port).ToString();
257+
buffer[0] = (byte)MessageType.ConnectToServer;
258+
buffer[1] = (byte)s.Length;
259+
for (int i = 0; i < s.Length; i++)
260+
{
261+
buffer[i + 2] = (byte)s[i]; // Get ASCII characters
262+
}
263+
264+
NetworkTransport.Send(hostId, connectionId, GetReliableChannel(), buffer, s.Length + 2, out error);
265+
}
266+
else
267+
{
268+
//Register us as a server
269+
buffer[0] = (byte)MessageType.StartServer;
270+
NetworkTransport.Send(hostId, connectionId, GetReliableChannel(), buffer, 1, out error);
271+
}
272+
return NetworkEventType.Nothing; // Connect event is ignored
273+
}
274+
case NetworkEventType.DisconnectEvent:
275+
{
276+
if ((NetworkError)error == NetworkError.CRCMismatch) Debug.LogError("[MLAPI.Relay] The MLAPI Relay detected a CRC missmatch. This could be due to the maxClients or other connectionConfig settings not being the same");
277+
return NetworkEventType.DisconnectEvent;
278+
}
279+
}
280+
return @event;
281+
}
282+
283+
public static void ReverseOffset(byte[] b, int offset, int dLen)
284+
{
285+
for (int i = offset; i < dLen; ++i)
286+
b[i - offset] = b[i];
287+
}
288+
289+
public static void ForwardOffset(byte[] b, int offset, int dLen)
290+
{
291+
for (int i = dLen; i >= 0; --i)
292+
b[i + offset] = b[i];
293+
}
294+
295+
//TODO: Fix
296+
public static byte GetReliableChannel()
297+
{
298+
for (byte i = 0; i < channels.Count; i++)
299+
{
300+
switch (channels[i].QOS)
301+
{
302+
case QosType.Reliable:
303+
case QosType.ReliableFragmented:
304+
case QosType.ReliableFragmentedSequenced:
305+
case QosType.ReliableSequenced:
306+
case QosType.ReliableStateUpdate:
307+
return i;
308+
}
309+
}
310+
throw new InvalidConfigException("A reliable channel is required");
311+
}
312+
}
313+
314+
public static class Helpers
315+
{
316+
public static void ToBytes(this byte[] b, ushort data, int offset = 0)
317+
{
318+
b[offset] = (byte)data;
319+
b[offset + 1] = (byte)(data >> 8);
320+
}
321+
public static ushort FromBytes(this byte[] b, int offset = 0)
322+
{
323+
return (ushort)(b[offset] | (b[offset + 1] << 8));
324+
}
325+
}
326+
327+
public class InvalidConfigException : SystemException
328+
{
329+
public InvalidConfigException() { }
330+
public InvalidConfigException(string issue) : base(issue) { }
331+
}
332+
}

0 commit comments

Comments
 (0)