Skip to content

Commit 4c7f63d

Browse files
committed
New requirements fullfilled
1 parent d42bf95 commit 4c7f63d

4 files changed

Lines changed: 68 additions & 61 deletions

File tree

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

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,31 +1852,6 @@ internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool pla
18521852
}
18531853
}
18541854

1855-
/// <summary>
1856-
/// Serializes the given instantiation data and stores it to be used during the spawn process
1857-
/// by a compatible <see cref="INetworkPrefabInstanceHandlerWithData{T}"/>
1858-
/// </summary>
1859-
public void InjectInstantiationData<T>(T data) where T : struct, INetworkSerializable
1860-
{
1861-
if (!NetworkManager.PrefabHandler.TryGetHandlerWithData(GlobalObjectIdHash, out var prefabHandler) || !prefabHandler.HandlesDataType<T>())
1862-
{
1863-
throw new Exception("[InstantiationData] Cannot inject data: no compatible handler found for the specified data type.");
1864-
}
1865-
1866-
using var writer = new FastBufferWriter(4, Collections.Allocator.Temp, int.MaxValue);
1867-
var serializer = new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
1868-
1869-
try
1870-
{
1871-
data.NetworkSerialize(serializer);
1872-
InstantiationData = writer.ToArray();
1873-
}
1874-
catch (Exception ex)
1875-
{
1876-
NetworkLog.LogError($"[InstantiationData] Failed to serialize instantiation data for {nameof(NetworkObject)} '{gameObject.name}': {ex}");
1877-
}
1878-
}
1879-
18801855
/// <summary>
18811856
/// This invokes <see cref="NetworkSpawnManager.InstantiateAndSpawn(NetworkObject, ulong, bool, bool, bool, Vector3, Quaternion)"/>.
18821857
/// </summary>
Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using Unity.Collections;
34
using UnityEngine;
45

56
namespace Unity.Netcode
@@ -8,47 +9,39 @@ namespace Unity.Netcode
89
/// Specialized version of <see cref="INetworkPrefabInstanceHandler"/> that receives
910
/// custom instantiation data injected by the server before spawning.
1011
/// </summary>
11-
public interface INetworkPrefabInstanceHandlerWithData<T> : INetworkPrefabInstanceHandlerWithData where T : struct, INetworkSerializable
12+
public interface INetworkPrefabInstanceHandlerWithData<T> where T : struct, INetworkSerializable
1213
{
13-
// Propagating custom data through the entire spawn pipeline would add complexity and reduce modularity.
14-
// To work around this, deserialization injects the data into this static map, keyed by the handler instance.
15-
// The handler then reads the data at instantiation time, keeping the interface clean and stateless from the user's perspective.
16-
// This avoids requiring implementers to store the data explicitly or declare additional fields.
17-
static readonly Dictionary<INetworkPrefabInstanceHandlerWithData, T> _handlerToData = new();
14+
NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation, T instantiationData);
15+
void Destroy(NetworkObject networkObject);
1816

19-
NetworkObject INetworkPrefabInstanceHandler.Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation) => Instantiate(ownerClientId, position, rotation, _handlerToData[this]);
20-
void INetworkPrefabInstanceHandlerWithData.RemoveDataEntry(INetworkPrefabInstanceHandlerWithData instance) => _handlerToData.Remove(instance);
21-
bool INetworkPrefabInstanceHandlerWithData.HandlesDataType<U>() => typeof(T) == typeof(U);
22-
void INetworkPrefabInstanceHandlerWithData.ReadInstantiationData<RW>(ref BufferSerializer<RW> serializer)
17+
public static void InjectInstantiationDataForObject(GameObject prefab, T instantiationData)
2318
{
24-
_handlerToData.TryGetValue(this, out var value);
25-
serializer.SerializeValue(ref value);
26-
_handlerToData[this] = value;
19+
if (prefab.TryGetComponent<NetworkObject>(out var networkObject))
20+
{
21+
networkObject.NetworkManager.PrefabHandler.InjectInstantiationData(prefab, instantiationData);
22+
}
23+
else
24+
{
25+
Debug.LogError($"Prefab {prefab.name} does not have a NetworkObject component.");
26+
}
2727
}
28-
29-
NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation, T instantiationData);
3028
}
3129

32-
/// <summary>
33-
/// Internal use only. Do not implement directly. Use <see cref="INetworkPrefabInstanceHandlerWithData{T}"/> instead.
34-
/// </summary>
35-
public interface INetworkPrefabInstanceHandlerWithData : INetworkPrefabInstanceHandler
30+
internal interface INetworkPrefabInstanceHandlerWithData : INetworkPrefabInstanceHandler
3631
{
37-
/// <summary>
38-
/// Invoked during deserialization to read the instantiation data associated with this prefab instance.
39-
/// </summary>
40-
void ReadInstantiationData<T>(ref BufferSerializer<T> serializer) where T : IReaderWriter;
32+
bool HandlesDataType<T>();
33+
void ReadInstantiationData<TReaderWriter>(ref BufferSerializer<TReaderWriter> serializer) where TReaderWriter : IReaderWriter;
34+
}
4135

