diff --git a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs index 59a187a5fc..59e2164dd3 100644 --- a/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs @@ -797,8 +797,9 @@ internal void HandleConnectionApproval(ulong ownerClientId, NetworkManager.Conne // Server-side spawning (only if there is a prefab hash or player prefab provided) if (!NetworkManager.DistributedAuthorityMode && response.CreatePlayerObject && (response.PlayerPrefabHash.HasValue || NetworkManager.NetworkConfig.PlayerPrefab != null)) { - var playerObject = response.PlayerPrefabHash.HasValue ? NetworkManager.SpawnManager.GetNetworkObjectToSpawn(response.PlayerPrefabHash.Value, ownerClientId, response.Position ?? null, response.Rotation ?? null) - : NetworkManager.SpawnManager.GetNetworkObjectToSpawn(NetworkManager.NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash, ownerClientId, response.Position ?? null, response.Rotation ?? null); + var instantiationPayloadWriter = new BufferSerializer(new BufferSerializerWriter(new FastBufferWriter(0,Allocator.Temp))); + var playerObject = response.PlayerPrefabHash.HasValue ? NetworkManager.SpawnManager.GetNetworkObjectToSpawn(response.PlayerPrefabHash.Value, ownerClientId, ref instantiationPayloadWriter, response.Position ?? null, response.Rotation ?? null) + : NetworkManager.SpawnManager.GetNetworkObjectToSpawn(NetworkManager.NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash, ownerClientId, ref instantiationPayloadWriter, response.Position ?? null, response.Rotation ?? null); // Spawn the player NetworkObject locally NetworkManager.SpawnManager.SpawnNetworkObjectLocally( @@ -950,7 +951,8 @@ internal void CreateAndSpawnPlayer(ulong ownerId) if (playerPrefab != null) { var globalObjectIdHash = playerPrefab.GetComponent().GlobalObjectIdHash; - var networkObject = NetworkManager.SpawnManager.GetNetworkObjectToSpawn(globalObjectIdHash, ownerId, playerPrefab.transform.position, playerPrefab.transform.rotation); + var instantiationPayloadWriter = new BufferSerializer(new BufferSerializerWriter(new FastBufferWriter(0, Allocator.Temp))); + var networkObject = NetworkManager.SpawnManager.GetNetworkObjectToSpawn(globalObjectIdHash, ownerId, ref instantiationPayloadWriter, playerPrefab.transform.position, playerPrefab.transform.rotation); networkObject.IsSceneObject = false; networkObject.SpawnAsPlayerObject(ownerId, networkObject.DestroyWithScene); } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index 64c8e96076..26d03b87ee 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; +using Unity.Collections; using Unity.Netcode.Components; #if UNITY_EDITOR using UnityEditor; @@ -45,6 +46,13 @@ public sealed class NetworkObject : MonoBehaviour [SerializeField] internal uint InScenePlacedSourceGlobalObjectIdHash; + /// + /// Metadata sent during the instantiation process. + /// Retrieved in INetworkCustomSpawnDataSynchronizer before instantiation, + /// and available to INetworkPrefabInstanceHandler.Instantiate() for custom handling by user code. + /// + internal FastBufferReader InstantiationPayload; + /// /// Gets the Prefab Hash Id of this object if the object is registerd as a prefab otherwise it returns 0 /// @@ -2812,6 +2820,7 @@ internal struct SceneObject public ulong NetworkObjectId; public ulong OwnerClientId; public ushort OwnershipFlags; + public FastBufferReader InstantiationPayload; public bool IsPlayerObject { @@ -2882,6 +2891,12 @@ public bool SpawnWithObservers set => ByteUtility.SetBit(ref m_BitField, 10, value); } + public bool HasInstantiationPayload + { + get => ByteUtility.GetBit(m_BitField, 11); + set => ByteUtility.SetBit(ref m_BitField, 11, value); + } + // When handling the initial synchronization of NetworkObjects, // this will be populated with the known observers. public ulong[] Observers; @@ -2948,12 +2963,26 @@ public void Serialize(FastBufferWriter writer) var writeSize = 0; writeSize += HasTransform ? FastBufferWriter.GetWriteSize() : 0; writeSize += FastBufferWriter.GetWriteSize(); + if (HasInstantiationPayload) + { + writeSize += FastBufferWriter.GetWriteSize(); + writeSize += InstantiationPayload.Length; + } if (!writer.TryBeginWrite(writeSize)) { throw new OverflowException("Could not serialize SceneObject: Out of buffer space."); } + if (HasInstantiationPayload) + { + writer.WriteValueSafe(InstantiationPayload.Length); + unsafe + { + writer.WriteBytes(InstantiationPayload.GetUnsafePtr(), InstantiationPayload.Length); + } + } + if (HasTransform) { writer.WriteValue(Transform); @@ -3014,12 +3043,34 @@ public void Deserialize(FastBufferReader reader) readSize += HasTransform ? FastBufferWriter.GetWriteSize() : 0; readSize += FastBufferWriter.GetWriteSize(); + int preInstanceDataSize = 0; + if (HasInstantiationPayload) + { + if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize())) + { + throw new OverflowException($"Could not deserialize SceneObject: Reading past the end of the buffer ({nameof(InstantiationPayload)} size)"); + } + + reader.ReadValueSafe(out preInstanceDataSize); + readSize += FastBufferWriter.GetWriteSize(); + readSize += preInstanceDataSize; + } + // Try to begin reading the remaining bytes if (!reader.TryBeginRead(readSize)) { throw new OverflowException("Could not deserialize SceneObject: Reading past the end of the buffer"); } + if (HasInstantiationPayload) + { + unsafe + { + InstantiationPayload = new FastBufferReader(reader.GetUnsafePtrAtCurrentPosition(), Allocator.Persistent, preInstanceDataSize); + reader.Seek(reader.Position + preInstanceDataSize); + } + } + if (HasTransform) { reader.ReadValue(out Transform); @@ -3148,7 +3199,9 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager NetworkSceneHandle = NetworkSceneHandle, Hash = CheckForGlobalObjectIdHashOverride(), OwnerObject = this, - TargetClientId = targetClientId + TargetClientId = targetClientId, + HasInstantiationPayload = InstantiationPayload.IsInitialized, + InstantiationPayload = InstantiationPayload }; // Handle Parenting @@ -3243,6 +3296,11 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf // in order to be able to determine which NetworkVariables the client will be allowed to read. networkObject.OwnerClientId = sceneObject.OwnerClientId; + // Even though the Instantiation Payload is typically consumed during the spawn message handling phase, + // we still assign it here to preserve the original spawn metadata for potential inspection, diagnostics, + // or in case future systems want to access it directly without relying on synchronization messages. + networkObject.InstantiationPayload = sceneObject.InstantiationPayload; + // Special Case: Invoke NetworkBehaviour.OnPreSpawn methods here before SynchronizeNetworkBehaviours networkObject.InvokeBehaviourNetworkPreSpawn(); diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs index 15e30205f8..815e38d35c 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/CustomMessageManager.cs @@ -180,18 +180,14 @@ internal void InvokeNamedMessage(ulong hash, ulong sender, FastBufferReader read // We dont know what size to use. Try every (more collision prone) if (m_NamedMessageHandlers32.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler32)) { - // handler can remove itself, cache the name for metrics - var messageName = m_MessageHandlerNameLookup32[hash]; messageHandler32(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup32[hash], bytesCount); } if (m_NamedMessageHandlers64.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler64)) { - // handler can remove itself, cache the name for metrics - var messageName = m_MessageHandlerNameLookup64[hash]; messageHandler64(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup64[hash], bytesCount); } } else @@ -202,19 +198,15 @@ internal void InvokeNamedMessage(ulong hash, ulong sender, FastBufferReader read case HashSize.VarIntFourBytes: if (m_NamedMessageHandlers32.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler32)) { - // handler can remove itself, cache the name for metrics - var messageName = m_MessageHandlerNameLookup32[hash]; messageHandler32(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup32[hash], bytesCount); } break; case HashSize.VarIntEightBytes: if (m_NamedMessageHandlers64.TryGetValue(hash, out HandleNamedMessageDelegate messageHandler64)) { - // handler can remove itself, cache the name for metrics - var messageName = m_MessageHandlerNameLookup64[hash]; messageHandler64(sender, reader); - m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, messageName, bytesCount); + m_NetworkManager.NetworkMetrics.TrackNamedMessageReceived(sender, m_MessageHandlerNameLookup64[hash], bytesCount); } break; } diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/INetworkCustomSpawnDataReceiver.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/INetworkCustomSpawnDataReceiver.cs new file mode 100644 index 0000000000..d496dbb935 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/INetworkCustomSpawnDataReceiver.cs @@ -0,0 +1,20 @@ +namespace Unity.Netcode +{ + /// + /// Interface for synchronizing custom instantiation payloads during NetworkObject spawning. + /// Used alongside to extend instantiation behavior. + /// + public interface INetworkInstantiationPayloadSynchronizer + { + /// + /// Provides a method for synchronizing instantiation payload data during the spawn process. + /// Extends to allow passing additional data prior to instantiation + /// to help identify or configure the local object instance that should be linked to the spawned NetworkObject. + /// + /// This method is invoked immediately before is called, + /// allowing you to cache or prepare information needed during instantiation. + /// + /// The buffer serializer used to read or write custom instantiation data. + void OnSynchronize(ref BufferSerializer serializer) where T : IReaderWriter; + } +} diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/INetworkCustomSpawnDataReceiver.cs.meta b/com.unity.netcode.gameobjects/Runtime/Spawning/INetworkCustomSpawnDataReceiver.cs.meta new file mode 100644 index 0000000000..3895ba444c --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/INetworkCustomSpawnDataReceiver.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9bf5119a47f8d3247aaa4cd13c1ee96b \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs index fe0dd270e9..723db0720e 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs @@ -252,12 +252,33 @@ internal uint GetSourceGlobalObjectIdHash(uint networkPrefabHash) /// /// /// - internal NetworkObject HandleNetworkPrefabSpawn(uint networkPrefabAssetHash, ulong ownerClientId, Vector3 position, Quaternion rotation) + internal NetworkObject HandleNetworkPrefabSpawn(uint networkPrefabAssetHash, ulong ownerClientId, ref BufferSerializer preInstanceDataSerializer, Vector3 position, Quaternion rotation) where T : IReaderWriter { if (m_PrefabAssetToPrefabHandler.TryGetValue(networkPrefabAssetHash, out var prefabInstanceHandler)) { + if (prefabInstanceHandler is INetworkInstantiationPayloadSynchronizer synchronizer) + { + synchronizer.OnSynchronize(ref preInstanceDataSerializer); + } var networkObjectInstance = prefabInstanceHandler.Instantiate(ownerClientId, position, rotation); - + if (networkObjectInstance != null) + { + if (preInstanceDataSerializer.IsReader) + { + networkObjectInstance.InstantiationPayload = preInstanceDataSerializer.GetFastBufferReader(); + } + else + { + var writer = preInstanceDataSerializer.GetFastBufferWriter(); + if (writer.Length > 0) + { + unsafe + { + networkObjectInstance.InstantiationPayload = new FastBufferReader(writer.GetUnsafePtr(), Collections.Allocator.Persistent, writer.Length); + } + } + } + } //Now we must make sure this alternate PrefabAsset spawned in place of the prefab asset with the networkPrefabAssetHash (GlobalObjectIdHash) //is registered and linked to the networkPrefabAssetHash so during the HandleNetworkPrefabDestroy process we can identify the alternate prefab asset. if (networkObjectInstance != null && !m_PrefabInstanceToPrefabAsset.ContainsKey(networkObjectInstance.GlobalObjectIdHash)) diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 19227c82ba..dc4740c693 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -678,12 +678,12 @@ internal enum InstantiateAndSpawnErrorTypes internal static readonly Dictionary InstantiateAndSpawnErrors = new Dictionary( new KeyValuePair[]{ - new KeyValuePair(InstantiateAndSpawnErrorTypes.NetworkPrefabNull, $"The {nameof(NetworkObject)} prefab parameter was null!"), - new KeyValuePair(InstantiateAndSpawnErrorTypes.NotAuthority, $"Only the server has authority to {nameof(InstantiateAndSpawn)}!"), - new KeyValuePair(InstantiateAndSpawnErrorTypes.InvokedWhenShuttingDown, $"Invoking {nameof(InstantiateAndSpawn)} while shutting down! Calls to {nameof(InstantiateAndSpawn)} will be ignored."), - new KeyValuePair(InstantiateAndSpawnErrorTypes.NotRegisteredNetworkPrefab, $"The {nameof(NetworkObject)} parameter is not a registered network prefab. Did you forget to register it or are you trying to instantiate and spawn an instance of a network prefab?"), - new KeyValuePair(InstantiateAndSpawnErrorTypes.NetworkManagerNull, $"The {nameof(NetworkManager)} parameter was null!"), - new KeyValuePair(InstantiateAndSpawnErrorTypes.NoActiveSession, "You can only invoke this method when you are connected to an existing/in-progress network session!") + new KeyValuePair(InstantiateAndSpawnErrorTypes.NetworkPrefabNull, $"The {nameof(NetworkObject)} prefab parameter was null!"), + new KeyValuePair(InstantiateAndSpawnErrorTypes.NotAuthority, $"Only the server has authority to {nameof(InstantiateAndSpawn)}!"), + new KeyValuePair(InstantiateAndSpawnErrorTypes.InvokedWhenShuttingDown, $"Invoking {nameof(InstantiateAndSpawn)} while shutting down! Calls to {nameof(InstantiateAndSpawn)} will be ignored."), + new KeyValuePair(InstantiateAndSpawnErrorTypes.NotRegisteredNetworkPrefab, $"The {nameof(NetworkObject)} parameter is not a registered network prefab. Did you forget to register it or are you trying to instantiate and spawn an instance of a network prefab?"), + new KeyValuePair(InstantiateAndSpawnErrorTypes.NetworkManagerNull, $"The {nameof(NetworkManager)} parameter was null!"), + new KeyValuePair(InstantiateAndSpawnErrorTypes.NoActiveSession, "You can only invoke this method when you are connected to an existing/in-progress network session!") }); /// @@ -748,7 +748,9 @@ internal NetworkObject InstantiateAndSpawnNoParameterChecks(NetworkObject networ // - Distributed authority mode always spawns the override if one exists. if (forceOverride || NetworkManager.IsClient || NetworkManager.DistributedAuthorityMode || NetworkManager.PrefabHandler.ContainsHandler(networkPrefab.GlobalObjectIdHash)) { - networkObject = GetNetworkObjectToSpawn(networkPrefab.GlobalObjectIdHash, ownerClientId, position, rotation); + Debug.Assert(networkPrefab.GlobalObjectIdHash != 0, $"The {nameof(NetworkObject)} prefab passed in does not have a valid {nameof(NetworkObject.GlobalObjectIdHash)} value!"); + var intantiationPayloadWriter = new BufferSerializer(new BufferSerializerWriter(new FastBufferWriter(20, Collections.Allocator.Temp))); + networkObject = GetNetworkObjectToSpawn(networkPrefab.GlobalObjectIdHash, ownerClientId, ref intantiationPayloadWriter, position, rotation); } else // Under this case, server instantiate the prefab passed in. { @@ -779,14 +781,14 @@ internal NetworkObject InstantiateAndSpawnNoParameterChecks(NetworkObject networ /// Gets the right NetworkObject prefab instance to spawn. If a handler is registered or there is an override assigned to the /// passed in globalObjectIdHash value, then that is what will be instantiated, spawned, and returned. /// - internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ownerId, Vector3? position, Quaternion? rotation, bool isScenePlaced = false) + internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ownerId, ref BufferSerializer instantiationPayloadSerializer, Vector3? position, Quaternion? rotation, bool isScenePlaced = false) where T : IReaderWriter { NetworkObject networkObject = null; // If the prefab hash has a registered INetworkPrefabInstanceHandler derived class if (NetworkManager.PrefabHandler.ContainsHandler(globalObjectIdHash)) { // Let the handler spawn the NetworkObject - networkObject = NetworkManager.PrefabHandler.HandleNetworkPrefabSpawn(globalObjectIdHash, ownerId, position ?? default, rotation ?? default); + networkObject = NetworkManager.PrefabHandler.HandleNetworkPrefabSpawn(globalObjectIdHash, ownerId, ref instantiationPayloadSerializer, position ?? default, rotation ?? default); networkObject.NetworkManagerOwner = NetworkManager; } else @@ -807,22 +809,22 @@ internal NetworkObject GetNetworkObjectToSpawn(uint globalObjectIdHash, ulong ow break; case NetworkPrefabOverride.Hash: case NetworkPrefabOverride.Prefab: + { + // When scene management is disabled and this is an in-scene placed NetworkObject, we want to always use the + // SourcePrefabToOverride and not any possible prefab override as a user might want to spawn overrides dynamically + // but might want to use the same source network prefab as an in-scene placed NetworkObject. + // (When scene management is enabled, clients don't delete their in-scene placed NetworkObjects prior to dynamically + // spawning them so the original prefab placed is preserved and this is not needed) + if (inScenePlacedWithNoSceneManagement) { - // When scene management is disabled and this is an in-scene placed NetworkObject, we want to always use the - // SourcePrefabToOverride and not any possible prefab override as a user might want to spawn overrides dynamically - // but might want to use the same source network prefab as an in-scene placed NetworkObject. - // (When scene management is enabled, clients don't delete their in-scene placed NetworkObjects prior to dynamically - // spawning them so the original prefab placed is preserved and this is not needed) - if (inScenePlacedWithNoSceneManagement) - { - networkPrefabReference = networkPrefab.SourcePrefabToOverride ? networkPrefab.SourcePrefabToOverride : networkPrefab.Prefab; - } - else - { - networkPrefabReference = NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[globalObjectIdHash].OverridingTargetPrefab; - } - break; + networkPrefabReference = networkPrefab.SourcePrefabToOverride ? networkPrefab.SourcePrefabToOverride : networkPrefab.Prefab; } + else + { + networkPrefabReference = NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[globalObjectIdHash].OverridingTargetPrefab; + } + break; + } } } @@ -888,7 +890,8 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SceneObject sceneO // If scene management is disabled or the NetworkObject was dynamically spawned if (!NetworkManager.NetworkConfig.EnableSceneManagement || !sceneObject.IsSceneObject) { - networkObject = GetNetworkObjectToSpawn(sceneObject.Hash, sceneObject.OwnerClientId, position, rotation, sceneObject.IsSceneObject); + var instantiationPayloadReader = new BufferSerializer(new BufferSerializerReader(sceneObject.InstantiationPayload)); + networkObject = GetNetworkObjectToSpawn(sceneObject.Hash, sceneObject.OwnerClientId, ref instantiationPayloadReader, position, rotation, sceneObject.IsSceneObject); } else // Get the in-scene placed NetworkObject { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerTests.cs index c66c843abf..40b48e7a35 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerTests.cs @@ -110,7 +110,8 @@ public void NetworkPrefabHandlerClass([Values] bool distributedAuthority) //Test result of registering via GameObject reference Assert.True(gameObjectRegistered); - var spawnedObject = networkPrefabHandler.HandleNetworkPrefabSpawn(baseObject.GlobalObjectIdHash, 0, prefabPosition, prefabRotation); + var instantiationPayloadWriter = new BufferSerializer(new BufferSerializerWriter(new FastBufferWriter(0, Collections.Allocator.Temp))); + var spawnedObject = networkPrefabHandler.HandleNetworkPrefabSpawn(baseObject.GlobalObjectIdHash, 0, ref instantiationPayloadWriter, prefabPosition, prefabRotation); //Test that something was instantiated Assert.NotNull(spawnedObject); @@ -135,7 +136,8 @@ public void NetworkPrefabHandlerClass([Values] bool distributedAuthority) prefabPosition = new Vector3(2.0f, 1.0f, 5.0f); prefabRotation = new Quaternion(4.0f, 1.5f, 5.4f, 5.1f); - spawnedObject = networkPrefabHandler.HandleNetworkPrefabSpawn(baseObject.GlobalObjectIdHash, 0, prefabPosition, prefabRotation); + instantiationPayloadWriter = new BufferSerializer(new BufferSerializerWriter(new FastBufferWriter(0, Collections.Allocator.Temp))); + spawnedObject = networkPrefabHandler.HandleNetworkPrefabSpawn(baseObject.GlobalObjectIdHash, 0, ref instantiationPayloadWriter, prefabPosition, prefabRotation); //Test that something was instantiated Assert.NotNull(spawnedObject); @@ -160,7 +162,8 @@ public void NetworkPrefabHandlerClass([Values] bool distributedAuthority) prefabPosition = new Vector3(6.0f, 4.0f, 1.0f); prefabRotation = new Quaternion(3f, 2f, 4f, 1f); - spawnedObject = networkPrefabHandler.HandleNetworkPrefabSpawn(baseObject.GlobalObjectIdHash, 0, prefabPosition, prefabRotation); + instantiationPayloadWriter = new BufferSerializer(new BufferSerializerWriter(new FastBufferWriter(0, Collections.Allocator.Temp))); + spawnedObject = networkPrefabHandler.HandleNetworkPrefabSpawn(baseObject.GlobalObjectIdHash, 0, ref instantiationPayloadWriter, prefabPosition, prefabRotation); //Test that something was instantiated Assert.NotNull(spawnedObject);