chore: migrate 2830 allow null references in NetworkBehaviourReference and NetworkObjectReference (#2874)
* initial commit * update adding changelog entry * update and style Fixing some style issues along with property type issues. * test Adding some generalized testing to validate both NetworkBehaviourReference and NetworkObjectReference can be created using a null and serialized when null. * update Updating the changed description. --------- Co-authored-by: Simone Guggiari <simogecko@gmail.com>
This commit is contained in:
Родитель
3ca359d05f
Коммит
d90292da99
|
@ -32,6 +32,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
|
|||
|
||||
### Changed
|
||||
|
||||
- Changed `NetworkObjectReference` and `NetworkBehaviourReference` to allow null references when constructing and serializing. (#2874)
|
||||
- Changed `NetworkAnimator` no longer requires the `Animator` component to exist on the same `GameObject`. (#2872)
|
||||
- Changed `NetworkTransform` to now use `NetworkTransformMessage` as opposed to named messages for NetworkTransformState updates. (#2810)
|
||||
- Changed `CustomMessageManager` so it no longer attempts to register or "unregister" a null or empty string and will log an error if this condition occurs. (#2807)
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Unity.Netcode
|
|||
{
|
||||
private NetworkObjectReference m_NetworkObjectReference;
|
||||
private ushort m_NetworkBehaviourId;
|
||||
private static ushort s_NullId = ushort.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="NetworkBehaviourReference{T}"/> struct.
|
||||
|
@ -21,7 +22,9 @@ namespace Unity.Netcode
|
|||
{
|
||||
if (networkBehaviour == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(networkBehaviour));
|
||||
m_NetworkObjectReference = new NetworkObjectReference((NetworkObject)null);
|
||||
m_NetworkBehaviourId = s_NullId;
|
||||
return;
|
||||
}
|
||||
if (networkBehaviour.NetworkObject == null)
|
||||
{
|
||||
|
@ -60,6 +63,10 @@ namespace Unity.Netcode
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static NetworkBehaviour GetInternal(NetworkBehaviourReference networkBehaviourRef, NetworkManager networkManager = null)
|
||||
{
|
||||
if (networkBehaviourRef.m_NetworkBehaviourId == s_NullId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (networkBehaviourRef.m_NetworkObjectReference.TryGet(out NetworkObject networkObject, networkManager))
|
||||
{
|
||||
return networkObject.GetNetworkBehaviourAtOrderIndex(networkBehaviourRef.m_NetworkBehaviourId);
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Unity.Netcode
|
|||
public struct NetworkObjectReference : INetworkSerializable, IEquatable<NetworkObjectReference>
|
||||
{
|
||||
private ulong m_NetworkObjectId;
|
||||
private static ulong s_NullId = ulong.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="NetworkObject.NetworkObjectId"/> of the referenced <see cref="NetworkObject"/>.
|
||||
|
@ -24,13 +25,13 @@ namespace Unity.Netcode
|
|||
/// Creates a new instance of the <see cref="NetworkObjectReference"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="networkObject">The <see cref="NetworkObject"/> to reference.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public NetworkObjectReference(NetworkObject networkObject)
|
||||
{
|
||||
if (networkObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(networkObject));
|
||||
m_NetworkObjectId = s_NullId;
|
||||
return;
|
||||
}
|
||||
|
||||
if (networkObject.IsSpawned == false)
|
||||
|
@ -45,16 +46,20 @@ namespace Unity.Netcode
|
|||
/// Creates a new instance of the <see cref="NetworkObjectReference"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The GameObject from which the <see cref="NetworkObject"/> component will be referenced.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public NetworkObjectReference(GameObject gameObject)
|
||||
{
|
||||
if (gameObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(gameObject));
|
||||
m_NetworkObjectId = s_NullId;
|
||||
return;
|
||||
}
|
||||
|
||||
var networkObject = gameObject.GetComponent<NetworkObject>() ?? throw new ArgumentException($"Cannot create {nameof(NetworkObjectReference)} from {nameof(GameObject)} without a {nameof(NetworkObject)} component.");
|
||||
var networkObject = gameObject.GetComponent<NetworkObject>();
|
||||
if (!networkObject)
|
||||
{
|
||||
throw new ArgumentException($"Cannot create {nameof(NetworkObjectReference)} from {nameof(GameObject)} without a {nameof(NetworkObject)} component.");
|
||||
}
|
||||
if (networkObject.IsSpawned == false)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(NetworkObjectReference)} can only be created from spawned {nameof(NetworkObject)}s.");
|
||||
|
@ -80,10 +85,14 @@ namespace Unity.Netcode
|
|||
/// </summary>
|
||||
/// <param name="networkObjectRef">The reference.</param>
|
||||
/// <param name="networkManager">The networkmanager. Uses <see cref="NetworkManager.Singleton"/> to resolve if null.</param>
|
||||
/// <returns>The resolves <see cref="NetworkObject"/>. Returns null if the networkobject was not found</returns>
|
||||
/// <returns>The resolved <see cref="NetworkObject"/>. Returns null if the networkobject was not found</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static NetworkObject Resolve(NetworkObjectReference networkObjectRef, NetworkManager networkManager = null)
|
||||
{
|
||||
if (networkObjectRef.m_NetworkObjectId == s_NullId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
networkManager = networkManager ?? NetworkManager.Singleton;
|
||||
networkManager.SpawnManager.SpawnedObjects.TryGetValue(networkObjectRef.m_NetworkObjectId, out NetworkObject networkObject);
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Unity.Netcode.RuntimeTests
|
|||
{
|
||||
private class TestNetworkBehaviour : NetworkBehaviour
|
||||
{
|
||||
public static bool ReceivedRPC;
|
||||
|
||||
public NetworkVariable<NetworkBehaviourReference> TestVariable = new NetworkVariable<NetworkBehaviourReference>();
|
||||
|
||||
public TestNetworkBehaviour RpcReceivedBehaviour;
|
||||
|
@ -25,6 +27,7 @@ namespace Unity.Netcode.RuntimeTests
|
|||
public void SendReferenceServerRpc(NetworkBehaviourReference value)
|
||||
{
|
||||
RpcReceivedBehaviour = (TestNetworkBehaviour)value;
|
||||
ReceivedRPC = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,8 +60,43 @@ namespace Unity.Netcode.RuntimeTests
|
|||
Assert.AreEqual(testNetworkBehaviour, testNetworkBehaviour.RpcReceivedBehaviour);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestSerializeNull([Values] bool initializeWithNull)
|
||||
{
|
||||
TestNetworkBehaviour.ReceivedRPC = false;
|
||||
using var networkObjectContext = UnityObjectContext.CreateNetworkObject();
|
||||
var testNetworkBehaviour = networkObjectContext.Object.gameObject.AddComponent<TestNetworkBehaviour>();
|
||||
networkObjectContext.Object.Spawn();
|
||||
|
||||
using var otherObjectContext = UnityObjectContext.CreateNetworkObject();
|
||||
otherObjectContext.Object.Spawn();
|
||||
|
||||
// If not initializing with null, then use the default constructor with no assigned NetworkBehaviour
|
||||
if (!initializeWithNull)
|
||||
{
|
||||
testNetworkBehaviour.SendReferenceServerRpc(new NetworkBehaviourReference());
|
||||
}
|
||||
else // Otherwise, initialize and pass in null as the reference
|
||||
{
|
||||
testNetworkBehaviour.SendReferenceServerRpc(new NetworkBehaviourReference(null));
|
||||
}
|
||||
|
||||
// wait for rpc completion
|
||||
float t = 0;
|
||||
while (!TestNetworkBehaviour.ReceivedRPC)
|
||||
{
|
||||
t += Time.deltaTime;
|
||||
if (t > 5f)
|
||||
{
|
||||
new AssertionException("RPC with NetworkBehaviour reference hasn't been received");
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// validate
|
||||
Assert.AreEqual(null, testNetworkBehaviour.RpcReceivedBehaviour);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestRpcImplicitNetworkBehaviour()
|
||||
|
@ -89,6 +127,7 @@ namespace Unity.Netcode.RuntimeTests
|
|||
Assert.AreEqual(testNetworkBehaviour, testNetworkBehaviour.RpcReceivedBehaviour);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestNetworkVariable()
|
||||
{
|
||||
|
@ -131,15 +170,6 @@ namespace Unity.Netcode.RuntimeTests
|
|||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailSerializeNullBehaviour()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
{
|
||||
NetworkBehaviourReference outReference = null;
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//Stop, shutdown, and destroy
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace Unity.Netcode.RuntimeTests
|
|||
{
|
||||
private class TestNetworkBehaviour : NetworkBehaviour
|
||||
{
|
||||
public static bool ReceivedRPC;
|
||||
public NetworkVariable<NetworkObjectReference> TestVariable = new NetworkVariable<NetworkObjectReference>();
|
||||
|
||||
public NetworkObject RpcReceivedNetworkObject;
|
||||
|
@ -28,6 +29,7 @@ namespace Unity.Netcode.RuntimeTests
|
|||
[ServerRpc]
|
||||
public void SendReferenceServerRpc(NetworkObjectReference value)
|
||||
{
|
||||
ReceivedRPC = true;
|
||||
RpcReceivedGameObject = value;
|
||||
RpcReceivedNetworkObject = value;
|
||||
}
|
||||
|
@ -150,6 +152,60 @@ namespace Unity.Netcode.RuntimeTests
|
|||
Assert.AreEqual(networkObject, result);
|
||||
}
|
||||
|
||||
public enum NetworkObjectConstructorTypes
|
||||
{
|
||||
None,
|
||||
NullNetworkObject,
|
||||
NullGameObject
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestSerializeNull([Values] NetworkObjectConstructorTypes networkObjectConstructorTypes)
|
||||
{
|
||||
TestNetworkBehaviour.ReceivedRPC = false;
|
||||
using var networkObjectContext = UnityObjectContext.CreateNetworkObject();
|
||||
var testNetworkBehaviour = networkObjectContext.Object.gameObject.AddComponent<TestNetworkBehaviour>();
|
||||
networkObjectContext.Object.Spawn();
|
||||
|
||||
switch (networkObjectConstructorTypes)
|
||||
{
|
||||
case NetworkObjectConstructorTypes.None:
|
||||
{
|
||||
testNetworkBehaviour.SendReferenceServerRpc(new NetworkObjectReference());
|
||||
break;
|
||||
}
|
||||
case NetworkObjectConstructorTypes.NullNetworkObject:
|
||||
{
|
||||
testNetworkBehaviour.SendReferenceServerRpc(new NetworkObjectReference((NetworkObject)null));
|
||||
break;
|
||||
}
|
||||
case NetworkObjectConstructorTypes.NullGameObject:
|
||||
{
|
||||
testNetworkBehaviour.SendReferenceServerRpc(new NetworkObjectReference((GameObject)null));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// wait for rpc completion
|
||||
float t = 0;
|
||||
while (!TestNetworkBehaviour.ReceivedRPC)
|
||||
{
|
||||
|
||||
t += Time.deltaTime;
|
||||
if (t > 5f)
|
||||
{
|
||||
new AssertionException("RPC with NetworkBehaviour reference hasn't been received");
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// validate
|
||||
Assert.AreEqual(null, testNetworkBehaviour.RpcReceivedNetworkObject);
|
||||
Assert.AreEqual(null, testNetworkBehaviour.RpcReceivedGameObject);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TestRpc()
|
||||
{
|
||||
|
@ -305,24 +361,6 @@ namespace Unity.Netcode.RuntimeTests
|
|||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailSerializeNullNetworkObject()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
{
|
||||
NetworkObjectReference outReference = (NetworkObject)null;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FailSerializeNullGameObject()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
{
|
||||
NetworkObjectReference outReference = (GameObject)null;
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
//Stop, shutdown, and destroy
|
||||
|
|
Загрузка…
Ссылка в новой задаче