Skip to content

Commit e36996c

Browse files
update
First pass merge of distributed authority feature.
1 parent 1fa39e1 commit e36996c

File tree

178 files changed

+14705
-2098
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

178 files changed

+14705
-2098
lines changed

LICENSE.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
MIT License
1+
Unity Companion License (UCL License)
22

3-
Copyright (c) 2021 Unity Technologies
3+
com.unity.netcode.gameobjects copyright © 2021-2024 Unity Technologies
4+
Licensed under the Unity Companion License for Unity-dependent projects (see https://unity3d.com/legal/licenses/unity_companion_license).
5+
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.
46

5-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
67

7-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8-
9-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
4343

4444
### Fixed
4545

46+
- Fixed issue where in-scene placed `NetworkObject`s with complex nested children `NetworkObject`s (more than one child in depth) would not synchronize properly if WorldPositionStays was set to true. (#2796)
4647
- Fixed issue where a client disconnected by a server-host would not receive a local notification. (#2789)
4748
- Fixed issue where a server-host could shutdown during a relay connection but periodically the transport disconnect message sent to any connected clients could be dropped. (#2789)
4849
- Fixed issue where a host could disconnect its local client but remain running as a server. (#2789)

com.unity.netcode.gameobjects/Components/Messages/NetworkTransformMessage.cs

Lines changed: 132 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ internal struct NetworkTransformMessage : INetworkMessage
1111
public int Version => 0;
1212
public ulong NetworkObjectId;
1313
public int NetworkBehaviourId;
14+
#if NGO_DAMODE
15+
// This is only used when serializing but not serialized
16+
public bool DistributedAuthorityMode;
17+
// Might get removed
18+
public ulong[] TargetIds;
19+
20+
private int GetTargetIdLength()
21+
{
22+
if (TargetIds != null)
23+
{
24+
return TargetIds.Length;
25+
}
26+
return 0;
27+
}
28+
#endif
1429
public NetworkTransform.NetworkTransformState State;
1530

1631
private NetworkTransform m_ReceiverNetworkTransform;
@@ -32,6 +47,22 @@ public void Serialize(FastBufferWriter writer, int targetVersion)
3247
BytePacker.WriteValueBitPacked(writer, NetworkObjectId);
3348
BytePacker.WriteValueBitPacked(writer, NetworkBehaviourId);
3449
writer.WriteNetworkSerializable(State);
50+
#if NGO_DAMODE
51+
if (DistributedAuthorityMode)
52+
{
53+
var length = GetTargetIdLength();
54+
BytePacker.WriteValuePacked(writer, length);
55+
// If no target ids, then just exit early (DAHost specific)
56+
if (length == 0)
57+
{
58+
return;
59+
}
60+
foreach (var target in TargetIds)
61+
{
62+
BytePacker.WriteValuePacked(writer, target);
63+
}
64+
}
65+
#endif
3566
}
3667
}
3768

@@ -45,39 +76,101 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
4576
}
4677
var currentPosition = reader.Position;
4778
ByteUnpacker.ReadValueBitPacked(reader, out NetworkObjectId);
48-
if (!networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId))
79+
var isSpawnedLocally = networkManager.SpawnManager.SpawnedObjects.ContainsKey(NetworkObjectId);
80+
#if NGO_DAMODE
81+
// Only defer if the NetworkObject is not spawned yet and the local NetworkManager is not running as a DAHost.
82+
if (!isSpawnedLocally && !networkManager.DAHost)
83+
#else
84+
if (!isSpawnedLocally)
85+
#endif
4986
{
5087
networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnSpawn, NetworkObjectId, reader, ref context);
5188
return false;
5289
}
90+
91+
// While the below check and assignment might seem out of place, this is specific to running in DAHost mode when a NetworkObject is
92+
// hidden from the DAHost but is visible to other clients. Since the DAHost needs to forward updates to the clients, we ignore processing
93+
// this message locally
94+
var networkObject = (NetworkObject)null;
95+
var isServerAuthoritative = false;
96+
var ownerAuthoritativeServerSide = false;
97+
5398
// Get the behaviour index
5499
ByteUnpacker.ReadValueBitPacked(reader, out NetworkBehaviourId);
55100

56101
// Deserialize the state
57-
reader.ReadNetworkSerializable(out State);
102+
reader.ReadNetworkSerializableInPlace(ref State);
58103

59-
var networkObject = networkManager.SpawnManager.SpawnedObjects[NetworkObjectId];
104+
#if NGO_DAMODE
105+
if (networkManager.DistributedAuthorityMode)
106+
{
107+
var targetCount = 0;
108+
ByteUnpacker.ReadValueBitPacked(reader, out targetCount);
109+
if (targetCount > 0)
110+
{
111+
TargetIds = new ulong[targetCount];
112+
}
113+
var targetId = (ulong)0;
114+
for (int i = 0; i < targetCount; i++)
115+
{
116+
ByteUnpacker.ReadValueBitPacked(reader, out targetId);
117+
TargetIds[i] = targetId;
118+
}
119+
}
120+
#endif
60121