42-
/// <summary>
43-
/// Removes the data entry for the given instance.
44-
/// Is important to call this when the instance isnt referenced to avoid memory leaks.
45-
/// </summary>
46-
/// <param name="instance"></param>
47-
void RemoveDataEntry(INetworkPrefabInstanceHandlerWithData instance);
36+
internal class HandlerWrapper<T> : INetworkPrefabInstanceHandlerWithData where T : struct, INetworkSerializable
37+
{
38+
private readonly INetworkPrefabInstanceHandlerWithData<T> _impl;
39+
private T _payload;
4840

49-
/// <summary>
50-
/// Returns true if <typeparamref name="T"/> matches the expected instantiation data type for this handler.
51-
/// </summary>
52-
bool HandlesDataType<T>() where T : struct, INetworkSerializable;
41+
public HandlerWrapper(INetworkPrefabInstanceHandlerWithData<T> impl) => _impl = impl;
42+
public bool HandlesDataType<U>() => typeof(T) == typeof(U);
43+
public void ReadInstantiationData<TReaderWriter>(ref BufferSerializer<TReaderWriter> serializer) where TReaderWriter : IReaderWriter => serializer.SerializeValue(ref _payload);
44+
public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation) => _impl.Instantiate(ownerClientId, position, rotation, _payload);
45+
public void Destroy(NetworkObject networkObject) => _impl.Destroy(networkObject);
5346
}
54-
}
47+
}

com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ public bool AddHandler(GameObject networkPrefabAsset, INetworkPrefabInstanceHand
8484
{
8585
return AddHandler(networkPrefabAsset.GetComponent<NetworkObject>().GlobalObjectIdHash, instanceHandler);
8686
}
87+
public bool AddHandler<T>(GameObject networkPrefabAsset, INetworkPrefabInstanceHandlerWithData<T> instanceHandler) where T : struct, INetworkSerializable
88+
{
89+
return AddHandler(networkPrefabAsset.GetComponent<NetworkObject>().GlobalObjectIdHash, instanceHandler);
90+
}
8791

8892
/// <summary>
8993
/// Use a <see cref="NetworkObject"/> to register a class that implements the <see cref="INetworkPrefabInstanceHandler"/> interface with the <see cref="NetworkPrefabHandler"/>
@@ -95,6 +99,10 @@ public bool AddHandler(NetworkObject prefabAssetNetworkObject, INetworkPrefabIns
9599
{
96100
return AddHandler(prefabAssetNetworkObject.GlobalObjectIdHash, instanceHandler);
97101
}
102+
public bool AddHandler<T>(NetworkObject prefabAssetNetworkObject, INetworkPrefabInstanceHandlerWithData<T> instanceHandler) where T : struct, INetworkSerializable
103+
{
104+
return AddHandler(prefabAssetNetworkObject.GlobalObjectIdHash, instanceHandler);
105+
}
98106

99107
/// <summary>
100108
/// Use a <see cref="NetworkObject.GlobalObjectIdHash"/> to register a class that implements the <see cref="INetworkPrefabInstanceHandler"/> interface with the <see cref="NetworkPrefabHandler"/>
@@ -116,6 +124,38 @@ public bool AddHandler(uint globalObjectIdHash, INetworkPrefabInstanceHandler in
116124

117125
return false;
118126
}
127+
public bool AddHandler<T>(uint globalObjectIdHash, INetworkPrefabInstanceHandlerWithData<T> instanceHandler) where T : struct, INetworkSerializable
128+
{
129+
if (!m_PrefabAssetToPrefabHandler.ContainsKey(globalObjectIdHash))
130+
return AddHandler(globalObjectIdHash, new HandlerWrapper<T>(instanceHandler));
131+
return false;
132+
}
133+
134+
public void InjectInstantiationData<T>(GameObject gameObject, T instantiationData) where T : struct, INetworkSerializable
135+
{
136+
if (gameObject.TryGetComponent<NetworkObject>(out var networkObject))
137+
InjectInstantiationData(networkObject,instantiationData);
138+
}
139+
public void InjectInstantiationData<T>(NetworkObject networkObject, T data) where T : struct, INetworkSerializable
140+
{
141+
if (!TryGetHandlerWithData(networkObject.GlobalObjectIdHash, out var prefabHandler) || !prefabHandler.HandlesDataType<T>())
142+
{
143+
throw new Exception("[InstantiationData] Cannot inject data: no compatible handler found for the specified data type.");
144+
}
145+
146+
using var writer = new FastBufferWriter(4, Collections.Allocator.Temp, int.MaxValue);
147+
var serializer = new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
148+
149+
try
150+
{
151+
data.NetworkSerialize(serializer);
152+
networkObject.InstantiationData = writer.ToArray();
153+
}
154+
catch (Exception ex)
155+
{
156+
NetworkLog.LogError($"[InstantiationData] Failed to serialize instantiation data for {nameof(NetworkObject)} '{networkObject.name}': {ex}");
157+
}
158+
}
119159

120160
/// <summary>
121161
/// HOST ONLY!
@@ -214,7 +254,6 @@ public bool RemoveHandler(uint globalObjectIdHash)
214254

215255
if(m_PrefabAssetToPrefabHandlerWithData.TryGetValue(globalObjectIdHash, out var handlerWithData))
216256
{
217-
handlerWithData.RemoveDataEntry(handlerWithData);
218257
m_PrefabAssetToPrefabHandlerWithData.Remove(globalObjectIdHash);
219258
}
220259
return m_PrefabAssetToPrefabHandler.Remove(globalObjectIdHash);

com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerWithDataTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ private void RegisterPrefab(NetworkManager manager, out PrefabInstanceHandlerWit
107107
private NetworkObject SpawnPrefabWithData(NetworkSerializableTest data)
108108
{
109109
var instance = GameObject.Instantiate(_prefab).GetComponent<NetworkObject>();
110-
instance.InjectInstantiationData(data);
110+
server.PrefabHandler.InjectInstantiationData(instance, data);
111111
instance.Spawn();
112112
return instance;
113113
}

0 commit comments

Comments
 (0)