Skip to content

Commit fb7d11a

Browse files
update
Some additions and modifications to finalize the hybrid prefab concept.
1 parent 2eeb2c7 commit fb7d11a

7 files changed

Lines changed: 293 additions & 18 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#if UNIFIED_NETCODE
2+
using System;
3+
using Unity.NetCode;
4+
5+
namespace Unity.Netcode
6+
{
7+
// Temporarily making this public
8+
// TODO: Make this internal when complete (if used)
9+
public partial class NetworkObjectBridge : GhostBehaviour
10+
{
11+
public Action<ulong> NetworkObjectIdChanged;
12+
13+
internal GhostField<ulong> NetworkObjectId = new GhostField<ulong>();
14+
15+
public void SetNetworkObjectId(ulong value)
16+
{
17+
NetworkObjectId.Value = value;
18+
}
19+
public override void Awake()
20+
{
21+
base.Awake();
22+
NetworkObjectId.ValueChanged += OnNetworkObjectIdChanged;
23+
}
24+
25+
private void OnNetworkObjectIdChanged(ulong value)
26+
{
27+
NetworkObjectIdChanged?.Invoke(value);
28+
}
29+
}
30+
}
31+
#endif

com.unity.netcode.gameobjects/Runtime/Components/NetworkObjectBridge.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/Core/NetworkObject.cs

Lines changed: 174 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
using System.Text;
66
using Unity.Netcode.Components;
77
using Unity.Netcode.Runtime;
8+
#if UNIFIED_NETCODE
9+
using Unity.NetCode;
10+
#endif
11+
812
#if UNITY_EDITOR
913
using UnityEditor;
1014
#if UNITY_2021_2_OR_NEWER
@@ -243,6 +247,10 @@ private static void CheckPrefabStage(PrefabStage prefabStage)
243247
/// </summary>
244248
internal void OnValidate()
245249
{
250+
#if UNIFIED_NETCODE
251+
UnifiedValidation();
252+
#endif
253+
246254
// Always exit early if we are in prefab edit mode and this instance is the
247255
// prefab instance within the InContext or InIsolation edit scene.
248256
if (s_PrefabInstance == this)
@@ -338,6 +346,27 @@ private void CheckForInScenePlaced()
338346
}
339347
#endif // UNITY_EDITOR
340348

349+
#if UNIFIED_NETCODE
350+
[HideInInspector]
351+
[SerializeField]
352+
internal GhostAdapter GhostAdapter;
353+
354+
[HideInInspector]
355+
[SerializeField]
356+
internal bool HasGhost;
357+
358+
private void UnifiedValidation()
359+
{
360+
NetworkObjectBridge = GetComponent<NetworkObjectBridge>();
361+
GhostAdapter = GetComponent<GhostAdapter>();
362+
HasGhost = GhostAdapter != null;
363+
if (HasGhost && NetworkObjectBridge == null)
364+
{
365+
NetworkObjectBridge = gameObject.AddComponent<NetworkObjectBridge>();
366+
}
367+
}
368+
#endif
369+
341370
internal bool HasParentNetworkObject(Transform transform)
342371
{
343372
if (transform.parent != null)
@@ -2836,6 +2865,10 @@ internal struct SceneObject
28362865
public ulong OwnerClientId;
28372866
public ushort OwnershipFlags;
28382867

2868+
#if UNIFIED_NETCODE
2869+
public int GhostId;
2870+
#endif
2871+
28392872
public bool IsPlayerObject
28402873
{
28412874
get => ByteUtility.GetBit(m_BitField, 0);
@@ -2911,6 +2944,14 @@ public bool HasInstantiationData
29112944
set => ByteUtility.SetBit(ref m_BitField, 11, value);
29122945
}
29132946

2947+
#if UNIFIED_NETCODE
2948+
public bool HasGhost
2949+
{
2950+
get => ByteUtility.GetBit(m_BitField, 12);
2951+
set => ByteUtility.SetBit(ref m_BitField, 12, value);
2952+
}
2953+
#endif
2954+
29142955
// When handling the initial synchronization of NetworkObjects,
29152956
// this will be populated with the known observers.
29162957
public ulong[] Observers;
@@ -3000,6 +3041,13 @@ public void Serialize(FastBufferWriter writer)
30003041
writer.WriteValue(OwnerObject.GetSceneOriginHandle());
30013042
}
30023043