61-
// Get the target NetworkTransform
62-
m_ReceiverNetworkTransform = networkObject.ChildNetworkBehaviours[NetworkBehaviourId] as NetworkTransform;
122+
if (isSpawnedLocally)
123+
{
124+
networkObject = networkManager.SpawnManager.SpawnedObjects[NetworkObjectId];
125+
// Get the target NetworkTransform
126+
m_ReceiverNetworkTransform = networkObject.ChildNetworkBehaviours[NetworkBehaviourId] as NetworkTransform;
127+
isServerAuthoritative = m_ReceiverNetworkTransform.IsServerAuthoritative();
128+
ownerAuthoritativeServerSide = !isServerAuthoritative && networkManager.IsServer;
129+
}
130+
#if NGO_DAMODE
131+
else
132+
{
133+
// If we are the DAHost and the NetworkObject is hidden from the host we still need to forward this message
134+
ownerAuthoritativeServerSide = networkManager.DAHost && !isSpawnedLocally;
135+
}
136+
#endif
63137

64-
var isServerAuthoritative = m_ReceiverNetworkTransform.IsServerAuthoritative();
65-
var ownerAuthoritativeServerSide = !isServerAuthoritative && networkManager.IsServer;
66138
if (ownerAuthoritativeServerSide)
67139
{
68-
var ownerClientId = networkObject.OwnerClientId;
69-
if (ownerClientId == NetworkManager.ServerClientId)
140+
var ownerClientId = (ulong)0;
141+
142+
if (networkObject != null)
70143
{
71-
// Ownership must have changed, ignore any additional pending messages that might have
72-
// come from a previous owner client.
73-
return true;
144+
ownerClientId = networkObject.OwnerClientId;
145+
if (ownerClientId == NetworkManager.ServerClientId)
146+
{
147+
// Ownership must have changed, ignore any additional pending messages that might have
148+
// come from a previous owner client.
149+
return true;
150+
}
74151
}
152+
#if NGO_DAMODE
153+
else if (networkManager.DAHost)
154+
{
155+
// Specific to distributed authority mode, the only sender of state updates will be the owner
156+
ownerClientId = context.SenderId;
157+
}
158+
#endif
75159

76160
var networkDelivery = State.IsReliableStateUpdate() ? NetworkDelivery.ReliableSequenced : NetworkDelivery.UnreliableSequenced;
77161

78162
// Forward the state update if there are any remote clients to foward it to
79163
if (networkManager.ConnectionManager.ConnectedClientsList.Count > (networkManager.IsHost ? 2 : 1))
80164
{
165+
#if NGO_DAMODE
166+
var clientCount = networkManager.DistributedAuthorityMode ? GetTargetIdLength() : networkManager.ConnectionManager.ConnectedClientsList.Count;
167+
if (clientCount == 0)
168+
{
169+
return true;
170+
}
171+
#else
172+
var clientCount = networkManager.ConnectionManager.ConnectedClientsList.Count;
173+
#endif
81174
// This is only to copy the existing and already serialized struct for forwarding purposes only.
82175
// This will not include any changes made to this struct at this particular stage of processing the message.
83176
var currentMessage = this;
@@ -86,15 +179,29 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
86179
// Rewind the new reader to the beginning of the message's payload
87180
currentMessage.m_CurrentReader.Seek(currentPosition);
88181
// Forward the message to all connected clients that are observers of the associated NetworkObject
89-
var clientCount = networkManager.ConnectionManager.ConnectedClientsList.Count;
182+
90183
for (int i = 0; i < clientCount; i++)
91184
{
185+
#if NGO_DAMODE
186+
var clientId = networkManager.DistributedAuthorityMode ? TargetIds[i] : networkManager.ConnectionManager.ConnectedClientsList[i].ClientId;
187+
if (NetworkManager.ServerClientId == clientId || (!isServerAuthoritative && clientId == ownerClientId) ||
188+
(!networkManager.DistributedAuthorityMode && !networkObject.Observers.Contains(clientId)))
189+
#else
92190
var clientId = networkManager.ConnectionManager.ConnectedClientsList[i].ClientId;
93191
if (NetworkManager.ServerClientId == clientId || (!isServerAuthoritative && clientId == ownerClientId) || !networkObject.Observers.Contains(clientId))
192+
#endif
94193
{
95194
continue;
96195
}
97-
networkManager.MessageManager.SendMessage(ref currentMessage, networkDelivery, clientId);
196+
197+
if (clientId > 1)
198+
{
199+
networkManager.MessageManager.SendMessage(ref currentMessage, networkDelivery, clientId);
200+
}
201+
else
202+
{
203+
networkManager.MessageManager.SendMessage(ref currentMessage, networkDelivery, clientId);
204+
}
98205
}
99206
// Dispose of the reader used for forwarding
100207
currentMessage.m_CurrentReader.Dispose();
@@ -105,6 +212,17 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
105212

106213
public void Handle(ref NetworkContext context)
107214
{
215+
#if NGO_DAMODE
216+
var networkManager = context.SystemOwner as NetworkManager;
217+
// Only if the local NetworkManager instance is running as the DAHost we just exit if there is no local
218+
// NetworkTransform component to apply the state update to (i.e. it is hidden from the DAHost and it
219+
// just forwarded the state update to any other connected client)
220+
if (networkManager.DAHost && m_ReceiverNetworkTransform == null)
221+
{
222+
return;
223+
}
224+
#endif
225+
108226
if (m_ReceiverNetworkTransform == null)
109227
{
110228
Debug.LogError($"[{nameof(NetworkTransformMessage)}][Dropped] Reciever {nameof(NetworkTransform)} was not set!");

0 commit comments

Comments
 (0)