com.unity.netcode.gameobjects@2.0.0-pre.4

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com).

## [2.0.0-pre.4] - 2024-08-21

### Added

- Added `NetworkVariable.CheckDirtyState` that is to be used in tandem with collections in order to detect whether the collection or an item within the collection has changed. (#3004)

### Fixed

- Fixed issue where nested `NetworkTransform` components were not getting updated. (#3016)
- Fixed issue by adding null checks in `NetworkVariableBase.CanClientRead` and `NetworkVariableBase.CanClientWrite` methods to ensure safe access to `NetworkBehaviour`. (#3012)
- Fixed issue where `FixedStringSerializer<T>` was using `NetworkVariableSerialization<byte>.AreEqual` to determine if two bytes were equal causes an exception to be thrown due to no byte serializer having been defined. (#3009)
- Fixed Issue where a state with dual triggers, inbound and outbound, could cause a false layer to layer state transition message to be sent to non-authority `NetworkAnimator` instances and cause a warning message to be logged. (#3008)
- Fixed issue using collections within `NetworkVariable` where the collection would not detect changes to items or nested items. (#3004)
- Fixed issue where `List`, `Dictionary`, and `HashSet` collections would not uniquely duplicate nested collections. (#3004)
- Fixed issue where `NotAuthorityTarget` would include the service observer in the list of targets to send the RPC to as opposed to excluding the service observer as it should. (#3000)
- Fixed issue where `ProxyRpcTargetGroup` could attempt to send a message if there were no targets to send to. (#3000)

### Changed

- Changed `NetworkAnimator` to automatically switch to owner authoritative mode when using a distributed authority network topology. (#3021)
- Changed permissions exception thrown in `NetworkList` to exiting early with a logged error that is now a unified permissions message within `NetworkVariableBase`. (#3004)
- Changed permissions exception thrown in `NetworkVariable.Value` to exiting early with a logged error that is now a unified permissions message within `NetworkVariableBase`. (#3004)
This commit is contained in:
Unity Technologies
2024-08-21 00:00:00 +00:00
parent a813ba0dd6
commit eab996f3ac
41 changed files with 4052 additions and 838 deletions

View File

@@ -0,0 +1,182 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests
{
[TestFixture(HostOrServer.DAHost)]
[TestFixture(HostOrServer.Host)]
internal class NetworkVarBufferCopyTest : NetcodeIntegrationTest
{
internal class DummyNetVar : NetworkVariableBase
{
private const int k_DummyValue = 0x13579BDF;
public bool DeltaWritten;
public bool FieldWritten;
public bool DeltaRead;
public bool FieldRead;
public override void WriteDelta(FastBufferWriter writer)
{
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(k_DummyValue) + 1);
using (var bitWriter = writer.EnterBitwiseContext())
{
bitWriter.WriteBits(1, 1);
}
writer.WriteValue(k_DummyValue);
DeltaWritten = true;
}
public override void WriteField(FastBufferWriter writer)
{
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(k_DummyValue) + 1);
using (var bitWriter = writer.EnterBitwiseContext())
{
bitWriter.WriteBits(1, 1);
}
writer.WriteValue(k_DummyValue);
FieldWritten = true;
}
public override void ReadField(FastBufferReader reader)
{
reader.TryBeginRead(FastBufferWriter.GetWriteSize(k_DummyValue) + 1);
using (var bitReader = reader.EnterBitwiseContext())
{
bitReader.ReadBits(out byte b, 1);
}
reader.ReadValue(out int i);
Assert.AreEqual(k_DummyValue, i);
FieldRead = true;
}
public override void ReadDelta(FastBufferReader reader, bool keepDirtyDelta)
{
reader.TryBeginRead(FastBufferWriter.GetWriteSize(k_DummyValue) + 1);
using (var bitReader = reader.EnterBitwiseContext())
{
bitReader.ReadBits(out byte b, 1);
}
reader.ReadValue(out int i);
Assert.AreEqual(k_DummyValue, i);
DeltaRead = true;
}
public DummyNetVar(
NetworkVariableReadPermission readPerm = DefaultReadPerm,
NetworkVariableWritePermission writePerm = DefaultWritePerm) : base(readPerm, writePerm) { }
}
internal class DummyNetBehaviour : NetworkBehaviour
{
public static bool DistributedAuthority;
public DummyNetVar NetVar;
private void Awake()
{
if (DistributedAuthority)
{
NetVar = new DummyNetVar(writePerm: NetworkVariableWritePermission.Owner);
}
else
{
NetVar = new DummyNetVar();
}
}
public override void OnNetworkSpawn()
{
if ((NetworkManager.DistributedAuthorityMode && !IsOwner) || (!NetworkManager.DistributedAuthorityMode && !IsServer))
{
ClientDummyNetBehaviourSpawned(this);
}
base.OnNetworkSpawn();
}
}
protected override int NumberOfClients => 1;
public NetworkVarBufferCopyTest(HostOrServer hostOrServer) : base(hostOrServer) { }
private static List<DummyNetBehaviour> s_ClientDummyNetBehavioursSpawned = new List<DummyNetBehaviour>();
public static void ClientDummyNetBehaviourSpawned(DummyNetBehaviour dummyNetBehaviour)
{
s_ClientDummyNetBehavioursSpawned.Add(dummyNetBehaviour);
}
protected override IEnumerator OnSetup()
{
s_ClientDummyNetBehavioursSpawned.Clear();
return base.OnSetup();
}
protected override void OnCreatePlayerPrefab()
{
DummyNetBehaviour.DistributedAuthority = m_DistributedAuthority;
m_PlayerPrefab.AddComponent<DummyNetBehaviour>();
}
[UnityTest]
public IEnumerator TestEntireBufferIsCopiedOnNetworkVariableDelta()
{
// This is the *SERVER VERSION* of the *CLIENT PLAYER*
var serverClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ServerNetworkManager, serverClientPlayerResult);
var serverSideClientPlayer = serverClientPlayerResult.Result;
var serverComponent = serverSideClientPlayer.GetComponent<DummyNetBehaviour>();
// This is the *CLIENT VERSION* of the *CLIENT PLAYER*
var clientClientPlayerResult = new NetcodeIntegrationTestHelpers.ResultWrapper<NetworkObject>();
yield return NetcodeIntegrationTestHelpers.GetNetworkObjectByRepresentation(
x => x.IsPlayerObject && x.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId,
m_ClientNetworkManagers[0], clientClientPlayerResult);
var clientSideClientPlayer = clientClientPlayerResult.Result;
var clientComponent = clientSideClientPlayer.GetComponent<DummyNetBehaviour>();
// Wait for the DummyNetBehaviours on the client side to notify they have been initialized and spawned
yield return WaitForConditionOrTimeOut(() => s_ClientDummyNetBehavioursSpawned.Count >= 1);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, "Timed out waiting for client side DummyNetBehaviour to register it was spawned!");
// Check that FieldWritten is written when dirty
var authorityComponent = m_DistributedAuthority ? clientComponent : serverComponent;
var nonAuthorityComponent = m_DistributedAuthority ? serverComponent : clientComponent;
authorityComponent.NetVar.SetDirty(true);
yield return s_DefaultWaitForTick;
Assert.True(authorityComponent.NetVar.FieldWritten);
// Check that DeltaWritten is written when dirty
authorityComponent.NetVar.SetDirty(true);
yield return s_DefaultWaitForTick;
Assert.True(authorityComponent.NetVar.DeltaWritten);
// Check that both FieldRead and DeltaRead were invoked on the client side
yield return WaitForConditionOrTimeOut(() => nonAuthorityComponent.NetVar.FieldRead == true && nonAuthorityComponent.NetVar.DeltaRead == true);
var timedOutMessage = "Timed out waiting for client reads: ";
if (s_GlobalTimeoutHelper.TimedOut)
{
if (!nonAuthorityComponent.NetVar.FieldRead)
{
timedOutMessage += "[FieldRead]";
}
if (!nonAuthorityComponent.NetVar.DeltaRead)
{
timedOutMessage += "[DeltaRead]";
}
}
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, timedOutMessage);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a7d44caa76a64b02978f5aca0e7b576a
timeCreated: 1627926008

View File

@@ -0,0 +1,420 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
internal class NetworkVariableAnticipationComponent : NetworkBehaviour
{
public AnticipatedNetworkVariable<int> SnapOnAnticipationFailVariable = new AnticipatedNetworkVariable<int>(0, StaleDataHandling.Ignore);
public AnticipatedNetworkVariable<float> SmoothOnAnticipationFailVariable = new AnticipatedNetworkVariable<float>(0, StaleDataHandling.Reanticipate);
public AnticipatedNetworkVariable<float> ReanticipateOnAnticipationFailVariable = new AnticipatedNetworkVariable<float>(0, StaleDataHandling.Reanticipate);
public override void OnReanticipate(double lastRoundTripTime)
{
if (SmoothOnAnticipationFailVariable.ShouldReanticipate)
{
if (Mathf.Abs(SmoothOnAnticipationFailVariable.AuthoritativeValue - SmoothOnAnticipationFailVariable.PreviousAnticipatedValue) > Mathf.Epsilon)
{
SmoothOnAnticipationFailVariable.Smooth(SmoothOnAnticipationFailVariable.PreviousAnticipatedValue, SmoothOnAnticipationFailVariable.AuthoritativeValue, 1, Mathf.Lerp);
}
}
if (ReanticipateOnAnticipationFailVariable.ShouldReanticipate)
{
// Would love to test some stuff about anticipation based on time, but that is difficult to test accurately.
// This reanticipating variable will just always anticipate a value 5 higher than the server value.
ReanticipateOnAnticipationFailVariable.Anticipate(ReanticipateOnAnticipationFailVariable.AuthoritativeValue + 5);
}
}
public bool SnapRpcResponseReceived = false;
[Rpc(SendTo.Server)]
public void SetSnapValueRpc(int i, RpcParams rpcParams = default)
{
SnapOnAnticipationFailVariable.AuthoritativeValue = i;
SetSnapValueResponseRpc(RpcTarget.Single(rpcParams.Receive.SenderClientId, RpcTargetUse.Temp));
}
[Rpc(SendTo.SpecifiedInParams)]
public void SetSnapValueResponseRpc(RpcParams rpcParams)
{
SnapRpcResponseReceived = true;
}
[Rpc(SendTo.Server)]
public void SetSmoothValueRpc(float f)
{
SmoothOnAnticipationFailVariable.AuthoritativeValue = f;
}
[Rpc(SendTo.Server)]
public void SetReanticipateValueRpc(float f)
{
ReanticipateOnAnticipationFailVariable.AuthoritativeValue = f;
}
}
internal class NetworkVariableAnticipationTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 2;
protected override bool m_EnableTimeTravel => true;
protected override bool m_SetupIsACoroutine => false;
protected override bool m_TearDownIsACoroutine => false;
protected override void OnPlayerPrefabGameObjectCreated()
{
m_PlayerPrefab.AddComponent<NetworkVariableAnticipationComponent>();
}
public NetworkVariableAnticipationComponent GetTestComponent()
{
return m_ClientNetworkManagers[0].LocalClient.PlayerObject.GetComponent<NetworkVariableAnticipationComponent>();
}
public NetworkVariableAnticipationComponent GetServerComponent()
{
foreach (var obj in Object.FindObjectsByType<NetworkVariableAnticipationComponent>(FindObjectsSortMode.None))
{
if (obj.NetworkManager == m_ServerNetworkManager && obj.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId)
{
return obj;
}
}
return null;
}
public NetworkVariableAnticipationComponent GetOtherClientComponent()
{
foreach (var obj in Object.FindObjectsByType<NetworkVariableAnticipationComponent>(FindObjectsSortMode.None))
{
if (obj.NetworkManager == m_ClientNetworkManagers[1] && obj.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId)
{
return obj;
}
}
return null;
}
[Test]
public void WhenAnticipating_ValueChangesImmediately()
{
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
testComponent.SmoothOnAnticipationFailVariable.Anticipate(15);
testComponent.ReanticipateOnAnticipationFailVariable.Anticipate(20);
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(15, testComponent.SmoothOnAnticipationFailVariable.Value);
Assert.AreEqual(20, testComponent.ReanticipateOnAnticipationFailVariable.Value);
}
[Test]
public void WhenAnticipating_AuthoritativeValueDoesNotChange()
{
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
testComponent.SmoothOnAnticipationFailVariable.Anticipate(15);
testComponent.ReanticipateOnAnticipationFailVariable.Anticipate(20);
Assert.AreEqual(0, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, testComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, testComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
}
[Test]
public void WhenAnticipating_ServerDoesNotChange()
{
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
testComponent.SmoothOnAnticipationFailVariable.Anticipate(15);
testComponent.ReanticipateOnAnticipationFailVariable.Anticipate(20);
var serverComponent = GetServerComponent();
Assert.AreEqual(0, serverComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, serverComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, serverComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, serverComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, serverComponent.SmoothOnAnticipationFailVariable.Value);
Assert.AreEqual(0, serverComponent.ReanticipateOnAnticipationFailVariable.Value);
TimeTravel(2, 120);
Assert.AreEqual(0, serverComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, serverComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, serverComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, serverComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, serverComponent.SmoothOnAnticipationFailVariable.Value);
Assert.AreEqual(0, serverComponent.ReanticipateOnAnticipationFailVariable.Value);
}
[Test]
public void WhenAnticipating_OtherClientDoesNotChange()
{
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
testComponent.SmoothOnAnticipationFailVariable.Anticipate(15);
testComponent.ReanticipateOnAnticipationFailVariable.Anticipate(20);
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(0, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, otherClientComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, otherClientComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, otherClientComponent.SmoothOnAnticipationFailVariable.Value);
Assert.AreEqual(0, otherClientComponent.ReanticipateOnAnticipationFailVariable.Value);
TimeTravel(2, 120);
Assert.AreEqual(0, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, otherClientComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, otherClientComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(0, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, otherClientComponent.SmoothOnAnticipationFailVariable.Value);
Assert.AreEqual(0, otherClientComponent.ReanticipateOnAnticipationFailVariable.Value);
}
[Test]
public void WhenServerChangesSnapValue_ValuesAreUpdated()
{
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
testComponent.SetSnapValueRpc(10);
WaitForMessageReceivedWithTimeTravel<RpcMessage>(
new List<NetworkManager> { m_ServerNetworkManager }
);
var serverComponent = GetServerComponent();
Assert.AreEqual(10, serverComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(10, serverComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(0, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
WaitForMessageReceivedWithTimeTravel<NetworkVariableDeltaMessage>(m_ClientNetworkManagers.ToList());
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
Assert.AreEqual(10, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(10, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
}
[Test]
public void WhenServerChangesSmoothValue_ValuesAreLerped()
{
var testComponent = GetTestComponent();
testComponent.SmoothOnAnticipationFailVariable.Anticipate(15);
Assert.AreEqual(15, testComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(0, testComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
// Set to a different value to simulate a anticipation failure - will lerp between the anticipated value
// and the actual one
testComponent.SetSmoothValueRpc(20);
WaitForMessageReceivedWithTimeTravel<RpcMessage>(
new List<NetworkManager> { m_ServerNetworkManager }
);
var serverComponent = GetServerComponent();
Assert.AreEqual(20, serverComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, serverComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(0, otherClientComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(0, otherClientComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
WaitForMessageReceivedWithTimeTravel<NetworkVariableDeltaMessage>(m_ClientNetworkManagers.ToList());
Assert.AreEqual(15 + 1f / 60f * 5, testComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, testComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
Assert.AreEqual(0 + 1f / 60f * 20, otherClientComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, otherClientComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
for (var i = 1; i < 60; ++i)
{
TimeTravel(1f / 60f, 1);
Assert.AreEqual(15 + 1f / 60f * 5 * (i + 1), testComponent.SmoothOnAnticipationFailVariable.Value, 0.00001);
Assert.AreEqual(20, testComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
Assert.AreEqual(0 + 1f / 60f * 20 * (i + 1), otherClientComponent.SmoothOnAnticipationFailVariable.Value, 0.00001);
Assert.AreEqual(20, otherClientComponent.SmoothOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
}
TimeTravel(1f / 60f, 1);
Assert.AreEqual(20, testComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, otherClientComponent.SmoothOnAnticipationFailVariable.Value, Mathf.Epsilon);
}
[Test]
public void WhenServerChangesReanticipateValue_ValuesAreReanticipated()
{
var testComponent = GetTestComponent();
testComponent.ReanticipateOnAnticipationFailVariable.Anticipate(15);
Assert.AreEqual(15, testComponent.ReanticipateOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(0, testComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
// Set to a different value to simulate a anticipation failure - will lerp between the anticipated value
// and the actual one
testComponent.SetReanticipateValueRpc(20);
WaitForMessageReceivedWithTimeTravel<RpcMessage>(
new List<NetworkManager> { m_ServerNetworkManager }
);
var serverComponent = GetServerComponent();
Assert.AreEqual(20, serverComponent.ReanticipateOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, serverComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(0, otherClientComponent.ReanticipateOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(0, otherClientComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
WaitForMessageReceivedWithTimeTravel<NetworkVariableDeltaMessage>(m_ClientNetworkManagers.ToList());
Assert.AreEqual(25, testComponent.ReanticipateOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, testComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
Assert.AreEqual(25, otherClientComponent.ReanticipateOnAnticipationFailVariable.Value, Mathf.Epsilon);
Assert.AreEqual(20, otherClientComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue, Mathf.Epsilon);
}
[Test]
public void WhenNonStaleDataArrivesToIgnoreVariable_ItIsNotIgnored([Values(10u, 30u, 60u)] uint tickRate, [Values(0u, 1u, 2u)] uint skipFrames)
{
m_ServerNetworkManager.NetworkConfig.TickRate = tickRate;
m_ServerNetworkManager.NetworkTickSystem.TickRate = tickRate;
for (var i = 0; i < skipFrames; ++i)
{
TimeTravel(1 / 60f, 1);
}
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
testComponent.SetSnapValueRpc(20);
WaitForMessageReceivedWithTimeTravel<RpcMessage>(new List<NetworkManager> { m_ServerNetworkManager });
var serverComponent = GetServerComponent();
Assert.AreEqual(20, serverComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(20, serverComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
WaitForMessageReceivedWithTimeTravel<NetworkVariableDeltaMessage>(m_ClientNetworkManagers.ToList());
// Both values get updated
Assert.AreEqual(20, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(20, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
// Other client got the server value and had made no anticipation, so it applies it to the anticipated value as well.
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(20, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(20, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
}
[Test]
public void WhenStaleDataArrivesToIgnoreVariable_ItIsIgnored([Values(10u, 30u, 60u)] uint tickRate, [Values(0u, 1u, 2u)] uint skipFrames)
{
m_ServerNetworkManager.NetworkConfig.TickRate = tickRate;
m_ServerNetworkManager.NetworkTickSystem.TickRate = tickRate;
for (var i = 0; i < skipFrames; ++i)
{
TimeTravel(1 / 60f, 1);
}
var testComponent = GetTestComponent();
testComponent.SnapOnAnticipationFailVariable.Anticipate(10);
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(0, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
testComponent.SetSnapValueRpc(30);
var serverComponent = GetServerComponent();
serverComponent.SnapOnAnticipationFailVariable.AuthoritativeValue = 20;
Assert.AreEqual(20, serverComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(20, serverComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
WaitForMessageReceivedWithTimeTravel<NetworkVariableDeltaMessage>(m_ClientNetworkManagers.ToList());
if (testComponent.SnapRpcResponseReceived)
{
// In this case the tick rate is slow enough that the RPC was received and processed, so we check that.
Assert.AreEqual(30, testComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(30, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(30, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(30, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
}
else
{
// In this case, we got an update before the RPC was processed, so we should have ignored it.
// Anticipated client received this data for a tick earlier than its anticipation, and should have prioritized the anticipated value
Assert.AreEqual(10, testComponent.SnapOnAnticipationFailVariable.Value);
// However, the authoritative value still gets updated
Assert.AreEqual(20, testComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
// Other client got the server value and had made no anticipation, so it applies it to the anticipated value as well.
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(20, otherClientComponent.SnapOnAnticipationFailVariable.Value);
Assert.AreEqual(20, otherClientComponent.SnapOnAnticipationFailVariable.AuthoritativeValue);
}
}
[Test]
public void WhenStaleDataArrivesToReanticipatedVariable_ItIsAppliedAndReanticipated()
{
var testComponent = GetTestComponent();
testComponent.ReanticipateOnAnticipationFailVariable.Anticipate(10);
Assert.AreEqual(10, testComponent.ReanticipateOnAnticipationFailVariable.Value);
Assert.AreEqual(0, testComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
var serverComponent = GetServerComponent();
serverComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue = 20;
Assert.AreEqual(20, serverComponent.ReanticipateOnAnticipationFailVariable.Value);
Assert.AreEqual(20, serverComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
WaitForMessageReceivedWithTimeTravel<NetworkVariableDeltaMessage>(m_ClientNetworkManagers.ToList());
Assert.AreEqual(25, testComponent.ReanticipateOnAnticipationFailVariable.Value);
// However, the authoritative value still gets updated
Assert.AreEqual(20, testComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
// Other client got the server value and had made no anticipation, so it applies it to the anticipated value as well.
var otherClientComponent = GetOtherClientComponent();
Assert.AreEqual(25, otherClientComponent.ReanticipateOnAnticipationFailVariable.Value);
Assert.AreEqual(20, otherClientComponent.ReanticipateOnAnticipationFailVariable.AuthoritativeValue);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 74e627a9d18dcd04e9c56ab2539a6593

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7d01969a8bbbd7146a24490a5190ea7e

View File

@@ -0,0 +1,165 @@
#if !NGO_MINIMALPROJECT
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests
{
[TestFixtureSource(nameof(TestDataSource))]
internal class NetworkVariableInheritanceTests : NetcodeIntegrationTest
{
public NetworkVariableInheritanceTests(HostOrServer hostOrServer)
: base(hostOrServer)
{
}
protected override int NumberOfClients => 2;
public static IEnumerable<TestFixtureData> TestDataSource() =>
Enum.GetValues(typeof(HostOrServer)).OfType<HostOrServer>().Select(x => new TestFixtureData(x));
internal class ComponentA : NetworkBehaviour
{
public NetworkVariable<int> PublicFieldA = new NetworkVariable<int>(1);
protected NetworkVariable<int> m_ProtectedFieldA = new NetworkVariable<int>(2);
private NetworkVariable<int> m_PrivateFieldA = new NetworkVariable<int>(3);
public void ChangeValuesA(int pub, int pro, int pri)
{
PublicFieldA.Value = pub;
m_ProtectedFieldA.Value = pro;
m_PrivateFieldA.Value = pri;
}
public bool CompareValuesA(ComponentA other)
{
return PublicFieldA.Value == other.PublicFieldA.Value &&
m_ProtectedFieldA.Value == other.m_ProtectedFieldA.Value &&
m_PrivateFieldA.Value == other.m_PrivateFieldA.Value;
}
}
internal class ComponentB : ComponentA
{
public NetworkVariable<int> PublicFieldB = new NetworkVariable<int>(11);
protected NetworkVariable<int> m_ProtectedFieldB = new NetworkVariable<int>(22);
private NetworkVariable<int> m_PrivateFieldB = new NetworkVariable<int>(33);
public void ChangeValuesB(int pub, int pro, int pri)
{
PublicFieldB.Value = pub;
m_ProtectedFieldB.Value = pro;
m_PrivateFieldB.Value = pri;
}
public bool CompareValuesB(ComponentB other)
{
return PublicFieldB.Value == other.PublicFieldB.Value &&
m_ProtectedFieldB.Value == other.m_ProtectedFieldB.Value &&
m_PrivateFieldB.Value == other.m_PrivateFieldB.Value;
}
}
internal class ComponentC : ComponentB
{
public NetworkVariable<int> PublicFieldC = new NetworkVariable<int>(111);
protected NetworkVariable<int> m_ProtectedFieldC = new NetworkVariable<int>(222);
private NetworkVariable<int> m_PrivateFieldC = new NetworkVariable<int>(333);
public void ChangeValuesC(int pub, int pro, int pri)
{
PublicFieldC.Value = pub;
m_ProtectedFieldA.Value = pro;
m_PrivateFieldC.Value = pri;
}
public bool CompareValuesC(ComponentC other)
{
return PublicFieldC.Value == other.PublicFieldC.Value &&
m_ProtectedFieldC.Value == other.m_ProtectedFieldC.Value &&
m_PrivateFieldC.Value == other.m_PrivateFieldC.Value;
}
}
private GameObject m_TestObjectPrefab;
private ulong m_TestObjectId = 0;
protected override void OnOneTimeSetup()
{
NetworkVariableBase.IgnoreInitializeWarning = true;
base.OnOneTimeSetup();
}
protected override void OnOneTimeTearDown()
{
NetworkVariableBase.IgnoreInitializeWarning = false;
base.OnOneTimeTearDown();
}
protected override void OnServerAndClientsCreated()
{
m_TestObjectPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableInheritanceTests)}.{nameof(m_TestObjectPrefab)}]");
m_TestObjectPrefab.AddComponent<ComponentA>();
m_TestObjectPrefab.AddComponent<ComponentB>();
m_TestObjectPrefab.AddComponent<ComponentC>();
}
protected override IEnumerator OnServerAndClientsConnected()
{
var serverTestObject = SpawnObject(m_TestObjectPrefab, m_ServerNetworkManager).GetComponent<NetworkObject>();
m_TestObjectId = serverTestObject.NetworkObjectId;
var serverTestComponentA = serverTestObject.GetComponent<ComponentA>();
var serverTestComponentB = serverTestObject.GetComponent<ComponentB>();
var serverTestComponentC = serverTestObject.GetComponent<ComponentC>();
serverTestComponentA.ChangeValuesA(1000, 2000, 3000);
serverTestComponentB.ChangeValuesA(1000, 2000, 3000);
serverTestComponentB.ChangeValuesB(1100, 2200, 3300);
serverTestComponentC.ChangeValuesA(1000, 2000, 3000);
serverTestComponentC.ChangeValuesB(1100, 2200, 3300);
serverTestComponentC.ChangeValuesC(1110, 2220, 3330);
yield return WaitForTicks(m_ServerNetworkManager, 2);
}
private bool CheckTestObjectComponentValuesOnAll()
{
var serverTestObject = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjectId];
var serverTestComponentA = serverTestObject.GetComponent<ComponentA>();
var serverTestComponentB = serverTestObject.GetComponent<ComponentB>();
var serverTestComponentC = serverTestObject.GetComponent<ComponentC>();
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
var clientTestObject = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjectId];
var clientTestComponentA = clientTestObject.GetComponent<ComponentA>();
var clientTestComponentB = clientTestObject.GetComponent<ComponentB>();
var clientTestComponentC = clientTestObject.GetComponent<ComponentC>();
if (!serverTestComponentA.CompareValuesA(clientTestComponentA) ||
!serverTestComponentB.CompareValuesA(clientTestComponentB) ||
!serverTestComponentB.CompareValuesB(clientTestComponentB) ||
!serverTestComponentC.CompareValuesA(clientTestComponentC) ||
!serverTestComponentC.CompareValuesB(clientTestComponentC) ||
!serverTestComponentC.CompareValuesC(clientTestComponentC))
{
return false;
}
}
return true;
}
[UnityTest]
public IEnumerator TestInheritedFields()
{
yield return WaitForConditionOrTimeOut(CheckTestObjectComponentValuesOnAll);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut, nameof(CheckTestObjectComponentValuesOnAll));
}
}
}
#endif

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 41d4aef8f33a8eb4e87879075f868e66

View File

@@ -0,0 +1,306 @@
#if !NGO_MINIMALPROJECT
using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using UnityEngine.TestTools;
using Random = UnityEngine.Random;
namespace Unity.Netcode.RuntimeTests
{
[TestFixtureSource(nameof(TestDataSource))]
internal class NetworkVariablePermissionTests : NetcodeIntegrationTest
{
public static IEnumerable<TestFixtureData> TestDataSource()
{
NetworkVariableBase.IgnoreInitializeWarning = true;
foreach (HostOrServer hostOrServer in Enum.GetValues(typeof(HostOrServer)))
{
// DANGO-EXP TODO: Add support for distributed authority mode
if (hostOrServer == HostOrServer.DAHost)
{
continue;
}
yield return new TestFixtureData(hostOrServer);
}
NetworkVariableBase.IgnoreInitializeWarning = false;
}
protected override int NumberOfClients => 3;
public NetworkVariablePermissionTests(HostOrServer hostOrServer) : base(hostOrServer) { }
private GameObject m_TestObjPrefab;
private ulong m_TestObjId = 0;
protected override void OnServerAndClientsCreated()
{
m_TestObjPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariablePermissionTests)}.{nameof(m_TestObjPrefab)}]");
var testComp = m_TestObjPrefab.AddComponent<NetVarPermTestComp>();
}
protected override IEnumerator OnServerAndClientsConnected()
{
m_TestObjId = SpawnObject(m_TestObjPrefab, m_ServerNetworkManager).GetComponent<NetworkObject>().NetworkObjectId;
yield return null;
}
private IEnumerator WaitForPositionsAreEqual(NetworkVariable<Vector3> netvar, Vector3 expected)
{
yield return WaitForConditionOrTimeOut(() => netvar.Value == expected);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut);
}
private IEnumerator WaitForOwnerWritableAreEqualOnAll()
{
yield return WaitForConditionOrTimeOut(CheckOwnerWritableAreEqualOnAll);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut);
}
private bool CheckOwnerWritableAreEqualOnAll()
{
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
var testObjClient = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
if (testObjServer.OwnerClientId != testObjClient.OwnerClientId ||
testCompServer.OwnerWritable_Position.Value != testCompClient.OwnerWritable_Position.Value ||
testCompServer.OwnerWritable_Position.ReadPerm != testCompClient.OwnerWritable_Position.ReadPerm ||
testCompServer.OwnerWritable_Position.WritePerm != testCompClient.OwnerWritable_Position.WritePerm)
{
return false;
}
}
return true;
}
private IEnumerator WaitForServerWritableAreEqualOnAll()
{
yield return WaitForConditionOrTimeOut(CheckServerWritableAreEqualOnAll);
Assert.IsFalse(s_GlobalTimeoutHelper.TimedOut);
}
private bool CheckServerWritableAreEqualOnAll()
{
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
var testObjClient = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
if (testCompServer.ServerWritable_Position.Value != testCompClient.ServerWritable_Position.Value ||
testCompServer.ServerWritable_Position.ReadPerm != testCompClient.ServerWritable_Position.ReadPerm ||
testCompServer.ServerWritable_Position.WritePerm != testCompClient.ServerWritable_Position.WritePerm)
{
return false;
}
}
return true;
}
private bool CheckOwnerReadWriteAreEqualOnOwnerAndServer()
{
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
var testObjClient = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
if (testObjServer.OwnerClientId == testObjClient.OwnerClientId &&
testCompServer.OwnerReadWrite_Position.Value == testCompClient.ServerWritable_Position.Value &&
testCompServer.OwnerReadWrite_Position.ReadPerm == testCompClient.ServerWritable_Position.ReadPerm &&
testCompServer.OwnerReadWrite_Position.WritePerm == testCompClient.ServerWritable_Position.WritePerm)
{
return true;
}
}
return false;
}
private bool CheckOwnerReadWriteAreNotEqualOnNonOwnerClients(NetVarPermTestComp ownerReadWriteObject)
{
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
var testObjClient = clientNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
if (testObjClient.OwnerClientId != ownerReadWriteObject.OwnerClientId ||
ownerReadWriteObject.OwnerReadWrite_Position.Value == testCompClient.ServerWritable_Position.Value ||
ownerReadWriteObject.OwnerReadWrite_Position.ReadPerm != testCompClient.ServerWritable_Position.ReadPerm ||
ownerReadWriteObject.OwnerReadWrite_Position.WritePerm != testCompClient.ServerWritable_Position.WritePerm)
{
return false;
}
}
return true;
}
[UnityTest]
public IEnumerator ServerChangesOwnerWritableNetVar()
{
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
var oldValue = testCompServer.OwnerWritable_Position.Value;
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
testCompServer.OwnerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompServer.OwnerWritable_Position, newValue);
yield return WaitForOwnerWritableAreEqualOnAll();
}
[UnityTest]
public IEnumerator ServerChangesServerWritableNetVar()
{
yield return WaitForServerWritableAreEqualOnAll();
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
var oldValue = testCompServer.ServerWritable_Position.Value;
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
testCompServer.ServerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompServer.ServerWritable_Position, newValue);
yield return WaitForServerWritableAreEqualOnAll();
}
[UnityTest]
public IEnumerator ClientChangesOwnerWritableNetVar()
{
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjClient = m_ClientNetworkManagers[clientManagerIndex].SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
var oldValue = testCompClient.OwnerWritable_Position.Value;
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
testCompClient.OwnerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompClient.OwnerWritable_Position, newValue);
yield return WaitForOwnerWritableAreEqualOnAll();
}
/// <summary>
/// This tests the scenario where a client owner has both read and write
/// permissions set. The server should be the only instance that can read
/// the NetworkVariable. ServerCannotChangeOwnerWritableNetVar performs
/// the same check to make sure the server cannot write to a client owner
/// NetworkVariable with owner write permissions.
/// </summary>
[UnityTest]
public IEnumerator ClientOwnerWithReadWriteChangesNetVar()
{
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjClient = m_ClientNetworkManagers[clientManagerIndex].SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
var oldValue = testCompClient.OwnerReadWrite_Position.Value;
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
testCompClient.OwnerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompClient.OwnerWritable_Position, newValue);
// Verify the client owner and server match
yield return CheckOwnerReadWriteAreEqualOnOwnerAndServer();
// Verify the non-owner clients do not have the same Value but do have the same permissions
yield return CheckOwnerReadWriteAreNotEqualOnNonOwnerClients(testCompClient);
}
[UnityTest]
public IEnumerator ClientCannotChangeServerWritableNetVar()
{
yield return WaitForServerWritableAreEqualOnAll();
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return WaitForTicks(m_ServerNetworkManager, 2);
yield return WaitForServerWritableAreEqualOnAll();
var testObjClient = m_ClientNetworkManagers[clientManagerIndex].SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
var oldValue = testCompClient.ServerWritable_Position.Value;
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
LogAssert.Expect(LogType.Error, testCompClient.ServerWritable_Position.GetWritePermissionError());
testCompClient.ServerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompServer.ServerWritable_Position, oldValue);
yield return WaitForServerWritableAreEqualOnAll();
testCompServer.ServerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompServer.ServerWritable_Position, newValue);
yield return WaitForServerWritableAreEqualOnAll();
}
[UnityTest]
public IEnumerator ServerCannotChangeOwnerWritableNetVar()
{
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjServer = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_TestObjId];
var testCompServer = testObjServer.GetComponent<NetVarPermTestComp>();
int clientManagerIndex = m_ClientNetworkManagers.Length - 1;
var newOwnerClientId = m_ClientNetworkManagers[clientManagerIndex].LocalClientId;
testObjServer.ChangeOwnership(newOwnerClientId);
yield return WaitForTicks(m_ServerNetworkManager, 4);
yield return WaitForOwnerWritableAreEqualOnAll();
var oldValue = testCompServer.OwnerWritable_Position.Value;
var newValue = oldValue + new Vector3(Random.Range(0, 100.0f), Random.Range(0, 100.0f), Random.Range(0, 100.0f));
LogAssert.Expect(LogType.Error, testCompServer.OwnerWritable_Position.GetWritePermissionError());
testCompServer.OwnerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompServer.OwnerWritable_Position, oldValue);
yield return WaitForOwnerWritableAreEqualOnAll();
var testObjClient = m_ClientNetworkManagers[clientManagerIndex].SpawnManager.SpawnedObjects[m_TestObjId];
var testCompClient = testObjClient.GetComponent<NetVarPermTestComp>();
testCompClient.OwnerWritable_Position.Value = newValue;
yield return WaitForPositionsAreEqual(testCompClient.OwnerWritable_Position, newValue);
yield return WaitForOwnerWritableAreEqualOnAll();
}
}
}
#endif

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 60d49d322bef8ff4ebb8c4abf57e18e3

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d271d8738dbbb5e4aa0cae91b663f183
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,937 @@
using System;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
namespace Unity.Netcode.RuntimeTests
{
internal class NetVarPermTestComp : NetworkBehaviour
{
public NetworkVariable<Vector3> OwnerWritable_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableBase.DefaultReadPerm, NetworkVariableWritePermission.Owner);
public NetworkVariable<Vector3> ServerWritable_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableBase.DefaultReadPerm, NetworkVariableWritePermission.Server);
public NetworkVariable<Vector3> OwnerReadWrite_Position = new NetworkVariable<Vector3>(Vector3.one, NetworkVariableReadPermission.Owner, NetworkVariableWritePermission.Owner);
}
internal class NetworkVariableMiddleclass<TMiddleclassName> : NetworkVariable<TMiddleclassName>
{
}
internal class NetworkVariableSubclass<TSubclassName> : NetworkVariableMiddleclass<TSubclassName>
{
}
internal class NetworkBehaviourWithNetVarArray : NetworkBehaviour
{
public NetworkVariable<int> Int0 = new NetworkVariable<int>();
public NetworkVariable<int> Int1 = new NetworkVariable<int>();
public NetworkVariable<int> Int2 = new NetworkVariable<int>();
public NetworkVariable<int> Int3 = new NetworkVariable<int>();
public NetworkVariable<int> Int4 = new NetworkVariable<int>();
public NetworkVariable<int>[] AllInts = new NetworkVariable<int>[5];
public int InitializedFieldCount => NetworkVariableFields.Count;
private void Awake()
{
AllInts[0] = Int0;
AllInts[1] = Int1;
AllInts[2] = Int2;
AllInts[3] = Int3;
AllInts[4] = Int4;
}
}
internal struct TypeReferencedOnlyInCustomSerialization1 : INetworkSerializeByMemcpy
{
public int I;
}
internal struct TypeReferencedOnlyInCustomSerialization2 : INetworkSerializeByMemcpy
{
public int I;
}
internal struct TypeReferencedOnlyInCustomSerialization3 : INetworkSerializeByMemcpy
{
public int I;
}
internal struct TypeReferencedOnlyInCustomSerialization4 : INetworkSerializeByMemcpy
{
public int I;
}
internal struct TypeReferencedOnlyInCustomSerialization5 : INetworkSerializeByMemcpy
{
public int I;
}
internal struct TypeReferencedOnlyInCustomSerialization6 : INetworkSerializeByMemcpy
{
public int I;
}
// Both T and U are serializable
[GenerateSerializationForGenericParameter(0)]
[GenerateSerializationForGenericParameter(1)]
internal class CustomSerializableClass<TSerializableType1, TSerializableType2>
{
}
// Only U is serializable
[GenerateSerializationForGenericParameter(1)]
internal class CustomSerializableBaseClass<TUnserializableType, TSerializableType>
{
}
// T is serializable, passes TypeReferencedOnlyInCustomSerialization3 as U to the subclass, making it serializable
[GenerateSerializationForGenericParameter(0)]
internal class CustomSerializableSubclass<TSerializableType> : CustomSerializableBaseClass<TSerializableType, TypeReferencedOnlyInCustomSerialization3>
{
}
// T is serializable, passes TypeReferencedOnlyInCustomSerialization3 as U to the subclass, making it serializable
[GenerateSerializationForGenericParameter(0)]
internal class CustomSerializableSubclassWithNativeArray<TSerializableType> : CustomSerializableBaseClass<TSerializableType, NativeArray<TypeReferencedOnlyInCustomSerialization3>>
{
}
internal class CustomGenericSerializationTestBehaviour : NetworkBehaviour
{
public CustomSerializableClass<TypeReferencedOnlyInCustomSerialization1, TypeReferencedOnlyInCustomSerialization2> Value1;
public CustomSerializableClass<NativeArray<TypeReferencedOnlyInCustomSerialization1>, NativeArray<TypeReferencedOnlyInCustomSerialization2>> Value2;
public CustomSerializableSubclass<TypeReferencedOnlyInCustomSerialization4> Value3;
public CustomSerializableSubclassWithNativeArray<NativeArray<TypeReferencedOnlyInCustomSerialization4>> Value4;
}
[GenerateSerializationForType(typeof(TypeReferencedOnlyInCustomSerialization5))]
[GenerateSerializationForType(typeof(NativeArray<TypeReferencedOnlyInCustomSerialization5>))]
internal struct SomeRandomStruct
{
[GenerateSerializationForType(typeof(TypeReferencedOnlyInCustomSerialization6))]
[GenerateSerializationForType(typeof(NativeArray<TypeReferencedOnlyInCustomSerialization6>))]
public void Foo()
{
}
}
internal struct TemplatedValueOnlyReferencedByNetworkVariableSubclass<T> : INetworkSerializeByMemcpy
where T : unmanaged
{
public T Value;
}
public enum ByteEnum : byte
{
A,
B,
C = byte.MaxValue
}
public enum SByteEnum : sbyte
{
A,
B,
C = sbyte.MaxValue
}
public enum ShortEnum : short
{
A,
B,
C = short.MaxValue
}
public enum UShortEnum : ushort
{
A,
B,
C = ushort.MaxValue
}
public enum IntEnum : int
{
A,
B,
C = int.MaxValue
}
public enum UIntEnum : uint
{
A,
B,
C = uint.MaxValue
}
public enum LongEnum : long
{
A,
B,
C = long.MaxValue
}
public enum ULongEnum : ulong
{
A,
B,
C = ulong.MaxValue
}
internal struct HashableNetworkVariableTestStruct : INetworkSerializeByMemcpy, IEquatable<HashableNetworkVariableTestStruct>
{
public byte A;
public short B;
public ushort C;
public int D;
public uint E;
public long F;
public ulong G;
public bool H;
public char I;
public float J;
public double K;
public bool Equals(HashableNetworkVariableTestStruct other)
{
return A == other.A && B == other.B && C == other.C && D == other.D && E == other.E && F == other.F && G == other.G && H == other.H && I == other.I && J.Equals(other.J) && K.Equals(other.K);
}
public override bool Equals(object obj)
{
return obj is HashableNetworkVariableTestStruct other && Equals(other);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
hashCode.Add(A);
hashCode.Add(B);
hashCode.Add(C);
hashCode.Add(D);
hashCode.Add(E);
hashCode.Add(F);
hashCode.Add(G);
hashCode.Add(H);
hashCode.Add(I);
hashCode.Add(J);
hashCode.Add(K);
return hashCode.ToHashCode();
}
}
internal struct HashMapKeyStruct : INetworkSerializeByMemcpy, IEquatable<HashMapKeyStruct>
{
public byte A;
public short B;
public ushort C;
public int D;
public uint E;
public long F;
public ulong G;
public bool H;
public char I;
public float J;
public double K;
public bool Equals(HashMapKeyStruct other)
{
return A == other.A && B == other.B && C == other.C && D == other.D && E == other.E && F == other.F && G == other.G && H == other.H && I == other.I && J.Equals(other.J) && K.Equals(other.K);
}
public override bool Equals(object obj)
{
return obj is HashMapKeyStruct other && Equals(other);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
hashCode.Add(A);
hashCode.Add(B);
hashCode.Add(C);
hashCode.Add(D);
hashCode.Add(E);
hashCode.Add(F);
hashCode.Add(G);
hashCode.Add(H);
hashCode.Add(I);
hashCode.Add(J);
hashCode.Add(K);
return hashCode.ToHashCode();
}
}
internal struct HashMapValStruct : INetworkSerializeByMemcpy, IEquatable<HashMapValStruct>
{
public byte A;
public short B;
public ushort C;
public int D;
public uint E;
public long F;
public ulong G;
public bool H;
public char I;
public float J;
public double K;
public bool Equals(HashMapValStruct other)
{
return A == other.A && B == other.B && C == other.C && D == other.D && E == other.E && F == other.F && G == other.G && H == other.H && I == other.I && J.Equals(other.J) && K.Equals(other.K);
}
public override bool Equals(object obj)
{
return obj is HashMapValStruct other && Equals(other);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
hashCode.Add(A);
hashCode.Add(B);
hashCode.Add(C);
hashCode.Add(D);
hashCode.Add(E);
hashCode.Add(F);
hashCode.Add(G);
hashCode.Add(H);
hashCode.Add(I);
hashCode.Add(J);
hashCode.Add(K);
return hashCode.ToHashCode();
}
}
internal struct NetworkVariableTestStruct : INetworkSerializeByMemcpy
{
public byte A;
public short B;
public ushort C;
public int D;
public uint E;
public long F;
public ulong G;
public bool H;
public char I;
public float J;
public double K;
private static System.Random s_Random = new System.Random();
public static NetworkVariableTestStruct GetTestStruct()
{
var testStruct = new NetworkVariableTestStruct
{
A = (byte)s_Random.Next(),
B = (short)s_Random.Next(),
C = (ushort)s_Random.Next(),
D = s_Random.Next(),
E = (uint)s_Random.Next(),
F = ((long)s_Random.Next() << 32) + s_Random.Next(),
G = ((ulong)s_Random.Next() << 32) + (ulong)s_Random.Next(),
H = true,
I = '\u263a',
J = (float)s_Random.NextDouble(),
K = s_Random.NextDouble(),
};
return testStruct;
}
}
internal class HashableNetworkVariableTestClass : INetworkSerializable, IEquatable<HashableNetworkVariableTestClass>
{
public HashableNetworkVariableTestStruct Data;
public bool Equals(HashableNetworkVariableTestClass other)
{
return Data.Equals(other.Data);
}
public override bool Equals(object obj)
{
return obj is HashableNetworkVariableTestClass other && Equals(other);
}
public override int GetHashCode()
{
return Data.GetHashCode();
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref Data);
}
}
internal class HashMapKeyClass : INetworkSerializable, IEquatable<HashMapKeyClass>
{
public HashMapKeyStruct Data;
public bool Equals(HashMapKeyClass other)
{
return Data.Equals(other.Data);
}
public override bool Equals(object obj)
{
return obj is HashMapKeyClass other && Equals(other);
}
public override int GetHashCode()
{
return Data.GetHashCode();
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref Data);
}
}
internal class HashMapValClass : INetworkSerializable, IEquatable<HashMapValClass>
{
public HashMapValStruct Data;
public bool Equals(HashMapValClass other)
{
return Data.Equals(other.Data);
}
public override bool Equals(object obj)
{
return obj is HashMapValClass other && Equals(other);
}
public override int GetHashCode()
{
return Data.GetHashCode();
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref Data);
}
}
internal class NetworkVariableTestClass : INetworkSerializable, IEquatable<NetworkVariableTestClass>
{
public NetworkVariableTestStruct Data;
public bool Equals(NetworkVariableTestClass other)
{
return NetworkVariableSerialization<NetworkVariableTestStruct>.AreEqual(ref Data, ref other.Data);
}
public override bool Equals(object obj)
{
return obj is NetworkVariableTestClass other && Equals(other);
}
// This type is not used for hashing, we just need to implement IEquatable to verify lists match.
public override int GetHashCode()
{
return 0;
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref Data);
}
}
// The ILPP code for NetworkVariables to determine how to serialize them relies on them existing as fields of a NetworkBehaviour to find them.
// Some of the tests below create NetworkVariables on the stack, so this class is here just to make sure the relevant types are all accounted for.
internal class NetVarILPPClassForTests : NetworkBehaviour
{
public NetworkVariable<byte> ByteVar;
public NetworkVariable<NativeArray<byte>> ByteArrayVar;
public NetworkVariable<List<byte>> ByteManagedListVar;
public NetworkVariable<HashSet<byte>> ByteManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<byte>> ByteListVar;
public NetworkVariable<NativeHashSet<byte>> ByteHashSetVar;
public NetworkVariable<NativeHashMap<byte, byte>> ByteByteHashMapVar;
public NetworkVariable<NativeHashMap<ulong, byte>> ULongByteHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, byte>> Vector2ByteHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, byte>> HashMapKeyStructByteHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, byte>> ByteByteDictionaryVar;
public NetworkVariable<Dictionary<ulong, byte>> ULongByteDictionaryVar;
public NetworkVariable<Dictionary<Vector2, byte>> Vector2ByteDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, byte>> HashMapKeyClassByteDictionaryVar;
public NetworkVariable<sbyte> SbyteVar;
public NetworkVariable<NativeArray<sbyte>> SbyteArrayVar;
public NetworkVariable<List<sbyte>> SbyteManagedListVar;
public NetworkVariable<HashSet<sbyte>> SbyteManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<sbyte>> SbyteListVar;
public NetworkVariable<NativeHashSet<sbyte>> SbyteHashSetVar;
public NetworkVariable<NativeHashMap<byte, sbyte>> ByteSbyteHashMapVar;
public NetworkVariable<NativeHashMap<ulong, sbyte>> ULongSbyteHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, sbyte>> Vector2SbyteHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, sbyte>> HashMapKeyStructSbyteHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, sbyte>> ByteSbyteDictionaryVar;
public NetworkVariable<Dictionary<ulong, sbyte>> ULongSbyteDictionaryVar;
public NetworkVariable<Dictionary<Vector2, sbyte>> Vector2SbyteDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, sbyte>> HashMapKeyClassSbyteDictionaryVar;
public NetworkVariable<short> ShortVar;
public NetworkVariable<NativeArray<short>> ShortArrayVar;
public NetworkVariable<List<short>> ShortManagedListVar;
public NetworkVariable<HashSet<short>> ShortManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<short>> ShortListVar;
public NetworkVariable<NativeHashSet<short>> ShortHashSetVar;
public NetworkVariable<NativeHashMap<byte, short>> ByteShortHashMapVar;
public NetworkVariable<NativeHashMap<ulong, short>> ULongShortHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, short>> Vector2ShortHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, short>> HashMapKeyStructShortHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, short>> ByteShortDictionaryVar;
public NetworkVariable<Dictionary<ulong, short>> ULongShortDictionaryVar;
public NetworkVariable<Dictionary<Vector2, short>> Vector2ShortDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, short>> HashMapKeyClassShortDictionaryVar;
public NetworkVariable<ushort> UshortVar;
public NetworkVariable<NativeArray<ushort>> UshortArrayVar;
public NetworkVariable<List<ushort>> UshortManagedListVar;
public NetworkVariable<HashSet<ushort>> UshortManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<ushort>> UshortListVar;
public NetworkVariable<NativeHashSet<ushort>> UshortHashSetVar;
public NetworkVariable<NativeHashMap<byte, ushort>> ByteUshortHashMapVar;
public NetworkVariable<NativeHashMap<ulong, ushort>> ULongUshortHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, ushort>> Vector2UshortHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, ushort>> HashMapKeyStructUshortHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, ushort>> ByteUshortDictionaryVar;
public NetworkVariable<Dictionary<ulong, ushort>> ULongUshortDictionaryVar;
public NetworkVariable<Dictionary<Vector2, ushort>> Vector2UshortDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, ushort>> HashMapKeyClassUshortDictionaryVar;
public NetworkVariable<int> IntVar;
public NetworkVariable<NativeArray<int>> IntArrayVar;
public NetworkVariable<List<int>> IntManagedListVar;
public NetworkVariable<HashSet<int>> IntManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<int>> IntListVar;
public NetworkVariable<NativeHashSet<int>> IntHashSetVar;
public NetworkVariable<NativeHashMap<byte, int>> ByteIntHashMapVar;
public NetworkVariable<NativeHashMap<ulong, int>> ULongIntHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, int>> Vector2IntHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, int>> HashMapKeyStructIntHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, int>> ByteIntDictionaryVar;
public NetworkVariable<Dictionary<ulong, int>> ULongIntDictionaryVar;
public NetworkVariable<Dictionary<Vector2, int>> Vector2IntDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, int>> HashMapKeyClassIntDictionaryVar;
public NetworkVariable<uint> UintVar;
public NetworkVariable<NativeArray<uint>> UintArrayVar;
public NetworkVariable<List<uint>> UintManagedListVar;
public NetworkVariable<HashSet<uint>> UintManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<uint>> UintListVar;
public NetworkVariable<NativeHashSet<uint>> UintHashSetVar;
public NetworkVariable<NativeHashMap<byte, uint>> ByteUintHashMapVar;
public NetworkVariable<NativeHashMap<ulong, uint>> ULongUintHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, uint>> Vector2UintHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, uint>> HashMapKeyStructUintHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, uint>> ByteUintDictionaryVar;
public NetworkVariable<Dictionary<ulong, uint>> ULongUintDictionaryVar;
public NetworkVariable<Dictionary<Vector2, uint>> Vector2UintDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, uint>> HashMapKeyClassUintDictionaryVar;
public NetworkVariable<long> LongVar;
public NetworkVariable<NativeArray<long>> LongArrayVar;
public NetworkVariable<List<long>> LongManagedListVar;
public NetworkVariable<HashSet<long>> LongManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<long>> LongListVar;
public NetworkVariable<NativeHashSet<long>> LongHashSetVar;
public NetworkVariable<NativeHashMap<byte, long>> ByteLongHashMapVar;
public NetworkVariable<NativeHashMap<ulong, long>> ULongLongHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, long>> Vector2LongHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, long>> HashMapKeyStructLongHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, long>> ByteLongDictionaryVar;
public NetworkVariable<Dictionary<ulong, long>> ULongLongDictionaryVar;
public NetworkVariable<Dictionary<Vector2, long>> Vector2LongDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, long>> HashMapKeyClassLongDictionaryVar;
public NetworkVariable<ulong> UlongVar;
public NetworkVariable<NativeArray<ulong>> UlongArrayVar;
public NetworkVariable<List<ulong>> UlongManagedListVar;
public NetworkVariable<HashSet<ulong>> UlongManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<ulong>> UlongListVar;
public NetworkVariable<NativeHashSet<ulong>> UlongHashSetVar;
public NetworkVariable<NativeHashMap<byte, ulong>> ByteUlongHashMapVar;
public NetworkVariable<NativeHashMap<ulong, ulong>> ULongUlongHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, ulong>> Vector2UlongHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, ulong>> HashMapKeyStructUlongHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, ulong>> ByteUlongDictionaryVar;
public NetworkVariable<Dictionary<ulong, ulong>> ULongUlongDictionaryVar;
public NetworkVariable<Dictionary<Vector2, ulong>> Vector2UlongDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, ulong>> HashMapKeyClassUlongDictionaryVar;
public NetworkVariable<bool> BoolVar;
public NetworkVariable<NativeArray<bool>> BoolArrayVar;
public NetworkVariable<List<bool>> BoolManagedListVar;
public NetworkVariable<HashSet<bool>> BoolManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<bool>> BoolListVar;
public NetworkVariable<NativeHashSet<bool>> BoolHashSetVar;
public NetworkVariable<NativeHashMap<byte, bool>> ByteBoolHashMapVar;
public NetworkVariable<NativeHashMap<ulong, bool>> ULongBoolHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, bool>> Vector2BoolHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, bool>> HashMapKeyStructBoolHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, bool>> ByteBoolDictionaryVar;
public NetworkVariable<Dictionary<ulong, bool>> ULongBoolDictionaryVar;
public NetworkVariable<Dictionary<Vector2, bool>> Vector2BoolDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, bool>> HashMapKeyClassBoolDictionaryVar;
public NetworkVariable<char> CharVar;
public NetworkVariable<NativeArray<char>> CharArrayVar;
public NetworkVariable<List<char>> CharManagedListVar;
public NetworkVariable<HashSet<char>> CharManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<char>> CharListVar;
public NetworkVariable<NativeHashSet<char>> CharHashSetVar;
public NetworkVariable<NativeHashMap<byte, char>> ByteCharHashMapVar;
public NetworkVariable<NativeHashMap<ulong, char>> ULongCharHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, char>> Vector2CharHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, char>> HashMapKeyStructCharHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, char>> ByteCharDictionaryVar;
public NetworkVariable<Dictionary<ulong, char>> ULongCharDictionaryVar;
public NetworkVariable<Dictionary<Vector2, char>> Vector2CharDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, char>> HashMapKeyClassCharDictionaryVar;
public NetworkVariable<float> FloatVar;
public NetworkVariable<NativeArray<float>> FloatArrayVar;
public NetworkVariable<List<float>> FloatManagedListVar;
public NetworkVariable<HashSet<float>> FloatManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<float>> FloatListVar;
public NetworkVariable<NativeHashSet<float>> FloatHashSetVar;
public NetworkVariable<NativeHashMap<byte, float>> ByteFloatHashMapVar;
public NetworkVariable<NativeHashMap<ulong, float>> ULongFloatHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, float>> Vector2FloatHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, float>> HashMapKeyStructFloatHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, float>> ByteFloatDictionaryVar;
public NetworkVariable<Dictionary<ulong, float>> ULongFloatDictionaryVar;
public NetworkVariable<Dictionary<Vector2, float>> Vector2FloatDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, float>> HashMapKeyClassFloatDictionaryVar;
public NetworkVariable<double> DoubleVar;
public NetworkVariable<NativeArray<double>> DoubleArrayVar;
public NetworkVariable<List<double>> DoubleManagedListVar;
public NetworkVariable<HashSet<double>> DoubleManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<double>> DoubleListVar;
public NetworkVariable<NativeHashSet<double>> DoubleHashSetVar;
public NetworkVariable<NativeHashMap<byte, double>> ByteDoubleHashMapVar;
public NetworkVariable<NativeHashMap<ulong, double>> ULongDoubleHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, double>> Vector2DoubleHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, double>> HashMapKeyStructDoubleHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, double>> ByteDoubleDictionaryVar;
public NetworkVariable<Dictionary<ulong, double>> ULongDoubleDictionaryVar;
public NetworkVariable<Dictionary<Vector2, double>> Vector2DoubleDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, double>> HashMapKeyClassDoubleDictionaryVar;
public NetworkVariable<ByteEnum> ByteEnumVar;
public NetworkVariable<NativeArray<ByteEnum>> ByteEnumArrayVar;
public NetworkVariable<List<ByteEnum>> ByteEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<ByteEnum>> ByteEnumListVar;
#endif
public NetworkVariable<SByteEnum> SByteEnumVar;
public NetworkVariable<NativeArray<SByteEnum>> SByteEnumArrayVar;
public NetworkVariable<List<SByteEnum>> SByteEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<SByteEnum>> SByteEnumListVar;
#endif
public NetworkVariable<ShortEnum> ShortEnumVar;
public NetworkVariable<NativeArray<ShortEnum>> ShortEnumArrayVar;
public NetworkVariable<List<ShortEnum>> ShortEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<ShortEnum>> ShortEnumListVar;
#endif
public NetworkVariable<UShortEnum> UShortEnumVar;
public NetworkVariable<NativeArray<UShortEnum>> UShortEnumArrayVar;
public NetworkVariable<List<UShortEnum>> UShortEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<UShortEnum>> UShortEnumListVar;
#endif
public NetworkVariable<IntEnum> IntEnumVar;
public NetworkVariable<NativeArray<IntEnum>> IntEnumArrayVar;
public NetworkVariable<List<IntEnum>> IntEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<IntEnum>> IntEnumListVar;
#endif
public NetworkVariable<UIntEnum> UIntEnumVar;
public NetworkVariable<NativeArray<UIntEnum>> UIntEnumArrayVar;
public NetworkVariable<List<UIntEnum>> UIntEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<UIntEnum>> UIntEnumListVar;
#endif
public NetworkVariable<LongEnum> LongEnumVar;
public NetworkVariable<NativeArray<LongEnum>> LongEnumArrayVar;
public NetworkVariable<List<LongEnum>> LongEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<LongEnum>> LongEnumListVar;
#endif
public NetworkVariable<ULongEnum> ULongEnumVar;
public NetworkVariable<NativeArray<ULongEnum>> ULongEnumArrayVar;
public NetworkVariable<List<ULongEnum>> ULongEnumManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<ULongEnum>> ULongEnumListVar;
#endif
public NetworkVariable<Vector2> Vector2Var;
public NetworkVariable<NativeArray<Vector2>> Vector2ArrayVar;
public NetworkVariable<List<Vector2>> Vector2ManagedListVar;
public NetworkVariable<HashSet<Vector2>> Vector2ManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Vector2>> Vector2ListVar;
public NetworkVariable<NativeHashSet<Vector2>> Vector2HashSetVar;
public NetworkVariable<NativeHashMap<byte, Vector2>> ByteVector2HashMapVar;
public NetworkVariable<NativeHashMap<ulong, Vector2>> ULongVector2HashMapVar;
public NetworkVariable<NativeHashMap<Vector2, Vector2>> Vector2Vector2HashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, Vector2>> HashMapKeyStructVector2HashMapVar;
#endif
public NetworkVariable<Dictionary<byte, Vector2>> ByteVector2DictionaryVar;
public NetworkVariable<Dictionary<ulong, Vector2>> ULongVector2DictionaryVar;
public NetworkVariable<Dictionary<Vector2, Vector2>> Vector2Vector2DictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, Vector2>> HashMapKeyClassVector2DictionaryVar;
public NetworkVariable<Vector3> Vector3Var;
public NetworkVariable<NativeArray<Vector3>> Vector3ArrayVar;
public NetworkVariable<List<Vector3>> Vector3ManagedListVar;
public NetworkVariable<HashSet<Vector3>> Vector3ManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Vector3>> Vector3ListVar;
public NetworkVariable<NativeHashSet<Vector3>> Vector3HashSetVar;
public NetworkVariable<NativeHashMap<byte, Vector3>> ByteVector3HashMapVar;
public NetworkVariable<NativeHashMap<ulong, Vector3>> ULongVector3HashMapVar;
public NetworkVariable<NativeHashMap<Vector2, Vector3>> Vector2Vector3HashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, Vector3>> HashMapKeyStructVector3HashMapVar;
#endif
public NetworkVariable<Dictionary<byte, Vector3>> ByteVector3DictionaryVar;
public NetworkVariable<Dictionary<ulong, Vector3>> ULongVector3DictionaryVar;
public NetworkVariable<Dictionary<Vector2, Vector3>> Vector2Vector3DictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, Vector3>> HashMapKeyClassVector3DictionaryVar;
public NetworkVariable<Vector2Int> Vector2IntVar;
public NetworkVariable<NativeArray<Vector2Int>> Vector2IntArrayVar;
public NetworkVariable<List<Vector2Int>> Vector2IntManagedListVar;
public NetworkVariable<HashSet<Vector2Int>> Vector2IntManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Vector2Int>> Vector2IntListVar;
public NetworkVariable<NativeHashSet<Vector2Int>> Vector2IntHashSetVar;
public NetworkVariable<NativeHashMap<byte, Vector2Int>> ByteVector2IntHashMapVar;
public NetworkVariable<NativeHashMap<ulong, Vector2Int>> ULongVector2IntHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, Vector2Int>> Vector2Vector2IntHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, Vector2Int>> HashMapKeyStructVector2IntHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, Vector2Int>> ByteVector2IntDictionaryVar;
public NetworkVariable<Dictionary<ulong, Vector2Int>> ULongVector2IntDictionaryVar;
public NetworkVariable<Dictionary<Vector2, Vector2Int>> Vector2Vector2IntDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, Vector2Int>> HashMapKeyClassVector2IntDictionaryVar;
public NetworkVariable<Vector3Int> Vector3IntVar;
public NetworkVariable<NativeArray<Vector3Int>> Vector3IntArrayVar;
public NetworkVariable<List<Vector3Int>> Vector3IntManagedListVar;
public NetworkVariable<HashSet<Vector3Int>> Vector3IntManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Vector3Int>> Vector3IntListVar;
public NetworkVariable<NativeHashSet<Vector3Int>> Vector3IntHashSetVar;
public NetworkVariable<NativeHashMap<byte, Vector3Int>> ByteVector3IntHashMapVar;
public NetworkVariable<NativeHashMap<ulong, Vector3Int>> ULongVector3IntHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, Vector3Int>> Vector2Vector3IntHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, Vector3Int>> HashMapKeyStructVector3IntHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, Vector3Int>> ByteVector3IntDictionaryVar;
public NetworkVariable<Dictionary<ulong, Vector3Int>> ULongVector3IntDictionaryVar;
public NetworkVariable<Dictionary<Vector2, Vector3Int>> Vector2Vector3IntDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, Vector3Int>> HashMapKeyClassVector3IntDictionaryVar;
public NetworkVariable<Vector4> Vector4Var;
public NetworkVariable<NativeArray<Vector4>> Vector4ArrayVar;
public NetworkVariable<List<Vector4>> Vector4ManagedListVar;
public NetworkVariable<HashSet<Vector4>> Vector4ManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Vector4>> Vector4ListVar;
public NetworkVariable<NativeHashSet<Vector4>> Vector4HashSetVar;
public NetworkVariable<NativeHashMap<byte, Vector4>> ByteVector4HashMapVar;
public NetworkVariable<NativeHashMap<ulong, Vector4>> ULongVector4HashMapVar;
public NetworkVariable<NativeHashMap<Vector2, Vector4>> Vector2Vector4HashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, Vector4>> HashMapKeyStructVector4HashMapVar;
#endif
public NetworkVariable<Dictionary<byte, Vector4>> ByteVector4DictionaryVar;
public NetworkVariable<Dictionary<ulong, Vector4>> ULongVector4DictionaryVar;
public NetworkVariable<Dictionary<Vector2, Vector4>> Vector2Vector4DictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, Vector4>> HashMapKeyClassVector4DictionaryVar;
public NetworkVariable<Quaternion> QuaternionVar;
public NetworkVariable<NativeArray<Quaternion>> QuaternionArrayVar;
public NetworkVariable<List<Quaternion>> QuaternionManagedListVar;
public NetworkVariable<HashSet<Quaternion>> QuaternionManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Quaternion>> QuaternionListVar;
public NetworkVariable<NativeHashSet<Quaternion>> QuaternionHashSetVar;
public NetworkVariable<NativeHashMap<byte, Quaternion>> ByteQuaternionHashMapVar;
public NetworkVariable<NativeHashMap<ulong, Quaternion>> ULongQuaternionHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, Quaternion>> Vector2QuaternionHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, Quaternion>> HashMapKeyStructQuaternionHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, Quaternion>> ByteQuaternionDictionaryVar;
public NetworkVariable<Dictionary<ulong, Quaternion>> ULongQuaternionDictionaryVar;
public NetworkVariable<Dictionary<Vector2, Quaternion>> Vector2QuaternionDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, Quaternion>> HashMapKeyClassQuaternionDictionaryVar;
public NetworkVariable<Color> ColorVar;
public NetworkVariable<NativeArray<Color>> ColorArrayVar;
public NetworkVariable<List<Color>> ColorManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Color>> ColorListVar;
#endif
public NetworkVariable<Color32> Color32Var;
public NetworkVariable<NativeArray<Color32>> Color32ArrayVar;
public NetworkVariable<List<Color32>> Color32ManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Color32>> Color32ListVar;
#endif
public NetworkVariable<Ray> RayVar;
public NetworkVariable<NativeArray<Ray>> RayArrayVar;
public NetworkVariable<List<Ray>> RayManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Ray>> RayListVar;
#endif
public NetworkVariable<Ray2D> Ray2DVar;
public NetworkVariable<NativeArray<Ray2D>> Ray2DArrayVar;
public NetworkVariable<List<Ray2D>> Ray2DManagedListVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<Ray2D>> Ray2DListVar;
#endif
public NetworkVariable<NetworkVariableTestStruct> TestStructVar;
public NetworkVariable<NativeArray<NetworkVariableTestStruct>> TestStructArrayVar;
public NetworkVariable<List<NetworkVariableTestClass>> TestStructManagedListVar;
public NetworkVariable<HashSet<HashableNetworkVariableTestClass>> TestStructManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<NetworkVariableTestStruct>> TestStructListVar;
public NetworkVariable<NativeHashSet<HashableNetworkVariableTestStruct>> TestStructHashSetVar;
public NetworkVariable<NativeHashMap<byte, HashMapValStruct>> ByteTestStructHashMapVar;
public NetworkVariable<NativeHashMap<ulong, HashMapValStruct>> ULongTestStructHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, HashMapValStruct>> Vector2TestStructHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, HashMapValStruct>> HashMapKeyStructTestStructHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, HashMapValClass>> ByteTestStructDictionaryVar;
public NetworkVariable<Dictionary<ulong, HashMapValClass>> ULongTestStructDictionaryVar;
public NetworkVariable<Dictionary<Vector2, HashMapValClass>> Vector2TestStructDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, HashMapValClass>> HashMapKeyClassTestStructDictionaryVar;
public NetworkVariable<FixedString32Bytes> FixedStringVar;
public NetworkVariable<NativeArray<FixedString32Bytes>> FixedStringArrayVar;
public NetworkVariable<List<FixedString32Bytes>> FixedStringManagedListVar;
public NetworkVariable<HashSet<FixedString32Bytes>> FixedStringManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<FixedString32Bytes>> FixedStringListVar;
public NetworkVariable<NativeHashSet<FixedString32Bytes>> FixedStringHashSetVar;
public NetworkVariable<NativeHashMap<byte, FixedString32Bytes>> ByteFixedStringHashMapVar;
public NetworkVariable<NativeHashMap<ulong, FixedString32Bytes>> ULongFixedStringHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, FixedString32Bytes>> Vector2FixedStringHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, FixedString32Bytes>> HashMapKeyStructFixedStringHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, FixedString32Bytes>> ByteFixedStringDictionaryVar;
public NetworkVariable<Dictionary<ulong, FixedString32Bytes>> ULongFixedStringDictionaryVar;
public NetworkVariable<Dictionary<Vector2, FixedString32Bytes>> Vector2FixedStringDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, FixedString32Bytes>> HashMapKeyClassFixedStringDictionaryVar;
public NetworkVariable<UnmanagedNetworkSerializableType> UnmanagedNetworkSerializableTypeVar;
public NetworkVariable<HashSet<UnmanagedNetworkSerializableType>> UnmanagedNetworkSerializableManagedHashSetVar;
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
public NetworkVariable<NativeList<UnmanagedNetworkSerializableType>> UnmanagedNetworkSerializableListVar;
public NetworkVariable<NativeHashSet<UnmanagedNetworkSerializableType>> UnmanagedNetworkSerializableHashSetVar;
public NetworkVariable<NativeHashMap<byte, UnmanagedNetworkSerializableType>> ByteUnmanagedNetworkSerializableHashMapVar;
public NetworkVariable<NativeHashMap<ulong, UnmanagedNetworkSerializableType>> ULongUnmanagedNetworkSerializableHashMapVar;
public NetworkVariable<NativeHashMap<Vector2, UnmanagedNetworkSerializableType>> Vector2UnmanagedNetworkSerializableHashMapVar;
public NetworkVariable<NativeHashMap<HashMapKeyStruct, UnmanagedNetworkSerializableType>> HashMapKeyStructUnmanagedNetworkSerializableHashMapVar;
#endif
public NetworkVariable<Dictionary<byte, UnmanagedNetworkSerializableType>> ByteUnmanagedNetworkSerializableDictionaryVar;
public NetworkVariable<Dictionary<ulong, UnmanagedNetworkSerializableType>> ULongUnmanagedNetworkSerializableDictionaryVar;
public NetworkVariable<Dictionary<Vector2, UnmanagedNetworkSerializableType>> Vector2UnmanagedNetworkSerializableDictionaryVar;
public NetworkVariable<Dictionary<HashMapKeyClass, UnmanagedNetworkSerializableType>> HashMapKeyClassUnmanagedNetworkSerializableDictionaryVar;
public NetworkVariable<NativeArray<UnmanagedNetworkSerializableType>> UnmanagedNetworkSerializableArrayVar;
public NetworkVariable<List<UnmanagedNetworkSerializableType>> UnmanagedNetworkSerializableManagedListVar;
public NetworkVariable<ManagedNetworkSerializableType> ManagedNetworkSerializableTypeVar;
public NetworkVariable<string> StringVar;
public NetworkVariable<Guid> GuidVar;
public NetworkVariableSubclass<TemplatedValueOnlyReferencedByNetworkVariableSubclass<int>> SubclassVar;
}
internal class TemplateNetworkBehaviourType<T> : NetworkBehaviour
{
public NetworkVariable<T> TheVar;
}
internal class IntermediateNetworkBehavior<T> : TemplateNetworkBehaviourType<T>
{
public NetworkVariable<T> TheVar2;
}
#if !NGO_MINIMALPROJECT
internal class ClassHavingNetworkBehaviour : IntermediateNetworkBehavior<TestClass>
{
}
// Please do not reference TestClass_ReferencedOnlyByTemplateNetworkBehavourType anywhere other than here!
internal class ClassHavingNetworkBehaviour2 : TemplateNetworkBehaviourType<TestClass_ReferencedOnlyByTemplateNetworkBehaviourType>
{
}
internal class StructHavingNetworkBehaviour : TemplateNetworkBehaviourType<TestStruct>
{
}
#endif
internal struct StructUsedOnlyInNetworkList : IEquatable<StructUsedOnlyInNetworkList>, INetworkSerializeByMemcpy
{
public int Value;
public bool Equals(StructUsedOnlyInNetworkList other)
{
return Value == other.Value;
}
public override bool Equals(object obj)
{
return obj is StructUsedOnlyInNetworkList other && Equals(other);
}
public override int GetHashCode()
{
return Value;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a580aaafc247486193f372174a99fae4
timeCreated: 1705098783

View File

@@ -0,0 +1,138 @@
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
internal class NetworkVariableTraitsComponent : NetworkBehaviour
{
public NetworkVariable<float> TheVariable = new NetworkVariable<float>();
}
internal class NetworkVariableTraitsTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 2;
protected override bool m_EnableTimeTravel => true;
protected override bool m_SetupIsACoroutine => false;
protected override bool m_TearDownIsACoroutine => false;
protected override void OnPlayerPrefabGameObjectCreated()
{
m_PlayerPrefab.AddComponent<NetworkVariableTraitsComponent>();
}
public NetworkVariableTraitsComponent GetTestComponent()
{
return m_ClientNetworkManagers[0].LocalClient.PlayerObject.GetComponent<NetworkVariableTraitsComponent>();
}
public NetworkVariableTraitsComponent GetServerComponent()
{
foreach (var obj in Object.FindObjectsByType<NetworkVariableTraitsComponent>(FindObjectsSortMode.None))
{
if (obj.NetworkManager == m_ServerNetworkManager && obj.OwnerClientId == m_ClientNetworkManagers[0].LocalClientId)
{
return obj;
}
}
return null;
}
[Test]
public void WhenNewValueIsLessThanThreshold_VariableIsNotSerialized()
{
var serverComponent = GetServerComponent();
var testComponent = GetTestComponent();
serverComponent.TheVariable.CheckExceedsDirtinessThreshold = (in float value, in float newValue) => Mathf.Abs(newValue - value) >= 0.1;
serverComponent.TheVariable.Value = 0.05f;
TimeTravel(2, 120);
Assert.AreEqual(0.05f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0, testComponent.TheVariable.Value); ;
}
[Test]
public void WhenNewValueIsGreaterThanThreshold_VariableIsSerialized()
{
var serverComponent = GetServerComponent();
var testComponent = GetTestComponent();
serverComponent.TheVariable.CheckExceedsDirtinessThreshold = (in float value, in float newValue) => Mathf.Abs(newValue - value) >= 0.1;
serverComponent.TheVariable.Value = 0.15f;
TimeTravel(2, 120);
Assert.AreEqual(0.15f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0.15f, testComponent.TheVariable.Value); ;
}
[Test]
public void WhenNewValueIsLessThanThresholdButMaxTimeHasPassed_VariableIsSerialized()
{
var serverComponent = GetServerComponent();
var testComponent = GetTestComponent();
serverComponent.TheVariable.CheckExceedsDirtinessThreshold = (in float value, in float newValue) => Mathf.Abs(newValue - value) >= 0.1;
serverComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MaxSecondsBetweenUpdates = 2 });
serverComponent.TheVariable.LastUpdateSent = m_ServerNetworkManager.NetworkTimeSystem.LocalTime;
serverComponent.TheVariable.Value = 0.05f;
TimeTravel(1 / 60f * 119, 119);
Assert.AreEqual(0.05f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0, testComponent.TheVariable.Value); ;
TimeTravel(1 / 60f * 4, 4);
Assert.AreEqual(0.05f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0.05f, testComponent.TheVariable.Value); ;
}
[Test]
public void WhenNewValueIsGreaterThanThresholdButMinTimeHasNotPassed_VariableIsNotSerialized()
{
var serverComponent = GetServerComponent();
var testComponent = GetTestComponent();
serverComponent.TheVariable.CheckExceedsDirtinessThreshold = (in float value, in float newValue) => Mathf.Abs(newValue - value) >= 0.1;
serverComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MinSecondsBetweenUpdates = 2 });
serverComponent.TheVariable.LastUpdateSent = m_ServerNetworkManager.NetworkTimeSystem.LocalTime;
serverComponent.TheVariable.Value = 0.15f;
TimeTravel(1 / 60f * 119, 119);
Assert.AreEqual(0.15f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0, testComponent.TheVariable.Value); ;
TimeTravel(1 / 60f * 4, 4);
Assert.AreEqual(0.15f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0.15f, testComponent.TheVariable.Value); ;
}
[Test]
public void WhenNoThresholdIsSetButMinTimeHasNotPassed_VariableIsNotSerialized()
{
var serverComponent = GetServerComponent();
var testComponent = GetTestComponent();
serverComponent.TheVariable.SetUpdateTraits(new NetworkVariableUpdateTraits { MinSecondsBetweenUpdates = 2 });
serverComponent.TheVariable.LastUpdateSent = m_ServerNetworkManager.NetworkTimeSystem.LocalTime;
serverComponent.TheVariable.Value = 0.15f;
TimeTravel(1 / 60f * 119, 119);
Assert.AreEqual(0.15f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0, testComponent.TheVariable.Value); ;
TimeTravel(1 / 60f * 4, 4);
Assert.AreEqual(0.15f, serverComponent.TheVariable.Value); ;
Assert.AreEqual(0.15f, testComponent.TheVariable.Value); ;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 49f46ca2b4327464498a7465891647bb

View File

@@ -0,0 +1,263 @@
using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;
namespace Unity.Netcode.RuntimeTests
{
internal struct MyTypeOne
{
public int Value;
}
internal struct MyTypeTwo
{
public int Value;
}
internal struct MyTypeThree
{
public int Value;
}
/// <summary>
/// Used to help track instances of any child derived class
/// </summary>
internal class WorkingUserNetworkVariableComponentBase : NetworkBehaviour
{
private static Dictionary<ulong, WorkingUserNetworkVariableComponentBase> s_Instances = new Dictionary<ulong, WorkingUserNetworkVariableComponentBase>();
internal static T GetRelativeInstance<T>(ulong clientId) where T : NetworkBehaviour
{
if (s_Instances.ContainsKey(clientId))
{
return s_Instances[clientId] as T;
}
return null;
}
public static void Reset()
{
s_Instances.Clear();
}
public override void OnNetworkSpawn()
{
if (!s_Instances.ContainsKey(NetworkManager.LocalClientId))
{
s_Instances.Add(NetworkManager.LocalClientId, this);
}
else
{
Debug.LogWarning($"{name} is spawned but client id {NetworkManager.LocalClientId} instance already exists!");
}
}
public override void OnNetworkDespawn()
{
if (s_Instances.ContainsKey(NetworkManager.LocalClientId))
{
s_Instances.Remove(NetworkManager.LocalClientId);
}
else
{
Debug.LogWarning($"{name} is was never spawned but client id {NetworkManager.LocalClientId} is trying to despawn it!");
}
}
}
internal class WorkingUserNetworkVariableComponent : WorkingUserNetworkVariableComponentBase
{
public NetworkVariable<MyTypeOne> NetworkVariable = new NetworkVariable<MyTypeOne>();
}
internal class WorkingUserNetworkVariableComponentUsingExtensionMethod : WorkingUserNetworkVariableComponentBase
{
public NetworkVariable<MyTypeTwo> NetworkVariable = new NetworkVariable<MyTypeTwo>();
}
internal class NonWorkingUserNetworkVariableComponent : NetworkBehaviour
{
public NetworkVariable<MyTypeThree> NetworkVariable = new NetworkVariable<MyTypeThree>();
}
internal static class NetworkVariableUserSerializableTypesTestsExtensionMethods
{
public static void WriteValueSafe(this FastBufferWriter writer, in MyTypeTwo value)
{
writer.WriteValueSafe(value.Value);
}
public static void ReadValueSafe(this FastBufferReader reader, out MyTypeTwo value)
{
value = new MyTypeTwo();
reader.ReadValueSafe(out value.Value);
}
}
internal class NetworkVariableUserSerializableTypesTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 1;
public NetworkVariableUserSerializableTypesTests()
: base(HostOrServer.Server)
{
}
private GameObject m_WorkingPrefab;
private GameObject m_ExtensionMethodPrefab;
private GameObject m_NonWorkingPrefab;
protected override IEnumerator OnSetup()
{
WorkingUserNetworkVariableComponentBase.Reset();
UserNetworkVariableSerialization<MyTypeOne>.WriteValue = null;
UserNetworkVariableSerialization<MyTypeOne>.ReadValue = null;
UserNetworkVariableSerialization<MyTypeOne>.DuplicateValue = null;
UserNetworkVariableSerialization<MyTypeTwo>.WriteValue = null;
UserNetworkVariableSerialization<MyTypeTwo>.ReadValue = null;
UserNetworkVariableSerialization<MyTypeTwo>.DuplicateValue = null;
UserNetworkVariableSerialization<MyTypeThree>.WriteValue = null;
UserNetworkVariableSerialization<MyTypeThree>.ReadValue = null;
UserNetworkVariableSerialization<MyTypeThree>.DuplicateValue = null;
return base.OnSetup();
}
protected override void OnServerAndClientsCreated()
{
m_WorkingPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableUserSerializableTypesTests)}.{nameof(m_WorkingPrefab)}]");
m_ExtensionMethodPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableUserSerializableTypesTests)}.{nameof(m_ExtensionMethodPrefab)}]");
m_NonWorkingPrefab = CreateNetworkObjectPrefab($"[{nameof(NetworkVariableUserSerializableTypesTests)}.{nameof(m_NonWorkingPrefab)}]");
m_WorkingPrefab.AddComponent<WorkingUserNetworkVariableComponent>();
m_ExtensionMethodPrefab.AddComponent<WorkingUserNetworkVariableComponentUsingExtensionMethod>();
m_NonWorkingPrefab.AddComponent<NonWorkingUserNetworkVariableComponent>();
}
private bool CheckForClientInstance<T>() where T : WorkingUserNetworkVariableComponentBase
{
var instance = WorkingUserNetworkVariableComponentBase.GetRelativeInstance<T>(m_ClientNetworkManagers[0].LocalClientId);
return instance != null && instance.IsSpawned;
}
[UnityTest]
public IEnumerator WhenUsingAUserSerializableNetworkVariableWithUserSerialization_ReplicationWorks()
{
UserNetworkVariableSerialization<MyTypeOne>.WriteValue = (FastBufferWriter writer, in MyTypeOne value) =>
{
writer.WriteValueSafe(value.Value);
};
UserNetworkVariableSerialization<MyTypeOne>.ReadValue = (FastBufferReader reader, out MyTypeOne value) =>
{
value = new MyTypeOne();
reader.ReadValueSafe(out value.Value);
};
UserNetworkVariableSerialization<MyTypeOne>.DuplicateValue = (in MyTypeOne value, ref MyTypeOne duplicatedValue) =>
{
duplicatedValue = value;
};
var serverObject = SpawnObject(m_WorkingPrefab, m_ServerNetworkManager);
var serverNetworkObject = serverObject.GetComponent<NetworkObject>();
// Wait for the client instance to be spawned, which removes the need to check for two NetworkVariableDeltaMessages
yield return WaitForConditionOrTimeOut(() => CheckForClientInstance<WorkingUserNetworkVariableComponent>());
AssertOnTimeout($"Timed out waiting for the client side object to spawn!");
// Get server and client instances of the test component
var clientInstance = WorkingUserNetworkVariableComponentBase.GetRelativeInstance<WorkingUserNetworkVariableComponent>(m_ClientNetworkManagers[0].LocalClientId);
var serverInstance = serverNetworkObject.GetComponent<WorkingUserNetworkVariableComponent>();
// Set the server side value
serverInstance.NetworkVariable.Value = new MyTypeOne { Value = 20 };
// Wait for the NetworkVariableDeltaMessage
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<NetworkVariableDeltaMessage>(m_ClientNetworkManagers[0]);
// Wait for the client side value to be updated to the server side value (can take an additional frame)
yield return WaitForConditionOrTimeOut(() => clientInstance.NetworkVariable.Value.Value == serverInstance.NetworkVariable.Value.Value);
Assert.AreEqual(serverNetworkObject.GetComponent<WorkingUserNetworkVariableComponent>().NetworkVariable.Value.Value, clientInstance.NetworkVariable.Value.Value);
Assert.AreEqual(20, clientInstance.NetworkVariable.Value.Value);
}
[UnityTest]
public IEnumerator WhenUsingAUserSerializableNetworkVariableWithUserSerializationViaExtensionMethod_ReplicationWorks()
{
UserNetworkVariableSerialization<MyTypeTwo>.WriteValue = NetworkVariableUserSerializableTypesTestsExtensionMethods.WriteValueSafe;
UserNetworkVariableSerialization<MyTypeTwo>.ReadValue = NetworkVariableUserSerializableTypesTestsExtensionMethods.ReadValueSafe;
UserNetworkVariableSerialization<MyTypeTwo>.DuplicateValue = (in MyTypeTwo value, ref MyTypeTwo duplicatedValue) =>
{
duplicatedValue = value;
};
var serverObject = SpawnObject(m_ExtensionMethodPrefab, m_ServerNetworkManager);
var serverNetworkObject = serverObject.GetComponent<NetworkObject>();
// Wait for the client instance to be spawned, which removes the need to check for two NetworkVariableDeltaMessages
yield return WaitForConditionOrTimeOut(() => CheckForClientInstance<WorkingUserNetworkVariableComponentUsingExtensionMethod>());
AssertOnTimeout($"Timed out waiting for the client side object to spawn!");
// Get server and client instances of the test component
var clientInstance = WorkingUserNetworkVariableComponentBase.GetRelativeInstance<WorkingUserNetworkVariableComponentUsingExtensionMethod>(m_ClientNetworkManagers[0].LocalClientId);
var serverInstance = serverNetworkObject.GetComponent<WorkingUserNetworkVariableComponentUsingExtensionMethod>();
// Set the server side value
serverInstance.NetworkVariable.Value = new MyTypeTwo { Value = 20 };
// Wait for the NetworkVariableDeltaMessage
yield return NetcodeIntegrationTestHelpers.WaitForMessageOfTypeReceived<NetworkVariableDeltaMessage>(m_ClientNetworkManagers[0]);
// Wait for the client side value to be updated to the server side value (can take an additional frame)
yield return WaitForConditionOrTimeOut(() => clientInstance.NetworkVariable.Value.Value == serverInstance.NetworkVariable.Value.Value);
AssertOnTimeout($"Timed out waiting for the client side object's value ({clientInstance.NetworkVariable.Value.Value}) to equal the server side objects value ({serverInstance.NetworkVariable.Value.Value})!");
Assert.AreEqual(serverInstance.NetworkVariable.Value.Value, clientInstance.NetworkVariable.Value.Value);
Assert.AreEqual(20, clientInstance.NetworkVariable.Value.Value);
}
[Test]
public void WhenUsingAUserSerializableNetworkVariableWithoutUserSerialization_ReplicationFails()
{
var serverObject = Object.Instantiate(m_NonWorkingPrefab);
var serverNetworkObject = serverObject.GetComponent<NetworkObject>();
serverNetworkObject.NetworkManagerOwner = m_ServerNetworkManager;
Assert.Throws<ArgumentException>(
() =>
{
serverNetworkObject.Spawn();
}
);
}
protected override IEnumerator OnTearDown()
{
// These have to get set to SOMETHING, otherwise we will get an exception thrown because Object.Destroy()
// calls __initializeNetworkVariables, and the network variable initialization attempts to call FallbackSerializer<T>,
// which throws an exception if any of these values are null. They don't have to DO anything, they just have to
// be non-null to keep the test from failing during teardown.
// None of this is related to what's being tested above, and in reality, these values being null is an invalid
// use case. But one of the tests is explicitly testing that invalid use case, and the values are being set
// to null in OnSetup to ensure test isolation. This wouldn't be a situation a user would have to think about
// in a real world use case.
UserNetworkVariableSerialization<MyTypeOne>.WriteValue = (FastBufferWriter writer, in MyTypeOne value) => { };
UserNetworkVariableSerialization<MyTypeOne>.ReadValue = (FastBufferReader reader, out MyTypeOne value) => { value = new MyTypeOne(); };
UserNetworkVariableSerialization<MyTypeOne>.DuplicateValue = (in MyTypeOne value, ref MyTypeOne duplicatedValue) =>
{
duplicatedValue = value;
};
UserNetworkVariableSerialization<MyTypeTwo>.WriteValue = (FastBufferWriter writer, in MyTypeTwo value) => { };
UserNetworkVariableSerialization<MyTypeTwo>.ReadValue = (FastBufferReader reader, out MyTypeTwo value) => { value = new MyTypeTwo(); };
UserNetworkVariableSerialization<MyTypeTwo>.DuplicateValue = (in MyTypeTwo value, ref MyTypeTwo duplicatedValue) =>
{
duplicatedValue = value;
};
UserNetworkVariableSerialization<MyTypeThree>.WriteValue = (FastBufferWriter writer, in MyTypeThree value) => { };
UserNetworkVariableSerialization<MyTypeThree>.ReadValue = (FastBufferReader reader, out MyTypeThree value) => { value = new MyTypeThree(); };
UserNetworkVariableSerialization<MyTypeThree>.DuplicateValue = (in MyTypeThree value, ref MyTypeThree duplicatedValue) =>
{
duplicatedValue = value;
};
return base.OnTearDown();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1195640cf744e85b58c5af6d11eeb34
timeCreated: 1652907276

View File

@@ -0,0 +1,114 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests
{
// This is a bit of a quirky test.
// Addresses MTT-4386 #2109
// Where the NetworkVariable updates would be repeated on some clients.
// The twist comes fom the updates needing to happens very specifically for the issue to repro in tests
internal class OwnerModifiedObject : NetworkBehaviour, INetworkUpdateSystem
{
public NetworkList<int> MyNetworkList;
internal static int Updates = 0;
public static bool EnableVerbose;
private void Awake()
{
MyNetworkList = new NetworkList<int>(new List<int>(), NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
MyNetworkList.OnListChanged += Changed;
}
public void Changed(NetworkListEvent<int> listEvent)
{
var expected = 0;
var listString = "";
foreach (var i in MyNetworkList)
{
Assert.AreEqual(i, expected);
expected++;
listString += i.ToString();
}
if (EnableVerbose)
{
Debug.Log($"[{NetworkManager.LocalClientId}] Value changed to {listString}");
}
Updates++;
}
public bool AddValues;
public NetworkUpdateStage NetworkUpdateStageToCheck;
private int m_ValueToUpdate;
public void NetworkUpdate(NetworkUpdateStage updateStage)
{
if (updateStage == NetworkUpdateStageToCheck)
{
if (AddValues)
{
MyNetworkList.Add(m_ValueToUpdate++);
AddValues = false;
}
}
}
public override void OnDestroy()
{
NetworkUpdateLoop.UnregisterAllNetworkUpdates(this);
base.OnDestroy();
}
public void InitializeLastCient()
{
NetworkUpdateLoop.RegisterAllNetworkUpdates(this);
}
}
[TestFixture(HostOrServer.DAHost)]
[TestFixture(HostOrServer.Host)]
internal class OwnerModifiedTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 2;
public OwnerModifiedTests(HostOrServer hostOrServer) : base(hostOrServer) { }
protected override void OnCreatePlayerPrefab()
{
m_PlayerPrefab.AddComponent<OwnerModifiedObject>();
}
[UnityTest]
public IEnumerator OwnerModifiedTest()
{
OwnerModifiedObject.EnableVerbose = m_EnableVerboseDebug;
// We use this to assure we are the "last client" connected.
yield return CreateAndStartNewClient();
var ownerModLastClient = m_ClientNetworkManagers[2].LocalClient.PlayerObject.GetComponent<OwnerModifiedObject>();
ownerModLastClient.InitializeLastCient();
// Run through all update loops setting the value once every 5 frames
foreach (var updateLoopType in System.Enum.GetValues(typeof(NetworkUpdateStage)))
{
ownerModLastClient.NetworkUpdateStageToCheck = (NetworkUpdateStage)updateLoopType;
VerboseDebug($"Testing Update Stage: {ownerModLastClient.NetworkUpdateStageToCheck}");
ownerModLastClient.AddValues = true;
yield return WaitForTicks(m_ServerNetworkManager, 5);
}
yield return WaitForTicks(m_ServerNetworkManager, 5);
// We'll have at least one update per stage per client, if all goes well.
Assert.True(OwnerModifiedObject.Updates > 20);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 419d83ebac7544ea9b0a9d5c3eab2c71
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,181 @@
using System.Collections;
using System.Collections.Generic;
using Unity.Netcode.TestHelpers.Runtime;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.Netcode.RuntimeTests
{
internal class OwnerPermissionObject : NetworkBehaviour
{
// indexed by [object, machine]
public static OwnerPermissionObject[,] Objects = new OwnerPermissionObject[3, 3];
public static int CurrentlySpawning = 0;
public static List<OwnerPermissionObject> ClientTargetedNetworkObjects = new List<OwnerPermissionObject>();
// a client-owned NetworkVariable
public NetworkVariable<int> MyNetworkVariableOwner;
// a server-owned NetworkVariable
public NetworkVariable<int> MyNetworkVariableServer;
// a client-owned NetworkVariable
public NetworkList<int> MyNetworkListOwner;
// a server-owned NetworkVariable
public NetworkList<int> MyNetworkListServer;
// verifies two lists are identical
public static void CheckLists(NetworkList<int> listA, NetworkList<int> listB)
{
Debug.Assert(listA.Count == listB.Count);
for (var i = 0; i < listA.Count; i++)
{
Debug.Assert(listA[i] == listB[i]);
}
}
// verifies all objects have consistent lists on all clients
public static void VerifyConsistency()
{
for (var objectIndex = 0; objectIndex < 3; objectIndex++)
{
CheckLists(Objects[objectIndex, 0].MyNetworkListOwner, Objects[objectIndex, 1].MyNetworkListOwner);
CheckLists(Objects[objectIndex, 0].MyNetworkListOwner, Objects[objectIndex, 2].MyNetworkListOwner);
CheckLists(Objects[objectIndex, 0].MyNetworkListServer, Objects[objectIndex, 1].MyNetworkListServer);
CheckLists(Objects[objectIndex, 0].MyNetworkListServer, Objects[objectIndex, 2].MyNetworkListServer);
}
}
public override void OnNetworkSpawn()
{
Objects[CurrentlySpawning, NetworkManager.LocalClientId] = GetComponent<OwnerPermissionObject>();
}
private void Awake()
{
MyNetworkVariableOwner = new NetworkVariable<int>(writePerm: NetworkVariableWritePermission.Owner);
MyNetworkVariableOwner.OnValueChanged += OwnerChanged;
MyNetworkVariableServer = new NetworkVariable<int>(writePerm: NetworkVariableWritePermission.Server);
MyNetworkVariableServer.OnValueChanged += ServerChanged;
MyNetworkListOwner = new NetworkList<int>(writePerm: NetworkVariableWritePermission.Owner);
MyNetworkListOwner.OnListChanged += ListOwnerChanged;
MyNetworkListServer = new NetworkList<int>(writePerm: NetworkVariableWritePermission.Server);
MyNetworkListServer.OnListChanged += ListServerChanged;
}
public void OwnerChanged(int before, int after)
{
}
public void ServerChanged(int before, int after)
{
}
public void ListOwnerChanged(NetworkListEvent<int> listEvent)
{
}
public void ListServerChanged(NetworkListEvent<int> listEvent)
{
}
}
internal class OwnerPermissionHideTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 2;
private GameObject m_PrefabToSpawn;
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = CreateNetworkObjectPrefab("OwnerPermissionObject");
m_PrefabToSpawn.AddComponent<OwnerPermissionObject>();
}
[UnityTest]
public IEnumerator OwnerPermissionTest()
{
// create 3 objects
for (var objectIndex = 0; objectIndex < 3; objectIndex++)
{
OwnerPermissionObject.CurrentlySpawning = objectIndex;
NetworkManager ownerManager = m_ServerNetworkManager;
if (objectIndex != 0)
{
ownerManager = m_ClientNetworkManagers[objectIndex - 1];
}
SpawnObject(m_PrefabToSpawn, ownerManager);
// wait for each object to spawn on each client
for (var clientIndex = 0; clientIndex < 3; clientIndex++)
{
while (OwnerPermissionObject.Objects[objectIndex, clientIndex] == null)
{
yield return new WaitForSeconds(0.0f);
}
}
}
var nextValueToWrite = 1;
var serverIndex = 0;
for (var objectIndex = 0; objectIndex < 3; objectIndex++)
{
for (var clientWriting = 0; clientWriting < 3; clientWriting++)
{
// ==== Server-writable NetworkVariable ====
VerboseDebug($"Writing to server-write variable on object {objectIndex} on client {clientWriting}");
nextValueToWrite++;
if (clientWriting != serverIndex)
{
LogAssert.Expect(LogType.Error, OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkVariableServer.GetWritePermissionError());
}
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkVariableServer.Value = nextValueToWrite;
// ==== Owner-writable NetworkVariable ====
VerboseDebug($"Writing to owner-write variable on object {objectIndex} on client {clientWriting}");
nextValueToWrite++;
if (clientWriting != objectIndex)
{
LogAssert.Expect(LogType.Error, OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkVariableOwner.GetWritePermissionError());
}
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkVariableOwner.Value = nextValueToWrite;
// ==== Server-writable NetworkList ====
VerboseDebug($"Writing to [Add] server-write NetworkList on object {objectIndex} on client {clientWriting}");
nextValueToWrite++;
if (clientWriting != serverIndex)
{
LogAssert.Expect(LogType.Error, OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkListServer.GetWritePermissionError());
}
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkListServer.Add(nextValueToWrite);
// ==== Owner-writable NetworkList ====
VerboseDebug($"Writing to [Add] owner-write NetworkList on object {objectIndex} on client {clientWriting}");
nextValueToWrite++;
if (clientWriting != objectIndex)
{
LogAssert.Expect(LogType.Error, OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkListOwner.GetWritePermissionError());
}
OwnerPermissionObject.Objects[objectIndex, clientWriting].MyNetworkListOwner.Add(nextValueToWrite);
yield return WaitForTicks(m_ServerNetworkManager, 5);
yield return WaitForTicks(m_ClientNetworkManagers[0], 5);
yield return WaitForTicks(m_ClientNetworkManagers[1], 5);
OwnerPermissionObject.VerifyConsistency();
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88c657dcbe9a2414ba551b60dab19acd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: