com.unity.netcode.gameobjects@1.0.0-pre.2
# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). ## [1.0.0-pre.2] - 2020-12-20 ### Added - Associated Known Issues for the 1.0.0-pre.1 release in the changelog ### Changed - Updated label for `1.0.0-pre.1` changelog section ## [1.0.0-pre.1] - 2020-12-20 ### Added - Added `ClientNetworkTransform` sample to the SDK package (#1168) - Added `Bootstrap` sample to the SDK package (#1140) - Enhanced `NetworkSceneManager` implementation with additive scene loading capabilities (#1080, #955, #913) - `NetworkSceneManager.OnSceneEvent` provides improved scene event notificaitons - Enhanced `NetworkTransform` implementation with per axis/component based and threshold based state replication (#1042, #1055, #1061, #1084, #1101) - Added a jitter-resistent `BufferedLinearInterpolator<T>` for `NetworkTransform` (#1060) - Implemented `NetworkPrefabHandler` that provides support for object pooling and `NetworkPrefab` overrides (#1073, #1004, #977, #905,#749, #727) - Implemented auto `NetworkObject` transform parent synchronization at runtime over the network (#855) - Adopted Unity C# Coding Standards in the codebase with `.editorconfig` ruleset (#666, #670) - When a client tries to spawn a `NetworkObject` an exception is thrown to indicate unsupported behavior. (#981) - Added a `NetworkTime` and `NetworkTickSystem` which allows for improved control over time and ticks. (#845) - Added a `OnNetworkDespawn` function to `NetworkObject` which gets called when a `NetworkObject` gets despawned and can be overriden. (#865) - Added `SnapshotSystem` that would allow variables and spawn/despawn messages to be sent in blocks (#805, #852, #862, #963, #1012, #1013, #1021, #1040, #1062, #1064, #1083, #1091, #1111, #1129, #1166, #1192) - Disabled by default for now, except spawn/despawn messages - Will leverage unreliable messages with eventual consistency - `NetworkBehaviour` and `NetworkObject`'s `NetworkManager` instances can now be overriden (#762) - Added metrics reporting for the new network profiler if the Multiplayer Tools package is present (#1104, #1089, #1096, #1086, #1072, #1058, #960, #897, #891, #878) - `NetworkBehaviour.IsSpawned` a quick (and stable) way to determine if the associated NetworkObject is spawned (#1190) - Added `NetworkRigidbody` and `NetworkRigidbody2D` components to support networking `Rigidbody` and `Rigidbody2D` components (#1202, #1175) - Added `NetworkObjectReference` and `NetworkBehaviourReference` structs which allow to sending `NetworkObject/Behaviours` over RPCs/`NetworkVariable`s (#1173) - Added `NetworkAnimator` component to support networking `Animator` component (#1281, #872) ### Changed - Bumped minimum Unity version, renamed package as "Unity Netcode for GameObjects", replaced `MLAPI` namespace and its variants with `Unity.Netcode` namespace and per asm-def variants (#1007, #1009, #1015, #1017, #1019, #1025, #1026, #1065) - Minimum Unity version: - 2019.4 → 2020.3+ - Package rename: - Display name: `MLAPI Networking Library` → `Netcode for GameObjects` - Name: `com.unity.multiplayer.mlapi` → `com.unity.netcode.gameobjects` - Updated package description - All `MLAPI.x` namespaces are replaced with `Unity.Netcode` - `MLAPI.Messaging` → `Unity.Netcode` - `MLAPI.Connection` → `Unity.Netcode` - `MLAPI.Logging` → `Unity.Netcode` - `MLAPI.SceneManagement` → `Unity.Netcode` - and other `MLAPI.x` variants to `Unity.Netcode` - All assembly definitions are renamed with `Unity.Netcode.x` variants - `Unity.Multiplayer.MLAPI.Runtime` → `Unity.Netcode.Runtime` - `Unity.Multiplayer.MLAPI.Editor` → `Unity.Netcode.Editor` - and other `Unity.Multiplayer.MLAPI.x` variants to `Unity.Netcode.x` variants - Renamed `Prototyping` namespace and assembly definition to `Components` (#1145) - Changed `NetworkObject.Despawn(bool destroy)` API to default to `destroy = true` for better usability (#1217) - Scene registration in `NetworkManager` is now replaced by Build Setttings → Scenes in Build List (#1080) - `NetworkSceneManager.SwitchScene` has been replaced by `NetworkSceneManager.LoadScene` (#955) - `NetworkManager, NetworkConfig, and NetworkSceneManager` scene registration replaced with scenes in build list (#1080) - `GlobalObjectIdHash` replaced `PrefabHash` and `PrefabHashGenerator` for stability and consistency (#698) - `NetworkStart` has been renamed to `OnNetworkSpawn`. (#865) - Network variable cleanup - eliminated shared mode, variables are server-authoritative (#1059, #1074) - `NetworkManager` and other systems are no longer singletons/statics (#696, #705, #706, #737, #738, #739, #746, #747, #763, #765, #766, #783, #784, #785, #786, #787, #788) - Changed `INetworkSerializable.NetworkSerialize` method signature to use `BufferSerializer<T>` instead of `NetworkSerializer` (#1187) - Changed `CustomMessagingManager`'s methods to use `FastBufferWriter` and `FastBufferReader` instead of `Stream` (#1187) - Reduced internal runtime allocations by removing LINQ calls and replacing managed lists/arrays with native collections (#1196) ### Removed - Removed `NetworkNavMeshAgent` (#1150) - Removed `NetworkDictionary`, `NetworkSet` (#1149) - Removed `NetworkVariableSettings` (#1097) - Removed predefined `NetworkVariable<T>` types (#1093) - Removed `NetworkVariableBool`, `NetworkVariableByte`, `NetworkVariableSByte`, `NetworkVariableUShort`, `NetworkVariableShort`, `NetworkVariableUInt`, `NetworkVariableInt`, `NetworkVariableULong`, `NetworkVariableLong`, `NetworkVariableFloat`, `NetworkVariableDouble`, `NetworkVariableVector2`, `NetworkVariableVector3`, `NetworkVariableVector4`, `NetworkVariableColor`, `NetworkVariableColor32`, `NetworkVariableRay`, `NetworkVariableQuaternion` - Removed `NetworkChannel` and `MultiplexTransportAdapter` (#1133) - Removed ILPP backend for 2019.4, minimum required version is 2020.3+ (#895) - `NetworkManager.NetworkConfig` had the following properties removed: (#1080) - Scene Registrations no longer exists - Allow Runtime Scene Changes was no longer needed and was removed - Removed the NetworkObject.Spawn payload parameter (#1005) - Removed `ProfilerCounter`, the original MLAPI network profiler, and the built-in network profiler module (2020.3). A replacement can now be found in the Multiplayer Tools package. (#1048) - Removed UNet RelayTransport and related relay functionality in UNetTransport (#1081) - Removed `UpdateStage` parameter from `ServerRpcSendParams` and `ClientRpcSendParams` (#1187) - Removed `NetworkBuffer`, `NetworkWriter`, `NetworkReader`, `NetworkSerializer`, `PooledNetworkBuffer`, `PooledNetworkWriter`, and `PooledNetworkReader` (#1187) - Removed `EnableNetworkVariable` in `NetworkConfig`, it is always enabled now (#1179) - Removed `NetworkTransform`'s FixedSendsPerSecond, AssumeSyncedSends, InterpolateServer, ExtrapolatePosition, MaxSendsToExtrapolate, Channel, EnableNonProvokedResendChecks, DistanceSendrate (#1060) (#826) (#1042, #1055, #1061, #1084, #1101) - Removed `NetworkManager`'s `StopServer()`, `StopClient()` and `StopHost()` methods and replaced with single `NetworkManager.Shutdown()` method for all (#1108) ### Fixed - Fixed ServerRpc ownership check to `Debug.LogError` instead of `Debug.LogWarning` (#1126) - Fixed `NetworkObject.OwnerClientId` property changing before `NetworkBehaviour.OnGainedOwnership()` callback (#1092) - Fixed `NetworkBehaviourILPP` to iterate over all types in an assembly (#803) - Fixed cross-asmdef RPC ILPP by importing types into external assemblies (#678) - Fixed `NetworkManager` shutdown when quitting the application or switching scenes (#1011) - Now `NetworkManager` shutdowns correctly and despawns existing `NetworkObject`s - Fixed Only one `PlayerPrefab` can be selected on `NetworkManager` inspector UI in the editor (#676) - Fixed connection approval not being triggered for host (#675) - Fixed various situations where messages could be processed in an invalid order, resulting in errors (#948, #1187, #1218) - Fixed `NetworkVariable`s being default-initialized on the client instead of being initialized with the desired value (#1266) - Improved runtime performance and reduced GC pressure (#1187) - Fixed #915 - clients are receiving data from objects not visible to them (#1099) - Fixed `NetworkTransform`'s "late join" issues, `NetworkTransform` now uses `NetworkVariable`s instead of RPCs (#826) - Throw an exception for silent failure when a client tries to get another player's `PlayerObject`, it is now only allowed on the server-side (#844) ### Known Issues - `NetworkVariable` does not serialize `INetworkSerializable` types through their `NetworkSerialize` implementation - `NetworkObjects` marked as `DontDestroyOnLoad` are disabled during some network scene transitions - `NetworkTransform` interpolates from the origin when switching Local Space synchronization - Exceptions thrown in `OnNetworkSpawn` user code for an object will prevent the callback in other objects - Cannot send an array of `INetworkSerializable` in RPCs - ILPP generation fails with special characters in project path ## [0.2.0] - 2021-06-03 WIP version increment to pass package validation checks. Changelog & final version number TBD. ## [0.1.1] - 2021-06-01 This is hotfix v0.1.1 for the initial experimental Unity MLAPI Package. ### Changed - Fixed issue with the Unity Registry package version missing some fixes from the v0.1.0 release. ## [0.1.0] - 2021-03-23 This is the initial experimental Unity MLAPI Package, v0.1.0. ### Added - Refactored a new standard for Remote Procedure Call (RPC) in MLAPI which provides increased performance, significantly reduced boilerplate code, and extensibility for future-proofed code. MLAPI RPC includes `ServerRpc` and `ClientRpc` to execute logic on the server and client-side. This provides a single performant unified RPC solution, replacing MLAPI Convenience and Performance RPC (see [here](#removed-features)). - Added standarized serialization types, including built-in and custom serialization flows. See [RFC #2](https://github.com/Unity-Technologies/com.unity.multiplayer.rfcs/blob/master/text/0002-serializable-types.md) for details. - `INetworkSerializable` interface replaces `IBitWritable`. - Added `NetworkSerializer`..., which is the main aggregator that implements serialization code for built-in supported types and holds `NetworkReader` and `NetworkWriter` instances internally. - Added a Network Update Loop infrastructure that aids Netcode systems to update (such as RPC queue and transport) outside of the standard `MonoBehaviour` event cycle. See [RFC #8](https://github.com/Unity-Technologies/com.unity.multiplayer.rfcs/blob/master/text/0008-network-update-loop.md) and the following details: - It uses Unity's [low-level Player Loop API](https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.html) and allows for registering `INetworkUpdateSystem`s with `NetworkUpdate` methods to be executed at specific `NetworkUpdateStage`s, which may also be before or after `MonoBehaviour`-driven game logic execution. - You will typically interact with `NetworkUpdateLoop` for registration and `INetworkUpdateSystem` for implementation. - `NetworkVariable`s are now tick-based using the `NetworkTickSystem`, tracking time through network interactions and syncs. - Added message batching to handle consecutive RPC requests sent to the same client. `RpcBatcher` sends batches based on requests from the `RpcQueueProcessing`, by batch size threshold or immediately. - [GitHub 494](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/494): Added a constraint to allow one `NetworkObject` per `GameObject`, set through the `DisallowMultipleComponent` attribute. - Integrated MLAPI with the Unity Profiler for versions 2020.2 and later: - Added new profiler modules for MLAPI that report important network data. - Attached the profiler to a remote player to view network data over the wire. - A test project is available for building and experimenting with MLAPI features. This project is available in the MLAPI GitHub [testproject folder](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/tree/release/0.1.0/testproject). - Added a [MLAPI Community Contributions](https://github.com/Unity-Technologies/mlapi-community-contributions/tree/master/com.mlapi.contrib.extensions) new GitHub repository to accept extensions from the MLAPI community. Current extensions include moved MLAPI features for lag compensation (useful for Server Authoritative actions) and `TrackedObject`. ### Changed - [GitHub 520](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/520): MLAPI now uses the Unity Package Manager for installation management. - Added functionality and usability to `NetworkVariable`, previously called `NetworkVar`. Updates enhance options and fully replace the need for `SyncedVar`s. - [GitHub 507](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/507): Reimplemented `NetworkAnimator`, which synchronizes animation states for networked objects. - GitHub [444](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/444) and [455](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/455): Channels are now represented as bytes instead of strings. For users of previous versions of MLAPI, this release renames APIs due to refactoring. All obsolete marked APIs have been removed as per [GitHub 513](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/513) and [GitHub 514](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/514). | Previous MLAPI Versions | V 0.1.0 Name | | -- | -- | | `NetworkingManager` | `NetworkManager` | | `NetworkedObject` | `NetworkObject` | | `NetworkedBehaviour` | `NetworkBehaviour` | | `NetworkedClient` | `NetworkClient` | | `NetworkedPrefab` | `NetworkPrefab` | | `NetworkedVar` | `NetworkVariable` | | `NetworkedTransform` | `NetworkTransform` | | `NetworkedAnimator` | `NetworkAnimator` | | `NetworkedAnimatorEditor` | `NetworkAnimatorEditor` | | `NetworkedNavMeshAgent` | `NetworkNavMeshAgent` | | `SpawnManager` | `NetworkSpawnManager` | | `BitStream` | `NetworkBuffer` | | `BitReader` | `NetworkReader` | | `BitWriter` | `NetworkWriter` | | `NetEventType` | `NetworkEventType` | | `ChannelType` | `NetworkDelivery` | | `Channel` | `NetworkChannel` | | `Transport` | `NetworkTransport` | | `NetworkedDictionary` | `NetworkDictionary` | | `NetworkedList` | `NetworkList` | | `NetworkedSet` | `NetworkSet` | | `MLAPIConstants` | `NetworkConstants` | | `UnetTransport` | `UNetTransport` | ### Fixed - [GitHub 460](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/460): Fixed an issue for RPC where the host-server was not receiving RPCs from the host-client and vice versa without the loopback flag set in `NetworkingManager`. - Fixed an issue where data in the Profiler was incorrectly aggregated and drawn, which caused the profiler data to increment indefinitely instead of resetting each frame. - Fixed an issue the client soft-synced causing PlayMode client-only scene transition issues, caused when running the client in the editor and the host as a release build. Users may have encountered a soft sync of `NetworkedInstanceId` issues in the `SpawnManager.ClientCollectSoftSyncSceneObjectSweep` method. - [GitHub 458](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/458): Fixed serialization issues in `NetworkList` and `NetworkDictionary` when running in Server mode. - [GitHub 498](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/498): Fixed numerical precision issues to prevent not a number (NaN) quaternions. - [GitHub 438](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/438): Fixed booleans by reaching or writing bytes instead of bits. - [GitHub 519](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/519): Fixed an issue where calling `Shutdown()` before making `NetworkManager.Singleton = null` is null on `NetworkManager.OnDestroy()`. ### Removed With a new release of MLAPI in Unity, some features have been removed: - SyncVars have been removed from MLAPI. Use `NetworkVariable`s in place of this functionality. <!-- MTT54 --> - [GitHub 527](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/527): Lag compensation systems and `TrackedObject` have moved to the new [MLAPI Community Contributions](https://github.com/Unity-Technologies/mlapi-community-contributions/tree/master/com.mlapi.contrib.extensions) repo. - [GitHub 509](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/509): Encryption has been removed from MLAPI. The `Encryption` option in `NetworkConfig` on the `NetworkingManager` is not available in this release. This change will not block game creation or running. A current replacement for this functionality is not available, and may be developed in future releases. See the following changes: - Removed `SecuritySendFlags` from all APIs. - Removed encryption, cryptography, and certificate configurations from APIs including `NetworkManager` and `NetworkConfig`. - Removed "hail handshake", including `NetworkManager` implementation and `NetworkConstants` entries. - Modified `RpcQueue` and `RpcBatcher` internals to remove encryption and authentication from reading and writing. - Removed the previous MLAPI Profiler editor window from Unity versions 2020.2 and later. - Removed previous MLAPI Convenience and Performance RPC APIs with the new standard RPC API. See [RFC #1](https://github.com/Unity-Technologies/com.unity.multiplayer.rfcs/blob/master/text/0001-std-rpc-api.md) for details. - [GitHub 520](https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/520): Removed the MLAPI Installer. ### Known Issues - `NetworkNavMeshAgent` does not synchronize mesh data, Agent Size, Steering, Obstacle Avoidance, or Path Finding settings. It only synchronizes the destination and velocity, not the path to the destination. - For `RPC`, methods with a `ClientRpc` or `ServerRpc` suffix which are not marked with [ServerRpc] or [ClientRpc] will cause a compiler error. - For `NetworkAnimator`, Animator Overrides are not supported. Triggers do not work. - For `NetworkVariable`, the `NetworkDictionary` `List` and `Set` must use the `reliableSequenced` channel. - `NetworkObjects`s are supported but when spawning a prefab with nested child network objects you have to manually call spawn on them - `NetworkTransform` have the following issues: - Replicated objects may have jitter. - The owner is always authoritative about the object's position. - Scale is not synchronized. - Connection Approval is not called on the host client. - For `NamedMessages`, always use `NetworkBuffer` as the underlying stream for sending named and unnamed messages. - For `NetworkManager`, connection management is limited. Use `IsServer`, `IsClient`, `IsConnectedClient`, or other code to check if MLAPI connected correctly. ## [0.0.1-preview.1] - 2020-12-20 This was an internally-only-used version of the Unity MLAPI Package
This commit is contained in:
8
Tests/Editor.meta
Normal file
8
Tests/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d656bc8bb2502584ab6883d254d64782
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
31
Tests/Editor/ArithmeticTests.cs
Normal file
31
Tests/Editor/ArithmeticTests.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class ArithmeticTests
|
||||
{
|
||||
[Test]
|
||||
public void TestCeil()
|
||||
{
|
||||
Assert.That(Arithmetic.CeilingExact(10, 5), Is.EqualTo(2));
|
||||
Assert.That(Arithmetic.CeilingExact(11, 5), Is.EqualTo(3));
|
||||
Assert.That(Arithmetic.CeilingExact(0, 5), Is.EqualTo(0));
|
||||
Assert.That(Arithmetic.CeilingExact(1, 5), Is.EqualTo(1));
|
||||
Assert.That(Arithmetic.CeilingExact(2, 5), Is.EqualTo(1));
|
||||
Assert.That(Arithmetic.CeilingExact(3, 5), Is.EqualTo(1));
|
||||
Assert.That(Arithmetic.CeilingExact(4, 5), Is.EqualTo(1));
|
||||
Assert.That(Arithmetic.CeilingExact(5, 5), Is.EqualTo(1));
|
||||
Assert.That(Arithmetic.CeilingExact(6, 5), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestZigZag()
|
||||
{
|
||||
Assert.That(Arithmetic.ZigZagDecode(Arithmetic.ZigZagEncode(1234)), Is.EqualTo(1234));
|
||||
Assert.That(Arithmetic.ZigZagDecode(Arithmetic.ZigZagEncode(-1)), Is.EqualTo(-1));
|
||||
Assert.That(Arithmetic.ZigZagDecode(Arithmetic.ZigZagEncode(0)), Is.EqualTo(0));
|
||||
Assert.That(Arithmetic.ZigZagDecode(Arithmetic.ZigZagEncode(long.MaxValue)), Is.EqualTo(long.MaxValue));
|
||||
Assert.That(Arithmetic.ZigZagDecode(Arithmetic.ZigZagEncode(long.MinValue)), Is.EqualTo(long.MinValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/ArithmeticTests.cs.meta
Normal file
11
Tests/Editor/ArithmeticTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc0dc1cbf78a5486db1ccbc245d90992
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Tests/Editor/Build.meta
Normal file
8
Tests/Editor/Build.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a46bbc7e63044f498612ed996afa274
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
371
Tests/Editor/Build/BuildTestScene.unity
Normal file
371
Tests/Editor/Build/BuildTestScene.unity
Normal file
@@ -0,0 +1,371 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 12
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 0
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 512
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 256
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 1
|
||||
m_PVRDenoiserTypeDirect: 1
|
||||
m_PVRDenoiserTypeIndirect: 1
|
||||
m_PVRDenoiserTypeAO: 1
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 1
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 0}
|
||||
m_LightingSettings: {fileID: 0}
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &1290761662
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1290761665}
|
||||
- component: {fileID: 1290761664}
|
||||
- component: {fileID: 1290761663}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &1290761663
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1290761662}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &1290761664
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1290761662}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1290761665
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1290761662}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1858588911
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1858588913}
|
||||
- component: {fileID: 1858588912}
|
||||
m_Layer: 0
|
||||
m_Name: Directional Light
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!108 &1858588912
|
||||
Light:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858588911}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
|
||||
m_Intensity: 1
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.80208
|
||||
m_CookieSize: 10
|
||||
m_Shadows:
|
||||
m_Type: 2
|
||||
m_Resolution: -1
|
||||
m_CustomResolution: -1
|
||||
m_Strength: 1
|
||||
m_Bias: 0.05
|
||||
m_NormalBias: 0.4
|
||||
m_NearPlane: 0.2
|
||||
m_CullingMatrixOverride:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_UseCullingMatrixOverride: 0
|
||||
m_Cookie: {fileID: 0}
|
||||
m_DrawHalo: 0
|
||||
m_Flare: {fileID: 0}
|
||||
m_RenderMode: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingLayerMask: 1
|
||||
m_Lightmapping: 4
|
||||
m_LightShadowCasterMode: 0
|
||||
m_AreaSize: {x: 1, y: 1}
|
||||
m_BounceIntensity: 1
|
||||
m_ColorTemperature: 6570
|
||||
m_UseColorTemperature: 0
|
||||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_UseViewFrustumForShadowCasterCull: 1
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
--- !u!4 &1858588913
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1858588911}
|
||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||
--- !u!1 &1896907459
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1896907460}
|
||||
- component: {fileID: 1896907461}
|
||||
m_Layer: 0
|
||||
m_Name: '[NetworkManager]'
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1896907460
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1896907459}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 2
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &1896907461
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1896907459}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 593a2fe42fa9d37498c96f9a383b6521, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
DontDestroy: 1
|
||||
RunInBackground: 1
|
||||
LogLevel: 1
|
||||
NetworkConfig:
|
||||
ProtocolVersion: 0
|
||||
NetworkTransport: {fileID: 0}
|
||||
RegisteredScenes:
|
||||
- BuildTestScene
|
||||
AllowRuntimeSceneChanges: 0
|
||||
PlayerPrefab: {fileID: 0}
|
||||
NetworkPrefabs: []
|
||||
TickRate: 30
|
||||
ClientConnectionBufferTimeout: 10
|
||||
ConnectionApproval: 0
|
||||
ConnectionData:
|
||||
EnableTimeResync: 0
|
||||
TimeResyncInterval: 30
|
||||
EnableNetworkVariable: 1
|
||||
EnsureNetworkVariableLengthSafety: 0
|
||||
EnableSceneManagement: 1
|
||||
ForceSamePrefabs: 1
|
||||
RecycleNetworkIds: 1
|
||||
NetworkIdRecycleDelay: 120
|
||||
RpcHashSize: 0
|
||||
LoadSceneTimeOut: 120
|
||||
MessageBufferTimeout: 20
|
||||
EnableNetworkLogs: 1
|
||||
7
Tests/Editor/Build/BuildTestScene.unity.meta
Normal file
7
Tests/Editor/Build/BuildTestScene.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d45c09a54b1da466ab6c385ee45fd3e4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Tests/Editor/Build/BuildTests.cs
Normal file
28
Tests/Editor/Build/BuildTests.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class BuildTests
|
||||
{
|
||||
public const string DefaultBuildScenePath = "Tests/Editor/Build/BuildTestScene.unity";
|
||||
|
||||
[Test]
|
||||
public void BasicBuildTest()
|
||||
{
|
||||
var execAssembly = Assembly.GetExecutingAssembly();
|
||||
var packagePath = UnityEditor.PackageManager.PackageInfo.FindForAssembly(execAssembly).assetPath;
|
||||
var buildReport = BuildPipeline.BuildPlayer(
|
||||
new[] { Path.Combine(packagePath, DefaultBuildScenePath) },
|
||||
Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds", nameof(BuildTests)),
|
||||
EditorUserBuildSettings.activeBuildTarget,
|
||||
BuildOptions.None
|
||||
);
|
||||
Assert.AreEqual(BuildResult.Succeeded, buildReport.summary.result);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Build/BuildTests.cs.meta
Normal file
11
Tests/Editor/Build/BuildTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efb549c2173d5478e93a71fbd05c0392
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
116
Tests/Editor/IndexAllocatorTests.cs
Normal file
116
Tests/Editor/IndexAllocatorTests.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class FixedAllocatorTest
|
||||
{
|
||||
[Test]
|
||||
public void SimpleTest()
|
||||
{
|
||||
int pos;
|
||||
|
||||
var allocator = new IndexAllocator(20000, 200);
|
||||
allocator.DebugDisplay();
|
||||
|
||||
// allocate 20 bytes
|
||||
Assert.IsTrue(allocator.Allocate(0, 20, out pos));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// can't ask for negative amount of memory
|
||||
Assert.IsFalse(allocator.Allocate(1, -20, out pos));
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// can't ask for deallocation of negative index
|
||||
Assert.IsFalse(allocator.Deallocate(-1));
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// can't ask for the same index twice
|
||||
Assert.IsFalse(allocator.Allocate(0, 20, out pos));
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// allocate another 20 bytes
|
||||
Assert.IsTrue(allocator.Allocate(1, 20, out pos));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// allocate a third 20 bytes
|
||||
Assert.IsTrue(allocator.Allocate(2, 20, out pos));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// deallocate 0
|
||||
Assert.IsTrue(allocator.Deallocate(0));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// deallocate 1
|
||||
allocator.Deallocate(1);
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// deallocate 2
|
||||
allocator.Deallocate(2);
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// allocate 50 bytes
|
||||
Assert.IsTrue(allocator.Allocate(0, 50, out pos));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// allocate another 50 bytes
|
||||
Assert.IsTrue(allocator.Allocate(1, 50, out pos));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// allocate a third 50 bytes
|
||||
Assert.IsTrue(allocator.Allocate(2, 50, out pos));
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// deallocate 1, a block in the middle this time
|
||||
allocator.Deallocate(1);
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
|
||||
// allocate a smaller one in its place
|
||||
allocator.Allocate(1, 25, out pos);
|
||||
allocator.DebugDisplay();
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReuseTest()
|
||||
{
|
||||
int count = 100;
|
||||
bool[] used = new bool[count];
|
||||
int[] pos = new int[count];
|
||||
int iterations = 10000;
|
||||
|
||||
var allocator = new IndexAllocator(20000, 200);
|
||||
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
int index = Random.Range(0, count);
|
||||
if (used[index])
|
||||
{
|
||||
Assert.IsTrue(allocator.Deallocate(index));
|
||||
used[index] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int position;
|
||||
int length = 10 * Random.Range(1, 10);
|
||||
Assert.IsTrue(allocator.Allocate(index, length, out position));
|
||||
pos[index] = position;
|
||||
used[index] = true;
|
||||
}
|
||||
Assert.IsTrue(allocator.Verify());
|
||||
}
|
||||
allocator.DebugDisplay();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/IndexAllocatorTests.cs.meta
Normal file
11
Tests/Editor/IndexAllocatorTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85ac488e1432d49668c711fa625a0743
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
359
Tests/Editor/InterpolatorTests.cs
Normal file
359
Tests/Editor/InterpolatorTests.cs
Normal file
@@ -0,0 +1,359 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class InterpolatorTests
|
||||
{
|
||||
private const float k_Precision = 0.00000001f;
|
||||
private const int k_MockTickRate = 1;
|
||||
|
||||
private NetworkTime T(float time, uint tickRate = k_MockTickRate)
|
||||
{
|
||||
return new NetworkTime(tickRate, timeSec: time);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReset()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 100f);
|
||||
interpolator.AddMeasurement(5, 1.0f);
|
||||
var initVal = interpolator.Update(10f, serverTime.Time, serverTime.TimeTicksAgo(1).Time); // big value
|
||||
Assert.That(initVal, Is.EqualTo(5f));
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(5f));
|
||||
|
||||
interpolator.ResetTo(100f, serverTime.Time);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(100f));
|
||||
var val = interpolator.Update(1f, serverTime.Time, serverTime.TimeTicksAgo(1).Time);
|
||||
Assert.That(val, Is.EqualTo(100f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NormalUsage()
|
||||
{
|
||||
// Testing float instead of Vector3. The only difference with Vector3 is the lerp method used.
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0f));
|
||||
|
||||
interpolator.AddMeasurement(0f, 1.0f);
|
||||
interpolator.AddMeasurement(1f, 2.0f);
|
||||
|
||||
// too small update, nothing happens, doesn't consume from buffer yet
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0.01d); // t = 0.1d
|
||||
interpolator.Update(.01f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0f));
|
||||
|
||||
// consume first measurement, still can't interpolate with just one tick consumed
|
||||
serverTime += 1.0d; // t = 1.01
|
||||
interpolator.Update(1.0f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0f));
|
||||
|
||||
// consume second measurement, start to interpolate
|
||||
serverTime += 1.0d; // t = 2.01
|
||||
var valueFromUpdate = interpolator.Update(1.0f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0.01f).Within(k_Precision));
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0.01f).Within(k_Precision)); // test a second time, to make sure the get doesn't update the value
|
||||
Assert.That(valueFromUpdate, Is.EqualTo(interpolator.GetInterpolatedValue()).Within(k_Precision));
|
||||
|
||||
// continue interpolation
|
||||
serverTime = new NetworkTime(k_MockTickRate, 2.5d); // t = 2.5d
|
||||
interpolator.Update(2.5f - 2.01f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0.5f).Within(k_Precision));
|
||||
|
||||
// check when reaching end
|
||||
serverTime += 0.5d; // t = 3
|
||||
interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1f).Within(k_Precision));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Out of order or 'ACB' problem
|
||||
/// Given two measurements have already arrived A and C, if a new measurement B arrives, the interpolation shouldn't go to B, but continue
|
||||
/// to C.
|
||||
/// Adding B should be ignored if interpolation is already interpolating between A and C
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OutOfOrderShouldStillWork()
|
||||
{
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0.01d);
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
double timeStep = 0.5d;
|
||||
|
||||
interpolator.AddMeasurement(0f, 0d);
|
||||
interpolator.AddMeasurement(2f, 2d);
|
||||
|
||||
serverTime = new NetworkTime(k_MockTickRate, 1.5d);
|
||||
interpolator.Update(1.5f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(0f).Within(k_Precision));
|
||||
|
||||
serverTime += timeStep; // t = 2.0
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1f).Within(k_Precision));
|
||||
|
||||
serverTime += timeStep; // t = 2.5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1.5f).Within(k_Precision));
|
||||
|
||||
// makes sure that interpolation still continues in right direction
|
||||
interpolator.AddMeasurement(1, 1d);
|
||||
|
||||
serverTime += timeStep; // t = 3
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(2f).Within(k_Precision));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MessageLoss()
|
||||
{
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0.01d);
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
double timeStep = 0.5d;
|
||||
|
||||
interpolator.AddMeasurement(1f, 1d);
|
||||
interpolator.AddMeasurement(2f, 2d);
|
||||
// message time=3 was lost
|
||||
interpolator.AddMeasurement(4f, 4d);
|
||||
interpolator.AddMeasurement(5f, 5d);
|
||||
// message time=6 was lost
|
||||
interpolator.AddMeasurement(100f, 7d); // high value to produce a misprediction
|
||||
|
||||
// first value teleports interpolator
|
||||
serverTime = new NetworkTime(k_MockTickRate, 1d);
|
||||
interpolator.Update(1f, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1f));
|
||||
|
||||
// nothing happens, not ready to consume second value yet
|
||||
serverTime += timeStep; // t = 1.5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1f));
|
||||
|
||||
// beginning of interpolation, second value consumed, currently at start
|
||||
serverTime += timeStep; // t = 2
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1f));
|
||||
|
||||
// interpolation starts
|
||||
serverTime += timeStep; // t = 2.5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(1.5f));
|
||||
|
||||
serverTime += timeStep; // t = 3
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(2f));
|
||||
|
||||
// extrapolating to 2.5
|
||||
serverTime += timeStep; // t = 3.5d
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(2.5f));
|
||||
|
||||
// next value skips to where it was supposed to be once buffer time is showing the next value
|
||||
serverTime += timeStep; // t = 4
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(3f));
|
||||
|
||||
// interpolation continues as expected
|
||||
serverTime += timeStep; // t = 4.5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(3.5f));
|
||||
|
||||
serverTime += timeStep; // t = 5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(4f));
|
||||
|
||||
// lost time=6, extrapolating
|
||||
serverTime += timeStep; // t = 5.5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(4.5f));
|
||||
|
||||
serverTime += timeStep; // t = 6.0
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(5f));
|
||||
|
||||
// misprediction
|
||||
serverTime += timeStep; // t = 6.5
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.EqualTo(5.5f));
|
||||
|
||||
// lerp to right value
|
||||
serverTime += timeStep; // t = 7.0
|
||||
interpolator.Update((float)timeStep, serverTime);
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.GreaterThan(6.0f));
|
||||
Assert.That(interpolator.GetInterpolatedValue(), Is.LessThanOrEqualTo(100f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddFirstMeasurement()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0d);
|
||||
interpolator.AddMeasurement(2f, 1d);
|
||||
interpolator.AddMeasurement(3f, 2d);
|
||||
|
||||
serverTime += 1d; // t = 1
|
||||
var interpolatedValue = interpolator.Update(1f, serverTime);
|
||||
// when consuming only one measurement and it's the first one consumed, teleport to it
|
||||
Assert.That(interpolatedValue, Is.EqualTo(2f));
|
||||
|
||||
// then interpolation should work as usual
|
||||
serverTime += 1d; // t = 2
|
||||
interpolatedValue = interpolator.Update(1f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(2f));
|
||||
|
||||
serverTime += 0.5d; // t = 2.5
|
||||
interpolatedValue = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(2.5f));
|
||||
|
||||
serverTime += 0.5d; // t = 3
|
||||
interpolatedValue = interpolator.Update(.5f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(3f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JumpToEachValueIfDeltaTimeTooBig()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0d);
|
||||
interpolator.AddMeasurement(2f, 1d);
|
||||
interpolator.AddMeasurement(3f, 2d);
|
||||
|
||||
serverTime += 1d; // t = 1
|
||||
var interpolatedValue = interpolator.Update(1f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(2f));
|
||||
|
||||
// big deltaTime, jumping to latest value
|
||||
serverTime += 9f; // t = 10
|
||||
interpolatedValue = interpolator.Update(8f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JumpToLastValueFromStart()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0d);
|
||||
|
||||
serverTime += 1d; // t = 1
|
||||
interpolator.AddMeasurement(1f, serverTime.Time);
|
||||
serverTime += 1d; // t = 2
|
||||
interpolator.AddMeasurement(2f, serverTime.Time);
|
||||
serverTime += 1d; // t = 3
|
||||
interpolator.AddMeasurement(3f, serverTime.Time);
|
||||
|
||||
// big time jump
|
||||
serverTime += 7d; // t = 10
|
||||
var interpolatedValue = interpolator.Update(10f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(3f));
|
||||
|
||||
// interpolation continues as normal
|
||||
serverTime = new NetworkTime(k_MockTickRate, 11d); // t = 11
|
||||
interpolator.AddMeasurement(11f, serverTime.Time); // out of order
|
||||
|
||||
serverTime = new NetworkTime(k_MockTickRate, 10.5d); // t = 10.5
|
||||
interpolatedValue = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(3f));
|
||||
|
||||
serverTime += 0.5d; // t = 11
|
||||
interpolatedValue = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(10f));
|
||||
|
||||
serverTime += 0.5d; // t = 11.5
|
||||
interpolatedValue = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(10.5f));
|
||||
|
||||
serverTime += 0.5d; // t = 12
|
||||
interpolatedValue = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(11f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBufferSizeLimit()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
// set first value
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0d);
|
||||
serverTime += 1.0d; // t = 1
|
||||
interpolator.AddMeasurement(-1f, serverTime.Time);
|
||||
interpolator.Update(1f, serverTime);
|
||||
|
||||
// max + 1
|
||||
serverTime += 1.0d; // t = 2
|
||||
interpolator.AddMeasurement(2, serverTime.Time); // +1, this should trigger a burst and teleport to last value
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
interpolator.AddMeasurement(i + 3, i + 3d);
|
||||
}
|
||||
|
||||
// client was paused for a while, some time has past, we just got a burst of values from the server that teleported us to the last value received
|
||||
serverTime = new NetworkTime(k_MockTickRate, 102d);
|
||||
var interpolatedValue = interpolator.Update(101f, serverTime);
|
||||
Assert.That(interpolatedValue, Is.EqualTo(102));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUpdatingInterpolatorWithNoData()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0.0d);
|
||||
// invalid case, this is undefined behaviour
|
||||
Assert.Throws<InvalidOperationException>(() => interpolator.Update(1f, serverTime));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDuplicatedValues()
|
||||
{
|
||||
var interpolator = new BufferedLinearInterpolatorFloat();
|
||||
|
||||
var serverTime = new NetworkTime(k_MockTickRate, 0.0d);
|
||||
|
||||
serverTime += 1d; // t = 1
|
||||
interpolator.AddMeasurement(1f, serverTime.Time);
|
||||
serverTime += 1d; // t = 2
|
||||
interpolator.AddMeasurement(2f, serverTime.Time);
|
||||
interpolator.AddMeasurement(2f, serverTime.Time);
|
||||
|
||||
// empty interpolator teleports to initial value
|
||||
serverTime = new NetworkTime(k_MockTickRate, 0.0d);
|
||||
serverTime += 1d; // t = 1
|
||||
var interp = interpolator.Update(1f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(1f));
|
||||
|
||||
// consume value, start interp, currently at start value
|
||||
serverTime += 1d; // t = 2
|
||||
interp = interpolator.Update(1f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(1f));
|
||||
|
||||
// interp
|
||||
serverTime += 0.5d; // t = 2.5
|
||||
interp = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(1.5f));
|
||||
|
||||
// reach end
|
||||
serverTime += 0.5d; // t = 3
|
||||
interp = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(2f));
|
||||
|
||||
// with unclamped interpolation, we continue mispredicting since the two last values are actually treated as the same. Therefore we're not stopping at "2"
|
||||
serverTime += 0.5d; // t = 3.5
|
||||
interp = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(2.5f));
|
||||
|
||||
serverTime += 0.5d; // t = 4
|
||||
interp = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(3f));
|
||||
|
||||
// we add a measurement with an updated time
|
||||
var pastServerTime = new NetworkTime(k_MockTickRate, 3.0d);
|
||||
interpolator.AddMeasurement(2f, pastServerTime.Time);
|
||||
|
||||
interp = interpolator.Update(0.5f, serverTime);
|
||||
Assert.That(interp, Is.EqualTo(2f));
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/InterpolatorTests.cs.meta
Normal file
11
Tests/Editor/InterpolatorTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5cfbc170161c4e95ac6124ee43068b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Tests/Editor/Messaging.meta
Normal file
3
Tests/Editor/Messaging.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55531000b0344935b665541f089df60e
|
||||
timeCreated: 1630354914
|
||||
216
Tests/Editor/Messaging/MessageReceivingTests.cs
Normal file
216
Tests/Editor/Messaging/MessageReceivingTests.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class MessageReceivingTests
|
||||
{
|
||||
private struct TestMessage : INetworkMessage
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public static bool Deserialized;
|
||||
public static List<TestMessage> DeserializedValues = new List<TestMessage>();
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
Deserialized = true;
|
||||
reader.ReadValueSafe(out TestMessage value);
|
||||
DeserializedValues.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMessageProvider : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessage),
|
||||
Handler = TestMessage.Receive
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private MessagingSystem m_MessagingSystem;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
TestMessage.Deserialized = false;
|
||||
TestMessage.DeserializedValues.Clear();
|
||||
|
||||
m_MessagingSystem = new MessagingSystem(new NopMessageSender(), this, new TestMessageProvider());
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
m_MessagingSystem.Dispose();
|
||||
}
|
||||
|
||||
private TestMessage GetMessage()
|
||||
{
|
||||
var random = new Random();
|
||||
return new TestMessage
|
||||
{
|
||||
A = random.Next(),
|
||||
B = random.Next(),
|
||||
C = random.Next(),
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenHandlingAMessage_ReceiveMethodIsCalled()
|
||||
{
|
||||
var messageHeader = new MessageHeader
|
||||
{
|
||||
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
||||
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
||||
};
|
||||
var message = GetMessage();
|
||||
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(message));
|
||||
writer.WriteValue(message);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
m_MessagingSystem.HandleMessage(messageHeader, reader, 0, 0);
|
||||
Assert.IsTrue(TestMessage.Deserialized);
|
||||
Assert.AreEqual(1, TestMessage.DeserializedValues.Count);
|
||||
Assert.AreEqual(message, TestMessage.DeserializedValues[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenHandlingIncomingData_ReceiveIsNotCalledBeforeProcessingIncomingMessageQueue()
|
||||
{
|
||||
var batchHeader = new BatchHeader
|
||||
{
|
||||
BatchSize = 1
|
||||
};
|
||||
var messageHeader = new MessageHeader
|
||||
{
|
||||
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
||||
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
||||
};
|
||||
var message = GetMessage();
|
||||
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(batchHeader) +
|
||||
FastBufferWriter.GetWriteSize(messageHeader) +
|
||||
FastBufferWriter.GetWriteSize(message));
|
||||
writer.WriteValue(batchHeader);
|
||||
writer.WriteValue(messageHeader);
|
||||
writer.WriteValue(message);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
m_MessagingSystem.HandleIncomingData(0, new ArraySegment<byte>(writer.ToArray()), 0);
|
||||
Assert.IsFalse(TestMessage.Deserialized);
|
||||
Assert.IsEmpty(TestMessage.DeserializedValues); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenReceivingAMessageAndProcessingMessageQueue_ReceiveMethodIsCalled()
|
||||
{
|
||||
var batchHeader = new BatchHeader
|
||||
{
|
||||
BatchSize = 1
|
||||
};
|
||||
var messageHeader = new MessageHeader
|
||||
{
|
||||
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
||||
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
||||
};
|
||||
var message = GetMessage();
|
||||
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(batchHeader) +
|
||||
FastBufferWriter.GetWriteSize(messageHeader) +
|
||||
FastBufferWriter.GetWriteSize(message));
|
||||
writer.WriteValue(batchHeader);
|
||||
writer.WriteValue(messageHeader);
|
||||
writer.WriteValue(message);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
m_MessagingSystem.HandleIncomingData(0, new ArraySegment<byte>(writer.ToArray()), 0);
|
||||
m_MessagingSystem.ProcessIncomingMessageQueue();
|
||||
Assert.IsTrue(TestMessage.Deserialized);
|
||||
Assert.AreEqual(1, TestMessage.DeserializedValues.Count);
|
||||
Assert.AreEqual(message, TestMessage.DeserializedValues[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenReceivingMultipleMessagesAndProcessingMessageQueue_ReceiveMethodIsCalledMultipleTimes()
|
||||
{
|
||||
var batchHeader = new BatchHeader
|
||||
{
|
||||
BatchSize = 2
|
||||
};
|
||||
var messageHeader = new MessageHeader
|
||||
{
|
||||
MessageSize = (ushort)UnsafeUtility.SizeOf<TestMessage>(),
|
||||
MessageType = m_MessagingSystem.GetMessageType(typeof(TestMessage)),
|
||||
};
|
||||
var message = GetMessage();
|
||||
var message2 = GetMessage();
|
||||
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.TryBeginWrite(FastBufferWriter.GetWriteSize(batchHeader) +
|
||||
FastBufferWriter.GetWriteSize(messageHeader) * 2 +
|
||||
FastBufferWriter.GetWriteSize(message) * 2);
|
||||
writer.WriteValue(batchHeader);
|
||||
writer.WriteValue(messageHeader);
|
||||
writer.WriteValue(message);
|
||||
writer.WriteValue(messageHeader);
|
||||
writer.WriteValue(message2);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
m_MessagingSystem.HandleIncomingData(0, new ArraySegment<byte>(writer.ToArray()), 0);
|
||||
Assert.IsFalse(TestMessage.Deserialized);
|
||||
Assert.IsEmpty(TestMessage.DeserializedValues);
|
||||
|
||||
m_MessagingSystem.ProcessIncomingMessageQueue();
|
||||
Assert.IsTrue(TestMessage.Deserialized);
|
||||
Assert.AreEqual(2, TestMessage.DeserializedValues.Count);
|
||||
Assert.AreEqual(message, TestMessage.DeserializedValues[0]);
|
||||
Assert.AreEqual(message2, TestMessage.DeserializedValues[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Messaging/MessageReceivingTests.cs.meta
Normal file
11
Tests/Editor/Messaging/MessageReceivingTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbc8fb6cf75f52d46a5d74971ce4b240
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
179
Tests/Editor/Messaging/MessageRegistrationTests.cs
Normal file
179
Tests/Editor/Messaging/MessageRegistrationTests.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class MessageRegistrationTests
|
||||
{
|
||||
|
||||
private struct TestMessageOne : INetworkMessage
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private struct TestMessageTwo : INetworkMessage
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
private class TestMessageProviderOne : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageOne),
|
||||
Handler = TestMessageOne.Receive
|
||||
},
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageTwo),
|
||||
Handler = TestMessageTwo.Receive
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private struct TestMessageThree : INetworkMessage
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
private class TestMessageProviderTwo : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageThree),
|
||||
Handler = TestMessageThree.Receive
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private struct TestMessageFour : INetworkMessage
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
writer.WriteValue(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
private class TestMessageProviderThree : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessageFour),
|
||||
Handler = TestMessageFour.Receive
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCreatingMessageSystem_OnlyProvidedTypesAreRegistered()
|
||||
{
|
||||
var sender = new NopMessageSender();
|
||||
|
||||
var systemOne = new MessagingSystem(sender, null, new TestMessageProviderOne());
|
||||
var systemTwo = new MessagingSystem(sender, null, new TestMessageProviderTwo());
|
||||
var systemThree = new MessagingSystem(sender, null, new TestMessageProviderThree());
|
||||
|
||||
using (systemOne)
|
||||
using (systemTwo)
|
||||
using (systemThree)
|
||||
{
|
||||
Assert.AreEqual(2, systemOne.MessageHandlerCount);
|
||||
Assert.AreEqual(1, systemTwo.MessageHandlerCount);
|
||||
Assert.AreEqual(1, systemThree.MessageHandlerCount);
|
||||
|
||||
Assert.Contains(typeof(TestMessageOne), systemOne.MessageTypes);
|
||||
Assert.Contains(typeof(TestMessageTwo), systemOne.MessageTypes);
|
||||
Assert.Contains(typeof(TestMessageThree), systemTwo.MessageTypes);
|
||||
Assert.Contains(typeof(TestMessageFour), systemThree.MessageTypes);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCreatingMessageSystem_BoundTypeMessageHandlersAreRegistered()
|
||||
{
|
||||
var sender = new NopMessageSender();
|
||||
|
||||
var systemOne = new MessagingSystem(sender, null, new TestMessageProviderOne());
|
||||
var systemTwo = new MessagingSystem(sender, null, new TestMessageProviderTwo());
|
||||
var systemThree = new MessagingSystem(sender, null, new TestMessageProviderThree());
|
||||
|
||||
using (systemOne)
|
||||
using (systemTwo)
|
||||
using (systemThree)
|
||||
{
|
||||
MessagingSystem.MessageHandler handlerOne = TestMessageOne.Receive;
|
||||
MessagingSystem.MessageHandler handlerTwo = TestMessageTwo.Receive;
|
||||
MessagingSystem.MessageHandler handlerThree = TestMessageThree.Receive;
|
||||
MessagingSystem.MessageHandler handlerFour = TestMessageFour.Receive;
|
||||
|
||||
var foundHandlerOne = systemOne.MessageHandlers[systemOne.GetMessageType(typeof(TestMessageOne))];
|
||||
|
||||
Assert.AreEqual(handlerOne,
|
||||
systemOne.MessageHandlers[systemOne.GetMessageType(typeof(TestMessageOne))]);
|
||||
Assert.AreEqual(handlerTwo,
|
||||
systemOne.MessageHandlers[systemOne.GetMessageType(typeof(TestMessageTwo))]);
|
||||
Assert.AreEqual(handlerThree,
|
||||
systemTwo.MessageHandlers[systemTwo.GetMessageType(typeof(TestMessageThree))]);
|
||||
Assert.AreEqual(handlerFour,
|
||||
systemThree.MessageHandlers[systemThree.GetMessageType(typeof(TestMessageFour))]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Messaging/MessageRegistrationTests.cs.meta
Normal file
11
Tests/Editor/Messaging/MessageRegistrationTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03e7cc2b6f0c5c540a529429f48529f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
223
Tests/Editor/Messaging/MessageSendingTests.cs
Normal file
223
Tests/Editor/Messaging/MessageSendingTests.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class MessageSendingTests
|
||||
{
|
||||
private struct TestMessage : INetworkMessage
|
||||
{
|
||||
public int A;
|
||||
public int B;
|
||||
public int C;
|
||||
public static bool Serialized;
|
||||
|
||||
public void Serialize(FastBufferWriter writer)
|
||||
{
|
||||
Serialized = true;
|
||||
writer.WriteValueSafe(this);
|
||||
}
|
||||
|
||||
public static void Receive(FastBufferReader reader, in NetworkContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMessageSender : IMessageSender
|
||||
{
|
||||
public List<byte[]> MessageQueue = new List<byte[]>();
|
||||
|
||||
public void Send(ulong clientId, NetworkDelivery delivery, FastBufferWriter batchData)
|
||||
{
|
||||
MessageQueue.Add(batchData.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMessageProvider : IMessageProvider
|
||||
{
|
||||
public List<MessagingSystem.MessageWithHandler> GetMessages()
|
||||
{
|
||||
return new List<MessagingSystem.MessageWithHandler>
|
||||
{
|
||||
new MessagingSystem.MessageWithHandler
|
||||
{
|
||||
MessageType = typeof(TestMessage),
|
||||
Handler = TestMessage.Receive
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private TestMessageSender m_MessageSender;
|
||||
private MessagingSystem m_MessagingSystem;
|
||||
private ulong[] m_Clients = { 0 };
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
TestMessage.Serialized = false;
|
||||
|
||||
m_MessageSender = new TestMessageSender();
|
||||
m_MessagingSystem = new MessagingSystem(m_MessageSender, this, new TestMessageProvider());
|
||||
m_MessagingSystem.ClientConnected(0);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
m_MessagingSystem.Dispose();
|
||||
}
|
||||
|
||||
private TestMessage GetMessage()
|
||||
{
|
||||
var random = new Random();
|
||||
return new TestMessage
|
||||
{
|
||||
A = random.Next(),
|
||||
B = random.Next(),
|
||||
C = random.Next(),
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingMessage_SerializeIsCalled()
|
||||
{
|
||||
var message = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
Assert.IsTrue(TestMessage.Serialized);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingMessage_NothingIsSentBeforeProcessingSendQueue()
|
||||
{
|
||||
var message = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
Assert.IsEmpty(m_MessageSender.MessageQueue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenProcessingSendQueue_MessageIsSent()
|
||||
{
|
||||
var message = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(1, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingMultipleMessages_MessagesAreBatched()
|
||||
{
|
||||
var message = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(1, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenNotExceedingBatchSize_NewBatchesAreNotCreated()
|
||||
{
|
||||
var message = GetMessage();
|
||||
var size = UnsafeUtility.SizeOf<TestMessage>() + UnsafeUtility.SizeOf<MessageHeader>();
|
||||
for (var i = 0; i < 1300 / size; ++i)
|
||||
{
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
}
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(1, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenExceedingBatchSize_NewBatchesAreCreated()
|
||||
{
|
||||
var message = GetMessage();
|
||||
var size = UnsafeUtility.SizeOf<TestMessage>() + UnsafeUtility.SizeOf<MessageHeader>();
|
||||
for (var i = 0; i < (1300 / size) + 1; ++i)
|
||||
{
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
}
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(2, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenExceedingMTUSizeWithFragmentedDelivery_NewBatchesAreNotCreated()
|
||||
{
|
||||
var message = GetMessage();
|
||||
var size = UnsafeUtility.SizeOf<TestMessage>() + UnsafeUtility.SizeOf<MessageHeader>();
|
||||
for (var i = 0; i < (1300 / size) + 1; ++i)
|
||||
{
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.ReliableFragmentedSequenced, m_Clients);
|
||||
}
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(1, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSwitchingDelivery_NewBatchesAreCreated()
|
||||
{
|
||||
var message = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Unreliable, m_Clients);
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(2, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSwitchingChannel_NewBatchesAreNotCreated()
|
||||
{
|
||||
var message = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
Assert.AreEqual(1, m_MessageSender.MessageQueue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingMessaged_SentDataIsCorrect()
|
||||
{
|
||||
var message = GetMessage();
|
||||
var message2 = GetMessage();
|
||||
m_MessagingSystem.SendMessage(message, NetworkDelivery.Reliable, m_Clients);
|
||||
m_MessagingSystem.SendMessage(message2, NetworkDelivery.Reliable, m_Clients);
|
||||
|
||||
m_MessagingSystem.ProcessSendQueues();
|
||||
var reader = new FastBufferReader(m_MessageSender.MessageQueue[0], Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
reader.TryBeginRead(
|
||||
FastBufferWriter.GetWriteSize<BatchHeader>() +
|
||||
FastBufferWriter.GetWriteSize<MessageHeader>() * 2 +
|
||||
FastBufferWriter.GetWriteSize<TestMessage>() * 2
|
||||
);
|
||||
reader.ReadValue(out BatchHeader header);
|
||||
Assert.AreEqual(2, header.BatchSize);
|
||||
|
||||
reader.ReadValue(out MessageHeader messageHeader);
|
||||
Assert.AreEqual(m_MessagingSystem.GetMessageType(typeof(TestMessage)), messageHeader.MessageType);
|
||||
Assert.AreEqual(UnsafeUtility.SizeOf<TestMessage>(), messageHeader.MessageSize);
|
||||
reader.ReadValue(out TestMessage receivedMessage);
|
||||
Assert.AreEqual(message, receivedMessage);
|
||||
|
||||
reader.ReadValue(out MessageHeader messageHeader2);
|
||||
Assert.AreEqual(m_MessagingSystem.GetMessageType(typeof(TestMessage)), messageHeader2.MessageType);
|
||||
Assert.AreEqual(UnsafeUtility.SizeOf<TestMessage>(), messageHeader2.MessageSize);
|
||||
reader.ReadValue(out TestMessage receivedMessage2);
|
||||
Assert.AreEqual(message2, receivedMessage2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Messaging/MessageSendingTests.cs.meta
Normal file
11
Tests/Editor/Messaging/MessageSendingTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea2fc218c5e07c54795fc9bed4a6a62c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Tests/Editor/Messaging/NopMessageSender.cs
Normal file
9
Tests/Editor/Messaging/NopMessageSender.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
internal class NopMessageSender : IMessageSender
|
||||
{
|
||||
public void Send(ulong clientId, NetworkDelivery delivery, FastBufferWriter batchData)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Messaging/NopMessageSender.cs.meta
Normal file
11
Tests/Editor/Messaging/NopMessageSender.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 817c58672ba39a74da57082ed176956e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Tests/Editor/Metrics.meta
Normal file
3
Tests/Editor/Metrics.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87ddfad8823c4fe192fff56b7acc241b
|
||||
timeCreated: 1629386688
|
||||
41
Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs
Normal file
41
Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
#if MULTIPLAYER_TOOLS
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using Unity.Multiplayer.Tools.MetricTypes;
|
||||
using Unity.Multiplayer.Tools.NetStats;
|
||||
|
||||
namespace Unity.Netcode.EditorTests.Metrics
|
||||
{
|
||||
public class NetworkMetricsRegistrationTests
|
||||
{
|
||||
static Type[] s_MetricTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(x => x.GetTypes())
|
||||
.Where(x => x.GetInterfaces().Contains(typeof(INetworkMetricEvent)))
|
||||
.ToArray();
|
||||
|
||||
[TestCaseSource(nameof(s_MetricTypes))][Ignore("Disable test while we reevaluate the assumption that INetworkMetricEvent interfaces must be reported from MLAPI.")]
|
||||
public void ValidateThatAllMetricTypesAreRegistered(Type metricType)
|
||||
{
|
||||
var dispatcher = new NetworkMetrics().Dispatcher as MetricDispatcher;
|
||||
Assert.NotNull(dispatcher);
|
||||
|
||||
var collection = typeof(MetricDispatcher)
|
||||
.GetField("m_Collection", BindingFlags.NonPublic | BindingFlags.Instance)?
|
||||
.GetValue(dispatcher) as MetricCollection;
|
||||
Assert.NotNull(collection);
|
||||
|
||||
Assert.That(
|
||||
collection.Metrics.OfType<IEventMetric>(),
|
||||
Has.Exactly(2).Matches<IEventMetric>(
|
||||
eventMetric =>
|
||||
{
|
||||
var eventType = eventMetric.GetType().GetGenericArguments()?.FirstOrDefault();
|
||||
return eventType == metricType;
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
11
Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs.meta
Normal file
11
Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af741f5e3d4f5544eaa68bb9bcaf54c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
79
Tests/Editor/NetworkBehaviourTests.cs
Normal file
79
Tests/Editor/NetworkBehaviourTests.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class NetworkBehaviourTests
|
||||
{
|
||||
[Test]
|
||||
public void HasNetworkObjectTest()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(HasNetworkObjectTest));
|
||||
var networkBehaviour = gameObject.AddComponent<EmptyNetworkBehaviour>();
|
||||
|
||||
Assert.That(networkBehaviour.HasNetworkObject, Is.False);
|
||||
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
|
||||
Assert.That(networkBehaviour.HasNetworkObject, Is.True);
|
||||
|
||||
Object.DestroyImmediate(networkObject);
|
||||
|
||||
Assert.That(networkBehaviour.HasNetworkObject, Is.False);
|
||||
|
||||
// Cleanup
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AccessNetworkObjectTest()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(AccessNetworkObjectTest));
|
||||
var networkBehaviour = gameObject.AddComponent<EmptyNetworkBehaviour>();
|
||||
|
||||
Assert.That(networkBehaviour.NetworkObject, Is.Null);
|
||||
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
|
||||
Assert.That(networkBehaviour.NetworkObject, Is.EqualTo(networkObject));
|
||||
|
||||
Object.DestroyImmediate(networkObject);
|
||||
|
||||
Assert.That(networkBehaviour.NetworkObject, Is.Null);
|
||||
|
||||
// Cleanup
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GivenClassDerivesFromNetworkBehaviour_GetTypeNameReturnsCorrectValue()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(GivenClassDerivesFromNetworkBehaviour_GetTypeNameReturnsCorrectValue));
|
||||
var networkBehaviour = gameObject.AddComponent<EmptyNetworkBehaviour>();
|
||||
|
||||
Assert.AreEqual(nameof(EmptyNetworkBehaviour), networkBehaviour.__getTypeName());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GivenClassDerivesFromNetworkBehaviourDerivedClass_GetTypeNameReturnsCorrectValue()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(GivenClassDerivesFromNetworkBehaviourDerivedClass_GetTypeNameReturnsCorrectValue));
|
||||
var networkBehaviour = gameObject.AddComponent<DerivedNetworkBehaviour>();
|
||||
|
||||
Assert.AreEqual(nameof(DerivedNetworkBehaviour), networkBehaviour.__getTypeName());
|
||||
}
|
||||
|
||||
// Note: in order to repro https://github.com/Unity-Technologies/com.unity.netcode.gameobjects/issues/1078
|
||||
// this child class must be defined before its parent to assure it is processed first by ILPP
|
||||
public class DerivedNetworkBehaviour : EmptyNetworkBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class EmptyNetworkBehaviour : NetworkBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/NetworkBehaviourTests.cs.meta
Normal file
11
Tests/Editor/NetworkBehaviourTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73e18571452c102e4b209671741f3b51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Tests/Editor/NetworkManagerCustomMessageManagerTests.cs
Normal file
30
Tests/Editor/NetworkManagerCustomMessageManagerTests.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class NetworkManagerCustomMessageManagerTests
|
||||
{
|
||||
[Test]
|
||||
public void CustomMessageManagerAssigned()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(CustomMessageManagerAssigned));
|
||||
var networkManager = gameObject.AddComponent<NetworkManager>();
|
||||
var transport = gameObject.AddComponent<DummyTransport>();
|
||||
|
||||
networkManager.NetworkConfig = new NetworkConfig();
|
||||
// Set dummy transport that does nothing
|
||||
networkManager.NetworkConfig.NetworkTransport = transport;
|
||||
|
||||
CustomMessagingManager preManager = networkManager.CustomMessagingManager;
|
||||
|
||||
// Start server to cause initialization
|
||||
networkManager.StartServer();
|
||||
|
||||
Debug.Assert(preManager == null);
|
||||
Debug.Assert(networkManager.CustomMessagingManager != null);
|
||||
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 315ffe39806441839400d21871d566a0
|
||||
timeCreated: 1618478909
|
||||
54
Tests/Editor/NetworkManagerMessageHandlerTests.cs
Normal file
54
Tests/Editor/NetworkManagerMessageHandlerTests.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using Unity.Netcode.Editor;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
// Should probably have one of these for more files? In the future we could use the SIPTransport?
|
||||
[DontShowInTransportDropdown]
|
||||
internal class DummyTransport : NetworkTransport
|
||||
{
|
||||
public override ulong ServerClientId { get; } = 0;
|
||||
public override void Send(ulong clientId, ArraySegment<byte> payload, NetworkDelivery networkDelivery)
|
||||
{
|
||||
}
|
||||
|
||||
public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment<byte> payload, out float receiveTime)
|
||||
{
|
||||
clientId = 0;
|
||||
payload = new ArraySegment<byte>();
|
||||
receiveTime = 0;
|
||||
return NetworkEvent.Nothing;
|
||||
}
|
||||
|
||||
public override bool StartClient()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool StartServer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void DisconnectRemoteClient(ulong clientId)
|
||||
{
|
||||
}
|
||||
|
||||
public override void DisconnectLocalClient()
|
||||
{
|
||||
}
|
||||
|
||||
public override ulong GetCurrentRtt(ulong clientId)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/NetworkManagerMessageHandlerTests.cs.meta
Normal file
11
Tests/Editor/NetworkManagerMessageHandlerTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 976ca592c7fa4bcb854203dfbadc0ad9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Tests/Editor/NetworkManagerSceneManagerTests.cs
Normal file
29
Tests/Editor/NetworkManagerSceneManagerTests.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class NetworkManagerSceneManagerTests
|
||||
{
|
||||
[Test]
|
||||
public void SceneManagerAssigned()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(SceneManagerAssigned));
|
||||
var networkManager = gameObject.AddComponent<NetworkManager>();
|
||||
var transport = gameObject.AddComponent<DummyTransport>();
|
||||
networkManager.NetworkConfig = new NetworkConfig();
|
||||
// Set dummy transport that does nothing
|
||||
networkManager.NetworkConfig.NetworkTransport = transport;
|
||||
|
||||
NetworkSceneManager preManager = networkManager.SceneManager;
|
||||
|
||||
// Start server to cause initialization process
|
||||
networkManager.StartServer();
|
||||
|
||||
Debug.Assert(preManager == null);
|
||||
Debug.Assert(networkManager.SceneManager != null);
|
||||
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Editor/NetworkManagerSceneManagerTests.cs.meta
Normal file
3
Tests/Editor/NetworkManagerSceneManagerTests.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9753bf4088484cbebee95d917699dec6
|
||||
timeCreated: 1618482634
|
||||
76
Tests/Editor/NetworkObjectTests.cs
Normal file
76
Tests/Editor/NetworkObjectTests.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class NetworkObjectTests
|
||||
{
|
||||
[Test]
|
||||
public void NetworkManagerOverrideTest()
|
||||
{
|
||||
// Create "bait"
|
||||
var singletonNetworkManager = new GameObject(nameof(NetworkManager)).AddComponent<NetworkManager>();
|
||||
singletonNetworkManager.SetSingleton();
|
||||
|
||||
// Create override
|
||||
var networkManager = new GameObject(nameof(NetworkManager)).AddComponent<NetworkManager>();
|
||||
|
||||
// NetworkObject
|
||||
var gameObject = new GameObject(nameof(NetworkManagerOverrideTest));
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
|
||||
// Set override
|
||||
networkObject.NetworkManagerOwner = networkManager;
|
||||
|
||||
Debug.Assert(networkObject.NetworkManager == networkManager);
|
||||
|
||||
Object.DestroyImmediate(singletonNetworkManager.gameObject);
|
||||
Object.DestroyImmediate(networkManager.gameObject);
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetBehaviourIndexNone()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(GetBehaviourIndexNone));
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
|
||||
// TODO: Maybe not hardcode message?
|
||||
LogAssert.Expect(LogType.Error, $"[Netcode] Behaviour index was out of bounds. Did you mess up the order of your {nameof(NetworkBehaviour)}s?");
|
||||
LogAssert.Expect(LogType.Error, $"[Netcode] Behaviour index was out of bounds. Did you mess up the order of your {nameof(NetworkBehaviour)}s?");
|
||||
LogAssert.Expect(LogType.Error, $"[Netcode] Behaviour index was out of bounds. Did you mess up the order of your {nameof(NetworkBehaviour)}s?");
|
||||
|
||||
Assert.That(networkObject.GetNetworkBehaviourAtOrderIndex(0), Is.Null);
|
||||
Assert.That(networkObject.GetNetworkBehaviourAtOrderIndex(1), Is.Null);
|
||||
Assert.That(networkObject.GetNetworkBehaviourAtOrderIndex(2), Is.Null);
|
||||
|
||||
// Cleanup
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetBehaviourIndexOne()
|
||||
{
|
||||
var gameObject = new GameObject(nameof(GetBehaviourIndexOne));
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
var networkBehaviour = gameObject.AddComponent<EmptyNetworkBehaviour>();
|
||||
|
||||
// TODO: Maybe not hardcode message?
|
||||
LogAssert.Expect(LogType.Error, $"[Netcode] Behaviour index was out of bounds. Did you mess up the order of your {nameof(NetworkBehaviour)}s?");
|
||||
LogAssert.Expect(LogType.Error, $"[Netcode] Behaviour index was out of bounds. Did you mess up the order of your {nameof(NetworkBehaviour)}s?");
|
||||
|
||||
Assert.That(networkObject.GetNetworkBehaviourAtOrderIndex(0), Is.EqualTo(networkBehaviour));
|
||||
Assert.That(networkObject.GetNetworkBehaviourAtOrderIndex(1), Is.Null);
|
||||
Assert.That(networkObject.GetNetworkBehaviourAtOrderIndex(2), Is.Null);
|
||||
|
||||
// Cleanup
|
||||
Object.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
public class EmptyNetworkBehaviour : NetworkBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/NetworkObjectTests.cs.meta
Normal file
11
Tests/Editor/NetworkObjectTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 542af4c12ffee14f59967bc8e41f5e9d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Tests/Editor/Serialization.meta
Normal file
3
Tests/Editor/Serialization.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e12c4be6e89f459aa2826abba8c8d301
|
||||
timeCreated: 1628799671
|
||||
587
Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs
Normal file
587
Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs
Normal file
@@ -0,0 +1,587 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace Unity.Netcode
|
||||
{
|
||||
public abstract class BaseFastBufferReaderWriterTest
|
||||
{
|
||||
|
||||
#region Test Types
|
||||
protected enum ByteEnum : byte
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum SByteEnum : sbyte
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum ShortEnum : short
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum UShortEnum : ushort
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum IntEnum : int
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum UIntEnum : uint
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum LongEnum : long
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
protected enum ULongEnum : ulong
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C
|
||||
};
|
||||
|
||||
protected struct TestStruct
|
||||
{
|
||||
public byte A;
|
||||
public short B;
|
||||
public ushort C;
|
||||
public int D;
|
||||
public uint E;
|
||||
public long F;
|
||||
public ulong G;
|
||||
public bool H;
|
||||
public char I;
|
||||
public float J;
|
||||
public double K;
|
||||
}
|
||||
|
||||
public enum WriteType
|
||||
{
|
||||
WriteDirect,
|
||||
WriteSafe
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
protected abstract void RunTypeTest<T>(T valueToTest) where T : unmanaged;
|
||||
|
||||
protected abstract void RunTypeTestSafe<T>(T valueToTest) where T : unmanaged;
|
||||
|
||||
protected abstract void RunTypeArrayTest<T>(T[] valueToTest) where T : unmanaged;
|
||||
|
||||
protected abstract void RunTypeArrayTestSafe<T>(T[] valueToTest) where T : unmanaged;
|
||||
|
||||
#region Helpers
|
||||
protected TestStruct GetTestStruct()
|
||||
{
|
||||
var random = new Random();
|
||||
|
||||
var testStruct = new TestStruct
|
||||
{
|
||||
A = (byte)random.Next(),
|
||||
B = (short)random.Next(),
|
||||
C = (ushort)random.Next(),
|
||||
D = (int)random.Next(),
|
||||
E = (uint)random.Next(),
|
||||
F = ((long)random.Next() << 32) + random.Next(),
|
||||
G = ((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
H = true,
|
||||
I = '\u263a',
|
||||
J = (float)random.NextDouble(),
|
||||
K = random.NextDouble(),
|
||||
};
|
||||
|
||||
return testStruct;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void BaseTypeTest(Type testType, WriteType writeType)
|
||||
{
|
||||
var random = new Random();
|
||||
|
||||
void RunTypeTestLocal<T>(T val, WriteType wt) where T : unmanaged
|
||||
{
|
||||
switch (wt)
|
||||
{
|
||||
case WriteType.WriteDirect:
|
||||
RunTypeTest(val);
|
||||
break;
|
||||
case WriteType.WriteSafe:
|
||||
RunTypeTestSafe(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (testType == typeof(byte))
|
||||
{
|
||||
RunTypeTestLocal((byte)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(sbyte))
|
||||
{
|
||||
RunTypeTestLocal((sbyte)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(short))
|
||||
{
|
||||
RunTypeTestLocal((short)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(ushort))
|
||||
{
|
||||
RunTypeTestLocal((ushort)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(int))
|
||||
{
|
||||
RunTypeTestLocal((int)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(uint))
|
||||
{
|
||||
RunTypeTestLocal((uint)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(long))
|
||||
{
|
||||
RunTypeTestLocal(((long)random.Next() << 32) + random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(ulong))
|
||||
{
|
||||
RunTypeTestLocal(((ulong)random.Next() << 32) + (ulong)random.Next(), writeType);
|
||||
}
|
||||
else if (testType == typeof(bool))
|
||||
{
|
||||
RunTypeTestLocal(true, writeType);
|
||||
}
|
||||
else if (testType == typeof(char))
|
||||
{
|
||||
RunTypeTestLocal('a', writeType);
|
||||
RunTypeTestLocal('\u263a', writeType);
|
||||
}
|
||||
else if (testType == typeof(float))
|
||||
{
|
||||
RunTypeTestLocal((float)random.NextDouble(), writeType);
|
||||
}
|
||||
else if (testType == typeof(double))
|
||||
{
|
||||
RunTypeTestLocal(random.NextDouble(), writeType);
|
||||
}
|
||||
else if (testType == typeof(ByteEnum))
|
||||
{
|
||||
RunTypeTestLocal(ByteEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(SByteEnum))
|
||||
{
|
||||
RunTypeTestLocal(SByteEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(ShortEnum))
|
||||
{
|
||||
RunTypeTestLocal(ShortEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(UShortEnum))
|
||||
{
|
||||
RunTypeTestLocal(UShortEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(IntEnum))
|
||||
{
|
||||
RunTypeTestLocal(IntEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(UIntEnum))
|
||||
{
|
||||
RunTypeTestLocal(UIntEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(LongEnum))
|
||||
{
|
||||
RunTypeTestLocal(LongEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(ULongEnum))
|
||||
{
|
||||
RunTypeTestLocal(ULongEnum.C, writeType);
|
||||
}
|
||||
else if (testType == typeof(Vector2))
|
||||
{
|
||||
RunTypeTestLocal(new Vector2((float)random.NextDouble(), (float)random.NextDouble()), writeType);
|
||||
}
|
||||
else if (testType == typeof(Vector3))
|
||||
{
|
||||
RunTypeTestLocal(new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
|
||||
}
|
||||
else if (testType == typeof(Vector4))
|
||||
{
|
||||
RunTypeTestLocal(new Vector4((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
|
||||
}
|
||||
else if (testType == typeof(Quaternion))
|
||||
{
|
||||
RunTypeTestLocal(new Quaternion((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
|
||||
}
|
||||
else if (testType == typeof(Color))
|
||||
{
|
||||
RunTypeTestLocal(new Color((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()), writeType);
|
||||
}
|
||||
else if (testType == typeof(Color32))
|
||||
{
|
||||
RunTypeTestLocal(new Color32((byte)random.Next(), (byte)random.Next(), (byte)random.Next(), (byte)random.Next()), writeType);
|
||||
}
|
||||
else if (testType == typeof(Ray))
|
||||
{
|
||||
RunTypeTestLocal(new Ray(
|
||||
new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble()),
|
||||
new Vector3((float)random.NextDouble(), (float)random.NextDouble(), (float)random.NextDouble())), writeType);
|
||||
}
|
||||
else if (testType == typeof(Ray2D))
|
||||
{
|
||||
RunTypeTestLocal(new Ray2D(
|
||||
new Vector2((float)random.NextDouble(), (float)random.NextDouble()),
|
||||
new Vector2((float)random.NextDouble(), (float)random.NextDouble())), writeType);
|
||||
}
|
||||
else if (testType == typeof(TestStruct))
|
||||
{
|
||||
RunTypeTestLocal(GetTestStruct(), writeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("No type handler was provided for this type in the test!");
|
||||
}
|
||||
}
|
||||
|
||||
public void BaseArrayTypeTest(Type testType, WriteType writeType)
|
||||
{
|
||||
var random = new Random();
|
||||
void RunTypeTestLocal<T>(T[] val, WriteType wt) where T : unmanaged
|
||||
{
|
||||
switch (wt)
|
||||
{
|
||||
case WriteType.WriteDirect:
|
||||
RunTypeArrayTest(val);
|
||||
break;
|
||||
case WriteType.WriteSafe:
|
||||
RunTypeArrayTestSafe(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (testType == typeof(byte))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
(byte) random.Next(),
|
||||
(byte) random.Next(),
|
||||
(byte) random.Next(),
|
||||
(byte) random.Next(),
|
||||
(byte) random.Next(),
|
||||
(byte) random.Next(),
|
||||
(byte) random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(sbyte))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
(sbyte) random.Next(),
|
||||
(sbyte) random.Next(),
|
||||
(sbyte) random.Next(),
|
||||
(sbyte) random.Next(),
|
||||
(sbyte) random.Next(),
|
||||
(sbyte) random.Next(),
|
||||
(sbyte) random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(short))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
(short) random.Next(),
|
||||
(short) random.Next(),
|
||||
(short) random.Next(),
|
||||
(short) random.Next(),
|
||||
(short) random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(ushort))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
(ushort) random.Next(),
|
||||
(ushort) random.Next(),
|
||||
(ushort) random.Next(),
|
||||
(ushort) random.Next(),
|
||||
(ushort) random.Next(),
|
||||
(ushort) random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(int))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
random.Next(),
|
||||
random.Next(),
|
||||
random.Next(),
|
||||
random.Next(),
|
||||
random.Next(),
|
||||
random.Next(),
|
||||
random.Next(),
|
||||
random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(uint))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
(uint) random.Next(),
|
||||
(uint) random.Next(),
|
||||
(uint) random.Next(),
|
||||
(uint) random.Next(),
|
||||
(uint) random.Next(),
|
||||
(uint) random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(long))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
((long)random.Next() << 32) + (long)random.Next(),
|
||||
((long)random.Next() << 32) + (long)random.Next(),
|
||||
((long)random.Next() << 32) + (long)random.Next(),
|
||||
((long)random.Next() << 32) + (long)random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(ulong))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next(),
|
||||
((ulong)random.Next() << 32) + (ulong)random.Next()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(bool))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(char))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
'a',
|
||||
'\u263a'
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(float))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble(),
|
||||
(float)random.NextDouble()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(double))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble(),
|
||||
random.NextDouble()
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(ByteEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
ByteEnum.C,
|
||||
ByteEnum.A,
|
||||
ByteEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(SByteEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
SByteEnum.C,
|
||||
SByteEnum.A,
|
||||
SByteEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(ShortEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
ShortEnum.C,
|
||||
ShortEnum.A,
|
||||
ShortEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(UShortEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
UShortEnum.C,
|
||||
UShortEnum.A,
|
||||
UShortEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(IntEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
IntEnum.C,
|
||||
IntEnum.A,
|
||||
IntEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(UIntEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
UIntEnum.C,
|
||||
UIntEnum.A,
|
||||
UIntEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(LongEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
LongEnum.C,
|
||||
LongEnum.A,
|
||||
LongEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(ULongEnum))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
ULongEnum.C,
|
||||
ULongEnum.A,
|
||||
ULongEnum.B
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Vector2))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble()),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Vector3))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble()),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Vector4))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Vector4((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Vector4((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Vector4((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Quaternion))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Quaternion((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Quaternion((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Quaternion((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble(), (float) random.NextDouble()),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Color))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Color((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Color((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Color((float) random.NextDouble(), (float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Color32))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Color32((byte) random.Next(), (byte) random.Next(), (byte) random.Next(), (byte) random.Next()),
|
||||
new Color32((byte) random.Next(), (byte) random.Next(), (byte) random.Next(), (byte) random.Next()),
|
||||
new Color32((byte) random.Next(), (byte) random.Next(), (byte) random.Next(), (byte) random.Next()),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Ray))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Ray(
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble())),
|
||||
new Ray(
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble())),
|
||||
new Ray(
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble()),
|
||||
new Vector3((float) random.NextDouble(), (float) random.NextDouble(),
|
||||
(float) random.NextDouble())),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(Ray2D))
|
||||
{
|
||||
RunTypeTestLocal(new[]{
|
||||
new Ray2D(
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble())),
|
||||
new Ray2D(
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble())),
|
||||
new Ray2D(
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble()),
|
||||
new Vector2((float) random.NextDouble(), (float) random.NextDouble())),
|
||||
}, writeType);
|
||||
}
|
||||
else if (testType == typeof(TestStruct))
|
||||
{
|
||||
RunTypeTestLocal(new[] {
|
||||
GetTestStruct(),
|
||||
GetTestStruct(),
|
||||
GetTestStruct(),
|
||||
}, writeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail("No type handler was provided for this type in the test!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 573b1f36caed496a9c6e0eaa788d0c29
|
||||
timeCreated: 1629917174
|
||||
71
Tests/Editor/Serialization/BitCounterTests.cs
Normal file
71
Tests/Editor/Serialization/BitCounterTests.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class BitCounterTests
|
||||
{
|
||||
[Test]
|
||||
public void WhenCountingUsedBitsIn64BitValue_ResultMatchesHighBitSetPlusOne([Range(0, 63)] int highBit)
|
||||
{
|
||||
if (highBit == 0)
|
||||
{
|
||||
ulong value = 0;
|
||||
// 0 is a special case. All values are considered at least 1 bit.
|
||||
Assert.AreEqual(1, BitCounter.GetUsedBitCount(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong value = 1UL << highBit;
|
||||
Assert.AreEqual(highBit + 1, BitCounter.GetUsedBitCount(value));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCountingUsedBitsIn32BitValue_ResultMatchesHighBitSetPlusOne([Range(0, 31)] int highBit)
|
||||
{
|
||||
if (highBit == 0)
|
||||
{
|
||||
uint value = 0;
|
||||
// 0 is a special case. All values are considered at least 1 bit.
|
||||
Assert.AreEqual(1, BitCounter.GetUsedBitCount(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint value = 1U << highBit;
|
||||
Assert.AreEqual(highBit + 1, BitCounter.GetUsedBitCount(value));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCountingUsedBytesIn64BitValue_ResultMatchesHighBitSetOver8PlusOne([Range(0, 63)] int highBit)
|
||||
{
|
||||
if (highBit == 0)
|
||||
{
|
||||
ulong value = 0;
|
||||
// 0 is a special case. All values are considered at least 1 byte.
|
||||
Assert.AreEqual(1, BitCounter.GetUsedByteCount(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong value = 1UL << highBit;
|
||||
Assert.AreEqual(highBit / 8 + 1, BitCounter.GetUsedByteCount(value));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCountingUsedBytesIn32BitValue_ResultMatchesHighBitSetOver8PlusOne([Range(0, 31)] int highBit)
|
||||
{
|
||||
if (highBit == 0)
|
||||
{
|
||||
uint value = 0;
|
||||
// 0 is a special case. All values are considered at least 1 byte.
|
||||
Assert.AreEqual(1, BitCounter.GetUsedByteCount(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint value = 1U << highBit;
|
||||
Assert.AreEqual(highBit / 8 + 1, BitCounter.GetUsedByteCount(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Serialization/BitCounterTests.cs.meta
Normal file
11
Tests/Editor/Serialization/BitCounterTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76e459b9c2aeea94ebf448c237061485
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
371
Tests/Editor/Serialization/BitReaderTests.cs
Normal file
371
Tests/Editor/Serialization/BitReaderTests.cs
Normal file
@@ -0,0 +1,371 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class BitReaderTests
|
||||
{
|
||||
[Test]
|
||||
public void TestReadingOneBit()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(3));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBit(true);
|
||||
|
||||
bitWriter.WriteBit(true);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
}
|
||||
|
||||
writer.WriteByte(0b11111111);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
Assert.IsTrue(reader.TryBeginRead(3));
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
bool b;
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
}
|
||||
|
||||
reader.ReadByte(out byte lastByte);
|
||||
Assert.AreEqual(0b11111111, lastByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public unsafe void TestTryBeginReadBits()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(4, Allocator.Temp);
|
||||
var reader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
nativeArray.Dispose();
|
||||
using (reader)
|
||||
{
|
||||
int* asInt = (int*)reader.GetUnsafePtr();
|
||||
*asInt = 0b11111111_00001010_10101011;
|
||||
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => reader.TryBeginRead(1));
|
||||
Assert.Throws<InvalidOperationException>(() => reader.TryBeginReadValue(1));
|
||||
Assert.IsTrue(bitReader.TryBeginReadBits(1));
|
||||
bitReader.ReadBit(out bool b);
|
||||
Assert.IsTrue(b);
|
||||
|
||||
// Can't use Assert.Throws() because ref struct BitWriter can't be captured in a lambda
|
||||
try
|
||||
{
|
||||
bitReader.ReadBit(out b);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
Assert.IsTrue(bitReader.TryBeginReadBits(3));
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsFalse(b);
|
||||
bitReader.ReadBit(out b);
|
||||
Assert.IsTrue(b);
|
||||
|
||||
byte byteVal;
|
||||
try
|
||||
{
|
||||
bitReader.ReadBits(out byteVal, 4);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bitReader.ReadBits(out byteVal, 1);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
Assert.IsTrue(bitReader.TryBeginReadBits(3));
|
||||
|
||||
try
|
||||
{
|
||||
bitReader.ReadBits(out byteVal, 4);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
Assert.IsTrue(bitReader.TryBeginReadBits(4));
|
||||
bitReader.ReadBits(out byteVal, 3);
|
||||
Assert.AreEqual(0b010, byteVal);
|
||||
|
||||
Assert.IsTrue(bitReader.TryBeginReadBits(5));
|
||||
|
||||
bitReader.ReadBits(out byteVal, 5);
|
||||
Assert.AreEqual(0b10101, byteVal);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, reader.Position);
|
||||
|
||||
Assert.IsTrue(reader.TryBeginRead(1));
|
||||
reader.ReadByte(out byte nextByte);
|
||||
Assert.AreEqual(0b11111111, nextByte);
|
||||
|
||||
Assert.IsTrue(reader.TryBeginRead(1));
|
||||
reader.ReadByte(out nextByte);
|
||||
Assert.AreEqual(0b00000000, nextByte);
|
||||
|
||||
Assert.IsFalse(reader.TryBeginRead(1));
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
Assert.IsFalse(bitReader.TryBeginReadBits(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReadingMultipleBits()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(3));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111, 1);
|
||||
bitWriter.WriteBits(0b11111111, 1);
|
||||
bitWriter.WriteBits(0b11111110, 2);
|
||||
bitWriter.WriteBits(0b11111000, 4);
|
||||
bitWriter.WriteBits(0b11111010, 4);
|
||||
}
|
||||
writer.WriteByte(0b11111111);
|
||||
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
Assert.IsTrue(reader.TryBeginRead(3));
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
byte b;
|
||||
bitReader.ReadBits(out b, 1);
|
||||
Assert.AreEqual(0b1, b);
|
||||
|
||||
bitReader.ReadBits(out b, 1);
|
||||
Assert.AreEqual(0b1, b);
|
||||
|
||||
bitReader.ReadBits(out b, 2);
|
||||
Assert.AreEqual(0b10, b);
|
||||
|
||||
bitReader.ReadBits(out b, 4);
|
||||
Assert.AreEqual(0b1000, b);
|
||||
|
||||
bitReader.ReadBits(out b, 4);
|
||||
Assert.AreEqual(0b1010, b);
|
||||
}
|
||||
|
||||
reader.ReadByte(out byte lastByte);
|
||||
Assert.AreEqual(0b11111111, lastByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReadingMultipleBitsToLongs()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(3));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111UL, 1);
|
||||
bitWriter.WriteBits(0b11111111UL, 1);
|
||||
bitWriter.WriteBits(0b11111110UL, 2);
|
||||
bitWriter.WriteBits(0b11111000UL, 4);
|
||||
bitWriter.WriteBits(0b11111010UL, 4);
|
||||
}
|
||||
|
||||
writer.WriteByte(0b11111111);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
Assert.IsTrue(reader.TryBeginRead(3));
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
ulong ul;
|
||||
bitReader.ReadBits(out ul, 1);
|
||||
Assert.AreEqual(0b1, ul);
|
||||
|
||||
bitReader.ReadBits(out ul, 1);
|
||||
Assert.AreEqual(0b1, ul);
|
||||
|
||||
bitReader.ReadBits(out ul, 2);
|
||||
Assert.AreEqual(0b10, ul);
|
||||
|
||||
bitReader.ReadBits(out ul, 4);
|
||||
Assert.AreEqual(0b1000, ul);
|
||||
|
||||
bitReader.ReadBits(out ul, 4);
|
||||
Assert.AreEqual(0b1010, ul);
|
||||
}
|
||||
|
||||
reader.ReadByte(out byte lastByte);
|
||||
Assert.AreEqual(0b11111111, lastByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestReadingMultipleBytesToLongs([Range(1U, 64U)] uint numBits)
|
||||
{
|
||||
ulong value = 0xFFFFFFFFFFFFFFFF;
|
||||
var reader = new FastBufferReader((byte*)&value, Allocator.Temp, sizeof(ulong));
|
||||
using (reader)
|
||||
{
|
||||
ulong* asUlong = (ulong*)reader.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(value, *asUlong);
|
||||
var mask = 0UL;
|
||||
for (var i = 0; i < numBits; ++i)
|
||||
{
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
|
||||
ulong readValue;
|
||||
|
||||
Assert.IsTrue(reader.TryBeginRead(sizeof(ulong)));
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
bitReader.ReadBits(out readValue, numBits);
|
||||
}
|
||||
Assert.AreEqual(value & mask, readValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestReadingMultipleBytesToLongsMisaligned([Range(1U, 63U)] uint numBits)
|
||||
{
|
||||
ulong value = 0b01010101_10101010_01010101_10101010_01010101_10101010_01010101_10101010;
|
||||
var reader = new FastBufferReader((byte*)&value, Allocator.Temp, sizeof(ulong));
|
||||
using (reader)
|
||||
{
|
||||
ulong* asUlong = (ulong*)reader.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(value, *asUlong);
|
||||
var mask = 0UL;
|
||||
for (var i = 0; i < numBits; ++i)
|
||||
{
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
|
||||
ulong readValue;
|
||||
|
||||
Assert.IsTrue(reader.TryBeginRead(sizeof(ulong)));
|
||||
using (var bitReader = reader.EnterBitwiseContext())
|
||||
{
|
||||
bitReader.ReadBit(out bool unused);
|
||||
bitReader.ReadBits(out readValue, numBits);
|
||||
}
|
||||
Assert.AreEqual((value >> 1) & mask, readValue);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestReadingBitsThrowsIfTryBeginReadNotCalled()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(4, Allocator.Temp);
|
||||
var reader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
nativeArray.Dispose();
|
||||
using (reader)
|
||||
{
|
||||
int* asInt = (int*)reader.GetUnsafePtr();
|
||||
*asInt = 0b11111111_00001010_10101011;
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitReader = reader.EnterBitwiseContext();
|
||||
bitReader.ReadBit(out bool b);
|
||||
});
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitReader = reader.EnterBitwiseContext();
|
||||
bitReader.ReadBits(out byte b, 1);
|
||||
});
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitReader = reader.EnterBitwiseContext();
|
||||
bitReader.ReadBits(out ulong ul, 1);
|
||||
});
|
||||
|
||||
Assert.AreEqual(0, reader.Position);
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
Assert.IsTrue(reader.TryBeginRead(1));
|
||||
using var bitReader = reader.EnterBitwiseContext();
|
||||
ulong ul;
|
||||
try
|
||||
{
|
||||
bitReader.ReadBits(out ul, 4);
|
||||
bitReader.ReadBits(out ul, 4);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
Assert.Fail("Overflow exception was thrown too early.");
|
||||
throw;
|
||||
}
|
||||
bitReader.ReadBits(out ul, 4);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Serialization/BitReaderTests.cs.meta
Normal file
11
Tests/Editor/Serialization/BitReaderTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67df11865abcd5843a4e142cf6bbd901
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
333
Tests/Editor/Serialization/BitWriterTests.cs
Normal file
333
Tests/Editor/Serialization/BitWriterTests.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class BitWriterTests
|
||||
{
|
||||
[Test]
|
||||
public unsafe void TestWritingOneBit()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
int* asInt = (int*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asInt);
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(3));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b1, *asInt);
|
||||
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b11, *asInt);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b1011, *asInt);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b10001011, *asInt);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b1010_10001011, *asInt);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, writer.Position);
|
||||
Assert.AreEqual(0b1010_10001011, *asInt);
|
||||
|
||||
writer.WriteByte(0b11111111);
|
||||
Assert.AreEqual(0b11111111_00001010_10001011, *asInt);
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public unsafe void TestTryBeginWriteBits()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
int* asInt = (int*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asInt);
|
||||
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => writer.TryBeginWrite(1));
|
||||
Assert.Throws<InvalidOperationException>(() => writer.TryBeginWriteValue(1));
|
||||
Assert.IsTrue(bitWriter.TryBeginWriteBits(1));
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b1, *asInt);
|
||||
|
||||
// Can't use Assert.Throws() because ref struct BitWriter can't be captured in a lambda
|
||||
try
|
||||
{
|
||||
bitWriter.WriteBit(true);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
|
||||
Assert.IsTrue(bitWriter.TryBeginWriteBits(3));
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b11, *asInt);
|
||||
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBit(true);
|
||||
Assert.AreEqual(0b1011, *asInt);
|
||||
|
||||
try
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111, 4);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111, 1);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
Assert.IsTrue(bitWriter.TryBeginWriteBits(3));
|
||||
|
||||
try
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111, 4);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Should get called here.
|
||||
}
|
||||
Assert.IsTrue(bitWriter.TryBeginWriteBits(4));
|
||||
|
||||
bitWriter.WriteBits(0b11111010, 3);
|
||||
|
||||
Assert.AreEqual(0b00101011, *asInt);
|
||||
|
||||
Assert.IsTrue(bitWriter.TryBeginWriteBits(5));
|
||||
|
||||
bitWriter.WriteBits(0b11110101, 5);
|
||||
Assert.AreEqual(0b1010_10101011, *asInt);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, writer.Position);
|
||||
Assert.AreEqual(0b1010_10101011, *asInt);
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(1));
|
||||
writer.WriteByte(0b11111111);
|
||||
Assert.AreEqual(0b11111111_00001010_10101011, *asInt);
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(1));
|
||||
writer.WriteByte(0b00000000);
|
||||
Assert.AreEqual(0b11111111_00001010_10101011, *asInt);
|
||||
|
||||
Assert.IsFalse(writer.TryBeginWrite(1));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
Assert.IsFalse(bitWriter.TryBeginWriteBits(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestWritingMultipleBits()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
int* asInt = (int*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asInt);
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(3));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111, 1);
|
||||
Assert.AreEqual(0b1, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111111, 1);
|
||||
Assert.AreEqual(0b11, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111110, 2);
|
||||
Assert.AreEqual(0b1011, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111000, 4);
|
||||
Assert.AreEqual(0b10001011, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111010, 4);
|
||||
Assert.AreEqual(0b1010_10001011, *asInt);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, writer.Position);
|
||||
Assert.AreEqual(0b1010_10001011, *asInt);
|
||||
|
||||
writer.WriteByte(0b11111111);
|
||||
Assert.AreEqual(0b11111111_00001010_10001011, *asInt);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestWritingMultipleBitsFromLongs()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
int* asInt = (int*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asInt);
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(3));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111UL, 1);
|
||||
Assert.AreEqual(0b1, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111111UL, 1);
|
||||
Assert.AreEqual(0b11, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111110UL, 2);
|
||||
Assert.AreEqual(0b1011, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111000UL, 4);
|
||||
Assert.AreEqual(0b10001011, *asInt);
|
||||
|
||||
bitWriter.WriteBits(0b11111010UL, 4);
|
||||
Assert.AreEqual(0b1010_10001011, *asInt);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, writer.Position);
|
||||
Assert.AreEqual(0b1010_10001011, *asInt);
|
||||
|
||||
writer.WriteByte(0b11111111);
|
||||
Assert.AreEqual(0b11111111_00001010_10001011, *asInt);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestWritingMultipleBytesFromLongs([Range(1U, 64U)] uint numBits)
|
||||
{
|
||||
var writer = new FastBufferWriter(sizeof(ulong), Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
ulong* asUlong = (ulong*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asUlong);
|
||||
var mask = 0UL;
|
||||
for (var i = 0; i < numBits; ++i)
|
||||
{
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
|
||||
ulong value = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(sizeof(ulong)));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBits(value, numBits);
|
||||
}
|
||||
Assert.AreEqual(value & mask, *asUlong);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestWritingMultipleBytesFromLongsMisaligned([Range(1U, 63U)] uint numBits)
|
||||
{
|
||||
var writer = new FastBufferWriter(sizeof(ulong), Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
ulong* asUlong = (ulong*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asUlong);
|
||||
var mask = 0UL;
|
||||
for (var i = 0; i < numBits; ++i)
|
||||
{
|
||||
mask |= (1UL << i);
|
||||
}
|
||||
|
||||
ulong value = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
Assert.IsTrue(writer.TryBeginWrite(sizeof(ulong)));
|
||||
using (var bitWriter = writer.EnterBitwiseContext())
|
||||
{
|
||||
bitWriter.WriteBit(false);
|
||||
bitWriter.WriteBits(value, numBits);
|
||||
}
|
||||
Assert.AreEqual(value & mask, *asUlong >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void TestWritingBitsThrowsIfTryBeginWriteNotCalled()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
int* asInt = (int*)writer.GetUnsafePtr();
|
||||
|
||||
Assert.AreEqual(0, *asInt);
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitWriter = writer.EnterBitwiseContext();
|
||||
bitWriter.WriteBit(true);
|
||||
});
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitWriter = writer.EnterBitwiseContext();
|
||||
bitWriter.WriteBit(false);
|
||||
});
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitWriter = writer.EnterBitwiseContext();
|
||||
bitWriter.WriteBits(0b11111111, 1);
|
||||
});
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
using var bitWriter = writer.EnterBitwiseContext();
|
||||
bitWriter.WriteBits(0b11111111UL, 1);
|
||||
});
|
||||
|
||||
Assert.AreEqual(0, writer.Position);
|
||||
Assert.AreEqual(0, *asInt);
|
||||
|
||||
writer.WriteByteSafe(0b11111111);
|
||||
Assert.AreEqual(0b11111111, *asInt);
|
||||
|
||||
|
||||
Assert.Throws<OverflowException>(() =>
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(1));
|
||||
using var bitWriter = writer.EnterBitwiseContext();
|
||||
try
|
||||
{
|
||||
bitWriter.WriteBits(0b11111111UL, 4);
|
||||
bitWriter.WriteBits(0b11111111UL, 4);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
Assert.Fail("Overflow exception was thrown too early.");
|
||||
}
|
||||
bitWriter.WriteBits(0b11111111UL, 1);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Serialization/BitWriterTests.cs.meta
Normal file
11
Tests/Editor/Serialization/BitWriterTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fed657e0516a72f469fbf886e3e5149a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
353
Tests/Editor/Serialization/BufferSerializerTests.cs
Normal file
353
Tests/Editor/Serialization/BufferSerializerTests.cs
Normal file
@@ -0,0 +1,353 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class BufferSerializerTests
|
||||
{
|
||||
[Test]
|
||||
public void TestIsReaderIsWriter()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
Assert.IsFalse(serializer.IsReader);
|
||||
Assert.IsTrue(serializer.IsWriter);
|
||||
}
|
||||
byte[] readBuffer = new byte[4];
|
||||
var reader = new FastBufferReader(readBuffer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
Assert.IsTrue(serializer.IsReader);
|
||||
Assert.IsFalse(serializer.IsWriter);
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public unsafe void TestGetUnderlyingStructs()
|
||||
{
|
||||
var writer = new FastBufferWriter(4, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
FastBufferWriter underlyingWriter = serializer.GetFastBufferWriter();
|
||||
Assert.IsTrue(underlyingWriter.Handle == writer.Handle);
|
||||
// Can't use Assert.Throws() because ref structs can't be passed into lambdas.
|
||||
try
|
||||
{
|
||||
serializer.GetFastBufferReader();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
||||
byte[] readBuffer = new byte[4];
|
||||
var reader = new FastBufferReader(readBuffer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
FastBufferReader underlyingReader = serializer.GetFastBufferReader();
|
||||
Assert.IsTrue(underlyingReader.Handle == reader.Handle);
|
||||
// Can't use Assert.Throws() because ref structs can't be passed into lambdas.
|
||||
try
|
||||
{
|
||||
serializer.GetFastBufferWriter();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSerializingValues()
|
||||
{
|
||||
var random = new Random();
|
||||
int value = random.Next();
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
serializer.SerializeValue(ref value);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
int readValue = 0;
|
||||
deserializer.SerializeValue(ref readValue);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void TestSerializingBytes()
|
||||
{
|
||||
var random = new Random();
|
||||
byte value = (byte)random.Next();
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
serializer.SerializeValue(ref value);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
byte readValue = 0;
|
||||
deserializer.SerializeValue(ref readValue);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void TestSerializingArrays()
|
||||
{
|
||||
var random = new Random();
|
||||
int[] value = { random.Next(), random.Next(), random.Next() };
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
serializer.SerializeValue(ref value);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
int[] readValue = null;
|
||||
deserializer.SerializeValue(ref readValue);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void TestSerializingStrings([Values] bool oneBytChars)
|
||||
{
|
||||
string value = "I am a test string";
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
serializer.SerializeValue(ref value, oneBytChars);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
string readValue = null;
|
||||
deserializer.SerializeValue(ref readValue, oneBytChars);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestSerializingValuesPreChecked()
|
||||
{
|
||||
var random = new Random();
|
||||
int value = random.Next();
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
try
|
||||
{
|
||||
serializer.SerializeValuePreChecked(ref value);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(serializer.PreCheck(FastBufferWriter.GetWriteSize(value)));
|
||||
serializer.SerializeValuePreChecked(ref value);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
int readValue = 0;
|
||||
try
|
||||
{
|
||||
deserializer.SerializeValuePreChecked(ref readValue);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(deserializer.PreCheck(FastBufferWriter.GetWriteSize(value)));
|
||||
deserializer.SerializeValuePreChecked(ref readValue);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void TestSerializingBytesPreChecked()
|
||||
{
|
||||
var random = new Random();
|
||||
byte value = (byte)random.Next();
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
try
|
||||
{
|
||||
serializer.SerializeValuePreChecked(ref value);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(serializer.PreCheck(FastBufferWriter.GetWriteSize(value)));
|
||||
serializer.SerializeValuePreChecked(ref value);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
byte readValue = 0;
|
||||
try
|
||||
{
|
||||
deserializer.SerializeValuePreChecked(ref readValue);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(deserializer.PreCheck(FastBufferWriter.GetWriteSize(value)));
|
||||
deserializer.SerializeValuePreChecked(ref readValue);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void TestSerializingArraysPreChecked()
|
||||
{
|
||||
var random = new Random();
|
||||
int[] value = { random.Next(), random.Next(), random.Next() };
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
try
|
||||
{
|
||||
serializer.SerializeValuePreChecked(ref value);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(serializer.PreCheck(FastBufferWriter.GetWriteSize(value)));
|
||||
serializer.SerializeValuePreChecked(ref value);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
int[] readValue = null;
|
||||
try
|
||||
{
|
||||
deserializer.SerializeValuePreChecked(ref readValue);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(deserializer.PreCheck(FastBufferWriter.GetWriteSize(value)));
|
||||
deserializer.SerializeValuePreChecked(ref readValue);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public void TestSerializingStringsPreChecked([Values] bool oneBytChars)
|
||||
{
|
||||
string value = "I am a test string";
|
||||
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
var serializer =
|
||||
new BufferSerializer<BufferSerializerWriter>(new BufferSerializerWriter(writer));
|
||||
try
|
||||
{
|
||||
serializer.SerializeValuePreChecked(ref value, oneBytChars);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(serializer.PreCheck(FastBufferWriter.GetWriteSize(value, oneBytChars)));
|
||||
serializer.SerializeValuePreChecked(ref value, oneBytChars);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var deserializer =
|
||||
new BufferSerializer<BufferSerializerReader>(new BufferSerializerReader(reader));
|
||||
string readValue = null;
|
||||
try
|
||||
{
|
||||
deserializer.SerializeValuePreChecked(ref readValue, oneBytChars);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
// Pass
|
||||
}
|
||||
|
||||
Assert.IsTrue(deserializer.PreCheck(FastBufferWriter.GetWriteSize(value, oneBytChars)));
|
||||
deserializer.SerializeValuePreChecked(ref readValue, oneBytChars);
|
||||
|
||||
Assert.AreEqual(value, readValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Serialization/BufferSerializerTests.cs.meta
Normal file
11
Tests/Editor/Serialization/BufferSerializerTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cf899c97866c76498b71585a61a8142
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1103
Tests/Editor/Serialization/BytePackerTests.cs
Normal file
1103
Tests/Editor/Serialization/BytePackerTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Tests/Editor/Serialization/BytePackerTests.cs.meta
Normal file
11
Tests/Editor/Serialization/BytePackerTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b50db056cd7443b4eb2e00b603d4c15c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
830
Tests/Editor/Serialization/FastBufferReaderTests.cs
Normal file
830
Tests/Editor/Serialization/FastBufferReaderTests.cs
Normal file
@@ -0,0 +1,830 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class FastBufferReaderTests : BaseFastBufferReaderWriterTest
|
||||
{
|
||||
#region Common Checks
|
||||
private void WriteCheckBytes(FastBufferWriter writer, int writeSize, string failMessage = "")
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(2), "Writer denied write permission");
|
||||
writer.WriteValue((byte)0x80);
|
||||
Assert.AreEqual(writeSize + 1, writer.Position, failMessage);
|
||||
Assert.AreEqual(writeSize + 1, writer.Length, failMessage);
|
||||
writer.WriteValue((byte)0xFF);
|
||||
Assert.AreEqual(writeSize + 2, writer.Position, failMessage);
|
||||
Assert.AreEqual(writeSize + 2, writer.Length, failMessage);
|
||||
}
|
||||
|
||||
private void VerifyCheckBytes(FastBufferReader reader, int checkPosition, string failMessage = "")
|
||||
{
|
||||
reader.Seek(checkPosition);
|
||||
reader.TryBeginRead(2);
|
||||
|
||||
reader.ReadByte(out byte value);
|
||||
Assert.AreEqual(0x80, value, failMessage);
|
||||
reader.ReadByte(out value);
|
||||
Assert.AreEqual(0xFF, value, failMessage);
|
||||
}
|
||||
|
||||
private void VerifyPositionAndLength(FastBufferReader reader, int length, string failMessage = "")
|
||||
{
|
||||
Assert.AreEqual(0, reader.Position, failMessage);
|
||||
Assert.AreEqual(length, reader.Length, failMessage);
|
||||
}
|
||||
|
||||
private FastBufferReader CommonChecks<T>(FastBufferWriter writer, T valueToTest, int writeSize, string failMessage = "") where T : unmanaged
|
||||
{
|
||||
WriteCheckBytes(writer, writeSize, failMessage);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
|
||||
VerifyPositionAndLength(reader, writer.Length, failMessage);
|
||||
|
||||
VerifyCheckBytes(reader, writeSize, failMessage);
|
||||
|
||||
reader.Seek(0);
|
||||
|
||||
return reader;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Generic Checks
|
||||
protected override unsafe void RunTypeTest<T>(T valueToTest)
|
||||
{
|
||||
var writeSize = FastBufferWriter.GetWriteSize(valueToTest);
|
||||
Assert.AreEqual(sizeof(T), writeSize);
|
||||
var writer = new FastBufferWriter(writeSize + 2, Allocator.Temp);
|
||||
|
||||
using (writer)
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(writeSize + 2), "Writer denied write permission");
|
||||
|
||||
var failMessage = $"RunTypeTest failed with type {typeof(T)} and value {valueToTest}";
|
||||
|
||||
writer.WriteValue(valueToTest);
|
||||
|
||||
var reader = CommonChecks(writer, valueToTest, writeSize, failMessage);
|
||||
|
||||
using (reader)
|
||||
{
|
||||
Assert.IsTrue(reader.TryBeginRead(FastBufferWriter.GetWriteSize<T>()));
|
||||
reader.ReadValue(out T result);
|
||||
Assert.AreEqual(valueToTest, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override unsafe void RunTypeTestSafe<T>(T valueToTest)
|
||||
{
|
||||
var writeSize = FastBufferWriter.GetWriteSize(valueToTest);
|
||||
var writer = new FastBufferWriter(writeSize + 2, Allocator.Temp);
|
||||
|
||||
using (writer)
|
||||
{
|
||||
Assert.AreEqual(sizeof(T), writeSize);
|
||||
|
||||
var failMessage = $"RunTypeTest failed with type {typeof(T)} and value {valueToTest}";
|
||||
|
||||
writer.WriteValueSafe(valueToTest);
|
||||
|
||||
|
||||
var reader = CommonChecks(writer, valueToTest, writeSize, failMessage);
|
||||
|
||||
using (reader)
|
||||
{
|
||||
reader.ReadValueSafe(out T result);
|
||||
Assert.AreEqual(valueToTest, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyArrayEquality<T>(T[] value, T[] compareValue, int offset) where T : unmanaged
|
||||
{
|
||||
Assert.AreEqual(value.Length, compareValue.Length);
|
||||
|
||||
for (var i = 0; i < value.Length; ++i)
|
||||
{
|
||||
Assert.AreEqual(value[i], compareValue[i]);
|
||||
}
|
||||
}
|
||||
|
||||
protected override unsafe void RunTypeArrayTest<T>(T[] valueToTest)
|
||||
{
|
||||
var writeSize = FastBufferWriter.GetWriteSize(valueToTest);
|
||||
var writer = new FastBufferWriter(writeSize + 2, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
Assert.AreEqual(sizeof(int) + sizeof(T) * valueToTest.Length, writeSize);
|
||||
Assert.IsTrue(writer.TryBeginWrite(writeSize + 2), "Writer denied write permission");
|
||||
|
||||
writer.WriteValue(valueToTest);
|
||||
|
||||
WriteCheckBytes(writer, writeSize);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
VerifyPositionAndLength(reader, writer.Length);
|
||||
|
||||
Assert.IsTrue(reader.TryBeginRead(writeSize));
|
||||
reader.ReadValue(out T[] result);
|
||||
VerifyArrayEquality(valueToTest, result, 0);
|
||||
|
||||
VerifyCheckBytes(reader, writeSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override unsafe void RunTypeArrayTestSafe<T>(T[] valueToTest)
|
||||
{
|
||||
var writeSize = FastBufferWriter.GetWriteSize(valueToTest);
|
||||
var writer = new FastBufferWriter(writeSize + 2, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
Assert.AreEqual(sizeof(int) + sizeof(T) * valueToTest.Length, writeSize);
|
||||
|
||||
writer.WriteValueSafe(valueToTest);
|
||||
|
||||
WriteCheckBytes(writer, writeSize);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
VerifyPositionAndLength(reader, writer.Length);
|
||||
|
||||
reader.ReadValueSafe(out T[] result);
|
||||
VerifyArrayEquality(valueToTest, result, 0);
|
||||
|
||||
VerifyCheckBytes(reader, writeSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tests
|
||||
[Test]
|
||||
public void GivenFastBufferWriterContainingValue_WhenReadingUnmanagedType_ValueMatchesWhatWasWritten(
|
||||
[Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint),
|
||||
typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double),
|
||||
typeof(ByteEnum), typeof(SByteEnum), typeof(ShortEnum), typeof(UShortEnum), typeof(IntEnum),
|
||||
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3), typeof(Vector4),
|
||||
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
|
||||
Type testType,
|
||||
[Values] WriteType writeType)
|
||||
{
|
||||
BaseTypeTest(testType, writeType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GivenFastBufferWriterContainingValue_WhenReadingArrayOfUnmanagedElementType_ValueMatchesWhatWasWritten(
|
||||
[Values(typeof(byte), typeof(sbyte), typeof(short), typeof(ushort), typeof(int), typeof(uint),
|
||||
typeof(long), typeof(ulong), typeof(bool), typeof(char), typeof(float), typeof(double),
|
||||
typeof(ByteEnum), typeof(SByteEnum), typeof(ShortEnum), typeof(UShortEnum), typeof(IntEnum),
|
||||
typeof(UIntEnum), typeof(LongEnum), typeof(ULongEnum), typeof(Vector2), typeof(Vector3), typeof(Vector4),
|
||||
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(Ray), typeof(Ray2D), typeof(TestStruct))]
|
||||
Type testType,
|
||||
[Values] WriteType writeType)
|
||||
{
|
||||
BaseArrayTypeTest(testType, writeType);
|
||||
}
|
||||
|
||||
[TestCase(false, WriteType.WriteDirect)]
|
||||
[TestCase(false, WriteType.WriteSafe)]
|
||||
[TestCase(true, WriteType.WriteDirect)]
|
||||
[TestCase(true, WriteType.WriteSafe)]
|
||||
public void GivenFastBufferWriterContainingValue_WhenReadingString_ValueMatchesWhatWasWritten(bool oneByteChars, WriteType writeType)
|
||||
{
|
||||
string valueToTest = "Hello, I am a test string!";
|
||||
|
||||
var serializedValueSize = FastBufferWriter.GetWriteSize(valueToTest, oneByteChars);
|
||||
|
||||
var writer = new FastBufferWriter(serializedValueSize + 3, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
switch (writeType)
|
||||
{
|
||||
case WriteType.WriteDirect:
|
||||
Assert.IsTrue(writer.TryBeginWrite(serializedValueSize + 2), "Writer denied write permission");
|
||||
writer.WriteValue(valueToTest, oneByteChars);
|
||||
break;
|
||||
case WriteType.WriteSafe:
|
||||
writer.WriteValueSafe(valueToTest, oneByteChars);
|
||||
break;
|
||||
}
|
||||
|
||||
WriteCheckBytes(writer, serializedValueSize);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
VerifyPositionAndLength(reader, writer.Length);
|
||||
|
||||
string result = null;
|
||||
switch (writeType)
|
||||
{
|
||||
case WriteType.WriteDirect:
|
||||
Assert.IsTrue(reader.TryBeginRead(serializedValueSize + 2), "Reader denied read permission");
|
||||
reader.ReadValue(out result, oneByteChars);
|
||||
break;
|
||||
case WriteType.WriteSafe:
|
||||
reader.ReadValueSafe(out result, oneByteChars);
|
||||
break;
|
||||
}
|
||||
Assert.AreEqual(valueToTest, result);
|
||||
|
||||
VerifyCheckBytes(reader, serializedValueSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[TestCase(1, 0)]
|
||||
[TestCase(2, 0)]
|
||||
[TestCase(3, 0)]
|
||||
[TestCase(4, 0)]
|
||||
[TestCase(5, 0)]
|
||||
[TestCase(6, 0)]
|
||||
[TestCase(7, 0)]
|
||||
[TestCase(8, 0)]
|
||||
|
||||
[TestCase(1, 1)]
|
||||
[TestCase(2, 1)]
|
||||
[TestCase(3, 1)]
|
||||
[TestCase(4, 1)]
|
||||
[TestCase(5, 1)]
|
||||
[TestCase(6, 1)]
|
||||
[TestCase(7, 1)]
|
||||
|
||||
[TestCase(1, 2)]
|
||||
[TestCase(2, 2)]
|
||||
[TestCase(3, 2)]
|
||||
[TestCase(4, 2)]
|
||||
[TestCase(5, 2)]
|
||||
[TestCase(6, 2)]
|
||||
|
||||
[TestCase(1, 3)]
|
||||
[TestCase(2, 3)]
|
||||
[TestCase(3, 3)]
|
||||
[TestCase(4, 3)]
|
||||
[TestCase(5, 3)]
|
||||
|
||||
[TestCase(1, 4)]
|
||||
[TestCase(2, 4)]
|
||||
[TestCase(3, 4)]
|
||||
[TestCase(4, 4)]
|
||||
|
||||
[TestCase(1, 5)]
|
||||
[TestCase(2, 5)]
|
||||
[TestCase(3, 5)]
|
||||
|
||||
[TestCase(1, 6)]
|
||||
[TestCase(2, 6)]
|
||||
|
||||
[TestCase(1, 7)]
|
||||
public void GivenFastBufferWriterContainingValue_WhenReadingPartialValue_ValueMatchesWhatWasWritten(int count, int offset)
|
||||
{
|
||||
var random = new Random();
|
||||
var valueToTest = ((ulong)random.Next() << 32) + (ulong)random.Next();
|
||||
var writer = new FastBufferWriter(sizeof(ulong) + 2, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
Assert.IsTrue(writer.TryBeginWrite(count + 2), "Writer denied write permission");
|
||||
writer.WritePartialValue(valueToTest, count, offset);
|
||||
|
||||
var failMessage = $"TestReadingPartialValues failed with value {valueToTest}";
|
||||
WriteCheckBytes(writer, count, failMessage);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
VerifyPositionAndLength(reader, writer.Length, failMessage);
|
||||
Assert.IsTrue(reader.TryBeginRead(count + 2), "Reader denied read permission");
|
||||
|
||||
ulong mask = 0;
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
mask = (mask << 8) | 0b11111111;
|
||||
}
|
||||
|
||||
mask <<= (offset * 8);
|
||||
|
||||
reader.ReadPartialValue(out ulong result, count, offset);
|
||||
Assert.AreEqual(valueToTest & mask, result & mask, failMessage);
|
||||
VerifyCheckBytes(reader, count, failMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public unsafe void GivenFastBufferReaderInitializedFromFastBufferWriterContainingValue_WhenCallingToArray_ReturnedArrayMatchesContentOfWriter()
|
||||
{
|
||||
var testStruct = GetTestStruct();
|
||||
var requiredSize = FastBufferWriter.GetWriteSize(testStruct);
|
||||
var writer = new FastBufferWriter(requiredSize, Allocator.Temp);
|
||||
|
||||
using (writer)
|
||||
{
|
||||
writer.TryBeginWrite(requiredSize);
|
||||
writer.WriteValue(testStruct);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
var array = reader.ToArray();
|
||||
var underlyingArray = writer.GetUnsafePtr();
|
||||
for (var i = 0; i < array.Length; ++i)
|
||||
{
|
||||
Assert.AreEqual(array[i], underlyingArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadByteWithoutCallingTryBeingReadFirst_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadByte(out byte b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadBytesWithoutCallingTryBeingReadFirst_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
byte[] b = { 0, 1, 2 };
|
||||
using (emptyReader)
|
||||
{
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadBytes(ref b, 3); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithUnmanagedTypeWithoutCallingTryBeingReadFirst_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadValue(out int i); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithByteArrayWithoutCallingTryBeingReadFirst_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadValue(out byte[] b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithStringWithoutCallingTryBeingReadFirst_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadValue(out string s); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueAfterCallingTryBeginWriteWithTooFewBytes_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(sizeof(int) - 1);
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadValue(out int i); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadBytePastBoundaryMarkedByTryBeginWrite_OverflowExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(sizeof(int) - 1);
|
||||
emptyReader.ReadByte(out byte b);
|
||||
emptyReader.ReadByte(out b);
|
||||
emptyReader.ReadByte(out b);
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadByte(out b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadByteDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadByte(out byte b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadBytesDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
byte[] b = { 0, 1, 2 };
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadBytes(ref b, 3); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithUnmanagedTypeDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadValue(out int i); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithByteArrayDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadValue(out byte[] b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithStringDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadValue(out string s); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadByteSafeDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadByteSafe(out byte b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadBytesSafeDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
byte[] b = { 0, 1, 2 };
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadBytesSafe(ref b, 3); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueSafeWithUnmanagedTypeDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadValueSafe(out int i); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueSafeWithByteArrayDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadValueSafe(out byte[] b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueSafeWithStringDuringBitwiseContext_InvalidOperationExceptionIsThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
using var context = emptyReader.EnterBitwiseContext();
|
||||
Assert.Throws<InvalidOperationException>(() => { emptyReader.ReadValueSafe(out string s); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadByteAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadByte(out byte theByte);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadBytesAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
|
||||
byte[] theBytes = { 0, 1, 2 };
|
||||
emptyReader.ReadBytes(ref theBytes, 3);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithUnmanagedTypeAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadValue(out int i);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithByteArrayAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadValue(out byte[] theBytes);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueWithStringAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadValue(out string s);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadByteSafeAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadByteSafe(out byte theByte);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadBytesSafeAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
|
||||
byte[] theBytes = { 0, 1, 2 };
|
||||
emptyReader.ReadBytesSafe(ref theBytes, 3);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueSafeWithUnmanagedTypeAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadValueSafe(out int i);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueSafeWithByteArrayAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadValueSafe(out byte[] theBytes);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingReadValueSafeWithStringAfterExitingBitwiseContext_InvalidOperationExceptionIsNotThrown()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
using (var context = emptyReader.EnterBitwiseContext())
|
||||
{
|
||||
context.ReadBit(out bool theBit);
|
||||
}
|
||||
emptyReader.ReadValueSafe(out string s);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenCallingTryBeginRead_TheAllowedReadPositionIsMarkedRelativeToCurrentPosition()
|
||||
{
|
||||
var nativeArray = new NativeArray<byte>(100, Allocator.Temp);
|
||||
var emptyReader = new FastBufferReader(nativeArray, Allocator.Temp);
|
||||
|
||||
using (emptyReader)
|
||||
{
|
||||
emptyReader.TryBeginRead(100);
|
||||
emptyReader.ReadByte(out byte b);
|
||||
emptyReader.TryBeginRead(1);
|
||||
emptyReader.ReadByte(out b);
|
||||
Assert.Throws<OverflowException>(() => { emptyReader.ReadByte(out byte b); });
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenReadingAfterSeeking_TheNewReadComesFromTheCorrectPosition()
|
||||
{
|
||||
var writer = new FastBufferWriter(100, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteByteSafe(1);
|
||||
writer.WriteByteSafe(3);
|
||||
writer.WriteByteSafe(2);
|
||||
writer.WriteByteSafe(5);
|
||||
writer.WriteByteSafe(4);
|
||||
writer.WriteByteSafe(0);
|
||||
|
||||
var reader = new FastBufferReader(writer, Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
reader.Seek(5);
|
||||
reader.ReadByteSafe(out byte b);
|
||||
Assert.AreEqual(reader.Position, 6);
|
||||
Assert.AreEqual(reader.Length, writer.Length);
|
||||
Assert.AreEqual(0, b);
|
||||
|
||||
reader.Seek(0);
|
||||
reader.ReadByteSafe(out b);
|
||||
Assert.AreEqual(reader.Position, 1);
|
||||
Assert.AreEqual(reader.Length, writer.Length);
|
||||
Assert.AreEqual(1, b);
|
||||
|
||||
reader.Seek(10);
|
||||
Assert.AreEqual(reader.Position, writer.Length);
|
||||
Assert.AreEqual(reader.Length, writer.Length);
|
||||
|
||||
reader.Seek(2);
|
||||
reader.ReadByteSafe(out b);
|
||||
Assert.AreEqual(2, b);
|
||||
|
||||
reader.Seek(1);
|
||||
reader.ReadByteSafe(out b);
|
||||
Assert.AreEqual(3, b);
|
||||
|
||||
reader.Seek(4);
|
||||
reader.ReadByteSafe(out b);
|
||||
Assert.AreEqual(4, b);
|
||||
|
||||
reader.Seek(3);
|
||||
reader.ReadByteSafe(out b);
|
||||
Assert.AreEqual(5, b);
|
||||
|
||||
Assert.AreEqual(reader.Position, 4);
|
||||
Assert.AreEqual(reader.Length, writer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public unsafe void WhenCallingTryBeginReadInternal_AllowedReadPositionDoesNotMoveBackward()
|
||||
{
|
||||
var reader = new FastBufferReader(new NativeArray<byte>(100, Allocator.Temp), Allocator.Temp);
|
||||
using (reader)
|
||||
{
|
||||
reader.TryBeginRead(25);
|
||||
reader.TryBeginReadInternal(5);
|
||||
Assert.AreEqual(reader.Handle->AllowedReadMark, 25);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Serialization/FastBufferReaderTests.cs.meta
Normal file
11
Tests/Editor/Serialization/FastBufferReaderTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2881f8138b479c34389b76687e5307ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1069
Tests/Editor/Serialization/FastBufferWriterTests.cs
Normal file
1069
Tests/Editor/Serialization/FastBufferWriterTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Tests/Editor/Serialization/FastBufferWriterTests.cs.meta
Normal file
11
Tests/Editor/Serialization/FastBufferWriterTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1cef42b60935e29469ed1404fb30ba2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
73
Tests/Editor/SnapshotRttTests.cs
Normal file
73
Tests/Editor/SnapshotRttTests.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class SnapshotRttTests
|
||||
{
|
||||
private const double k_Epsilon = 0.0001;
|
||||
|
||||
[Test]
|
||||
public void TestBasicRtt()
|
||||
{
|
||||
var snapshot = new SnapshotSystem(default);
|
||||
var client1 = snapshot.GetConnectionRtt(0);
|
||||
|
||||
client1.NotifySend(0, 0.0);
|
||||
client1.NotifySend(1, 10.0);
|
||||
|
||||
client1.NotifyAck(1, 15.0);
|
||||
|
||||
client1.NotifySend(2, 20.0);
|
||||
client1.NotifySend(3, 30.0);
|
||||
client1.NotifySend(4, 32.0);
|
||||
|
||||
client1.NotifyAck(4, 38.0);
|
||||
client1.NotifyAck(3, 40.0);
|
||||
|
||||
ConnectionRtt.Rtt ret = client1.GetRtt();
|
||||
Assert.True(ret.AverageSec < 7.0 + k_Epsilon);
|
||||
Assert.True(ret.AverageSec > 7.0 - k_Epsilon);
|
||||
Assert.True(ret.WorstSec < 10.0 + k_Epsilon);
|
||||
Assert.True(ret.WorstSec > 10.0 - k_Epsilon);
|
||||
Assert.True(ret.BestSec < 5.0 + k_Epsilon);
|
||||
Assert.True(ret.BestSec > 5.0 - k_Epsilon);
|
||||
|
||||
// note: `last` latency is latest received Ack, not latest sent sequence.
|
||||
Assert.True(ret.LastSec < 10.0 + k_Epsilon);
|
||||
Assert.True(ret.LastSec > 10.0 - k_Epsilon);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEdgeCasesRtt()
|
||||
{
|
||||
var snapshot = new SnapshotSystem(NetworkManager.Singleton);
|
||||
var client1 = snapshot.GetConnectionRtt(0);
|
||||
var iterationCount = NetworkConfig.RttWindowSize * 3;
|
||||
var extraCount = NetworkConfig.RttWindowSize * 2;
|
||||
|
||||
// feed in some messages
|
||||
for (var iteration = 0; iteration < iterationCount; iteration++)
|
||||
{
|
||||
client1.NotifySend(iteration, 25.0 * iteration);
|
||||
}
|
||||
// ack some random ones in there (1 out of each 9), always 7.0 later
|
||||
for (var iteration = 0; iteration < iterationCount; iteration += 9)
|
||||
{
|
||||
client1.NotifyAck(iteration, 25.0 * iteration + 7.0);
|
||||
}
|
||||
// ack some unused key, to check it doesn't throw off the values
|
||||
for (var iteration = iterationCount; iteration < iterationCount + extraCount; iteration++)
|
||||
{
|
||||
client1.NotifyAck(iteration, 42.0);
|
||||
}
|
||||
|
||||
ConnectionRtt.Rtt ret = client1.GetRtt();
|
||||
Assert.True(ret.AverageSec < 7.0 + k_Epsilon);
|
||||
Assert.True(ret.AverageSec > 7.0 - k_Epsilon);
|
||||
Assert.True(ret.WorstSec < 7.0 + k_Epsilon);
|
||||
Assert.True(ret.WorstSec > 7.0 - k_Epsilon);
|
||||
Assert.True(ret.BestSec < 7.0 + k_Epsilon);
|
||||
Assert.True(ret.BestSec > 7.0 - k_Epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/SnapshotRttTests.cs.meta
Normal file
11
Tests/Editor/SnapshotRttTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a05afab7f08d44c07b2c5e144ba0b45a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Tests/Editor/StartStopTests.cs
Normal file
62
Tests/Editor/StartStopTests.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class StartStopTests
|
||||
{
|
||||
private NetworkManager m_NetworkManager;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
// Create the reusable NetworkManager
|
||||
m_NetworkManager = new GameObject(nameof(NetworkManager)).AddComponent<NetworkManager>();
|
||||
var transport = m_NetworkManager.gameObject.AddComponent<DummyTransport>();
|
||||
|
||||
m_NetworkManager.NetworkConfig = new NetworkConfig()
|
||||
{
|
||||
NetworkTransport = transport
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStopAndRestartForExceptions()
|
||||
{
|
||||
m_NetworkManager.StartServer();
|
||||
m_NetworkManager.Shutdown();
|
||||
m_NetworkManager.StartServer();
|
||||
m_NetworkManager.Shutdown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStartupServerState()
|
||||
{
|
||||
m_NetworkManager.StartServer();
|
||||
|
||||
Assert.True(m_NetworkManager.IsServer);
|
||||
Assert.False(m_NetworkManager.IsClient);
|
||||
Assert.False(m_NetworkManager.IsHost);
|
||||
|
||||
m_NetworkManager.Shutdown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFlagShutdown()
|
||||
{
|
||||
m_NetworkManager.StartServer();
|
||||
m_NetworkManager.Shutdown();
|
||||
|
||||
Assert.False(m_NetworkManager.IsServer);
|
||||
Assert.False(m_NetworkManager.IsClient);
|
||||
Assert.False(m_NetworkManager.IsHost);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
// Cleanup
|
||||
Object.DestroyImmediate(m_NetworkManager.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Editor/StartStopTests.cs.meta
Normal file
3
Tests/Editor/StartStopTests.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8e36047cb5542bcaade2a9a8746d713
|
||||
timeCreated: 1630336158
|
||||
8
Tests/Editor/Timing.meta
Normal file
8
Tests/Editor/Timing.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff3d73d1a9b7596419b0f389d0219f31
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
182
Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs
Normal file
182
Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests for running a <see cref="NetworkTimeSystem"/> as a client.
|
||||
/// </summary>
|
||||
public class ClientNetworkTimeSystemTests
|
||||
{
|
||||
private const double k_AcceptableRttOffset = 0.03d; // 30ms offset is fine
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether time is stable if RTT is stable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void StableRttTest()
|
||||
{
|
||||
double receivedServerTime = 2;
|
||||
|
||||
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, 0.1d);
|
||||
timeSystem.Reset(receivedServerTime, 0.15);
|
||||
var tickSystem = new NetworkTickSystem(60, timeSystem.LocalTime, timeSystem.ServerTime);
|
||||
|
||||
Assert.True(timeSystem.LocalTime > 2);
|
||||
|
||||
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, 0.1f, 42);
|
||||
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, 0.095f, 0.105f, 42); // 10ms jitter
|
||||
|
||||
// run for a while so that we reach regular RTT offset
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
|
||||
{
|
||||
// sync network stats
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps[step]);
|
||||
});
|
||||
|
||||
// check how we close we are to target time.
|
||||
var expectedRtt = 0.1d;
|
||||
var offsetToTarget = (timeSystem.LocalTime - timeSystem.ServerTime) - expectedRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec;
|
||||
Debug.Log($"offset to target time after running for a while: {offsetToTarget}");
|
||||
Assert.IsTrue(Math.Abs(offsetToTarget) < k_AcceptableRttOffset);
|
||||
|
||||
// run again, test that we never need to speed up or slow down under stable RTT
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
|
||||
{
|
||||
// sync network stats
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps[step]);
|
||||
});
|
||||
|
||||
// check again to ensure we are still close to the target
|
||||
var newOffsetToTarget = (timeSystem.LocalTime - timeSystem.ServerTime) - expectedRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec;
|
||||
Debug.Log($"offset to target time after running longer: {newOffsetToTarget}");
|
||||
Assert.IsTrue(Math.Abs(newOffsetToTarget) < k_AcceptableRttOffset);
|
||||
|
||||
// difference between first and second offset should be minimal
|
||||
var dif = offsetToTarget - newOffsetToTarget;
|
||||
Assert.IsTrue(Math.Abs(dif) < 0.01d); // less than 10ms
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether local time can speed up and slow down to catch up when RTT changes.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void RttCatchupSlowdownTest()
|
||||
{
|
||||
double receivedServerTime = 2;
|
||||
|
||||
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, 0.1d);
|
||||
timeSystem.Reset(receivedServerTime, 0.15);
|
||||
var tickSystem = new NetworkTickSystem(60, timeSystem.LocalTime, timeSystem.ServerTime);
|
||||
|
||||
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, 0.1f, 42);
|
||||
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, 0.095f, 0.105f, 42); // 10ms jitter
|
||||
|
||||
// run for a while so that we reach regular RTT offset
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
|
||||
{
|
||||
// sync network stats
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps[step]);
|
||||
});
|
||||
|
||||
// increase RTT to ~200ms from ~100ms
|
||||
var rttSteps2 = TimingTestHelper.GetRandomTimeSteps(1000f, 0.195f, 0.205f, 42);
|
||||
|
||||
double unscaledLocalTime = timeSystem.LocalTime;
|
||||
double unscaledServerTime = timeSystem.ServerTime;
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
|
||||
{
|
||||
// sync network stats
|
||||
unscaledLocalTime += steps[step];
|
||||
unscaledServerTime += steps[step];
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps2[step]);
|
||||
});
|
||||
|
||||
var totalLocalSpeedUpTime = timeSystem.LocalTime - unscaledLocalTime;
|
||||
var totalServerSpeedUpTime = timeSystem.ServerTime - unscaledServerTime;
|
||||
|
||||
// speed up of 0.1f expected
|
||||
Debug.Log($"Total local speed up time catch up: {totalLocalSpeedUpTime}");
|
||||
Assert.True(Math.Abs(totalLocalSpeedUpTime - 0.1) < k_AcceptableRttOffset);
|
||||
Assert.True(Math.Abs(totalServerSpeedUpTime) < k_AcceptableRttOffset); // server speedup/slowdowns should not be affected by RTT
|
||||
|
||||
|
||||
// run again with RTT ~100ms and see whether we slow down by -0.1f
|
||||
unscaledLocalTime = timeSystem.LocalTime;
|
||||
unscaledServerTime = timeSystem.ServerTime;
|
||||
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
|
||||
{
|
||||
// sync network stats
|
||||
unscaledLocalTime += steps[step];
|
||||
unscaledServerTime += steps[step];
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps[step]);
|
||||
});
|
||||
|
||||
totalLocalSpeedUpTime = timeSystem.LocalTime - unscaledLocalTime;
|
||||
totalServerSpeedUpTime = timeSystem.ServerTime - unscaledServerTime;
|
||||
|
||||
// slow down of 0.1f expected
|
||||
Debug.Log($"Total local speed up time slow down: {totalLocalSpeedUpTime}");
|
||||
Assert.True(Math.Abs(totalLocalSpeedUpTime + 0.1) < k_AcceptableRttOffset);
|
||||
Assert.True(Math.Abs(totalServerSpeedUpTime) < k_AcceptableRttOffset); // server speedup/slowdowns should not be affected by RTT
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether time resets when there is a huge spike in RTT and is able to stabilize again.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ResetTest()
|
||||
{
|
||||
double receivedServerTime = 2;
|
||||
|
||||
var timeSystem = new NetworkTimeSystem(0.05d, 0.05d, 0.1d);
|
||||
timeSystem.Reset(receivedServerTime, 0.15);
|
||||
var tickSystem = new NetworkTickSystem(60, timeSystem.LocalTime, timeSystem.ServerTime);
|
||||
|
||||
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, 0.1f, 42);
|
||||
var rttSteps = TimingTestHelper.GetRandomTimeSteps(1000f, 0.095f, 0.105f, 42); // 10ms jitter
|
||||
|
||||
// run for a while so that we reach regular RTT offset
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step)
|
||||
{
|
||||
// sync network stats
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps[step]);
|
||||
});
|
||||
|
||||
|
||||
// increase RTT to ~500ms from ~100ms
|
||||
var rttSteps2 = TimingTestHelper.GetRandomTimeSteps(1000f, 0.495f, 0.505f, 42);
|
||||
|
||||
// run a single advance expect a hard rest
|
||||
|
||||
receivedServerTime += 1 / 60d;
|
||||
timeSystem.Sync(receivedServerTime, 0.5);
|
||||
bool reset = timeSystem.Advance(1 / 60d);
|
||||
Assert.IsTrue(reset);
|
||||
|
||||
TimingTestHelper.ApplySteps(timeSystem, tickSystem, steps, delegate (int step, bool reset)
|
||||
{
|
||||
Assert.IsFalse(reset);
|
||||
|
||||
// sync network stats
|
||||
receivedServerTime += steps[step];
|
||||
timeSystem.Sync(receivedServerTime, rttSteps2[step]);
|
||||
|
||||
// after hard reset time should stay close to rtt
|
||||
var expectedRtt = 0.5d;
|
||||
Assert.IsTrue(Math.Abs((timeSystem.LocalTime - timeSystem.ServerTime) - expectedRtt - timeSystem.ServerBufferSec - timeSystem.LocalBufferSec) < k_AcceptableRttOffset);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs.meta
Normal file
11
Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1cd95d37c9e3f904ba19b1fcf33123c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
207
Tests/Editor/Timing/NetworkTimeTests.cs
Normal file
207
Tests/Editor/Timing/NetworkTimeTests.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class NetworkTimeTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase(0d, 0u)]
|
||||
[TestCase(5d, 0u)]
|
||||
[TestCase(-5d, 0u)]
|
||||
public void TestFailCreateInvalidTime(double time, uint tickrate)
|
||||
{
|
||||
Assert.Throws<UnityEngine.Assertions.AssertionException>(() => new NetworkTime(tickrate, time));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(0d, 0f, 20u)]
|
||||
[TestCase(0d, 0f, 30u)]
|
||||
[TestCase(0d, 0f, 60u)]
|
||||
[TestCase(201d, 201f, 20u)]
|
||||
[TestCase(201d, 201f, 30u)]
|
||||
[TestCase(201d, 201f, 60u)]
|
||||
[TestCase(-4301d, -4301f, 20u)]
|
||||
[TestCase(-4301d, -4301f, 30u)]
|
||||
[TestCase(-4301d, -4301f, 60u)]
|
||||
[TestCase(float.MaxValue, float.MaxValue, 20u)]
|
||||
[TestCase(float.MaxValue, float.MaxValue, 30u)]
|
||||
[TestCase(float.MaxValue, float.MaxValue, 60u)]
|
||||
public void TestTimeAsFloat(double d, float f, uint tickRate)
|
||||
{
|
||||
var networkTime = new NetworkTime(tickRate, d);
|
||||
Assert.True(Mathf.Approximately(networkTime.TimeAsFloat, f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(53.55d, 53.5d, 10u)]
|
||||
[TestCase(1013553.55d, 1013553.5d, 10u)]
|
||||
[TestCase(0d, 0d, 10u)]
|
||||
[TestCase(-27.41d, -27.5d, 10u)]
|
||||
[TestCase(53.55d, 53.54d, 50u)]
|
||||
[TestCase(1013553.55d, 1013553.54d, 50u)]
|
||||
[TestCase(0d, 0d, 50u)]
|
||||
[TestCase(-27.4133d, -27.42d, 50u)]
|
||||
public void TestToFixedTime(double time, double expectedFixedTime, uint tickRate)
|
||||
{
|
||||
Assert.AreEqual(expectedFixedTime, new NetworkTime(tickRate, time).ToFixedTime().Time);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(34d, 0)]
|
||||
[TestCase(17.32d, 0.2d / 60d)]
|
||||
[TestCase(-42.44d, 1d / 60d - 0.4d / 60d)]
|
||||
[TestCase(-6d, 0)]
|
||||
[TestCase(int.MaxValue / 61d, 0.00082, 10d)] // Int.Max / 61 / (1/60) to get divisor then: Int.Max - divisor * 1 / 60
|
||||
public void NetworkTimeCreate(double time, double tickOffset, double epsilon = 0.0001d)
|
||||
{
|
||||
var networkTime = new NetworkTime(60, time);
|
||||
|
||||
Assert.IsTrue(Approximately(time, networkTime.Time));
|
||||
Assert.IsTrue(Approximately(networkTime.Tick * networkTime.FixedDeltaTime + networkTime.TickOffset, networkTime.Time, epsilon));
|
||||
Assert.IsTrue(Approximately(networkTime.TickOffset, tickOffset));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NetworkTimeDefault()
|
||||
{
|
||||
NetworkTime defaultTime = default;
|
||||
|
||||
Assert.IsTrue(defaultTime.Time == 0f);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(17.32d)]
|
||||
[TestCase(34d)]
|
||||
[TestCase(-42.4d)]
|
||||
[TestCase(-6d)]
|
||||
[TestCase(int.MaxValue / 61d)]
|
||||
public void NetworkTimeAddFloatTest(double time)
|
||||
{
|
||||
double a = 34d;
|
||||
double floatResultB = a + time;
|
||||
|
||||
var timeA = new NetworkTime(60, a);
|
||||
NetworkTime timeB = timeA + time;
|
||||
|
||||
Assert.IsTrue(Approximately(floatResultB, timeB.Time));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(17.32d)]
|
||||
[TestCase(34d)]
|
||||
[TestCase(-42.4d)]
|
||||
[TestCase(-6d)]
|
||||
[TestCase(int.MaxValue / 61d)]
|
||||
public void NetworkTimeSubFloatTest(double time)
|
||||
{
|
||||
double a = 34d;
|
||||
double floatResultB = a - time;
|
||||
|
||||
var timeA = new NetworkTime(60, a);
|
||||
NetworkTime timeB = timeA - time;
|
||||
|
||||
Assert.IsTrue(Approximately(floatResultB, timeB.Time));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(17.32d)]
|
||||
[TestCase(34d)]
|
||||
[TestCase(-42.4d)]
|
||||
[TestCase(-6d)]
|
||||
[TestCase(int.MaxValue / 61d)]
|
||||
public void NetworkTimeAddNetworkTimeTest(double time)
|
||||
{
|
||||
double a = 34d;
|
||||
double floatResultB = a + time;
|
||||
|
||||
var timeA = new NetworkTime(60, a);
|
||||
NetworkTime timeB = timeA + new NetworkTime(60, time);
|
||||
Assert.IsTrue(Approximately(floatResultB, timeB.Time));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(17.32d)]
|
||||
[TestCase(34d)]
|
||||
[TestCase(-42.4d)]
|
||||
[TestCase(-6d)]
|
||||
[TestCase(int.MaxValue / 61d)]
|
||||
public void NetworkTimeSubNetworkTimeTest(double time)
|
||||
{
|
||||
double a = 34d;
|
||||
|
||||
double floatResultB = a - time;
|
||||
|
||||
var timeA = new NetworkTime(60, a);
|
||||
NetworkTime timeB = timeA - new NetworkTime(60, time);
|
||||
Assert.IsTrue(Approximately(floatResultB, timeB.Time));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NetworkTimeAdvanceTest()
|
||||
{
|
||||
var random = new Random(42);
|
||||
var randomSteps = Enumerable.Repeat(0f, 1000).Select(t => Mathf.Lerp(1 / 25f, 1.80f, (float)random.NextDouble())).ToList();
|
||||
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 60, 0f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 1, 0f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 10, 0f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 20, 0f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 30, 0f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 144, 0f);
|
||||
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 60, 23132.231f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 1, 23132.231f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 10, 23132.231f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 20, 23132.231f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 30, 23132.231f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 30, 23132.231f);
|
||||
NetworkTimeAdvanceTestInternal(randomSteps, 144, 23132.231f);
|
||||
|
||||
var shortSteps = Enumerable.Repeat(1 / 30f, 1000);
|
||||
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 60, 0f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 1, 0f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 10, 0f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 20, 0f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 30, 0f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 144, 0f);
|
||||
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 60, 1000000f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 60, 1000000f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 1, 1000000f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 10, 1000000f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 20, 1000000f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 30, 1000000f);
|
||||
NetworkTimeAdvanceTestInternal(shortSteps, 144, 1000000f);
|
||||
}
|
||||
|
||||
private void NetworkTimeAdvanceTestInternal(IEnumerable<float> steps, uint tickRate, float start, float start2 = 0f)
|
||||
{
|
||||
float maxAcceptableTotalOffset = 0.005f;
|
||||
|
||||
var startTime = new NetworkTime(tickRate, start);
|
||||
var startTime2 = new NetworkTime(tickRate, start2);
|
||||
NetworkTime dif = startTime2 - startTime;
|
||||
|
||||
foreach (var step in steps)
|
||||
{
|
||||
startTime += step;
|
||||
startTime2 += step;
|
||||
Assert.IsTrue(Approximately(startTime.Time, (startTime2 - dif).Time));
|
||||
}
|
||||
|
||||
Assert.IsTrue(Approximately(startTime.Time, (startTime2 - dif).Time, maxAcceptableTotalOffset));
|
||||
}
|
||||
|
||||
private static bool Approximately(double a, double b, double epsilon = 0.000001d)
|
||||
{
|
||||
var dif = Math.Abs(a - b);
|
||||
return dif <= epsilon;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Editor/Timing/NetworkTimeTests.cs.meta
Normal file
11
Tests/Editor/Timing/NetworkTimeTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c9814eeb95ebba4d8cbb67deab9369b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
35
Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs
Normal file
35
Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
public class ServerNetworkTimeSystemTests
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// On the server local time should always be equal to server time. This test ensures that this is the case.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void LocalTimeEqualServerTimeTest()
|
||||
{
|
||||
var steps = TimingTestHelper.GetRandomTimeSteps(100f, 0.01f, 0.1f, 42);
|
||||
|
||||
var serverTimeSystem = NetworkTimeSystem.ServerTimeSystem();
|
||||
var serverTickSystem = new NetworkTickSystem(60, 0, 0);
|
||||
|
||||
serverTimeSystem.Reset(0.5d, 0);
|
||||
|
||||
TimingTestHelper.ApplySteps(serverTimeSystem, serverTickSystem, steps, step =>
|
||||
{
|
||||
Assert.IsTrue(Mathf.Approximately((float)serverTimeSystem.LocalTime, (float)serverTimeSystem.ServerTime));
|
||||
Assert.IsTrue(Mathf.Approximately((float)serverTickSystem.LocalTime.Time, (float)serverTimeSystem.ServerTime));
|
||||
});
|
||||
|
||||
Assert.IsTrue(serverTimeSystem.LocalTime > 1d);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs.meta
Normal file
11
Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 970d8f921595c7249a5ffc92fd74c7fc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
63
Tests/Editor/Timing/TimingTestHelper.cs
Normal file
63
Tests/Editor/Timing/TimingTestHelper.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Random = System.Random;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper functions for timing related tests. Allows to get a set of time steps and simulate time advancing without the need of a full playmode test.
|
||||
/// </summary>
|
||||
public static class TimingTestHelper
|
||||
{
|
||||
public static List<float> GetRandomTimeSteps(float totalDuration, float min, float max, int seed)
|
||||
{
|
||||
var random = new Random(seed);
|
||||
var steps = new List<float>();
|
||||
|
||||
while (totalDuration > 0f)
|
||||
{
|
||||
var next = Mathf.Lerp(min, max, (float)random.NextDouble());
|
||||
steps.Add(next);
|
||||
totalDuration -= next;
|
||||
}
|
||||
|
||||
// correct overshoot at the end
|
||||
steps[steps.Count - 1] -= totalDuration;
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
public delegate void StepCheckDelegate(int step);
|
||||
|
||||
public delegate void StepCheckResetDelegate(int step, bool reset);
|
||||
|
||||
public static void ApplySteps(NetworkTimeSystem timeSystem, NetworkTickSystem tickSystem, List<float> steps, StepCheckDelegate stepCheck = null)
|
||||
{
|
||||
for (var i = 0; i < steps.Count; i++)
|
||||
{
|
||||
var step = steps[i];
|
||||
timeSystem.Advance(step);
|
||||
tickSystem.UpdateTick(timeSystem.LocalTime, timeSystem.ServerTime);
|
||||
if (stepCheck != null)
|
||||
{
|
||||
stepCheck(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplySteps(NetworkTimeSystem timeSystem, NetworkTickSystem tickSystem, List<float> steps, StepCheckResetDelegate stepCheck = null)
|
||||
{
|
||||
for (var i = 0; i < steps.Count; i++)
|
||||
{
|
||||
var step = steps[i];
|
||||
var reset = timeSystem.Advance(step);
|
||||
tickSystem.UpdateTick(timeSystem.LocalTime, timeSystem.ServerTime);
|
||||
if (stepCheck != null)
|
||||
{
|
||||
stepCheck(i, reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
Tests/Editor/Timing/TimingTestHelper.cs.meta
Normal file
11
Tests/Editor/Timing/TimingTestHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9010f986d5ecb994a8dd34076ff41c8e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Tests/Editor/UI.meta
Normal file
3
Tests/Editor/UI.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f672293e0efc41a6a7e930fd7ff14436
|
||||
timeCreated: 1631650280
|
||||
15
Tests/Editor/UI/UITestHelpers.cs
Normal file
15
Tests/Editor/UI/UITestHelpers.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Unity.Netcode.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.EditorTests
|
||||
{
|
||||
internal static class UITestHelpers
|
||||
{
|
||||
[MenuItem("Netcode/UI/Reset Multiplayer Tools Tip Status")]
|
||||
private static void ResetMultiplayerToolsTipStatus()
|
||||
{
|
||||
PlayerPrefs.DeleteKey(NetworkManagerEditor.InstallMultiplayerToolsTipDismissedPlayerPrefKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Editor/UI/UITestHelpers.cs.meta
Normal file
3
Tests/Editor/UI/UITestHelpers.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bde5fc3349494f77bebd0be12a6957e1
|
||||
timeCreated: 1631650292
|
||||
36
Tests/Editor/com.unity.netcode.editortests.asmdef
Normal file
36
Tests/Editor/com.unity.netcode.editortests.asmdef
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "Unity.Netcode.EditorTests",
|
||||
"rootNamespace": "Unity.Netcode.EditorTests",
|
||||
"references": [
|
||||
"Unity.Netcode.Runtime",
|
||||
"Unity.Netcode.Editor",
|
||||
"Unity.Netcode.Components",
|
||||
"Unity.Multiplayer.MetricTypes",
|
||||
"Unity.Multiplayer.NetStats"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false,
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.multiplayer.tools",
|
||||
"expression": "",
|
||||
"define": "MULTIPLAYER_TOOLS"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
Tests/Editor/com.unity.netcode.editortests.asmdef.meta
Normal file
7
Tests/Editor/com.unity.netcode.editortests.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 072b82e2b7c1dcf439827d3fbc4f52a1
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Tests/Runtime.meta
Normal file
8
Tests/Runtime.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d3a545f9ce7b074c95a3b1c3101dee9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
5
Tests/Runtime/AssemblyInfo.cs
Normal file
5
Tests/Runtime/AssemblyInfo.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("TestProject.EditorTests")]
|
||||
[assembly: InternalsVisibleTo("TestProject.RuntimeTests")]
|
||||
[assembly: InternalsVisibleTo("TestProject.ToolsIntegration.RuntimeTests")]
|
||||
11
Tests/Runtime/AssemblyInfo.cs.meta
Normal file
11
Tests/Runtime/AssemblyInfo.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5751b3c3bb5621e4686249b8083be068
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
178
Tests/Runtime/BaseMultiInstanceTest.cs
Normal file
178
Tests/Runtime/BaseMultiInstanceTest.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TestTools;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public abstract class BaseMultiInstanceTest
|
||||
{
|
||||
private const string k_FirstPartOfTestRunnerSceneName = "InitTestScene";
|
||||
|
||||
protected GameObject m_PlayerPrefab;
|
||||
protected NetworkManager m_ServerNetworkManager;
|
||||
protected NetworkManager[] m_ClientNetworkManagers;
|
||||
|
||||
protected abstract int NbClients { get; }
|
||||
|
||||
protected bool m_BypassStartAndWaitForClients = false;
|
||||
|
||||
[UnitySetUp]
|
||||
public virtual IEnumerator Setup()
|
||||
{
|
||||
yield return StartSomeClientsAndServerWithPlayers(true, NbClients, _ => { });
|
||||
}
|
||||
|
||||
[UnityTearDown]
|
||||
public virtual IEnumerator Teardown()
|
||||
{
|
||||
// Shutdown and clean up both of our NetworkManager instances
|
||||
try
|
||||
{
|
||||
MultiInstanceHelpers.Destroy();
|
||||
}
|
||||
catch (Exception e) { throw e; }
|
||||
finally
|
||||
{
|
||||
if (m_PlayerPrefab != null)
|
||||
{
|
||||
Object.Destroy(m_PlayerPrefab);
|
||||
m_PlayerPrefab = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure any NetworkObject with a GlobalObjectIdHash value of 0 is destroyed
|
||||
// If we are tearing down, we don't want to leave NetworkObjects hanging around
|
||||
var networkObjects = Object.FindObjectsOfType<NetworkObject>().ToList();
|
||||
foreach (var networkObject in networkObjects)
|
||||
{
|
||||
Object.DestroyImmediate(networkObject);
|
||||
}
|
||||
|
||||
// wait for next frame so everything is destroyed, so following tests can execute from clean environment
|
||||
int nextFrameNumber = Time.frameCount + 1;
|
||||
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We want to exclude the TestRunner scene on the host-server side so it won't try to tell clients to
|
||||
/// synchronize to this scene when they connect
|
||||
/// </summary>
|
||||
private static bool VerifySceneIsValidForClientsToLoad(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode)
|
||||
{
|
||||
// exclude test runner scene
|
||||
if (sceneName.StartsWith(k_FirstPartOfTestRunnerSceneName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This registers scene validation callback for the server to prevent it from telling connecting
|
||||
/// clients to synchronize (i.e. load) the test runner scene. This will also register the test runner
|
||||
/// scene and its handle for both client(s) and server-host.
|
||||
/// </summary>
|
||||
public static void SceneManagerValidationAndTestRunnerInitialization(NetworkManager networkManager)
|
||||
{
|
||||
// If VerifySceneBeforeLoading is not already set, then go ahead and set it so the host/server
|
||||
// will not try to synchronize clients to the TestRunner scene. We only need to do this for the server.
|
||||
if (networkManager.IsServer && networkManager.SceneManager.VerifySceneBeforeLoading == null)
|
||||
{
|
||||
networkManager.SceneManager.VerifySceneBeforeLoading = VerifySceneIsValidForClientsToLoad;
|
||||
// If a unit/integration test does not handle this on their own, then Ignore the validation warning
|
||||
networkManager.SceneManager.DisableValidationWarnings(true);
|
||||
}
|
||||
|
||||
// Register the test runner scene so it will be able to synchronize NetworkObjects without logging a
|
||||
// warning about using the currently active scene
|
||||
var scene = SceneManager.GetActiveScene();
|
||||
// As long as this is a test runner scene (or most likely a test runner scene)
|
||||
if (scene.name.StartsWith(k_FirstPartOfTestRunnerSceneName))
|
||||
{
|
||||
// Register the test runner scene just so we avoid another warning about not being able to find the
|
||||
// scene to synchronize NetworkObjects. Next, add the currently active test runner scene to the scenes
|
||||
// loaded and register the server to client scene handle since host-server shares the test runner scene
|
||||
// with the clients.
|
||||
networkManager.SceneManager.GetAndAddNewlyLoadedSceneByName(scene.name);
|
||||
networkManager.SceneManager.ServerSceneHandleToClientSceneHandle.Add(scene.handle, scene.handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility to spawn some clients and a server and set them up
|
||||
/// </summary>
|
||||
/// <param name="nbClients"></param>
|
||||
/// <param name="updatePlayerPrefab">Update the prefab with whatever is needed before players spawn</param>
|
||||
/// <param name="targetFrameRate">The targetFrameRate of the Unity engine to use while this multi instance test is running. Will be reset on teardown.</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerator StartSomeClientsAndServerWithPlayers(bool useHost, int nbClients, Action<GameObject> updatePlayerPrefab = null, int targetFrameRate = 60)
|
||||
{
|
||||
// Make sure any NetworkObject with a GlobalObjectIdHash value of 0 is destroyed
|
||||
// If we are tearing down, we don't want to leave NetworkObjects hanging around
|
||||
var networkObjects = Object.FindObjectsOfType<NetworkObject>().ToList();
|
||||
var networkObjectsList = networkObjects.Where(c => c.GlobalObjectIdHash == 0);
|
||||
foreach (var netObject in networkObjects)
|
||||
{
|
||||
Object.DestroyImmediate(netObject);
|
||||
}
|
||||
|
||||
// Create multiple NetworkManager instances
|
||||
if (!MultiInstanceHelpers.Create(nbClients, out NetworkManager server, out NetworkManager[] clients, targetFrameRate))
|
||||
{
|
||||
Debug.LogError("Failed to create instances");
|
||||
Assert.Fail("Failed to create instances");
|
||||
}
|
||||
|
||||
m_ClientNetworkManagers = clients;
|
||||
m_ServerNetworkManager = server;
|
||||
|
||||
// Create playerPrefab
|
||||
m_PlayerPrefab = new GameObject("Player");
|
||||
NetworkObject networkObject = m_PlayerPrefab.AddComponent<NetworkObject>();
|
||||
/*
|
||||
* Normally we would only allow player prefabs to be set to a prefab. Not runtime created objects.
|
||||
* In order to prevent having a Resource folder full of a TON of prefabs that we have to maintain,
|
||||
* MultiInstanceHelper has a helper function that lets you mark a runtime created object to be
|
||||
* treated as a prefab by the Netcode. That's how we can get away with creating the player prefab
|
||||
* at runtime without it being treated as a SceneObject or causing other conflicts with the Netcode.
|
||||
*/
|
||||
// Make it a prefab
|
||||
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
if (updatePlayerPrefab != null)
|
||||
{
|
||||
updatePlayerPrefab(m_PlayerPrefab); // update player prefab with whatever is needed before players are spawned
|
||||
}
|
||||
|
||||
// Set the player prefab
|
||||
server.NetworkConfig.PlayerPrefab = m_PlayerPrefab;
|
||||
|
||||
for (int i = 0; i < clients.Length; i++)
|
||||
{
|
||||
clients[i].NetworkConfig.PlayerPrefab = m_PlayerPrefab;
|
||||
}
|
||||
|
||||
if (!m_BypassStartAndWaitForClients)
|
||||
{
|
||||
// Start the instances and pass in our SceneManagerInitialization action that is invoked immediately after host-server
|
||||
// is started and after each client is started.
|
||||
if (!MultiInstanceHelpers.Start(useHost, server, clients, SceneManagerValidationAndTestRunnerInitialization))
|
||||
{
|
||||
Debug.LogError("Failed to start instances");
|
||||
Assert.Fail("Failed to start instances");
|
||||
}
|
||||
|
||||
// Wait for connection on client side
|
||||
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
|
||||
|
||||
// Wait for connection on server side
|
||||
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnectedToServer(server, useHost ? nbClients + 1 : nbClients));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Runtime/BaseMultiInstanceTest.cs.meta
Normal file
3
Tests/Runtime/BaseMultiInstanceTest.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 789a3189410645aca48f11a51c823418
|
||||
timeCreated: 1621620979
|
||||
8
Tests/Runtime/Components.meta
Normal file
8
Tests/Runtime/Components.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09f6601e441556642ab8217941b24e5c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
109
Tests/Runtime/Components/BufferDataValidationComponent.cs
Normal file
109
Tests/Runtime/Components/BufferDataValidationComponent.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Used in conjunction with the RpcQueueTest to validate from 1 byte to (n) MaximumBufferSize
|
||||
/// - Sending and Receiving a continually growing buffer up to (MaximumBufferSize)
|
||||
/// - Default maximum buffer size is 1MB
|
||||
/// </summary>
|
||||
public class BufferDataValidationComponent : NetworkBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows the external RPCQueueTest to begin testing or stop it
|
||||
/// </summary>
|
||||
public bool EnableTesting;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum size of the buffer to send
|
||||
/// </summary>
|
||||
public int MaximumBufferSize = 1 << 15;
|
||||
|
||||
/// <summary>
|
||||
/// The rate at which the buffer size increases until it reaches MaximumBufferSize
|
||||
/// (the default starting buffer size is 1 bytes)
|
||||
/// </summary>
|
||||
public int BufferSizeStart = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Is checked to determine if the test exited because it failed
|
||||
/// </summary>
|
||||
public bool TestFailed { get; internal set; }
|
||||
|
||||
private bool m_WaitForValidation;
|
||||
private int m_CurrentBufferSize;
|
||||
|
||||
private List<byte> m_SendBuffer;
|
||||
private List<byte> m_PreCalculatedBufferValues;
|
||||
|
||||
// Start is called before the first frame update
|
||||
private void Start()
|
||||
{
|
||||
m_WaitForValidation = false;
|
||||
m_CurrentBufferSize = BufferSizeStart;
|
||||
m_SendBuffer = new List<byte>(MaximumBufferSize + 1);
|
||||
m_PreCalculatedBufferValues = new List<byte>(MaximumBufferSize + 1);
|
||||
while (m_PreCalculatedBufferValues.Count <= MaximumBufferSize)
|
||||
{
|
||||
m_PreCalculatedBufferValues.Add((byte)Random.Range(0, 255));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns back whether the test has completed the total number of iterations
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsTestComplete()
|
||||
{
|
||||
if (m_CurrentBufferSize > MaximumBufferSize || TestFailed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
private void Update()
|
||||
{
|
||||
if (NetworkManager.Singleton.IsListening && EnableTesting && !IsTestComplete() && !m_WaitForValidation)
|
||||
{
|
||||
m_SendBuffer.Clear();
|
||||
//Keep the current contents of the bufffer and fill the buffer with the delta difference of the buffer's current size and new size from the m_PreCalculatedBufferValues
|
||||
m_SendBuffer.AddRange(m_PreCalculatedBufferValues.GetRange(0, m_CurrentBufferSize));
|
||||
|
||||
//Make sure we don't do anything until we finish validating buffer
|
||||
m_WaitForValidation = true;
|
||||
|
||||
//Send the buffer
|
||||
SendBufferServerRpc(m_SendBuffer.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server side RPC for testing
|
||||
/// </summary>
|
||||
/// <param name="parameters">server rpc parameters</param>
|
||||
[ServerRpc]
|
||||
private void SendBufferServerRpc(byte[] buffer)
|
||||
{
|
||||
TestFailed = !NetworkManagerHelper.BuffersMatch(0, buffer.Length, buffer, m_SendBuffer.ToArray());
|
||||
if (!TestFailed)
|
||||
{
|
||||
Debug.Log($"Tested buffer size of {m_SendBuffer.Count} -- OK");
|
||||
}
|
||||
|
||||
if (m_CurrentBufferSize == MaximumBufferSize)
|
||||
{
|
||||
m_CurrentBufferSize++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Increasse buffer size
|
||||
m_CurrentBufferSize = m_CurrentBufferSize << 1;
|
||||
}
|
||||
|
||||
m_WaitForValidation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1bb4bf89a220a8b409a4afb1f0f4eced
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
242
Tests/Runtime/Components/NetworkVariableTestComponent.cs
Normal file
242
Tests/Runtime/Components/NetworkVariableTestComponent.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
/// <summary>
|
||||
/// This provides coverage for all of the predefined NetworkVariable types
|
||||
/// The initial goal is for generalized full coverage of NetworkVariables:
|
||||
/// Covers all of the various constructor calls (i.e. various parameters or no parameters)
|
||||
/// Covers the local NetworkVariable's OnValueChanged functionality (i.e. when a specific type changes do we get a notification?)
|
||||
/// This was built as a NetworkBehaviour for further client-server unit testing patterns when this capability is available.
|
||||
/// </summary>
|
||||
internal class NetworkVariableTestComponent : NetworkBehaviour
|
||||
{
|
||||
private NetworkVariable<bool> m_NetworkVariableBool;
|
||||
private NetworkVariable<byte> m_NetworkVariableByte;
|
||||
private NetworkVariable<Color> m_NetworkVariableColor;
|
||||
private NetworkVariable<Color32> m_NetworkVariableColor32;
|
||||
private NetworkVariable<double> m_NetworkVariableDouble;
|
||||
private NetworkVariable<float> m_NetworkVariableFloat;
|
||||
private NetworkVariable<int> m_NetworkVariableInt;
|
||||
private NetworkVariable<long> m_NetworkVariableLong;
|
||||
private NetworkVariable<sbyte> m_NetworkVariableSByte;
|
||||
private NetworkVariable<Quaternion> m_NetworkVariableQuaternion;
|
||||
private NetworkVariable<short> m_NetworkVariableShort;
|
||||
private NetworkVariable<Vector4> m_NetworkVariableVector4;
|
||||
private NetworkVariable<Vector3> m_NetworkVariableVector3;
|
||||
private NetworkVariable<Vector2> m_NetworkVariableVector2;
|
||||
private NetworkVariable<Ray> m_NetworkVariableRay;
|
||||
private NetworkVariable<ulong> m_NetworkVariableULong;
|
||||
private NetworkVariable<uint> m_NetworkVariableUInt;
|
||||
private NetworkVariable<ushort> m_NetworkVariableUShort;
|
||||
|
||||
|
||||
public NetworkVariableHelper<bool> Bool_Var;
|
||||
public NetworkVariableHelper<byte> Byte_Var;
|
||||
public NetworkVariableHelper<Color> Color_Var;
|
||||
public NetworkVariableHelper<Color32> Color32_Var;
|
||||
public NetworkVariableHelper<double> Double_Var;
|
||||
public NetworkVariableHelper<float> Float_Var;
|
||||
public NetworkVariableHelper<int> Int_Var;
|
||||
public NetworkVariableHelper<long> Long_Var;
|
||||
public NetworkVariableHelper<sbyte> Sbyte_Var;
|
||||
public NetworkVariableHelper<Quaternion> Quaternion_Var;
|
||||
public NetworkVariableHelper<short> Short_Var;
|
||||
public NetworkVariableHelper<Vector4> Vector4_Var;
|
||||
public NetworkVariableHelper<Vector3> Vector3_Var;
|
||||
public NetworkVariableHelper<Vector2> Vector2_Var;
|
||||
public NetworkVariableHelper<Ray> Ray_Var;
|
||||
public NetworkVariableHelper<ulong> Ulong_Var;
|
||||
public NetworkVariableHelper<uint> Uint_Var;
|
||||
public NetworkVariableHelper<ushort> Ushort_Var;
|
||||
|
||||
|
||||
public bool EnableTesting;
|
||||
private bool m_Initialized;
|
||||
private bool m_FinishedTests;
|
||||
private bool m_ChangesAppliedToNetworkVariables;
|
||||
|
||||
private float m_WaitForChangesTimeout;
|
||||
|
||||
// Start is called before the first frame update
|
||||
private void InitializeTest()
|
||||
{
|
||||
// Generic Constructor Test Coverage
|
||||
m_NetworkVariableBool = new NetworkVariable<bool>();
|
||||
m_NetworkVariableByte = new NetworkVariable<byte>();
|
||||
m_NetworkVariableColor = new NetworkVariable<Color>();
|
||||
m_NetworkVariableColor32 = new NetworkVariable<Color32>();
|
||||
m_NetworkVariableDouble = new NetworkVariable<double>();
|
||||
m_NetworkVariableFloat = new NetworkVariable<float>();
|
||||
m_NetworkVariableInt = new NetworkVariable<int>();
|
||||
m_NetworkVariableLong = new NetworkVariable<long>();
|
||||
m_NetworkVariableSByte = new NetworkVariable<sbyte>();
|
||||
m_NetworkVariableQuaternion = new NetworkVariable<Quaternion>();
|
||||
m_NetworkVariableShort = new NetworkVariable<short>();
|
||||
m_NetworkVariableVector4 = new NetworkVariable<Vector4>();
|
||||
m_NetworkVariableVector3 = new NetworkVariable<Vector3>();
|
||||
m_NetworkVariableVector2 = new NetworkVariable<Vector2>();
|
||||
m_NetworkVariableRay = new NetworkVariable<Ray>();
|
||||
m_NetworkVariableULong = new NetworkVariable<ulong>();
|
||||
m_NetworkVariableUInt = new NetworkVariable<uint>();
|
||||
m_NetworkVariableUShort = new NetworkVariable<ushort>();
|
||||
|
||||
|
||||
// NetworkVariable Value Type Constructor Test Coverage
|
||||
m_NetworkVariableBool = new NetworkVariable<bool>(true);
|
||||
m_NetworkVariableByte = new NetworkVariable<byte>((byte)0);
|
||||
m_NetworkVariableColor = new NetworkVariable<Color>(new Color(1, 1, 1, 1));
|
||||
m_NetworkVariableColor32 = new NetworkVariable<Color32>(new Color32(1, 1, 1, 1));
|
||||
m_NetworkVariableDouble = new NetworkVariable<double>(1.0);
|
||||
m_NetworkVariableFloat = new NetworkVariable<float>(1.0f);
|
||||
m_NetworkVariableInt = new NetworkVariable<int>(1);
|
||||
m_NetworkVariableLong = new NetworkVariable<long>(1);
|
||||
m_NetworkVariableSByte = new NetworkVariable<sbyte>((sbyte)0);
|
||||
m_NetworkVariableQuaternion = new NetworkVariable<Quaternion>(Quaternion.identity);
|
||||
m_NetworkVariableShort = new NetworkVariable<short>(256);
|
||||
m_NetworkVariableVector4 = new NetworkVariable<Vector4>(new Vector4(1, 1, 1, 1));
|
||||
m_NetworkVariableVector3 = new NetworkVariable<Vector3>(new Vector3(1, 1, 1));
|
||||
m_NetworkVariableVector2 = new NetworkVariable<Vector2>(new Vector2(1, 1));
|
||||
m_NetworkVariableRay = new NetworkVariable<Ray>(new Ray());
|
||||
m_NetworkVariableULong = new NetworkVariable<ulong>(1);
|
||||
m_NetworkVariableUInt = new NetworkVariable<uint>(1);
|
||||
m_NetworkVariableUShort = new NetworkVariable<ushort>(1);
|
||||
|
||||
m_NetworkVariableBool = new NetworkVariable<bool>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableByte = new NetworkVariable<byte>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableColor = new NetworkVariable<Color>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableColor32 = new NetworkVariable<Color32>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableDouble = new NetworkVariable<double>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableFloat = new NetworkVariable<float>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableInt = new NetworkVariable<int>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableLong = new NetworkVariable<long>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableSByte = new NetworkVariable<sbyte>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableQuaternion = new NetworkVariable<Quaternion>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableShort = new NetworkVariable<short>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableVector4 = new NetworkVariable<Vector4>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableVector3 = new NetworkVariable<Vector3>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableVector2 = new NetworkVariable<Vector2>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableRay = new NetworkVariable<Ray>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableULong = new NetworkVariable<ulong>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableUInt = new NetworkVariable<uint>(NetworkVariableReadPermission.Everyone);
|
||||
m_NetworkVariableUShort = new NetworkVariable<ushort>(NetworkVariableReadPermission.Everyone);
|
||||
|
||||
|
||||
// NetworkVariable Value Type and NetworkVariableSettings Constructor Test Coverage
|
||||
m_NetworkVariableBool = new NetworkVariable<bool>(NetworkVariableReadPermission.Everyone, true);
|
||||
m_NetworkVariableByte = new NetworkVariable<byte>(NetworkVariableReadPermission.Everyone, 0);
|
||||
m_NetworkVariableColor = new NetworkVariable<Color>(NetworkVariableReadPermission.Everyone, new Color(1, 1, 1, 1));
|
||||
m_NetworkVariableColor32 = new NetworkVariable<Color32>(NetworkVariableReadPermission.Everyone, new Color32(1, 1, 1, 1));
|
||||
m_NetworkVariableDouble = new NetworkVariable<double>(NetworkVariableReadPermission.Everyone, 1.0);
|
||||
m_NetworkVariableFloat = new NetworkVariable<float>(NetworkVariableReadPermission.Everyone, 1.0f);
|
||||
m_NetworkVariableInt = new NetworkVariable<int>(NetworkVariableReadPermission.Everyone, 1);
|
||||
m_NetworkVariableLong = new NetworkVariable<long>(NetworkVariableReadPermission.Everyone, 1);
|
||||
m_NetworkVariableSByte = new NetworkVariable<sbyte>(NetworkVariableReadPermission.Everyone, 0);
|
||||
m_NetworkVariableQuaternion = new NetworkVariable<Quaternion>(NetworkVariableReadPermission.Everyone, Quaternion.identity);
|
||||
m_NetworkVariableShort = new NetworkVariable<short>(NetworkVariableReadPermission.Everyone, 1);
|
||||
m_NetworkVariableVector4 = new NetworkVariable<Vector4>(NetworkVariableReadPermission.Everyone, new Vector4(1, 1, 1, 1));
|
||||
m_NetworkVariableVector3 = new NetworkVariable<Vector3>(NetworkVariableReadPermission.Everyone, new Vector3(1, 1, 1));
|
||||
m_NetworkVariableVector2 = new NetworkVariable<Vector2>(NetworkVariableReadPermission.Everyone, new Vector2(1, 1));
|
||||
m_NetworkVariableRay = new NetworkVariable<Ray>(NetworkVariableReadPermission.Everyone, new Ray());
|
||||
m_NetworkVariableULong = new NetworkVariable<ulong>(NetworkVariableReadPermission.Everyone, 1);
|
||||
m_NetworkVariableUInt = new NetworkVariable<uint>(NetworkVariableReadPermission.Everyone, 1);
|
||||
m_NetworkVariableUShort = new NetworkVariable<ushort>(NetworkVariableReadPermission.Everyone, 1);
|
||||
|
||||
// Use this nifty class: NetworkVariableHelper
|
||||
// Tracks if NetworkVariable changed invokes the OnValueChanged callback for the given instance type
|
||||
Bool_Var = new NetworkVariableHelper<bool>(m_NetworkVariableBool);
|
||||
Byte_Var = new NetworkVariableHelper<byte>(m_NetworkVariableByte);
|
||||
Color_Var = new NetworkVariableHelper<Color>(m_NetworkVariableColor);
|
||||
Color32_Var = new NetworkVariableHelper<Color32>(m_NetworkVariableColor32);
|
||||
Double_Var = new NetworkVariableHelper<double>(m_NetworkVariableDouble);
|
||||
Float_Var = new NetworkVariableHelper<float>(m_NetworkVariableFloat);
|
||||
Int_Var = new NetworkVariableHelper<int>(m_NetworkVariableInt);
|
||||
Long_Var = new NetworkVariableHelper<long>(m_NetworkVariableLong);
|
||||
Sbyte_Var = new NetworkVariableHelper<sbyte>(m_NetworkVariableSByte);
|
||||
Quaternion_Var = new NetworkVariableHelper<Quaternion>(m_NetworkVariableQuaternion);
|
||||
Short_Var = new NetworkVariableHelper<short>(m_NetworkVariableShort);
|
||||
Vector4_Var = new NetworkVariableHelper<Vector4>(m_NetworkVariableVector4);
|
||||
Vector3_Var = new NetworkVariableHelper<Vector3>(m_NetworkVariableVector3);
|
||||
Vector2_Var = new NetworkVariableHelper<Vector2>(m_NetworkVariableVector2);
|
||||
Ray_Var = new NetworkVariableHelper<Ray>(m_NetworkVariableRay);
|
||||
Ulong_Var = new NetworkVariableHelper<ulong>(m_NetworkVariableULong);
|
||||
Uint_Var = new NetworkVariableHelper<uint>(m_NetworkVariableUInt);
|
||||
Ushort_Var = new NetworkVariableHelper<ushort>(m_NetworkVariableUShort);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test result for all values changed the expected number of times (once per unique NetworkVariable type)
|
||||
/// </summary>
|
||||
public bool DidAllValuesChange()
|
||||
{
|
||||
if (NetworkVariableBaseHelper.VarChangedCount == NetworkVariableBaseHelper.InstanceCount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns back whether the test has completed the total number of iterations
|
||||
/// </summary>
|
||||
public bool IsTestComplete()
|
||||
{
|
||||
return m_FinishedTests;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
private void Update()
|
||||
{
|
||||
if (EnableTesting)
|
||||
{
|
||||
//Added timeout functionality for near future changes to NetworkVariables and the Snapshot system
|
||||
if (!m_FinishedTests && m_ChangesAppliedToNetworkVariables)
|
||||
{
|
||||
//We finish testing if all NetworkVariables changed their value or we timed out waiting for
|
||||
//all NetworkVariables to change their value
|
||||
m_FinishedTests = DidAllValuesChange() || (m_WaitForChangesTimeout < Time.realtimeSinceStartup);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NetworkManager != null && NetworkManager.IsListening)
|
||||
{
|
||||
if (!m_Initialized)
|
||||
{
|
||||
InitializeTest();
|
||||
m_Initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Now change all of the values to make sure we are at least testing the local callback
|
||||
m_NetworkVariableBool.Value = false;
|
||||
m_NetworkVariableByte.Value = 255;
|
||||
m_NetworkVariableColor.Value = new Color(100, 100, 100);
|
||||
m_NetworkVariableColor32.Value = new Color32(100, 100, 100, 100);
|
||||
m_NetworkVariableDouble.Value = 1000;
|
||||
m_NetworkVariableFloat.Value = 1000.0f;
|
||||
m_NetworkVariableInt.Value = 1000;
|
||||
m_NetworkVariableLong.Value = 100000;
|
||||
m_NetworkVariableSByte.Value = -127;
|
||||
m_NetworkVariableQuaternion.Value = new Quaternion(100, 100, 100, 100);
|
||||
m_NetworkVariableShort.Value = short.MaxValue;
|
||||
m_NetworkVariableVector4.Value = new Vector4(1000, 1000, 1000, 1000);
|
||||
m_NetworkVariableVector3.Value = new Vector3(1000, 1000, 1000);
|
||||
m_NetworkVariableVector2.Value = new Vector2(1000, 1000);
|
||||
m_NetworkVariableRay.Value = new Ray(Vector3.one, Vector3.right);
|
||||
m_NetworkVariableULong.Value = ulong.MaxValue;
|
||||
m_NetworkVariableUInt.Value = uint.MaxValue;
|
||||
m_NetworkVariableUShort.Value = ushort.MaxValue;
|
||||
|
||||
//Set the timeout (i.e. how long we will wait for all NetworkVariables to have registered their changes)
|
||||
m_WaitForChangesTimeout = Time.realtimeSinceStartup + 0.50f;
|
||||
m_ChangesAppliedToNetworkVariables = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef882d7ba8231eb45839424f54a12486
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
66
Tests/Runtime/ConnectionApproval.cs
Normal file
66
Tests/Runtime/ConnectionApproval.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class ConnectionApprovalTests
|
||||
{
|
||||
private Guid m_ValidationToken;
|
||||
private bool m_IsValidated;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
// Create, instantiate, and host
|
||||
Assert.IsTrue(NetworkManagerHelper.StartNetworkManager(out _, NetworkManagerHelper.NetworkManagerOperatingMode.None));
|
||||
m_ValidationToken = Guid.NewGuid();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator ConnectionApproval()
|
||||
{
|
||||
NetworkManagerHelper.NetworkManagerObject.ConnectionApprovalCallback += NetworkManagerObject_ConnectionApprovalCallback;
|
||||
NetworkManagerHelper.NetworkManagerObject.NetworkConfig.ConnectionApproval = true;
|
||||
NetworkManagerHelper.NetworkManagerObject.NetworkConfig.PlayerPrefab = null;
|
||||
NetworkManagerHelper.NetworkManagerObject.NetworkConfig.ConnectionData = Encoding.UTF8.GetBytes(m_ValidationToken.ToString());
|
||||
m_IsValidated = false;
|
||||
NetworkManagerHelper.NetworkManagerObject.StartHost();
|
||||
|
||||
var timeOut = Time.realtimeSinceStartup + 3.0f;
|
||||
var timedOut = false;
|
||||
while (!m_IsValidated)
|
||||
{
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
if (timeOut < Time.realtimeSinceStartup)
|
||||
{
|
||||
timedOut = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Make sure we didn't time out
|
||||
Assert.False(timedOut);
|
||||
Assert.True(m_IsValidated);
|
||||
}
|
||||
|
||||
private void NetworkManagerObject_ConnectionApprovalCallback(byte[] connectionData, ulong clientId, NetworkManager.ConnectionApprovedDelegate callback)
|
||||
{
|
||||
var stringGuid = Encoding.UTF8.GetString(connectionData);
|
||||
if (m_ValidationToken.ToString() == stringGuid)
|
||||
{
|
||||
m_IsValidated = true;
|
||||
}
|
||||
callback(false, null, m_IsValidated, null, null);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
// Stop, shutdown, and destroy
|
||||
NetworkManagerHelper.ShutdownNetworkManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/ConnectionApproval.cs.meta
Normal file
11
Tests/Runtime/ConnectionApproval.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52ef2017d72b57f418907e98e1d8b90a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
53
Tests/Runtime/DisconnectTests.cs
Normal file
53
Tests/Runtime/DisconnectTests.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class DisconnectTests
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator RemoteDisconnectPlayerObjectCleanup()
|
||||
{
|
||||
// create server and client instances
|
||||
MultiInstanceHelpers.Create(1, out NetworkManager server, out NetworkManager[] clients);
|
||||
|
||||
// create prefab
|
||||
var gameObject = new GameObject("PlayerObject");
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
networkObject.DontDestroyWithOwner = true;
|
||||
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObject);
|
||||
|
||||
server.NetworkConfig.PlayerPrefab = gameObject;
|
||||
|
||||
for (int i = 0; i < clients.Length; i++)
|
||||
{
|
||||
clients[i].NetworkConfig.PlayerPrefab = gameObject;
|
||||
}
|
||||
|
||||
// start server and connect clients
|
||||
MultiInstanceHelpers.Start(false, server, clients);
|
||||
|
||||
// wait for connection on client side
|
||||
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients));
|
||||
|
||||
// wait for connection on server side
|
||||
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientConnectedToServer(server));
|
||||
|
||||
// disconnect the remote client
|
||||
server.DisconnectClient(clients[0].LocalClientId);
|
||||
|
||||
// wait 1 frame because destroys are delayed
|
||||
var nextFrameNumber = Time.frameCount + 1;
|
||||
yield return new WaitUntil(() => Time.frameCount >= nextFrameNumber);
|
||||
|
||||
// ensure the object was destroyed
|
||||
Assert.False(server.SpawnManager.SpawnedObjects.Any(x => x.Value.IsPlayerObject && x.Value.OwnerClientId == clients[0].LocalClientId));
|
||||
|
||||
// cleanup
|
||||
MultiInstanceHelpers.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Tests/Runtime/DisconnectTests.cs.meta
Normal file
3
Tests/Runtime/DisconnectTests.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b05b4daca3854ff6b01a1f002d433dd6
|
||||
timeCreated: 1631652586
|
||||
8
Tests/Runtime/Helpers.meta
Normal file
8
Tests/Runtime/Helpers.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb1b6e801936c7f4a9af28dbed5ea2ff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
273
Tests/Runtime/Helpers/NetworkManagerHelper.cs
Normal file
273
Tests/Runtime/Helpers/NetworkManagerHelper.cs
Normal file
@@ -0,0 +1,273 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using NUnit.Framework;
|
||||
using Unity.Netcode.Transports.UNET;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to instantiate a NetworkManager
|
||||
/// This also provides the ability to:
|
||||
/// --- instantiate GameObjects with NetworkObject components that returns a Guid for accessing it later.
|
||||
/// --- add NetworkBehaviour components to the instantiated GameObjects
|
||||
/// --- spawn a NetworkObject using its parent GameObject's Guid
|
||||
/// Call StartNetworkManager in the constructor of your runtime unit test class.
|
||||
/// Call ShutdownNetworkManager in the destructor of your runtime unit test class.
|
||||
///
|
||||
/// Includes a useful "BuffersMatch" method that allows you to compare two buffers (returns true if they match false if not)
|
||||
/// </summary>
|
||||
public static class NetworkManagerHelper
|
||||
{
|
||||
public static NetworkManager NetworkManagerObject { get; internal set; }
|
||||
public static GameObject NetworkManagerGameObject { get; internal set; }
|
||||
|
||||
internal static Dictionary<Guid, GameObject> InstantiatedGameObjects = new Dictionary<Guid, GameObject>();
|
||||
internal static Dictionary<Guid, NetworkObject> InstantiatedNetworkObjects = new Dictionary<Guid, NetworkObject>();
|
||||
internal static NetworkManagerOperatingMode CurrentNetworkManagerMode;
|
||||
|
||||
/// <summary>
|
||||
/// This provides the ability to start NetworkManager in various modes
|
||||
/// </summary>
|
||||
public enum NetworkManagerOperatingMode
|
||||
{
|
||||
None,
|
||||
Host,
|
||||
Server,
|
||||
Client,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called upon the RpcQueueTests being instantiated.
|
||||
/// This creates an instance of the NetworkManager to be used during unit tests.
|
||||
/// Currently, the best method to run unit tests is by starting in host mode as you can
|
||||
/// send messages to yourself (i.e. Host-Client to Host-Server and vice versa).
|
||||
/// As such, the default setting is to start in Host mode.
|
||||
/// </summary>
|
||||
/// <param name="managerMode">parameter to specify which mode you want to start the NetworkManager</param>
|
||||
/// <param name="networkConfig">parameter to specify custom NetworkConfig settings</param>
|
||||
/// <returns>true if it was instantiated or is already instantiate otherwise false means it failed to instantiate</returns>
|
||||
public static bool StartNetworkManager(out NetworkManager networkManager, NetworkManagerOperatingMode managerMode = NetworkManagerOperatingMode.Host, NetworkConfig networkConfig = null)
|
||||
{
|
||||
// If we are changing the current manager mode and the current manager mode is not "None", then stop the NetworkManager mode
|
||||
if (CurrentNetworkManagerMode != managerMode && CurrentNetworkManagerMode != NetworkManagerOperatingMode.None)
|
||||
{
|
||||
StopNetworkManagerMode();
|
||||
}
|
||||
|
||||
if (NetworkManagerGameObject == null)
|
||||
{
|
||||
NetworkManagerGameObject = new GameObject(nameof(NetworkManager));
|
||||
NetworkManagerObject = NetworkManagerGameObject.AddComponent<NetworkManager>();
|
||||
|
||||
if (NetworkManagerObject == null)
|
||||
{
|
||||
networkManager = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.Log($"{nameof(NetworkManager)} Instantiated.");
|
||||
|
||||
var unetTransport = NetworkManagerGameObject.AddComponent<UNetTransport>();
|
||||
if (networkConfig == null)
|
||||
{
|
||||
networkConfig = new NetworkConfig
|
||||
{
|
||||
EnableSceneManagement = false,
|
||||
};
|
||||
}
|
||||
|
||||
NetworkManagerObject.NetworkConfig = networkConfig;
|
||||
|
||||
unetTransport.ConnectAddress = "127.0.0.1";
|
||||
unetTransport.ConnectPort = 7777;
|
||||
unetTransport.ServerListenPort = 7777;
|
||||
unetTransport.MessageBufferSize = 65535;
|
||||
unetTransport.MaxConnections = 100;
|
||||
unetTransport.MessageSendMode = UNetTransport.SendMode.Immediately;
|
||||
NetworkManagerObject.NetworkConfig.NetworkTransport = unetTransport;
|
||||
|
||||
// Starts the network manager in the mode specified
|
||||
StartNetworkManagerMode(managerMode);
|
||||
}
|
||||
|
||||
networkManager = NetworkManagerObject;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a GameObject with a NetworkObject component
|
||||
/// </summary>
|
||||
/// <param name="nameOfGameObject">the name of the object</param>
|
||||
/// <returns></returns>
|
||||
public static Guid AddGameNetworkObject(string nameOfGameObject)
|
||||
{
|
||||
var gameObjectId = Guid.NewGuid();
|
||||
|
||||
// Create the player object that we will spawn as a host
|
||||
var gameObject = new GameObject(nameOfGameObject);
|
||||
|
||||
Assert.IsNotNull(gameObject);
|
||||
|
||||
var networkObject = gameObject.AddComponent<NetworkObject>();
|
||||
|
||||
Assert.IsNotNull(networkObject);
|
||||
|
||||
Assert.IsFalse(InstantiatedGameObjects.ContainsKey(gameObjectId));
|
||||
Assert.IsFalse(InstantiatedNetworkObjects.ContainsKey(gameObjectId));
|
||||
|
||||
InstantiatedGameObjects.Add(gameObjectId, gameObject);
|
||||
InstantiatedNetworkObjects.Add(gameObjectId, networkObject);
|
||||
|
||||
return gameObjectId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class to add a component to the GameObject with a NetoworkObject component
|
||||
/// </summary>
|
||||
/// <typeparam name="T">NetworkBehaviour component being added to the GameObject</typeparam>
|
||||
/// <param name="gameObjectIdentifier">ID returned to reference the game object</param>
|
||||
/// <returns></returns>
|
||||
public static T AddComponentToObject<T>(Guid gameObjectIdentifier) where T : NetworkBehaviour
|
||||
{
|
||||
Assert.IsTrue(InstantiatedGameObjects.ContainsKey(gameObjectIdentifier));
|
||||
return InstantiatedGameObjects[gameObjectIdentifier].AddComponent<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawn the NetworkObject, so Rpcs can flow
|
||||
/// </summary>
|
||||
/// <param name="gameObjectIdentifier">ID returned to reference the game object</param>
|
||||
public static void SpawnNetworkObject(Guid gameObjectIdentifier)
|
||||
{
|
||||
Assert.IsTrue(InstantiatedNetworkObjects.ContainsKey(gameObjectIdentifier));
|
||||
if (!InstantiatedNetworkObjects[gameObjectIdentifier].IsSpawned)
|
||||
{
|
||||
InstantiatedNetworkObjects[gameObjectIdentifier].Spawn();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the NetworkManager in the current mode specified by managerMode
|
||||
/// </summary>
|
||||
/// <param name="managerMode">the mode to start the NetworkManager as</param>
|
||||
private static void StartNetworkManagerMode(NetworkManagerOperatingMode managerMode)
|
||||
{
|
||||
CurrentNetworkManagerMode = managerMode;
|
||||
switch (CurrentNetworkManagerMode)
|
||||
{
|
||||
case NetworkManagerOperatingMode.Host:
|
||||
{
|
||||
// Starts the host
|
||||
NetworkManagerObject.StartHost();
|
||||
break;
|
||||
}
|
||||
case NetworkManagerOperatingMode.Server:
|
||||
{
|
||||
// Starts the server
|
||||
NetworkManagerObject.StartServer();
|
||||
break;
|
||||
}
|
||||
case NetworkManagerOperatingMode.Client:
|
||||
{
|
||||
// Starts the client
|
||||
NetworkManagerObject.StartClient();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we started an netcode session
|
||||
if (CurrentNetworkManagerMode != NetworkManagerOperatingMode.None)
|
||||
{
|
||||
// With some unit tests the Singleton can still be from a previous unit test
|
||||
// depending upon the order of operations that occurred.
|
||||
if (NetworkManager.Singleton != NetworkManagerObject)
|
||||
{
|
||||
NetworkManagerObject.SetSingleton();
|
||||
}
|
||||
|
||||
// Only log this if we started an netcode session
|
||||
Debug.Log($"{CurrentNetworkManagerMode} started.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the current mode of the NetworkManager
|
||||
/// </summary>
|
||||
private static void StopNetworkManagerMode()
|
||||
{
|
||||
NetworkManagerObject.Shutdown();
|
||||
|
||||
Debug.Log($"{CurrentNetworkManagerMode} stopped.");
|
||||
CurrentNetworkManagerMode = NetworkManagerOperatingMode.None;
|
||||
}
|
||||
|
||||
// This is called, even if we assert and exit early from a test
|
||||
public static void ShutdownNetworkManager()
|
||||
{
|
||||
// clean up any game objects created with custom unit testing components
|
||||
foreach (var entry in InstantiatedGameObjects)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(entry.Value);
|
||||
}
|
||||
|
||||
InstantiatedGameObjects.Clear();
|
||||
|
||||
if (NetworkManagerGameObject != null)
|
||||
{
|
||||
Debug.Log($"{nameof(NetworkManager)} shutdown.");
|
||||
|
||||
StopNetworkManagerMode();
|
||||
UnityEngine.Object.DestroyImmediate(NetworkManagerGameObject);
|
||||
Debug.Log($"{nameof(NetworkManager)} destroyed.");
|
||||
}
|
||||
NetworkManagerGameObject = null;
|
||||
NetworkManagerObject = null;
|
||||
}
|
||||
|
||||
public static bool BuffersMatch(int indexOffset, long targetSize, byte[] sourceArray, byte[] originalArray)
|
||||
{
|
||||
long largeInt64Blocks = targetSize >> 3; // Divide by 8
|
||||
int originalArrayOffset = 0;
|
||||
// process by 8 byte blocks if we can
|
||||
for (long i = 0; i < largeInt64Blocks; i++)
|
||||
{
|
||||
if (BitConverter.ToInt64(sourceArray, indexOffset) != BitConverter.ToInt64(originalArray, originalArrayOffset))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
indexOffset += 8;
|
||||
originalArrayOffset += 8;
|
||||
}
|
||||
|
||||
long offset = largeInt64Blocks * 8;
|
||||
long remainder = targetSize - offset;
|
||||
|
||||
// 4 byte block
|
||||
if (remainder >= 4)
|
||||
{
|
||||
if (BitConverter.ToInt32(sourceArray, indexOffset) != BitConverter.ToInt32(originalArray, originalArrayOffset))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
indexOffset += 4;
|
||||
originalArrayOffset += 4;
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
// Remainder of bytes < 4
|
||||
if (targetSize - offset > 0)
|
||||
{
|
||||
for (long i = 0; i < (targetSize - offset); i++)
|
||||
{
|
||||
if (sourceArray[indexOffset + i] != originalArray[originalArrayOffset + i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/Helpers/NetworkManagerHelper.cs.meta
Normal file
11
Tests/Runtime/Helpers/NetworkManagerHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c920be150fd14ad4ca1936e1a259417c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
153
Tests/Runtime/Helpers/NetworkVariableHelper.cs
Normal file
153
Tests/Runtime/Helpers/NetworkVariableHelper.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Will automatically register for the NetworkVariable OnValueChanged
|
||||
/// delegate handler. It then will expose that single delegate invocation
|
||||
/// to anything that registers for this NetworkVariableHelper's instance's OnValueChanged event.
|
||||
/// This allows us to register any NetworkVariable type as well as there are basically two "types of types":
|
||||
/// IEquatable<T>
|
||||
/// ValueType
|
||||
/// From both we can then at least determine if the value indeed changed
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class NetworkVariableHelper<T> : NetworkVariableBaseHelper where T : unmanaged
|
||||
{
|
||||
private readonly NetworkVariable<T> m_NetworkVariable;
|
||||
public delegate void OnMyValueChangedDelegateHandler(T previous, T next);
|
||||
public event OnMyValueChangedDelegateHandler OnValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// IEquatable<T> Equals Check
|
||||
/// </summary>
|
||||
private void CheckVariableChanged(IEquatable<T> previous, IEquatable<T> next)
|
||||
{
|
||||
if (!previous.Equals(next))
|
||||
{
|
||||
ValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ValueType Equals Check
|
||||
/// </summary>
|
||||
private void CheckVariableChanged(ValueType previous, ValueType next)
|
||||
{
|
||||
if (!previous.Equals(next))
|
||||
{
|
||||
ValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// INetworkVariable's OnVariableChanged delegate callback
|
||||
/// </summary>
|
||||
/// <param name="previous"></param>
|
||||
/// <param name="next"></param>
|
||||
private void OnVariableChanged(T previous, T next)
|
||||
{
|
||||
if (previous is ValueType testValueType)
|
||||
{
|
||||
CheckVariableChanged(previous, next);
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckVariableChanged(previous as IEquatable<T>, next as IEquatable<T>);
|
||||
}
|
||||
|
||||
OnValueChanged?.Invoke(previous, next);
|
||||
}
|
||||
|
||||
public NetworkVariableHelper(NetworkVariableBase networkVariable) : base(networkVariable)
|
||||
{
|
||||
m_NetworkVariable = networkVariable as NetworkVariable<T>;
|
||||
m_NetworkVariable.OnValueChanged = OnVariableChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The BaseNetworkVariableHelper keeps track of:
|
||||
/// The number of instances and associates the instance with the NetworkVariable
|
||||
/// The number of times a specific NetworkVariable instance had its value changed (i.e. !Equal)
|
||||
/// Note: This could be expanded for future tests focuses around NetworkVariables
|
||||
/// </summary>
|
||||
internal class NetworkVariableBaseHelper
|
||||
{
|
||||
private static Dictionary<NetworkVariableBaseHelper, NetworkVariableBase> s_Instances;
|
||||
private static Dictionary<NetworkVariableBase, int> s_InstanceChangedCount;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total number of registered INetworkVariables
|
||||
/// </summary>
|
||||
public static int InstanceCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instances != null)
|
||||
{
|
||||
return s_Instances.Count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns total number of changes that occurred for all registered INetworkVariables
|
||||
/// </summary>
|
||||
public static int VarChangedCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_InstanceChangedCount != null)
|
||||
{
|
||||
var changeCount = 0;
|
||||
foreach (var keyPair in s_InstanceChangedCount)
|
||||
{
|
||||
changeCount += keyPair.Value;
|
||||
}
|
||||
return changeCount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the child class NetworkVariableHelper when a value changed
|
||||
/// </summary>
|
||||
protected void ValueChanged()
|
||||
{
|
||||
if (s_Instances.ContainsKey(this))
|
||||
{
|
||||
if (s_InstanceChangedCount.ContainsKey(s_Instances[this]))
|
||||
{
|
||||
s_InstanceChangedCount[s_Instances[this]]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkVariableBaseHelper(NetworkVariableBase networkVariable)
|
||||
{
|
||||
if (s_Instances == null)
|
||||
{
|
||||
s_Instances = new Dictionary<NetworkVariableBaseHelper, NetworkVariableBase>();
|
||||
}
|
||||
|
||||
if (s_InstanceChangedCount == null)
|
||||
{
|
||||
s_InstanceChangedCount = new Dictionary<NetworkVariableBase, int>();
|
||||
}
|
||||
|
||||
// Register new instance and associated INetworkVariable
|
||||
if (!s_Instances.ContainsKey(this))
|
||||
{
|
||||
s_Instances.Add(this, networkVariable);
|
||||
if (!s_InstanceChangedCount.ContainsKey(networkVariable))
|
||||
{
|
||||
s_InstanceChangedCount.Add(networkVariable, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/Helpers/NetworkVariableHelper.cs.meta
Normal file
11
Tests/Runtime/Helpers/NetworkVariableHelper.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 218bb185a48c6f9449e1c74f4855a774
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
245
Tests/Runtime/HiddenVariableTests.cs
Normal file
245
Tests/Runtime/HiddenVariableTests.cs
Normal file
@@ -0,0 +1,245 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class HiddenVariableTest : NetworkBehaviour
|
||||
{
|
||||
}
|
||||
|
||||
public class HiddenVariableObject : NetworkBehaviour
|
||||
{
|
||||
public NetworkVariable<int> MyNetworkVariable = new NetworkVariable<int>();
|
||||
public NetworkList<int> MyNetworkList = new NetworkList<int>();
|
||||
|
||||
public static Dictionary<ulong, int> ValueOnClient = new Dictionary<ulong, int>();
|
||||
public static int ExpectedSize = 0;
|
||||
public static int SpawnCount = 0;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
Debug.Log($"{nameof(HiddenVariableObject)}.{nameof(OnNetworkSpawn)}() with value {MyNetworkVariable.Value}");
|
||||
|
||||
MyNetworkVariable.OnValueChanged += Changed;
|
||||
MyNetworkList.OnListChanged += ListChanged;
|
||||
SpawnCount++;
|
||||
|
||||
base.OnNetworkSpawn();
|
||||
}
|
||||
|
||||
public void Changed(int before, int after)
|
||||
{
|
||||
Debug.Log($"Value changed from {before} to {after} on {NetworkManager.LocalClientId}");
|
||||
ValueOnClient[NetworkManager.LocalClientId] = after;
|
||||
}
|
||||
public void ListChanged(NetworkListEvent<int> listEvent)
|
||||
{
|
||||
Debug.Log($"ListEvent received: type {listEvent.Type}, index {listEvent.Index}, value {listEvent.Value}");
|
||||
Debug.Assert(ExpectedSize == MyNetworkList.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public class HiddenVariableTests : BaseMultiInstanceTest
|
||||
{
|
||||
protected override int NbClients => 4;
|
||||
|
||||
private NetworkObject m_NetSpawnedObject;
|
||||
private List<NetworkObject> m_NetSpawnedObjectOnClient = new List<NetworkObject>();
|
||||
private GameObject m_TestNetworkPrefab;
|
||||
|
||||
[UnitySetUp]
|
||||
public override IEnumerator Setup()
|
||||
{
|
||||
yield return StartSomeClientsAndServerWithPlayers(useHost: true, nbClients: NbClients,
|
||||
updatePlayerPrefab: playerPrefab =>
|
||||
{
|
||||
var networkTransform = playerPrefab.AddComponent<HiddenVariableTest>();
|
||||
m_TestNetworkPrefab = PreparePrefab();
|
||||
});
|
||||
}
|
||||
|
||||
public GameObject PreparePrefab()
|
||||
{
|
||||
var prefabToSpawn = new GameObject("MyTestObject");
|
||||
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
|
||||
MultiInstanceHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
|
||||
prefabToSpawn.AddComponent<HiddenVariableObject>();
|
||||
|
||||
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
|
||||
foreach (var clientNetworkManager in m_ClientNetworkManagers)
|
||||
{
|
||||
clientNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
|
||||
}
|
||||
return prefabToSpawn;
|
||||
}
|
||||
|
||||
public IEnumerator WaitForConnectedCount(int targetCount)
|
||||
{
|
||||
var endTime = Time.realtimeSinceStartup + 1.0;
|
||||
while (m_ServerNetworkManager.ConnectedClientsList.Count < targetCount && Time.realtimeSinceStartup < endTime)
|
||||
{
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator WaitForSpawnCount(int targetCount)
|
||||
{
|
||||
var endTime = Time.realtimeSinceStartup + 1.0;
|
||||
while (HiddenVariableObject.SpawnCount != targetCount &&
|
||||
Time.realtimeSinceStartup < endTime)
|
||||
{
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
public void VerifyLists()
|
||||
{
|
||||
NetworkList<int> prev = null;
|
||||
int numComparison = 0;
|
||||
|
||||
// for all the instances of NetworkList
|
||||
foreach (var gameObject in m_NetSpawnedObjectOnClient)
|
||||
{
|
||||
// this skips despawned/hidden objects
|
||||
if (gameObject != null)
|
||||
{
|
||||
// if we've seen another one before
|
||||
if (prev != null)
|
||||
{
|
||||
var curr = gameObject.GetComponent<HiddenVariableObject>().MyNetworkList;
|
||||
|
||||
// check that the two lists are identical
|
||||
Debug.Assert(curr.Count == prev.Count);
|
||||
for (int index = 0; index < curr.Count; index++)
|
||||
{
|
||||
Debug.Assert(curr[index] == prev[index]);
|
||||
}
|
||||
numComparison++;
|
||||
}
|
||||
// store the list
|
||||
prev = gameObject.GetComponent<HiddenVariableObject>().MyNetworkList;
|
||||
}
|
||||
}
|
||||
Debug.Log($"{numComparison} comparisons done.");
|
||||
}
|
||||
|
||||
public IEnumerator RefreshGameObects()
|
||||
{
|
||||
m_NetSpawnedObjectOnClient.Clear();
|
||||
|
||||
foreach (var netMan in m_ClientNetworkManagers)
|
||||
{
|
||||
var serverClientPlayerResult = new MultiInstanceHelpers.CoroutineResultWrapper<NetworkObject>();
|
||||
yield return MultiInstanceHelpers.Run(
|
||||
MultiInstanceHelpers.GetNetworkObjectByRepresentation(
|
||||
x => x.NetworkObjectId == m_NetSpawnedObject.NetworkObjectId,
|
||||
netMan,
|
||||
serverClientPlayerResult));
|
||||
m_NetSpawnedObjectOnClient.Add(serverClientPlayerResult.Result);
|
||||
}
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator HiddenVariableTest()
|
||||
{
|
||||
HiddenVariableObject.SpawnCount = 0;
|
||||
HiddenVariableObject.ValueOnClient.Clear();
|
||||
HiddenVariableObject.ExpectedSize = 0;
|
||||
HiddenVariableObject.SpawnCount = 0;
|
||||
|
||||
Debug.Log("Running test");
|
||||
|
||||
var spawnedObject = Object.Instantiate(m_TestNetworkPrefab);
|
||||
m_NetSpawnedObject = spawnedObject.GetComponent<NetworkObject>();
|
||||
m_NetSpawnedObject.NetworkManagerOwner = m_ServerNetworkManager;
|
||||
yield return WaitForConnectedCount(NbClients);
|
||||
Debug.Log("Clients connected");
|
||||
|
||||
// ==== Spawn object with ownership on one client
|
||||
var client = m_ServerNetworkManager.ConnectedClientsList[1];
|
||||
var otherClient = m_ServerNetworkManager.ConnectedClientsList[2];
|
||||
m_NetSpawnedObject.SpawnWithOwnership(client.ClientId);
|
||||
|
||||
yield return RefreshGameObects();
|
||||
|
||||
// === Check spawn occured
|
||||
yield return WaitForSpawnCount(NbClients + 1);
|
||||
Debug.Assert(HiddenVariableObject.SpawnCount == NbClients + 1);
|
||||
Debug.Log("Objects spawned");
|
||||
|
||||
// ==== Set the NetworkVariable value to 2
|
||||
HiddenVariableObject.ExpectedSize = 1;
|
||||
HiddenVariableObject.SpawnCount = 0;
|
||||
|
||||
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = 2;
|
||||
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(2);
|
||||
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
|
||||
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
|
||||
{
|
||||
Debug.Assert(HiddenVariableObject.ValueOnClient[id] == 2);
|
||||
}
|
||||
|
||||
VerifyLists();
|
||||
|
||||
Debug.Log("Value changed");
|
||||
|
||||
// ==== Hide our object to a different client
|
||||
HiddenVariableObject.ExpectedSize = 2;
|
||||
m_NetSpawnedObject.NetworkHide(otherClient.ClientId);
|
||||
|
||||
// ==== Change the NetworkVariable value
|
||||
// we should get one less notification of value changing and no errors or exception
|
||||
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = 3;
|
||||
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(3);
|
||||
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
|
||||
{
|
||||
if (id != otherClient.ClientId)
|
||||
{
|
||||
Debug.Assert(HiddenVariableObject.ValueOnClient[id] == 3);
|
||||
}
|
||||
}
|
||||
|
||||
VerifyLists();
|
||||
Debug.Log("Values changed");
|
||||
|
||||
// ==== Show our object again to this client
|
||||
HiddenVariableObject.ExpectedSize = 3;
|
||||
m_NetSpawnedObject.NetworkShow(otherClient.ClientId);
|
||||
|
||||
// ==== Wait for object to be spawned
|
||||
yield return WaitForSpawnCount(1);
|
||||
Debug.Assert(HiddenVariableObject.SpawnCount == 1);
|
||||
Debug.Log("Object spawned");
|
||||
|
||||
// ==== We need a refresh for the newly re-spawned object
|
||||
yield return RefreshGameObects();
|
||||
|
||||
// ==== Change the NetworkVariable value
|
||||
// we should get all notifications of value changing and no errors or exception
|
||||
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkVariable.Value = 4;
|
||||
m_NetSpawnedObject.GetComponent<HiddenVariableObject>().MyNetworkList.Add(4);
|
||||
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
|
||||
foreach (var id in m_ServerNetworkManager.ConnectedClientsIds)
|
||||
{
|
||||
Debug.Assert(HiddenVariableObject.ValueOnClient[id] == 4);
|
||||
}
|
||||
|
||||
VerifyLists();
|
||||
Debug.Log("Values changed");
|
||||
|
||||
// ==== Hide our object to that different client again, and then destroy it
|
||||
m_NetSpawnedObject.NetworkHide(otherClient.ClientId);
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
m_NetSpawnedObject.Despawn();
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/HiddenVariableTests.cs.meta
Normal file
11
Tests/Runtime/HiddenVariableTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c64eb7c36fc44eadac730241b23e006
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Tests/Runtime/Messaging.meta
Normal file
3
Tests/Runtime/Messaging.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60efb82fa0154d6caf94fea440f167d4
|
||||
timeCreated: 1627407732
|
||||
156
Tests/Runtime/Messaging/NamedMessageTests.cs
Normal file
156
Tests/Runtime/Messaging/NamedMessageTests.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class NamedMessageTests : BaseMultiInstanceTest
|
||||
{
|
||||
protected override int NbClients => 2;
|
||||
|
||||
private NetworkManager FirstClient => m_ClientNetworkManagers[0];
|
||||
private NetworkManager SecondClient => m_ClientNetworkManagers[1];
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NamedMessageIsReceivedOnClientWithContent()
|
||||
{
|
||||
var messageName = Guid.NewGuid().ToString();
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage(
|
||||
messageName,
|
||||
FirstClient.LocalClientId,
|
||||
writer);
|
||||
}
|
||||
|
||||
ulong receivedMessageSender = 0;
|
||||
var receivedMessageContent = new Guid();
|
||||
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(
|
||||
messageName,
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
receivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out receivedMessageContent);
|
||||
});
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
|
||||
Assert.AreEqual(messageContent, receivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, receivedMessageSender);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator NamedMessageIsReceivedOnMultipleClientsWithContent()
|
||||
{
|
||||
var messageName = Guid.NewGuid().ToString();
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage(
|
||||
messageName,
|
||||
new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId },
|
||||
writer);
|
||||
}
|
||||
|
||||
ulong firstReceivedMessageSender = 0;
|
||||
var firstReceivedMessageContent = new Guid();
|
||||
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(
|
||||
messageName,
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
firstReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out firstReceivedMessageContent);
|
||||
});
|
||||
|
||||
ulong secondReceivedMessageSender = 0;
|
||||
var secondReceivedMessageContent = new Guid();
|
||||
SecondClient.CustomMessagingManager.RegisterNamedMessageHandler(
|
||||
messageName,
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
secondReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out secondReceivedMessageContent);
|
||||
});
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
|
||||
Assert.AreEqual(messageContent, firstReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
|
||||
|
||||
Assert.AreEqual(messageContent, secondReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSendingNamedMessageToAll_AllClientsReceiveIt()
|
||||
{
|
||||
var messageName = Guid.NewGuid().ToString();
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessageToAll(messageName, writer);
|
||||
}
|
||||
|
||||
ulong firstReceivedMessageSender = 0;
|
||||
var firstReceivedMessageContent = new Guid();
|
||||
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(
|
||||
messageName,
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
firstReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out firstReceivedMessageContent);
|
||||
});
|
||||
|
||||
ulong secondReceivedMessageSender = 0;
|
||||
var secondReceivedMessageContent = new Guid();
|
||||
SecondClient.CustomMessagingManager.RegisterNamedMessageHandler(
|
||||
messageName,
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
secondReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out secondReceivedMessageContent);
|
||||
});
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
|
||||
Assert.AreEqual(messageContent, firstReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
|
||||
|
||||
Assert.AreEqual(messageContent, secondReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingNamedMessageToNullClientList_ArgumentNullExceptionIsThrown()
|
||||
{
|
||||
var messageName = Guid.NewGuid().ToString();
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
Assert.Throws<ArgumentNullException>(
|
||||
() =>
|
||||
{
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendNamedMessage(messageName, null, writer);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/Messaging/NamedMessageTests.cs.meta
Normal file
11
Tests/Runtime/Messaging/NamedMessageTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50770f69eb9d3604184f918a2d0674e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
145
Tests/Runtime/Messaging/UnnamedMessageTests.cs
Normal file
145
Tests/Runtime/Messaging/UnnamedMessageTests.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests
|
||||
{
|
||||
public class UnnamedMessageTests : BaseMultiInstanceTest
|
||||
{
|
||||
protected override int NbClients => 2;
|
||||
|
||||
private NetworkManager FirstClient => m_ClientNetworkManagers[0];
|
||||
private NetworkManager SecondClient => m_ClientNetworkManagers[1];
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UnnamedMessageIsReceivedOnClientWithContent()
|
||||
{
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendUnnamedMessage(
|
||||
FirstClient.LocalClientId,
|
||||
writer);
|
||||
}
|
||||
|
||||
ulong receivedMessageSender = 0;
|
||||
var receivedMessageContent = new Guid();
|
||||
FirstClient.CustomMessagingManager.OnUnnamedMessage +=
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
receivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out receivedMessageContent);
|
||||
};
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
|
||||
Assert.AreEqual(messageContent, receivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, receivedMessageSender);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator UnnamedMessageIsReceivedOnMultipleClientsWithContent()
|
||||
{
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendUnnamedMessage(
|
||||
new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId },
|
||||
writer);
|
||||
}
|
||||
|
||||
ulong firstReceivedMessageSender = 0;
|
||||
var firstReceivedMessageContent = new Guid();
|
||||
FirstClient.CustomMessagingManager.OnUnnamedMessage +=
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
firstReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out firstReceivedMessageContent);
|
||||
};
|
||||
|
||||
ulong secondReceivedMessageSender = 0;
|
||||
var secondReceivedMessageContent = new Guid();
|
||||
SecondClient.CustomMessagingManager.OnUnnamedMessage +=
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
secondReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out secondReceivedMessageContent);
|
||||
};
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
|
||||
Assert.AreEqual(messageContent, firstReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
|
||||
|
||||
Assert.AreEqual(messageContent, secondReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenSendingUnnamedMessageToAll_AllClientsReceiveIt()
|
||||
{
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendUnnamedMessageToAll(writer);
|
||||
}
|
||||
|
||||
ulong firstReceivedMessageSender = 0;
|
||||
var firstReceivedMessageContent = new Guid();
|
||||
FirstClient.CustomMessagingManager.OnUnnamedMessage +=
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
firstReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out firstReceivedMessageContent);
|
||||
};
|
||||
|
||||
ulong secondReceivedMessageSender = 0;
|
||||
var secondReceivedMessageContent = new Guid();
|
||||
SecondClient.CustomMessagingManager.OnUnnamedMessage +=
|
||||
(ulong sender, FastBufferReader reader) =>
|
||||
{
|
||||
secondReceivedMessageSender = sender;
|
||||
|
||||
reader.ReadValueSafe(out secondReceivedMessageContent);
|
||||
};
|
||||
|
||||
yield return new WaitForSeconds(0.2f);
|
||||
|
||||
Assert.AreEqual(messageContent, firstReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, firstReceivedMessageSender);
|
||||
|
||||
Assert.AreEqual(messageContent, secondReceivedMessageContent);
|
||||
Assert.AreEqual(m_ServerNetworkManager.LocalClientId, secondReceivedMessageSender);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WhenSendingNamedMessageToNullClientList_ArgumentNullExceptionIsThrown()
|
||||
{
|
||||
var messageContent = Guid.NewGuid();
|
||||
var writer = new FastBufferWriter(1300, Allocator.Temp);
|
||||
using (writer)
|
||||
{
|
||||
writer.WriteValueSafe(messageContent);
|
||||
Assert.Throws<ArgumentNullException>(
|
||||
() =>
|
||||
{
|
||||
m_ServerNetworkManager.CustomMessagingManager.SendUnnamedMessage(null, writer);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Tests/Runtime/Messaging/UnnamedMessageTests.cs.meta
Normal file
11
Tests/Runtime/Messaging/UnnamedMessageTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5affb61a1b56d44c80d0e2d55cc04aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Tests/Runtime/Metrics.meta
Normal file
8
Tests/Runtime/Metrics.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cd7fa97c73f3674b9cce18b1e0a6874
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
275
Tests/Runtime/Metrics/MessagingMetricsTests.cs
Normal file
275
Tests/Runtime/Metrics/MessagingMetricsTests.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
#if MULTIPLAYER_TOOLS
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Unity.Collections;
|
||||
using Unity.Multiplayer.Tools.MetricTypes;
|
||||
using Unity.Netcode.RuntimeTests.Metrics.Utility;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
{
|
||||
public class MessagingMetricsTests : DualClientMetricTestBase
|
||||
{
|
||||
const uint MessageNameHashSize = 8;
|
||||
|
||||
const uint MessageOverhead = MessageNameHashSize;
|
||||
|
||||
protected override int NbClients => 2;
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNetworkMessageSentMetric()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
|
||||
|
||||
var messageName = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
|
||||
}
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var networkMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, networkMessageSentMetricValues.Count);
|
||||
|
||||
var networkMessageEvent = networkMessageSentMetricValues.First();
|
||||
Assert.AreEqual(nameof(NamedMessage), networkMessageEvent.Name);
|
||||
Assert.AreEqual(FirstClient.LocalClientId, networkMessageEvent.Connection.Id);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNetworkMessageSentMetricToMultipleClients()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<NetworkMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageSent);
|
||||
var messageName = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
|
||||
}
|
||||
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var networkMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(2, networkMessageSentMetricValues.Count(x => x.Name.Equals(nameof(NamedMessage))));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNetworkMessageReceivedMetric()
|
||||
{
|
||||
var messageName = Guid.NewGuid();
|
||||
|
||||
LogAssert.Expect(LogType.Log, $"Received from {Server.LocalClientId}");
|
||||
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(messageName.ToString(), (ulong sender, FastBufferReader payload) =>
|
||||
{
|
||||
Debug.Log($"Received from {sender}");
|
||||
});
|
||||
var waitForMetricValues = new WaitForMetricValues<NetworkMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NetworkMessageReceived);
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
|
||||
}
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var networkMessageReceivedValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, networkMessageReceivedValues.Count(x => x.Name.Equals(nameof(NamedMessage))));
|
||||
|
||||
var namedMessageReceived = networkMessageReceivedValues.First();
|
||||
Assert.AreEqual(Server.LocalClientId, namedMessageReceived.Connection.Id);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNamedMessageSentMetric()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
|
||||
|
||||
var messageName = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
|
||||
}
|
||||
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var namedMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, namedMessageSentMetricValues.Count);
|
||||
|
||||
var namedMessageSent = namedMessageSentMetricValues.First();
|
||||
Assert.AreEqual(messageName.ToString(), namedMessageSent.Name);
|
||||
Assert.AreEqual(FirstClient.LocalClientId, namedMessageSent.Connection.Id);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + MessageOverhead, namedMessageSent.BytesCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNamedMessageSentMetricToMultipleClients()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
|
||||
var messageName = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
|
||||
}
|
||||
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var namedMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(2, namedMessageSentMetricValues.Count);
|
||||
Assert.That(namedMessageSentMetricValues.Select(x => x.Name), Has.All.EqualTo(messageName.ToString()));
|
||||
Assert.That(namedMessageSentMetricValues.Select(x => x.BytesCount), Has.All.EqualTo(FastBufferWriter.GetWriteSize(messageName) + MessageOverhead));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNamedMessageSentMetricToSelf()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.NamedMessageSent);
|
||||
var messageName = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), Server.LocalClientId, writer);
|
||||
}
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
waitForMetricValues.AssertMetricValuesHaveNotBeenFound();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackNamedMessageReceivedMetric()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<NamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.NamedMessageReceived);
|
||||
|
||||
var messageName = Guid.NewGuid();
|
||||
|
||||
LogAssert.Expect(LogType.Log, $"Received from {Server.LocalClientId}");
|
||||
FirstClient.CustomMessagingManager.RegisterNamedMessageHandler(messageName.ToString(), (ulong sender, FastBufferReader payload) =>
|
||||
{
|
||||
Debug.Log($"Received from {sender}");
|
||||
});
|
||||
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendNamedMessage(messageName.ToString(), FirstClient.LocalClientId, writer);
|
||||
}
|
||||
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var namedMessageReceivedValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, namedMessageReceivedValues.Count);
|
||||
|
||||
var namedMessageReceived = namedMessageReceivedValues.First();
|
||||
Assert.AreEqual(messageName.ToString(), namedMessageReceived.Name);
|
||||
Assert.AreEqual(Server.LocalClientId, namedMessageReceived.Connection.Id);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(messageName) + MessageOverhead, namedMessageReceived.BytesCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackUnnamedMessageSentMetric()
|
||||
{
|
||||
var message = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(message);
|
||||
|
||||
Server.CustomMessagingManager.SendUnnamedMessage(FirstClient.LocalClientId, writer);
|
||||
}
|
||||
|
||||
|
||||
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var unnamedMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, unnamedMessageSentMetricValues.Count);
|
||||
|
||||
var unnamedMessageSent = unnamedMessageSentMetricValues.First();
|
||||
Assert.AreEqual(FirstClient.LocalClientId, unnamedMessageSent.Connection.Id);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(message), unnamedMessageSent.BytesCount);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackUnnamedMessageSentMetricToMultipleClients()
|
||||
{
|
||||
var message = Guid.NewGuid();
|
||||
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(message);
|
||||
|
||||
Server.CustomMessagingManager.SendUnnamedMessage(new List<ulong> { FirstClient.LocalClientId, SecondClient.LocalClientId }, writer);
|
||||
}
|
||||
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var unnamedMessageSentMetricValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(2, unnamedMessageSentMetricValues.Count);
|
||||
Assert.That(unnamedMessageSentMetricValues.Select(x => x.BytesCount), Has.All.EqualTo(FastBufferWriter.GetWriteSize(message)));
|
||||
|
||||
var clientIds = unnamedMessageSentMetricValues.Select(x => x.Connection.Id).ToList();
|
||||
Assert.Contains(FirstClient.LocalClientId, clientIds);
|
||||
Assert.Contains(SecondClient.LocalClientId, clientIds);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackUnnamedMessageSentMetricToSelf()
|
||||
{
|
||||
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(ServerMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageSent);
|
||||
var messageName = Guid.NewGuid();
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(messageName);
|
||||
|
||||
Server.CustomMessagingManager.SendUnnamedMessage(Server.LocalClientId, writer);
|
||||
}
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
waitForMetricValues.AssertMetricValuesHaveNotBeenFound();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator TrackUnnamedMessageReceivedMetric()
|
||||
{
|
||||
var message = Guid.NewGuid();
|
||||
var waitForMetricValues = new WaitForMetricValues<UnnamedMessageEvent>(FirstClientMetrics.Dispatcher, NetworkMetricTypes.UnnamedMessageReceived);
|
||||
using (var writer = new FastBufferWriter(1300, Allocator.Temp))
|
||||
{
|
||||
writer.WriteValueSafe(message);
|
||||
|
||||
Server.CustomMessagingManager.SendUnnamedMessage(FirstClient.LocalClientId, writer);
|
||||
}
|
||||
|
||||
yield return waitForMetricValues.WaitForMetricsReceived();
|
||||
|
||||
var unnamedMessageReceivedValues = waitForMetricValues.AssertMetricValuesHaveBeenFound();
|
||||
Assert.AreEqual(1, unnamedMessageReceivedValues.Count);
|
||||
|
||||
var unnamedMessageReceived = unnamedMessageReceivedValues.First();
|
||||
Assert.AreEqual(Server.LocalClientId, unnamedMessageReceived.Connection.Id);
|
||||
Assert.AreEqual(FastBufferWriter.GetWriteSize(message), unnamedMessageReceived.BytesCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
Tests/Runtime/Metrics/MessagingMetricsTests.cs.meta
Normal file
11
Tests/Runtime/Metrics/MessagingMetricsTests.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2490ed51138306e4d92f8e9dcfc34462
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
66
Tests/Runtime/Metrics/MetricsDispatchTests.cs
Normal file
66
Tests/Runtime/Metrics/MetricsDispatchTests.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
#if MULTIPLAYER_TOOLS
|
||||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using Unity.Multiplayer.Tools.NetStats;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace Unity.Netcode.RuntimeTests.Metrics
|
||||
{
|
||||
public class MetricsDispatchTests
|
||||
{
|
||||
private int m_NbDispatches;
|
||||
|
||||
private NetworkManager m_NetworkManager;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var networkManagerStarted = NetworkManagerHelper.StartNetworkManager(
|
||||
out m_NetworkManager,
|
||||
NetworkManagerHelper.NetworkManagerOperatingMode.Host,
|
||||
new NetworkConfig
|
||||
{
|
||||
TickRate = 1,
|
||||
});
|
||||
Assert.IsTrue(networkManagerStarted);
|
||||
|
||||
var networkMetrics = m_NetworkManager.NetworkMetrics as NetworkMetrics;
|
||||
networkMetrics.Dispatcher.RegisterObserver(new MockMetricsObserver(() => m_NbDispatches++));
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
NetworkManagerHelper.ShutdownNetworkManager();
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator VerifyNetworkMetricsDispatchesOncePerFrame()
|
||||
{
|
||||
var nbDispatchesBeforeFrame = m_NbDispatches;
|
||||
|
||||
yield return null; // Wait one frame so dispatch occurs
|
||||
|
||||
var nbDispatchesAfterFrame = m_NbDispatches;
|
||||
|
||||
Assert.AreEqual(1, nbDispatchesAfterFrame - nbDispatchesBeforeFrame);
|
||||
}
|
||||
|
||||
private class MockMetricsObserver : IMetricObserver
|
||||
{
|
||||
private readonly Action m_OnObserve;
|
||||
|
||||
public MockMetricsObserver(Action onObserve)
|
||||
{
|
||||
m_OnObserve = onObserve;
|
||||
}
|
||||
|
||||
public void Observe(MetricCollection collection)
|
||||
{
|
||||
m_OnObserve?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
3
Tests/Runtime/Metrics/MetricsDispatchTests.cs.meta
Normal file
3
Tests/Runtime/Metrics/MetricsDispatchTests.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4833f15c8a59407abbb8532ea64b5683
|
||||
timeCreated: 1633451646
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user