Skip to content

Commit 6cf0413

Browse files
update
Automatically handle removing the Rigidbody on non-authority instances when running in client-server mode.
1 parent 1dd4bd2 commit 6cf0413

9 files changed

Lines changed: 364 additions & 7 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#if UNIFIED_NETCODE
2+
using System.Reflection;
3+
using UnityEngine;
4+
5+
namespace Unity.Netcode
6+
{
7+
internal static class ComponentHelpers
8+
{
9+
/// <summary>
10+
/// Copies the properties and fields of a source component to a target component
11+
/// </summary>
12+
/// <typeparam name="T">Type of the component being copied.</typeparam>
13+
/// <param name="target">The copy to target.</param>
14+
/// <param name="source">The copy from source.</param>
15+
/// <returns></returns>
16+
internal static T Copy<T>(this Component target, T source) where T : Component
17+
{
18+
var targetType = target.GetType();
19+
var sourceType = source.GetType();
20+
if (targetType != sourceType)
21+
{
22+
Debug.LogError($"[ComponentHelpers][GetCopyOf<{targetType.Name}>][Mismatched target & source] Source: {sourceType.Name}!");
23+
return null;
24+
}
25+
26+
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default | BindingFlags.DeclaredOnly;
27+
28+
// Copy properties
29+
foreach (var property in targetType.GetProperties(bindingFlags))
30+
{
31+
if (property.CanWrite)
32+
{
33+
try { property.SetValue(target, property.GetValue(source, null), null); }
34+
catch { } // Handle exceptions for unsupported properties
35+
}
36+
}
37+
38+
// Copy fields
39+
foreach (var field in targetType.GetFields(bindingFlags))
40+
{
41+
field.SetValue(target, field.GetValue(source));
42+
}
43+
44+
return target as T;
45+
}
46+
47+
/// <summary>
48+
/// Add a component of Type T and copy the source somponent's properties and fields.
49+
/// </summary>
50+
/// <typeparam name="T">Component type to add.</typeparam>
51+
/// <param name="gameObject">The target GameObject the component will be added to.</param>
52+
/// <param name="sourceComponent">The source component (must be the same Type of T).</param>
53+
/// <returns></returns>
54+
internal static T AddAndCopy<T>(this GameObject gameObject, T sourceComponent) where T : Component
55+
{
56+
return gameObject.AddComponent<T>().Copy(sourceComponent);
57+
}
58+
}
59+
}
60+
#endif

com.unity.netcode.gameobjects/Runtime/Components/Helpers/ComponentHelpers.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#if UNIFIED_NETCODE
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace Unity.Netcode
6+
{
7+
/// <summary>
8+
/// Can be used to remove and add back a component that is being tracked.
9+
/// Requires invoking <see cref="Initialize"/> before a component is marked to be tracked.
10+
/// </summary>
11+
[HideInInspector]
12+
internal class ComponentMarker : MonoBehaviour
13+
{
14+
internal static Dictionary<NetworkManager, Dictionary<GameObject, HashSet<ComponentMarker>>> RegisteredMarkers = new Dictionary<NetworkManager, Dictionary<GameObject, HashSet<ComponentMarker>>>();
15+
16+
private static void AddInstance(NetworkManager networkManager, ComponentMarker instance)
17+
{
18+
if (!RegisteredMarkers.ContainsKey(networkManager))
19+
{
20+
RegisteredMarkers.Add(networkManager, new Dictionary<GameObject, HashSet<ComponentMarker>>());
21+
}
22+
23+
if (!RegisteredMarkers[networkManager].ContainsKey(instance.gameObject))
24+
{
25+
RegisteredMarkers[networkManager].Add(instance.gameObject, new HashSet<ComponentMarker>());
26+
}
27+
RegisteredMarkers[networkManager][instance.gameObject].Add(instance);
28+
}
29+
30+
private static void RemoveInstance(NetworkManager networkManager, ComponentMarker instance)
31+
{
32+
if (!RegisteredMarkers.ContainsKey(networkManager))
33+
{
34+
return;
35+
}
36+
37+
if (!RegisteredMarkers[networkManager].ContainsKey(instance.gameObject))
38+
{
39+
return;
40+
}
41+
RegisteredMarkers[networkManager][instance.gameObject].Remove(instance);
42+
43+
if (RegisteredMarkers[networkManager][instance.gameObject].Count == 0)
44+
{
45+
RegisteredMarkers[networkManager].Remove(instance.gameObject);
46+
}
47+
48+
if (RegisteredMarkers[networkManager].Count == 0)
49+
{
50+
RegisteredMarkers.Remove(networkManager);
51+
}
52+
}
53+
54+
internal NetworkManager NetworkManager { get; private set; }
55+
56+
internal Component PrefabInstance { get; private set; }
57+
internal Component CurrentInstance { get; private set; }
58+
59+
internal void Add<T>() where T : Component
60+
{
61+
if (CurrentInstance)
62+
{
63+
return;
64+
}
65+
var instanceAsType = (T)PrefabInstance;
66+
CurrentInstance = ComponentHelpers.AddAndCopy(gameObject, instanceAsType);
67+
}
68+
69+
internal void Remove<T>() where T : Component
70+
{
71+
if (!CurrentInstance)
72+
{
73+
return;
74+
}
75+
Destroy(CurrentInstance);
76+
CurrentInstance = null;
77+
}
78+
79+
/// <summary>
80+
/// Initializes this marker to track the current component instance paired with the prefab's instance of the component.
81+
/// </summary>
82+
/// <typeparam name="T">The type of component being marked.</typeparam>
83+
/// <param name="networkManager">To help with integration testing (tracking which NetworkManager instance a registered marker belongs to.</param>
84+
/// <param name="currentInstance">The current active comonent instance.</param>
85+
/// <param name="prefabInstance">The prefab's instance of the component (used to replicate the setttings when adding back).</param>
86+
internal void Initialize<T>(NetworkManager networkManager, T currentInstance, T prefabInstance) where T : Component
87+
{
88+
CurrentInstance = currentInstance;
89+
PrefabInstance = prefabInstance;
90+
NetworkManager = networkManager;
91+
AddInstance(networkManager, this);
92+
}
93+
94+
internal void OnDestroy()
95+
{
96+
RemoveInstance(NetworkManager, this);
97+
}
98+
}
99+
}
100+
#endif

