|
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
4 | 4 | using System.Runtime.CompilerServices; |
| 5 | +using Unity.Collections; |
5 | 6 | using Unity.Netcode.Components; |
6 | 7 | #if UNITY_EDITOR |
7 | 8 | using UnityEditor; |
@@ -45,6 +46,13 @@ public sealed class NetworkObject : MonoBehaviour |
45 | 46 | [SerializeField] |
46 | 47 | internal uint InScenePlacedSourceGlobalObjectIdHash; |
47 | 48 |
|
| 49 | + /// <summary> |
| 50 | + /// Metadata sent during the instantiation process. |
| 51 | + /// Retrieved in INetworkCustomSpawnDataSynchronizer before instantiation, |
| 52 | + /// and available to INetworkPrefabInstanceHandler.Instantiate() for custom handling by user code. |
| 53 | + /// </summary> |
| 54 | + internal FastBufferReader InstantiationPayload; |
| 55 | + |
48 | 56 | /// <summary> |
49 | 57 | /// Gets the Prefab Hash Id of this object if the object is registerd as a prefab otherwise it returns 0 |
50 | 58 | /// </summary> |
@@ -2812,6 +2820,7 @@ internal struct SceneObject |
2812 | 2820 | public ulong NetworkObjectId; |
2813 | 2821 | public ulong OwnerClientId; |
2814 | 2822 | public ushort OwnershipFlags; |
| 2823 | + public FastBufferReader InstantiationPayload; |
2815 | 2824 |
|
2816 | 2825 | public bool IsPlayerObject |
2817 | 2826 | { |
@@ -2882,6 +2891,12 @@ public bool SpawnWithObservers |
2882 | 2891 | set => ByteUtility.SetBit(ref m_BitField, 10, value); |
2883 | 2892 | } |
2884 | 2893 |
|
| 2894 | + public bool HasInstantiationPayload |
| 2895 | + { |
| 2896 | + get => ByteUtility.GetBit(m_BitField, 11); |
| 2897 | + set => ByteUtility.SetBit(ref m_BitField, 11, value); |
| 2898 | + } |
| 2899 | + |
2885 | 2900 | // When handling the initial synchronization of NetworkObjects, |
2886 | 2901 | // this will be populated with the known observers. |
2887 | 2902 | public ulong[] Observers; |
@@ -2948,12 +2963,26 @@ public void Serialize(FastBufferWriter writer) |
2948 | 2963 | var writeSize = 0; |
2949 | 2964 | writeSize += HasTransform ? FastBufferWriter.GetWriteSize<TransformData>() : 0; |
2950 | 2965 | writeSize += FastBufferWriter.GetWriteSize<int>(); |
| 2966 | + if (HasInstantiationPayload) |
| 2967 | + { |
| 2968 | + writeSize += FastBufferWriter.GetWriteSize<int>(); |
| 2969 | + writeSize += InstantiationPayload.Length; |
| 2970 | + } |
2951 | 2971 |
|
2952 | 2972 | if (!writer.TryBeginWrite(writeSize)) |
2953 | 2973 | { |
2954 | 2974 | throw new OverflowException("Could not serialize SceneObject: Out of buffer space."); |
2955 | 2975 | } |
2956 | 2976 |
|
| 2977 | + if (HasInstantiationPayload) |
| 2978 | + { |
| 2979 | + writer.WriteValueSafe(InstantiationPayload.Length); |
| 2980 | + unsafe |
| 2981 | + { |
| 2982 | + writer.WriteBytes(InstantiationPayload.GetUnsafePtr(), InstantiationPayload.Length); |
| 2983 | + } |
| 2984 | + } |
| 2985 | + |
2957 | 2986 | if (HasTransform) |
2958 | 2987 | { |
2959 | 2988 | writer.WriteValue(Transform); |
@@ -3014,12 +3043,34 @@ public void Deserialize(FastBufferReader reader) |
3014 | 3043 | readSize += HasTransform ? FastBufferWriter.GetWriteSize<TransformData>() : 0; |
3015 | 3044 | readSize += FastBufferWriter.GetWriteSize<int>(); |
3016 | 3045 |
|
| 3046 | + int preInstanceDataSize = 0; |
| 3047 | + if (HasInstantiationPayload) |
| 3048 | + { |
| 3049 | + if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize<int>())) |
| 3050 | + { |
| 3051 | + throw new OverflowException($"Could not deserialize SceneObject: Reading past the end of the buffer ({nameof(InstantiationPayload)} size)"); |
| 3052 | + } |
| 3053 | + |
| 3054 | + reader.ReadValueSafe(out preInstanceDataSize); |
| 3055 | + readSize += FastBufferWriter.GetWriteSize<int>(); |
| 3056 | + readSize += preInstanceDataSize; |
| 3057 | + } |
| 3058 | + |
3017 | 3059 | // Try to begin reading the remaining bytes |
3018 | 3060 | if (!reader.TryBeginRead(readSize)) |
3019 | 3061 | { |
3020 | 3062 | throw new OverflowException("Could not deserialize SceneObject: Reading past the end of the buffer"); |
3021 | 3063 | } |
3022 | 3064 |
|
| 3065 | + if (HasInstantiationPayload) |
| 3066 | + { |
| 3067 | + unsafe |
| 3068 | + { |
| 3069 | + InstantiationPayload = new FastBufferReader(reader.GetUnsafePtrAtCurrentPosition(), Allocator.Persistent, preInstanceDataSize); |
| 3070 | + reader.Seek(reader.Position + preInstanceDataSize); |
| 3071 | + } |
| 3072 | + } |
| 3073 | + |
3023 | 3074 | if (HasTransform) |
3024 | 3075 | { |
3025 | 3076 | reader.ReadValue(out Transform); |
@@ -3148,7 +3199,9 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager |
3148 | 3199 | NetworkSceneHandle = NetworkSceneHandle, |
3149 | 3200 | Hash = CheckForGlobalObjectIdHashOverride(), |
3150 | 3201 | OwnerObject = this, |
3151 | | - TargetClientId = targetClientId |
| 3202 | + TargetClientId = targetClientId, |
| 3203 | + HasInstantiationPayload = InstantiationPayload.IsInitialized, |
| 3204 | + InstantiationPayload = InstantiationPayload |
3152 | 3205 | }; |
3153 | 3206 |
|
3154 | 3207 | // Handle Parenting |
@@ -3243,6 +3296,11 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf |
3243 | 3296 | // in order to be able to determine which NetworkVariables the client will be allowed to read. |
3244 | 3297 | networkObject.OwnerClientId = sceneObject.OwnerClientId; |
3245 | 3298 |
|
| 3299 | + // Even though the Instantiation Payload is typically consumed during the spawn message handling phase, |
| 3300 | + // we still assign it here to preserve the original spawn metadata for potential inspection, diagnostics, |
| 3301 | + // or in case future systems want to access it directly without relying on synchronization messages. |
| 3302 | + networkObject.InstantiationPayload = sceneObject.InstantiationPayload; |
| 3303 | + |
3246 | 3304 | // Special Case: Invoke NetworkBehaviour.OnPreSpawn methods here before SynchronizeNetworkBehaviours |
3247 | 3305 | networkObject.InvokeBehaviourNetworkPreSpawn(); |
3248 | 3306 |
|
|
0 commit comments