425 lines
16 KiB
C#
425 lines
16 KiB
C#
|
using NUnit.Framework;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace Mirror.Tests.SyncVarAttributeTests
|
||
|
{
|
||
|
class MockPlayer : NetworkBehaviour
|
||
|
{
|
||
|
public struct Guild
|
||
|
{
|
||
|
public string name;
|
||
|
}
|
||
|
|
||
|
[SyncVar]
|
||
|
public Guild guild;
|
||
|
}
|
||
|
|
||
|
class SyncVarGameObject : NetworkBehaviour
|
||
|
{
|
||
|
[SyncVar]
|
||
|
public GameObject value;
|
||
|
}
|
||
|
class SyncVarNetworkIdentity : NetworkBehaviour
|
||
|
{
|
||
|
[SyncVar]
|
||
|
public NetworkIdentity value;
|
||
|
}
|
||
|
class SyncVarTransform : NetworkBehaviour
|
||
|
{
|
||
|
[SyncVar]
|
||
|
public Transform value;
|
||
|
}
|
||
|
class SyncVarNetworkBehaviour : NetworkBehaviour
|
||
|
{
|
||
|
[SyncVar]
|
||
|
public SyncVarNetworkBehaviour value;
|
||
|
}
|
||
|
class SyncVarAbstractNetworkBehaviour : NetworkBehaviour
|
||
|
{
|
||
|
public abstract class MockMonsterBase : NetworkBehaviour
|
||
|
{
|
||
|
public abstract string GetName();
|
||
|
}
|
||
|
|
||
|
public class MockZombie : MockMonsterBase
|
||
|
{
|
||
|
public override string GetName() => "Zombie";
|
||
|
}
|
||
|
|
||
|
public class MockWolf : MockMonsterBase
|
||
|
{
|
||
|
public override string GetName() => "Wolf";
|
||
|
}
|
||
|
|
||
|
[SyncVar]
|
||
|
public MockMonsterBase monster1;
|
||
|
|
||
|
[SyncVar]
|
||
|
public MockMonsterBase monster2;
|
||
|
}
|
||
|
|
||
|
public class SyncVarAttributeTest : MirrorTest
|
||
|
{
|
||
|
[SetUp]
|
||
|
public override void SetUp()
|
||
|
{
|
||
|
base.SetUp();
|
||
|
|
||
|
// start server & connect client because we need spawn functions
|
||
|
NetworkServer.Listen(1);
|
||
|
|
||
|
// we are testing server->client syncs.
|
||
|
// so we need truly separted server & client, not host.
|
||
|
ConnectClientBlockingAuthenticatedAndReady(out _);
|
||
|
}
|
||
|
|
||
|
[TearDown]
|
||
|
public override void TearDown()
|
||
|
{
|
||
|
base.TearDown();
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void TestSettingStruct()
|
||
|
{
|
||
|
CreateNetworked(out _, out _, out MockPlayer player);
|
||
|
|
||
|
// synchronize immediately
|
||
|
player.syncInterval = 0f;
|
||
|
|
||
|
Assert.That(player.IsDirty(), Is.False, "First time object should not be dirty");
|
||
|
|
||
|
MockPlayer.Guild myGuild = new MockPlayer.Guild
|
||
|
{
|
||
|
name = "Back street boys"
|
||
|
};
|
||
|
|
||
|
player.guild = myGuild;
|
||
|
|
||
|
Assert.That(player.IsDirty(), "Setting struct should mark object as dirty");
|
||
|
player.ClearAllDirtyBits();
|
||
|
Assert.That(player.IsDirty(), Is.False, "ClearAllDirtyBits() should clear dirty flag");
|
||
|
|
||
|
// clearing the guild should set dirty bit too
|
||
|
player.guild = default;
|
||
|
Assert.That(player.IsDirty(), "Clearing struct should mark object as dirty");
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void TestSyncIntervalAndClearDirtyComponents()
|
||
|
{
|
||
|
CreateNetworked(out _, out _, out MockPlayer player);
|
||
|
player.lastSyncTime = NetworkTime.localTime;
|
||
|
// synchronize immediately
|
||
|
player.syncInterval = 1f;
|
||
|
|
||
|
player.guild = new MockPlayer.Guild
|
||
|
{
|
||
|
name = "Back street boys"
|
||
|
};
|
||
|
|
||
|
Assert.That(player.IsDirty(), Is.False, "Sync interval not met, so not dirty yet");
|
||
|
|
||
|
// ClearDirtyComponents should do nothing since syncInterval is not
|
||
|
// elapsed yet
|
||
|
player.netIdentity.ClearDirtyComponentsDirtyBits();
|
||
|
|
||
|
// set lastSyncTime far enough back to be ready for syncing
|
||
|
player.lastSyncTime = NetworkTime.localTime - player.syncInterval;
|
||
|
|
||
|
// should be dirty now
|
||
|
Assert.That(player.IsDirty(), Is.True, "Sync interval met, should be dirty");
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void TestSyncIntervalAndClearAllComponents()
|
||
|
{
|
||
|
CreateNetworked(out _, out _, out MockPlayer player);
|
||
|
player.lastSyncTime = NetworkTime.localTime;
|
||
|
// synchronize immediately
|
||
|
player.syncInterval = 1f;
|
||
|
|
||
|
player.guild = new MockPlayer.Guild
|
||
|
{
|
||
|
name = "Back street boys"
|
||
|
};
|
||
|
|
||
|
Assert.That(player.IsDirty(), Is.False, "Sync interval not met, so not dirty yet");
|
||
|
|
||
|
// ClearAllComponents should clear dirty even if syncInterval not
|
||
|
// elapsed yet
|
||
|
player.netIdentity.ClearAllComponentsDirtyBits();
|
||
|
|
||
|
// set lastSyncTime far enough back to be ready for syncing
|
||
|
player.lastSyncTime = NetworkTime.localTime - player.syncInterval;
|
||
|
|
||
|
// should be dirty now
|
||
|
Assert.That(player.IsDirty(), Is.False, "Sync interval met, should still not be dirty");
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void SyncsGameobject()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarGameObject serverObject,
|
||
|
out _, out _, out SyncVarGameObject clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out GameObject serverValue, out _,
|
||
|
out GameObject clientValue, out _);
|
||
|
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
ProcessMessages();
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue));
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void SyncIdentity()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarNetworkIdentity serverObject,
|
||
|
out _, out _, out SyncVarNetworkIdentity clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out NetworkIdentity serverValue,
|
||
|
out _, out NetworkIdentity clientValue);
|
||
|
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
ProcessMessages();
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue));
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void SyncTransform()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarTransform serverObject,
|
||
|
out _, out _, out SyncVarTransform clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out NetworkIdentity serverIdentity,
|
||
|
out _, out NetworkIdentity clientIdentity);
|
||
|
|
||
|
Transform serverValue = serverIdentity.transform;
|
||
|
Transform clientValue = clientIdentity.transform;
|
||
|
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
ProcessMessages();
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue));
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void SyncsBehaviour()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarNetworkBehaviour serverObject,
|
||
|
out _, out _, out SyncVarNetworkBehaviour clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarNetworkBehaviour serverValue,
|
||
|
out _, out _, out SyncVarNetworkBehaviour clientValue);
|
||
|
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
ProcessMessages();
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue));
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void SyncsMultipleBehaviour()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarNetworkBehaviour serverObject,
|
||
|
out _, out _, out SyncVarNetworkBehaviour clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out NetworkIdentity serverIdentity, out SyncVarNetworkBehaviour serverBehaviour1, out SyncVarNetworkBehaviour serverBehaviour2,
|
||
|
out _, out NetworkIdentity clientIdentity, out SyncVarNetworkBehaviour clientBehaviour1, out SyncVarNetworkBehaviour clientBehaviour2);
|
||
|
|
||
|
// create array/set indices
|
||
|
_ = serverIdentity.NetworkBehaviours;
|
||
|
|
||
|
int index1 = serverBehaviour1.ComponentIndex;
|
||
|
int index2 = serverBehaviour2.ComponentIndex;
|
||
|
|
||
|
// check components of same type have different indexes
|
||
|
Assert.That(index1, Is.Not.EqualTo(index2));
|
||
|
|
||
|
// check behaviour 1 can be synced
|
||
|
serverObject.value = serverBehaviour1;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
ProcessMessages();
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientBehaviour1));
|
||
|
|
||
|
// check that behaviour 2 can be synced
|
||
|
serverObject.value = serverBehaviour2;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
ProcessMessages();
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientBehaviour2));
|
||
|
}
|
||
|
|
||
|
// this test is also important if we do LocalWorldState later:
|
||
|
// - if LocalWorldMessage spawns netId=N
|
||
|
// - and we remove N from NetworkClient.spawned
|
||
|
// - and the next LocalWorldMessage contains updated payload for N
|
||
|
// => client should NOT assume it's a spawned payload just because the
|
||
|
// netId isn't in spawned anymore.
|
||
|
[Test]
|
||
|
public void SyncVarCacheNetidForGameObject()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarGameObject serverObject,
|
||
|
out _, out _, out SyncVarGameObject clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out GameObject serverValue, out NetworkIdentity serverIdentity,
|
||
|
out GameObject clientValue, out NetworkIdentity clientIdentity);
|
||
|
|
||
|
Assert.That(serverValue, Is.Not.Null, "getCreatedValue should not return null");
|
||
|
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
// remove identity from client, as if it walked out of range
|
||
|
NetworkClient.spawned.Remove(clientIdentity.netId);
|
||
|
|
||
|
ProcessMessages();
|
||
|
|
||
|
// check field shows as null
|
||
|
Assert.That(clientObject.value, Is.EqualTo(null), "field should return null");
|
||
|
|
||
|
// add identity back to collection, as if it walked back into range
|
||
|
NetworkClient.spawned.Add(clientIdentity.netId, clientIdentity);
|
||
|
|
||
|
// check field finds value
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue), "fields should return clientValue");
|
||
|
}
|
||
|
|
||
|
// this test is also important if we do LocalWorldState later:
|
||
|
// - if LocalWorldMessage spawns netId=N
|
||
|
// - and we remove N from NetworkClient.spawned
|
||
|
// - and the next LocalWorldMessage contains updated payload for N
|
||
|
// => client should NOT assume it's a spawned payload just because the
|
||
|
// netId isn't in spawned anymore.
|
||
|
[Test]
|
||
|
public void SyncVarCacheNetidForIdentity()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarNetworkIdentity serverObject,
|
||
|
out _, out _, out SyncVarNetworkIdentity clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out NetworkIdentity serverValue,
|
||
|
out _, out NetworkIdentity clientValue);
|
||
|
|
||
|
Assert.That(serverValue, Is.Not.Null, "getCreatedValue should not return null");
|
||
|
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
// remove identity from client, as if it walked out of range
|
||
|
NetworkClient.spawned.Remove(clientValue.netId);
|
||
|
|
||
|
ProcessMessages();
|
||
|
|
||
|
// check field shows as null
|
||
|
Assert.That(clientObject.value, Is.EqualTo(null), "field should return null");
|
||
|
|
||
|
// add identity back to collection, as if it walked back into range
|
||
|
NetworkClient.spawned.Add(clientValue.netId, clientValue);
|
||
|
|
||
|
// check field finds value
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue), "fields should return clientValue");
|
||
|
}
|
||
|
|
||
|
// this test is also important if we do LocalWorldState later:
|
||
|
// - if LocalWorldMessage spawns netId=N
|
||
|
// - and we remove N from NetworkClient.spawned
|
||
|
// - and the next LocalWorldMessage contains updated payload for N
|
||
|
// => client should NOT assume it's a spawned payload just because the
|
||
|
// netId isn't in spawned anymore.
|
||
|
[Test]
|
||
|
public void SyncVarCacheNetidForBehaviour()
|
||
|
{
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out _, out SyncVarNetworkBehaviour serverObject,
|
||
|
out _, out _, out SyncVarNetworkBehaviour clientObject);
|
||
|
|
||
|
// create spawned because we will look up netId in .spawned
|
||
|
CreateNetworkedAndSpawn(
|
||
|
out _, out NetworkIdentity serverIdentity, out SyncVarNetworkBehaviour serverValue,
|
||
|
out _, out NetworkIdentity clientIdentity, out SyncVarNetworkBehaviour clientValue);
|
||
|
|
||
|
Assert.That(serverValue, Is.Not.Null, "getCreatedValue should not return null");
|
||
|
|
||
|
// set on server
|
||
|
serverObject.value = serverValue;
|
||
|
clientObject.value = null;
|
||
|
|
||
|
// remove identity from client, as if it walked out of range
|
||
|
NetworkClient.spawned.Remove(clientIdentity.netId);
|
||
|
|
||
|
ProcessMessages();
|
||
|
|
||
|
// check field shows as null
|
||
|
Assert.That(clientObject.value, Is.EqualTo(null), "field should return null");
|
||
|
|
||
|
// add identity back to collection, as if it walked back into range
|
||
|
NetworkClient.spawned.Add(clientIdentity.netId, clientIdentity);
|
||
|
|
||
|
// check field finds value
|
||
|
Assert.That(clientObject.value, Is.EqualTo(clientValue), "fields should return clientValue");
|
||
|
}
|
||
|
|
||
|
[Test]
|
||
|
public void TestSyncingAbstractNetworkBehaviour()
|
||
|
{
|
||
|
// set up a "server" object
|
||
|
CreateNetworked(out _, out NetworkIdentity serverIdentity, out SyncVarAbstractNetworkBehaviour serverBehaviour);
|
||
|
|
||
|
// spawn syncvar targets
|
||
|
CreateNetworked(out _, out NetworkIdentity wolfIdentity, out SyncVarAbstractNetworkBehaviour.MockWolf wolf);
|
||
|
CreateNetworked(out _, out NetworkIdentity zombieIdentity, out SyncVarAbstractNetworkBehaviour.MockZombie zombie);
|
||
|
|
||
|
wolfIdentity.netId = 135;
|
||
|
zombieIdentity.netId = 246;
|
||
|
|
||
|
serverBehaviour.monster1 = wolf;
|
||
|
serverBehaviour.monster2 = zombie;
|
||
|
|
||
|
// serialize all the data as we would for the network
|
||
|
NetworkWriter ownerWriter = new NetworkWriter();
|
||
|
// not really used in this Test
|
||
|
NetworkWriter observersWriter = new NetworkWriter();
|
||
|
serverIdentity.OnSerializeAllSafely(true, ownerWriter, observersWriter);
|
||
|
|
||
|
// set up a "client" object
|
||
|
CreateNetworked(out _, out NetworkIdentity clientIdentity, out SyncVarAbstractNetworkBehaviour clientBehaviour);
|
||
|
|
||
|
// apply all the data from the server object
|
||
|
NetworkReader reader = new NetworkReader(ownerWriter.ToArray());
|
||
|
clientIdentity.OnDeserializeAllSafely(reader, true);
|
||
|
|
||
|
// check that the syncvars got updated
|
||
|
Assert.That(clientBehaviour.monster1, Is.EqualTo(serverBehaviour.monster1), "Data should be synchronized");
|
||
|
Assert.That(clientBehaviour.monster2, Is.EqualTo(serverBehaviour.monster2), "Data should be synchronized");
|
||
|
}
|
||
|
}
|
||
|
}
|