Skip to content

Commit 0bd4efd

Browse files
committed
Merge branch 'experimental/v2-x-x/ngo-and-n4e' into experimental/v2-x-x/ngo-and-n4e-kitty
2 parents ff84ee2 + a6b852f commit 0bd4efd

File tree

4 files changed

+109
-11
lines changed

4 files changed

+109
-11
lines changed

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

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public struct NetcodeConnection
1313
internal Entity Entity;
1414
public int NetworkId;
1515

16+
internal float ConnectedTime;
17+
1618
public bool IsServer => World.IsServer();
1719
public void GoInGame()
1820
{
@@ -29,8 +31,12 @@ public void SendMessage<T>(T message) where T : unmanaged, IRpcCommand
2931
internal partial class UnifiedUpdateConnections : SystemBase
3032
{
3133
private List<NetcodeConnection> m_TempConnections = new List<NetcodeConnection>();
34+
35+
private Dictionary<int, NetcodeConnection> m_NewConnections = new Dictionary<int, NetcodeConnection>();
36+
3237
protected override void OnUpdate()
3338
{
39+
var isServer = World.IsServer();
3440
var commandBuffer = new EntityCommandBuffer(Allocator.Temp);
3541
foreach (var (networkId, connectionState, entity) in SystemAPI.Query<NetworkId, ConnectionState>().WithNone<NetworkStreamConnection>().WithEntityAccess())
3642
{
@@ -44,18 +50,40 @@ protected override void OnUpdate()
4450

4551
m_TempConnections.Clear();
4652

53+
4754
foreach (var (networkId, entity) in SystemAPI.Query<NetworkId>().WithAll<NetworkStreamConnection>().WithNone<NetworkStreamInGame>().WithEntityAccess())
4855
{
49-
commandBuffer.AddComponent<NetworkStreamInGame>(entity);
50-
commandBuffer.AddComponent(entity, default(ConnectionState));
51-
m_TempConnections.Add(new NetcodeConnection { World = World, Entity = entity, NetworkId = networkId.Value });
56+
// TODO-Unified: For new connections, we have a delay before the N4E in-game state for the client to provide time for the NGO side of the client to synchronize.
57+
// Note: Once both are using the same transport we should be able to get the transport id and determine the NGO assigned client-id and at that point once the
58+
// client has signaled that it has synchronized (or has been sent the synchronization data) we finalize the in-game connection state (or something along those lines).
59+
if (!m_NewConnections.ContainsKey(networkId.Value))
60+
{
61+
var newConnection = new NetcodeConnection { World = World, Entity = entity, NetworkId = networkId.Value, ConnectedTime = UnityEngine.Time.realtimeSinceStartup + 1.0f };
62+
m_NewConnections.Add(networkId.Value, newConnection);
63+
}
5264
}
5365

54-
foreach (var con in m_TempConnections)
66+
// If we have any pending connections
67+
if (m_NewConnections.Count > 0)
5568
{
56-
NetworkManager.OnNetCodeConnect?.Invoke(con);
69+
foreach (var entry in m_NewConnections)
70+
{
71+
// Check if the delay time has passed.
72+
if (entry.Value.ConnectedTime < UnityEngine.Time.realtimeSinceStartup)
73+
{
74+
// Set the connection in-game
75+
commandBuffer.AddComponent<NetworkStreamInGame>(entry.Value.Entity);
76+
commandBuffer.AddComponent(entry.Value.Entity, default(ConnectionState));
77+
NetworkManager.OnNetCodeConnect?.Invoke(entry.Value);
78+
m_TempConnections.Add(entry.Value);
79+
}
80+
}
81+
// Remove any connections that have "gone in-game".
82+
foreach (var connection in m_TempConnections)
83+
{
84+
m_NewConnections.Remove(connection.NetworkId);
85+
}
5786
}
58-
5987
m_TempConnections.Clear();
6088

6189
commandBuffer.Playback(EntityManager);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ public void NetworkUpdate(NetworkUpdateStage updateStage)
349349
{
350350
NetworkConfig.Prefabs.RegisterGhostPrefabs(this);
351351
}
352+
353+
if (!IsServer)
354+
{
355+
SpawnManager?.CheckGhostsPendingNetworkObjectId();
356+
}
352357
#endif
353358

354359
UpdateTopology();

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3854,13 +3854,27 @@ private void InitGhost()
38543854
}
38553855
}
38563856

3857-
private void RegisterGhostBridge()
3857+
internal bool IsGhostNetworkObjectIdValid()
3858+
{
3859+
if (NetworkObjectBridge == null)
3860+
{
3861+
return false;
3862+
}
3863+
// TODO-UNIFIED: Sometimes the GhostField can be latent. Need a way to know the GhostField has been set.
3864+
return NetworkObjectBridge.NetworkObjectId.Value < 1000000;
3865+
}
3866+
3867+
internal void RegisterGhostBridge()
38583868
{
38593869
if (NetworkManager.LogLevel == LogLevel.Developer)
38603870
{
38613871
Debug.Log($"[{nameof(NetworkObject)}][{nameof(NetworkObjectId)}] NetworkObjectBridge notified instance exists with assigned ID of: {NetworkObjectBridge.NetworkObjectId.Value}");
38623872
}
3863-
NetworkManager.SpawnManager.RegisterGhostPendingSpawn(this, NetworkObjectBridge.NetworkObjectId.Value);
3873+
3874+
if (!NetworkManager.IsServer)
3875+
{
3876+
NetworkManager.SpawnManager.RegisterGhostPendingSpawn(this, NetworkObjectBridge.NetworkObjectId.Value);
3877+
}
38643878
}
38653879

38663880
private void OnNetworkObjectIdChanged(ulong networkObjectId)

com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,59 @@ public class NetworkSpawnManager
3434

3535
internal readonly Dictionary<ulong, NetworkObject> GhostsPendingSpawn = new Dictionary<ulong, NetworkObject>();
3636

37-
public void RegisterGhostPendingSpawn(NetworkObject networkObject, ulong networkObjectId)
37+
internal readonly List<NetworkObject> GhostsPendingNetworkObjectId = new List<NetworkObject>();
38+
39+
internal void CheckGhostsPendingNetworkObjectId()
40+
{
41+
if (GhostsPendingNetworkObjectId.Count == 0)
42+
{
43+
return;
44+
}
45+
46+
for(int i = GhostsPendingNetworkObjectId.Count - 1; i >= 0; i--)
47+
{
48+
var networkObject = GhostsPendingNetworkObjectId[i];
49+
if (networkObject.IsGhostNetworkObjectIdValid())
50+
{
51+
GhostsPendingNetworkObjectId.Remove(networkObject);
52+
if (NetworkManager.LogLevel == LogLevel.Developer)
53+
{
54+
Debug.Log($"[{nameof(RegisterGhostPendingSpawn)}] {networkObject.name}'s Ghost {nameof(NetworkObject.NetworkObjectId)} is valid. Re-registering.");
55+
}
56+
networkObject.RegisterGhostBridge();
57+
}
58+
}
59+
}
60+
61+
internal void RegisterGhostPendingSpawn(NetworkObject networkObject, ulong networkObjectId)
3862
{
63+
if (!networkObject.IsGhostNetworkObjectIdValid())
64+
{
65+
GhostsPendingNetworkObjectId.Add(networkObject);
66+
if (NetworkManager.LogLevel == LogLevel.Developer)
67+
{
68+
Debug.Log($"[{nameof(RegisterGhostPendingSpawn)}] {networkObject.name}'s Ghost {nameof(NetworkObject.NetworkObjectId)} ({networkObjectId}) seems invalid. Adding to the pending NetworkObjectId list.");
69+
}
70+
return;
71+
}
3972
if (NetworkManager.LogLevel == LogLevel.Developer)
4073
{
4174
Debug.Log($"[{nameof(RegisterGhostPendingSpawn)}] Registering {networkObject.name} with a {nameof(NetworkObject.NetworkObjectId)} of {networkObjectId}.");
4275
}
43-
GhostsPendingSpawn.TryAdd(networkObjectId, networkObject);
76+
if(GhostsPendingSpawn.TryAdd(networkObjectId, networkObject))
77+
{
78+
// TODO-UNIFIED: We need a better way to preserve any hybrid instances pending NGO spawn.
79+
// For now, move any pending object into the DDOL.
80+
UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject);
81+
}
82+
4483
NetworkManager.DeferredMessageManager.ProcessTriggers(IDeferredNetworkMessageManager.TriggerType.OnGhostSpawned, networkObjectId);
4584
if (GhostsArePendingSynchronization && GhostsPendingSynchronization.ContainsKey(networkObjectId))
4685
{
86+
// TODO-UNIFIED: We need a better way to preserve any hybrid instances pending NGO spawn.
87+
// NOTE: We might be able to use the NetworkSceneHandle to get the associated local scene handle to which we can use to get the targeted scene.
88+
UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(networkObject.gameObject, UnityEngine.SceneManagement.SceneManager.GetActiveScene());
89+
4790
// When the object is spawned, it will invoke GetGhostNetworkObjectForSpawn below which removes the entry from GhostsPendingSpawn
4891
ProcessGhostPendingSynchronization(networkObjectId);
4992
}
@@ -58,6 +101,9 @@ internal NetworkObject GetGhostNetworkObjectForSpawn(ulong networkObjectId)
58101
}
59102
var networkObject = GhostsPendingSpawn[networkObjectId];
60103
GhostsPendingSpawn.Remove(networkObjectId);
104+
// TODO-UNIFIED: We need a better way to preserve any hybrid instances pending NGO spawn.
105+
// NOTE: We might be able to use the NetworkSceneHandle to get the associated local scene handle to which we can use to get the targeted scene.
106+
UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(networkObject.gameObject, UnityEngine.SceneManagement.SceneManager.GetActiveScene());
61107
return networkObject;
62108
}
63109

@@ -94,7 +140,6 @@ internal void ProcessGhostPendingSynchronization(ulong networkObjectId, bool rem
94140
//{
95141
// networkObject.InternalInSceneNetworkObjectsSpawned();
96142
//}
97-
98143
if (removeUponSpawn)
99144
{
100145
GhostsArePendingSynchronization = GhostsPendingSynchronization.Count > 0;
@@ -2011,6 +2056,12 @@ internal NetworkSpawnManager(NetworkManager networkManager)
20112056

20122057
internal void Shutdown()
20132058
{
2059+
#if UNIFIED_NETCODE
2060+
GhostsPendingNetworkObjectId.Clear();
2061+
GhostsPendingNetworkObjectId.Clear();
2062+
GhostsPendingSpawn.Clear();
2063+
GhostsPendingSynchronization.Clear();
2064+
#endif
20142065
NetworkObjectsToSynchronizeSceneChanges.Clear();
20152066
CleanUpDisposedObjects.Clear();
20162067
}

0 commit comments

Comments
 (0)