Skip to content

Commit e11cf0a

Browse files
fix: Fixes warning logged on double-initialize of prefabs lists. (#2565)
* fix: Fixes warning logged on double-initialize of prefabs lists. Also, makes adding prefabs before initializing the list no longer an error case - those prefabs are stored in a separate list so that during initialization, they can be re-added to the prefabs list after pulling in data from the NetworkPrefabsList ScriptableObjects. * Changelog * Update CHANGELOG.md Re-ordering the changelog entries --------- Co-authored-by: Noel Stephens <[email protected]>
1 parent 0ba6837 commit e11cf0a

File tree

3 files changed

+191
-10
lines changed

3 files changed

+191
-10
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1212

1313
### Fixed
1414

15+
- Fixed warning "Runtime Network Prefabs was not empty at initialization time." being erroneously logged when no runtime network prefabs had been added (#2565)
1516
- Fixed issue where some temporary debug console logging was left in a merged PR. (#2562)
1617
- Fixed the "Generate Default Network Prefabs List" setting not loading correctly and always reverting to being checked. (#2545)
1718
- Fixed issue where users could not use NetworkSceneManager.VerifySceneBeforeLoading to exclude runtime generated scenes from client synchronization. (#2550)
@@ -29,6 +30,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
2930

3031
## Changed
3132

33+
- Adding network prefabs before NetworkManager initialization is now supported. (#2565)
3234
- Connecting clients being synchronized now switch to the server's active scene before spawning and synchronizing NetworkObjects. (#2532)
3335
- Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.4. (#2533)
3436
- Improved performance of NetworkBehaviour initialization by replacing reflection when initializing NetworkVariables with compile-time code generation, which should help reduce hitching during additive scene loads. (#2522)

com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ public class NetworkPrefabs
3838
[NonSerialized]
3939
private List<NetworkPrefab> m_Prefabs = new List<NetworkPrefab>();
4040

41+
[NonSerialized]
42+
private List<NetworkPrefab> m_RuntimeAddedPrefabs = new List<NetworkPrefab>();
43+
4144
private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
4245
{
4346
if (AddPrefabRegistration(networkPrefab))
4447
{
48+
// Don't add this to m_RuntimeAddedPrefabs
49+
// This prefab is now in the PrefabList, so if we shutdown and initialize again, we'll pick it up from there.
4550
m_Prefabs.Add(networkPrefab);
4651
}
4752
}
@@ -67,8 +72,6 @@ internal void Shutdown()
6772
list.OnAdd -= AddTriggeredByNetworkPrefabList;
6873
list.OnRemove -= RemoveTriggeredByNetworkPrefabList;
6974
}
70-
71-
NetworkPrefabsLists.Clear();
7275
}
7376

7477
/// <summary>
@@ -77,13 +80,7 @@ internal void Shutdown()
7780
/// </summary>
7881
public void Initialize(bool warnInvalid = true)
7982
{
80-
if (NetworkPrefabsLists.Count != 0 && m_Prefabs.Count > 0)
81-
{
82-
NetworkLog.LogWarning("Runtime Network Prefabs was not empty at initialization time. Network " +
83-
"Prefab registrations made before initialization will be replaced by NetworkPrefabsList.");
84-
m_Prefabs.Clear();
85-
}
86-
83+
m_Prefabs.Clear();
8784
foreach (var list in NetworkPrefabsLists)
8885
{
8986
list.OnAdd += AddTriggeredByNetworkPrefabList;
@@ -93,7 +90,7 @@ public void Initialize(bool warnInvalid = true)
9390
NetworkPrefabOverrideLinks.Clear();
9491
OverrideToNetworkPrefab.Clear();
9592

96-
var prefabs = NetworkPrefabsLists.Count != 0 ? new List<NetworkPrefab>() : m_Prefabs;
93+
var prefabs = new List<NetworkPrefab>();
9794

9895
if (NetworkPrefabsLists.Count != 0)
9996
{
@@ -126,6 +123,18 @@ public void Initialize(bool warnInvalid = true)
126123
}
127124
}
128125

126+
foreach (var networkPrefab in m_RuntimeAddedPrefabs)
127+
{
128+
if (AddPrefabRegistration(networkPrefab))
129+
{
130+
m_Prefabs.Add(networkPrefab);
131+
}
132+
else
133+
{
134+
removeList?.Add(networkPrefab);
135+
}
136+
}
137+
129138
// Clear out anything that is invalid or not used
130139
if (removeList?.Count > 0)
131140
{
@@ -152,6 +161,7 @@ public bool Add(NetworkPrefab networkPrefab)
152161
if (AddPrefabRegistration(networkPrefab))
153162
{
154163
m_Prefabs.Add(networkPrefab);
164+
m_RuntimeAddedPrefabs.Add(networkPrefab);
155165
return true;
156166
}
157167

@@ -175,6 +185,7 @@ public void Remove(NetworkPrefab prefab)
175185
}
176186

177187
m_Prefabs.Remove(prefab);
188+
m_RuntimeAddedPrefabs.Remove(prefab);
178189
OverrideToNetworkPrefab.Remove(prefab.TargetPrefabGlobalObjectIdHash);
179190
NetworkPrefabOverrideLinks.Remove(prefab.SourcePrefabGlobalObjectIdHash);
180191
}
@@ -203,6 +214,15 @@ public void Remove(GameObject prefab)
203214
return;
204215
}
205216
}
217+
218+
for (int i = 0; i < m_RuntimeAddedPrefabs.Count; i++)
219+
{
220+
if (m_RuntimeAddedPrefabs[i].Prefab == prefab)
221+
{
222+
Remove(m_RuntimeAddedPrefabs[i]);
223+
return;
224+
}
225+
}
206226
}
207227

208228
/// <summary>

com.unity.netcode.gameobjects/Tests/Editor/NetworkManagerConfigurationTests.cs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,5 +305,164 @@ public void WhenModifyingPrefabListUsingPrefabsListAPI_ModificationIsShared()
305305
Assert.IsTrue(sharedList.Contains(object2.gameObject));
306306
Assert.IsTrue(sharedList.Contains(object3.gameObject));
307307
}
308+
309+
[Test]
310+
public void WhenCallingInitializeAfterAddingAPrefabUsingPrefabsAPI_ThePrefabStillExists()
311+
{
312+
// Setup
313+
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
314+
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
315+
networkManager.NetworkConfig = new NetworkConfig
316+
{
317+
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
318+
};
319+
320+
var networkManagerObject2 = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
321+
var networkManager2 = networkManagerObject2.AddComponent<NetworkManager>();
322+
networkManager2.NetworkConfig = new NetworkConfig
323+
{
324+
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
325+
};
326+
327+
var object1 = new GameObject("Object 1").AddComponent<NetworkObject>();
328+
var object2 = new GameObject("Object 2").AddComponent<NetworkObject>();
329+
var object3 = new GameObject("Object 3").AddComponent<NetworkObject>();
330+
331+
object1.GlobalObjectIdHash = 1;
332+
object2.GlobalObjectIdHash = 2;
333+
object3.GlobalObjectIdHash = 3;
334+
335+
var sharedList = ScriptableObject.CreateInstance<NetworkPrefabsList>();
336+
sharedList.List.Add(new NetworkPrefab { Prefab = object1.gameObject });
337+
338+
networkManager.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
339+
networkManager2.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
340+
341+
networkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object2.gameObject });
342+
networkManager2.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object3.gameObject });
343+
344+
networkManager.Initialize(true);
345+
networkManager2.Initialize(false);
346+
347+
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object1.gameObject));
348+
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object1.gameObject));
349+
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object2.gameObject));
350+
Assert.IsFalse(networkManager2.NetworkConfig.Prefabs.Contains(object2.gameObject));
351+
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object3.gameObject));
352+
Assert.IsFalse(networkManager.NetworkConfig.Prefabs.Contains(object3.gameObject));
353+
354+
Assert.IsTrue(sharedList.Contains(object1.gameObject));
355+
Assert.IsFalse(sharedList.Contains(object2.gameObject));
356+
Assert.IsFalse(sharedList.Contains(object3.gameObject));
357+
}
358+
359+
[Test]
360+
public void WhenShuttingDownAndReinitializingPrefabs_RuntimeAddedPrefabsStillExists()
361+
{
362+
// Setup
363+
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
364+
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
365+
networkManager.NetworkConfig = new NetworkConfig
366+
{
367+
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
368+
};
369+
370+
var networkManagerObject2 = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
371+
var networkManager2 = networkManagerObject2.AddComponent<NetworkManager>();
372+
networkManager2.NetworkConfig = new NetworkConfig
373+
{
374+
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
375+
};
376+
377+
var object1 = new GameObject("Object 1").AddComponent<NetworkObject>();
378+
var object2 = new GameObject("Object 2").AddComponent<NetworkObject>();
379+
var object3 = new GameObject("Object 3").AddComponent<NetworkObject>();
380+
381+
object1.GlobalObjectIdHash = 1;
382+
object2.GlobalObjectIdHash = 2;
383+
object3.GlobalObjectIdHash = 3;
384+
385+
var sharedList = ScriptableObject.CreateInstance<NetworkPrefabsList>();
386+
sharedList.List.Add(new NetworkPrefab { Prefab = object1.gameObject });
387+
388+
networkManager.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
389+
networkManager2.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
390+
391+
networkManager.Initialize(true);
392+
networkManager2.Initialize(false);
393+
394+
networkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object2.gameObject });
395+
networkManager2.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object3.gameObject });
396+
397+
networkManager.ShutdownInternal();
398+
networkManager2.ShutdownInternal();
399+
400+
networkManager.Initialize(true);
401+
networkManager2.Initialize(false);
402+
403+
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object1.gameObject));
404+
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object1.gameObject));
405+
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object2.gameObject));
406+
Assert.IsFalse(networkManager2.NetworkConfig.Prefabs.Contains(object2.gameObject));
407+
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object3.gameObject));
408+
Assert.IsFalse(networkManager.NetworkConfig.Prefabs.Contains(object3.gameObject));
409+
410+
Assert.IsTrue(sharedList.Contains(object1.gameObject));
411+
Assert.IsFalse(sharedList.Contains(object2.gameObject));
412+
Assert.IsFalse(sharedList.Contains(object3.gameObject));
413+
}
414+
415+
[Test]
416+
public void WhenCallingInitializeMultipleTimes_NothingBreaks()
417+
{
418+
// Setup
419+
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
420+
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
421+
networkManager.NetworkConfig = new NetworkConfig
422+
{
423+
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
424+
};
425+
426+
var networkManagerObject2 = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
427+
var networkManager2 = networkManagerObject2.AddComponent<NetworkManager>();
428+
networkManager2.NetworkConfig = new NetworkConfig
429+
{
430+
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
431+
};
432+
433+
var object1 = new GameObject("Object 1").AddComponent<NetworkObject>();
434+
var object2 = new GameObject("Object 2").AddComponent<NetworkObject>();
435+
var object3 = new GameObject("Object 3").AddComponent<NetworkObject>();
436+
437+
object1.GlobalObjectIdHash = 1;
438+
object2.GlobalObjectIdHash = 2;
439+
object3.GlobalObjectIdHash = 3;
440+
441+
var sharedList = ScriptableObject.CreateInstance<NetworkPrefabsList>();
442+
sharedList.List.Add(new NetworkPrefab { Prefab = object1.gameObject });
443+
444+
networkManager.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
445+
networkManager2.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
446+
447+
networkManager.Initialize(true);
448+
networkManager2.Initialize(false);
449+
450+
networkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object2.gameObject });
451+
networkManager2.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object3.gameObject });
452+
453+
networkManager.NetworkConfig.Prefabs.Initialize();
454+
networkManager2.NetworkConfig.Prefabs.Initialize();
455+
456+
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object1.gameObject));
457+
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object1.gameObject));
458+
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object2.gameObject));
459+
Assert.IsFalse(networkManager2.NetworkConfig.Prefabs.Contains(object2.gameObject));
460+
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object3.gameObject));
461+
Assert.IsFalse(networkManager.NetworkConfig.Prefabs.Contains(object3.gameObject));
462+
463+
Assert.IsTrue(sharedList.Contains(object1.gameObject));
464+
Assert.IsFalse(sharedList.Contains(object2.gameObject));
465+
Assert.IsFalse(sharedList.Contains(object3.gameObject));
466+
}
308467
}
309468
}

0 commit comments

Comments
 (0)