Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Fixed

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

## Changed

- Adding network prefabs before NetworkManager initialization is now supported. (#2565)
- Connecting clients being synchronized now switch to the server's active scene before spawning and synchronizing NetworkObjects. (#2532)
- Updated `UnityTransport` dependency on `com.unity.transport` to 1.3.4. (#2533)
- 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@ public class NetworkPrefabs
[NonSerialized]
private List<NetworkPrefab> m_Prefabs = new List<NetworkPrefab>();

[NonSerialized]
private List<NetworkPrefab> m_RuntimeAddedPrefabs = new List<NetworkPrefab>();

private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
{
if (AddPrefabRegistration(networkPrefab))
{
// Don't add this to m_RuntimeAddedPrefabs
// This prefab is now in the PrefabList, so if we shutdown and initialize again, we'll pick it up from there.
m_Prefabs.Add(networkPrefab);
}
}
Expand All @@ -67,8 +72,6 @@ internal void Shutdown()
list.OnAdd -= AddTriggeredByNetworkPrefabList;
list.OnRemove -= RemoveTriggeredByNetworkPrefabList;
}

NetworkPrefabsLists.Clear();
}

/// <summary>
Expand All @@ -77,13 +80,7 @@ internal void Shutdown()
/// </summary>
public void Initialize(bool warnInvalid = true)
{
if (NetworkPrefabsLists.Count != 0 && m_Prefabs.Count > 0)
{
NetworkLog.LogWarning("Runtime Network Prefabs was not empty at initialization time. Network " +
"Prefab registrations made before initialization will be replaced by NetworkPrefabsList.");
m_Prefabs.Clear();
}

m_Prefabs.Clear();
foreach (var list in NetworkPrefabsLists)
{
list.OnAdd += AddTriggeredByNetworkPrefabList;
Expand All @@ -93,7 +90,7 @@ public void Initialize(bool warnInvalid = true)
NetworkPrefabOverrideLinks.Clear();
OverrideToNetworkPrefab.Clear();

var prefabs = NetworkPrefabsLists.Count != 0 ? new List<NetworkPrefab>() : m_Prefabs;
var prefabs = new List<NetworkPrefab>();

if (NetworkPrefabsLists.Count != 0)
{
Expand Down Expand Up @@ -126,6 +123,18 @@ public void Initialize(bool warnInvalid = true)
}
}

foreach (var networkPrefab in m_RuntimeAddedPrefabs)
{
if (AddPrefabRegistration(networkPrefab))
{
m_Prefabs.Add(networkPrefab);
}
else
{
removeList?.Add(networkPrefab);
}
}

// Clear out anything that is invalid or not used
if (removeList?.Count > 0)
{
Expand All @@ -152,6 +161,7 @@ public bool Add(NetworkPrefab networkPrefab)
if (AddPrefabRegistration(networkPrefab))
{
m_Prefabs.Add(networkPrefab);
m_RuntimeAddedPrefabs.Add(networkPrefab);
return true;
}

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

m_Prefabs.Remove(prefab);
m_RuntimeAddedPrefabs.Remove(prefab);
OverrideToNetworkPrefab.Remove(prefab.TargetPrefabGlobalObjectIdHash);
NetworkPrefabOverrideLinks.Remove(prefab.SourcePrefabGlobalObjectIdHash);
}
Expand Down Expand Up @@ -203,6 +214,15 @@ public void Remove(GameObject prefab)
return;
}
}

for (int i = 0; i < m_RuntimeAddedPrefabs.Count; i++)
{
if (m_RuntimeAddedPrefabs[i].Prefab == prefab)
{
Remove(m_RuntimeAddedPrefabs[i]);
return;
}
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,5 +305,164 @@ public void WhenModifyingPrefabListUsingPrefabsListAPI_ModificationIsShared()
Assert.IsTrue(sharedList.Contains(object2.gameObject));
Assert.IsTrue(sharedList.Contains(object3.gameObject));
}

[Test]
public void WhenCallingInitializeAfterAddingAPrefabUsingPrefabsAPI_ThePrefabStillExists()
{
// Setup
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
networkManager.NetworkConfig = new NetworkConfig
{
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
};

var networkManagerObject2 = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager2 = networkManagerObject2.AddComponent<NetworkManager>();
networkManager2.NetworkConfig = new NetworkConfig
{
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
};

var object1 = new GameObject("Object 1").AddComponent<NetworkObject>();
var object2 = new GameObject("Object 2").AddComponent<NetworkObject>();
var object3 = new GameObject("Object 3").AddComponent<NetworkObject>();

object1.GlobalObjectIdHash = 1;
object2.GlobalObjectIdHash = 2;
object3.GlobalObjectIdHash = 3;

var sharedList = ScriptableObject.CreateInstance<NetworkPrefabsList>();
sharedList.List.Add(new NetworkPrefab { Prefab = object1.gameObject });

networkManager.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
networkManager2.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };

networkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object2.gameObject });
networkManager2.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object3.gameObject });

networkManager.Initialize(true);
networkManager2.Initialize(false);

Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object1.gameObject));
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object1.gameObject));
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object2.gameObject));
Assert.IsFalse(networkManager2.NetworkConfig.Prefabs.Contains(object2.gameObject));
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object3.gameObject));
Assert.IsFalse(networkManager.NetworkConfig.Prefabs.Contains(object3.gameObject));

Assert.IsTrue(sharedList.Contains(object1.gameObject));
Assert.IsFalse(sharedList.Contains(object2.gameObject));
Assert.IsFalse(sharedList.Contains(object3.gameObject));
}

[Test]
public void WhenShuttingDownAndReinitializingPrefabs_RuntimeAddedPrefabsStillExists()
{
// Setup
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
networkManager.NetworkConfig = new NetworkConfig
{
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
};

var networkManagerObject2 = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager2 = networkManagerObject2.AddComponent<NetworkManager>();
networkManager2.NetworkConfig = new NetworkConfig
{
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
};

var object1 = new GameObject("Object 1").AddComponent<NetworkObject>();
var object2 = new GameObject("Object 2").AddComponent<NetworkObject>();
var object3 = new GameObject("Object 3").AddComponent<NetworkObject>();

object1.GlobalObjectIdHash = 1;
object2.GlobalObjectIdHash = 2;
object3.GlobalObjectIdHash = 3;

var sharedList = ScriptableObject.CreateInstance<NetworkPrefabsList>();
sharedList.List.Add(new NetworkPrefab { Prefab = object1.gameObject });

networkManager.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
networkManager2.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };

networkManager.Initialize(true);
networkManager2.Initialize(false);

networkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object2.gameObject });
networkManager2.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object3.gameObject });

networkManager.ShutdownInternal();
networkManager2.ShutdownInternal();

networkManager.Initialize(true);
networkManager2.Initialize(false);

Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object1.gameObject));
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object1.gameObject));
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object2.gameObject));
Assert.IsFalse(networkManager2.NetworkConfig.Prefabs.Contains(object2.gameObject));
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object3.gameObject));
Assert.IsFalse(networkManager.NetworkConfig.Prefabs.Contains(object3.gameObject));

Assert.IsTrue(sharedList.Contains(object1.gameObject));
Assert.IsFalse(sharedList.Contains(object2.gameObject));
Assert.IsFalse(sharedList.Contains(object3.gameObject));
}

[Test]
public void WhenCallingInitializeMultipleTimes_NothingBreaks()
{
// Setup
var networkManagerObject = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager = networkManagerObject.AddComponent<NetworkManager>();
networkManager.NetworkConfig = new NetworkConfig
{
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
};

var networkManagerObject2 = new GameObject(nameof(NestedNetworkObjectPrefabCheck));
var networkManager2 = networkManagerObject2.AddComponent<NetworkManager>();
networkManager2.NetworkConfig = new NetworkConfig
{
NetworkTransport = networkManager.gameObject.AddComponent<UnityTransport>()
};

var object1 = new GameObject("Object 1").AddComponent<NetworkObject>();
var object2 = new GameObject("Object 2").AddComponent<NetworkObject>();
var object3 = new GameObject("Object 3").AddComponent<NetworkObject>();

object1.GlobalObjectIdHash = 1;
object2.GlobalObjectIdHash = 2;
object3.GlobalObjectIdHash = 3;

var sharedList = ScriptableObject.CreateInstance<NetworkPrefabsList>();
sharedList.List.Add(new NetworkPrefab { Prefab = object1.gameObject });

networkManager.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };
networkManager2.NetworkConfig.Prefabs.NetworkPrefabsLists = new List<NetworkPrefabsList> { sharedList };

networkManager.Initialize(true);
networkManager2.Initialize(false);

networkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object2.gameObject });
networkManager2.NetworkConfig.Prefabs.Add(new NetworkPrefab { Prefab = object3.gameObject });

networkManager.NetworkConfig.Prefabs.Initialize();
networkManager2.NetworkConfig.Prefabs.Initialize();

Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object1.gameObject));
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object1.gameObject));
Assert.IsTrue(networkManager.NetworkConfig.Prefabs.Contains(object2.gameObject));
Assert.IsFalse(networkManager2.NetworkConfig.Prefabs.Contains(object2.gameObject));
Assert.IsTrue(networkManager2.NetworkConfig.Prefabs.Contains(object3.gameObject));
Assert.IsFalse(networkManager.NetworkConfig.Prefabs.Contains(object3.gameObject));

Assert.IsTrue(sharedList.Contains(object1.gameObject));
Assert.IsFalse(sharedList.Contains(object2.gameObject));
Assert.IsFalse(sharedList.Contains(object3.gameObject));
}
}
}