com.unity.netcode.gameobjects/Runtime/Components/Helpers/ComponentMarker.cs.meta

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

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ public override bool Initialize(string defaultWorldName)
7979
Instance = this;
8080
AutoConnectPort = Port;
8181
CreateDefaultClientServerWorlds();
82-
8382
var initialized = base.Initialize(defaultWorldName);
8483
OnInitialized?.Invoke(initialized);
8584
return initialized;

com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1791,6 +1791,19 @@ internal void RegisterRigidbody(NetworkRigidbodyBase networkRigidbody)
17911791
m_UseRigidbodyForMotion = m_NetworkRigidbodyInternal.UseRigidBodyForMotion;
17921792
}
17931793
}
1794+
1795+
#if UNIFIED_NETCODE
1796+
internal void UnregisterRigidbody()
1797+
{
1798+
if (m_NetworkRigidbodyInternal)
1799+
{
1800+
NetworkManager.NetworkTransformRegistration(NetworkObject, false, false);
1801+
NetworkManager.NetworkTransformRegistration(NetworkObject, true, true);
1802+
m_NetworkRigidbodyInternal = null;
1803+
m_UseRigidbodyForMotion = false;
1804+
}
1805+
}
1806+
#endif
17941807
#endif
17951808

17961809
#if DEBUG_NETWORKTRANSFORM || UNITY_INCLUDE_TESTS
@@ -3594,6 +3607,8 @@ protected virtual void Awake()
35943607
}
35953608

35963609
CachedTransform = transform;
3610+
3611+
35973612
}
35983613