3044+
#if UNIFIED_NETCODE
3045+
if (HasGhost)
3046+
{
3047+
writer.WriteValueSafe(GhostId);
3048+
}
3049+
#endif
3050+
30033051
// write placeholder for serialized data size.
30043052
// Can't be bitpacked because we don't know the value until we calculate it later
30053053
var positionBeforeSynchronizing = writer.Position;
@@ -3079,6 +3127,13 @@ public void Deserialize(FastBufferReader reader)
30793127
// scene handle that the NetworkObject resides in.
30803128
reader.ReadValue(out NetworkSceneHandle);
30813129

3130+
#if UNIFIED_NETCODE
3131+
if (HasGhost)
3132+
{
3133+
reader.ReadValueSafe(out GhostId);
3134+
}
3135+
#endif
3136+
30823137
// Read the size of the remaining synchronization data
30833138
// This data will be read in AddSceneObject()
30843139
reader.ReadValueSafe(out SynchronizationDataSize);
@@ -3175,7 +3230,11 @@ internal SceneObject GetMessageSceneObject(ulong targetClientId = NetworkManager
31753230
Hash = CheckForGlobalObjectIdHashOverride(),
31763231
OwnerObject = this,
31773232
TargetClientId = targetClientId,
3178-
HasInstantiationData = InstantiationData != null && InstantiationData.Length > 0
3233+
HasInstantiationData = InstantiationData != null && InstantiationData.Length > 0,
3234+
#if UNIFIED_NETCODE
3235+
HasGhost = HasGhost,
3236+
GhostId = HasGhost ? GhostInstance.ghostId : 0,
3237+
#endif
31793238
};
31803239

31813240
// Handle Parenting
@@ -3248,11 +3307,9 @@ internal static NetworkObject AddSceneObject(in SceneObject sceneObject, FastBuf
32483307
reader.ReadValueSafe(out instantiationData);
32493308
}
32503309

3251-
32523310
// Attempt to create a local NetworkObject
32533311
var networkObject = networkManager.SpawnManager.CreateLocalNetworkObject(sceneObject, instantiationData);
32543312

