Skip to content

Commit ff84ee2

Browse files
committed
Transport sharing WIP
1 parent 526f30b commit ff84ee2

File tree

5 files changed

+311
-0
lines changed

5 files changed

+311
-0
lines changed

com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ public override bool Initialize(string defaultWorldName)
9999
OnInitialized?.Invoke(initialized);
100100
return initialized;
101101
}
102+
103+
public static void StopClient()
104+
{
105+
ClientWorld.Dispose();
106+
ClientWorlds.Remove(ClientWorld);
107+
}
108+
109+
public static void StopServer()
110+
{
111+
ServerWorld.Dispose();
112+
ServerWorlds.Remove(ServerWorld);
113+
}
102114

103115
~UnifiedBootStrap()
104116
{

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#endif
99
using Unity.Netcode.Components;
1010
using Unity.Netcode.Runtime;
11+
using Unity.Netcode.Unified;
1112
using UnityEngine;
1213
#if UNITY_EDITOR
1314
using UnityEditor;
@@ -1212,6 +1213,11 @@ internal void Initialize(bool server)
12121213

12131214
// UnityTransport dependencies are then initialized
12141215
RealTimeProvider = ComponentFactory.Create<IRealTimeProvider>(this);
1216+
1217+
#if UNIFIED_NETCODE
1218+
NetworkConfig.NetworkTransport = gameObject.AddComponent<UnifiedNetcodeTransport>();
1219+
#endif
1220+
12151221
MetricsManager.Initialize(this);
12161222

12171223
{

com.unity.netcode.gameobjects/Runtime/Transports/Unified.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
#if UNIFIED_NETCODE
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
using Unity.Burst;
6+
using Unity.Burst.Intrinsics;
7+
using Unity.Collections;
8+
using Unity.Collections.LowLevel.Unsafe;
9+
using Unity.Entities;
10+
using Unity.NetCode;
11+
using Unity.Networking.Transport;
12+
using UnityEngine;
13+
14+
namespace Unity.Netcode.Unified
15+
{
16+
internal struct TransportRpc : IRpcCommand, IRpcCommandSerializer<TransportRpc>
17+
{
18+
public FixedList4096Bytes<byte> Buffer;
19+
20+
internal static string ByteArrayToString(FixedList4096Bytes<byte> ba, int offset, int count)
21+
{
22+
var hex = new StringBuilder(ba.Length * 2);
23+
for (int i = offset; i < offset + count; ++i)
24+
{
25+
hex.AppendFormat("{0:x2} ", ba[i]);
26+
}
27+
28+
return hex.ToString();
29+
}
30+
internal static string ByteArrayToString(NativeArray<byte> ba, int offset, int count)
31+
{
32+
var hex = new StringBuilder(ba.Length * 2);
33+
for (int i = offset; i < offset + count; ++i)
34+
{
35+
hex.AppendFormat("{0:x2} ", ba[i]);
36+
}
37+
38+
return hex.ToString();
39+
}
40+
41+
public unsafe void Serialize(ref DataStreamWriter writer, in RpcSerializerState state, in TransportRpc data)
42+
{
43+
writer.WriteInt(data.Buffer.Length);
44+
var span = new Span<byte>(data.Buffer.GetUnsafePtr(), data.Buffer.Length);
45+
writer.WriteBytes(span);
46+
}
47+
48+
public unsafe void Deserialize(ref DataStreamReader reader, in RpcDeserializerState state, ref TransportRpc data)
49+
{
50+
var length = reader.ReadInt();
51+
data.Buffer = new FixedList4096Bytes<byte>();
52+
data.Buffer.Length = length;
53+
var span = new Span<byte>(data.Buffer.GetUnsafePtr(), length);
54+
reader.ReadBytes(span);
55+
}
56+
57+
[BurstCompile(DisableDirectCall = true)]
58+
private static void InvokeExecute(ref RpcExecutor.Parameters parameters)
59+
{
60+
RpcExecutor.ExecuteCreateRequestComponent<TransportRpc, TransportRpc>(ref parameters);
61+
}
62+
63+
static readonly PortableFunctionPointer<RpcExecutor.ExecuteDelegate> InvokeExecuteFunctionPointer = new PortableFunctionPointer<RpcExecutor.ExecuteDelegate>(InvokeExecute);
64+
65+
public PortableFunctionPointer<RpcExecutor.ExecuteDelegate> CompileExecute()
66+
{
67+
return InvokeExecuteFunctionPointer;
68+
}
69+
}
70+
71+
[UpdateInGroup(typeof(RpcCommandRequestSystemGroup))]
72+
[CreateAfter(typeof(RpcSystem))]
73+
[BurstCompile]
74+
partial struct TransportRpcCommandRequestSystem : ISystem
75+
{
76+
private RpcCommandRequest<TransportRpc, TransportRpc> m_Request;
77+
78+
[BurstCompile]
79+
struct SendRpc : IJobChunk
80+
{
81+
public RpcCommandRequest<TransportRpc, TransportRpc>.SendRpcData data;
82+
83+
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
84+
{
85+
data.Execute(chunk, unfilteredChunkIndex);
86+
}
87+
}
88+
89+
public void OnCreate(ref SystemState state)
90+
{
91+
m_Request.OnCreate(ref state);
92+
}
93+
94+
[BurstCompile]
95+
public void OnUpdate(ref SystemState state)
96+
{
97+
var sendJob = new SendRpc { data = m_Request.InitJobData(ref state) };
98+
state.Dependency = sendJob.Schedule(m_Request.Query, state.Dependency);
99+
}
100+
}
101+
102+
103+
internal partial class UnifiedNetcodeUpdateSystem : SystemBase
104+
{
105+
public UnifiedNetcodeTransport Transport;
106+
107+
public List<Connection> DiscconedtQueue = new List<Connection>();
108+
109+
public void Disconnect(Connection connection)
110+
{
111+
DiscconedtQueue.Add(connection);
112+
}
113+
114+
protected override void OnUpdate()
115+
{
116+
using var commandBuffer = new EntityCommandBuffer(Allocator.Temp);
117+
foreach(var (request, rpc, entity) in SystemAPI.Query<RefRO<ReceiveRpcCommandRequest>, RefRW<TransportRpc>>().WithEntityAccess())
118+
{
119+
var connectionId = SystemAPI.GetComponent<NetworkId>(request.ValueRO.SourceConnection).Value;
120+
121+
var buffer = rpc.ValueRW.Buffer;
122+
Transport.DispatchMessage(connectionId, buffer);
123+
commandBuffer.DestroyEntity(entity);
124+
}
125+
126+
foreach (var connection in DiscconedtQueue)
127+
{
128+
commandBuffer.AddComponent<NetworkStreamRequestDisconnect>(connection.ConnectionEntity);
129+
}
130+
commandBuffer.Playback(EntityManager);
131+
DiscconedtQueue.Clear();
132+
}
133+
}
134+
135+
internal class UnifiedNetcodeTransport : NetworkTransport
136+
{
137+
private int m_ServerClientId = -1;
138+
public override ulong ServerClientId => (ulong)m_ServerClientId;
139+
140+
private bool m_IsClient;
141+
private bool m_IsServer;
142+
private bool m_StartedServerWorld = false;
143+
private bool m_StartedClientWorld = false;
144+
145+
private IRealTimeProvider m_RealTimeProvider;
146+
147+
private Dictionary<int, Connection> m_Connections;
148+
149+
internal void DispatchMessage(int connectionId, FixedList4096Bytes<byte> buffer)
150+
{
151+
ArraySegment<byte> data = new ArraySegment<byte>(buffer.ToArray());
152+
InvokeOnTransportEvent(NetworkEvent.Data, (ulong)connectionId, data, m_RealTimeProvider.RealTimeSinceStartup);
153+
}
154+
155+
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
156+
{
157+
if (!m_Connections.TryGetValue((int)clientId, out Connection connection))
158+
{
159+
return;
160+
}
161+
162+
var rpc = new TransportRpc
163+
{
164+
Buffer = new FixedList4096Bytes<byte>(),
165+
};
166+
167+
unsafe
168+
{
169+
rpc.Buffer.Length = payload.Count;
170+
fixed (byte* data = payload.Array)
171+
{
172+
UnsafeUtility.MemCpy(rpc.Buffer.GetUnsafePtr(), (void*)(data + payload.Offset), payload.Count);
173+
}
174+
}
175+
176+
connection.SendMessage(rpc);
177+
}
178+
179+
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
180+
{
181+
clientId = 0;
182+
payload = default;
183+
receiveTime = 0;
184+
return NetworkEvent.Nothing;
185+
}
186+
187+
private void OnClientConnectedToServer(Connection connection, NetCodeConnectionEvent connectionEvent)
188+
{
189+
m_Connections[connection.NetworkId.Value] = connection;
190+
m_ServerClientId = connection.NetworkId.Value;
191+
InvokeOnTransportEvent(NetworkEvent.Connect, (ulong)connection.NetworkId.Value, default, m_RealTimeProvider.RealTimeSinceStartup);
192+
}
193+
194+
private void OnServerNewClientConnection(Connection connection, NetCodeConnectionEvent connectionEvent)
195+
{
196+
m_Connections[connection.NetworkId.Value] = connection;
197+
InvokeOnTransportEvent(NetworkEvent.Connect, (ulong)connection.NetworkId.Value, default, m_RealTimeProvider.RealTimeSinceStartup);
198+
}
199+
200+
private void OnClientDisconnectFromServer(Connection connection, NetCodeConnectionEvent connectionEvent)
201+
{
202+
InvokeOnTransportEvent(NetworkEvent.Disconnect, (ulong)connection.NetworkId.Value, default, m_RealTimeProvider.RealTimeSinceStartup);
203+
}
204+
205+
private void OnServerClientDisconnected(Connection connection, NetCodeConnectionEvent connectionEvent)
206+
{
207+
InvokeOnTransportEvent(NetworkEvent.Disconnect, (ulong)connection.NetworkId.Value, default, m_RealTimeProvider.RealTimeSinceStartup);
208+
}
209+
210+
public override bool StartClient()
211+
{
212+
if (!UnifiedBootStrap.HasClientWorlds)
213+
{
214+
UnifiedBootStrap.CreateClientWorld("ClientWorld");
215+
m_StartedClientWorld = true;
216+
}
217+
218+
NetCode.Netcode.Client.OnConnect = OnClientConnectedToServer;
219+
NetCode.Netcode.Client.OnDisconnect = OnClientDisconnectFromServer;
220+
var updateSystem = NetCode.Netcode.GetWorld(false).GetExistingSystemManaged<UnifiedNetcodeUpdateSystem>();
221+
updateSystem.Transport = this;
222+
return true;
223+
}
224+
225+
public override bool StartServer()
226+
{
227+
if (!UnifiedBootStrap.HasServerWorld)
228+
{
229+
UnifiedBootStrap.CreateServerWorld("ServerWorld");
230+
m_StartedClientWorld = true;
231+
}
232+
else
233+
{
234+
foreach (var connection in NetCode.Netcode.Server.Connections)
235+
{
236+
OnServerNewClientConnection(connection, default);
237+
}
238+
}
239+
240+
NetCode.Netcode.Server.OnConnect = OnServerNewClientConnection;
241+
NetCode.Netcode.Server.OnDisconnect = OnServerClientDisconnected;
242+
var updateSystem = NetCode.Netcode.GetWorld(true).GetExistingSystemManaged<UnifiedNetcodeUpdateSystem>();
243+
updateSystem.Transport = this;
244+
return true;
245+
}
246+
247+
public override void DisconnectRemoteClient(ulong clientId)
248+
{
249+
var updateSystem = NetCode.Netcode.GetWorld(true).GetExistingSystemManaged<UnifiedNetcodeUpdateSystem>();
250+
updateSystem.Disconnect(m_Connections[(int)clientId]);
251+
m_Connections.Remove((int)clientId);
252+
}
253+
254+
public override void DisconnectLocalClient()
255+
{
256+
var updateSystem = NetCode.Netcode.GetWorld(false).GetExistingSystemManaged<UnifiedNetcodeUpdateSystem>();
257+
updateSystem.Disconnect(m_Connections[(int)ServerClientId]);
258+
m_Connections.Remove((int)ServerClientId);
259+
}
260+
261+
public override ulong GetCurrentRtt(ulong clientId)
262+
{
263+
// todo
264+
return 0;
265+
//return (ulong)m_Connections[(int)clientId].RTT;
266+
}
267+
268+
public override void Shutdown()
269+
{
270+
if (m_StartedClientWorld)
271+
{
272+
UnifiedBootStrap.StopClient();
273+
}
274+
if (m_StartedServerWorld)
275+
{
276+
UnifiedBootStrap.StopServer();
277+
}
278+
}
279+
280+
public override void Initialize(NetworkManager networkManager = null)
281+
{
282+
m_Connections = new Dictionary<int, Connection>();
283+
m_RealTimeProvider = networkManager.RealTimeProvider;
284+
}
285+
}
286+
}
287+
#endif

com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)