Skip to content

Commit e138a9c

Browse files
fix: client owner with both owner read and write permissions on a NetworkVariable does not update the server when changed (#2097)
* fix MTT-4266 This fixes the issue where a NetworkVariable that is set to owner read and write permissions and the owner is a client, then the server would not be updated with any changes to the NetworkVariable. * test This includes an additional test to check that a client owner with both Owner read and write permissions will only update changes to the NetworkVariable on the server. * update Adding the changelog entry for this fix. * update adding PR number.
1 parent 421a364 commit e138a9c

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
1414

1515
### Fixed
1616

17-
- Fixed issue when attempting to spawn a parent `GameObject`, with `NetworkObject` component attached, that has one or more child `GameObject`s, that are inactive in the hierarchy, with `NetworkBehaviour` components it will no longer attempt to spawn the associated NetworkBehaviour(s) or invoke ownership changed notifications but will log a warning message. (#2096)
17+
- Fixed issue where a client owner of a `NetworkVariable` with both owner read and write permissions would not update the server side when changed. (#2097)
18+
- Fixed issue when attempting to spawn a parent `GameObject`, with `NetworkObject` component attached, that has one or more child `GameObject`s, that are inactive in the hierarchy, with `NetworkBehaviour` components it will no longer attempt to spawn the associated `NetworkBehaviour`(s) or invoke ownership changed notifications but will log a warning message. (#2096)
1819
- Fixed issue where `NetworkObject.NetworkHide` was despawning and destroying, as opposed to only despawning, in-scene placed `NetworkObject`s. (#2086)
1920
- Fixed issue where `NetworkAnimator` would not synchronize a looping animation for late joining clients if it was at the very end of its loop. (#2076)
2021
- Fixed issue where `NetworkAnimator` was not removing its subscription from `OnClientConnectedCallback` when despawned during the shutdown sequence. (#2074)

com.unity.netcode.gameobjects/Runtime/NetworkVariable/NetworkVariableBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public bool CanClientRead(ulong clientId)
111111
case NetworkVariableReadPermission.Everyone:
112112
return true;
113113
case NetworkVariableReadPermission.Owner:
114-
return clientId == m_NetworkBehaviour.NetworkObject.OwnerClientId;
114+
return clientId == m_NetworkBehaviour.NetworkObject.OwnerClientId || NetworkManager.ServerClientId == clientId;
115115
}
116116
}
117117

com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariableTests.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class NetVarPermTestComp : NetworkBehaviour
1414
{
1515
public NetworkVariable<Vector3> OwnerWritable_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableBase.DefaultReadPerm, NetworkVariableWritePermission.Owner);
1616
public NetworkVariable<Vector3> ServerWritable_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableBase.DefaultReadPerm, NetworkVariableWritePermission.Server);
17+
public NetworkVariable<Vector3> OwnerReadWrite_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableReadPermission.Owner, NetworkVariableWritePermission.Owner);
1718
}
1819

1920
[TestFixtureSource(nameof(TestDataSource))]
@@ -104,6 +105,42 @@ private bool CheckServerWritableAreEqualOnAll()
104105
return true;
105106
}
106107

108+
private bool CheckOwnerReadWriteAreEqualOnOwnerAndServer()
109+
{
110+
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
111+
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
112+
foreach (var clientNetworkManager in m_ClientNetworkManagers)
113+
{
114+
var testObjClient = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
115+
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
116+
if (testObjServer.OwnerClientId == testObjClient.OwnerClientId &&
117+
testCompServer.OwnerReadWrite_Position.Value == testCompClient.ServerWritable_Position.Value &&
118+
testCompServer.OwnerReadWrite_Position.ReadPerm == testCompClient.ServerWritable_Position.ReadPerm &&
119+
testCompServer.OwnerReadWrite_Position.WritePerm == testCompClient.ServerWritable_Position.WritePerm)
120+
{
121+
return true;
122+
}
123+
}
124+
return false;
125+
}
126+
127+
private bool CheckOwnerReadWriteAreNotEqualOnNonOwnerClients(NetVarPermTestComp ownerReadWriteObject)
128+
{
129+
foreach (var clientNetworkManager in m_ClientNetworkManagers)
130+
{
131+
var testObjClient = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
132+
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
133+
if (testObjClient.OwnerClientId != ownerReadWriteObject.OwnerClientId ||
134+
ownerReadWriteObject.OwnerReadWrite_Position.Value == testCompClient.ServerWritable_Position.Value ||
135+
ownerReadWriteObject.OwnerReadWrite_Position.ReadPerm != testCompClient.ServerWritable_Position.ReadPerm ||
136+
ownerReadWriteObject.OwnerReadWrite_Position.WritePerm != testCompClient.ServerWritable_Position.WritePerm)
137+
{
138+
return false;
139+
}
140+
}
141+
return true;
142+
}
143+
107144
[UnityTest]
108145
public IEnumerator ServerChangesOwnerWritableNetVar()
109146
{
@@ -164,6 +201,44 @@ public IEnumerator ClientChangesOwnerWritableNetVar()
164201
yield return WaitForOwnerWritableAreEqualOnAll();
165202
}
166203

204+
/// <summary>
205+
/// This tests the scenario where a client owner has both read and write
206+
/// permissions set. The server should be the only instance that can read
207+
/// the NetworkVariable. ServerCannotChangeOwnerWritableNetVar performs
208+
/// the same check to make sure the server cannot write to a client owner
209+
/// NetworkVariable with owner write permissions.
210+
/// </summary>
211+
[UnityTest]
212+
public IEnumerator ClientOwnerWithReadWriteChangesNetVar()
213+
{
214+
yield return WaitForOwnerWritableAreEqualOnAll();
215+
216+
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
217+
218+
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
219+
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
220+
testObjServer.ChangeOwnership(newOwnerClientId);
221+
yield return NetcodeIntegrationTestHelpers.WaitForTicks(m_ServerNetworkManager, 2);
222+
223+
yield return WaitForOwnerWritableAreEqualOnAll();
224+
225+
var testObjClient = m_ClientNetworkManagers[clientManagerIndex].SpawnManager.SpawnedObjects[m_TestObjId];
226+
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
227+
228+
var oldValue = testCompClient.OwnerReadWrite_Position.Value;
229+
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
230+
231+
testCompClient.OwnerWritable_Position.Value = newValue;
232+
yield return WaitForPositionsAreEqual(testCompClient.OwnerWritable_Position, newValue);
233+
234+
// Verify the client owner and server match
235+
yield return CheckOwnerReadWriteAreEqualOnOwnerAndServer();
236+
237+
// Verify the non-owner clients do not have the same Value but do have the same permissions
238+
yield return CheckOwnerReadWriteAreNotEqualOnNonOwnerClients(testCompClient);
239+
}
240+
241+
167242
[UnityTest]
168243
public IEnumerator ClientCannotChangeServerWritableNetVar()
169244
{

0 commit comments

Comments
 (0)