Skip to content

Commit 1b709f5

Browse files
committed
feat(transport): Added ENET transport
1 parent 8a5183a commit 1b709f5

File tree

8 files changed

+373
-239
lines changed

8 files changed

+373
-239
lines changed

MLAPI.EnetTransport/EnetTransport.cs

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using ENet;
4+
using MLAPI.Transports;
5+
6+
namespace MLAPI.EnetTransport
7+
{
8+
public class EnetTransport : Transport
9+
{
10+
public struct EnetChannel
11+
{
12+
public byte Id;
13+
public string Name;
14+
public PacketFlags Flags;
15+
}
16+
17+
public ushort Port = 7777;
18+
public string Address = "127.0.0.1";
19+
public int MaxClients = 100;
20+
public List<TransportChannel> Channels = new List<TransportChannel>();
21+
public int MessageBufferSize = 1024 * 5;
22+
23+
24+
// Runtime / state
25+
private byte[] messageBuffer;
26+
private WeakReference temporaryBufferReference;
27+
28+
29+
private readonly Dictionary<uint, Peer> connectedEnetPeers = new Dictionary<uint, Peer>();
30+
31+
private readonly Dictionary<string, byte> channelNameToId = new Dictionary<string, byte>();
32+
private readonly Dictionary<byte, string> channelIdToName = new Dictionary<byte, string>();
33+
private readonly Dictionary<byte, EnetChannel> internalChannels = new Dictionary<byte, EnetChannel>();
34+
35+
private Host host;
36+
37+
private uint serverPeerId;
38+
39+
public override ulong ServerClientId => GetMLAPIClientId(0, true);
40+
41+
public override void Send(ulong clientId, ArraySegment<byte> data, string channelName, bool skipQueue)
42+
{
43+
Packet packet = default(Packet);
44+
45+
packet.Create(data.Array, data.Offset, data.Count, internalChannels[channelNameToId[channelName]].Flags);
46+
47+
GetEnetConnectionDetails(clientId, out uint peerId);
48+
49+
connectedEnetPeers[peerId].Send(channelNameToId[channelName], ref packet);
50+
}
51+
52+
public override void FlushSendQueue(ulong clientId)
53+
{
54+
// Not needed
55+
}
56+
57+
public override NetEventType PollEvent(out ulong clientId, out string channelName, out ArraySegment<byte> payload)
58+
{
59+
Event @event;
60+
61+
if (host.CheckEvents(out @event) <= 0 && host.Service(0, out @event) > 0)
62+
{
63+
clientId = GetMLAPIClientId(@event.Peer.ID, false);
64+
65+
switch (@event.Type)
66+
{
67+
case EventType.None:
68+
{
69+
channelName = null;
70+
return NetEventType.Nothing;
71+
}
72+
case EventType.Connect:
73+
{
74+
channelName = null;
75+
76+
connectedEnetPeers.Add(@event.Peer.ID, @event.Peer);
77+
78+
return NetEventType.Connect;
79+
}
80+
case EventType.Disconnect:
81+
{
82+
channelName = null;
83+
84+
connectedEnetPeers.Remove(@event.Peer.ID);
85+
86+
return NetEventType.Disconnect;
87+
}
88+
case EventType.Receive:
89+
{
90+
channelName = channelIdToName[@event.ChannelID];
91+
int size = @event.Packet.Length;
92+
93+
if (size > messageBuffer.Length)
94+
{
95+
byte[] tempBuffer;
96+
97+
if (temporaryBufferReference != null && temporaryBufferReference.IsAlive && ((byte[]) temporaryBufferReference.Target).Length >= size)
98+
{
99+
tempBuffer = (byte[])temporaryBufferReference.Target;
100+
}
101+
else
102+
{
103+
tempBuffer = new byte[size];
104+
temporaryBufferReference = new WeakReference(tempBuffer);
105+
}
106+
107+
@event.Packet.CopyTo(tempBuffer);
108+
payload = new ArraySegment<byte>(tempBuffer, 0, size);
109+
}
110+
else
111+
{
112+
@event.Packet.CopyTo(messageBuffer);
113+
payload = new ArraySegment<byte>(messageBuffer, 0, size);
114+
}
115+
116+
117+
@event.Packet.Dispose();
118+
return NetEventType.Data;
119+
}
120+
case EventType.Timeout:
121+
{
122+
channelName = null;
123+
124+
connectedEnetPeers.Remove(@event.Peer.ID);
125+
126+
return NetEventType.Disconnect;
127+
}
128+
default:
129+
{
130+
channelName = null;
131+
132+
return NetEventType.Nothing;
133+
}
134+
}
135+
}
136+
else
137+
{
138+
channelName = null;
139+
clientId = 0;
140+
141+
return NetEventType.Nothing;
142+
}
143+
}
144+
145+
public override void StartClient()
146+
{
147+
host = new Host();
148+
149+
Address address = new Address();
150+
151+
address.Port = Port;
152+
address.SetHost(Address);
153+
154+
host.Create(address, 1);
155+
156+
Peer serverPeer = host.Connect(address, MLAPI_CHANNELS.Length + Channels.Count);
157+
158+
serverPeerId = serverPeer.ID;
159+
}
160+
161+
public override void StartServer()
162+
{
163+
host = new Host();
164+
165+
host.SetChannelLimit(MLAPI_CHANNELS.Length + Channels.Count);
166+
167+
Address address = new Address();
168+
169+
address.Port = Port;
170+
171+
host.Create(address, MaxClients);
172+
}
173+
174+
public override void DisconnectRemoteClient(ulong clientId)
175+
{
176+
GetEnetConnectionDetails(serverPeerId, out uint peerId);
177+
178+
connectedEnetPeers[peerId].DisconnectLater(0);
179+
}
180+
181+
public override void DisconnectLocalClient()
182+
{
183+
host.Flush();
184+
185+
GetEnetConnectionDetails(serverPeerId, out uint peerId);
186+
187+
connectedEnetPeers[peerId].DisconnectNow(0);
188+
}
189+
190+
public override ulong GetCurrentRtt(ulong clientId)
191+
{
192+
GetEnetConnectionDetails(serverPeerId, out uint peerId);
193+
194+
return connectedEnetPeers[peerId].RoundTripTime;
195+
}
196+
197+
public override void Shutdown()
198+
{
199+
host.Flush();
200+
host.Dispose();
201+
Library.Deinitialize();
202+
}
203+
204+
public override void Init()
205+
{
206+
Library.Initialize();
207+
208+
internalChannels.Clear();
209+
channelIdToName.Clear();
210+
channelNameToId.Clear();
211+
212+
213+
// MLAPI Channels
214+
for (byte i = 0; i < MLAPI_CHANNELS.Length; i++)
215+
{
216+
channelIdToName.Add(i, MLAPI_CHANNELS[i].Name);
217+
channelNameToId.Add(MLAPI_CHANNELS[i].Name, i);
218+
internalChannels.Add(i, new EnetChannel()
219+
{
220+
Id = i,
221+
Name = MLAPI_CHANNELS[i].Name,
222+
Flags = ChannelTypeToPacketFlag(MLAPI_CHANNELS[i].Type)
223+
});
224+
}
225+
226+
// Internal Channels
227+
for (int i = 0; i < Channels.Count; i++)
228+
{
229+
byte id = (byte) (i + MLAPI_CHANNELS.Length);
230+
231+
channelIdToName.Add(id, Channels[i].Name);
232+
channelNameToId.Add(Channels[i].Name, id);
233+
internalChannels.Add(id, new EnetChannel()
234+
{
235+
Id = id,
236+
Name = Channels[i].Name,
237+
Flags = ChannelTypeToPacketFlag(Channels[i].Type)
238+
});
239+
}
240+
241+
messageBuffer = new byte[MessageBufferSize];
242+
}
243+
244+
public PacketFlags ChannelTypeToPacketFlag(ChannelType type)
245+
{
246+
switch (type)
247+
{
248+
case ChannelType.Unreliable:
249+
{
250+
return PacketFlags.Unsequenced | PacketFlags.UnreliableFragment;
251+
}
252+
case ChannelType.UnreliableFragmented:
253+
{
254+
return PacketFlags.Unsequenced | PacketFlags.UnreliableFragment;
255+
}
256+
case ChannelType.UnreliableSequenced:
257+
{
258+
return PacketFlags.UnreliableFragment;
259+
}
260+
case ChannelType.Reliable:
261+
{
262+
return PacketFlags.Reliable | PacketFlags.Unsequenced;
263+
}
264+
case ChannelType.ReliableFragmented:
265+
{
266+
return PacketFlags.Reliable | PacketFlags.Unsequenced;
267+
}
268+
case ChannelType.ReliableSequenced:
269+
{
270+
return PacketFlags.Reliable;
271+
}
272+
case ChannelType.StateUpdate:
273+
{
274+
return PacketFlags.None;
275+
}
276+
case ChannelType.ReliableStateUpdate:
277+
{
278+
return PacketFlags.Reliable;
279+
}
280+
case ChannelType.AllCostDelivery:
281+
{
282+
return PacketFlags.Reliable;
283+
}
284+
case ChannelType.UnreliableFragmentedSequenced:
285+
{
286+
return PacketFlags.UnreliableFragment;
287+
}
288+
case ChannelType.ReliableFragmentedSequenced:
289+
{
290+
return PacketFlags.Reliable;
291+
}
292+
default:
293+
{
294+
throw new ArgumentOutOfRangeException(nameof(type), type, null);
295+
}
296+
}
297+
}
298+
299+
public ulong GetMLAPIClientId(uint peerId, bool isServer)
300+
{
301+
if (isServer)
302+
{
303+
return 0;
304+
}
305+
else
306+
{
307+
return peerId + 1;
308+
}
309+
}
310+
311+
public void GetEnetConnectionDetails(ulong clientId, out uint peerId)
312+
{
313+
if (clientId == 0)
314+
{
315+
peerId = serverPeerId;
316+
}
317+
else
318+
{
319+
peerId = (uint)clientId - 1;
320+
}
321+
}
322+
}
323+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="../common.props" />
3+
<PropertyGroup>
4+
<ImplicitlyExpandNETStandardFacades>false</ImplicitlyExpandNETStandardFacades>
5+
<DisableHandlePackageFileConflicts>true</DisableHandlePackageFileConflicts>
6+
<AssemblyTitle>MLAPI.EnetTransport</AssemblyTitle>
7+
<Product>MLAPI.EnetTransport</Product>
8+
<Description>ENET Transport for MLAPI</Description>
9+
<Version>1.0.0</Version>
10+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
11+
<TargetFrameworks>net35;net471;net45;netstandard2.0</TargetFrameworks>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
16+
<HintPath>..\Libraries\Unity\UnityEngine.dll</HintPath>
17+
<SpecificVersion>False</SpecificVersion>
18+
<Private>false</Private>
19+
</Reference>
20+
</ItemGroup>
21+
<ItemGroup>
22+
<PackageReference Include="ENet-CSharp" Version="2.2.3" />
23+
</ItemGroup>
24+
<ItemGroup>
25+
<ProjectReference Include="..\MLAPI\MLAPI.csproj" />
26+
</ItemGroup>
27+
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Runtime.InteropServices;
2+
3+
// Setting ComVisible to false makes the types in this assembly not visible
4+
// to COM components. If you need to access a type in this assembly from
5+
// COM, set the ComVisible attribute to true on that type.
6+
[assembly: ComVisible(false)]
7+
8+
// The following GUID is for the ID of the typelib if this project is exposed to COM
9+
[assembly: Guid("059FA226-17AB-4BD4-92BC-BCE3574FCAA0")]

MLAPI.sln

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MLAPI-Tests", "MLAPI-Tests\
1111
EndProject
1212
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MLAPI-Examples", "MLAPI-Examples\MLAPI-Examples.csproj", "{FED83E10-8157-42C6-A58F-C2545C0D93B4}"
1313
EndProject
14+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLAPI.EnetTransport", "MLAPI.EnetTransport\MLAPI.EnetTransport.csproj", "{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}"
15+
EndProject
1416
Global
1517
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1618
Debug_Lite|Any CPU = Debug_Lite|Any CPU
@@ -51,6 +53,14 @@ Global
5153
{FED83E10-8157-42C6-A58F-C2545C0D93B4}.Release_Lite|Any CPU.Build.0 = Release_Lite|Any CPU
5254
{FED83E10-8157-42C6-A58F-C2545C0D93B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
5355
{FED83E10-8157-42C6-A58F-C2545C0D93B4}.Release|Any CPU.Build.0 = Release|Any CPU
56+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Debug_Lite|Any CPU.ActiveCfg = Debug|Any CPU
57+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Debug_Lite|Any CPU.Build.0 = Debug|Any CPU
58+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
60+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Release_Lite|Any CPU.ActiveCfg = Debug|Any CPU
61+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Release_Lite|Any CPU.Build.0 = Debug|Any CPU
62+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
63+
{059FA226-17AB-4BD4-92BC-BCE3574FCAA0}.Release|Any CPU.Build.0 = Release|Any CPU
5464
EndGlobalSection
5565
GlobalSection(SolutionProperties) = preSolution
5666
HideSolutionNode = FALSE

0 commit comments

Comments
 (0)