Skip to content

Commit e58355d

Browse files
ShadauxCat0xFA11
andauthored
feat: Add "RemoveNetworkPrefab" which is necessary for certain addressables implementations (#1950)
* feat: Add "RemoveNetworkPrefab" which is necessary for certain addressables implementations * changelog * tests * - Added XMLDoc - Enforced not removing prefabs when ForceSamePrefabs is enabled. Co-authored-by: Fatih Mar <[email protected]>
1 parent 7b7ab49 commit e58355d

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

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

1111
### Added
1212

13+
- Added `NetworkManager.RemoveNetworkPrefab(...)` to remove a prefab from the prefabs list (#1950)
14+
1315
### Changed
1416

1517
- (API Breaking) `ConnectionApprovalCallback` is no longer an `event` and will not allow more than 1 handler registered at a time. Also, `ConnectionApprovalCallback` is now a `Func<>` taking `ConnectionApprovalRequest` in and returning `ConnectionApprovalResponse` back out (#1972)

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,47 @@ public void AddNetworkPrefab(GameObject prefab)
576576
}
577577
}
578578

579+
/// <summary>
580+
/// Remove a prefab from the prefab list.
581+
/// As with AddNetworkPrefab, this is specific to the client it's called on -
582+
/// calling it on the server does not automatically remove anything on any of the
583+
/// client processes.
584+
///
585+
/// Like AddNetworkPrefab, when NetworkConfig.ForceSamePrefabs is enabled,
586+
/// this cannot be called after connecting.
587+
/// </summary>
588+
/// <param name="prefab"></param>
589+
public void RemoveNetworkPrefab(GameObject prefab)
590+
{
591+
if (IsListening && NetworkConfig.ForceSamePrefabs)
592+
{
593+
throw new Exception($"Prefabs cannot be removed after starting {nameof(NetworkManager)} when {nameof(NetworkConfig.ForceSamePrefabs)} is enabled.");
594+
}
595+
596+
var globalObjectIdHash = prefab.GetComponent<NetworkObject>().GlobalObjectIdHash;
597+
for (var i = 0; i < NetworkConfig.NetworkPrefabs.Count; ++i)
598+
{
599+
if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent<NetworkObject>().GlobalObjectIdHash == globalObjectIdHash)
600+
{
601+
NetworkConfig.NetworkPrefabs.RemoveAt(i);
602+
break;
603+
}
604+
}
605+
if (PrefabHandler.ContainsHandler(globalObjectIdHash))
606+
{
607+
PrefabHandler.RemoveHandler(globalObjectIdHash);
608+
}
609+
if (NetworkConfig.NetworkPrefabOverrideLinks.TryGetValue(globalObjectIdHash, out var targetPrefab))
610+
{
611+
NetworkConfig.NetworkPrefabOverrideLinks.Remove(globalObjectIdHash);
612+
var targetHash = targetPrefab.Prefab.GetComponent<NetworkObject>().GlobalObjectIdHash;
613+
if (NetworkConfig.OverrideToNetworkPrefab.ContainsKey(targetHash))
614+
{
615+
NetworkConfig.OverrideToNetworkPrefab.Remove(targetHash);
616+
}
617+
}
618+
}
619+
579620
private bool ShouldAddPrefab(NetworkPrefab networkPrefab, out uint sourcePrefabGlobalObjectIdHash, out uint targetPrefabGlobalObjectIdHash, int index = -1)
580621
{
581622
sourcePrefabGlobalObjectIdHash = 0;
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System.Collections;
2+
using NUnit.Framework;
3+
using UnityEngine;
4+
using UnityEngine.TestTools;
5+
using Unity.Netcode.TestHelpers.Runtime;
6+
using Object = UnityEngine.Object;
7+
8+
namespace Unity.Netcode.RuntimeTests
9+
{
10+
public class AddNetworkPrefabTest : NetcodeIntegrationTest
11+
{
12+
public class EmptyComponent : NetworkBehaviour
13+
{
14+
15+
}
16+
protected override int NumberOfClients => 1;
17+
18+
private GameObject m_Prefab;
19+
20+
protected override IEnumerator OnSetup()
21+
{
22+
// Host is irrelevant, messages don't get sent to the host "client"
23+
m_UseHost = false;
24+
25+
m_Prefab = new GameObject("Object");
26+
var networkObject = m_Prefab.AddComponent<NetworkObject>();
27+
m_Prefab.AddComponent<EmptyComponent>();
28+
29+
// Make it a prefab
30+
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObject);
31+
yield return null;
32+
}
33+
34+
protected override void OnServerAndClientsCreated()
35+
{
36+
m_ServerNetworkManager.NetworkConfig.SpawnTimeout = 0;
37+
m_ServerNetworkManager.NetworkConfig.ForceSamePrefabs = false;
38+
foreach (var client in m_ClientNetworkManagers)
39+
{
40+
client.NetworkConfig.SpawnTimeout = 0;
41+
client.NetworkConfig.ForceSamePrefabs = false;
42+
}
43+
}
44+
45+
private EmptyComponent GetObjectForClient(ulong clientId)
46+
{
47+
foreach (var component in Object.FindObjectsOfType<EmptyComponent>())
48+
{
49+
if (component.IsSpawned && component.NetworkManager.LocalClientId == clientId)
50+
{
51+
return component;
52+
}
53+
}
54+
55+
return null;
56+
}
57+
58+
private void RegisterPrefab()
59+
{
60+
m_ServerNetworkManager.AddNetworkPrefab(m_Prefab);
61+
foreach (var client in m_ClientNetworkManagers)
62+
{
63+
client.AddNetworkPrefab(m_Prefab);
64+
}
65+
}
66+
67+
private void DeregisterPrefab()
68+
{
69+
m_ServerNetworkManager.RemoveNetworkPrefab(m_Prefab);
70+
foreach (var client in m_ClientNetworkManagers)
71+
{
72+
client.RemoveNetworkPrefab(m_Prefab);
73+
}
74+
}
75+
76+
private static CoroutineRunner s_CoroutineRunner;
77+
78+
[UnityTest]
79+
public IEnumerator WhenSpawningBeforeAddingPrefab_SpawnFails()
80+
{
81+
var serverObject = Object.Instantiate(m_Prefab);
82+
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
83+
serverObject.GetComponent<NetworkObject>().Spawn();
84+
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
85+
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
86+
}
87+
88+
[UnityTest]
89+
public IEnumerator WhenSpawningAfterAddingServerPrefabButBeforeAddingClientPrefab_SpawnFails()
90+
{
91+
m_ServerNetworkManager.AddNetworkPrefab(m_Prefab);
92+
93+
var serverObject = Object.Instantiate(m_Prefab);
94+
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
95+
serverObject.GetComponent<NetworkObject>().Spawn();
96+
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
97+
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
98+
}
99+
100+
[UnityTest]
101+
public IEnumerator WhenSpawningAfterAddingPrefabOnServerAndClient_SpawnSucceeds()
102+
{
103+
RegisterPrefab();
104+
105+
var serverObject = Object.Instantiate(m_Prefab);
106+
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
107+
serverObject.GetComponent<NetworkObject>().Spawn();
108+
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeHandled<CreateObjectMessage>(m_ClientNetworkManagers[0]);
109+
Assert.IsNotNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
110+
}
111+
112+
[UnityTest]
113+
public IEnumerator WhenSpawningAfterRemovingPrefabOnClient_SpawnFails()
114+
{
115+
RegisterPrefab();
116+
117+
var serverObject = Object.Instantiate(m_Prefab);
118+
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
119+
serverObject.GetComponent<NetworkObject>().Spawn();
120+
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
121+
Assert.IsNotNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
122+
123+
serverObject.GetComponent<NetworkObject>().Despawn();
124+
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<DestroyObjectMessage>(m_ClientNetworkManagers[0]);
125+
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
126+
127+
DeregisterPrefab();
128+
129+
serverObject = Object.Instantiate(m_Prefab);
130+
serverObject.GetComponent<NetworkObject>().NetworkManagerOwner = m_ServerNetworkManager;
131+
serverObject.GetComponent<NetworkObject>().Spawn();
132+
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<CreateObjectMessage>(m_ClientNetworkManagers[0]);
133+
Assert.IsNull(GetObjectForClient(m_ClientNetworkManagers[0].LocalClientId));
134+
}
135+
}
136+
}

com.unity.netcode.gameobjects/Tests/Runtime/AddNetworkPrefabTests.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)