mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-17 18:40:33 +00:00
Compare commits
4 Commits
539cdef947
...
f6954b55e1
Author | SHA1 | Date | |
---|---|---|---|
|
f6954b55e1 | ||
|
1187a59b18 | ||
|
cb6a7812f5 | ||
|
c36feeb0fe |
@ -863,7 +863,7 @@ internal void OnStopLocalPlayer()
|
||||
for (int i = 0; i < components.Length; ++i)
|
||||
{
|
||||
NetworkBehaviour component = components[i];
|
||||
ulong nthBit = (1u << i);
|
||||
ulong nthBit = 1ul << i;
|
||||
|
||||
bool dirty = component.IsDirty();
|
||||
|
||||
@ -910,7 +910,7 @@ ulong ClientDirtyMask()
|
||||
|
||||
// on client, only consider owned components with SyncDirection to server
|
||||
NetworkBehaviour component = components[i];
|
||||
ulong nthBit = (1u << i);
|
||||
ulong nthBit = 1ul << i;
|
||||
|
||||
if (isOwned && component.syncDirection == SyncDirection.ClientToServer)
|
||||
{
|
||||
@ -928,7 +928,7 @@ ulong ClientDirtyMask()
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool IsDirty(ulong mask, int index)
|
||||
{
|
||||
ulong nthBit = (ulong)(1 << index);
|
||||
ulong nthBit = 1ul << index;
|
||||
return (mask & nthBit) != 0;
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,13 @@ public static class NetworkReaderExtensions
|
||||
public static decimal? ReadDecimalNullable(this NetworkReader reader) => reader.ReadBlittableNullable<decimal>();
|
||||
|
||||
public static Half ReadHalf(this NetworkReader reader) => new Half(reader.ReadUShort());
|
||||
public static Vector3Half ReadVector3Half(this NetworkReader reader)
|
||||
{
|
||||
Half x = reader.ReadHalf();
|
||||
Half y = reader.ReadHalf();
|
||||
Half z = reader.ReadHalf();
|
||||
return new Vector3Half(x, y, z);
|
||||
}
|
||||
|
||||
/// <exception cref="T:System.ArgumentException">if an invalid utf8 string is sent</exception>
|
||||
public static string ReadString(this NetworkReader reader)
|
||||
|
@ -58,6 +58,12 @@ public static class NetworkWriterExtensions
|
||||
public static void WriteDecimalNullable(this NetworkWriter writer, decimal? value) => writer.WriteBlittableNullable(value);
|
||||
|
||||
public static void WriteHalf(this NetworkWriter writer, Half value) => writer.WriteUShort(value._value);
|
||||
public static void WriteVector3Half(this NetworkWriter writer, Vector3Half value)
|
||||
{
|
||||
writer.WriteHalf(value.x);
|
||||
writer.WriteHalf(value.y);
|
||||
writer.WriteHalf(value.z);
|
||||
}
|
||||
|
||||
public static void WriteString(this NetworkWriter writer, string value)
|
||||
{
|
||||
|
125
Assets/Mirror/Core/Tools/Vector3Half.cs
Normal file
125
Assets/Mirror/Core/Tools/Vector3Half.cs
Normal file
@ -0,0 +1,125 @@
|
||||
#pragma warning disable CS0659 // 'Vector3Half' overrides Object.Equals(object o) but does not override Object.GetHashCode()
|
||||
#pragma warning disable CS0661 // 'Vector3Half' defines operator == or operator != but does not override Object.GetHashCode()
|
||||
|
||||
// Vector3Half by mischa (based on game engine project)
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Mirror
|
||||
{
|
||||
public struct Vector3Half
|
||||
{
|
||||
public Half x;
|
||||
public Half y;
|
||||
public Half z;
|
||||
|
||||
public static readonly Vector3Half zero = new Vector3Half((Half)0, (Half)0, (Half)0);
|
||||
public static readonly Vector3Half one = new Vector3Half((Half)1, (Half)1, (Half)1);
|
||||
public static readonly Vector3Half forward = new Vector3Half((Half)0, (Half)0, (Half)1);
|
||||
public static readonly Vector3Half back = new Vector3Half((Half)0, (Half)0, (Half)(-1));
|
||||
public static readonly Vector3Half left = new Vector3Half((Half)(-1), (Half)0, (Half)0);
|
||||
public static readonly Vector3Half right = new Vector3Half((Half)1, (Half)0, (Half)0);
|
||||
public static readonly Vector3Half up = new Vector3Half((Half)0, (Half)1, (Half)0);
|
||||
public static readonly Vector3Half down = new Vector3Half((Half)0, (Half)(-1), (Half)0);
|
||||
|
||||
// constructor /////////////////////////////////////////////////////////
|
||||
public Vector3Half(Half x, Half y, Half z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
// operators ///////////////////////////////////////////////////////////
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3Half operator +(Vector3Half a, Vector3Half b) =>
|
||||
new Vector3Half(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3Half operator -(Vector3Half a, Vector3Half b) =>
|
||||
new Vector3Half(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector3Half operator -(Vector3Half v) =>
|
||||
new Vector3Half(-v.x, -v.y, -v.z);
|
||||
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static Vector3Half operator *(Vector3Half a, long n) =>
|
||||
// new Vector3Half(a.x * n, a.y * n, a.z * n);
|
||||
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public static Vector3Half operator *(long n, Vector3Half a) =>
|
||||
// new Vector3Half(a.x * n, a.y * n, a.z * n);
|
||||
|
||||
// == returns true if approximately equal (with epsilon).
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(Vector3Half a, Vector3Half b) =>
|
||||
a.x == b.x &&
|
||||
a.y == b.y &&
|
||||
a.z == b.z;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(Vector3Half a, Vector3Half b) => !(a == b);
|
||||
|
||||
// NO IMPLICIT System.Numerics.Vector3Half conversion because double<->float
|
||||
// would silently lose precision in large worlds.
|
||||
|
||||
// [i] component index. useful for iterating all components etc.
|
||||
public Half this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
default: throw new IndexOutOfRangeException($"Vector3Half[{index}] out of range.");
|
||||
}
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
x = value;
|
||||
break;
|
||||
case 1:
|
||||
y = value;
|
||||
break;
|
||||
case 2:
|
||||
z = value;
|
||||
break;
|
||||
default: throw new IndexOutOfRangeException($"Vector3Half[{index}] out of range.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// instance functions //////////////////////////////////////////////////
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"({x} {y} {z})";
|
||||
|
||||
// equality ////////////////////////////////////////////////////////////
|
||||
// implement Equals & HashCode explicitly for performance.
|
||||
// calling .Equals (instead of "==") checks for exact equality.
|
||||
// (API compatibility)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(Vector3Half other) =>
|
||||
x == other.x && y == other.y && z == other.z;
|
||||
|
||||
// Equals(object) can reuse Equals(Vector4)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override bool Equals(object other) =>
|
||||
other is Vector3Half vector4 && Equals(vector4);
|
||||
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
// Unity 2019/2020 don't have HashCode.Combine yet.
|
||||
// this is only to avoid reflection. without defining, it works too.
|
||||
// default generated by rider
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override int GetHashCode() => HashCode.Combine(x, y, z);
|
||||
#endif
|
||||
}
|
||||
}
|
3
Assets/Mirror/Core/Tools/Vector3Half.cs.meta
Normal file
3
Assets/Mirror/Core/Tools/Vector3Half.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b70bf28681a14c65a37793a87c8df33e
|
||||
timeCreated: 1730890316
|
@ -1,4 +1,5 @@
|
||||
// base class for networking tests to make things easier.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@ -81,6 +82,18 @@ protected void CreateNetworked(out GameObject go, out NetworkIdentity identity)
|
||||
instantiated.Add(go);
|
||||
}
|
||||
|
||||
protected void CreateNetworked(out GameObject go, out NetworkIdentity identity, Action<NetworkIdentity> preAwake)
|
||||
{
|
||||
go = new GameObject();
|
||||
identity = go.AddComponent<NetworkIdentity>();
|
||||
preAwake(identity);
|
||||
// Awake is only called in play mode.
|
||||
// call manually for initialization.
|
||||
identity.Awake();
|
||||
// track
|
||||
instantiated.Add(go);
|
||||
}
|
||||
|
||||
// create GameObject + NetworkIdentity + NetworkBehaviour<T>
|
||||
// add to tracker list if needed (useful for cleanups afterwards)
|
||||
protected void CreateNetworked<T>(out GameObject go, out NetworkIdentity identity, out T component)
|
||||
@ -269,6 +282,44 @@ protected void CreateNetworkedAndSpawn(
|
||||
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||
}
|
||||
|
||||
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||
// => preAwake callbacks can be used to add network behaviours to the NI
|
||||
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||
// => returns objects from client and from server.
|
||||
// will be same in host mode.
|
||||
protected void CreateNetworkedAndSpawn(
|
||||
out GameObject serverGO, out NetworkIdentity serverIdentity, Action<NetworkIdentity> serverPreAwake,
|
||||
out GameObject clientGO, out NetworkIdentity clientIdentity, Action<NetworkIdentity> clientPreAwake,
|
||||
NetworkConnectionToClient ownerConnection = null)
|
||||
{
|
||||
// server & client need to be active before spawning
|
||||
Debug.Assert(NetworkClient.active, "NetworkClient needs to be active before spawning.");
|
||||
Debug.Assert(NetworkServer.active, "NetworkServer needs to be active before spawning.");
|
||||
|
||||
// create one on server, one on client
|
||||
// (spawning has to find it on client, it doesn't create it)
|
||||
CreateNetworked(out serverGO, out serverIdentity, serverPreAwake);
|
||||
CreateNetworked(out clientGO, out clientIdentity, clientPreAwake);
|
||||
|
||||
// give both a scene id and register it on client for spawnables
|
||||
clientIdentity.sceneId = serverIdentity.sceneId = (ulong)serverGO.GetHashCode();
|
||||
NetworkClient.spawnableObjects[clientIdentity.sceneId] = clientIdentity;
|
||||
|
||||
// spawn
|
||||
NetworkServer.Spawn(serverGO, ownerConnection);
|
||||
ProcessMessages();
|
||||
|
||||
// double check isServer/isClient. avoids debugging headaches.
|
||||
Assert.That(serverIdentity.isServer, Is.True);
|
||||
Assert.That(clientIdentity.isClient, Is.True);
|
||||
|
||||
// double check that we have authority if we passed an owner connection
|
||||
if (ownerConnection != null)
|
||||
Debug.Assert(clientIdentity.isOwned == true, $"Behaviour Had Wrong Authority when spawned, This means that the test is broken and will give the wrong results");
|
||||
|
||||
// make sure the client really spawned it.
|
||||
Assert.That(NetworkClient.spawned.ContainsKey(serverIdentity.netId));
|
||||
}
|
||||
// create GameObject + NetworkIdentity + NetworkBehaviour & SPAWN
|
||||
// => ownerConnection can be NetworkServer.localConnection if needed.
|
||||
protected void CreateNetworkedAndSpawn<T>(out GameObject go, out NetworkIdentity identity, out T component, NetworkConnectionToClient ownerConnection = null)
|
||||
|
@ -1,4 +1,5 @@
|
||||
// OnDe/SerializeSafely tests.
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using Mirror.Tests.EditorBehaviours.NetworkIdentities;
|
||||
using NUnit.Framework;
|
||||
@ -42,7 +43,7 @@ public void SerializeAndDeserializeAll()
|
||||
);
|
||||
|
||||
// set sync modes
|
||||
serverOwnerComp.syncMode = clientOwnerComp.syncMode = SyncMode.Owner;
|
||||
serverOwnerComp.syncMode = clientOwnerComp.syncMode = SyncMode.Owner;
|
||||
serverObserversComp.syncMode = clientObserversComp.syncMode = SyncMode.Observers;
|
||||
|
||||
// set unique values on server components
|
||||
@ -65,10 +66,127 @@ public void SerializeAndDeserializeAll()
|
||||
// deserialize client object with OBSERVERS payload
|
||||
reader = new NetworkReader(observersWriter.ToArray());
|
||||
clientIdentity.DeserializeClient(reader, true);
|
||||
Assert.That(clientOwnerComp.value, Is.EqualTo(null)); // owner mode shouldn't be in data
|
||||
Assert.That(clientOwnerComp.value, Is.EqualTo(null)); // owner mode shouldn't be in data
|
||||
Assert.That(clientObserversComp.value, Is.EqualTo(42)); // observers mode should be in data
|
||||
}
|
||||
|
||||
// test serialize -> deserialize of any supported number of components
|
||||
[Test]
|
||||
public void SerializeAndDeserializeN([NUnit.Framework.Range(1, 64)] int numberOfNBs)
|
||||
{
|
||||
List<SerializeTest1NetworkBehaviour> serverNBs = new List<SerializeTest1NetworkBehaviour>();
|
||||
List<SerializeTest1NetworkBehaviour> clientNBs = new List<SerializeTest1NetworkBehaviour>();
|
||||
// need two of both versions so we can serialize -> deserialize
|
||||
CreateNetworkedAndSpawn(
|
||||
out _, out NetworkIdentity serverIdentity, ni =>
|
||||
{
|
||||
for (int i = 0; i < numberOfNBs; i++)
|
||||
{
|
||||
SerializeTest1NetworkBehaviour nb = ni.gameObject.AddComponent<SerializeTest1NetworkBehaviour>();
|
||||
nb.syncInterval = 0;
|
||||
nb.syncMode = SyncMode.Observers;
|
||||
serverNBs.Add(nb);
|
||||
}
|
||||
},
|
||||
out _, out NetworkIdentity clientIdentity, ni =>
|
||||
{
|
||||
for (int i = 0; i < numberOfNBs; i++)
|
||||
{
|
||||
SerializeTest1NetworkBehaviour nb = ni.gameObject.AddComponent<SerializeTest1NetworkBehaviour>();
|
||||
nb.syncInterval = 0;
|
||||
nb.syncMode = SyncMode.Observers;
|
||||
clientNBs.Add(nb);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// INITIAL SYNC
|
||||
// set unique values on server components
|
||||
for (int i = 0; i < serverNBs.Count; i++)
|
||||
{
|
||||
serverNBs[i].value = (i + 1) * 3;
|
||||
serverNBs[i].SetDirty();
|
||||
}
|
||||
|
||||
// serialize server object
|
||||
serverIdentity.SerializeServer(true, ownerWriter, observersWriter);
|
||||
|
||||
// deserialize client object with OBSERVERS payload
|
||||
NetworkReader reader = new NetworkReader(observersWriter.ToArray());
|
||||
clientIdentity.DeserializeClient(reader, true);
|
||||
for (int i = 0; i < clientNBs.Count; i++)
|
||||
{
|
||||
int expected = (i + 1) * 3;
|
||||
Assert.That(clientNBs[i].value, Is.EqualTo(expected), $"Expected the clientNBs[{i}] to have a value of {expected}");
|
||||
}
|
||||
|
||||
// clear dirty bits for incremental sync
|
||||
foreach (SerializeTest1NetworkBehaviour serverNB in serverNBs)
|
||||
serverNB.ClearAllDirtyBits();
|
||||
|
||||
// INCREMENTAL SYNC ALL
|
||||
// set unique values on server components
|
||||
for (int i = 0; i < serverNBs.Count; i++)
|
||||
{
|
||||
serverNBs[i].value = (i + 1) * 11;
|
||||
serverNBs[i].SetDirty();
|
||||
}
|
||||
|
||||
ownerWriter.Reset();
|
||||
observersWriter.Reset();
|
||||
// serialize server object
|
||||
serverIdentity.SerializeServer(false, ownerWriter, observersWriter);
|
||||
|
||||
// deserialize client object with OBSERVERS payload
|
||||
reader = new NetworkReader(observersWriter.ToArray());
|
||||
clientIdentity.DeserializeClient(reader, false);
|
||||
for (int i = 0; i < clientNBs.Count; i++)
|
||||
{
|
||||
int expected = (i + 1) * 11;
|
||||
Assert.That(clientNBs[i].value, Is.EqualTo(expected), $"Expected the clientNBs[{i}] to have a value of {expected}");
|
||||
}
|
||||
|
||||
// clear dirty bits for incremental sync
|
||||
foreach (SerializeTest1NetworkBehaviour serverNB in serverNBs)
|
||||
serverNB.ClearAllDirtyBits();
|
||||
|
||||
// INCREMENTAL SYNC INDIVIDUAL
|
||||
for (int i = 0; i < numberOfNBs; i++)
|
||||
{
|
||||
// reset all client nbs
|
||||
foreach (SerializeTest1NetworkBehaviour clientNB in clientNBs)
|
||||
clientNB.value = 0;
|
||||
|
||||
int expected = (i + 1) * 7;
|
||||
|
||||
// set unique value on server components
|
||||
serverNBs[i].value = expected;
|
||||
serverNBs[i].SetDirty();
|
||||
|
||||
ownerWriter.Reset();
|
||||
observersWriter.Reset();
|
||||
// serialize server object
|
||||
serverIdentity.SerializeServer(false, ownerWriter, observersWriter);
|
||||
|
||||
// deserialize client object with OBSERVERS payload
|
||||
reader = new NetworkReader(observersWriter.ToArray());
|
||||
clientIdentity.DeserializeClient(reader, false);
|
||||
for (int index = 0; index < clientNBs.Count; index++)
|
||||
{
|
||||
SerializeTest1NetworkBehaviour clientNB = clientNBs[index];
|
||||
if (index == i)
|
||||
{
|
||||
Assert.That(clientNB.value, Is.EqualTo(expected), $"Expected the clientNBs[{index}] to have a value of {expected}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(clientNB.value, Is.EqualTo(0), $"Expected the clientNBs[{index}] to have a value of 0 since we're not syncing that index (on sync of #{i})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// serialization should work even if a component throws an exception.
|
||||
// so if first component throws, second should still be serialized fine.
|
||||
[Test]
|
||||
@ -150,20 +268,20 @@ public void TooManyComponents()
|
||||
public void ErrorCorrection()
|
||||
{
|
||||
int original = 0x12345678;
|
||||
byte safety = 0x78; // last byte
|
||||
byte safety = 0x78; // last byte
|
||||
|
||||
// correct size shouldn't be corrected
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 0, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 0, safety), Is.EqualTo(original));
|
||||
|
||||
// read a little too much
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 1, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 2, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 42, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 1, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 2, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original + 42, safety), Is.EqualTo(original));
|
||||
|
||||
// read a little too less
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original - 1, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original - 2, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original - 42, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original - 1, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original - 2, safety), Is.EqualTo(original));
|
||||
Assert.That(NetworkBehaviour.ErrorCorrection(original - 42, safety), Is.EqualTo(original));
|
||||
|
||||
// reading way too much / less is expected to fail.
|
||||
// we can only correct the last byte, not more.
|
||||
|
150
Assets/Mirror/Tests/Editor/Tools/Vector3HalfTests.cs
Normal file
150
Assets/Mirror/Tests/Editor/Tools/Vector3HalfTests.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Mirror.Tests.Tools
|
||||
{
|
||||
public class Vector3HalfTests
|
||||
{
|
||||
[Test]
|
||||
public void Constructor()
|
||||
{
|
||||
Vector3Half v = new Vector3Half();
|
||||
Assert.That(v.x, Is.EqualTo((Half)0));
|
||||
Assert.That(v.y, Is.EqualTo((Half)0));
|
||||
Assert.That(v.z, Is.EqualTo((Half)0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConstructorXYZ()
|
||||
{
|
||||
Vector3Half v = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Assert.That(v.x, Is.EqualTo((Half)1));
|
||||
Assert.That(v.y, Is.EqualTo((Half)2));
|
||||
Assert.That(v.z, Is.EqualTo((Half)3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OperatorAdd()
|
||||
{
|
||||
Vector3Half a = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Vector3Half b = new Vector3Half((Half)2, (Half)3, (Half)4);
|
||||
Assert.That(a + b, Is.EqualTo(new Vector3Half((Half)3, (Half)5, (Half)7)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OperatorSubtract()
|
||||
{
|
||||
Vector3Half a = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Vector3Half b = new Vector3Half((Half)(-2), (Half)(-3), (Half)(-4));
|
||||
Assert.That(a - b, Is.EqualTo(new Vector3Half((Half)3, (Half)5, (Half)7)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OperatorInverse()
|
||||
{
|
||||
Vector3Half v = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Assert.That(-v, Is.EqualTo(new Vector3Half((Half)(-1), (Half)(-2), (Half)(-3))));
|
||||
}
|
||||
|
||||
// [Test]
|
||||
// public void OperatorMultiply()
|
||||
// {
|
||||
// Vector3Half a = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
// // a * n, n * a are two different operators. test both.
|
||||
// Assert.That(a * (Half)2, Is.EqualTo(new Vector3Half((Half)2, (Half)4, (Half)6)));
|
||||
// Assert.That((Half)2 * a, Is.EqualTo(new Vector3Half((Half)2, (Half)4, (Half)6)));
|
||||
// }
|
||||
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[Test]
|
||||
public void OperatorEquals()
|
||||
{
|
||||
// two vectors which are approximately the same
|
||||
Vector3Half a = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Vector3Half b = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Assert.That(a == b, Is.True);
|
||||
|
||||
// two vectors which are definitely not the same
|
||||
Assert.That(a == Vector3Half.one, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OperatorNotEquals()
|
||||
{
|
||||
// two vectors which are approximately the same
|
||||
Vector3Half a = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Vector3Half b = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
Assert.That(a != b, Is.False);
|
||||
|
||||
// two vectors which are definitely not the same
|
||||
Assert.That(a != Vector3Half.one, Is.True);
|
||||
}
|
||||
#endif
|
||||
|
||||
[Test]
|
||||
public void OperatorIndexer()
|
||||
{
|
||||
Vector3Half a = new Vector3Half((Half)1, (Half)2, (Half)3);
|
||||
|
||||
// get
|
||||
Assert.That(a[0], Is.EqualTo((Half)1));
|
||||
Assert.That(a[1], Is.EqualTo((Half)2));
|
||||
Assert.That(a[2], Is.EqualTo((Half)3));
|
||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
||||
{
|
||||
Half _ = a[-1];
|
||||
});
|
||||
Assert.Throws<IndexOutOfRangeException>(() =>
|
||||
{
|
||||
Half _ = a[3];
|
||||
});
|
||||
|
||||
// set
|
||||
a[0] = -1;
|
||||
a[1] = -2;
|
||||
a[2] = -3;
|
||||
Assert.Throws<IndexOutOfRangeException>(() => { a[-1] = (Half)0; });
|
||||
Assert.Throws<IndexOutOfRangeException>(() => { a[3] = (Half)0; });
|
||||
Assert.That(a, Is.EqualTo(new Vector3Half((Half)(-1), (Half)(-2), (Half)(-3))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToStringTest()
|
||||
{
|
||||
// should be rounded to :F2
|
||||
Vector3Half v = new Vector3Half((Half)(-10), (Half)0, (Half)42);
|
||||
Assert.That(v.ToString(), Is.EqualTo("(-10 0 42)"));
|
||||
}
|
||||
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[Test]
|
||||
public void EqualsVector3Half()
|
||||
{
|
||||
Assert.That(Vector3Half.one.Equals(Vector3Half.one), Is.True);
|
||||
Assert.That(Vector3Half.one.Equals(Vector3Half.zero), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EqualsObject()
|
||||
{
|
||||
Assert.That(Vector3Half.one.Equals((object)42), Is.False);
|
||||
Assert.That(Vector3Half.one.Equals((object)Vector3Half.one), Is.True);
|
||||
Assert.That(Vector3Half.one.Equals((object)Vector3Half.zero), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetHashCodeTest()
|
||||
{
|
||||
// shouldn't be 0
|
||||
Assert.That(Vector3Half.zero.GetHashCode(), !Is.EqualTo(0));
|
||||
Assert.That(Vector3Half.one.GetHashCode(), !Is.EqualTo(0));
|
||||
|
||||
// should be same for same vector
|
||||
Assert.That(Vector3Half.zero.GetHashCode(), Is.EqualTo(Vector3Half.zero.GetHashCode()));
|
||||
|
||||
// should be different for different vectors
|
||||
Assert.That(Vector3Half.zero.GetHashCode(), !Is.EqualTo(Vector3Half.one.GetHashCode()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc5f32db47ab4ffb92433050cc1b6e9f
|
||||
timeCreated: 1730890719
|
Loading…
Reference in New Issue
Block a user