mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
Added Tests
This commit is contained in:
parent
7d974fbdbe
commit
140691e744
8
Assets/Mirror/Tests.meta
Normal file
8
Assets/Mirror/Tests.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4de157ac7e1594c758ce6dc401674f5c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/Mirror/Tests/Common.meta
Normal file
8
Assets/Mirror/Tests/Common.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dd4f310377c5a4ad39bd31546c95c2a2
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Assets/Mirror/Tests/Common/Castle.Core.dll
Normal file
BIN
Assets/Mirror/Tests/Common/Castle.Core.dll
Normal file
Binary file not shown.
112
Assets/Mirror/Tests/Common/Castle.Core.dll.meta
Normal file
112
Assets/Mirror/Tests/Common/Castle.Core.dll.meta
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 739a02265856e4e4b8a3ae587a908479
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
'': Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux: 1
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude LinuxUniversal: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude WebGL: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
- first:
|
||||||
|
Facebook: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Facebook: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Linux
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: LinuxUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
62
Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs
Normal file
62
Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used by both runtime and edit time tests
|
||||||
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
|
public abstract class ClientSceneTestsBase : MirrorEditModeTest
|
||||||
|
{
|
||||||
|
// use guid to find asset so that the path does not matter
|
||||||
|
protected const string ValidPrefabAssetGuid = "33169286da0313d45ab5bfccc6cf3775";
|
||||||
|
protected const string PrefabWithChildrenAssetGuid = "a78e009e3f2dee44e8859516974ede43";
|
||||||
|
protected const string InvalidPrefabAssetGuid = "78f0a3f755d35324e959f3ecdd993fb0";
|
||||||
|
// random guid, not used anywhere
|
||||||
|
protected const string AnotherGuidString = "5794128cdfda04542985151f82990d05";
|
||||||
|
|
||||||
|
protected GameObject validPrefab;
|
||||||
|
protected NetworkIdentity validPrefabNetworkIdentity;
|
||||||
|
protected GameObject prefabWithChildren;
|
||||||
|
protected GameObject invalidPrefab;
|
||||||
|
protected Guid validPrefabGuid;
|
||||||
|
protected Guid anotherGuid;
|
||||||
|
|
||||||
|
static GameObject LoadPrefab(string guid)
|
||||||
|
{
|
||||||
|
return AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(guid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeSetUp]
|
||||||
|
public void OneTimeSetUp()
|
||||||
|
{
|
||||||
|
validPrefab = LoadPrefab(ValidPrefabAssetGuid);
|
||||||
|
validPrefabNetworkIdentity = validPrefab.GetComponent<NetworkIdentity>();
|
||||||
|
prefabWithChildren = LoadPrefab(PrefabWithChildrenAssetGuid);
|
||||||
|
invalidPrefab = LoadPrefab(InvalidPrefabAssetGuid);
|
||||||
|
validPrefabGuid = new Guid(ValidPrefabAssetGuid);
|
||||||
|
anotherGuid = new Guid(AnotherGuidString);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
// reset asset id in case they are changed by tests
|
||||||
|
validPrefabNetworkIdentity.assetId = validPrefabGuid;
|
||||||
|
|
||||||
|
base.TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
[OneTimeTearDown]
|
||||||
|
public void OneTimeTearDown()
|
||||||
|
{
|
||||||
|
validPrefab = null;
|
||||||
|
prefabWithChildren = null;
|
||||||
|
invalidPrefab = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs.meta
Normal file
11
Assets/Mirror/Tests/Common/ClientSceneTestsBase.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bf741fb5970e5e048aea5ff3e396d24c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,212 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used by both runtime and edit time tests
|
||||||
|
/// </summary>
|
||||||
|
[TestFixture]
|
||||||
|
public abstract class ClientSceneTests_RegisterPrefabBase : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab, false)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId, true)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate, false)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId, true)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate, false)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId, true)]
|
||||||
|
public void CheckOverloadWithAssetId(RegisterPrefabOverload overload, bool expected)
|
||||||
|
{
|
||||||
|
// test to make sure OverloadWithAssetId correctly works with flags
|
||||||
|
Assert.That(OverloadWithAssetId(overload), Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab, false)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId, false)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate, true)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId, true)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate, true)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId, true)]
|
||||||
|
public void CheckOverloadWithHandler(RegisterPrefabOverload overload, bool expected)
|
||||||
|
{
|
||||||
|
// test to make sure OverloadWithHandler correctly works with flags
|
||||||
|
Assert.That(OverloadWithHandler(overload), Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows TestCases to call different overloads for RegisterPrefab.
|
||||||
|
/// Without this we would need duplicate tests for each overload
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum RegisterPrefabOverload
|
||||||
|
{
|
||||||
|
Prefab = 1,
|
||||||
|
Prefab_NewAssetId = 2,
|
||||||
|
Prefab_SpawnDelegate = 4,
|
||||||
|
Prefab_SpawnDelegate_NewAssetId = 8,
|
||||||
|
Prefab_SpawnHandlerDelegate = 16,
|
||||||
|
Prefab_SpawnHandlerDelegate_NewAssetId = 32,
|
||||||
|
|
||||||
|
WithAssetId = Prefab_NewAssetId | Prefab_SpawnDelegate_NewAssetId | Prefab_SpawnHandlerDelegate_NewAssetId,
|
||||||
|
WithHandler = Prefab_SpawnDelegate | Prefab_SpawnDelegate_NewAssetId | Prefab_SpawnHandlerDelegate | Prefab_SpawnHandlerDelegate_NewAssetId
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static bool OverloadWithAssetId(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
return (overload & RegisterPrefabOverload.WithAssetId) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static bool OverloadWithHandler(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
return (overload & RegisterPrefabOverload.WithHandler) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
SpawnHandlerDelegate spawnHandlerDelegate = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
switch (overload)
|
||||||
|
{
|
||||||
|
case RegisterPrefabOverload.Prefab:
|
||||||
|
NetworkClient.RegisterPrefab(prefab);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Debug.LogError("Overload not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, Guid guid)
|
||||||
|
{
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
SpawnHandlerDelegate spawnHandlerDelegate = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
switch (overload)
|
||||||
|
{
|
||||||
|
case RegisterPrefabOverload.Prefab_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, guid);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, guid, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, guid, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RegisterPrefabOverload.Prefab:
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate:
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
|
||||||
|
Debug.LogError("Overload did not have guid parameter");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.LogError("Overload not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, SpawnDelegate spawnHandler)
|
||||||
|
{
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
switch (overload)
|
||||||
|
{
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RegisterPrefabOverload.Prefab:
|
||||||
|
case RegisterPrefabOverload.Prefab_NewAssetId:
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
|
||||||
|
Debug.LogError("Overload did not have SpawnDelegate parameter");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.LogError("Overload not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, SpawnHandlerDelegate spawnHandlerDelegate)
|
||||||
|
{
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
switch (overload)
|
||||||
|
{
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RegisterPrefabOverload.Prefab:
|
||||||
|
case RegisterPrefabOverload.Prefab_NewAssetId:
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate:
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
|
||||||
|
Debug.LogError("Overload did not have SpawnHandlerDelegate parameter");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.LogError("Overload not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CallRegisterPrefab(GameObject prefab, RegisterPrefabOverload overload, UnSpawnDelegate unspawnHandler)
|
||||||
|
{
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
SpawnHandlerDelegate spawnHandlerDelegate = new SpawnHandlerDelegate(x => null);
|
||||||
|
|
||||||
|
switch (overload)
|
||||||
|
{
|
||||||
|
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandler, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
case RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId:
|
||||||
|
NetworkClient.RegisterPrefab(prefab, anotherGuid, spawnHandlerDelegate, unspawnHandler);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RegisterPrefabOverload.Prefab:
|
||||||
|
case RegisterPrefabOverload.Prefab_NewAssetId:
|
||||||
|
Debug.LogError("Overload did not have UnSpawnDelegate parameter");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.LogError("Overload not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Guid GuidForOverload(RegisterPrefabOverload overload) => OverloadWithAssetId(overload) ? anotherGuid : validPrefabGuid;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8eb53689226946640bc49bb962b13638
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
12
Assets/Mirror/Tests/Common/FakeNetworkConnection.cs
Normal file
12
Assets/Mirror/Tests/Common/FakeNetworkConnection.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class FakeNetworkConnection : NetworkConnectionToClient
|
||||||
|
{
|
||||||
|
public FakeNetworkConnection() : base(1) {}
|
||||||
|
public override string address => "Test";
|
||||||
|
public override void Disconnect() {}
|
||||||
|
internal override void Send(ArraySegment<byte> segment, int channelId = 0) {}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Common/FakeNetworkConnection.cs.meta
Normal file
11
Assets/Mirror/Tests/Common/FakeNetworkConnection.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 935b1eb49c500674eaaf88982952a69e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
208
Assets/Mirror/Tests/Common/MemoryTransport.cs
Normal file
208
Assets/Mirror/Tests/Common/MemoryTransport.cs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// memory transport for easier testing
|
||||||
|
// note: file needs to be outside of Editor folder, otherwise AddComponent
|
||||||
|
// can't be called with MemoryTransport
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class MemoryTransport : Transport
|
||||||
|
{
|
||||||
|
public enum EventType { Connected, Data, Disconnected }
|
||||||
|
public struct Message
|
||||||
|
{
|
||||||
|
public int connectionId;
|
||||||
|
public EventType eventType;
|
||||||
|
public byte[] data;
|
||||||
|
public Message(int connectionId, EventType eventType, byte[] data)
|
||||||
|
{
|
||||||
|
this.connectionId = connectionId;
|
||||||
|
this.eventType = eventType;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool clientConnected;
|
||||||
|
public Queue<Message> clientIncoming = new Queue<Message>();
|
||||||
|
bool serverActive;
|
||||||
|
public Queue<Message> serverIncoming = new Queue<Message>();
|
||||||
|
|
||||||
|
public override bool Available() => true;
|
||||||
|
// limit max size to something reasonable so pool doesn't allocate
|
||||||
|
// int.MaxValue = 2GB each time.
|
||||||
|
public override int GetMaxPacketSize(int channelId) => ushort.MaxValue;
|
||||||
|
// 1400 max batch size
|
||||||
|
// -> need something != GetMaxPacketSize for testing
|
||||||
|
// -> MTU aka 1400 is used a lot anyway
|
||||||
|
public override int GetBatchThreshold(int channelId) => 1400;
|
||||||
|
public override void Shutdown() {}
|
||||||
|
public override bool ClientConnected() => clientConnected;
|
||||||
|
public override void ClientConnect(string address)
|
||||||
|
{
|
||||||
|
// only if server is running
|
||||||
|
if (serverActive)
|
||||||
|
{
|
||||||
|
// add server connected message with connId=1 because 0 is reserved
|
||||||
|
serverIncoming.Enqueue(new Message(1, EventType.Connected, null));
|
||||||
|
|
||||||
|
// add client connected message
|
||||||
|
clientIncoming.Enqueue(new Message(0, EventType.Connected, null));
|
||||||
|
|
||||||
|
clientConnected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void ClientSend(ArraySegment<byte> segment, int channelId)
|
||||||
|
{
|
||||||
|
// only if client connected
|
||||||
|
if (clientConnected)
|
||||||
|
{
|
||||||
|
// a real transport fails for > max sized messages.
|
||||||
|
// mirror checks it, but let's guarantee that we catch > max
|
||||||
|
// sized message send attempts just like a real transport would.
|
||||||
|
// => helps to cover packet size issues i.e. for timestamp
|
||||||
|
// batching tests
|
||||||
|
int max = GetMaxPacketSize(channelId);
|
||||||
|
if (segment.Count > max)
|
||||||
|
throw new Exception($"MemoryTransport ClientSend of {segment.Count} bytes exceeds max of {max} bytes");
|
||||||
|
|
||||||
|
// copy segment data because it's only valid until return
|
||||||
|
byte[] data = new byte[segment.Count];
|
||||||
|
Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
|
||||||
|
|
||||||
|
// add server data message with connId=1 because 0 is reserved
|
||||||
|
serverIncoming.Enqueue(new Message(1, EventType.Data, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override void ClientDisconnect()
|
||||||
|
{
|
||||||
|
// only if client connected
|
||||||
|
if (clientConnected)
|
||||||
|
{
|
||||||
|
// clear all pending messages that we may have received.
|
||||||
|
// over the wire, we wouldn't receive any more pending messages
|
||||||
|
// ether after calling disconnect.
|
||||||
|
clientIncoming.Clear();
|
||||||
|
|
||||||
|
// add server disconnected message with connId=1 because 0 is reserved
|
||||||
|
serverIncoming.Enqueue(new Message(1, EventType.Disconnected, null));
|
||||||
|
|
||||||
|
// add client disconnected message
|
||||||
|
clientIncoming.Enqueue(new Message(0, EventType.Disconnected, null));
|
||||||
|
|
||||||
|
// not connected anymore
|
||||||
|
clientConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// messages should always be processed in early update
|
||||||
|
public override void ClientEarlyUpdate()
|
||||||
|
{
|
||||||
|
// note: process even if not connected because when calling
|
||||||
|
// Disconnect, we add a Disconnected event which still needs to be
|
||||||
|
// processed here.
|
||||||
|
while (clientIncoming.Count > 0)
|
||||||
|
{
|
||||||
|
Message message = clientIncoming.Dequeue();
|
||||||
|
switch (message.eventType)
|
||||||
|
{
|
||||||
|
case EventType.Connected:
|
||||||
|
Debug.Log("MemoryTransport Client Message: Connected");
|
||||||
|
OnClientConnected.Invoke();
|
||||||
|
break;
|
||||||
|
case EventType.Data:
|
||||||
|
Debug.Log($"MemoryTransport Client Message: Data: {BitConverter.ToString(message.data)}");
|
||||||
|
OnClientDataReceived.Invoke(new ArraySegment<byte>(message.data), 0);
|
||||||
|
break;
|
||||||
|
case EventType.Disconnected:
|
||||||
|
Debug.Log("MemoryTransport Client Message: Disconnected");
|
||||||
|
OnClientDisconnected.Invoke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ServerActive() => serverActive;
|
||||||
|
public override Uri ServerUri() => throw new NotImplementedException();
|
||||||
|
public override void ServerStart() { serverActive = true; }
|
||||||
|
public override void ServerSend(int connectionId, ArraySegment<byte> segment, int channelId)
|
||||||
|
{
|
||||||
|
// only if server is running and client is connected
|
||||||
|
if (serverActive && clientConnected)
|
||||||
|
{
|
||||||
|
// a real transport fails for > max sized messages.
|
||||||
|
// mirror checks it, but let's guarantee that we catch > max
|
||||||
|
// sized message send attempts just like a real transport would.
|
||||||
|
// => helps to cover packet size issues i.e. for timestamp
|
||||||
|
// batching tests
|
||||||
|
int max = GetMaxPacketSize(channelId);
|
||||||
|
if (segment.Count > max)
|
||||||
|
throw new Exception($"MemoryTransport ServerSend of {segment.Count} bytes exceeds max of {max} bytes");
|
||||||
|
|
||||||
|
// copy segment data because it's only valid until return
|
||||||
|
byte[] data = new byte[segment.Count];
|
||||||
|
Array.Copy(segment.Array, segment.Offset, data, 0, segment.Count);
|
||||||
|
|
||||||
|
// add client data message
|
||||||
|
clientIncoming.Enqueue(new Message(0, EventType.Data, data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ServerDisconnect(int connectionId)
|
||||||
|
{
|
||||||
|
// clear all pending messages that we may have received.
|
||||||
|
// over the wire, we wouldn't receive any more pending messages
|
||||||
|
// ether after calling disconnect.
|
||||||
|
serverIncoming.Clear();
|
||||||
|
|
||||||
|
// add client disconnected message with connectionId
|
||||||
|
clientIncoming.Enqueue(new Message(connectionId, EventType.Disconnected, null));
|
||||||
|
|
||||||
|
// add server disconnected message with connectionId
|
||||||
|
serverIncoming.Enqueue(new Message(connectionId, EventType.Disconnected, null));
|
||||||
|
|
||||||
|
// not active anymore
|
||||||
|
serverActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ServerGetClientAddress(int connectionId) => string.Empty;
|
||||||
|
public override void ServerStop()
|
||||||
|
{
|
||||||
|
// clear all pending messages that we may have received.
|
||||||
|
// over the wire, we wouldn't receive any more pending messages
|
||||||
|
// ether after calling stop.
|
||||||
|
serverIncoming.Clear();
|
||||||
|
|
||||||
|
// add client disconnected message
|
||||||
|
clientIncoming.Enqueue(new Message(0, EventType.Disconnected, null));
|
||||||
|
|
||||||
|
// add server disconnected message with connId=1 because 0 is reserved
|
||||||
|
serverIncoming.Enqueue(new Message(1, EventType.Disconnected, null));
|
||||||
|
|
||||||
|
// not active anymore
|
||||||
|
serverActive = false;
|
||||||
|
}
|
||||||
|
// messages should always be processed in early update
|
||||||
|
public override void ServerEarlyUpdate()
|
||||||
|
{
|
||||||
|
while (serverIncoming.Count > 0)
|
||||||
|
{
|
||||||
|
Message message = serverIncoming.Dequeue();
|
||||||
|
switch (message.eventType)
|
||||||
|
{
|
||||||
|
case EventType.Connected:
|
||||||
|
Debug.Log("MemoryTransport Server Message: Connected");
|
||||||
|
OnServerConnected.Invoke(message.connectionId);
|
||||||
|
break;
|
||||||
|
case EventType.Data:
|
||||||
|
Debug.Log($"MemoryTransport Server Message: Data: {BitConverter.ToString(message.data)}");
|
||||||
|
OnServerDataReceived.Invoke(message.connectionId, new ArraySegment<byte>(message.data), 0);
|
||||||
|
break;
|
||||||
|
case EventType.Disconnected:
|
||||||
|
Debug.Log("MemoryTransport Server Message: Disconnected");
|
||||||
|
OnServerDisconnected.Invoke(message.connectionId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Common/MemoryTransport.cs.meta
Normal file
11
Assets/Mirror/Tests/Common/MemoryTransport.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6131cf1e8a1c14ef5b5253f86f3fc9c9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
16
Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef
Normal file
16
Assets/Mirror/Tests/Common/Mirror.Tests.Common.asmdef
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "Mirror.Tests.Common",
|
||||||
|
"references": [
|
||||||
|
"Mirror"
|
||||||
|
],
|
||||||
|
"optionalUnityReferences": [
|
||||||
|
"TestAssemblies"
|
||||||
|
],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": []
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4e9aca8a359ab48de906aedbfa1ffe21
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
14
Assets/Mirror/Tests/Common/MirrorEditModeTest.cs
Normal file
14
Assets/Mirror/Tests/Common/MirrorEditModeTest.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// base class for networking tests to make things easier.
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public abstract class MirrorEditModeTest : MirrorTest
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp() => base.SetUp();
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown() => base.TearDown();
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Common/MirrorEditModeTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Common/MirrorEditModeTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a6110480a9c07423290301aedafb2a93
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
27
Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs
Normal file
27
Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// base class for networking tests to make things easier.
|
||||||
|
using System.Collections;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public abstract class MirrorPlayModeTest : MirrorTest
|
||||||
|
{
|
||||||
|
// when overwriting, call it like this:
|
||||||
|
// yield return base.UnitySetUp();
|
||||||
|
[UnitySetUp]
|
||||||
|
public virtual IEnumerator UnitySetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when overwriting, call it like this:
|
||||||
|
// yield return base.UnityTearDown();
|
||||||
|
[UnityTearDown]
|
||||||
|
public virtual IEnumerator UnityTearDown()
|
||||||
|
{
|
||||||
|
base.TearDown();
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Common/MirrorPlayModeTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: be3f9e24bcdb748728f846e88eea29f3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
557
Assets/Mirror/Tests/Common/MirrorTest.cs
Normal file
557
Assets/Mirror/Tests/Common/MirrorTest.cs
Normal file
@ -0,0 +1,557 @@
|
|||||||
|
// base class for networking tests to make things easier.
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
// inherited by MirrorEditModeTest / MirrorPlayModeTest
|
||||||
|
// to call SetUp/TearDown by [SetUp]/[UnitySetUp] as needed
|
||||||
|
public abstract class MirrorTest
|
||||||
|
{
|
||||||
|
// keep track of networked GameObjects so we don't have to clean them
|
||||||
|
// up manually each time.
|
||||||
|
// CreateNetworked() adds to the list automatically.
|
||||||
|
public List<GameObject> instantiated;
|
||||||
|
|
||||||
|
// we usually need the memory transport
|
||||||
|
public MemoryTransport transport;
|
||||||
|
|
||||||
|
public virtual void SetUp()
|
||||||
|
{
|
||||||
|
instantiated = new List<GameObject>();
|
||||||
|
|
||||||
|
// need a transport to send & receive
|
||||||
|
Transport.activeTransport = transport = new GameObject().AddComponent<MemoryTransport>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void TearDown()
|
||||||
|
{
|
||||||
|
NetworkClient.Shutdown();
|
||||||
|
NetworkServer.Shutdown();
|
||||||
|
|
||||||
|
// some tests might modify NetworkServer.connections without ever
|
||||||
|
// starting the server.
|
||||||
|
// NetworkServer.Shutdown() only clears connections if it was started.
|
||||||
|
// so let's do it manually for proper test cleanup here.
|
||||||
|
NetworkServer.connections.Clear();
|
||||||
|
|
||||||
|
foreach (GameObject go in instantiated)
|
||||||
|
if (go != null)
|
||||||
|
GameObject.DestroyImmediate(go);
|
||||||
|
|
||||||
|
GameObject.DestroyImmediate(transport.gameObject);
|
||||||
|
Transport.activeTransport = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a tracked GameObject for tests without Networkidentity
|
||||||
|
// add to tracker list if needed (useful for cleanups afterwards)
|
||||||
|
protected void CreateGameObject(out GameObject go)
|
||||||
|
{
|
||||||
|
go = new GameObject();
|
||||||
|
// track
|
||||||
|
instantiated.Add(go);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + MonoBehaviour<T>
|
||||||
|
// add to tracker list if needed (useful for cleanups afterwards)
|
||||||
|
protected void CreateGameObject<T>(out GameObject go, out T component)
|
||||||
|
where T : MonoBehaviour
|
||||||
|
{
|
||||||
|
CreateGameObject(out go);
|
||||||
|
component = go.AddComponent<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity
|
||||||
|
// add to tracker list if needed (useful for cleanups afterwards)
|
||||||
|
protected void CreateNetworked(out GameObject go, out NetworkIdentity identity)
|
||||||
|
{
|
||||||
|
go = new GameObject();
|
||||||
|
identity = go.AddComponent<NetworkIdentity>();
|
||||||
|
// Awake is only called in play mode.
|
||||||
|
// call manually for initialization.
|
||||||
|
identity.Awake();
|
||||||
|
// track
|
||||||
|
instantiated.Add(go);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour<T>
|
||||||
|
// add to tracker list if needed (useful for cleanups afterwards)
|
||||||
|
protected void CreateNetworked<T>(out GameObject go, out NetworkIdentity identity, out T component)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
{
|
||||||
|
go = new GameObject();
|
||||||
|
identity = go.AddComponent<NetworkIdentity>();
|
||||||
|
component = go.AddComponent<T>();
|
||||||
|
// always set syncinterval = 0 for immediate testing
|
||||||
|
component.syncInterval = 0;
|
||||||
|
// Awake is only called in play mode.
|
||||||
|
// call manually for initialization.
|
||||||
|
identity.Awake();
|
||||||
|
// track
|
||||||
|
instantiated.Add(go);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + 2x NetworkBehaviour<T>
|
||||||
|
// add to tracker list if needed (useful for cleanups afterwards)
|
||||||
|
protected void CreateNetworked<T, U>(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
where U : NetworkBehaviour
|
||||||
|
{
|
||||||
|
go = new GameObject();
|
||||||
|
identity = go.AddComponent<NetworkIdentity>();
|
||||||
|
componentA = go.AddComponent<T>();
|
||||||
|
componentB = go.AddComponent<U>();
|
||||||
|
// always set syncinterval = 0 for immediate testing
|
||||||
|
componentA.syncInterval = 0;
|
||||||
|
componentB.syncInterval = 0;
|
||||||
|
// Awake is only called in play mode.
|
||||||
|
// call manually for initialization.
|
||||||
|
identity.Awake();
|
||||||
|
// track
|
||||||
|
instantiated.Add(go);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + 2x NetworkBehaviour<T>
|
||||||
|
// add to tracker list if needed (useful for cleanups afterwards)
|
||||||
|
protected void CreateNetworked<T, U, V>(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB, out V componentC)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
where U : NetworkBehaviour
|
||||||
|
where V : NetworkBehaviour
|
||||||
|
{
|
||||||
|
go = new GameObject();
|
||||||
|
identity = go.AddComponent<NetworkIdentity>();
|
||||||
|
componentA = go.AddComponent<T>();
|
||||||
|
componentB = go.AddComponent<U>();
|
||||||
|
componentC = go.AddComponent<V>();
|
||||||
|
// always set syncinterval = 0 for immediate testing
|
||||||
|
componentA.syncInterval = 0;
|
||||||
|
componentB.syncInterval = 0;
|
||||||
|
componentC.syncInterval = 0;
|
||||||
|
// Awake is only called in play mode.
|
||||||
|
// call manually for initialization.
|
||||||
|
identity.Awake();
|
||||||
|
// track
|
||||||
|
instantiated.Add(go);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
protected void CreateNetworkedAndSpawn(out GameObject go, out NetworkIdentity identity, NetworkConnection ownerConnection = null)
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
CreateNetworked(out go, out identity);
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(go, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
// => returns objects from client and from server.
|
||||||
|
// will be same in host mode.
|
||||||
|
protected void CreateNetworkedAndSpawn(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity,
|
||||||
|
NetworkConnection ownerConnection = null)
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create one on server, one on client
|
||||||
|
// (spawning has to find it on client, it doesn't create it)
|
||||||
|
CreateNetworked(out serverGO, out serverIdentity);
|
||||||
|
CreateNetworked(out clientGO, out clientIdentity);
|
||||||
|
|
||||||
|
// give both a scene id and register it on client for spawnables
|
||||||
|
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||||
|
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(serverGO, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// make sure the client really spawned it.
|
||||||
|
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
protected void CreateNetworkedAndSpawn<T>(out GameObject go, out NetworkIdentity identity, out T component, NetworkConnection ownerConnection = null)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
CreateNetworked(out go, out identity, out component);
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(go, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// double check that we have authority if we passed an owner connection
|
||||||
|
if (ownerConnection != null)
|
||||||
|
Debug.Assert(component.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
// => returns objects from client and from server.
|
||||||
|
// will be same in host mode.
|
||||||
|
protected void CreateNetworkedAndSpawn<T>(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponent,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponent,
|
||||||
|
NetworkConnection ownerConnection = null)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create one on server, one on client
|
||||||
|
// (spawning has to find it on client, it doesn't create it)
|
||||||
|
CreateNetworked(out serverGO, out serverIdentity, out serverComponent);
|
||||||
|
CreateNetworked(out clientGO, out clientIdentity, out clientComponent);
|
||||||
|
|
||||||
|
// give both a scene id and register it on client for spawnables
|
||||||
|
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||||
|
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(serverGO, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// double check that we have authority if we passed an owner connection
|
||||||
|
if (ownerConnection != null)
|
||||||
|
Debug.Assert(serverComponent.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
|
||||||
|
// make sure the client really spawned it.
|
||||||
|
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
protected void CreateNetworkedAndSpawn<T, U>(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB, NetworkConnection ownerConnection = null)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
where U : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
CreateNetworked(out go, out identity, out componentA, out componentB);
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(go, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// double check that we have authority if we passed an owner connection
|
||||||
|
if (ownerConnection != null)
|
||||||
|
{
|
||||||
|
Debug.Assert(componentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
Debug.Assert(componentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
// => returns objects from client and from server.
|
||||||
|
// will be same in host mode.
|
||||||
|
protected void CreateNetworkedAndSpawn<T, U>(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponentA, out U serverComponentB,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponentA, out U clientComponentB,
|
||||||
|
NetworkConnection ownerConnection = null)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
where U : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create one on server, one on client
|
||||||
|
// (spawning has to find it on client, it doesn't create it)
|
||||||
|
CreateNetworked(out serverGO, out serverIdentity, out serverComponentA, out serverComponentB);
|
||||||
|
CreateNetworked(out clientGO, out clientIdentity, out clientComponentA, out clientComponentB);
|
||||||
|
|
||||||
|
// give both a scene id and register it on client for spawnables
|
||||||
|
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||||
|
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(serverGO, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// double check that we have authority if we passed an owner connection
|
||||||
|
if (ownerConnection != null)
|
||||||
|
{
|
||||||
|
Debug.Assert(serverComponentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
Debug.Assert(serverComponentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the client really spawned it.
|
||||||
|
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
protected void CreateNetworkedAndSpawn<T, U, V>(out GameObject go, out NetworkIdentity identity, out T componentA, out U componentB, out V componentC, NetworkConnection ownerConnection = null)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
where U : NetworkBehaviour
|
||||||
|
where V : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
CreateNetworked(out go, out identity, out componentA, out componentB, out componentC);
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(go, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// double check that we have authority if we passed an owner connection
|
||||||
|
if (ownerConnection != null)
|
||||||
|
{
|
||||||
|
Debug.Assert(componentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
Debug.Assert(componentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
Debug.Assert(componentC.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||||
|
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||||
|
// => returns objects from client and from server.
|
||||||
|
// will be same in host mode.
|
||||||
|
protected void CreateNetworkedAndSpawn<T, U, V>(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponentA, out U serverComponentB, out V serverComponentC,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponentA, out U clientComponentB, out V clientComponentC,
|
||||||
|
NetworkConnection ownerConnection = null)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
where U : NetworkBehaviour
|
||||||
|
where V : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create one on server, one on client
|
||||||
|
// (spawning has to find it on client, it doesn't create it)
|
||||||
|
CreateNetworked(out serverGO, out serverIdentity, out serverComponentA, out serverComponentB, out serverComponentC);
|
||||||
|
CreateNetworked(out clientGO, out clientIdentity, out clientComponentA, out clientComponentB, out clientComponentC);
|
||||||
|
|
||||||
|
// give both a scene id and register it on client for spawnables
|
||||||
|
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||||
|
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||||
|
|
||||||
|
// spawn
|
||||||
|
NetworkServer.Spawn(serverGO, ownerConnection);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// double check that we have authority if we passed an owner connection
|
||||||
|
if (ownerConnection != null)
|
||||||
|
{
|
||||||
|
Debug.Assert(serverComponentA.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
Debug.Assert(serverComponentB.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
Debug.Assert(serverComponentC.hasAuthority == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the client really spawned it.
|
||||||
|
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
|
||||||
|
// often times, we really need a player object for the client to receive
|
||||||
|
// certain messages.
|
||||||
|
protected void CreateNetworkedAndSpawnPlayer(out GameObject go, out NetworkIdentity identity, NetworkConnection ownerConnection)
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create a networked object
|
||||||
|
CreateNetworked(out go, out identity);
|
||||||
|
|
||||||
|
// add as player & process spawn message on client.
|
||||||
|
NetworkServer.AddPlayerForConnection(ownerConnection, go);
|
||||||
|
ProcessMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
|
||||||
|
// often times, we really need a player object for the client to receive
|
||||||
|
// certain messages.
|
||||||
|
// => returns objects from client and from server.
|
||||||
|
// will be same in host mode.
|
||||||
|
protected void CreateNetworkedAndSpawnPlayer(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity,
|
||||||
|
NetworkConnection ownerConnection)
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create one on server, one on client
|
||||||
|
// (spawning has to find it on client, it doesn't create it)
|
||||||
|
CreateNetworked(out serverGO, out serverIdentity);
|
||||||
|
CreateNetworked(out clientGO, out clientIdentity);
|
||||||
|
|
||||||
|
// give both a scene id and register it on client for spawnables
|
||||||
|
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||||
|
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||||
|
|
||||||
|
// add as player & process spawn message on client.
|
||||||
|
NetworkServer.AddPlayerForConnection(ownerConnection, serverGO);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// make sure the client really spawned it.
|
||||||
|
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
|
||||||
|
// often times, we really need a player object for the client to receive
|
||||||
|
// certain messages.
|
||||||
|
protected void CreateNetworkedAndSpawnPlayer<T>(out GameObject go, out NetworkIdentity identity, out T component, NetworkConnection ownerConnection)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create a networked object
|
||||||
|
CreateNetworked(out go, out identity, out component);
|
||||||
|
|
||||||
|
// add as player & process spawn message on client.
|
||||||
|
NetworkServer.AddPlayerForConnection(ownerConnection, go);
|
||||||
|
ProcessMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN PLAYER.
|
||||||
|
// often times, we really need a player object for the client to receive
|
||||||
|
// certain messages.
|
||||||
|
// => returns objects from client and from server.
|
||||||
|
// will be same in host mode.
|
||||||
|
protected void CreateNetworkedAndSpawnPlayer<T>(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity, out T serverComponent,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity, out T clientComponent,
|
||||||
|
NetworkConnection ownerConnection)
|
||||||
|
where T : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// server & client need to be active before spawning
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// create one on server, one on client
|
||||||
|
// (spawning has to find it on client, it doesn't create it)
|
||||||
|
CreateNetworked(out serverGO, out serverIdentity, out serverComponent);
|
||||||
|
CreateNetworked(out clientGO, out clientIdentity, out clientComponent);
|
||||||
|
|
||||||
|
// give both a scene id and register it on client for spawnables
|
||||||
|
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||||
|
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||||
|
|
||||||
|
// add as player & process spawn message on client.
|
||||||
|
NetworkServer.AddPlayerForConnection(ownerConnection, serverGO);
|
||||||
|
ProcessMessages();
|
||||||
|
|
||||||
|
// make sure the client really spawned it.
|
||||||
|
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully connect client to local server
|
||||||
|
// gives out the server's connection to client for convenience if needed
|
||||||
|
protected void ConnectClientBlocking(out NetworkConnectionToClient connectionToClient)
|
||||||
|
{
|
||||||
|
NetworkClient.Connect("127.0.0.1");
|
||||||
|
UpdateTransport();
|
||||||
|
|
||||||
|
Assert.That(NetworkServer.connections.Count, Is.EqualTo(1));
|
||||||
|
connectionToClient = NetworkServer.connections.Values.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully connect client to local server & authenticate
|
||||||
|
protected void ConnectClientBlockingAuthenticated(out NetworkConnectionToClient connectionToClient)
|
||||||
|
{
|
||||||
|
ConnectClientBlocking(out connectionToClient);
|
||||||
|
|
||||||
|
// authenticate server & client connections
|
||||||
|
connectionToClient.isAuthenticated = true;
|
||||||
|
NetworkClient.connection.isAuthenticated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully connect client to local server & authenticate & set read
|
||||||
|
protected void ConnectClientBlockingAuthenticatedAndReady(out NetworkConnectionToClient connectionToClient)
|
||||||
|
{
|
||||||
|
ConnectClientBlocking(out connectionToClient);
|
||||||
|
|
||||||
|
// authenticate server & client connections
|
||||||
|
connectionToClient.isAuthenticated = true;
|
||||||
|
NetworkClient.connection.isAuthenticated = true;
|
||||||
|
|
||||||
|
// set ready
|
||||||
|
NetworkClient.Ready();
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(connectionToClient.isReady, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully connect HOST client to local server
|
||||||
|
// sets NetworkServer.localConnection / NetworkClient.connection.
|
||||||
|
protected void ConnectHostClientBlocking()
|
||||||
|
{
|
||||||
|
NetworkClient.ConnectHost();
|
||||||
|
NetworkClient.ConnectLocalServer();
|
||||||
|
UpdateTransport();
|
||||||
|
Assert.That(NetworkServer.connections.Count, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully connect client to local server & authenticate & set read
|
||||||
|
protected void ConnectHostClientBlockingAuthenticatedAndReady()
|
||||||
|
{
|
||||||
|
ConnectHostClientBlocking();
|
||||||
|
|
||||||
|
// authenticate server & client connections
|
||||||
|
NetworkServer.localConnection.isAuthenticated = true;
|
||||||
|
NetworkClient.connection.isAuthenticated = true;
|
||||||
|
|
||||||
|
// set ready
|
||||||
|
NetworkClient.Ready();
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(NetworkServer.localConnection.isReady, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateTransport()
|
||||||
|
{
|
||||||
|
transport.ClientEarlyUpdate();
|
||||||
|
transport.ServerEarlyUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ProcessMessages()
|
||||||
|
{
|
||||||
|
// server & client need to be active
|
||||||
|
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||||
|
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||||
|
|
||||||
|
// update server & client so batched messages are flushed
|
||||||
|
NetworkClient.NetworkLateUpdate();
|
||||||
|
NetworkServer.NetworkLateUpdate();
|
||||||
|
|
||||||
|
// update transport so sent messages are received
|
||||||
|
UpdateTransport();
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to create local connection pair
|
||||||
|
protected void CreateLocalConnectionPair(out LocalConnectionToClient connectionToClient, out LocalConnectionToServer connectionToServer)
|
||||||
|
{
|
||||||
|
connectionToClient = new LocalConnectionToClient();
|
||||||
|
connectionToServer = new LocalConnectionToServer();
|
||||||
|
connectionToClient.connectionToServer = connectionToServer;
|
||||||
|
connectionToServer.connectionToClient = connectionToClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Common/MirrorTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Common/MirrorTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 67c5177a4b35749b8b9c4ca7107d8c25
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Assets/Mirror/Tests/Common/NSubstitute.dll
Normal file
BIN
Assets/Mirror/Tests/Common/NSubstitute.dll
Normal file
Binary file not shown.
112
Assets/Mirror/Tests/Common/NSubstitute.dll.meta
Normal file
112
Assets/Mirror/Tests/Common/NSubstitute.dll.meta
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 601589975b5ca43179df797ffa3b468d
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
'': Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux: 1
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude LinuxUniversal: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude WebGL: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
- first:
|
||||||
|
Facebook: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Facebook: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Linux
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: LinuxUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll
Normal file
BIN
Assets/Mirror/Tests/Common/System.Threading.Tasks.Extensions.dll
Normal file
Binary file not shown.
@ -0,0 +1,117 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 00713e0dc7f8d4ed2906179677779859
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
'': Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux: 1
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude LinuxUniversal: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude WebGL: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
- first:
|
||||||
|
Facebook: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Facebook: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Linux
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: LinuxUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
WebGL: WebGL
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/Mirror/Tests/Editor.meta
Normal file
8
Assets/Mirror/Tests/Editor.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1d3db979f8f114547977d68180a77080
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
3
Assets/Mirror/Tests/Editor/Batching.meta
Normal file
3
Assets/Mirror/Tests/Editor/Batching.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6d113040314b4578b93a6f140f064f09
|
||||||
|
timeCreated: 1623240703
|
230
Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs
Normal file
230
Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.Batching
|
||||||
|
{
|
||||||
|
public class BatcherTests
|
||||||
|
{
|
||||||
|
Batcher batcher;
|
||||||
|
const int Threshold = 8 + 4; // 8 bytes timestamp + 4 bytes message
|
||||||
|
NetworkWriter writer;
|
||||||
|
|
||||||
|
// timestamp and serialized timestamp for convenience
|
||||||
|
const double TimeStamp = Math.PI;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
batcher = new Batcher(Threshold);
|
||||||
|
writer = new NetworkWriter();
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to create a batch prefixed by timestamp
|
||||||
|
public static byte[] ConcatTimestamp(double tickTimeStamp, byte[] data)
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
writer.WriteDouble(tickTimeStamp);
|
||||||
|
writer.WriteBytes(data, 0, data.Length);
|
||||||
|
return writer.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddMessage()
|
||||||
|
{
|
||||||
|
byte[] message = {0x01, 0x02};
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_OnlyAcceptsFreshWriter()
|
||||||
|
{
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x01}));
|
||||||
|
|
||||||
|
writer.WriteByte(0);
|
||||||
|
Assert.Throws<ArgumentException>(() => {
|
||||||
|
batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_NoMessage()
|
||||||
|
{
|
||||||
|
// make batch with no message
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_OneMessage()
|
||||||
|
{
|
||||||
|
// add message
|
||||||
|
byte[] message = {0x01, 0x02};
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(message));
|
||||||
|
|
||||||
|
// make batch
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_MultipleMessages_AlmostFullBatch()
|
||||||
|
{
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x01, 0x02}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x03}));
|
||||||
|
|
||||||
|
// make batch
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02, 0x03})));
|
||||||
|
|
||||||
|
// there should be no more batches to make
|
||||||
|
Assert.That(batcher.MakeNextBatch(writer, TimeStamp), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_MultipleMessages_ExactlyFullBatch()
|
||||||
|
{
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x01, 0x02}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x03, 0x04}));
|
||||||
|
|
||||||
|
// make batch
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02, 0x03, 0x04})));
|
||||||
|
|
||||||
|
// there should be no more batches to make
|
||||||
|
Assert.That(batcher.MakeNextBatch(writer, TimeStamp), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_MultipleMessages_MoreThanOneBatch()
|
||||||
|
{
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x01, 0x02}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x03, 0x04}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x05}));
|
||||||
|
|
||||||
|
// first batch
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02, 0x03, 0x04})));
|
||||||
|
|
||||||
|
// reset writer
|
||||||
|
writer.Position = 0;
|
||||||
|
|
||||||
|
// second batch
|
||||||
|
result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x05})));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_MultipleMessages_Small_Giant_Small()
|
||||||
|
{
|
||||||
|
// small, too big to include in batch, small
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x01}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x02, 0x03, 0x04, 0x05}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x06, 0x07}));
|
||||||
|
|
||||||
|
// first batch
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01})));
|
||||||
|
|
||||||
|
// reset writer
|
||||||
|
writer.Position = 0;
|
||||||
|
|
||||||
|
// second batch
|
||||||
|
result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x02, 0x03, 0x04, 0x05})));
|
||||||
|
|
||||||
|
// reset writer
|
||||||
|
writer.Position = 0;
|
||||||
|
|
||||||
|
// third batch
|
||||||
|
result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
|
||||||
|
// check result: <<tickTimeStamp:8, message>>
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x06, 0x07})));
|
||||||
|
}
|
||||||
|
|
||||||
|
// messages > threshold should simply be single batches.
|
||||||
|
// those need to be supported too, for example:
|
||||||
|
// kcp prefers MTU sized batches
|
||||||
|
// but we still allow up to 144 KB max message size
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_LargerThanThreshold()
|
||||||
|
{
|
||||||
|
// make a larger than threshold message
|
||||||
|
byte[] large = new byte[Threshold + 1];
|
||||||
|
for (int i = 0; i < Threshold + 1; ++i)
|
||||||
|
large[i] = (byte)i;
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(large));
|
||||||
|
|
||||||
|
// result should be only the large message
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, large)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// messages > threshold should simply be single batches.
|
||||||
|
// those need to be supported too, for example:
|
||||||
|
// kcp prefers MTU sized batches
|
||||||
|
// but we still allow up to 144 KB max message size
|
||||||
|
[Test]
|
||||||
|
public void MakeNextBatch_LargerThanThreshold_BetweenSmallerMessages()
|
||||||
|
{
|
||||||
|
// make a larger than threshold message
|
||||||
|
byte[] large = new byte[Threshold + 1];
|
||||||
|
for (int i = 0; i < Threshold + 1; ++i)
|
||||||
|
large[i] = (byte)i;
|
||||||
|
|
||||||
|
// add two small, one large, two small messages.
|
||||||
|
// to make sure everything around it is still batched,
|
||||||
|
// and the large one is a separate batch.
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x01}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x02}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(large));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x03}));
|
||||||
|
batcher.AddMessage(new ArraySegment<byte>(new byte[]{0x04}));
|
||||||
|
|
||||||
|
// first batch should be the two small messages
|
||||||
|
bool result = batcher.MakeNextBatch(writer, TimeStamp);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02})));
|
||||||
|
|
||||||
|
// reset writer
|
||||||
|
writer.Position = 0;
|
||||||
|
|
||||||
|
// second batch should be only the large message
|
||||||
|
result = batcher.MakeNextBatch(writer, TimeStamp + 1);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp + 1, large)));
|
||||||
|
|
||||||
|
// reset writer
|
||||||
|
writer.Position = 0;
|
||||||
|
|
||||||
|
// third batch be the two small messages
|
||||||
|
result = batcher.MakeNextBatch(writer, TimeStamp + 2);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
Assert.That(writer.ToArray().SequenceEqual(ConcatTimestamp(TimeStamp + 2, new byte[]{0x03, 0x04})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/Batching/BatcherTests.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 787d83b7e2ca4547aca251617d91f7d8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
138
Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs
Normal file
138
Assets/Mirror/Tests/Editor/Batching/UnbatcherTests.cs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.Batching
|
||||||
|
{
|
||||||
|
public class UnbatcherTests
|
||||||
|
{
|
||||||
|
Unbatcher unbatcher;
|
||||||
|
const double TimeStamp = Math.PI;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
unbatcher = new Unbatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetNextMessage_NoBatches()
|
||||||
|
{
|
||||||
|
bool result = unbatcher.GetNextMessage(out _, out _);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for nimoyd bug, where calling getnextmessage after the previous
|
||||||
|
// call already returned false would cause an InvalidOperationException.
|
||||||
|
[Test]
|
||||||
|
public void GetNextMessage_True_False_False_InvalidOperationException()
|
||||||
|
{
|
||||||
|
// add batch
|
||||||
|
byte[] batch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[2]);
|
||||||
|
unbatcher.AddBatch(new ArraySegment<byte>(batch));
|
||||||
|
|
||||||
|
// get next message, pretend we read the whole thing
|
||||||
|
bool result = unbatcher.GetNextMessage(out NetworkReader reader, out _);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
reader.Position = reader.Length;
|
||||||
|
|
||||||
|
// shouldn't get another one
|
||||||
|
result = unbatcher.GetNextMessage(out reader, out _);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
|
||||||
|
// calling it again was causing "InvalidOperationException: Queue empty"
|
||||||
|
result = unbatcher.GetNextMessage(out reader, out _);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetNextMessage_OneBatch()
|
||||||
|
{
|
||||||
|
// add one batch
|
||||||
|
byte[] batch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02});
|
||||||
|
unbatcher.AddBatch(new ArraySegment<byte>(batch));
|
||||||
|
|
||||||
|
// get next message, read first byte
|
||||||
|
bool result = unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimeStamp);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x01));
|
||||||
|
Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
|
||||||
|
|
||||||
|
// get next message, read last byte
|
||||||
|
result = unbatcher.GetNextMessage(out reader, out remoteTimeStamp);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x02));
|
||||||
|
Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
|
||||||
|
|
||||||
|
// there should be no more messages
|
||||||
|
result = unbatcher.GetNextMessage(out _, out _);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetNextMessage_MultipleBatches()
|
||||||
|
{
|
||||||
|
// add first batch
|
||||||
|
byte[] firstBatch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02});
|
||||||
|
unbatcher.AddBatch(new ArraySegment<byte>(firstBatch));
|
||||||
|
|
||||||
|
// add second batch
|
||||||
|
byte[] secondBatch = BatcherTests.ConcatTimestamp(TimeStamp + 1, new byte[]{0x03, 0x04});
|
||||||
|
unbatcher.AddBatch(new ArraySegment<byte>(secondBatch));
|
||||||
|
|
||||||
|
// get next message, read everything
|
||||||
|
bool result = unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimeStamp);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x01));
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x02));
|
||||||
|
Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
|
||||||
|
|
||||||
|
// get next message, should point to next batch at Timestamp + 1
|
||||||
|
result = unbatcher.GetNextMessage(out reader, out remoteTimeStamp);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x03));
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x04));
|
||||||
|
Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp + 1));
|
||||||
|
|
||||||
|
// there should be no more messages
|
||||||
|
result = unbatcher.GetNextMessage(out _, out _);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure that retiring a batch, then adding a new batch works.
|
||||||
|
// previously there was a bug where the batch was retired,
|
||||||
|
// the reader still pointed to the old batch with pos=len,
|
||||||
|
// a new batch was added
|
||||||
|
// GetNextMessage() still returned false because reader still pointed to
|
||||||
|
// the old batch with pos=len.
|
||||||
|
[Test]
|
||||||
|
public void RetireBatchAndTryNewBatch()
|
||||||
|
{
|
||||||
|
// add first batch
|
||||||
|
byte[] firstBatch = BatcherTests.ConcatTimestamp(TimeStamp, new byte[]{0x01, 0x02});
|
||||||
|
unbatcher.AddBatch(new ArraySegment<byte>(firstBatch));
|
||||||
|
|
||||||
|
// read everything
|
||||||
|
bool result = unbatcher.GetNextMessage(out NetworkReader reader, out double remoteTimeStamp);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x01));
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x02));
|
||||||
|
Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp));
|
||||||
|
|
||||||
|
// try to read again.
|
||||||
|
// reader will be at limit, which should retire the batch.
|
||||||
|
result = unbatcher.GetNextMessage(out _, out _);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
|
||||||
|
// add new batch
|
||||||
|
byte[] secondBatch = BatcherTests.ConcatTimestamp(TimeStamp + 1, new byte[]{0x03, 0x04});
|
||||||
|
unbatcher.AddBatch(new ArraySegment<byte>(secondBatch));
|
||||||
|
|
||||||
|
// read everything
|
||||||
|
result = unbatcher.GetNextMessage(out reader, out remoteTimeStamp);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x03));
|
||||||
|
Assert.That(reader.ReadByte(), Is.EqualTo(0x04));
|
||||||
|
Assert.That(remoteTimeStamp, Is.EqualTo(TimeStamp + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ccc928bb22f5469886cef8c6132aa717
|
||||||
|
timeCreated: 1623240730
|
134
Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs
Normal file
134
Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.RemoteAttrributeTest
|
||||||
|
{
|
||||||
|
class VirtualClientRpc : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int> onVirtualSendInt;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public virtual void RpcSendInt(int someInt) =>
|
||||||
|
onVirtualSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class VirtualNoOverrideClientRpc : VirtualClientRpc {}
|
||||||
|
|
||||||
|
class VirtualOverrideClientRpc : VirtualClientRpc
|
||||||
|
{
|
||||||
|
public event Action<int> onOverrideSendInt;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public override void RpcSendInt(int someInt) =>
|
||||||
|
onOverrideSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class VirtualOverrideClientRpcWithBase : VirtualClientRpc
|
||||||
|
{
|
||||||
|
public event Action<int> onOverrideSendInt;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public override void RpcSendInt(int someInt)
|
||||||
|
{
|
||||||
|
base.RpcSendInt(someInt);
|
||||||
|
onOverrideSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientRpcOverrideTest : RemoteTestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void VirtualRpcIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualClientRpc hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.RpcSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VirtualCommandWithNoOverrideIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualNoOverrideClientRpc hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.RpcSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OverrideVirtualRpcIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideClientRpc hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
int overrideCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
};
|
||||||
|
hostBehaviour.onOverrideSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
overrideCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.RpcSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(0));
|
||||||
|
Assert.That(overrideCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OverrideVirtualWithBaseCallsBothVirtualAndBase()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideClientRpcWithBase hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
int overrideCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.onOverrideSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
overrideCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.RpcSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
Assert.That(overrideCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/ClientRpcOverrideTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9759f0eddb9731c4b881ac30bacc0de0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
155
Assets/Mirror/Tests/Editor/ClientRpcTest.cs
Normal file
155
Assets/Mirror/Tests/Editor/ClientRpcTest.cs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.RemoteAttrributeTest
|
||||||
|
{
|
||||||
|
class ClientRpcBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int> onSendInt;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public void SendInt(int someInt) =>
|
||||||
|
onSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExcludeOwnerBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int> onSendInt;
|
||||||
|
|
||||||
|
[ClientRpc(includeOwner = false)]
|
||||||
|
public void RpcSendInt(int someInt) =>
|
||||||
|
onSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AbstractNetworkBehaviourClientRpcBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public abstract class MockMonsterBase : NetworkBehaviour {}
|
||||||
|
public class MockZombie : MockMonsterBase {}
|
||||||
|
public class MockWolf : MockMonsterBase {}
|
||||||
|
|
||||||
|
public event Action<MockMonsterBase> onSendMonsterBase;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public void RpcSendMonster(MockMonsterBase someMonster) =>
|
||||||
|
onSendMonsterBase?.Invoke(someMonster);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RpcOverloads : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public int firstCalled = 0;
|
||||||
|
public int secondCalled = 0;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public void RpcTest(int _) => ++firstCalled;
|
||||||
|
|
||||||
|
[ClientRpc]
|
||||||
|
public void RpcTest(string _) => ++secondCalled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientRpcTest : RemoteTestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void RpcIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out ClientRpcBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.SendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RpcIsCalledForNotOwner()
|
||||||
|
{
|
||||||
|
// spawn without owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out ExcludeOwnerBehaviour hostBehaviour);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.RpcSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RpcNotCalledForOwner()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out ExcludeOwnerBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.RpcSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(called, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RpcIsCalledWithAbstractNetworkBehaviourParameter()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out AbstractNetworkBehaviourClientRpcBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
// spawn clientrpc parameter targets
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out AbstractNetworkBehaviourClientRpcBehaviour.MockWolf wolf, NetworkServer.localConnection);
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out AbstractNetworkBehaviourClientRpcBehaviour.MockZombie zombie, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
AbstractNetworkBehaviourClientRpcBehaviour.MockMonsterBase currentMonster = null;
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
hostBehaviour.onSendMonsterBase += incomingMonster =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(incomingMonster, Is.EqualTo(currentMonster));
|
||||||
|
};
|
||||||
|
|
||||||
|
currentMonster = wolf;
|
||||||
|
hostBehaviour.RpcSendMonster(currentMonster);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
currentMonster = zombie;
|
||||||
|
hostBehaviour.RpcSendMonster(currentMonster);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteCalls uses md.FullName which gives us the full command/rpc name
|
||||||
|
// like "System.Void Mirror.Tests.RemoteAttrributeTest.AuthorityBehaviour::SendInt(System.Int32)"
|
||||||
|
// which means overloads with same name but different types should work.
|
||||||
|
[Test]
|
||||||
|
public void RpcOverload()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out RpcOverloads hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
hostBehaviour.RpcTest(42);
|
||||||
|
hostBehaviour.RpcTest("A");
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(hostBehaviour.firstCalled, Is.EqualTo(1));
|
||||||
|
Assert.That(hostBehaviour.secondCalled, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/ClientRpcTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/ClientRpcTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2928376e56382b646975dd00b68c2287
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
58
Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs
Normal file
58
Assets/Mirror/Tests/Editor/ClientSceneTests_ClearSpawners.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_ClearSpawners : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void RemovesAllPrefabsFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.prefabs.Add(Guid.NewGuid(), null);
|
||||||
|
NetworkClient.prefabs.Add(Guid.NewGuid(), null);
|
||||||
|
|
||||||
|
NetworkClient.ClearSpawners();
|
||||||
|
Assert.IsEmpty(NetworkClient.prefabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemovesAllSpawnHandlersFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
|
||||||
|
NetworkClient.ClearSpawners();
|
||||||
|
Assert.IsEmpty(NetworkClient.spawnHandlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemovesAllUnspawnHandlersFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
|
||||||
|
NetworkClient.ClearSpawners();
|
||||||
|
|
||||||
|
Assert.IsEmpty(NetworkClient.unspawnHandlers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ClearsAllDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.prefabs.Add(Guid.NewGuid(), null);
|
||||||
|
NetworkClient.prefabs.Add(Guid.NewGuid(), null);
|
||||||
|
|
||||||
|
NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
NetworkClient.spawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
|
||||||
|
NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
NetworkClient.unspawnHandlers.Add(Guid.NewGuid(), null);
|
||||||
|
|
||||||
|
NetworkClient.ClearSpawners();
|
||||||
|
|
||||||
|
Assert.IsEmpty(NetworkClient.prefabs);
|
||||||
|
Assert.IsEmpty(NetworkClient.spawnHandlers);
|
||||||
|
Assert.IsEmpty(NetworkClient.unspawnHandlers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ad2fe5633a9652045a5f7eb2643b6956
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
62
Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs
Normal file
62
Assets/Mirror/Tests/Editor/ClientSceneTests_GetPrefab.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_GetPrefab : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void ReturnsFalseForEmptyGuid()
|
||||||
|
{
|
||||||
|
bool result = NetworkClient.GetPrefab(new Guid(), out GameObject prefab);
|
||||||
|
|
||||||
|
Assert.IsFalse(result);
|
||||||
|
Assert.IsNull(prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReturnsFalseForPrefabNotFound()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
bool result = NetworkClient.GetPrefab(guid, out GameObject prefab);
|
||||||
|
|
||||||
|
Assert.IsFalse(result);
|
||||||
|
Assert.IsNull(prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReturnsFalseForPrefabIsNull()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
NetworkClient.prefabs.Add(guid, null);
|
||||||
|
bool result = NetworkClient.GetPrefab(guid, out GameObject prefab);
|
||||||
|
|
||||||
|
Assert.IsFalse(result);
|
||||||
|
Assert.IsNull(prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReturnsTrueWhenPrefabIsFound()
|
||||||
|
{
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
bool result = NetworkClient.GetPrefab(validPrefabGuid, out GameObject prefab);
|
||||||
|
|
||||||
|
Assert.IsTrue(result);
|
||||||
|
Assert.NotNull(prefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasOutPrefabWithCorrectGuid()
|
||||||
|
{
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
NetworkClient.GetPrefab(validPrefabGuid, out GameObject prefab);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.NotNull(prefab);
|
||||||
|
|
||||||
|
NetworkIdentity networkID = prefab.GetComponent<NetworkIdentity>();
|
||||||
|
Assert.AreEqual(networkID.assetId, validPrefabGuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 27cbff3906928974bb20c3f50eacbbb0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
736
Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs
Normal file
736
Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs
Normal file
@ -0,0 +1,736 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class PayloadTestBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public int value;
|
||||||
|
public Vector3 direction;
|
||||||
|
|
||||||
|
public event Action OnDeserializeCalled;
|
||||||
|
public event Action OnSerializeCalled;
|
||||||
|
|
||||||
|
public override bool OnSerialize(NetworkWriter writer, bool initialState)
|
||||||
|
{
|
||||||
|
base.OnSerialize(writer, initialState);
|
||||||
|
|
||||||
|
writer.WriteInt(value);
|
||||||
|
writer.WriteVector3(direction);
|
||||||
|
|
||||||
|
OnSerializeCalled?.Invoke();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||||||
|
{
|
||||||
|
base.OnDeserialize(reader, initialState);
|
||||||
|
|
||||||
|
value = reader.ReadInt();
|
||||||
|
direction = reader.ReadVector3();
|
||||||
|
|
||||||
|
OnDeserializeCalled?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BehaviourWithEvents : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action OnStartAuthorityCalled;
|
||||||
|
public event Action OnStartClientCalled;
|
||||||
|
public event Action OnStartLocalPlayerCalled;
|
||||||
|
|
||||||
|
public override void OnStartAuthority()
|
||||||
|
{
|
||||||
|
OnStartAuthorityCalled?.Invoke();
|
||||||
|
}
|
||||||
|
public override void OnStartClient()
|
||||||
|
{
|
||||||
|
OnStartClientCalled?.Invoke();
|
||||||
|
}
|
||||||
|
public override void OnStartLocalPlayer()
|
||||||
|
{
|
||||||
|
OnStartLocalPlayerCalled?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientSceneTests_OnSpawn : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
Dictionary<uint, NetworkIdentity> spawned => NetworkClient.spawned;
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
spawned.Clear();
|
||||||
|
base.TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_FindExistingObject()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity existing);
|
||||||
|
const uint netId = 1000;
|
||||||
|
existing.netId = netId;
|
||||||
|
spawned.Add(netId, existing);
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId
|
||||||
|
};
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity found);
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
Assert.That(found, Is.EqualTo(existing));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_ErrorWhenNoExistingAndAssetIdAndSceneIdAreBothEmpty()
|
||||||
|
{
|
||||||
|
const uint netId = 1001;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
assetId = new Guid(),
|
||||||
|
sceneId = 0,
|
||||||
|
netId = netId
|
||||||
|
};
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"OnSpawn message with netId '{netId}' has no AssetId or sceneId");
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsFalse(success);
|
||||||
|
Assert.IsNull(networkIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_SpawnsFromPrefabDictionary()
|
||||||
|
{
|
||||||
|
const uint netId = 1002;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
Assert.IsNotNull(networkIdentity);
|
||||||
|
Assert.That(networkIdentity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
GameObject.DestroyImmediate(networkIdentity.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_ErrorWhenPrefabInNullInDictionary()
|
||||||
|
{
|
||||||
|
const uint netId = 1002;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
};
|
||||||
|
|
||||||
|
// could happen if the prefab is destroyed or unloaded
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, null);
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Failed to spawn server object, did you forget to add it to the NetworkManager? assetId={msg.assetId} netId={msg.netId}");
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.IsFalse(success);
|
||||||
|
Assert.IsNull(networkIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_SpawnsFromPrefabIfBothPrefabAndHandlerExists()
|
||||||
|
{
|
||||||
|
const uint netId = 1003;
|
||||||
|
int handlerCalled = 0;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
NetworkClient.spawnHandlers.Add(validPrefabGuid, x =>
|
||||||
|
{
|
||||||
|
handlerCalled++;
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity _);
|
||||||
|
return go;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
Assert.IsNotNull(networkIdentity);
|
||||||
|
Assert.That(networkIdentity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
|
||||||
|
Assert.That(handlerCalled, Is.EqualTo(0), "Handler should not have been called");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_SpawnHandlerCalledFromDictionary()
|
||||||
|
{
|
||||||
|
const uint netId = 1003;
|
||||||
|
int handlerCalled = 0;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
};
|
||||||
|
|
||||||
|
GameObject createdInhandler = null;
|
||||||
|
|
||||||
|
NetworkClient.spawnHandlers.Add(validPrefabGuid, x =>
|
||||||
|
{
|
||||||
|
handlerCalled++;
|
||||||
|
Assert.That(x, Is.EqualTo(msg));
|
||||||
|
CreateNetworked(out createdInhandler, out NetworkIdentity _);
|
||||||
|
return createdInhandler;
|
||||||
|
});
|
||||||
|
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
Assert.IsNotNull(networkIdentity);
|
||||||
|
Assert.That(handlerCalled, Is.EqualTo(1));
|
||||||
|
Assert.That(networkIdentity.gameObject, Is.EqualTo(createdInhandler), "Object returned should be the same object created by the spawn handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_ErrorWhenSpawnHanlderReturnsNull()
|
||||||
|
{
|
||||||
|
const uint netId = 1003;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.spawnHandlers.Add(validPrefabGuid, (x) => null);
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Spawn Handler returned null, Handler assetId '{msg.assetId}'");
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsFalse(success);
|
||||||
|
Assert.IsNull(networkIdentity);
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_ErrorWhenSpawnHanlderReturnsWithoutNetworkIdentity()
|
||||||
|
{
|
||||||
|
const uint netId = 1003;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.spawnHandlers.Add(validPrefabGuid, (x) =>
|
||||||
|
{
|
||||||
|
CreateGameObject(out GameObject go);
|
||||||
|
return go;
|
||||||
|
});
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Object Spawned by handler did not have a NetworkIdentity, Handler assetId '{validPrefabGuid}'");
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsFalse(success);
|
||||||
|
Assert.IsNull(networkIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkIdentity CreateSceneObject(ulong sceneId)
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity);
|
||||||
|
// set sceneId to zero as it is set in onvalidate (does not set id at runtime)
|
||||||
|
identity.sceneId = sceneId;
|
||||||
|
NetworkClient.spawnableObjects.Add(sceneId, identity);
|
||||||
|
return identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_UsesSceneIdToSpawnFromSpawnableObjectsDictionary()
|
||||||
|
{
|
||||||
|
const uint netId = 1003;
|
||||||
|
const int sceneId = 100020;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
sceneId = sceneId
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkIdentity sceneObject = CreateSceneObject(sceneId);
|
||||||
|
|
||||||
|
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
Assert.IsNotNull(networkIdentity);
|
||||||
|
Assert.That(networkIdentity, Is.EqualTo(sceneObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_SpawnsUsingSceneIdInsteadOfAssetId()
|
||||||
|
{
|
||||||
|
const uint netId = 1003;
|
||||||
|
const int sceneId = 100020;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
sceneId = sceneId,
|
||||||
|
assetId = validPrefabGuid
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
NetworkIdentity sceneObject = CreateSceneObject(sceneId);
|
||||||
|
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
Assert.IsNotNull(networkIdentity);
|
||||||
|
Assert.That(networkIdentity, Is.EqualTo(sceneObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FindOrSpawnObject_ErrorWhenSceneIdIsNotInSpawnableObjectsDictionary()
|
||||||
|
{
|
||||||
|
const uint netId = 1004;
|
||||||
|
const int sceneId = 100021;
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
sceneId = sceneId,
|
||||||
|
};
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Spawn scene object not found for {msg.sceneId:X}. Make sure that client and server use exactly the same project. This only happens if the hierarchy gets out of sync.");
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not spawn assetId={msg.assetId} scene={msg.sceneId:X} netId={msg.netId}");
|
||||||
|
bool success = NetworkClient.FindOrSpawnObject(msg, out NetworkIdentity networkIdentity);
|
||||||
|
|
||||||
|
Assert.IsFalse(success);
|
||||||
|
Assert.IsNull(networkIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_AppliesTransform()
|
||||||
|
{
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
Vector3 position = new Vector3(10, 0, 20);
|
||||||
|
Quaternion rotation = Quaternion.Euler(0, 45, 0);
|
||||||
|
Vector3 scale = new Vector3(1.5f, 1.5f, 1.5f);
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = false,
|
||||||
|
isOwner = false,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = position,
|
||||||
|
rotation = rotation,
|
||||||
|
scale = scale,
|
||||||
|
|
||||||
|
payload = default,
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.That(identity.transform.position, Is.EqualTo(position));
|
||||||
|
// use angle because of floating point numbers
|
||||||
|
// only need to check if rotations are approximately equal
|
||||||
|
Assert.That(Quaternion.Angle(identity.transform.rotation, rotation), Is.LessThan(0.0001f));
|
||||||
|
Assert.That(identity.transform.localScale, Is.EqualTo(scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_AppliesLocalValuesToTransform()
|
||||||
|
{
|
||||||
|
const uint netId = 1000;
|
||||||
|
CreateGameObject(out GameObject parent);
|
||||||
|
parent.transform.position = new Vector3(100, 20, 0);
|
||||||
|
parent.transform.rotation = Quaternion.LookRotation(Vector3.left);
|
||||||
|
parent.transform.localScale = Vector3.one * 2;
|
||||||
|
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity identity);
|
||||||
|
go.transform.parent = parent.transform;
|
||||||
|
|
||||||
|
Vector3 position = new Vector3(10, 0, 20);
|
||||||
|
Quaternion rotation = Quaternion.Euler(0, 45, 0);
|
||||||
|
Vector3 scale = new Vector3(1.5f, 1.5f, 1.5f);
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = false,
|
||||||
|
isOwner = false,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = position,
|
||||||
|
rotation = rotation,
|
||||||
|
scale = scale,
|
||||||
|
|
||||||
|
payload = default,
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.That(identity.transform.localPosition, Is.EqualTo(position));
|
||||||
|
// use angle because of floating point numbers
|
||||||
|
// only need to check if rotations are approximately equal
|
||||||
|
Assert.That(Quaternion.Angle(identity.transform.localRotation, rotation), Is.LessThan(0.0001f));
|
||||||
|
Assert.That(identity.transform.localScale, Is.EqualTo(scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void ApplyPayload_AppliesAuthority(bool isOwner)
|
||||||
|
{
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = false,
|
||||||
|
isOwner = isOwner,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = Vector3.zero,
|
||||||
|
rotation = Quaternion.identity,
|
||||||
|
scale = Vector3.one,
|
||||||
|
|
||||||
|
payload = default
|
||||||
|
};
|
||||||
|
|
||||||
|
// set to opposite to make sure it is changed
|
||||||
|
identity.hasAuthority = !isOwner;
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.That(identity.hasAuthority, Is.EqualTo(isOwner));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void ApplyPayload_EnablesObject(bool startActive)
|
||||||
|
{
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity identity);
|
||||||
|
go.SetActive(startActive);
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = false,
|
||||||
|
isOwner = false,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = Vector3.zero,
|
||||||
|
rotation = Quaternion.identity,
|
||||||
|
scale = Vector3.one,
|
||||||
|
|
||||||
|
payload = default,
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.IsTrue(identity.gameObject.activeSelf);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_SetsAssetId()
|
||||||
|
{
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = false,
|
||||||
|
isOwner = false,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = guid,
|
||||||
|
// use local values for VR support
|
||||||
|
position = Vector3.zero,
|
||||||
|
rotation = Quaternion.identity,
|
||||||
|
scale = Vector3.one,
|
||||||
|
|
||||||
|
payload = default
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.IsTrue(identity.gameObject.activeSelf);
|
||||||
|
|
||||||
|
Assert.That(identity.assetId, Is.EqualTo(guid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_DoesNotSetAssetIdToEmpty()
|
||||||
|
{
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity);
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
identity.assetId = guid;
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = false,
|
||||||
|
isOwner = false,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = Vector3.zero,
|
||||||
|
rotation = Quaternion.identity,
|
||||||
|
scale = Vector3.one,
|
||||||
|
|
||||||
|
payload = default
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.That(identity.assetId, Is.EqualTo(guid), "AssetId should not have changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_SendsDataToNetworkBehaviourDeserialize()
|
||||||
|
{
|
||||||
|
const int value = 12;
|
||||||
|
Vector3 direction = new Vector3(0, 1, 1);
|
||||||
|
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
// server object
|
||||||
|
CreateNetworked(out _, out NetworkIdentity serverIdentity, out PayloadTestBehaviour serverPayloadBehaviour);
|
||||||
|
|
||||||
|
// client object
|
||||||
|
CreateNetworked(out _, out NetworkIdentity clientIdentity, out PayloadTestBehaviour clientPayloadBehaviour);
|
||||||
|
|
||||||
|
int onSerializeCalled = 0;
|
||||||
|
serverPayloadBehaviour.OnSerializeCalled += () => { onSerializeCalled++; };
|
||||||
|
|
||||||
|
int onDeserializeCalled = 0;
|
||||||
|
clientPayloadBehaviour.OnDeserializeCalled += () => { onDeserializeCalled++; };
|
||||||
|
|
||||||
|
serverPayloadBehaviour.value = value;
|
||||||
|
serverPayloadBehaviour.direction = direction;
|
||||||
|
|
||||||
|
NetworkWriter ownerWriter = new NetworkWriter();
|
||||||
|
NetworkWriter observersWriter = new NetworkWriter();
|
||||||
|
serverIdentity.OnSerializeAllSafely(true, ownerWriter, observersWriter);
|
||||||
|
|
||||||
|
// check that Serialize was called
|
||||||
|
Assert.That(onSerializeCalled, Is.EqualTo(1));
|
||||||
|
|
||||||
|
// create spawn message
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
payload = ownerWriter.ToArraySegment(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// check values start default
|
||||||
|
Assert.That(onDeserializeCalled, Is.EqualTo(0));
|
||||||
|
Assert.That(clientPayloadBehaviour.value, Is.EqualTo(0));
|
||||||
|
Assert.That(clientPayloadBehaviour.direction, Is.EqualTo(Vector3.zero));
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(clientIdentity, msg);
|
||||||
|
|
||||||
|
// check values have been set by payload
|
||||||
|
Assert.That(onDeserializeCalled, Is.EqualTo(1));
|
||||||
|
Assert.That(clientPayloadBehaviour.value, Is.EqualTo(value));
|
||||||
|
Assert.That(clientPayloadBehaviour.direction, Is.EqualTo(direction));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_LocalPlayerAddsIdentityToConnection()
|
||||||
|
{
|
||||||
|
Debug.Assert(NetworkClient.localPlayer == null, "LocalPlayer should be null before this test");
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = true,
|
||||||
|
isOwner = true,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = Vector3.zero,
|
||||||
|
rotation = Quaternion.identity,
|
||||||
|
scale = Vector3.one,
|
||||||
|
|
||||||
|
payload = default,
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.connection = new FakeNetworkConnection();
|
||||||
|
NetworkClient.ready = true;
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.localPlayer, Is.EqualTo(identity));
|
||||||
|
Assert.That(NetworkClient.connection.identity, Is.EqualTo(identity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyPayload_LocalPlayerWarningWhenNoReadyConnection()
|
||||||
|
{
|
||||||
|
Debug.Assert(NetworkClient.localPlayer == null, "LocalPlayer should be null before this test");
|
||||||
|
const uint netId = 1000;
|
||||||
|
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = true,
|
||||||
|
isOwner = true,
|
||||||
|
sceneId = 0,
|
||||||
|
assetId = Guid.Empty,
|
||||||
|
// use local values for VR support
|
||||||
|
position = Vector3.zero,
|
||||||
|
rotation = Quaternion.identity,
|
||||||
|
scale = Vector3.one,
|
||||||
|
|
||||||
|
payload = default,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Warning, "No ready connection found for setting player controller during InternalAddPlayer");
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.localPlayer, Is.EqualTo(identity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SpawnFinishedState
|
||||||
|
{
|
||||||
|
isSpawnFinished = 1,
|
||||||
|
hasAuthority = 2,
|
||||||
|
isLocalPlayer = 4
|
||||||
|
}
|
||||||
|
[Test]
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
[TestCase(2)]
|
||||||
|
[TestCase(3)]
|
||||||
|
[TestCase(4)]
|
||||||
|
[TestCase(5)]
|
||||||
|
[TestCase(6)]
|
||||||
|
[TestCase(7)]
|
||||||
|
public void ApplyPayload_isSpawnFinished(SpawnFinishedState flag)
|
||||||
|
{
|
||||||
|
bool isSpawnFinished = flag.HasFlag(SpawnFinishedState.isSpawnFinished);
|
||||||
|
bool hasAuthority = flag.HasFlag(SpawnFinishedState.hasAuthority);
|
||||||
|
bool isLocalPlayer = flag.HasFlag(SpawnFinishedState.isLocalPlayer);
|
||||||
|
|
||||||
|
if (isSpawnFinished)
|
||||||
|
{
|
||||||
|
NetworkClient.OnObjectSpawnFinished(new ObjectSpawnFinishedMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint netId = 1000;
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity, out BehaviourWithEvents events);
|
||||||
|
|
||||||
|
int onStartAuthorityCalled = 0;
|
||||||
|
int onStartClientCalled = 0;
|
||||||
|
int onStartLocalPlayerCalled = 0;
|
||||||
|
events.OnStartAuthorityCalled += () => { onStartAuthorityCalled++; };
|
||||||
|
events.OnStartClientCalled += () => { onStartClientCalled++; };
|
||||||
|
events.OnStartLocalPlayerCalled += () => { onStartLocalPlayerCalled++; };
|
||||||
|
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
isLocalPlayer = isLocalPlayer,
|
||||||
|
isOwner = hasAuthority,
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkClient.ApplySpawnPayload(identity, msg);
|
||||||
|
|
||||||
|
if (isSpawnFinished)
|
||||||
|
{
|
||||||
|
Assert.That(onStartClientCalled, Is.EqualTo(1));
|
||||||
|
Assert.That(onStartAuthorityCalled, Is.EqualTo(hasAuthority ? 1 : 0));
|
||||||
|
Assert.That(onStartLocalPlayerCalled, Is.EqualTo(isLocalPlayer ? 1 : 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.That(onStartAuthorityCalled, Is.Zero);
|
||||||
|
Assert.That(onStartClientCalled, Is.Zero);
|
||||||
|
Assert.That(onStartLocalPlayerCalled, Is.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OnSpawn_SpawnsAndAppliesPayload()
|
||||||
|
{
|
||||||
|
const int netId = 1;
|
||||||
|
Debug.Assert(spawned.Count == 0, "There should be no spawned objects before test");
|
||||||
|
|
||||||
|
Vector3 position = new Vector3(30, 20, 10);
|
||||||
|
Quaternion rotation = Quaternion.Euler(0, 0, 90);
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
assetId = validPrefabGuid,
|
||||||
|
position = position,
|
||||||
|
rotation = rotation
|
||||||
|
};
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
|
||||||
|
NetworkClient.OnSpawn(msg);
|
||||||
|
|
||||||
|
Assert.That(spawned.Count, Is.EqualTo(1));
|
||||||
|
Assert.IsTrue(spawned.ContainsKey(netId));
|
||||||
|
|
||||||
|
NetworkIdentity identity = spawned[netId];
|
||||||
|
Assert.IsNotNull(identity);
|
||||||
|
Assert.That(identity.name, Is.EqualTo($"{validPrefab.name}(Clone)"));
|
||||||
|
Assert.That(identity.transform.position, Is.EqualTo(position));
|
||||||
|
// use angle because of floating point numbers
|
||||||
|
// only need to check if rotations are approximately equal
|
||||||
|
Assert.That(Quaternion.Angle(identity.transform.rotation, rotation), Is.LessThan(0.0001f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OnSpawn_GiveNoExtraErrorsWhenPrefabIsntSpawned()
|
||||||
|
{
|
||||||
|
const int netId = 20033;
|
||||||
|
Debug.Assert(spawned.Count == 0, "There should be no spawned objects before test");
|
||||||
|
SpawnMessage msg = new SpawnMessage
|
||||||
|
{
|
||||||
|
netId = netId,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for log that FindOrSpawnObject gives, and make sure there are no other error logs
|
||||||
|
LogAssert.Expect(LogType.Error, $"OnSpawn message with netId '{netId}' has no AssetId or sceneId");
|
||||||
|
NetworkClient.OnSpawn(msg);
|
||||||
|
|
||||||
|
Assert.That(spawned, Is.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/ClientSceneTests_OnSpawn.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b85d949dccc6ab4498da187264323dcc
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,104 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_PrepareToSpawnSceneObjects : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
NetworkIdentity CreateSceneObject(ulong sceneId)
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject gameObject, out NetworkIdentity identity);
|
||||||
|
gameObject.name = "Runtime GameObject";
|
||||||
|
// set sceneId to zero as it is set in onvalidate (does not set id at runtime)
|
||||||
|
identity.sceneId = sceneId;
|
||||||
|
return identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddsAllInactiveIdentitiesInSceneWithSceneIdToDictionary()
|
||||||
|
{
|
||||||
|
NetworkIdentity obj1 = CreateSceneObject(10);
|
||||||
|
NetworkIdentity obj2 = CreateSceneObject(11);
|
||||||
|
|
||||||
|
obj1.gameObject.SetActive(false);
|
||||||
|
obj2.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
NetworkClient.PrepareToSpawnSceneObjects();
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.spawnableObjects, Has.Count.EqualTo(2));
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(obj1));
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DoesNotAddActiveObjectsToDictionary()
|
||||||
|
{
|
||||||
|
NetworkIdentity active = CreateSceneObject(30);
|
||||||
|
NetworkIdentity inactive = CreateSceneObject(32);
|
||||||
|
|
||||||
|
active.gameObject.SetActive(true);
|
||||||
|
inactive.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
NetworkClient.PrepareToSpawnSceneObjects();
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.spawnableObjects, Has.Count.EqualTo(1));
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(inactive));
|
||||||
|
Assert.IsFalse(NetworkClient.spawnableObjects.ContainsValue(active));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DoesNotAddObjectsWithNoSceneId()
|
||||||
|
{
|
||||||
|
NetworkIdentity noId = CreateSceneObject(0);
|
||||||
|
NetworkIdentity hasId = CreateSceneObject(40);
|
||||||
|
|
||||||
|
noId.gameObject.SetActive(false);
|
||||||
|
hasId.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
NetworkClient.PrepareToSpawnSceneObjects();
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(hasId));
|
||||||
|
Assert.IsFalse(NetworkClient.spawnableObjects.ContainsValue(noId));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddsIdentitiesToDictionaryUsingSceneId()
|
||||||
|
{
|
||||||
|
NetworkIdentity obj1 = CreateSceneObject(20);
|
||||||
|
NetworkIdentity obj2 = CreateSceneObject(21);
|
||||||
|
obj1.gameObject.SetActive(false);
|
||||||
|
obj2.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
NetworkClient.PrepareToSpawnSceneObjects();
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsKey(20));
|
||||||
|
Assert.That(NetworkClient.spawnableObjects[20], Is.EqualTo(obj1));
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsKey(21));
|
||||||
|
Assert.That(NetworkClient.spawnableObjects[21], Is.EqualTo(obj2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ClearsExistingItemsFromDictionary()
|
||||||
|
{
|
||||||
|
// destroyed objects from old scene
|
||||||
|
NetworkClient.spawnableObjects.Add(60, null);
|
||||||
|
NetworkClient.spawnableObjects.Add(62, null);
|
||||||
|
|
||||||
|
// active object
|
||||||
|
NetworkIdentity obj1 = CreateSceneObject(61);
|
||||||
|
NetworkClient.spawnableObjects.Add(61, obj1);
|
||||||
|
|
||||||
|
// new disabled object
|
||||||
|
NetworkIdentity obj2 = CreateSceneObject(63);
|
||||||
|
obj2.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
NetworkClient.PrepareToSpawnSceneObjects();
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.spawnableObjects, Has.Count.EqualTo(1));
|
||||||
|
Assert.IsFalse(NetworkClient.spawnableObjects.ContainsValue(null));
|
||||||
|
Assert.IsTrue(NetworkClient.spawnableObjects.ContainsValue(obj2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 546931b1b1c38d5498f2c189e68b63aa
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
300
Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs
Normal file
300
Assets/Mirror/Tests/Editor/ClientSceneTests_RegisterPrefab.cs
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_RegisterPrefab : ClientSceneTests_RegisterPrefabBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
public void Prefab_AddsPrefabToDictionary(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
|
||||||
|
CallRegisterPrefab(validPrefab, overload);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.prefabs.ContainsKey(guid));
|
||||||
|
Assert.AreEqual(NetworkClient.prefabs[guid], validPrefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
|
||||||
|
public void PrefabNewGuid_ErrorDoesNotChangePrefabsAssetId(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = anotherGuid;
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not register '{validPrefab.name}' to {guid} because it already had an AssetId, Existing assetId {validPrefabGuid}");
|
||||||
|
CallRegisterPrefab(validPrefab, overload);
|
||||||
|
|
||||||
|
Assert.IsFalse(NetworkClient.prefabs.ContainsKey(guid));
|
||||||
|
|
||||||
|
NetworkIdentity netId = validPrefab.GetComponent<NetworkIdentity>();
|
||||||
|
|
||||||
|
Assert.AreEqual(netId.assetId, validPrefabGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
|
||||||
|
public void HandlerNewGuid_ErrorDoesNotChangePrefabsAssetId(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = anotherGuid;
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not register Handler for '{validPrefab.name}' to {guid} because it already had an AssetId, Existing assetId {validPrefabGuid}");
|
||||||
|
CallRegisterPrefab(validPrefab, overload);
|
||||||
|
|
||||||
|
Assert.IsFalse(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(guid));
|
||||||
|
|
||||||
|
NetworkIdentity netId = validPrefab.GetComponent<NetworkIdentity>();
|
||||||
|
|
||||||
|
Assert.AreEqual(netId.assetId, validPrefabGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
|
||||||
|
public void PrefabNewGuid_NoErrorWhenNewAssetIdIsSameAsCurrentPrefab(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = validPrefabGuid;
|
||||||
|
|
||||||
|
CallRegisterPrefab(validPrefab, overload, guid);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.prefabs.ContainsKey(guid));
|
||||||
|
|
||||||
|
NetworkIdentity netId = validPrefab.GetComponent<NetworkIdentity>();
|
||||||
|
|
||||||
|
Assert.AreEqual(netId.assetId, validPrefabGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
|
||||||
|
public void HandlerNewGuid_NoErrorWhenAssetIdIsSameAsCurrentPrefab(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = validPrefabGuid;
|
||||||
|
|
||||||
|
CallRegisterPrefab(validPrefab, overload, guid);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
Assert.IsTrue(NetworkClient.unspawnHandlers.ContainsKey(guid));
|
||||||
|
|
||||||
|
NetworkIdentity netId = validPrefab.GetComponent<NetworkIdentity>();
|
||||||
|
|
||||||
|
Assert.AreEqual(netId.assetId, validPrefabGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
|
||||||
|
public void ErrorForNullPrefab(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
string msg = OverloadWithHandler(overload)
|
||||||
|
? "Could not register handler for prefab because the prefab was null"
|
||||||
|
: "Could not register prefab because it was null";
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, msg);
|
||||||
|
CallRegisterPrefab(null, overload);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
|
||||||
|
public void ErrorForPrefabWithoutNetworkIdentity(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
string msg = OverloadWithHandler(overload)
|
||||||
|
? $"Could not register handler for '{invalidPrefab.name}' since it contains no NetworkIdentity component"
|
||||||
|
: $"Could not register '{invalidPrefab.name}' since it contains no NetworkIdentity component";
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, msg);
|
||||||
|
CallRegisterPrefab(invalidPrefab, overload);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate_NewAssetId)]
|
||||||
|
public void NewGuid_ErrorForEmptyGuid(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
string msg = OverloadWithHandler(overload)
|
||||||
|
? $"Could not register handler for '{validPrefab.name}' with new assetId because the new assetId was empty"
|
||||||
|
: $"Could not register '{validPrefab.name}' with new assetId because the new assetId was empty";
|
||||||
|
LogAssert.Expect(LogType.Error, msg);
|
||||||
|
CallRegisterPrefab(validPrefab, overload, new Guid());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void ErrorIfPrefabHadSceneId(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
GameObject clone = GameObject.Instantiate(validPrefab);
|
||||||
|
NetworkIdentity netId = clone.GetComponent<NetworkIdentity>();
|
||||||
|
// Scene Id needs to not be zero for this test
|
||||||
|
netId.sceneId = 20;
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register '{clone.name}' because it has a sceneId, make sure you are passing in the original prefab and not an instance in the scene.");
|
||||||
|
CallRegisterPrefab(clone, overload);
|
||||||
|
|
||||||
|
GameObject.DestroyImmediate(clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void ErrorForNetworkIdentityInChildren(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
LogAssert.Expect(LogType.Error, $"Prefab '{prefabWithChildren.name}' has multiple NetworkIdentity components. There should only be one NetworkIdentity on a prefab, and it must be on the root object.");
|
||||||
|
CallRegisterPrefab(prefabWithChildren, overload);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
public void Prefab_WarningForAssetIdAlreadyExistingInPrefabsDictionary(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
|
||||||
|
NetworkClient.prefabs.Add(guid, validPrefab);
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Warning, $"Replacing existing prefab with assetId '{guid}'. Old prefab '{validPrefab.name}', New prefab '{validPrefab.name}'");
|
||||||
|
CallRegisterPrefab(validPrefab, overload);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void Handler_ErrorForAssetIdAlreadyExistingInPrefabsDictionary(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
|
||||||
|
NetworkClient.prefabs.Add(guid, validPrefab);
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"assetId '{guid}' is already used by prefab '{validPrefab.name}', unregister the prefab first before trying to add handler");
|
||||||
|
CallRegisterPrefab(validPrefab, overload);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void WarningForAssetIdAlreadyExistingInHandlersDictionary(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
|
||||||
|
NetworkClient.spawnHandlers.Add(guid, x => null);
|
||||||
|
NetworkClient.unspawnHandlers.Add(guid, x => {});
|
||||||
|
|
||||||
|
string msg = OverloadWithHandler(overload)
|
||||||
|
? $"Replacing existing spawnHandlers for prefab '{validPrefab.name}' with assetId '{guid}'"
|
||||||
|
: $"Adding prefab '{validPrefab.name}' with assetId '{guid}' when spawnHandlers with same assetId already exists.";
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Warning, msg);
|
||||||
|
CallRegisterPrefab(validPrefab, overload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
public void SpawnDelegate_AddsHandlerToSpawnHandlers(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
int handlerCalled = 0;
|
||||||
|
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
SpawnDelegate handler = new SpawnDelegate((pos, rot) =>
|
||||||
|
{
|
||||||
|
handlerCalled++;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
CallRegisterPrefab(validPrefab, overload, handler);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
|
||||||
|
// check spawnHandler above is called
|
||||||
|
SpawnHandlerDelegate handlerInDictionary = NetworkClient.spawnHandlers[guid];
|
||||||
|
handlerInDictionary.Invoke(default);
|
||||||
|
Assert.That(handlerCalled, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
public void SpawnDelegate_AddsHandlerToSpawnHandlersWithCorrectArguments(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
int handlerCalled = 0;
|
||||||
|
Vector3 somePosition = new Vector3(10, 20, 3);
|
||||||
|
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
SpawnDelegate handler = new SpawnDelegate((pos, assetId) =>
|
||||||
|
{
|
||||||
|
handlerCalled++;
|
||||||
|
Assert.That(pos, Is.EqualTo(somePosition));
|
||||||
|
Assert.That(assetId, Is.EqualTo(guid));
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
CallRegisterPrefab(validPrefab, overload, handler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
|
||||||
|
// check spawnHandler above is called
|
||||||
|
SpawnHandlerDelegate handlerInDictionary = NetworkClient.spawnHandlers[guid];
|
||||||
|
handlerInDictionary.Invoke(new SpawnMessage { position = somePosition, assetId = guid });
|
||||||
|
Assert.That(handlerCalled, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate_NewAssetId)]
|
||||||
|
public void SpawnDelegate_ErrorWhenSpawnHandlerIsNull(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
|
||||||
|
CallRegisterPrefab(validPrefab, overload, spawnHandler: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void SpawnHandleDelegate_AddsHandlerToSpawnHandlers(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
|
||||||
|
SpawnHandlerDelegate handler = new SpawnHandlerDelegate(x => null);
|
||||||
|
|
||||||
|
CallRegisterPrefab(validPrefab, overload, handler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
Assert.AreEqual(NetworkClient.spawnHandlers[guid], handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void SpawnHandleDelegate_ErrorWhenSpawnHandlerIsNull(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
|
||||||
|
CallRegisterPrefab(validPrefab, overload, spawnHandlerDelegate: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnDelegate)]
|
||||||
|
[TestCase(RegisterPrefabOverload.Prefab_SpawnHandlerDelegate)]
|
||||||
|
public void Handler_ErrorWhenUnSpawnHandlerIsNull(RegisterPrefabOverload overload)
|
||||||
|
{
|
||||||
|
Guid guid = GuidForOverload(overload);
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null UnSpawnHandler for {guid}");
|
||||||
|
CallRegisterPrefab(validPrefab, overload, unspawnHandler: null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bdfdcfafb85b3be418f2085e38663006
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,224 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_RegisterSpawnHandler : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_AddsHandlerToSpawnHandlers()
|
||||||
|
{
|
||||||
|
int handlerCalled = 0;
|
||||||
|
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((pos, rot) =>
|
||||||
|
{
|
||||||
|
handlerCalled++;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
|
||||||
|
// check spawnHandler above is called
|
||||||
|
SpawnHandlerDelegate handler = NetworkClient.spawnHandlers[guid];
|
||||||
|
handler.Invoke(default);
|
||||||
|
Assert.That(handlerCalled, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_AddsHandlerToSpawnHandlersWithCorrectArguments()
|
||||||
|
{
|
||||||
|
int handlerCalled = 0;
|
||||||
|
Vector3 somePosition = new Vector3(10, 20, 3);
|
||||||
|
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((pos, assetId) =>
|
||||||
|
{
|
||||||
|
handlerCalled++;
|
||||||
|
Assert.That(pos, Is.EqualTo(somePosition));
|
||||||
|
Assert.That(assetId, Is.EqualTo(guid));
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
|
||||||
|
// check spawnHandler above is called
|
||||||
|
SpawnHandlerDelegate handler = NetworkClient.spawnHandlers[guid];
|
||||||
|
handler.Invoke(new SpawnMessage { position = somePosition, assetId = guid });
|
||||||
|
Assert.That(handlerCalled, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_AddsHandlerToUnSpawnHandlers()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.unspawnHandlers.ContainsKey(guid));
|
||||||
|
Assert.AreEqual(NetworkClient.unspawnHandlers[guid], unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_ErrorWhenSpawnHandlerIsNull()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnDelegate spawnHandler = null;
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_ErrorWhenUnSpawnHandlerIsNull()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = null;
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null UnSpawnHandler for {guid}");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_ErrorWhenAssetIdIsEmpty()
|
||||||
|
{
|
||||||
|
Guid guid = new Guid();
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, "Can not Register SpawnHandler for empty Guid");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_WarningWhenHandlerForGuidAlreadyExistsInHandlerDictionary()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
SpawnDelegate spawnHandler2 = new SpawnDelegate((x, y) => new GameObject());
|
||||||
|
UnSpawnDelegate unspawnHandler2 = new UnSpawnDelegate(x => UnityEngine.Object.Destroy(x));
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Warning, $"Replacing existing spawnHandlers for {guid}");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler2, unspawnHandler2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnDelegate_ErrorWhenHandlerForGuidAlreadyExistsInPrefabDictionary()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
NetworkClient.prefabs.Add(guid, validPrefab);
|
||||||
|
|
||||||
|
SpawnDelegate spawnHandler = new SpawnDelegate((x, y) => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"assetId '{guid}' is already used by prefab '{validPrefab.name}'");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_AddsHandlerToSpawnHandlers()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.spawnHandlers.ContainsKey(guid));
|
||||||
|
Assert.AreEqual(NetworkClient.spawnHandlers[guid], spawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_AddsHandlerToUnSpawnHandlers()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
Assert.IsTrue(NetworkClient.unspawnHandlers.ContainsKey(guid));
|
||||||
|
Assert.AreEqual(NetworkClient.unspawnHandlers[guid], unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_ErrorWhenSpawnHandlerIsNull()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnHandlerDelegate spawnHandler = null;
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null SpawnHandler for {guid}");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_ErrorWhenUnSpawnHandlerIsNull()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = null;
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"Can not Register null UnSpawnHandler for {guid}");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_ErrorWhenAssetIdIsEmpty()
|
||||||
|
{
|
||||||
|
Guid guid = new Guid();
|
||||||
|
SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, "Can not Register SpawnHandler for empty Guid");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_WarningWhenHandlerForGuidAlreadyExistsInHandlerDictionary()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => null);
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => {});
|
||||||
|
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
|
||||||
|
SpawnHandlerDelegate spawnHandler2 = new SpawnHandlerDelegate(x => new GameObject());
|
||||||
|
UnSpawnDelegate unspawnHandler2 = new UnSpawnDelegate(x => UnityEngine.Object.Destroy(x));
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Warning, $"Replacing existing spawnHandlers for {guid}");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler2, unspawnHandler2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SpawnHandlerDelegate_ErrorWhenHandlerForGuidAlreadyExistsInPrefabDictionary()
|
||||||
|
{
|
||||||
|
Guid guid = Guid.NewGuid();
|
||||||
|
NetworkClient.prefabs.Add(guid, validPrefab);
|
||||||
|
|
||||||
|
SpawnHandlerDelegate spawnHandler = new SpawnHandlerDelegate(x => new GameObject());
|
||||||
|
UnSpawnDelegate unspawnHandler = new UnSpawnDelegate(x => UnityEngine.Object.Destroy(x));
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, $"assetId '{guid}' is already used by prefab '{validPrefab.name}'");
|
||||||
|
NetworkClient.RegisterSpawnHandler(guid, spawnHandler, unspawnHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c7e6577e8c2e64e41ae255edc61e91a2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,48 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_UnregisterPrefab : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void RemovesPrefabFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
NetworkClient.UnregisterPrefab(validPrefab);
|
||||||
|
Assert.IsFalse(NetworkClient.prefabs.ContainsKey(validPrefabGuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemovesSpawnHandlerFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.spawnHandlers.Add(validPrefabGuid, new SpawnHandlerDelegate(x => null));
|
||||||
|
NetworkClient.UnregisterPrefab(validPrefab);
|
||||||
|
Assert.IsFalse(NetworkClient.spawnHandlers.ContainsKey(validPrefabGuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemovesUnSpawnHandlerFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.unspawnHandlers.Add(validPrefabGuid, new UnSpawnDelegate(x => {}));
|
||||||
|
NetworkClient.UnregisterPrefab(validPrefab);
|
||||||
|
Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(validPrefabGuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ErrorWhenPrefabIsNull()
|
||||||
|
{
|
||||||
|
LogAssert.Expect(LogType.Error, "Could not unregister prefab because it was null");
|
||||||
|
NetworkClient.UnregisterPrefab(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ErrorWhenPrefabHasNoNetworkIdentity()
|
||||||
|
{
|
||||||
|
LogAssert.Expect(LogType.Error, $"Could not unregister '{invalidPrefab.name}' since it contains no NetworkIdentity component");
|
||||||
|
NetworkClient.UnregisterPrefab(invalidPrefab);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aa6fa692d80eaf8419e559c35034f016
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -0,0 +1,33 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.ClientSceneTests
|
||||||
|
{
|
||||||
|
public class ClientSceneTests_UnregisterSpawnHandler : ClientSceneTestsBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void RemovesSpawnHandlersFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.spawnHandlers.Add(validPrefabGuid, new SpawnHandlerDelegate(x => null));
|
||||||
|
NetworkClient.UnregisterSpawnHandler(validPrefabGuid);
|
||||||
|
Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(validPrefabGuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemovesUnSpawnHandlersFromDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.unspawnHandlers.Add(validPrefabGuid, new UnSpawnDelegate(x => {}));
|
||||||
|
NetworkClient.UnregisterSpawnHandler(validPrefabGuid);
|
||||||
|
Assert.IsFalse(NetworkClient.unspawnHandlers.ContainsKey(validPrefabGuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DoesNotRemovePrefabDictionary()
|
||||||
|
{
|
||||||
|
NetworkClient.prefabs.Add(validPrefabGuid, validPrefab);
|
||||||
|
NetworkClient.UnregisterSpawnHandler(validPrefabGuid);
|
||||||
|
// Should not be removed
|
||||||
|
Assert.IsTrue(NetworkClient.prefabs.ContainsKey(validPrefabGuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 49ef76b8883ba3845942503683c9a9b3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
182
Assets/Mirror/Tests/Editor/CommandOverrideTest.cs
Normal file
182
Assets/Mirror/Tests/Editor/CommandOverrideTest.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.RemoteAttrributeTest
|
||||||
|
{
|
||||||
|
class VirtualCommand : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int> onVirtualSendInt;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public virtual void CmdSendInt(int someInt) =>
|
||||||
|
onVirtualSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class VirtualNoOverrideCommand : VirtualCommand {}
|
||||||
|
|
||||||
|
class VirtualOverrideCommand : VirtualCommand
|
||||||
|
{
|
||||||
|
public event Action<int> onOverrideSendInt;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public override void CmdSendInt(int someInt) =>
|
||||||
|
onOverrideSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class VirtualOverrideCommandWithBase : VirtualCommand
|
||||||
|
{
|
||||||
|
public event Action<int> onOverrideSendInt;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public override void CmdSendInt(int someInt)
|
||||||
|
{
|
||||||
|
base.CmdSendInt(someInt);
|
||||||
|
onOverrideSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for 2 overrides
|
||||||
|
class VirtualOverrideCommandWithBase2 : VirtualOverrideCommandWithBase
|
||||||
|
{
|
||||||
|
public event Action<int> onOverrideSendInt2;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public override void CmdSendInt(int someInt)
|
||||||
|
{
|
||||||
|
base.CmdSendInt(someInt);
|
||||||
|
onOverrideSendInt2?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommandOverrideTest : RemoteTestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void VirtualCommandIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualCommand hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VirtualCommandWithNoOverrideIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualNoOverrideCommand hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OverrideVirtualCommandIsCalled()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideCommand hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
int overrideCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
};
|
||||||
|
hostBehaviour.onOverrideSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
overrideCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(0));
|
||||||
|
Assert.That(overrideCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OverrideVirtualWithBaseCallsBothVirtualAndBase()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideCommandWithBase hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
int overrideCallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.onOverrideSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
overrideCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
Assert.That(overrideCallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OverrideVirtualWithBaseCallsAllMethodsThatCallBase()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out VirtualOverrideCommandWithBase2 hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int virtualCallCount = 0;
|
||||||
|
int overrideCallCount = 0;
|
||||||
|
int override2CallCount = 0;
|
||||||
|
hostBehaviour.onVirtualSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
virtualCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.onOverrideSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
overrideCallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.onOverrideSendInt2 += incomingInt =>
|
||||||
|
{
|
||||||
|
override2CallCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(virtualCallCount, Is.EqualTo(1));
|
||||||
|
Assert.That(overrideCallCount, Is.EqualTo(1));
|
||||||
|
Assert.That(override2CallCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/CommandOverrideTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/CommandOverrideTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 881c801c26e90df43b3558a23c96e0ea
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
247
Assets/Mirror/Tests/Editor/CommandTest.cs
Normal file
247
Assets/Mirror/Tests/Editor/CommandTest.cs
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.RemoteAttrributeTest
|
||||||
|
{
|
||||||
|
class AuthorityBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int> onSendInt;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public void SendInt(int someInt) =>
|
||||||
|
onSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class IgnoreAuthorityBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int> onSendInt;
|
||||||
|
|
||||||
|
[Command(requiresAuthority = false)]
|
||||||
|
public void CmdSendInt(int someInt) =>
|
||||||
|
onSendInt?.Invoke(someInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SenderConnectionBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int, NetworkConnection> onSendInt;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public void CmdSendInt(int someInt, NetworkConnectionToClient conn = null) =>
|
||||||
|
onSendInt?.Invoke(someInt, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SenderConnectionIgnoreAuthorityBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<int, NetworkConnection> onSendInt;
|
||||||
|
|
||||||
|
[Command(requiresAuthority = false)]
|
||||||
|
public void CmdSendInt(int someInt, NetworkConnectionToClient conn = null) =>
|
||||||
|
onSendInt?.Invoke(someInt, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThrowBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public const string ErrorMessage = "Bad things happened";
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public void SendThrow(int _) => throw new Exception(ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandOverloads : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public int firstCalled = 0;
|
||||||
|
public int secondCalled = 0;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public void TheCommand(int _) => ++firstCalled;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public void TheCommand(string _) => ++secondCalled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CommandTest : RemoteTestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void CommandIsSentWithAuthority()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out AuthorityBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int callCount = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.SendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(callCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void WarningForCommandSentWithoutAuthority()
|
||||||
|
{
|
||||||
|
// spawn without owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out AuthorityBehaviour hostBehaviour);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int callCount = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
};
|
||||||
|
LogAssert.Expect(LogType.Warning, $"Trying to send command for object without authority. System.Void Mirror.Tests.RemoteAttrributeTest.AuthorityBehaviour::SendInt(System.Int32)");
|
||||||
|
hostBehaviour.SendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(callCount, Is.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CommandIsSentWithAuthorityWhenIgnoringAuthority()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out IgnoreAuthorityBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int callCount = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(callCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CommandIsSentWithoutAuthorityWhenIgnoringAuthority()
|
||||||
|
{
|
||||||
|
// spawn without owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out IgnoreAuthorityBehaviour hostBehaviour);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
|
||||||
|
int callCount = 0;
|
||||||
|
hostBehaviour.onSendInt += incomingInt =>
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
};
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(callCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// test to prevent https://github.com/vis2k/Mirror/issues/2629
|
||||||
|
// from happening again in the future
|
||||||
|
// -> [Command]s can be called on other objects with requiresAuthority=false.
|
||||||
|
// -> those objects don't have a .connectionToServer
|
||||||
|
// -> we broke it when using .connectionToServer instead of
|
||||||
|
// NetworkClient.connection in SendCommandInternal.
|
||||||
|
[Test]
|
||||||
|
public void Command_RequiresAuthorityFalse_ForOtherObjectWithoutConnectionToServer()
|
||||||
|
{
|
||||||
|
// spawn without owner (= without connectionToClient)
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out IgnoreAuthorityBehaviour comp);
|
||||||
|
|
||||||
|
// setup callback
|
||||||
|
int called = 0;
|
||||||
|
comp.onSendInt += _ => { ++called; };
|
||||||
|
|
||||||
|
// call command. don't require authority.
|
||||||
|
// the object doesn't have a .connectionToServer (like a scene object)
|
||||||
|
Assert.That(comp.connectionToServer, Is.Null);
|
||||||
|
comp.CmdSendInt(0);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SenderConnectionIsSetWhenCommandIsRecieved()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out SenderConnectionBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
NetworkConnectionToClient connectionToClient = NetworkServer.connections[0];
|
||||||
|
Debug.Assert(connectionToClient != null, $"connectionToClient was null, This means that the test is broken and will give the wrong results");
|
||||||
|
|
||||||
|
|
||||||
|
int callCount = 0;
|
||||||
|
hostBehaviour.onSendInt += (incomingInt, incomingConn) =>
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
Assert.That(incomingConn, Is.EqualTo(connectionToClient));
|
||||||
|
};
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(callCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SenderConnectionIsSetWhenCommandIsRecievedWithIgnoreAuthority()
|
||||||
|
{
|
||||||
|
// spawn without owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out SenderConnectionIgnoreAuthorityBehaviour hostBehaviour);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
NetworkConnectionToClient connectionToClient = NetworkServer.connections[0];
|
||||||
|
Debug.Assert(connectionToClient != null, $"connectionToClient was null, This means that the test is broken and will give the wrong results");
|
||||||
|
|
||||||
|
int callCount = 0;
|
||||||
|
hostBehaviour.onSendInt += (incomingInt, incomingConn) =>
|
||||||
|
{
|
||||||
|
callCount++;
|
||||||
|
Assert.That(incomingInt, Is.EqualTo(someInt));
|
||||||
|
Assert.That(incomingConn, Is.EqualTo(connectionToClient));
|
||||||
|
};
|
||||||
|
hostBehaviour.CmdSendInt(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(callCount, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CommandThatThrowsShouldBeCaught()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out ThrowBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const int someInt = 20;
|
||||||
|
NetworkConnectionToClient connectionToClient = NetworkServer.connections[0];
|
||||||
|
Debug.Assert(connectionToClient != null, $"connectionToClient was null, This means that the test is broken and will give the wrong results");
|
||||||
|
|
||||||
|
LogAssert.Expect(LogType.Error, new Regex($".*{ThrowBehaviour.ErrorMessage}.*"));
|
||||||
|
Assert.DoesNotThrow(() =>
|
||||||
|
{
|
||||||
|
hostBehaviour.SendThrow(someInt);
|
||||||
|
ProcessMessages();
|
||||||
|
}, "Processing new message should not throw, the exception from SendThrow should be caught");
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteCalls uses md.FullName which gives us the full command/rpc name
|
||||||
|
// like "System.Void Mirror.Tests.RemoteAttrributeTest.AuthorityBehaviour::SendInt(System.Int32)"
|
||||||
|
// which means overloads with same name but different types should work.
|
||||||
|
[Test]
|
||||||
|
public void CommandOverloads()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out _, out _, out CommandOverloads comp, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
// call both overloads once
|
||||||
|
comp.TheCommand(42);
|
||||||
|
comp.TheCommand("A");
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(comp.firstCalled, Is.EqualTo(1));
|
||||||
|
Assert.That(comp.secondCalled, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/CommandTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/CommandTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1dd3f8a95eee6f74997bc8abcd43a401
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
257
Assets/Mirror/Tests/Editor/CompressionTests.cs
Normal file
257
Assets/Mirror/Tests/Editor/CompressionTests.cs
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class CompressionTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void LargestAbsoluteComponentIndex()
|
||||||
|
{
|
||||||
|
// positive value & xyw smallest
|
||||||
|
Vector4 value = new Vector4(1, 3, 4, 2);
|
||||||
|
int index = Compression.LargestAbsoluteComponentIndex(value, out float largest, out Vector3 withoutLargest);
|
||||||
|
Assert.That(index, Is.EqualTo(2));
|
||||||
|
Assert.That(largest, Is.EqualTo(Mathf.Abs(value.z)));
|
||||||
|
Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.x, value.y, value.w)));
|
||||||
|
|
||||||
|
// negative value should use abs & xzw smallest
|
||||||
|
value = new Vector4(1, -5, 4, 0);
|
||||||
|
index = Compression.LargestAbsoluteComponentIndex(value, out largest, out withoutLargest);
|
||||||
|
Assert.That(index, Is.EqualTo(1));
|
||||||
|
Assert.That(largest, Is.EqualTo(Mathf.Abs(value.y)));
|
||||||
|
Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.x, value.z, value.w)));
|
||||||
|
|
||||||
|
// positive value & yzw smallest
|
||||||
|
value = new Vector4(5, 2, 3, 4);
|
||||||
|
index = Compression.LargestAbsoluteComponentIndex(value, out largest, out withoutLargest);
|
||||||
|
Assert.That(index, Is.EqualTo(0));
|
||||||
|
Assert.That(largest, Is.EqualTo(Mathf.Abs(value.x)));
|
||||||
|
Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.y, value.z, value.w)));
|
||||||
|
|
||||||
|
// test to guarantee it uses 'abs' for first value
|
||||||
|
// to reproduce https://github.com/vis2k/Mirror/issues/2674
|
||||||
|
// IF all values are properly 'abs', THEN first one should be largest
|
||||||
|
value = new Vector4(-3, 0, 1, 2);
|
||||||
|
index = Compression.LargestAbsoluteComponentIndex(value, out largest, out withoutLargest);
|
||||||
|
Assert.That(index, Is.EqualTo(0));
|
||||||
|
Assert.That(largest, Is.EqualTo(Mathf.Abs(value.x)));
|
||||||
|
Assert.That(withoutLargest, Is.EqualTo(new Vector3(value.y, value.z, value.w)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Ignore("Enable when needed.")]
|
||||||
|
public void LargestAbsoluteComponentIndexBenchmark()
|
||||||
|
{
|
||||||
|
Vector4 value = new Vector4(1, 2, 3, 4);
|
||||||
|
for (int i = 0; i < 100000; ++i)
|
||||||
|
Compression.LargestAbsoluteComponentIndex(value, out float _, out Vector3 _);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ScaleFloatToUShort()
|
||||||
|
{
|
||||||
|
Assert.That(Compression.ScaleFloatToUShort(-1f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(0));
|
||||||
|
Assert.That(Compression.ScaleFloatToUShort(0f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(32767));
|
||||||
|
Assert.That(Compression.ScaleFloatToUShort(0.5f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(49151));
|
||||||
|
Assert.That(Compression.ScaleFloatToUShort(1f, -1f, 1f, ushort.MinValue, ushort.MaxValue), Is.EqualTo(65535));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ScaleUShortToFloat()
|
||||||
|
{
|
||||||
|
Assert.That(Compression.ScaleUShortToFloat(0, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(-1).Within(0.0001f));
|
||||||
|
Assert.That(Compression.ScaleUShortToFloat(32767, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(-0f).Within(0.0001f));
|
||||||
|
Assert.That(Compression.ScaleUShortToFloat(49151, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(0.5f).Within(0.0001f));
|
||||||
|
Assert.That(Compression.ScaleUShortToFloat(65535, ushort.MinValue, ushort.MaxValue, -1, 1), Is.EqualTo(1).Within(0.0001f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CompressAndDecompressQuaternion()
|
||||||
|
{
|
||||||
|
// we need a normalized value
|
||||||
|
Quaternion value = new Quaternion(1, 3, 4, 2).normalized;
|
||||||
|
|
||||||
|
// compress
|
||||||
|
uint data = Compression.CompressQuaternion(value);
|
||||||
|
Assert.That(data, Is.EqualTo(0xA83E2F07));
|
||||||
|
|
||||||
|
// decompress
|
||||||
|
Quaternion decompressed = Compression.DecompressQuaternion(data);
|
||||||
|
Assert.That(decompressed.x, Is.EqualTo(value.x).Within(0.005f));
|
||||||
|
Assert.That(decompressed.y, Is.EqualTo(value.y).Within(0.005f));
|
||||||
|
Assert.That(decompressed.z, Is.EqualTo(value.z).Within(0.005f));
|
||||||
|
Assert.That(decompressed.w, Is.EqualTo(value.w).Within(0.005f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate all [0..360] euler angles for x, y, z
|
||||||
|
// to make sure it all works and we missed nothing.
|
||||||
|
[Test]
|
||||||
|
public void CompressAndDecompressQuaternion_Iterate_0_to_360()
|
||||||
|
{
|
||||||
|
// stepSize 1: 360 * 360 * 360 = 46 million [takes 96 s]
|
||||||
|
// stepSize 5: 72 * 72 * 72 = 373 thousand [takes 700 ms]
|
||||||
|
// stepSize 10: 36 * 36 * 36 = 46 thousand [takes 100 ms]
|
||||||
|
//
|
||||||
|
// => 10 is enough. 700ms accumulates in hours of time waited over
|
||||||
|
// the years..
|
||||||
|
const int stepSize = 10;
|
||||||
|
|
||||||
|
for (int x = 0; x <= 360; x += stepSize)
|
||||||
|
{
|
||||||
|
for (int y = 0; y <= 360; y += stepSize)
|
||||||
|
{
|
||||||
|
for (int z = 0; z <= 360; z += stepSize)
|
||||||
|
{
|
||||||
|
// we need a normalized value
|
||||||
|
Quaternion value = Quaternion.Euler(x, y, z).normalized;
|
||||||
|
|
||||||
|
// compress
|
||||||
|
uint data = Compression.CompressQuaternion(value);
|
||||||
|
|
||||||
|
// decompress
|
||||||
|
Quaternion decompressed = Compression.DecompressQuaternion(data);
|
||||||
|
|
||||||
|
// compare them. Quaternion.Angle is easiest to get the angle
|
||||||
|
// between them. using .eulerAngles would give 0, 90, 360 which is
|
||||||
|
// hard to compare.
|
||||||
|
float angle = Quaternion.Angle(value, decompressed);
|
||||||
|
// 1 degree tolerance
|
||||||
|
Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// someone mentioned issues with 90 degree euler becoming -90 degree
|
||||||
|
[Test]
|
||||||
|
public void CompressAndDecompressQuaternion_90DegreeEuler()
|
||||||
|
{
|
||||||
|
// we need a normalized value
|
||||||
|
Quaternion value = Quaternion.Euler(0, 90, 0).normalized;
|
||||||
|
|
||||||
|
// compress
|
||||||
|
uint data = Compression.CompressQuaternion(value);
|
||||||
|
|
||||||
|
// decompress
|
||||||
|
Quaternion decompressed = Compression.DecompressQuaternion(data);
|
||||||
|
|
||||||
|
// compare them. Quaternion.Angle is easiest to get the angle
|
||||||
|
// between them. using .eulerAngles would give 0, 90, 360 which is
|
||||||
|
// hard to compare.
|
||||||
|
Debug.Log($"euler={decompressed.eulerAngles}");
|
||||||
|
float angle = Quaternion.Angle(value, decompressed);
|
||||||
|
// 1 degree tolerance
|
||||||
|
Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for issue https://github.com/vis2k/Mirror/issues/2674
|
||||||
|
[Test]
|
||||||
|
public void CompressAndDecompressQuaternion_2674()
|
||||||
|
{
|
||||||
|
// we need a normalized value
|
||||||
|
Quaternion value = Quaternion.Euler(338.850037f, 170.609955f, 182.979996f).normalized;
|
||||||
|
Debug.Log($"original={value.eulerAngles}");
|
||||||
|
|
||||||
|
// compress
|
||||||
|
uint data = Compression.CompressQuaternion(value);
|
||||||
|
|
||||||
|
// decompress
|
||||||
|
Quaternion decompressed = Compression.DecompressQuaternion(data);
|
||||||
|
|
||||||
|
// compare them. Quaternion.Angle is easiest to get the angle
|
||||||
|
// between them. using .eulerAngles would give 0, 90, 360 which is
|
||||||
|
// hard to compare.
|
||||||
|
|
||||||
|
// (51.6, 355.5, 348.1)
|
||||||
|
Debug.Log($"euler={decompressed.eulerAngles}");
|
||||||
|
float angle = Quaternion.Angle(value, decompressed);
|
||||||
|
// 1 degree tolerance
|
||||||
|
Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// client sending invalid data should still produce valid quaternions to
|
||||||
|
// avoid any possible bugs on server
|
||||||
|
[Test]
|
||||||
|
public void DecompressQuaternionInvalidData()
|
||||||
|
{
|
||||||
|
// decompress
|
||||||
|
// 0xFFFFFFFF will decompress to (0.7, 0.7, 0.7, NaN)
|
||||||
|
Quaternion decompressed = Compression.DecompressQuaternion(0xFFFFFFFF);
|
||||||
|
Assert.That(decompressed, Is.EqualTo(Quaternion.identity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VarInt()
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
Compression.CompressVarUInt(writer, 0);
|
||||||
|
Compression.CompressVarUInt(writer, 234);
|
||||||
|
Compression.CompressVarUInt(writer, 2284);
|
||||||
|
Compression.CompressVarUInt(writer, 67821);
|
||||||
|
Compression.CompressVarUInt(writer, 16777210);
|
||||||
|
Compression.CompressVarUInt(writer, 16777219);
|
||||||
|
Compression.CompressVarUInt(writer, 4294967295);
|
||||||
|
Compression.CompressVarUInt(writer, 1099511627775);
|
||||||
|
Compression.CompressVarUInt(writer, 281474976710655);
|
||||||
|
Compression.CompressVarUInt(writer, 72057594037927935);
|
||||||
|
Compression.CompressVarUInt(writer, ulong.MaxValue);
|
||||||
|
|
||||||
|
Compression.CompressVarInt(writer, long.MinValue);
|
||||||
|
Compression.CompressVarInt(writer, -72057594037927935);
|
||||||
|
Compression.CompressVarInt(writer, -281474976710655);
|
||||||
|
Compression.CompressVarInt(writer, -1099511627775);
|
||||||
|
Compression.CompressVarInt(writer, -4294967295);
|
||||||
|
Compression.CompressVarInt(writer, -16777219);
|
||||||
|
Compression.CompressVarInt(writer, -16777210);
|
||||||
|
Compression.CompressVarInt(writer, -67821);
|
||||||
|
Compression.CompressVarInt(writer, -2284);
|
||||||
|
Compression.CompressVarInt(writer, -234);
|
||||||
|
Compression.CompressVarInt(writer, 0);
|
||||||
|
Compression.CompressVarInt(writer, 234);
|
||||||
|
Compression.CompressVarInt(writer, 2284);
|
||||||
|
Compression.CompressVarInt(writer, 67821);
|
||||||
|
Compression.CompressVarInt(writer, 16777210);
|
||||||
|
Compression.CompressVarInt(writer, 16777219);
|
||||||
|
Compression.CompressVarInt(writer, 4294967295);
|
||||||
|
Compression.CompressVarInt(writer, 1099511627775);
|
||||||
|
Compression.CompressVarInt(writer, 281474976710655);
|
||||||
|
Compression.CompressVarInt(writer, 72057594037927935);
|
||||||
|
Compression.CompressVarInt(writer, long.MaxValue);
|
||||||
|
|
||||||
|
NetworkReader reader = new NetworkReader(writer.ToArray());
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(0));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(234));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(2284));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(67821));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(16777210));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(16777219));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(4294967295));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(1099511627775));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(281474976710655));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(72057594037927935));
|
||||||
|
Assert.That(Compression.DecompressVarUInt(reader), Is.EqualTo(ulong.MaxValue));
|
||||||
|
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(long.MinValue));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-72057594037927935));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-281474976710655));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-1099511627775));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-4294967295));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-16777219));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-16777210));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-67821));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-2284));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(-234));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(0));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(234));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(2284));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(67821));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(16777210));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(16777219));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(4294967295));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(1099511627775));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(281474976710655));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(72057594037927935));
|
||||||
|
Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(long.MaxValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Assets/Mirror/Tests/Editor/CompressionTests.cs.meta
Normal file
3
Assets/Mirror/Tests/Editor/CompressionTests.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 541cf2bc89fe4395b2a50d921c91424a
|
||||||
|
timeCreated: 1613190697
|
53
Assets/Mirror/Tests/Editor/CustomRWTest.cs
Normal file
53
Assets/Mirror/Tests/Editor/CustomRWTest.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class MockQuest
|
||||||
|
{
|
||||||
|
public int Id;
|
||||||
|
|
||||||
|
public MockQuest(int id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MockQuest()
|
||||||
|
{
|
||||||
|
Id = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MockQuestReaderWriter
|
||||||
|
{
|
||||||
|
public static void WriteQuest(this NetworkWriter writer, MockQuest quest)
|
||||||
|
{
|
||||||
|
writer.WriteInt(quest.Id);
|
||||||
|
}
|
||||||
|
public static MockQuest WriteQuest(this NetworkReader reader)
|
||||||
|
{
|
||||||
|
return new MockQuest(reader.ReadInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class CustomRWTest
|
||||||
|
{
|
||||||
|
public struct QuestMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
public MockQuest quest;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCustomRW()
|
||||||
|
{
|
||||||
|
QuestMessage message = new QuestMessage
|
||||||
|
{
|
||||||
|
quest = new MockQuest(100)
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] data = MessagePackingTest.PackToByteArray(message);
|
||||||
|
QuestMessage unpacked = MessagePackingTest.UnpackFromByteArray<QuestMessage>(data);
|
||||||
|
Assert.That(unpacked.quest.Id, Is.EqualTo(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/CustomRWTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/CustomRWTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3d74d53ca2c8c4b1195833376f9f6bb6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
91
Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs
Normal file
91
Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public static class MyCustomEnumReadWrite
|
||||||
|
{
|
||||||
|
public static void WriteMyCustomEnum(this NetworkWriter networkWriter, EnumReadWriteTests.MyCustomEnum customEnum)
|
||||||
|
{
|
||||||
|
// if O write N
|
||||||
|
if (customEnum == EnumReadWriteTests.MyCustomEnum.O)
|
||||||
|
{
|
||||||
|
networkWriter.WriteInt((int)EnumReadWriteTests.MyCustomEnum.N);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
networkWriter.WriteInt((int)customEnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static EnumReadWriteTests.MyCustomEnum ReadMyCustomEnum(this NetworkReader networkReader)
|
||||||
|
{
|
||||||
|
return (EnumReadWriteTests.MyCustomEnum)networkReader.ReadInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class EnumReadWriteTests
|
||||||
|
{
|
||||||
|
public struct ByteMessage : NetworkMessage { public MyByteEnum byteEnum; }
|
||||||
|
public enum MyByteEnum : byte
|
||||||
|
{
|
||||||
|
A, B, C, D
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ShortMessage : NetworkMessage { public MyShortEnum shortEnum; }
|
||||||
|
public enum MyShortEnum : short
|
||||||
|
{
|
||||||
|
E, F, G, H
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct CustomMessage : NetworkMessage { public MyCustomEnum customEnum; }
|
||||||
|
|
||||||
|
public enum MyCustomEnum
|
||||||
|
{
|
||||||
|
M, N, O, P
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ByteIsSentForByteEnum()
|
||||||
|
{
|
||||||
|
ByteMessage msg = new ByteMessage() { byteEnum = MyByteEnum.B };
|
||||||
|
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
writer.Write(msg);
|
||||||
|
|
||||||
|
// should be 1 byte for data
|
||||||
|
Assert.That(writer.Position, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShortIsSentForShortEnum()
|
||||||
|
{
|
||||||
|
ShortMessage msg = new ShortMessage() { shortEnum = MyShortEnum.G };
|
||||||
|
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
writer.Write(msg);
|
||||||
|
|
||||||
|
// should be 2 bytes for data
|
||||||
|
Assert.That(writer.Position, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CustomWriterIsUsedForEnum()
|
||||||
|
{
|
||||||
|
CustomMessage serverMsg = new CustomMessage() { customEnum = MyCustomEnum.O };
|
||||||
|
CustomMessage clientMsg = SerializeAndDeserializeMessage(serverMsg);
|
||||||
|
|
||||||
|
// custom writer should write N if it sees O
|
||||||
|
Assert.That(clientMsg.customEnum, Is.EqualTo(MyCustomEnum.N));
|
||||||
|
}
|
||||||
|
T SerializeAndDeserializeMessage<T>(T msg)
|
||||||
|
where T : struct, NetworkMessage
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
|
||||||
|
writer.Write(msg);
|
||||||
|
|
||||||
|
NetworkReader reader = new NetworkReader(writer.ToArraySegment());
|
||||||
|
|
||||||
|
return reader.Read<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/EnumReadWriteTests.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 79e6cd90456eed340a72b1bdb6fe7e49
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
42
Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs
Normal file
42
Assets/Mirror/Tests/Editor/ExponentialMovingAverageTest.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ExponentialMovingAverageTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestInitial()
|
||||||
|
{
|
||||||
|
ExponentialMovingAverage ema = new ExponentialMovingAverage(10);
|
||||||
|
|
||||||
|
ema.Add(3);
|
||||||
|
|
||||||
|
Assert.That(ema.Value, Is.EqualTo(3));
|
||||||
|
Assert.That(ema.Var, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMovingAverage()
|
||||||
|
{
|
||||||
|
ExponentialMovingAverage ema = new ExponentialMovingAverage(10);
|
||||||
|
|
||||||
|
ema.Add(5);
|
||||||
|
ema.Add(6);
|
||||||
|
|
||||||
|
Assert.That(ema.Value, Is.EqualTo(5.1818).Within(0.0001f));
|
||||||
|
Assert.That(ema.Var, Is.EqualTo(0.1487).Within(0.0001f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestVar()
|
||||||
|
{
|
||||||
|
ExponentialMovingAverage ema = new ExponentialMovingAverage(10);
|
||||||
|
|
||||||
|
ema.Add(5);
|
||||||
|
ema.Add(6);
|
||||||
|
ema.Add(7);
|
||||||
|
|
||||||
|
Assert.That(ema.Var, Is.EqualTo(0.6134).Within(0.0001f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8e3f2ecadd13149f29cd3e83ef6a4bff
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
26
Assets/Mirror/Tests/Editor/ExtensionsTest.cs
Normal file
26
Assets/Mirror/Tests/Editor/ExtensionsTest.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class ExtensionsTest
|
||||||
|
{
|
||||||
|
// supposed to return same result on all platforms
|
||||||
|
[Test]
|
||||||
|
public void GetStableHashHode()
|
||||||
|
{
|
||||||
|
Assert.That("".GetStableHashCode(), Is.EqualTo(23));
|
||||||
|
Assert.That("Test".GetStableHashCode(), Is.EqualTo(23844169));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CopyToList()
|
||||||
|
{
|
||||||
|
List<int> source = new List<int>{1, 2, 3};
|
||||||
|
List<int> destination = new List<int>();
|
||||||
|
source.CopyTo(destination);
|
||||||
|
Assert.That(destination.SequenceEqual(source), Is.True);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Assets/Mirror/Tests/Editor/ExtensionsTest.cs.meta
Normal file
3
Assets/Mirror/Tests/Editor/ExtensionsTest.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 21e1452d6f734618a9364a2c6c116922
|
||||||
|
timeCreated: 1621762116
|
56
Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs
Normal file
56
Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using Mirror.Tests.RemoteAttrributeTest;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.GeneratedWriterTests
|
||||||
|
{
|
||||||
|
public class BaseData
|
||||||
|
{
|
||||||
|
public bool toggle;
|
||||||
|
}
|
||||||
|
public class SomeOtherData : BaseData
|
||||||
|
{
|
||||||
|
public int usefulNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DataSenderBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public event Action<SomeOtherData> onData;
|
||||||
|
|
||||||
|
[Command]
|
||||||
|
public void CmdSendData(SomeOtherData otherData)
|
||||||
|
{
|
||||||
|
onData?.Invoke(otherData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FieldsInBaseClasses : RemoteTestBase
|
||||||
|
{
|
||||||
|
[Test, Ignore("Destroy is needed for the code. Can't be called in Edit mode.")]
|
||||||
|
public void WriterShouldIncludeFieldsInBaseClass()
|
||||||
|
{
|
||||||
|
// spawn with owner
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out DataSenderBehaviour hostBehaviour, NetworkServer.localConnection);
|
||||||
|
|
||||||
|
const bool toggle = true;
|
||||||
|
const int usefulNumber = 10;
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
hostBehaviour.onData += data =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(data.usefulNumber, Is.EqualTo(usefulNumber));
|
||||||
|
Assert.That(data.toggle, Is.EqualTo(toggle));
|
||||||
|
};
|
||||||
|
hostBehaviour.CmdSendData(new SomeOtherData
|
||||||
|
{
|
||||||
|
usefulNumber = usefulNumber,
|
||||||
|
toggle = toggle
|
||||||
|
});
|
||||||
|
|
||||||
|
ProcessMessages();
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 518288ffe7c7215458a98466131fc7af
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
8
Assets/Mirror/Tests/Editor/Generated.meta
Normal file
8
Assets/Mirror/Tests/Editor/Generated.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f1a04c2c41f19ea46b0b1a33c8f2ae89
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
5946
Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs
Normal file
5946
Assets/Mirror/Tests/Editor/Generated/AttritubeTest.gen.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e49c298f22d4292439dc17f7e59f08b7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
1049
Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs
Normal file
1049
Assets/Mirror/Tests/Editor/Generated/CollectionWriterTests.gen.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c573b90d8949dec4cafb4f7401be9950
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
58
Assets/Mirror/Tests/Editor/Grid2DTests.cs
Normal file
58
Assets/Mirror/Tests/Editor/Grid2DTests.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class Grid2DTests
|
||||||
|
{
|
||||||
|
Grid2D<int> grid = new Grid2D<int>();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddAndGetNeighbours()
|
||||||
|
{
|
||||||
|
// add two at (0, 0)
|
||||||
|
grid.Add(Vector2Int.zero, 1);
|
||||||
|
grid.Add(Vector2Int.zero, 2);
|
||||||
|
HashSet<int> result = new HashSet<int>();
|
||||||
|
grid.GetWithNeighbours(Vector2Int.zero, result);
|
||||||
|
Assert.That(result.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(result.Contains(1), Is.True);
|
||||||
|
Assert.That(result.Contains(2), Is.True);
|
||||||
|
|
||||||
|
// add a neighbour at (1, 1)
|
||||||
|
grid.Add(new Vector2Int(1, 1), 3);
|
||||||
|
grid.GetWithNeighbours(Vector2Int.zero, result);
|
||||||
|
Assert.That(result.Count, Is.EqualTo(3));
|
||||||
|
Assert.That(result.Contains(1), Is.True);
|
||||||
|
Assert.That(result.Contains(2), Is.True);
|
||||||
|
Assert.That(result.Contains(3), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetIgnoresTooFarNeighbours()
|
||||||
|
{
|
||||||
|
// add at (0, 0)
|
||||||
|
grid.Add(Vector2Int.zero, 1);
|
||||||
|
|
||||||
|
// get at (2, 0) which is out of 9 neighbour radius
|
||||||
|
HashSet<int> result = new HashSet<int>();
|
||||||
|
grid.GetWithNeighbours(new Vector2Int(2, 0), result);
|
||||||
|
Assert.That(result.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ClearNonAlloc()
|
||||||
|
{
|
||||||
|
// add some
|
||||||
|
grid.Add(Vector2Int.zero, 1);
|
||||||
|
grid.Add(Vector2Int.zero, 2);
|
||||||
|
|
||||||
|
// clear and check if empty now
|
||||||
|
grid.ClearNonAlloc();
|
||||||
|
HashSet<int> result = new HashSet<int>();
|
||||||
|
grid.GetWithNeighbours(Vector2Int.zero, result);
|
||||||
|
Assert.That(result.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Assets/Mirror/Tests/Editor/Grid2DTests.cs.meta
Normal file
3
Assets/Mirror/Tests/Editor/Grid2DTests.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f8f3c4f37bb54824b5dfe70e0984b3d3
|
||||||
|
timeCreated: 1613188745
|
95
Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs
Normal file
95
Assets/Mirror/Tests/Editor/InterestManagementTests_Common.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// default = no component = everyone sees everyone
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public abstract class InterestManagementTests_Common : MirrorEditModeTest
|
||||||
|
{
|
||||||
|
protected GameObject gameObjectA;
|
||||||
|
protected NetworkIdentity identityA;
|
||||||
|
protected NetworkConnectionToClient connectionA;
|
||||||
|
|
||||||
|
protected GameObject gameObjectB;
|
||||||
|
protected NetworkIdentity identityB;
|
||||||
|
protected NetworkConnectionToClient connectionB;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
// A with connectionId = 0x0A, netId = 0xAA
|
||||||
|
CreateNetworked(out gameObjectA, out identityA);
|
||||||
|
connectionA = new NetworkConnectionToClient(0x0A);
|
||||||
|
connectionA.isAuthenticated = true;
|
||||||
|
connectionA.isReady = true;
|
||||||
|
connectionA.identity = identityA;
|
||||||
|
NetworkServer.spawned[0xAA] = identityA;
|
||||||
|
|
||||||
|
// B
|
||||||
|
CreateNetworked(out gameObjectB, out identityB);
|
||||||
|
connectionB = new NetworkConnectionToClient(0x0B);
|
||||||
|
connectionB.isAuthenticated = true;
|
||||||
|
connectionB.isReady = true;
|
||||||
|
connectionB.identity = identityB;
|
||||||
|
NetworkServer.spawned[0xBB] = identityB;
|
||||||
|
|
||||||
|
// need to start server so that interest management works
|
||||||
|
NetworkServer.Listen(10);
|
||||||
|
|
||||||
|
// add both connections
|
||||||
|
NetworkServer.connections[connectionA.connectionId] = connectionA;
|
||||||
|
NetworkServer.connections[connectionB.connectionId] = connectionB;
|
||||||
|
|
||||||
|
// spawn both so that .observers is created
|
||||||
|
NetworkServer.Spawn(gameObjectA, connectionA);
|
||||||
|
NetworkServer.Spawn(gameObjectB, connectionB);
|
||||||
|
|
||||||
|
// spawn already runs interest management once
|
||||||
|
// clear observers and observing so tests can start from scratch
|
||||||
|
identityA.observers.Clear();
|
||||||
|
identityB.observers.Clear();
|
||||||
|
connectionA.observing.Clear();
|
||||||
|
connectionB.observing.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
// set isServer is false. otherwise Destroy instead of
|
||||||
|
// DestroyImmediate is called internally, giving an error in Editor
|
||||||
|
identityA.isServer = false;
|
||||||
|
|
||||||
|
// set isServer is false. otherwise Destroy instead of
|
||||||
|
// DestroyImmediate is called internally, giving an error in Editor
|
||||||
|
identityB.isServer = false;
|
||||||
|
|
||||||
|
// clear connections first. calling OnDisconnect wouldn't work since
|
||||||
|
// we have no real clients.
|
||||||
|
NetworkServer.connections.Clear();
|
||||||
|
|
||||||
|
base.TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// player should always see self no matter what
|
||||||
|
[Test]
|
||||||
|
public void PlayerAlwaysSeesSelf_Initial()
|
||||||
|
{
|
||||||
|
// rebuild for A
|
||||||
|
// initial rebuild adds all connections if no interest management available
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
|
||||||
|
// should see self
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// forceHidden should still work
|
||||||
|
[Test]
|
||||||
|
public abstract void ForceHidden_Initial();
|
||||||
|
|
||||||
|
// forceShown should still work
|
||||||
|
[Test]
|
||||||
|
public abstract void ForceShown_Initial();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f0349d2e3a74454e9dc8badec1db0289
|
||||||
|
timeCreated: 1613049868
|
@ -0,0 +1,62 @@
|
|||||||
|
// default = no component = everyone sees everyone
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class InterestManagementTests_Default : InterestManagementTests_Common
|
||||||
|
{
|
||||||
|
// no interest management (default)
|
||||||
|
// => forceHidden should still work
|
||||||
|
[Test]
|
||||||
|
public override void ForceHidden_Initial()
|
||||||
|
{
|
||||||
|
// force hide A
|
||||||
|
identityA.visible = Visibility.ForceHidden;
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild adds all connections if no interest management available
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// A should not be seen by B because A is force hidden
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
// B should be seen by A because
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no interest management (default)
|
||||||
|
// => forceShown should still work
|
||||||
|
[Test]
|
||||||
|
public override void ForceShown_Initial()
|
||||||
|
{
|
||||||
|
// force show A
|
||||||
|
identityA.visible = Visibility.ForceShown;
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild adds all connections if no interest management available
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// both should see each other because by default, everyone sees everyone
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no interest management (default)
|
||||||
|
// => everyone should see everyone
|
||||||
|
[Test]
|
||||||
|
public void EveryoneSeesEveryone_Initial()
|
||||||
|
{
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild adds all connections if no interest management available
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// both should see each other
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add tests to make sure old observers are removed etc.
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c5ac1fc2c25043378f80bc02d868a5d6
|
||||||
|
timeCreated: 1613042576
|
142
Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs
Normal file
142
Assets/Mirror/Tests/Editor/InterestManagementTests_Distance.cs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// Vector3.Distance based
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class InterestManagementTests_Distance : InterestManagementTests_Common
|
||||||
|
{
|
||||||
|
DistanceInterestManagement aoi;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
// create AOI GameObject
|
||||||
|
CreateGameObject(out GameObject go, out aoi);
|
||||||
|
aoi.visRange = 10;
|
||||||
|
// setup server aoi since InterestManagement Awake isn't called
|
||||||
|
NetworkServer.aoi = aoi;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
base.TearDown();
|
||||||
|
// clear server aoi again
|
||||||
|
NetworkServer.aoi = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => forceHidden should still work
|
||||||
|
[Test]
|
||||||
|
public override void ForceHidden_Initial()
|
||||||
|
{
|
||||||
|
// A and B are at (0,0,0) so within range!
|
||||||
|
|
||||||
|
// force hide A
|
||||||
|
identityA.visible = Visibility.ForceHidden;
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild while both are within range
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// A should not be seen by B because A is force hidden
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
// B should be seen by A because
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => forceHidden should still work
|
||||||
|
[Test]
|
||||||
|
public override void ForceShown_Initial()
|
||||||
|
{
|
||||||
|
// A and B are too far from each other
|
||||||
|
identityB.transform.position = Vector3.right * (aoi.visRange + 1);
|
||||||
|
|
||||||
|
// force show A
|
||||||
|
identityA.visible = Visibility.ForceShown;
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild while both are within range
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// A should see B because A is force shown
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
// B should not be seen by A because they are too far from each other
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void InRange_Initial()
|
||||||
|
{
|
||||||
|
// A and B are at (0,0,0) so within range!
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// both should see each other because they are in range
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void InRange_NotInitial()
|
||||||
|
{
|
||||||
|
// A and B are at (0,0,0) so within range!
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
NetworkServer.RebuildObservers(identityA, false);
|
||||||
|
NetworkServer.RebuildObservers(identityB, false);
|
||||||
|
|
||||||
|
// both should see each other because they are in range
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void OutOfRange_Initial()
|
||||||
|
{
|
||||||
|
// A and B are too far from each other
|
||||||
|
identityB.transform.position = Vector3.right * (aoi.visRange + 1);
|
||||||
|
|
||||||
|
// rebuild for boths
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// both should not see each other
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void OutOfRange_NotInitial()
|
||||||
|
{
|
||||||
|
// A and B are too far from each other
|
||||||
|
identityB.transform.position = Vector3.right * (aoi.visRange + 1);
|
||||||
|
|
||||||
|
// rebuild for boths
|
||||||
|
NetworkServer.RebuildObservers(identityA, false);
|
||||||
|
NetworkServer.RebuildObservers(identityB, false);
|
||||||
|
|
||||||
|
// both should not see each other
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add tests to make sure old observers are removed etc.
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ffb9dc0ff01e4f979c216984d7fc48d0
|
||||||
|
timeCreated: 1613049838
|
@ -0,0 +1,154 @@
|
|||||||
|
// default = no component = everyone sees everyone
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class InterestManagementTests_SpatialHashing : InterestManagementTests_Common
|
||||||
|
{
|
||||||
|
SpatialHashingInterestManagement aoi;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
// create spatial hashing object & component
|
||||||
|
CreateGameObject(out GameObject go, out aoi);
|
||||||
|
aoi.visRange = 10;
|
||||||
|
// setup server aoi since InterestManagement Awake isn't called
|
||||||
|
NetworkServer.aoi = aoi;
|
||||||
|
|
||||||
|
// rebuild grid once so the two connections are in there
|
||||||
|
aoi.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
base.TearDown();
|
||||||
|
// clear server aoi again
|
||||||
|
NetworkServer.aoi = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => forceHidden should still work
|
||||||
|
[Test]
|
||||||
|
public override void ForceHidden_Initial()
|
||||||
|
{
|
||||||
|
// A and B are at (0,0,0) so within range!
|
||||||
|
|
||||||
|
// force hide A
|
||||||
|
identityA.visible = Visibility.ForceHidden;
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild while both are within range
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// A should not be seen by B because A is force hidden
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
// B should be seen by A because
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => forceShown should still work
|
||||||
|
[Test]
|
||||||
|
public override void ForceShown_Initial()
|
||||||
|
{
|
||||||
|
// A and B are too far from each other
|
||||||
|
identityB.transform.position = Vector3.right * (aoi.visRange + 1);
|
||||||
|
|
||||||
|
// force show A
|
||||||
|
identityA.visible = Visibility.ForceShown;
|
||||||
|
|
||||||
|
// update grid now that positions were changed
|
||||||
|
aoi.Update();
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
// initial rebuild while both are within range
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// A should see B because A is force shown
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
// B should not be seen by A because they are too far from each other
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void InRange_Initial()
|
||||||
|
{
|
||||||
|
// A and B are at (0,0,0) so within range!
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// both should see each other because they are in range
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void InRange_NotInitial()
|
||||||
|
{
|
||||||
|
// A and B are at (0,0,0) so within range!
|
||||||
|
|
||||||
|
// rebuild for both
|
||||||
|
NetworkServer.RebuildObservers(identityA, false);
|
||||||
|
NetworkServer.RebuildObservers(identityB, false);
|
||||||
|
|
||||||
|
// both should see each other because they are in range
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.True);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void OutOfRange_Initial()
|
||||||
|
{
|
||||||
|
// A and B are too far from each other
|
||||||
|
identityB.transform.position = Vector3.right * (aoi.visRange + 1);
|
||||||
|
|
||||||
|
// update grid now that positions were changed
|
||||||
|
aoi.Update();
|
||||||
|
|
||||||
|
// rebuild for boths
|
||||||
|
NetworkServer.RebuildObservers(identityA, true);
|
||||||
|
NetworkServer.RebuildObservers(identityB, true);
|
||||||
|
|
||||||
|
// both should not see each other
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brute force interest management
|
||||||
|
// => everyone should see everyone if in range
|
||||||
|
[Test]
|
||||||
|
public void OutOfRange_NotInitial()
|
||||||
|
{
|
||||||
|
// A and B are too far from each other
|
||||||
|
identityB.transform.position = Vector3.right * (aoi.visRange + 1);
|
||||||
|
|
||||||
|
// update grid now that positions were changed
|
||||||
|
aoi.Update();
|
||||||
|
|
||||||
|
// rebuild for boths
|
||||||
|
NetworkServer.RebuildObservers(identityA, false);
|
||||||
|
NetworkServer.RebuildObservers(identityB, false);
|
||||||
|
|
||||||
|
// both should not see each other
|
||||||
|
Assert.That(identityA.observers.ContainsKey(connectionB.connectionId), Is.False);
|
||||||
|
Assert.That(identityB.observers.ContainsKey(connectionA.connectionId), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add tests to make sure old observers are removed etc.
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 63d9e0d6aa9a4eec8b4e2db07e6261bf
|
||||||
|
timeCreated: 1613117841
|
71
Assets/Mirror/Tests/Editor/LocalConnectionTest.cs
Normal file
71
Assets/Mirror/Tests/Editor/LocalConnectionTest.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class LocalConnectionTest : MirrorTest
|
||||||
|
{
|
||||||
|
struct TestMessage : NetworkMessage {}
|
||||||
|
|
||||||
|
LocalConnectionToClient connectionToClient;
|
||||||
|
LocalConnectionToServer connectionToServer;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
CreateLocalConnectionPair(out connectionToClient, out connectionToServer);
|
||||||
|
|
||||||
|
// set up server/client connections so message handling works
|
||||||
|
NetworkClient.connection = connectionToServer;
|
||||||
|
NetworkServer.connections[connectionToClient.connectionId] = connectionToClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
connectionToServer.Disconnect();
|
||||||
|
base.TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ClientToServerTest()
|
||||||
|
{
|
||||||
|
Assert.That(connectionToClient.address, Is.EqualTo("localhost"));
|
||||||
|
|
||||||
|
bool invoked = false;
|
||||||
|
void Handler(NetworkConnection conn, TestMessage message)
|
||||||
|
{
|
||||||
|
invoked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up handler on the server connection
|
||||||
|
NetworkServer.RegisterHandler<TestMessage>(Handler, false);
|
||||||
|
|
||||||
|
connectionToServer.Send(new TestMessage());
|
||||||
|
connectionToServer.Update();
|
||||||
|
|
||||||
|
Assert.True(invoked, "handler should have been invoked");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ServerToClient()
|
||||||
|
{
|
||||||
|
Assert.That(connectionToServer.address, Is.EqualTo("localhost"));
|
||||||
|
|
||||||
|
bool invoked = false;
|
||||||
|
void Handler(TestMessage message)
|
||||||
|
{
|
||||||
|
invoked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up handler on the client connection
|
||||||
|
NetworkClient.RegisterHandler<TestMessage>(Handler, false);
|
||||||
|
|
||||||
|
connectionToClient.Send(new TestMessage());
|
||||||
|
connectionToServer.Update();
|
||||||
|
|
||||||
|
Assert.True(invoked, "handler should have been invoked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/LocalConnectionTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/LocalConnectionTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 405841e2a21c64d7585d5c71d06ffff2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
125
Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs
Normal file
125
Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// TODO Send only supports structs. Consider removing those tests.
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests.MessageTests
|
||||||
|
{
|
||||||
|
class ParentMessage : NetworkMessage
|
||||||
|
{
|
||||||
|
public int parentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChildMessage : ParentMessage
|
||||||
|
{
|
||||||
|
public int childValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class RequestMessageBase : NetworkMessage
|
||||||
|
{
|
||||||
|
public int responseId = 0;
|
||||||
|
}
|
||||||
|
public class ResponseMessage : RequestMessageBase
|
||||||
|
{
|
||||||
|
public int state;
|
||||||
|
public string message = "";
|
||||||
|
public int errorCode = 0; // optional for error codes
|
||||||
|
}
|
||||||
|
|
||||||
|
//reverseOrder to test this https://github.com/vis2k/Mirror/issues/1925
|
||||||
|
public class ResponseMessageReverse : RequestMessageBaseReverse
|
||||||
|
{
|
||||||
|
public int state;
|
||||||
|
public string message = "";
|
||||||
|
public int errorCode = 0; // optional for error codes
|
||||||
|
}
|
||||||
|
public abstract class RequestMessageBaseReverse : NetworkMessage
|
||||||
|
{
|
||||||
|
public int responseId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class MessageInheritanceTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void SendsVauesInParentAndChildClass()
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
|
||||||
|
writer.Write(new ChildMessage
|
||||||
|
{
|
||||||
|
parentValue = 3,
|
||||||
|
childValue = 4
|
||||||
|
});
|
||||||
|
|
||||||
|
byte[] arr = writer.ToArray();
|
||||||
|
|
||||||
|
NetworkReader reader = new NetworkReader(arr);
|
||||||
|
ChildMessage received = reader.Read<ChildMessage>();
|
||||||
|
|
||||||
|
Assert.AreEqual(3, received.parentValue);
|
||||||
|
Assert.AreEqual(4, received.childValue);
|
||||||
|
|
||||||
|
int writeLength = writer.Position;
|
||||||
|
int readLength = reader.Position;
|
||||||
|
Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n writeLength={writeLength}\n readLength={readLength}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SendsVauesWhenUsingAbstractClass()
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
|
||||||
|
const int state = 2;
|
||||||
|
const string message = "hello world";
|
||||||
|
const int responseId = 5;
|
||||||
|
writer.Write(new ResponseMessage
|
||||||
|
{
|
||||||
|
state = state,
|
||||||
|
message = message,
|
||||||
|
responseId = responseId,
|
||||||
|
});
|
||||||
|
|
||||||
|
byte[] arr = writer.ToArray();
|
||||||
|
|
||||||
|
NetworkReader reader = new NetworkReader(arr);
|
||||||
|
ResponseMessage received = reader.Read<ResponseMessage>();
|
||||||
|
|
||||||
|
Assert.AreEqual(state, received.state);
|
||||||
|
Assert.AreEqual(message, received.message);
|
||||||
|
Assert.AreEqual(responseId, received.responseId);
|
||||||
|
|
||||||
|
int writeLength = writer.Position;
|
||||||
|
int readLength = reader.Position;
|
||||||
|
Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n writeLength={writeLength}\n readLength={readLength}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SendsVauesWhenUsingAbstractClassReverseDefineOrder()
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
|
||||||
|
const int state = 2;
|
||||||
|
const string message = "hello world";
|
||||||
|
const int responseId = 5;
|
||||||
|
writer.Write(new ResponseMessageReverse
|
||||||
|
{
|
||||||
|
state = state,
|
||||||
|
message = message,
|
||||||
|
responseId = responseId,
|
||||||
|
});
|
||||||
|
|
||||||
|
byte[] arr = writer.ToArray();
|
||||||
|
|
||||||
|
NetworkReader reader = new NetworkReader(arr);
|
||||||
|
ResponseMessageReverse received = reader.Read<ResponseMessageReverse>();
|
||||||
|
|
||||||
|
Assert.AreEqual(state, received.state);
|
||||||
|
Assert.AreEqual(message, received.message);
|
||||||
|
Assert.AreEqual(responseId, received.responseId);
|
||||||
|
|
||||||
|
int writeLength = writer.Position;
|
||||||
|
int readLength = reader.Position;
|
||||||
|
Assert.That(writeLength == readLength, $"OnSerializeAll and OnDeserializeAll calls write the same amount of data\n writeLength={writeLength}\n readLength={readLength}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/MessageInheritanceTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 808855b645f9843d2b3077ab1304b2b3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
143
Assets/Mirror/Tests/Editor/MessagePackingTest.cs
Normal file
143
Assets/Mirror/Tests/Editor/MessagePackingTest.cs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using Mirror.Tests.MessageTests;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class MessagePackingTest
|
||||||
|
{
|
||||||
|
public struct EmptyMessage : NetworkMessage {}
|
||||||
|
|
||||||
|
// helper function to pack message into a simple byte[]
|
||||||
|
public static byte[] PackToByteArray<T>(T message)
|
||||||
|
where T : struct, NetworkMessage
|
||||||
|
{
|
||||||
|
using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
|
||||||
|
{
|
||||||
|
MessagePacking.Pack(message, writer);
|
||||||
|
return writer.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpack a message we received
|
||||||
|
public static T UnpackFromByteArray<T>(byte[] data)
|
||||||
|
where T : struct, NetworkMessage
|
||||||
|
{
|
||||||
|
using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(data))
|
||||||
|
{
|
||||||
|
int msgType = MessagePacking.GetId<T>();
|
||||||
|
|
||||||
|
int id = networkReader.ReadUShort();
|
||||||
|
if (id != msgType)
|
||||||
|
throw new FormatException($"Invalid message, could not unpack {typeof(T).FullName}");
|
||||||
|
|
||||||
|
return networkReader.Read<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// message id is generated from message.FullName.
|
||||||
|
// should be consistent across all platforms.
|
||||||
|
[Test]
|
||||||
|
public void GetId()
|
||||||
|
{
|
||||||
|
// "Mirror.Tests.MessageTests.TestMessage"
|
||||||
|
Debug.Log(typeof(TestMessage).FullName);
|
||||||
|
Assert.That(MessagePacking.GetId<TestMessage>(), Is.EqualTo(0x8706));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPacking()
|
||||||
|
{
|
||||||
|
SceneMessage message = new SceneMessage()
|
||||||
|
{
|
||||||
|
sceneName = "Hello world",
|
||||||
|
sceneOperation = SceneOperation.LoadAdditive
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] data = PackToByteArray(message);
|
||||||
|
|
||||||
|
SceneMessage unpacked = UnpackFromByteArray<SceneMessage>(data);
|
||||||
|
|
||||||
|
Assert.That(unpacked.sceneName, Is.EqualTo("Hello world"));
|
||||||
|
Assert.That(unpacked.sceneOperation, Is.EqualTo(SceneOperation.LoadAdditive));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UnpackWrongMessage()
|
||||||
|
{
|
||||||
|
SpawnMessage message = new SpawnMessage();
|
||||||
|
|
||||||
|
byte[] data = PackToByteArray(message);
|
||||||
|
|
||||||
|
Assert.Throws<FormatException>(() =>
|
||||||
|
{
|
||||||
|
ReadyMessage unpacked = UnpackFromByteArray<ReadyMessage>(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUnpackIdMismatch()
|
||||||
|
{
|
||||||
|
// Unpack<T> has a id != msgType case that throws a FormatException.
|
||||||
|
// let's try to trigger it.
|
||||||
|
|
||||||
|
SceneMessage message = new SceneMessage()
|
||||||
|
{
|
||||||
|
sceneName = "Hello world",
|
||||||
|
sceneOperation = SceneOperation.LoadAdditive
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] data = PackToByteArray(message);
|
||||||
|
|
||||||
|
// overwrite the id
|
||||||
|
data[0] = 0x01;
|
||||||
|
data[1] = 0x02;
|
||||||
|
|
||||||
|
Assert.Throws<FormatException>(() =>
|
||||||
|
{
|
||||||
|
SceneMessage unpacked = UnpackFromByteArray<SceneMessage>(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUnpackMessageNonGeneric()
|
||||||
|
{
|
||||||
|
// try a regular message
|
||||||
|
SceneMessage message = new SceneMessage()
|
||||||
|
{
|
||||||
|
sceneName = "Hello world",
|
||||||
|
sceneOperation = SceneOperation.LoadAdditive
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] data = PackToByteArray(message);
|
||||||
|
NetworkReader reader = new NetworkReader(data);
|
||||||
|
|
||||||
|
bool result = MessagePacking.Unpack(reader, out ushort msgType);
|
||||||
|
Assert.That(result, Is.EqualTo(true));
|
||||||
|
Assert.That(msgType, Is.EqualTo(BitConverter.ToUInt16(data, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UnpackInvalidMessage()
|
||||||
|
{
|
||||||
|
// try an invalid message
|
||||||
|
NetworkReader reader2 = new NetworkReader(new byte[0]);
|
||||||
|
bool result2 = MessagePacking.Unpack(reader2, out ushort msgType2);
|
||||||
|
Assert.That(result2, Is.EqualTo(false));
|
||||||
|
Assert.That(msgType2, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MessageIdIsCorrectLength()
|
||||||
|
{
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
MessagePacking.Pack(new EmptyMessage(), writer);
|
||||||
|
|
||||||
|
ArraySegment<byte> segment = writer.ToArraySegment();
|
||||||
|
|
||||||
|
Assert.That(segment.Count, Is.EqualTo(MessagePacking.HeaderSize), "Empty message should have same size as HeaderSize");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/MessagePackingTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/MessagePackingTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8d57c17d9ee7c49e6bacc54ddbeac751
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
386
Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs
Normal file
386
Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using NSubstitute;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class MyMiddleware : MiddlewareTransport {}
|
||||||
|
|
||||||
|
[Description("Test to make sure inner methods are called when using Middleware Transport")]
|
||||||
|
public class MiddlewareTransportTest
|
||||||
|
{
|
||||||
|
Transport inner;
|
||||||
|
MyMiddleware middleware;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
inner = Substitute.For<Transport>();
|
||||||
|
|
||||||
|
GameObject gameObject = new GameObject();
|
||||||
|
|
||||||
|
middleware = gameObject.AddComponent<MyMiddleware>();
|
||||||
|
middleware.inner = inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
GameObject.DestroyImmediate(middleware.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void TestAvailable(bool available)
|
||||||
|
{
|
||||||
|
inner.Available().Returns(available);
|
||||||
|
|
||||||
|
Assert.That(middleware.Available(), Is.EqualTo(available));
|
||||||
|
|
||||||
|
inner.Received(1).Available();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(Channels.Reliable, 4000)]
|
||||||
|
[TestCase(Channels.Reliable, 2000)]
|
||||||
|
[TestCase(Channels.Unreliable, 4000)]
|
||||||
|
public void TestGetMaxPacketSize(int channel, int packageSize)
|
||||||
|
{
|
||||||
|
inner.GetMaxPacketSize(Arg.Any<int>()).Returns(packageSize);
|
||||||
|
|
||||||
|
Assert.That(middleware.GetMaxPacketSize(channel), Is.EqualTo(packageSize));
|
||||||
|
|
||||||
|
inner.Received(1).GetMaxPacketSize(Arg.Is<int>(x => x == channel));
|
||||||
|
inner.Received(0).GetMaxPacketSize(Arg.Is<int>(x => x != channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestShutdown()
|
||||||
|
{
|
||||||
|
middleware.Shutdown();
|
||||||
|
|
||||||
|
inner.Received(1).Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase("localhost")]
|
||||||
|
[TestCase("example.com")]
|
||||||
|
public void TestClientConnect(string address)
|
||||||
|
{
|
||||||
|
middleware.ClientConnect(address);
|
||||||
|
|
||||||
|
inner.Received(1).ClientConnect(address);
|
||||||
|
inner.Received(0).ClientConnect(Arg.Is<string>(x => x != address));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void TestClientConnected(bool connected)
|
||||||
|
{
|
||||||
|
inner.ClientConnected().Returns(connected);
|
||||||
|
|
||||||
|
Assert.That(middleware.ClientConnected(), Is.EqualTo(connected));
|
||||||
|
|
||||||
|
inner.Received(1).ClientConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClientDisconnect()
|
||||||
|
{
|
||||||
|
middleware.ClientDisconnect();
|
||||||
|
|
||||||
|
inner.Received(1).ClientDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(Channels.Reliable)]
|
||||||
|
[TestCase(Channels.Unreliable)]
|
||||||
|
public void TestClientSend(int channel)
|
||||||
|
{
|
||||||
|
byte[] array = new byte[10];
|
||||||
|
const int offset = 2;
|
||||||
|
const int count = 5;
|
||||||
|
ArraySegment<byte> segment = new ArraySegment<byte>(array, offset, count);
|
||||||
|
|
||||||
|
middleware.ClientSend(segment, channel);
|
||||||
|
|
||||||
|
inner.Received(1).ClientSend(Arg.Is<ArraySegment<byte>>(x => x.Array == array && x.Offset == offset && x.Count == count), channel);
|
||||||
|
inner.Received(0).ClientSend(Arg.Any<ArraySegment<byte>>(), Arg.Is<int>(x => x != channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void TestServerActive(bool active)
|
||||||
|
{
|
||||||
|
inner.ServerActive().Returns(active);
|
||||||
|
|
||||||
|
Assert.That(middleware.ServerActive(), Is.EqualTo(active));
|
||||||
|
|
||||||
|
inner.Received(1).ServerActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestServerStart()
|
||||||
|
{
|
||||||
|
middleware.ServerStart();
|
||||||
|
|
||||||
|
inner.Received(1).ServerStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestServerStop()
|
||||||
|
{
|
||||||
|
middleware.ServerStop();
|
||||||
|
|
||||||
|
inner.Received(1).ServerStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0, 0)]
|
||||||
|
[TestCase(1, 0)]
|
||||||
|
[TestCase(0, 1)]
|
||||||
|
[TestCase(19, 1)]
|
||||||
|
public void TestServerSend(int id, int channel)
|
||||||
|
{
|
||||||
|
byte[] array = new byte[10];
|
||||||
|
const int offset = 2;
|
||||||
|
const int count = 5;
|
||||||
|
ArraySegment<byte> segment = new ArraySegment<byte>(array, offset, count);
|
||||||
|
|
||||||
|
middleware.ServerSend(id, segment, channel);
|
||||||
|
|
||||||
|
inner.Received(1).ServerSend(id, Arg.Is<ArraySegment<byte>>(x => x.Array == array && x.Offset == offset && x.Count == count), channel);
|
||||||
|
// only need to check first arg,
|
||||||
|
inner.Received(0).ServerSend(Arg.Is<int>(x => x != id), Arg.Any<ArraySegment<byte>>(), Arg.Any<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0, "tcp4://localhost:7777")]
|
||||||
|
[TestCase(19, "tcp4://example.com:7777")]
|
||||||
|
public void TestServerGetClientAddress(int id, string result)
|
||||||
|
{
|
||||||
|
inner.ServerGetClientAddress(id).Returns(result);
|
||||||
|
|
||||||
|
Assert.That(middleware.ServerGetClientAddress(id), Is.EqualTo(result));
|
||||||
|
|
||||||
|
inner.Received(1).ServerGetClientAddress(id);
|
||||||
|
inner.Received(0).ServerGetClientAddress(Arg.Is<int>(x => x != id));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase("tcp4://localhost:7777")]
|
||||||
|
[TestCase("tcp4://example.com:7777")]
|
||||||
|
public void TestServerUri(string address)
|
||||||
|
{
|
||||||
|
Uri uri = new Uri(address);
|
||||||
|
inner.ServerUri().Returns(uri);
|
||||||
|
|
||||||
|
Assert.That(middleware.ServerUri(), Is.EqualTo(uri));
|
||||||
|
|
||||||
|
inner.Received(1).ServerUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClientConnectedCallback()
|
||||||
|
{
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnClientConnected = () =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
};
|
||||||
|
// connect to give callback to inner
|
||||||
|
middleware.ClientConnect("localhost");
|
||||||
|
|
||||||
|
inner.OnClientConnected.Invoke();
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
inner.OnClientConnected.Invoke();
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
public void TestClientDataReceivedCallback(int channel)
|
||||||
|
{
|
||||||
|
byte[] data = new byte[4];
|
||||||
|
ArraySegment<byte> segment = new ArraySegment<byte>(data, 1, 2);
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnClientDataReceived = (d, c) =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(c, Is.EqualTo(channel));
|
||||||
|
Assert.That(d.Array, Is.EqualTo(segment.Array));
|
||||||
|
Assert.That(d.Offset, Is.EqualTo(segment.Offset));
|
||||||
|
Assert.That(d.Count, Is.EqualTo(segment.Count));
|
||||||
|
};
|
||||||
|
// connect to give callback to inner
|
||||||
|
middleware.ClientConnect("localhost");
|
||||||
|
|
||||||
|
inner.OnClientDataReceived.Invoke(segment, channel);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
|
||||||
|
data = new byte[4];
|
||||||
|
segment = new ArraySegment<byte>(data, 0, 3);
|
||||||
|
|
||||||
|
inner.OnClientDataReceived.Invoke(segment, channel);
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClientDisconnectedCallback()
|
||||||
|
{
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnClientDisconnected = () =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
};
|
||||||
|
// connect to give callback to inner
|
||||||
|
middleware.ClientConnect("localhost");
|
||||||
|
|
||||||
|
inner.OnClientDisconnected.Invoke();
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
inner.OnClientDisconnected.Invoke();
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClientErrorCallback()
|
||||||
|
{
|
||||||
|
Exception exception = new InvalidDataException();
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnClientError = (e) =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(e, Is.EqualTo(exception));
|
||||||
|
};
|
||||||
|
// connect to give callback to inner
|
||||||
|
middleware.ClientConnect("localhost");
|
||||||
|
|
||||||
|
inner.OnClientError.Invoke(exception);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
exception = new NullReferenceException();
|
||||||
|
|
||||||
|
inner.OnClientError.Invoke(exception);
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
[TestCase(19)]
|
||||||
|
public void TestServerConnectedCallback(int id)
|
||||||
|
{
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnServerConnected = (i) =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(i, Is.EqualTo(id));
|
||||||
|
};
|
||||||
|
// start to give callback to inner
|
||||||
|
middleware.ServerStart();
|
||||||
|
|
||||||
|
inner.OnServerConnected.Invoke(id);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
inner.OnServerConnected.Invoke(id);
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0, 0)]
|
||||||
|
[TestCase(1, 0)]
|
||||||
|
[TestCase(19, 0)]
|
||||||
|
[TestCase(0, 1)]
|
||||||
|
[TestCase(1, 1)]
|
||||||
|
[TestCase(19, 1)]
|
||||||
|
public void TestServerDataReceivedCallback(int id, int channel)
|
||||||
|
{
|
||||||
|
byte[] data = new byte[4];
|
||||||
|
ArraySegment<byte> segment = new ArraySegment<byte>(data, 1, 2);
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnServerDataReceived = (i, d, c) =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(i, Is.EqualTo(id));
|
||||||
|
Assert.That(c, Is.EqualTo(channel));
|
||||||
|
Assert.That(d.Array, Is.EqualTo(segment.Array));
|
||||||
|
Assert.That(d.Offset, Is.EqualTo(segment.Offset));
|
||||||
|
Assert.That(d.Count, Is.EqualTo(segment.Count));
|
||||||
|
};
|
||||||
|
// start to give callback to inner
|
||||||
|
middleware.ServerStart();
|
||||||
|
|
||||||
|
inner.OnServerDataReceived.Invoke(id, segment, channel);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
|
||||||
|
data = new byte[4];
|
||||||
|
segment = new ArraySegment<byte>(data, 0, 3);
|
||||||
|
|
||||||
|
inner.OnServerDataReceived.Invoke(id, segment, channel);
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
[TestCase(19)]
|
||||||
|
public void TestServerDisconnectedCallback(int id)
|
||||||
|
{
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnServerDisconnected = (i) =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(i, Is.EqualTo(id));
|
||||||
|
};
|
||||||
|
// start to give callback to inner
|
||||||
|
middleware.ServerStart();
|
||||||
|
|
||||||
|
inner.OnServerDisconnected.Invoke(id);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
inner.OnServerDisconnected.Invoke(id);
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0)]
|
||||||
|
[TestCase(1)]
|
||||||
|
[TestCase(19)]
|
||||||
|
public void TestServerErrorCallback(int id)
|
||||||
|
{
|
||||||
|
Exception exception = new InvalidDataException();
|
||||||
|
|
||||||
|
int called = 0;
|
||||||
|
middleware.OnServerError = (i, e) =>
|
||||||
|
{
|
||||||
|
called++;
|
||||||
|
Assert.That(i, Is.EqualTo(id));
|
||||||
|
Assert.That(e, Is.EqualTo(exception));
|
||||||
|
};
|
||||||
|
// start to give callback to inner
|
||||||
|
middleware.ServerStart();
|
||||||
|
|
||||||
|
inner.OnServerError.Invoke(id, exception);
|
||||||
|
Assert.That(called, Is.EqualTo(1));
|
||||||
|
|
||||||
|
exception = new NullReferenceException();
|
||||||
|
|
||||||
|
inner.OnServerError.Invoke(id, exception);
|
||||||
|
Assert.That(called, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/MiddlewareTransportTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1ee4c7efa89013a41aeee942e60af4e7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
33
Assets/Mirror/Tests/Editor/Mirror.Tests.asmdef
Normal file
33
Assets/Mirror/Tests/Editor/Mirror.Tests.asmdef
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "Mirror.Tests",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [
|
||||||
|
"Mirror",
|
||||||
|
"Mirror.Editor",
|
||||||
|
"Mirror.Components",
|
||||||
|
"Mirror.Tests.Common",
|
||||||
|
"Telepathy",
|
||||||
|
"UnityEngine.TestRunner",
|
||||||
|
"UnityEditor.TestRunner",
|
||||||
|
"Unity.Mirror.CodeGen"
|
||||||
|
],
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": true,
|
||||||
|
"precompiledReferences": [
|
||||||
|
"NSubstitute.dll",
|
||||||
|
"Castle.Core.dll",
|
||||||
|
"System.Threading.Tasks.Extensions.dll",
|
||||||
|
"Mono.CecilX.dll",
|
||||||
|
"nunit.framework.dll"
|
||||||
|
],
|
||||||
|
"autoReferenced": false,
|
||||||
|
"defineConstraints": [
|
||||||
|
"UNITY_INCLUDE_TESTS"
|
||||||
|
],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
7
Assets/Mirror/Tests/Editor/Mirror.Tests.asmdef.meta
Normal file
7
Assets/Mirror/Tests/Editor/Mirror.Tests.asmdef.meta
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8b489029f75e64a7bbf6918bf1a49e39
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
180
Assets/Mirror/Tests/Editor/MultiplexTest.cs
Normal file
180
Assets/Mirror/Tests/Editor/MultiplexTest.cs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
using System;
|
||||||
|
using NSubstitute;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class MultiplexTest : MirrorTest
|
||||||
|
{
|
||||||
|
Transport transport1;
|
||||||
|
Transport transport2;
|
||||||
|
new MultiplexTransport transport;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
CreateGameObject(out _, out transport);
|
||||||
|
|
||||||
|
transport1 = Substitute.For<Transport>();
|
||||||
|
transport2 = Substitute.For<Transport>();
|
||||||
|
transport.transports = new[] { transport1, transport2 };
|
||||||
|
|
||||||
|
transport.Awake();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Test behaves as an ordinary method
|
||||||
|
[Test]
|
||||||
|
public void TestAvailable()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
transport2.Available().Returns(false);
|
||||||
|
Assert.That(transport.Available());
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Test behaves as an ordinary method
|
||||||
|
[Test]
|
||||||
|
public void TestNotAvailable()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(false);
|
||||||
|
transport2.Available().Returns(false);
|
||||||
|
Assert.That(transport.Available(), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Test behaves as an ordinary method
|
||||||
|
[Test]
|
||||||
|
public void TestConnect()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(false);
|
||||||
|
transport2.Available().Returns(true);
|
||||||
|
transport.ClientConnect("some.server.com");
|
||||||
|
|
||||||
|
transport1.DidNotReceive().ClientConnect(Arg.Any<string>());
|
||||||
|
transport2.Received().ClientConnect("some.server.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Test behaves as an ordinary method
|
||||||
|
[Test]
|
||||||
|
public void TestConnectFirstUri()
|
||||||
|
{
|
||||||
|
Uri uri = new Uri("tcp://some.server.com");
|
||||||
|
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
transport2.Available().Returns(true);
|
||||||
|
|
||||||
|
transport.ClientConnect(uri);
|
||||||
|
transport1.Received().ClientConnect(uri);
|
||||||
|
transport2.DidNotReceive().ClientConnect(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A Test behaves as an ordinary method
|
||||||
|
[Test]
|
||||||
|
public void TestConnectSecondUri()
|
||||||
|
{
|
||||||
|
Uri uri = new Uri("ws://some.server.com");
|
||||||
|
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
|
||||||
|
// first transport does not support websocket
|
||||||
|
transport1
|
||||||
|
.When(x => x.ClientConnect(uri))
|
||||||
|
.Do(x => { throw new ArgumentException("Scheme not supported"); });
|
||||||
|
|
||||||
|
transport2.Available().Returns(true);
|
||||||
|
|
||||||
|
transport.ClientConnect(uri);
|
||||||
|
transport2.Received().ClientConnect(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestConnected()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
transport.ClientConnect("some.server.com");
|
||||||
|
|
||||||
|
transport1.ClientConnected().Returns(true);
|
||||||
|
|
||||||
|
Assert.That(transport.ClientConnected());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDisconnect()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
transport.ClientConnect("some.server.com");
|
||||||
|
|
||||||
|
transport.ClientDisconnect();
|
||||||
|
|
||||||
|
transport1.Received().ClientDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClientSend()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
transport.ClientConnect("some.server.com");
|
||||||
|
|
||||||
|
byte[] data = { 1, 2, 3 };
|
||||||
|
ArraySegment<byte> segment = new ArraySegment<byte>(data);
|
||||||
|
|
||||||
|
transport.ClientSend(segment, 3);
|
||||||
|
|
||||||
|
transport1.Received().ClientSend(segment, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClient1Connected()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(true);
|
||||||
|
transport2.Available().Returns(true);
|
||||||
|
|
||||||
|
Action callback = Substitute.For<Action>();
|
||||||
|
// find available
|
||||||
|
transport.Awake();
|
||||||
|
// set event and connect to give event to inner
|
||||||
|
transport.OnClientConnected = callback;
|
||||||
|
transport.ClientConnect("localhost");
|
||||||
|
transport1.OnClientConnected.Invoke();
|
||||||
|
callback.Received().Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClient2Connected()
|
||||||
|
{
|
||||||
|
transport1.Available().Returns(false);
|
||||||
|
transport2.Available().Returns(true);
|
||||||
|
|
||||||
|
Action callback = Substitute.For<Action>();
|
||||||
|
// find available
|
||||||
|
transport.Awake();
|
||||||
|
// set event and connect to give event to inner
|
||||||
|
transport.OnClientConnected = callback;
|
||||||
|
transport.ClientConnect("localhost");
|
||||||
|
transport2.OnClientConnected.Invoke();
|
||||||
|
callback.Received().Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestServerConnected()
|
||||||
|
{
|
||||||
|
byte[] data = { 1, 2, 3 };
|
||||||
|
ArraySegment<byte> segment = new ArraySegment<byte>(data);
|
||||||
|
|
||||||
|
// on connect, send a message back
|
||||||
|
void SendMessage(int connectionId)
|
||||||
|
{
|
||||||
|
transport.ServerSend(connectionId, segment, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set event and Start to give event to inner
|
||||||
|
transport.OnServerConnected = SendMessage;
|
||||||
|
transport.ServerStart();
|
||||||
|
|
||||||
|
transport1.OnServerConnected.Invoke(1);
|
||||||
|
|
||||||
|
transport1.Received().ServerSend(1, segment, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/MultiplexTest.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/MultiplexTest.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f0d8bef6afd464247bf433cdc5d3ff23
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
184
Assets/Mirror/Tests/Editor/NetworkBehaviourDirtyBitsTests.cs
Normal file
184
Assets/Mirror/Tests/Editor/NetworkBehaviourDirtyBitsTests.cs
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
// dirty bits are powerful magic.
|
||||||
|
// add some tests to guarantee correct behaviour.
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
class NetworkBehaviourWithSyncVarsAndCollections : NetworkBehaviour
|
||||||
|
{
|
||||||
|
// SyncVars
|
||||||
|
[SyncVar] public int health;
|
||||||
|
[SyncVar] public int mana;
|
||||||
|
|
||||||
|
// SyncCollections
|
||||||
|
public readonly SyncList<int> list = new SyncList<int>();
|
||||||
|
public readonly SyncDictionary<int, string> dict = new SyncDictionary<int, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NetworkBehaviourSyncVarDirtyBitsExposed : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public ulong syncVarDirtyBitsExposed => syncVarDirtyBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NetworkBehaviourDirtyBitsTests : MirrorEditModeTest
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
// SyncLists are only set dirty while owner has observers.
|
||||||
|
// need a connection.
|
||||||
|
NetworkServer.Listen(1);
|
||||||
|
ConnectHostClientBlockingAuthenticatedAndReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarDirtyBit()
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out NetworkBehaviourSyncVarDirtyBitsExposed comp);
|
||||||
|
|
||||||
|
// set 3rd dirty bit.
|
||||||
|
comp.SetSyncVarDirtyBit(0b_00000000_00000100);
|
||||||
|
Assert.That(comp.syncVarDirtyBitsExposed, Is.EqualTo(0b_00000000_00000100));
|
||||||
|
|
||||||
|
// set 5th dirty bit.
|
||||||
|
// both 3rd and 5th should be set.
|
||||||
|
comp.SetSyncVarDirtyBit(0b_00000000_00010000);
|
||||||
|
Assert.That(comp.syncVarDirtyBitsExposed, Is.EqualTo(0b_00000000_00010100));
|
||||||
|
}
|
||||||
|
|
||||||
|
// changing a SyncObject (collection) should modify the dirty mask.
|
||||||
|
[Test]
|
||||||
|
public void SyncObjectsSetDirtyBits()
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out NetworkBehaviourWithSyncVarsAndCollections comp);
|
||||||
|
|
||||||
|
// not dirty by default
|
||||||
|
Assert.That(comp.syncObjectDirtyBits, Is.EqualTo(0UL));
|
||||||
|
|
||||||
|
// change the list. should be dirty now.
|
||||||
|
comp.list.Add(42);
|
||||||
|
Assert.That(comp.syncObjectDirtyBits, Is.EqualTo(0b01));
|
||||||
|
|
||||||
|
// change the dict. should both be dirty.
|
||||||
|
comp.dict[42] = null;
|
||||||
|
Assert.That(comp.syncObjectDirtyBits, Is.EqualTo(0b11));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsDirty()
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity identity, out NetworkBehaviourWithSyncVarsAndCollections comp);
|
||||||
|
|
||||||
|
// not dirty by default
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
|
||||||
|
// changing a [SyncVar] should set it dirty
|
||||||
|
++comp.health;
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
comp.ClearAllDirtyBits();
|
||||||
|
|
||||||
|
// changing a SyncCollection should set it dirty
|
||||||
|
comp.list.Add(42);
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
comp.ClearAllDirtyBits();
|
||||||
|
|
||||||
|
// it should only be dirty after syncInterval elapsed
|
||||||
|
comp.syncInterval = float.MaxValue;
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ClearAllDirtyBitsClearsSyncVarDirtyBits()
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out EmptyBehaviour emptyBehaviour);
|
||||||
|
|
||||||
|
// set syncinterval so dirtybit works fine
|
||||||
|
emptyBehaviour.syncInterval = 0;
|
||||||
|
Assert.That(emptyBehaviour.IsDirty(), Is.False);
|
||||||
|
|
||||||
|
// set one syncvar dirty bit
|
||||||
|
emptyBehaviour.SetSyncVarDirtyBit(1);
|
||||||
|
Assert.That(emptyBehaviour.IsDirty(), Is.True);
|
||||||
|
|
||||||
|
// clear it
|
||||||
|
emptyBehaviour.ClearAllDirtyBits();
|
||||||
|
Assert.That(emptyBehaviour.IsDirty(), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ClearAllDirtyBitsClearsSyncObjectsDirtyBits()
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out NetworkBehaviourWithSyncVarsAndCollections comp);
|
||||||
|
|
||||||
|
// set syncinterval so dirtybit works fine
|
||||||
|
comp.syncInterval = 0;
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
|
||||||
|
// dirty the synclist
|
||||||
|
comp.list.Add(42);
|
||||||
|
Assert.That(comp.IsDirty, Is.True);
|
||||||
|
|
||||||
|
// clear bits should clear synclist bits too
|
||||||
|
comp.ClearAllDirtyBits();
|
||||||
|
Assert.That(comp.IsDirty, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkServer.Broadcast clears all dirty bits in all spawned
|
||||||
|
// identity's components if they have no observers.
|
||||||
|
//
|
||||||
|
// this way dirty bit tracking only starts after first observer.
|
||||||
|
// otherwise first observer would still get dirty update for everything
|
||||||
|
// that was dirty before he observed. even though he already got the
|
||||||
|
// full state in spawn packet.
|
||||||
|
[Test]
|
||||||
|
public void DirtyBitsAreClearedForSpawnedWithoutObservers()
|
||||||
|
{
|
||||||
|
// need one player, one monster
|
||||||
|
CreateNetworkedAndSpawnPlayer(out _, out NetworkIdentity player, NetworkServer.localConnection);
|
||||||
|
CreateNetworkedAndSpawn(out _, out NetworkIdentity monster, out NetworkBehaviourWithSyncVarsAndCollections monsterComp);
|
||||||
|
|
||||||
|
// without AOI, player connection sees everyone automatically.
|
||||||
|
// remove the monster from observing.
|
||||||
|
// remvoe player from monster observers.
|
||||||
|
monster.RemoveObserver(player.connectionToClient);
|
||||||
|
Assert.That(monster.observers.Count, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// modify something in the monster so that dirty bit is set
|
||||||
|
monsterComp.syncInterval = 0;
|
||||||
|
++monsterComp.health;
|
||||||
|
Assert.That(monsterComp.IsDirty(), Is.True);
|
||||||
|
|
||||||
|
// add first observer. dirty bits should be cleared.
|
||||||
|
monster.AddObserver(player.connectionToClient);
|
||||||
|
Assert.That(monsterComp.IsDirty(), Is.False);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hook tests can only be ran when inheriting from NetworkBehaviour
|
||||||
|
public class NetworkBehaviourDirtyBitsHookGuardTester : NetworkBehaviour
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void HookGuard()
|
||||||
|
{
|
||||||
|
// set hook guard for some bits
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
ulong bit = 1ul << i;
|
||||||
|
|
||||||
|
// should be false by default
|
||||||
|
Assert.That(GetSyncVarHookGuard(bit), Is.False);
|
||||||
|
|
||||||
|
// set true
|
||||||
|
SetSyncVarHookGuard(bit, true);
|
||||||
|
Assert.That(GetSyncVarHookGuard(bit), Is.True);
|
||||||
|
|
||||||
|
// set false again
|
||||||
|
SetSyncVarHookGuard(bit, false);
|
||||||
|
Assert.That(GetSyncVarHookGuard(bit), Is.False);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 71cd60f7177a4d3da75bb87f5ac13a18
|
||||||
|
timeCreated: 1631772886
|
341
Assets/Mirror/Tests/Editor/NetworkBehaviourSerializeTest.cs
Normal file
341
Assets/Mirror/Tests/Editor/NetworkBehaviourSerializeTest.cs
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
// Note: Weaver doesn't run on nested class so use namespace to group classes instead
|
||||||
|
namespace Mirror.Tests.NetworkBehaviourSerialize
|
||||||
|
{
|
||||||
|
#region No OnSerialize/OnDeserialize override
|
||||||
|
abstract class AbstractBehaviour : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public readonly SyncList<bool> syncListInAbstract = new SyncList<bool>();
|
||||||
|
|
||||||
|
[SyncVar]
|
||||||
|
public int SyncFieldInAbstract;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BehaviourWithSyncVar : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public readonly SyncList<bool> syncList = new SyncList<bool>();
|
||||||
|
|
||||||
|
[SyncVar]
|
||||||
|
public int SyncField;
|
||||||
|
}
|
||||||
|
|
||||||
|
class OverrideBehaviourFromSyncVar : AbstractBehaviour {}
|
||||||
|
|
||||||
|
class OverrideBehaviourWithSyncVarFromSyncVar : AbstractBehaviour
|
||||||
|
{
|
||||||
|
public readonly SyncList<bool> syncListInOverride = new SyncList<bool>();
|
||||||
|
|
||||||
|
[SyncVar]
|
||||||
|
public int SyncFieldInOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MiddleClass : AbstractBehaviour
|
||||||
|
{
|
||||||
|
// class with no sync var
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubClass : MiddleClass
|
||||||
|
{
|
||||||
|
// class with sync var
|
||||||
|
// this is to make sure that override works correctly if base class doesn't have sync vars
|
||||||
|
[SyncVar]
|
||||||
|
public Vector3 anotherSyncField;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MiddleClassWithSyncVar : AbstractBehaviour
|
||||||
|
{
|
||||||
|
// class with sync var
|
||||||
|
[SyncVar]
|
||||||
|
public string syncFieldInMiddle;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubClassFromSyncVar : MiddleClassWithSyncVar
|
||||||
|
{
|
||||||
|
// class with sync var
|
||||||
|
// this is to make sure that override works correctly if base class doesn't have sync vars
|
||||||
|
[SyncVar]
|
||||||
|
public Vector3 syncFieldInSub;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region OnSerialize/OnDeserialize override
|
||||||
|
|
||||||
|
class BehaviourWithSyncVarWithOnSerialize : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public readonly SyncList<bool> syncList = new SyncList<bool>();
|
||||||
|
|
||||||
|
[SyncVar]
|
||||||
|
public int SyncField;
|
||||||
|
|
||||||
|
public float customSerializeField;
|
||||||
|
|
||||||
|
public override bool OnSerialize(NetworkWriter writer, bool initialState)
|
||||||
|
{
|
||||||
|
writer.WriteFloat(customSerializeField);
|
||||||
|
return base.OnSerialize(writer, initialState);
|
||||||
|
}
|
||||||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||||||
|
{
|
||||||
|
customSerializeField = reader.ReadFloat();
|
||||||
|
base.OnDeserialize(reader, initialState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OverrideBehaviourFromSyncVarWithOnSerialize : AbstractBehaviour
|
||||||
|
{
|
||||||
|
public float customSerializeField;
|
||||||
|
|
||||||
|
public override bool OnSerialize(NetworkWriter writer, bool initialState)
|
||||||
|
{
|
||||||
|
writer.WriteFloat(customSerializeField);
|
||||||
|
return base.OnSerialize(writer, initialState);
|
||||||
|
}
|
||||||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||||||
|
{
|
||||||
|
customSerializeField = reader.ReadFloat();
|
||||||
|
base.OnDeserialize(reader, initialState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OverrideBehaviourWithSyncVarFromSyncVarWithOnSerialize : AbstractBehaviour
|
||||||
|
{
|
||||||
|
public readonly SyncList<bool> syncListInOverride = new SyncList<bool>();
|
||||||
|
|
||||||
|
[SyncVar]
|
||||||
|
public int SyncFieldInOverride;
|
||||||
|
|
||||||
|
public float customSerializeField;
|
||||||
|
|
||||||
|
public override bool OnSerialize(NetworkWriter writer, bool initialState)
|
||||||
|
{
|
||||||
|
writer.WriteFloat(customSerializeField);
|
||||||
|
return base.OnSerialize(writer, initialState);
|
||||||
|
}
|
||||||
|
public override void OnDeserialize(NetworkReader reader, bool initialState)
|
||||||
|
{
|
||||||
|
customSerializeField = reader.ReadFloat();
|
||||||
|
base.OnDeserialize(reader, initialState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public class NetworkBehaviourSerializeTest : MirrorEditModeTest
|
||||||
|
{
|
||||||
|
static void SyncNetworkBehaviour(NetworkBehaviour source, NetworkBehaviour target, bool initialState)
|
||||||
|
{
|
||||||
|
using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
|
||||||
|
{
|
||||||
|
source.OnSerialize(writer, initialState);
|
||||||
|
|
||||||
|
using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment()))
|
||||||
|
{
|
||||||
|
target.OnDeserialize(reader, initialState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
// SyncLists are only set dirty while owner has observers.
|
||||||
|
// need a connection.
|
||||||
|
NetworkServer.Listen(1);
|
||||||
|
ConnectHostClientBlockingAuthenticatedAndReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void BehaviourWithSyncVarTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out BehaviourWithSyncVar source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out BehaviourWithSyncVar target);
|
||||||
|
|
||||||
|
source.SyncField = 10;
|
||||||
|
source.syncList.Add(true);
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncField, Is.EqualTo(10));
|
||||||
|
Assert.That(target.syncList.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(target.syncList[0], Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void OverrideBehaviourFromSyncVarTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourFromSyncVar source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourFromSyncVar target);
|
||||||
|
|
||||||
|
source.SyncFieldInAbstract = 12;
|
||||||
|
source.syncListInAbstract.Add(true);
|
||||||
|
source.syncListInAbstract.Add(false);
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInAbstract, Is.EqualTo(12));
|
||||||
|
Assert.That(target.syncListInAbstract.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(target.syncListInAbstract[0], Is.True);
|
||||||
|
Assert.That(target.syncListInAbstract[1], Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void OverrideBehaviourWithSyncVarFromSyncVarTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourWithSyncVarFromSyncVar source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourWithSyncVarFromSyncVar target);
|
||||||
|
|
||||||
|
source.SyncFieldInAbstract = 10;
|
||||||
|
source.syncListInAbstract.Add(true);
|
||||||
|
|
||||||
|
source.SyncFieldInOverride = 52;
|
||||||
|
source.syncListInOverride.Add(false);
|
||||||
|
source.syncListInOverride.Add(true);
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInAbstract, Is.EqualTo(10));
|
||||||
|
Assert.That(target.syncListInAbstract.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(target.syncListInAbstract[0], Is.True);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInOverride, Is.EqualTo(52));
|
||||||
|
Assert.That(target.syncListInOverride.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(target.syncListInOverride[0], Is.False);
|
||||||
|
Assert.That(target.syncListInOverride[1], Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void SubClassTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out SubClass source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out SubClass target);
|
||||||
|
|
||||||
|
source.SyncFieldInAbstract = 10;
|
||||||
|
source.syncListInAbstract.Add(true);
|
||||||
|
|
||||||
|
source.anotherSyncField = new Vector3(40, 20, 10);
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInAbstract, Is.EqualTo(10));
|
||||||
|
Assert.That(target.syncListInAbstract.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(target.syncListInAbstract[0], Is.True);
|
||||||
|
|
||||||
|
Assert.That(target.anotherSyncField, Is.EqualTo(new Vector3(40, 20, 10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void SubClassFromSyncVarTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out SubClassFromSyncVar source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out SubClassFromSyncVar target);
|
||||||
|
|
||||||
|
source.SyncFieldInAbstract = 10;
|
||||||
|
source.syncListInAbstract.Add(true);
|
||||||
|
|
||||||
|
source.syncFieldInMiddle = "Hello World!";
|
||||||
|
source.syncFieldInSub = new Vector3(40, 20, 10);
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInAbstract, Is.EqualTo(10));
|
||||||
|
Assert.That(target.syncListInAbstract.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(target.syncListInAbstract[0], Is.True);
|
||||||
|
|
||||||
|
Assert.That(target.syncFieldInMiddle, Is.EqualTo("Hello World!"));
|
||||||
|
Assert.That(target.syncFieldInSub, Is.EqualTo(new Vector3(40, 20, 10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void BehaviourWithSyncVarWithOnSerializeTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out BehaviourWithSyncVarWithOnSerialize source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out BehaviourWithSyncVarWithOnSerialize target);
|
||||||
|
|
||||||
|
source.SyncField = 10;
|
||||||
|
source.syncList.Add(true);
|
||||||
|
|
||||||
|
source.customSerializeField = 20.5f;
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncField, Is.EqualTo(10));
|
||||||
|
Assert.That(target.syncList.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(target.syncList[0], Is.True);
|
||||||
|
|
||||||
|
Assert.That(target.customSerializeField, Is.EqualTo(20.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void OverrideBehaviourFromSyncVarWithOnSerializeTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourFromSyncVarWithOnSerialize source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourFromSyncVarWithOnSerialize target);
|
||||||
|
|
||||||
|
source.SyncFieldInAbstract = 12;
|
||||||
|
source.syncListInAbstract.Add(true);
|
||||||
|
source.syncListInAbstract.Add(false);
|
||||||
|
|
||||||
|
source.customSerializeField = 20.5f;
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInAbstract, Is.EqualTo(12));
|
||||||
|
Assert.That(target.syncListInAbstract.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(target.syncListInAbstract[0], Is.True);
|
||||||
|
Assert.That(target.syncListInAbstract[1], Is.False);
|
||||||
|
|
||||||
|
Assert.That(target.customSerializeField, Is.EqualTo(20.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(true)]
|
||||||
|
[TestCase(false)]
|
||||||
|
public void OverrideBehaviourWithSyncVarFromSyncVarWithOnSerializeTest(bool initialState)
|
||||||
|
{
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourWithSyncVarFromSyncVarWithOnSerialize source);
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out OverrideBehaviourWithSyncVarFromSyncVarWithOnSerialize target);
|
||||||
|
|
||||||
|
source.SyncFieldInAbstract = 10;
|
||||||
|
source.syncListInAbstract.Add(true);
|
||||||
|
|
||||||
|
source.SyncFieldInOverride = 52;
|
||||||
|
source.syncListInOverride.Add(false);
|
||||||
|
source.syncListInOverride.Add(true);
|
||||||
|
|
||||||
|
source.customSerializeField = 20.5f;
|
||||||
|
|
||||||
|
SyncNetworkBehaviour(source, target, initialState);
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInAbstract, Is.EqualTo(10));
|
||||||
|
Assert.That(target.syncListInAbstract.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(target.syncListInAbstract[0], Is.True);
|
||||||
|
|
||||||
|
|
||||||
|
Assert.That(target.SyncFieldInOverride, Is.EqualTo(52));
|
||||||
|
Assert.That(target.syncListInOverride.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(target.syncListInOverride[0], Is.False);
|
||||||
|
Assert.That(target.syncListInOverride[1], Is.True);
|
||||||
|
|
||||||
|
Assert.That(target.customSerializeField, Is.EqualTo(20.5f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 253d419ce2900134482c3c8b76883c60
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
884
Assets/Mirror/Tests/Editor/NetworkBehaviourTests.cs
Normal file
884
Assets/Mirror/Tests/Editor/NetworkBehaviourTests.cs
Normal file
@ -0,0 +1,884 @@
|
|||||||
|
using Mirror.RemoteCalls;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.TestTools;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
class EmptyBehaviour : NetworkBehaviour {}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class NetworkBehaviourDelegateComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public static void Delegate(NetworkBehaviour comp, NetworkReader reader, NetworkConnection senderConnection) {}
|
||||||
|
public static void Delegate2(NetworkBehaviour comp, NetworkReader reader, NetworkConnection senderConnection) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class NetworkBehaviourSetSyncVarGameObjectComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
//[SyncVar]
|
||||||
|
public GameObject test;
|
||||||
|
// usually generated by weaver
|
||||||
|
public uint testNetId;
|
||||||
|
|
||||||
|
// SetSyncVarGameObject wrapper to expose it
|
||||||
|
public void SetSyncVarGameObjectExposed(GameObject newGameObject, ulong dirtyBit) =>
|
||||||
|
SetSyncVarGameObject(newGameObject, ref test, dirtyBit, ref testNetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class NetworkBehaviourGetSyncVarGameObjectComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
//[SyncVar]
|
||||||
|
public GameObject test;
|
||||||
|
// usually generated by weaver
|
||||||
|
public uint testNetId;
|
||||||
|
|
||||||
|
// SetSyncVarGameObject wrapper to expose it
|
||||||
|
public GameObject GetSyncVarGameObjectExposed() =>
|
||||||
|
GetSyncVarGameObject(testNetId, ref test);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class NetworkBehaviourSetSyncVarNetworkIdentityComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
//[SyncVar]
|
||||||
|
public NetworkIdentity test;
|
||||||
|
// usually generated by weaver
|
||||||
|
public uint testNetId;
|
||||||
|
|
||||||
|
// SetSyncVarNetworkIdentity wrapper to expose it
|
||||||
|
public void SetSyncVarNetworkIdentityExposed(NetworkIdentity newNetworkIdentity, ulong dirtyBit) =>
|
||||||
|
SetSyncVarNetworkIdentity(newNetworkIdentity, ref test, dirtyBit, ref testNetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class NetworkBehaviourGetSyncVarNetworkIdentityComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
//[SyncVar]
|
||||||
|
public NetworkIdentity test;
|
||||||
|
// usually generated by weaver
|
||||||
|
public uint testNetId;
|
||||||
|
|
||||||
|
// SetSyncVarNetworkIdentity wrapper to expose it
|
||||||
|
public NetworkIdentity GetSyncVarNetworkIdentityExposed() =>
|
||||||
|
GetSyncVarNetworkIdentity(testNetId, ref test);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class OnStopClientComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public int called;
|
||||||
|
public override void OnStopClient() => ++called;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class OnStartClientComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public int called;
|
||||||
|
public override void OnStartClient() => ++called;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class OnStartLocalPlayerComponent : NetworkBehaviour
|
||||||
|
{
|
||||||
|
public int called;
|
||||||
|
public override void OnStartLocalPlayer() => ++called;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NetworkBehaviourTests : MirrorEditModeTest
|
||||||
|
{
|
||||||
|
[TearDown]
|
||||||
|
public override void TearDown()
|
||||||
|
{
|
||||||
|
NetworkServer.RemoveLocalConnection();
|
||||||
|
base.TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsServerOnly()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity, out EmptyBehaviour emptyBehaviour);
|
||||||
|
|
||||||
|
// call OnStartServer so isServer is true
|
||||||
|
identity.OnStartServer();
|
||||||
|
Assert.That(identity.isServer, Is.True);
|
||||||
|
|
||||||
|
// isServerOnly should be true when isServer = true && isClient = false
|
||||||
|
Assert.That(emptyBehaviour.isServer, Is.True);
|
||||||
|
Assert.That(emptyBehaviour.isClient, Is.False);
|
||||||
|
Assert.That(emptyBehaviour.isServerOnly, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsClientOnly()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity, out EmptyBehaviour emptyBehaviour);
|
||||||
|
|
||||||
|
// isClientOnly should be true when isServer = false && isClient = true
|
||||||
|
identity.isClient = true;
|
||||||
|
Assert.That(emptyBehaviour.isServer, Is.False);
|
||||||
|
Assert.That(emptyBehaviour.isClient, Is.True);
|
||||||
|
Assert.That(emptyBehaviour.isClientOnly, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasNoAuthorityByDefault()
|
||||||
|
{
|
||||||
|
// no authority by default
|
||||||
|
CreateNetworked(out _, out _, out EmptyBehaviour emptyBehaviour);
|
||||||
|
Assert.That(emptyBehaviour.hasAuthority, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasIdentitysNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity, out EmptyBehaviour emptyBehaviour);
|
||||||
|
identity.netId = 42;
|
||||||
|
Assert.That(emptyBehaviour.netId, Is.EqualTo(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasIdentitysConnectionToServer()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity, out EmptyBehaviour emptyBehaviour);
|
||||||
|
identity.connectionToServer = new LocalConnectionToServer();
|
||||||
|
Assert.That(emptyBehaviour.connectionToServer, Is.EqualTo(identity.connectionToServer));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasIdentitysConnectionToClient()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out NetworkIdentity identity, out EmptyBehaviour emptyBehaviour);
|
||||||
|
identity.connectionToClient = new LocalConnectionToClient();
|
||||||
|
Assert.That(emptyBehaviour.connectionToClient, Is.EqualTo(identity.connectionToClient));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ComponentIndex()
|
||||||
|
{
|
||||||
|
// create a NetworkIdentity with two components
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out EmptyBehaviour first, out EmptyBehaviour second);
|
||||||
|
Assert.That(first.ComponentIndex, Is.EqualTo(0));
|
||||||
|
Assert.That(second.ComponentIndex, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Ignore("NetworkServerTest.SendCommand does it already")]
|
||||||
|
public void SendCommandInternal() {}
|
||||||
|
|
||||||
|
[Test, Ignore("ClientRpcTest.cs tests Rpcs already")]
|
||||||
|
public void SendRPCInternal() {}
|
||||||
|
|
||||||
|
[Test, Ignore("TargetRpcTest.cs tests TargetRpcs already")]
|
||||||
|
public void SendTargetRPCInternal() {}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RegisterDelegateDoesntOverwrite()
|
||||||
|
{
|
||||||
|
// registerdelegate is protected, but we can use
|
||||||
|
// RegisterCommandDelegate which calls RegisterDelegate
|
||||||
|
int registeredHash1 = RemoteProcedureCalls.RegisterDelegate(
|
||||||
|
typeof(NetworkBehaviourDelegateComponent),
|
||||||
|
nameof(NetworkBehaviourDelegateComponent.Delegate),
|
||||||
|
RemoteCallType.Command,
|
||||||
|
NetworkBehaviourDelegateComponent.Delegate,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// registering the exact same one should be fine. it should simply
|
||||||
|
// do nothing.
|
||||||
|
int registeredHash2 = RemoteProcedureCalls.RegisterDelegate(
|
||||||
|
typeof(NetworkBehaviourDelegateComponent),
|
||||||
|
nameof(NetworkBehaviourDelegateComponent.Delegate),
|
||||||
|
RemoteCallType.Command,
|
||||||
|
NetworkBehaviourDelegateComponent.Delegate,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// registering the same name with a different callback shouldn't
|
||||||
|
// work
|
||||||
|
LogAssert.Expect(LogType.Error, $"Function {typeof(NetworkBehaviourDelegateComponent)}.{nameof(NetworkBehaviourDelegateComponent.Delegate)} and {typeof(NetworkBehaviourDelegateComponent)}.{nameof(NetworkBehaviourDelegateComponent.Delegate2)} have the same hash. Please rename one of them");
|
||||||
|
int registeredHash3 = RemoteProcedureCalls.RegisterDelegate(
|
||||||
|
typeof(NetworkBehaviourDelegateComponent),
|
||||||
|
nameof(NetworkBehaviourDelegateComponent.Delegate),
|
||||||
|
RemoteCallType.Command,
|
||||||
|
NetworkBehaviourDelegateComponent.Delegate2,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
RemoteProcedureCalls.RemoveDelegate(registeredHash1);
|
||||||
|
RemoteProcedureCalls.RemoveDelegate(registeredHash2);
|
||||||
|
RemoteProcedureCalls.RemoveDelegate(registeredHash3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetDelegate()
|
||||||
|
{
|
||||||
|
// registerdelegate is protected, but we can use
|
||||||
|
// RegisterCommandDelegate which calls RegisterDelegate
|
||||||
|
int registeredHash = RemoteProcedureCalls.RegisterDelegate(
|
||||||
|
typeof(NetworkBehaviourDelegateComponent),
|
||||||
|
nameof(NetworkBehaviourDelegateComponent.Delegate),
|
||||||
|
RemoteCallType.Command,
|
||||||
|
NetworkBehaviourDelegateComponent.Delegate,
|
||||||
|
false);
|
||||||
|
|
||||||
|
// get handler
|
||||||
|
int cmdHash = nameof(NetworkBehaviourDelegateComponent.Delegate).GetStableHashCode();
|
||||||
|
RemoteCallDelegate func = RemoteProcedureCalls.GetDelegate(cmdHash);
|
||||||
|
RemoteCallDelegate expected = NetworkBehaviourDelegateComponent.Delegate;
|
||||||
|
Assert.That(func, Is.EqualTo(expected));
|
||||||
|
|
||||||
|
// invalid hash should return null handler
|
||||||
|
RemoteCallDelegate funcNull = RemoteProcedureCalls.GetDelegate(1234);
|
||||||
|
Assert.That(funcNull, Is.Null);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
RemoteProcedureCalls.RemoveDelegate(registeredHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualZeroNetIdNullIsTrue()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
// null and identity.netid==0 returns true (=equal)
|
||||||
|
//
|
||||||
|
// later we should reevaluate if this is so smart or not. might be
|
||||||
|
// better to return false here.
|
||||||
|
// => we possibly return false so that resync doesn't happen when
|
||||||
|
// GO disappears? or not?
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(null, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// null should return false
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(null, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualZeroNetIdAndGOWithoutIdentityComponentIsTrue()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity _);
|
||||||
|
|
||||||
|
// null and identity.netid==0 returns true (=equal)
|
||||||
|
//
|
||||||
|
// later we should reevaluate if this is so smart or not. might be
|
||||||
|
// better to return false here.
|
||||||
|
// => we possibly return false so that resync doesn't happen when
|
||||||
|
// GO disappears? or not?
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(go, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualWithoutIdentityComponent()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject without networkidentity component should return false
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity _);
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(go, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualValidGOWithDifferentNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject with valid networkidentity and netid that is different
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
ni.netId = 43;
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(go, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualValidGOWithSameNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject with valid networkidentity and netid that is different
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
ni.netId = 42;
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(go, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualUnspawnedGO()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject with valid networkidentity and 0 netid that is unspawned
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
LogAssert.Expect(LogType.Warning, $"SetSyncVarGameObject GameObject {go} has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(go, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarGameObjectEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarGameObjectEqualUnspawnedGOZeroNetIdIsTrue()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// unspawned go and identity.netid==0 returns true (=equal)
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
LogAssert.Expect(LogType.Warning, $"SetSyncVarGameObject GameObject {go} has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
bool result = NetworkBehaviour.SyncVarGameObjectEqual(go, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarNetworkIdentityEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarNetworkIdentityEqualZeroNetIdNullIsTrue()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// null and identity.netid==0 returns true (=equal)
|
||||||
|
//
|
||||||
|
// later we should reevaluate if this is so smart or not. might be
|
||||||
|
// better to return false here.
|
||||||
|
// => we possibly return false so that resync doesn't happen when
|
||||||
|
// GO disappears? or not?
|
||||||
|
bool result = NetworkBehaviour.SyncVarNetworkIdentityEqual(null, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarNetworkIdentityEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarNetworkIdentityEqualNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// null should return false
|
||||||
|
bool result = NetworkBehaviour.SyncVarNetworkIdentityEqual(null, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarNetworkIdentityEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarNetworkIdentityEqualValidIdentityWithDifferentNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject with valid networkidentity and netid that is different
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
ni.netId = 43;
|
||||||
|
bool result = NetworkBehaviour.SyncVarNetworkIdentityEqual(ni, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarNetworkIdentityEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarNetworkIdentityEqualValidIdentityWithSameNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject with valid networkidentity and netid that is different
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity ni);
|
||||||
|
ni.netId = 42;
|
||||||
|
bool result = NetworkBehaviour.SyncVarNetworkIdentityEqual(ni, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarNetworkIdentityEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarNetworkIdentityEqualUnspawnedIdentity()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// our identity should have a netid for comparing
|
||||||
|
identity.netId = 42;
|
||||||
|
|
||||||
|
// gameobject with valid networkidentity and 0 netid that is unspawned
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
LogAssert.Expect(LogType.Warning, $"SetSyncVarNetworkIdentity NetworkIdentity {ni} has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
bool result = NetworkBehaviour.SyncVarNetworkIdentityEqual(ni, identity.netId);
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: SyncVarNetworkIdentityEqual should be static later
|
||||||
|
[Test]
|
||||||
|
public void SyncVarNetworkIdentityEqualUnspawnedIdentityZeroNetIdIsTrue()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// unspawned go and identity.netid==0 returns true (=equal)
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
LogAssert.Expect(LogType.Warning, $"SetSyncVarNetworkIdentity NetworkIdentity {ni} has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
bool result = NetworkBehaviour.SyncVarNetworkIdentityEqual(ni, identity.netId);
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarGameObjectWithValidObject()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourSetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// create a valid GameObject with networkidentity and netid
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
ni.netId = 43;
|
||||||
|
|
||||||
|
// set the GameObject SyncVar
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
comp.SetSyncVarGameObjectExposed(go, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(go));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(ni.netId));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarGameObjectNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourSetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// set some existing GO+netId first to check if it is going to be
|
||||||
|
// overwritten
|
||||||
|
CreateGameObject(out GameObject go);
|
||||||
|
comp.test = go;
|
||||||
|
comp.testNetId = 43;
|
||||||
|
|
||||||
|
// set the GameObject SyncVar to null
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
comp.SetSyncVarGameObjectExposed(null, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(null));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(0));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarGameObjectWithoutNetworkIdentity()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourSetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// set some existing GO+netId first to check if it is going to be
|
||||||
|
// overwritten
|
||||||
|
CreateGameObject(out GameObject go);
|
||||||
|
comp.test = go;
|
||||||
|
comp.testNetId = 43;
|
||||||
|
|
||||||
|
// create test GO with no networkidentity
|
||||||
|
CreateGameObject(out GameObject test);
|
||||||
|
|
||||||
|
// set the GameObject SyncVar to 'test' GO without netidentity.
|
||||||
|
// -> the way it currently works is that it sets netId to 0, but
|
||||||
|
// it DOES set gameObjectField to the GameObject without the
|
||||||
|
// NetworkIdentity, instead of setting it to null because it's
|
||||||
|
// seemingly invalid.
|
||||||
|
// -> there might be a deeper reason why UNET did that. perhaps for
|
||||||
|
// cases where we assign a GameObject before the network was
|
||||||
|
// fully started and has no netId or networkidentity yet etc.
|
||||||
|
// => it works, so let's keep it for now
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
comp.SetSyncVarGameObjectExposed(test, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(test));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(0));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarGameObjectZeroNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject gameObject, out NetworkIdentity identity, out NetworkBehaviourSetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// set some existing GO+netId first to check if it is going to be
|
||||||
|
// overwritten
|
||||||
|
CreateGameObject(out GameObject go);
|
||||||
|
comp.test = go;
|
||||||
|
comp.testNetId = 43;
|
||||||
|
|
||||||
|
// create test GO with networkidentity and zero netid
|
||||||
|
CreateNetworked(out GameObject test, out NetworkIdentity ni);
|
||||||
|
Assert.That(ni.netId, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// set the GameObject SyncVar to 'test' GO with zero netId.
|
||||||
|
// -> the way it currently works is that it sets netId to 0, but
|
||||||
|
// it DOES set gameObjectField to the GameObject without the
|
||||||
|
// NetworkIdentity, instead of setting it to null because it's
|
||||||
|
// seemingly invalid.
|
||||||
|
// -> there might be a deeper reason why UNET did that. perhaps for
|
||||||
|
// cases where we assign a GameObject before the network was
|
||||||
|
// fully started and has no netId or networkidentity yet etc.
|
||||||
|
// => it works, so let's keep it for now
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
LogAssert.Expect(LogType.Warning, $"SetSyncVarGameObject GameObject {test} has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
comp.SetSyncVarGameObjectExposed(test, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(test));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(0));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarGameObjectOnServer()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject gameObject, out NetworkIdentity identity, out NetworkBehaviourGetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// call OnStartServer so isServer is true
|
||||||
|
identity.OnStartServer();
|
||||||
|
Assert.That(identity.isServer, Is.True);
|
||||||
|
|
||||||
|
// create a syncable GameObject
|
||||||
|
CreateNetworked(out GameObject go, out NetworkIdentity ni);
|
||||||
|
ni.netId = identity.netId + 1;
|
||||||
|
|
||||||
|
// assign it in the component
|
||||||
|
comp.test = go;
|
||||||
|
comp.testNetId = ni.netId;
|
||||||
|
|
||||||
|
// get it on the server. should simply return the field instead of
|
||||||
|
// doing any netId lookup like on the client
|
||||||
|
GameObject result = comp.GetSyncVarGameObjectExposed();
|
||||||
|
Assert.That(result, Is.EqualTo(go));
|
||||||
|
|
||||||
|
// clean up: set isServer false first, otherwise Destroy instead of DestroyImmediate is called
|
||||||
|
identity.netId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarGameObjectOnServerNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject gameObject, out NetworkIdentity identity, out NetworkBehaviourGetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// call OnStartServer and assign netId so isServer is true
|
||||||
|
identity.OnStartServer();
|
||||||
|
Assert.That(identity.isServer, Is.True);
|
||||||
|
|
||||||
|
// get it on the server. null should work fine.
|
||||||
|
GameObject result = comp.GetSyncVarGameObjectExposed();
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarGameObjectOnClient()
|
||||||
|
{
|
||||||
|
// start server & connect client because we need spawn functions
|
||||||
|
NetworkServer.Listen(1);
|
||||||
|
ConnectClientBlockingAuthenticatedAndReady(out _);
|
||||||
|
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// are we on client and not on server?
|
||||||
|
identity.isClient = true;
|
||||||
|
Assert.That(identity.isServer, Is.False);
|
||||||
|
|
||||||
|
// create a networked object with test component
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourGetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// create a spawned, syncable GameObject
|
||||||
|
// (client tries to look up via netid, so needs to be spawned)
|
||||||
|
CreateNetworkedAndSpawn(
|
||||||
|
out GameObject serverGO, out NetworkIdentity serverIdentity,
|
||||||
|
out GameObject clientGO, out NetworkIdentity clientIdentity);
|
||||||
|
|
||||||
|
// assign ONLY netId in the component. assume that GameObject was
|
||||||
|
// assigned earlier but client walked so far out of range that it
|
||||||
|
// was despawned on the client. so it's forced to do the netId look-
|
||||||
|
// up.
|
||||||
|
Assert.That(comp.test, Is.Null);
|
||||||
|
comp.testNetId = clientIdentity.netId;
|
||||||
|
|
||||||
|
// get it on the client. should look up netId in spawned
|
||||||
|
GameObject result = comp.GetSyncVarGameObjectExposed();
|
||||||
|
Assert.That(result, Is.EqualTo(clientGO));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarGameObjectOnClientNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity);
|
||||||
|
|
||||||
|
// are we on client and not on server?
|
||||||
|
identity.isClient = true;
|
||||||
|
Assert.That(identity.isServer, Is.False);
|
||||||
|
|
||||||
|
// create a networked object with test component
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourGetSyncVarGameObjectComponent comp);
|
||||||
|
|
||||||
|
// get it on the client. null should be supported.
|
||||||
|
GameObject result = comp.GetSyncVarGameObjectExposed();
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarNetworkIdentityWithValidObject()
|
||||||
|
{
|
||||||
|
// create a networked object with test component
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourSetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// create a valid GameObject with networkidentity and netid
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity ni);
|
||||||
|
ni.netId = 43;
|
||||||
|
|
||||||
|
// set the NetworkIdentity SyncVar
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
comp.SetSyncVarNetworkIdentityExposed(ni, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(ni));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(ni.netId));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarNetworkIdentityNull()
|
||||||
|
{
|
||||||
|
// create a networked object with test component
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourSetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// set some existing NI+netId first to check if it is going to be
|
||||||
|
// overwritten
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity ni);
|
||||||
|
comp.test = ni;
|
||||||
|
comp.testNetId = 43;
|
||||||
|
|
||||||
|
// set the NetworkIdentity SyncVar to null
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
comp.SetSyncVarNetworkIdentityExposed(null, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(null));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(0));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SetSyncVarNetworkIdentityZeroNetId()
|
||||||
|
{
|
||||||
|
CreateNetworked(out _, out _, out NetworkBehaviourSetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// set some existing NI+netId first to check if it is going to be
|
||||||
|
// overwritten
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity ni);
|
||||||
|
comp.test = ni;
|
||||||
|
comp.testNetId = 43;
|
||||||
|
|
||||||
|
// create test GO with networkidentity and zero netid
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity testNi);
|
||||||
|
Assert.That(testNi.netId, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// set the NetworkIdentity SyncVar to 'test' GO with zero netId.
|
||||||
|
// -> the way it currently works is that it sets netId to 0, but
|
||||||
|
// it DOES set gameObjectField to the GameObject without the
|
||||||
|
// NetworkIdentity, instead of setting it to null because it's
|
||||||
|
// seemingly invalid.
|
||||||
|
// -> there might be a deeper reason why UNET did that. perhaps for
|
||||||
|
// cases where we assign a GameObject before the network was
|
||||||
|
// fully started and has no netId or networkidentity yet etc.
|
||||||
|
// => it works, so let's keep it for now
|
||||||
|
Assert.That(comp.IsDirty(), Is.False);
|
||||||
|
LogAssert.Expect(LogType.Warning, $"SetSyncVarNetworkIdentity NetworkIdentity {testNi} has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
comp.SetSyncVarNetworkIdentityExposed(testNi, 1ul);
|
||||||
|
Assert.That(comp.test, Is.EqualTo(testNi));
|
||||||
|
Assert.That(comp.testNetId, Is.EqualTo(0));
|
||||||
|
Assert.That(comp.IsDirty(), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarNetworkIdentityOnServer()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out NetworkBehaviourGetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// call OnStartServer so isServer is true
|
||||||
|
identity.OnStartServer();
|
||||||
|
Assert.That(identity.isServer, Is.True);
|
||||||
|
|
||||||
|
// create a syncable GameObject
|
||||||
|
CreateNetworked(out _, out NetworkIdentity ni);
|
||||||
|
ni.netId = identity.netId + 1;
|
||||||
|
|
||||||
|
// assign it in the component
|
||||||
|
comp.test = ni;
|
||||||
|
comp.testNetId = ni.netId;
|
||||||
|
|
||||||
|
// get it on the server. should simply return the field instead of
|
||||||
|
// doing any netId lookup like on the client
|
||||||
|
NetworkIdentity result = comp.GetSyncVarNetworkIdentityExposed();
|
||||||
|
Assert.That(result, Is.EqualTo(ni));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarNetworkIdentityOnServerNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out NetworkBehaviourGetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// call OnStartServer so isServer is true
|
||||||
|
identity.OnStartServer();
|
||||||
|
Assert.That(identity.isServer, Is.True);
|
||||||
|
|
||||||
|
// get it on the server. null should work fine.
|
||||||
|
NetworkIdentity result = comp.GetSyncVarNetworkIdentityExposed();
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarNetworkIdentityOnClient()
|
||||||
|
{
|
||||||
|
// start server & connect client because we need spawn functions
|
||||||
|
NetworkServer.Listen(1);
|
||||||
|
ConnectClientBlockingAuthenticatedAndReady(out _);
|
||||||
|
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out NetworkBehaviourGetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// are we on client and not on server?
|
||||||
|
identity.isClient = true;
|
||||||
|
Assert.That(identity.isServer, Is.False);
|
||||||
|
|
||||||
|
// create a spawned, syncable GameObject
|
||||||
|
// (client tries to look up via netid, so needs to be spawned)
|
||||||
|
CreateNetworkedAndSpawn(
|
||||||
|
out _, out NetworkIdentity serverIdentity,
|
||||||
|
out _, out NetworkIdentity clientIdentity);
|
||||||
|
|
||||||
|
// assign ONLY netId in the component. assume that GameObject was
|
||||||
|
// assigned earlier but client walked so far out of range that it
|
||||||
|
// was despawned on the client. so it's forced to do the netId look-
|
||||||
|
// up.
|
||||||
|
Assert.That(comp.test, Is.Null);
|
||||||
|
comp.testNetId = clientIdentity.netId;
|
||||||
|
|
||||||
|
// get it on the client. should look up netId in spawned
|
||||||
|
NetworkIdentity result = comp.GetSyncVarNetworkIdentityExposed();
|
||||||
|
Assert.That(result, Is.EqualTo(clientIdentity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSyncVarNetworkIdentityOnClientNull()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out NetworkBehaviourGetSyncVarNetworkIdentityComponent comp);
|
||||||
|
|
||||||
|
// are we on client and not on server?
|
||||||
|
identity.isClient = true;
|
||||||
|
Assert.That(identity.isServer, Is.False);
|
||||||
|
|
||||||
|
// get it on the client. null should be supported.
|
||||||
|
NetworkIdentity result = comp.GetSyncVarNetworkIdentityExposed();
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SerializeAndDeserializeObjectsAll()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity _, out NetworkBehaviourWithSyncVarsAndCollections comp);
|
||||||
|
|
||||||
|
// add values to synclist
|
||||||
|
comp.list.Add(42);
|
||||||
|
comp.list.Add(43);
|
||||||
|
|
||||||
|
// serialize it
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
comp.SerializeObjectsAll(writer);
|
||||||
|
|
||||||
|
// clear original list
|
||||||
|
comp.list.Clear();
|
||||||
|
Assert.That(comp.list.Count, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// deserialize it
|
||||||
|
NetworkReader reader = new NetworkReader(writer.ToArray());
|
||||||
|
comp.DeSerializeObjectsAll(reader);
|
||||||
|
Assert.That(comp.list.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(comp.list[0], Is.EqualTo(42));
|
||||||
|
Assert.That(comp.list[1], Is.EqualTo(43));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SerializeAndDeserializeObjectsDelta()
|
||||||
|
{
|
||||||
|
// SyncLists are only set dirty while owner has observers.
|
||||||
|
// need a connection.
|
||||||
|
NetworkServer.Listen(1);
|
||||||
|
ConnectHostClientBlockingAuthenticatedAndReady();
|
||||||
|
|
||||||
|
CreateNetworkedAndSpawn(out GameObject _, out NetworkIdentity _, out NetworkBehaviourWithSyncVarsAndCollections comp);
|
||||||
|
|
||||||
|
// add to synclist
|
||||||
|
comp.list.Add(42);
|
||||||
|
comp.list.Add(43);
|
||||||
|
|
||||||
|
// serialize it
|
||||||
|
NetworkWriter writer = new NetworkWriter();
|
||||||
|
comp.SerializeObjectsDelta(writer);
|
||||||
|
|
||||||
|
// clear original list
|
||||||
|
comp.list.Clear();
|
||||||
|
Assert.That(comp.list.Count, Is.EqualTo(0));
|
||||||
|
|
||||||
|
// deserialize it
|
||||||
|
NetworkReader reader = new NetworkReader(writer.ToArray());
|
||||||
|
comp.DeSerializeObjectsDelta(reader);
|
||||||
|
Assert.That(comp.list.Count, Is.EqualTo(2));
|
||||||
|
Assert.That(comp.list[0], Is.EqualTo(42));
|
||||||
|
Assert.That(comp.list[1], Is.EqualTo(43));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OnStopClient()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out OnStopClientComponent comp);
|
||||||
|
identity.OnStopClient();
|
||||||
|
Assert.That(comp.called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OnStartClient()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out OnStartClientComponent comp);
|
||||||
|
identity.OnStartClient();
|
||||||
|
Assert.That(comp.called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OnStartLocalPlayer()
|
||||||
|
{
|
||||||
|
CreateNetworked(out GameObject _, out NetworkIdentity identity, out OnStartLocalPlayerComponent comp);
|
||||||
|
identity.OnStartLocalPlayer();
|
||||||
|
Assert.That(comp.called, Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we need to inherit from networkbehaviour to test protected functions
|
||||||
|
public class NetworkBehaviourInitSyncObjectTester : NetworkBehaviour
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void InitSyncObject()
|
||||||
|
{
|
||||||
|
SyncObject syncObject = new SyncList<bool>();
|
||||||
|
InitSyncObject(syncObject);
|
||||||
|
Assert.That(syncObjects.Count, Is.EqualTo(1));
|
||||||
|
Assert.That(syncObjects[0], Is.EqualTo(syncObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Mirror/Tests/Editor/NetworkBehaviourTests.cs.meta
Normal file
11
Assets/Mirror/Tests/Editor/NetworkBehaviourTests.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0e4164d273d6e4d71bd39cc246f454b2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
128
Assets/Mirror/Tests/Editor/NetworkClientTests.cs
Normal file
128
Assets/Mirror/Tests/Editor/NetworkClientTests.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Mirror.Tests
|
||||||
|
{
|
||||||
|
public class NetworkClientTests : MirrorEditModeTest
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
// we need a server to connect to
|
||||||
|
NetworkServer.Listen(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ServerIp()
|
||||||
|
{
|
||||||
|
NetworkClient.ConnectHost();
|
||||||
|
Assert.That(NetworkClient.serverIp, Is.EqualTo("localhost"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IsConnected()
|
||||||
|
{
|
||||||
|
Assert.That(NetworkClient.isConnected, Is.False);
|
||||||
|
NetworkClient.ConnectHost();
|
||||||
|
Assert.That(NetworkClient.isConnected, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ConnectUri()
|
||||||
|
{
|
||||||
|
NetworkClient.Connect(new Uri("memory://localhost"));
|
||||||
|
// update transport so connect event is processed
|
||||||
|
UpdateTransport();
|
||||||
|
Assert.That(NetworkClient.isConnected, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DisconnectInHostMode()
|
||||||
|
{
|
||||||
|
NetworkClient.ConnectHost();
|
||||||
|
Assert.That(NetworkClient.isConnected, Is.True);
|
||||||
|
Assert.That(NetworkServer.localConnection, !Is.Null);
|
||||||
|
|
||||||
|
NetworkClient.Disconnect();
|
||||||
|
Assert.That(NetworkClient.isConnected, Is.False);
|
||||||
|
Assert.That(NetworkServer.localConnection, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Ignore("NetworkServerTest.SendClientToServerMessage does it already")]
|
||||||
|
public void Send() {}
|
||||||
|
|
||||||
|
// test to guarantee Disconnect() eventually calls OnClientDisconnected.
|
||||||
|
// prevents https://github.com/vis2k/Mirror/issues/2818 forever.
|
||||||
|
// previously there was a bug where:
|
||||||
|
// - Disconnect() sets state = Disconnected
|
||||||
|
// - Transport processes it
|
||||||
|
// - OnTransportDisconnected() early returns because
|
||||||
|
// state == Disconnected already, so it wouldn't call the event.
|
||||||
|
[Test]
|
||||||
|
public void DisconnectCallsOnClientDisconnected_Remote()
|
||||||
|
{
|
||||||
|
// setup hook
|
||||||
|
bool called = false;
|
||||||
|
NetworkClient.OnDisconnectedEvent = () => called = true;
|
||||||
|
|
||||||
|
// connect
|
||||||
|
ConnectClientBlocking(out _);
|
||||||
|
|
||||||
|
// disconnect & process everything
|
||||||
|
NetworkClient.Disconnect();
|
||||||
|
UpdateTransport();
|
||||||
|
|
||||||
|
// was it called?
|
||||||
|
Assert.That(called, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as above, but for host mode
|
||||||
|
// prevents https://github.com/vis2k/Mirror/issues/2818 forever.
|
||||||
|
[Test]
|
||||||
|
public void DisconnectCallsOnClientDisconnected_HostMode()
|
||||||
|
{
|
||||||
|
// setup hook
|
||||||
|
bool called = false;
|
||||||
|
NetworkClient.OnDisconnectedEvent = () => called = true;
|
||||||
|
|
||||||
|
// connect host
|
||||||
|
NetworkClient.ConnectHost();
|
||||||
|
|
||||||
|
// disconnect & process everything
|
||||||
|
NetworkClient.Disconnect();
|
||||||
|
UpdateTransport();
|
||||||
|
|
||||||
|
// was it called?
|
||||||
|
Assert.That(called, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShutdownCleanup()
|
||||||
|
{
|
||||||
|
// add some test event hooks to make sure they are cleaned up.
|
||||||
|
// there used to be a bug where they wouldn't be cleaned up.
|
||||||
|
NetworkClient.OnConnectedEvent = () => {};
|
||||||
|
NetworkClient.OnDisconnectedEvent = () => {};
|
||||||
|
|
||||||
|
NetworkClient.Shutdown();
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.handlers.Count, Is.EqualTo(0));
|
||||||
|
Assert.That(NetworkClient.spawned.Count, Is.EqualTo(0));
|
||||||
|
Assert.That(NetworkClient.spawnableObjects.Count, Is.EqualTo(0));
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.connectState, Is.EqualTo(ConnectState.None));
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.connection, Is.Null);
|
||||||
|
Assert.That(NetworkClient.localPlayer, Is.Null);
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.ready, Is.False);
|
||||||
|
Assert.That(NetworkClient.isSpawnFinished, Is.False);
|
||||||
|
Assert.That(NetworkClient.isLoadingScene, Is.False);
|
||||||
|
|
||||||
|
Assert.That(NetworkClient.OnConnectedEvent, Is.Null);
|
||||||
|
Assert.That(NetworkClient.OnDisconnectedEvent, Is.Null);
|
||||||
|
Assert.That(NetworkClient.OnErrorEvent, Is.Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user