35993614
internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManager)
@@ -3606,6 +3621,12 @@ internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManag
36063621
/// <inheritdoc/>
36073622
public override void OnNetworkSpawn()
36083623
{
3624+
#if UNIFIED_NETCODE
3625+
if (NetworkObject.HasGhost)
3626+
{
3627+
return;
3628+
}
3629+
#endif
36093630
m_ParentedChildren.Clear();
36103631
m_CachedNetworkManager = NetworkManager;
36113632

@@ -3700,6 +3721,13 @@ private void ResetInterpolatedStateToCurrentAuthoritativeState()
37003721
/// <param name="isOwnershipChange"></param>
37013722
private void InternalInitialization(bool isOwnershipChange = false)
37023723
{
3724+
3725+
#if UNIFIED_NETCODE
3726+
if (NetworkObject.HasGhost)
3727+
{
3728+
return;
3729+
}
3730+
#endif
37033731
if (!IsSpawned)
37043732
{
37053733
return;
@@ -3808,7 +3836,7 @@ protected void Initialize()
38083836
{
38093837
InternalInitialization();
38103838
}
3811-
#endregion
3839+
#endregion
38123840

38133841
#region PARENTING AND OWNERSHIP
38143842
/// <inheritdoc/>

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public class NetworkPrefabs
4747
[NonSerialized]
4848
private List<NetworkPrefab> m_Prefabs = new List<NetworkPrefab>();
4949

50+
#if UNIFIED_NETCODE
51+
[NonSerialized]
52+
internal Dictionary<uint, NetworkPrefab> PrefabTable = new Dictionary<uint, NetworkPrefab>();
53+
#endif
54+
5055
[NonSerialized]
5156
private List<NetworkPrefab> m_RuntimeAddedPrefabs = new List<NetworkPrefab>();
5257

@@ -57,12 +62,21 @@ private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
5762
// Don't add this to m_RuntimeAddedPrefabs
5863
// This prefab is now in the PrefabList, so if we shutdown and initialize again, we'll pick it up from there.
5964
m_Prefabs.Add(networkPrefab);
65+
#if UNIFIED_NETCODE
66+
if (!PrefabTable.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
67+
{
68+
PrefabTable.Add(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab);
69+
}
70+
#endif
6071
}
6172
}
6273

6374
private void RemoveTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
6475
{
6576
m_Prefabs.Remove(networkPrefab);
77+
#if UNIFIED_NETCODE
78+
PrefabTable.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash);
79+
#endif
6680
}
6781

6882
/// <summary>
@@ -95,6 +109,9 @@ public void Initialize(bool warnInvalid = true)
95109
{
96110
m_Prefabs.Clear();
97111
NetworkPrefabsLists.RemoveAll(x => x == null);
112+
#if UNIFIED_NETCODE
113+
PrefabTable.Clear();
114+
#endif
98115
foreach (var list in NetworkPrefabsLists)
99116
{
100117
list.OnAdd += AddTriggeredByNetworkPrefabList;
@@ -127,10 +144,22 @@ public void Initialize(bool warnInvalid = true)
127144
if (AddPrefabRegistration(networkPrefab))
128145
{
129146
m_Prefabs.Add(networkPrefab);
147+
#if UNIFIED_NETCODE
148+
if (!PrefabTable.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
149+
{
150+
PrefabTable.Add(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab);
151+
}
152+
#endif
130153
}
131154
else
132155
{
133156
removeList?.Add(networkPrefab);
157+
#if UNIFIED_NETCODE
158+
if (PrefabTable.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
159+
{
160+
PrefabTable.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash);
161+
}
162+
#endif
134163
}
135164
}
136165

@@ -139,10 +168,22 @@ public void Initialize(bool warnInvalid = true)
139168
if (AddPrefabRegistration(networkPrefab))
140169
{
141170
m_Prefabs.Add(networkPrefab);
171+
#if UNIFIED_NETCODE
172+
if (!PrefabTable.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
173+
{
174+
PrefabTable.Add(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab);
175+
}
176+
#endif
142177
}
143178
else
144179
{
145180
removeList?.Add(networkPrefab);
181+
#if UNIFIED_NETCODE
182+
if (PrefabTable.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
183+
{
184+
PrefabTable.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash);
185+
}
186+
#endif
146187
}
147188
}
148189

@@ -175,6 +216,12 @@ public bool Add(NetworkPrefab networkPrefab)
175216
{
176217
m_Prefabs.Add(networkPrefab);
177218
m_RuntimeAddedPrefabs.Add(networkPrefab);
219+
#if UNIFIED_NETCODE
220+
if (!PrefabTable.ContainsKey(networkPrefab.SourcePrefabGlobalObjectIdHash))
221+
{
222+
PrefabTable.Add(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab);
223+
}
224+
#endif
178225
return true;
179226
}
180227

@@ -202,6 +249,12 @@ public void Remove(NetworkPrefab prefab)
202249
m_RuntimeAddedPrefabs.Remove(prefab);
203250
OverrideToNetworkPrefab.Remove(prefab.TargetPrefabGlobalObjectIdHash);
204251
NetworkPrefabOverrideLinks.Remove(prefab.SourcePrefabGlobalObjectIdHash);
252+
#if UNIFIED_NETCODE
253+
if (PrefabTable.ContainsKey(prefab.SourcePrefabGlobalObjectIdHash))
254+
{
255+
PrefabTable.Remove(prefab.SourcePrefabGlobalObjectIdHash);
256+
}
257+
#endif
205258
}
206259

207260
/// <summary>

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,6 @@ public bool StartServer()
14001400
return false;
14011401
}
14021402
NetCodeConfig.Global.HostWorldModeSelection = NetCodeConfig.HostWorldMode.SingleWorld;
1403-
DefaultWorldInitialization.Initialize("Default World", false);
14041403
StartCoroutine(WaitForHybridPrefabRegistration(StartType.Server));
14051404
return true;
14061405
}
@@ -1475,7 +1474,6 @@ public bool StartClient()
14751474
return false;
14761475
}
14771476

1478-
DefaultWorldInitialization.Initialize("Default World", false);
14791477
StartCoroutine(WaitForHybridPrefabRegistration(StartType.Client));
14801478
// TODO-UNIFIED: Need a way to signal everything completed.
14811479
return true;
@@ -1549,8 +1547,6 @@ public bool StartHost()
15491547
ShutdownInternal();
15501548
return false;
15511549
}
1552-
1553-
DefaultWorldInitialization.Initialize("Default World", false);
15541550
StartCoroutine(WaitForHybridPrefabRegistration(StartType.Host));
15551551
// TODO-UNIFIED: Need a way to signal everything completed.
15561552
return true;

0 commit comments

Comments
 (0)