Skip to content

Commit 69ff930

Browse files
committed
feat: Added transport multiplex adapter
1 parent 4b0936e commit 69ff930

File tree

3 files changed

+303
-1
lines changed

3 files changed

+303
-1
lines changed
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
using System;
2+
3+
namespace MLAPI.Transports.Multiplex
4+
{
5+
public class MultiplexTransportAdapter : Transport
6+
{
7+
/// <summary>
8+
/// The method to use to distribute the transport connectionIds in a fixed size 64 bit integer.
9+
/// </summary>
10+
public enum ConnectionIdSpreadMethod
11+
{
12+
/// <summary>
13+
/// Drops the first few bits (left side) by shifting the transport clientId to the left and inserting the transportId in the first bits.
14+
/// Ensure that ALL transports dont use the last bits in their produced clientId.
15+
/// For incremental clientIds, this is the most space efficient assuming that every transport get used an equal amount.
16+
/// </summary>
17+
MakeRoomLastBits,
18+
/// <summary>
19+
/// Drops the first few bits (left side) and replaces them with the transport index.
20+
/// Ensure that ALL transports dont use the first few bits in the produced clientId.
21+
/// </summary>
22+
ReplaceFirstBits,
23+
/// <summary>
24+
/// Drops the last few bits (right side) and replaces them with the transport index.
25+
/// Ensure that ALL transports dont use the last bits in their produced clientId.
26+
/// This option is for advanced users and will not work with the official MLAPI transports as they use the last bits.
27+
/// </summary>
28+
ReplaceLastBits,
29+
/// <summary>
30+
/// Drops the last few bits (right side) by shifting the transport clientId to the right and inserting the transportId in the first bits.
31+
/// Ensure that ALL transports dont use the first bits in their produced clientId.
32+
/// </summary>
33+
MakeRoomFirstBits,
34+
/// <summary>
35+
/// Spreads the clientIds evenly among the transports.
36+
/// </summary>
37+
Spread
38+
}
39+
40+
public ConnectionIdSpreadMethod SpreadMethod = ConnectionIdSpreadMethod.MakeRoomLastBits;
41+
public Transport[] Transports = new Transport[0];
42+
public override ulong ServerClientId => 0;
43+
44+
private byte _lastProcessedTransportIndex;
45+
46+
public override void DisconnectLocalClient()
47+
{
48+
Transports[GetFirstSupportedTransportIndex()].DisconnectLocalClient();
49+
}
50+
51+
public override void DisconnectRemoteClient(ulong clientId)
52+
{
53+
GetMultiplexTransportDetails(clientId, out byte transportId, out ulong connectionId);
54+
55+
Transports[transportId].DisconnectRemoteClient(connectionId);
56+
}
57+
58+
public override void FlushSendQueue(ulong clientId)
59+
{
60+
GetMultiplexTransportDetails(clientId, out byte transportId, out ulong connectionId);
61+
62+
Transports[transportId].FlushSendQueue(connectionId);
63+
}
64+
65+
public override ulong GetCurrentRtt(ulong clientId)
66+
{
67+
GetMultiplexTransportDetails(clientId, out byte transportId, out ulong connectionId);
68+
69+
return Transports[transportId].GetCurrentRtt(connectionId);
70+
}
71+
72+
public override void Init()
73+
{
74+
for (int i = 0; i < Transports.Length; i++)
75+
{
76+
if (Transports[i].IsSupported)
77+
{
78+
Transports[i].Init();
79+
}
80+
}
81+
}
82+
83+
public override NetEventType PollEvent(out ulong clientId, out string channelName, out ArraySegment<byte> payload)
84+
{
85+
if (_lastProcessedTransportIndex > Transports.Length)
86+
_lastProcessedTransportIndex = 0;
87+
88+
for (byte i = _lastProcessedTransportIndex; i < Transports.Length; i++)
89+
{
90+
if (Transports[i].IsSupported)
91+
{
92+
_lastProcessedTransportIndex = i;
93+
94+
return Transports[i].PollEvent(out clientId, out channelName, out payload);
95+
}
96+
}
97+
98+
clientId = 0;
99+
channelName = null;
100+
payload = new ArraySegment<byte>();
101+
102+
return NetEventType.Nothing;
103+
}
104+
105+
public override void Send(ulong clientId, ArraySegment<byte> data, string channelName, bool skipQueue)
106+
{
107+
GetMultiplexTransportDetails(clientId, out byte transportId, out ulong connectionId);
108+
109+
Transports[transportId].Send(clientId, data, channelName, skipQueue);
110+
}
111+
112+
public override void Shutdown()
113+
{
114+
for (int i = 0; i < Transports.Length; i++)
115+
{
116+
if (Transports[i].IsSupported)
117+
{
118+
Transports[i].Shutdown();
119+
}
120+
}
121+
}
122+
123+
public override void StartClient()
124+
{
125+
for (int i = 0; i < Transports.Length; i++)
126+
{
127+
if (Transports[i].IsSupported)
128+
{
129+
Transports[i].StartClient();
130+
}
131+
}
132+
}
133+
134+
public override void StartServer()
135+
{
136+
for (int i = 0; i < Transports.Length; i++)
137+
{
138+
if (Transports[i].IsSupported)
139+
{
140+
Transports[i].StartServer();
141+
}
142+
}
143+
}
144+
145+
146+
public ulong GetMLAPIClientId(byte transportId, ulong connectionId, bool isServer)
147+
{
148+
if (isServer)
149+
{
150+
return ServerClientId;
151+
}
152+
else
153+
{
154+
// 0 Is reserved.
155+
connectionId += 1;
156+
157+
switch (SpreadMethod)
158+
{
159+
case ConnectionIdSpreadMethod.ReplaceFirstBits:
160+
{
161+
// Calculate bits to store transportId
162+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
163+
164+
// Drop first bits of connectionId
165+
ulong clientId = ((connectionId << bits) >> bits);
166+
167+
// Place transportId there
168+
ulong shiftedTransportId = (ulong)transportId << ((sizeof(ulong) * 8) - bits);
169+
170+
return clientId | shiftedTransportId;
171+
}
172+
case ConnectionIdSpreadMethod.MakeRoomFirstBits:
173+
{
174+
// Calculate bits to store transportId
175+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
176+
177+
// Drop first bits of connectionId
178+
ulong clientId = (connectionId >> bits);
179+
180+
// Place transportId there
181+
ulong shiftedTransportId = (ulong)transportId << ((sizeof(ulong) * 8) - bits);
182+
183+
return clientId | shiftedTransportId;
184+
}
185+
case ConnectionIdSpreadMethod.ReplaceLastBits:
186+
{
187+
// Calculate bits to store transportId
188+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
189+
190+
// Drop the last bits of connectionId
191+
ulong clientId = ((connectionId >> bits) << bits);
192+
193+
// Return the transport inserted at the end
194+
return clientId | transportId;
195+
}
196+
case ConnectionIdSpreadMethod.MakeRoomLastBits:
197+
{
198+
// Calculate bits to store transportId
199+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
200+
201+
// Drop the last bits of connectionId
202+
ulong clientId = (connectionId << bits);
203+
204+
// Return the transport inserted at the end
205+
return clientId | transportId;
206+
}
207+
case ConnectionIdSpreadMethod.Spread:
208+
{
209+
return connectionId * (ulong)Transports.Length + (ulong)transportId;
210+
}
211+
default:
212+
{
213+
return ServerClientId;
214+
}
215+
}
216+
}
217+
}
218+
219+
public void GetMultiplexTransportDetails(ulong clientId, out byte transportId, out ulong connectionId)
220+
{
221+
if (clientId == ServerClientId)
222+
{
223+
transportId = GetFirstSupportedTransportIndex();
224+
connectionId = Transports[transportId].ServerClientId;
225+
}
226+
else
227+
{
228+
switch (SpreadMethod)
229+
{
230+
case ConnectionIdSpreadMethod.ReplaceFirstBits:
231+
{
232+
// Calculate bits to store transportId
233+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
234+
235+
transportId = (byte)(clientId >> ((sizeof(ulong) * 8) - bits));
236+
connectionId = ((clientId << bits) >> bits) + 1;
237+
break;
238+
}
239+
case ConnectionIdSpreadMethod.MakeRoomFirstBits:
240+
{
241+
// Calculate bits to store transportId
242+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
243+
244+
transportId = (byte)(clientId >> ((sizeof(ulong) * 8) - bits));
245+
connectionId = (clientId << bits) + 1;
246+
break;
247+
}
248+
case ConnectionIdSpreadMethod.ReplaceLastBits:
249+
{
250+
// Calculate bits to store transportId
251+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
252+
253+
transportId = (byte)((clientId << ((sizeof(ulong) * 8) - bits)) >> ((sizeof(ulong) * 8) - bits));
254+
connectionId = ((clientId >> bits) << bits) + 1;
255+
break;
256+
}
257+
case ConnectionIdSpreadMethod.MakeRoomLastBits:
258+
{
259+
// Calculate bits to store transportId
260+
byte bits = (byte)UnityEngine.Mathf.CeilToInt(UnityEngine.Mathf.Log(Transports.Length, 2));
261+
262+
transportId = (byte)((clientId << ((sizeof(ulong) * 8) - bits)) >> ((sizeof(ulong) * 8) - bits));
263+
connectionId = (clientId >> bits) + 1;
264+
break;
265+
}
266+
case ConnectionIdSpreadMethod.Spread:
267+
{
268+
transportId = (byte)(clientId % (ulong)Transports.Length);
269+
connectionId = (clientId / (ulong)Transports.Length) + 1;
270+
break;
271+
}
272+
default:
273+
{
274+
transportId = GetFirstSupportedTransportIndex();
275+
connectionId = Transports[transportId].ServerClientId;
276+
break;
277+
}
278+
}
279+
}
280+
}
281+
282+
public byte GetFirstSupportedTransportIndex()
283+
{
284+
for (byte i = 0; i < Transports.Length; i++)
285+
{
286+
if (Transports[i].IsSupported)
287+
{
288+
return i;
289+
}
290+
}
291+
292+
return 0;
293+
}
294+
}
295+
}

MLAPI/Transports/Transport.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ public abstract class Transport : MonoBehaviour
1414
/// </summary>
1515
public abstract ulong ServerClientId { get; }
1616

17+
/// <summary>
18+
/// Gets a value indicating whether this <see cref="T:MLAPI.Transports.Transport"/> is supported in the current runtime context.
19+
/// This is used by multiplex adapters.
20+
/// </summary>
21+
/// <value><c>true</c> if is supported; otherwise, <c>false</c>.</value>
22+
public virtual bool IsSupported => true;
23+
1724
/// <summary>
1825
/// The channels the MLAPI will use when sending internal messages.
1926
/// </summary>

docs/_pages/features.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
</tr>
4848
<tr>
4949
<td>Multiplex Transport</td>
50-
<td><i class="fa fa-times" aria-hidden="true" style="color:red"></i></td>
50+
<td><i class="fa fa-check" aria-hidden="true" style="color:green"></i></td>
5151
<td><i class="fa fa-check" aria-hidden="true" style="color:green"></i></td>
5252
<td><i class="fa fa-times" aria-hidden="true" style="color:red"></i></td>
5353
</tr>

0 commit comments

Comments
 (0)