3255-
32563313
if (networkObject == null)
32573314
{
32583315
// Log the error that the NetworkObject failed to construct
@@ -3490,7 +3547,121 @@ private void Awake()
34903547
#endif
34913548
SetCachedParent(transform.parent);
34923549
SceneOrigin = gameObject.scene;
3550+
#if UNIFIED_NETCODE
3551+
InitGhost();
3552+
#endif
3553+
3554+
}
3555+
3556+
private void OnEnable()
3557+
{
3558+
Debug.Log("Enabled!");
3559+
}
3560+
3561+
private void OnDisable()
3562+
{
3563+
Debug.Log("Disabled!");
3564+
}
3565+
3566+
#if UNIFIED_NETCODE
3567+
3568+
private void Start()
3569+
{
3570+
enabled = true;
34933571
}
3572+
internal GhostInstance GhostInstance;
3573+
[SerializeField]
3574+
[HideInInspector]
3575+
internal NetworkObjectBridge NetworkObjectBridge;
3576+
3577+
private void InitGhost()
3578+
{
3579+
enabled = true;
3580+
// All instances with Ghosts are automatically registered
3581+
if (HasGhost && NetworkObjectBridge)
3582+
{
3583+
Debug.Log($"[{nameof(NetworkObject)}] GhostBridge {name} detected and instantiated.");
3584+
NetworkObjectBridge.NetworkObjectIdChanged += OnNetworkObjectIdChanged;
3585+
if (NetworkObjectBridge.NetworkObjectId.Value != 0)
3586+
{
3587+
RegisterGhostBridge();
3588+
}
3589+
//var networkObjectRegistration = (false, (ulong)0);
3590+
//NetworkManager.SpawnManager.RegisterGhostPendingSpawn(this, NetworkObjectBridge.NetworkObjectId);
3591+
//try
3592+
//{
3593+
// networkObjectRegistration = GhostAdapter.GetNetworkObjectId();
3594+
//}
3595+
//catch (Exception ex)
3596+
//{
3597+
// Debug.LogException(ex);
3598+
//}
3599+
3600+
//if (networkObjectRegistration.Item1)
3601+
//{
3602+
// // Authority and Non-Authority:
3603+
// // Upon instantiation it will always register itself as a Ghost that is pending NGO spawn.
3604+
3605+
// // Non-Authority:
3606+
// // - If registered prior to the CreateObjectMessage, then upon receiving the CreateObjectMessag it will be processed immediately using this instance.
3607+
// // - If registered after receiving the CreateObjectMessage, then upon registering it will also process any deferred CreateObjectMessages
3608+
// // If this happens prior to receiving the is received,
3609+
// // Authority:
3610+
// // Upon spawning locally, this entry is removed from the ghost pending spawn table.
3611+
3612+
3613+
3614+
//}
3615+
//else if (!NetworkManager.IsServer)
3616+
//{
3617+
// StartCoroutine(WaitForGhostData());
3618+
//}
3619+
//else
3620+
//{
3621+
// Debug.LogError($"[{name}] Failed to get ghost instance or GhostId is zero!");
3622+
//}
3623+
}
3624+
}
3625+
3626+
private void RegisterGhostBridge()
3627+
{
3628+
Debug.Log($"[{nameof(NetworkObject)}][{nameof(NetworkObjectId)}] NetworkObjectBridge notified instance exists with assigned ID of: {NetworkObjectBridge.NetworkObjectId.Value}");
3629+
NetworkManager.SpawnManager.RegisterGhostPendingSpawn(this, NetworkObjectBridge.NetworkObjectId.Value);
3630+
}
3631+
3632+
private void OnNetworkObjectIdChanged(ulong networkObjectId)
3633+
{
3634+
RegisterGhostBridge();
3635+
}
3636+
3637+
//private System.Collections.IEnumerator WaitForGhostData()
3638+
//{
3639+
// var waitPeriod = new WaitForSeconds(0.1f);
3640+
// var timeout = Time.realtimeSinceStartup + 5.0f;
3641+
// while (timeout > Time.realtimeSinceStartup)
3642+
// {
3643+
// enabled = true;
3644+
// var networkObjectRegistration = (false, (ulong)0);
3645+
// try
3646+
// {
3647+
// networkObjectRegistration = GhostAdapter.GetNetworkObjectId();
3648+
// }
3649+
// catch (Exception ex)
3650+
// {
3651+
// Debug.LogException(ex);
3652+
// }
3653+
// if (networkObjectRegistration.Item1)
3654+
// {
3655+
// NetworkManager.SpawnManager.RegisterGhostPendingSpawn(this, networkObjectRegistration.Item2);
3656+
// yield break;
3657+
// }
3658+
// yield return waitPeriod;
3659+
// }
3660+
3661+
// Debug.Log("Timed out waiting for Ghost to be registered!");
3662+
3663+
//}
3664+
#endif
34943665

34953666
/// <summary>
34963667
/// Update

com.unity.netcode.gameobjects/Runtime/Messaging/IDeferredNetworkMessageManager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ internal enum TriggerType
88
OnSpawn,
99
OnAddPrefab,
1010
OnNextFrame,
11+
#if UNIFIED_NETCODE
12+
OnGhostSpawned,
13+
#endif
1114
}
1215

1316
/// <summary>

com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,17 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
120120
ByteUnpacker.ReadValuePacked(reader, out NetworkObjectId);
121121
}
122122

123+
#if UNIFIED_NETCODE
124+
UnityEngine.Debug.Log($"Received {nameof(CreateObjectMessage)} for NetworkObjectId-{ObjectInfo.NetworkObjectId}.");
125+
// For now, we will defer the create object message until the associated Ghost is spawned
126+
if (ObjectInfo.HasGhost && !networkManager.SpawnManager.GhostsPendingSpawn.ContainsKey(ObjectInfo.NetworkObjectId))
127+
{
128+
UnityEngine.Debug.Log($"Deferring {nameof(CreateObjectMessage)} to wait for Ghost.");
129+
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnGhostSpawned, (ulong)ObjectInfo.GhostId, reader, ref context, k_Name);
130+
return false;
131+
}
132+
#endif
133+
123134
if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectInfo))
124135
{
125136
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectInfo.Hash, reader, ref context, k_Name);

0 commit comments

Comments
 (0)