Skip to content

Commit 01ebbc2

Browse files
committed
getting ready to test dx12 and fix known bad bugs
1 parent 80447d7 commit 01ebbc2

6 files changed

Lines changed: 163 additions & 495 deletions

File tree

Basis/Assets/AddressableAssetsData/link.xml

Lines changed: 0 additions & 384 deletions
This file was deleted.

Basis/Assets/AddressableAssetsData/link.xml.meta

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 112 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,161 @@
11
using System;
22
using System.Runtime.CompilerServices;
33
using Unity.Mathematics;
4-
using static BasisNetworkPrimitiveCompression;
4+
55
namespace Basis.Scripts.Networking.Compression
66
{
77
public static class BasisUnityBitPackerExtensionsUnsafe
88
{
99
[MethodImpl(MethodImplOptions.AggressiveInlining)]
10-
public static void WriteUShort(ushort value, ref byte[] bytes, ref int offset)
10+
private static bool EnsureSpace(byte[] bytes, int offset, int size)
1111
{
12-
bytes[offset++] = (byte)value;
13-
bytes[offset++] = (byte)(value >> 8);
12+
return (uint)offset <= (uint)bytes.Length && offset + size <= bytes.Length;
1413
}
1514

1615
[MethodImpl(MethodImplOptions.AggressiveInlining)]
17-
public static ushort ReadUShort(ref byte[] bytes, ref int offset)
16+
private static bool IsFinite(float v) => math.isfinite(v);
17+
18+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
19+
private static bool IsFinite3(float a, float b, float c) =>
20+
IsFinite(a) & IsFinite(b) & IsFinite(c);
21+
22+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
23+
private static bool IsFinite4(float a, float b, float c, float d) =>
24+
IsFinite(a) & IsFinite(b) & IsFinite(c) & IsFinite(d);
25+
26+
/// <summary>
27+
/// Optional stricter validation: quaternions should be close-ish to unit length.
28+
/// Networking compression often expects normalized rotations.
29+
/// </summary>
30+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
31+
private static bool IsReasonableQuaternion(float x, float y, float z, float w, float tolerance)
1832
{
19-
ushort result = (ushort)(bytes[offset] | (bytes[offset + 1] << 8));
33+
// length^2 should be near 1
34+
float lenSq = x * x + y * y + z * z + w * w;
35+
// Reject zeros / nonsense
36+
if (!(lenSq > 0f) || !IsFinite(lenSq)) return false;
37+
38+
// Accept within tolerance (e.g. 0.01..0.05 depending on how noisy your source can be)
39+
return math.abs(lenSq - 1f) <= tolerance;
40+
}
41+
42+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
43+
public static bool TryReadUShort(ref byte[] bytes, ref int offset, out ushort value)
44+
{
45+
value = default;
46+
if (!EnsureSpace(bytes, offset, 2)) return false;
47+
48+
value = (ushort)(bytes[offset] | (bytes[offset + 1] << 8));
2049
offset += 2;
21-
return result;
50+
return true;
2251
}
23-
public unsafe static void WriteQuaternionToBytes(quaternion q,ref byte[] bytes,ref int offset)
52+
53+
54+
public unsafe static bool TryReadQuaternionFromBytes(
55+
ref byte[] bytes,
56+
ref int offset,
57+
out quaternion q,
58+
float unitLengthTolerance = 0.02f,
59+
bool requireUnitLength = true)
2460
{
61+
q = default;
62+
if (!EnsureSpace(bytes, offset, 16)) return false;
63+
64+
float x, y, z, w;
2565
fixed (byte* ptr = &bytes[offset])
2666
{
2767
float* f = (float*)ptr;
28-
f[0] = float.IsNaN(q.value.x) ? 0f : q.value.x;
29-
f[1] = float.IsNaN(q.value.y) ? 0f : q.value.y;
30-
f[2] = float.IsNaN(q.value.z) ? 0f : q.value.z;
31-
f[3] = float.IsNaN(q.value.w) ? 1f : q.value.w;
68+
x = f[0];
69+
y = f[1];
70+
z = f[2];
71+
w = f[3];
72+
}
73+
74+
// Validate without repairing
75+
if (!IsFinite4(x, y, z, w))
76+
{
77+
return false;
78+
}
79+
80+
if (requireUnitLength && !IsReasonableQuaternion(x, y, z, w, unitLengthTolerance))
81+
{
82+
return false;
3283
}
84+
3385
offset += 16;
86+
q = new quaternion(x, y, z, w);
87+
return true;
3488
}
3589

36-
public unsafe static quaternion ReadQuaternionFromBytes(ref byte[] bytes, ref int offset)
90+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
91+
public static bool TryReadPosition(ref byte[] buffer, ref int offset, out Unity.Mathematics.float3 position)
3792
{
38-
float x, y, z, w;
39-
fixed (byte* ptr = &bytes[offset])
93+
position = default;
94+
if (!EnsureSpace(buffer, offset, 12)) return false;
95+
96+
float x, y, z;
97+
unsafe
4098
{
41-
x = *((float*)ptr);
42-
y = *((float*)(ptr + 4));
43-
z = *((float*)(ptr + 8));
44-
w = *((float*)(ptr + 12));
99+
fixed (byte* src = &buffer[offset])
100+
{
101+
float* fSrc = (float*)src;
102+
x = fSrc[0];
103+
y = fSrc[1];
104+
z = fSrc[2];
105+
}
45106
}
46-
offset += 16;
47107

48-
if (float.IsNaN(x)) x = 0f;
49-
if (float.IsNaN(y)) y = 0f;
50-
if (float.IsNaN(z)) z = 0f;
51-
if (float.IsNaN(w)) w = 1f;
108+
if (!IsFinite3(x, y, z)) return false;
52109

53-
return new quaternion(x, y, z, w);
110+
offset += 12;
111+
position = new Unity.Mathematics.float3(x, y, z);
112+
return true;
54113
}
55-
static void WriteULongLE(ulong v, ref byte[] bytes, ref int offset)
114+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
115+
private static float Sanitize(float v, float fallback)
56116
{
57-
// little-endian
58-
bytes[offset++] = (byte)(v);
59-
bytes[offset++] = (byte)(v >> 8);
60-
bytes[offset++] = (byte)(v >> 16);
61-
bytes[offset++] = (byte)(v >> 24);
62-
bytes[offset++] = (byte)(v >> 32);
63-
bytes[offset++] = (byte)(v >> 40);
64-
bytes[offset++] = (byte)(v >> 48);
65-
bytes[offset++] = (byte)(v >> 56);
117+
// math.isfinite catches both NaN and ±Infinity.
118+
return math.isfinite(v) ? v : fallback;
66119
}
67-
68-
static ulong ReadULongLE(ref byte[] bytes, ref int offset)
120+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
121+
public static void WriteUShort(ushort value, ref byte[] bytes, ref int offset)
69122
{
70-
ulong v =
71-
(ulong)bytes[offset] |
72-
((ulong)bytes[offset + 1] << 8) |
73-
((ulong)bytes[offset + 2] << 16) |
74-
((ulong)bytes[offset + 3] << 24) |
75-
((ulong)bytes[offset + 4] << 32) |
76-
((ulong)bytes[offset + 5] << 40) |
77-
((ulong)bytes[offset + 6] << 48) |
78-
((ulong)bytes[offset + 7] << 56);
79-
80-
offset += 8;
81-
return v;
123+
EnsureSpace(bytes, offset, 2); bytes[offset++] = (byte)value; bytes[offset++] = (byte)(value >> 8);
82124
}
83125
[MethodImpl(MethodImplOptions.AggressiveInlining)]
84-
public static void WritePosition(UnityEngine.Vector3 position, ref byte[] buffer, ref int offset)
126+
public static ushort ReadUShort(ref byte[] bytes, ref int offset)
85127
{
86-
unsafe
128+
EnsureSpace(bytes, offset, 2);
129+
ushort result = (ushort)(bytes[offset] | (bytes[offset + 1] << 8));
130+
offset += 2;
131+
return result;
132+
}
133+
public unsafe static void WriteQuaternionToBytes(quaternion q, ref byte[] bytes, ref int offset)
134+
{
135+
EnsureSpace(bytes, offset, 16); fixed (byte* ptr = &bytes[offset])
87136
{
88-
fixed (byte* dst = &buffer[offset])
89-
{
90-
float* fDst = (float*)dst;
91-
fDst[0] = position.x;
92-
fDst[1] = position.y;
93-
fDst[2] = position.z;
94-
}
137+
float* f = (float*)ptr; f[0] = Sanitize(q.value.x, 0f);
138+
f[1] = Sanitize(q.value.y, 0f);
139+
f[2] = Sanitize(q.value.z, 0f);
140+
f[3] = Sanitize(q.value.w, 1f);
95141
}
96-
97-
offset += 12;
142+
offset += 16;
98143
}
99-
100144
[MethodImpl(MethodImplOptions.AggressiveInlining)]
101-
public static UnityEngine.Vector3 ReadPosition(ref byte[] buffer, ref int offset)
145+
public static void WritePosition(UnityEngine.Vector3 position, ref byte[] buffer, ref int offset)
102146
{
103-
UnityEngine.Vector3 result;
147+
EnsureSpace(buffer, offset, 12);
104148
unsafe
105149
{
106-
fixed (byte* src = &buffer[offset])
150+
fixed (byte* dst = &buffer[offset])
107151
{
108-
float* fSrc = (float*)src;
109-
result.x = float.IsNaN(fSrc[0]) ? 0f : fSrc[0];
110-
result.y = float.IsNaN(fSrc[1]) ? 0f : fSrc[1];
111-
result.z = float.IsNaN(fSrc[2]) ? 0f : fSrc[2];
152+
float* fDst = (float*)dst;
153+
fDst[0] = Sanitize(position.x, 0f);
154+
fDst[1] = Sanitize(position.y, 0f);
155+
fDst[2] = Sanitize(position.z, 0f);
112156
}
113157
}
114-
115158
offset += 12;
116-
return result;
117159
}
118160
}
119161
}

Basis/Packages/com.basis.framework/Networking/NetworkedAvatar/BasisNetworkAvatarDecompressor.cs

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public static void DecompressAndProcessAvatar(BasisNetworkReceiver baseReceiver,
2929
{
3030
int offset = 0;
3131
double interval = (double)BasisNetworkManagement.ServerMetaDataMessage.SyncInterval;
32-
if (CreateAvatarBuffer(data, ref offset, (interval + (double)syncMessage.interval) / 1000.0, out BasisAvatarBuffer avatarBuffer))
32+
if (TryCreateAvatarBuffer(data, ref offset, (interval + (double)syncMessage.interval) / 1000.0, out BasisAvatarBuffer avatarBuffer))
3333
{
3434
EnqueueAndProcessAdditionalData(baseReceiver, avatarBuffer, syncMessage.avatarSerialization);
3535
}
@@ -53,7 +53,7 @@ public static void DecompressAndProcessAvatar(BasisNetworkReceiver baseReceiver,
5353
if (length >= BasisBitPackingConstants.AvatarSyncSize)
5454
{
5555
int offset = 0;
56-
if (CreateAvatarBuffer(data, ref offset, 0.01f, out BasisAvatarBuffer avatarBuffer))
56+
if (TryCreateAvatarBuffer(data, ref offset, 0.01f, out BasisAvatarBuffer avatarBuffer))
5757
{
5858
EnqueueAndProcessAdditionalData(baseReceiver, avatarBuffer, avatarSerialization);
5959
}
@@ -63,53 +63,65 @@ public static void DecompressAndProcessAvatar(BasisNetworkReceiver baseReceiver,
6363
BasisDebug.LogError("Data did not have enough for AvatarsyncMessage", BasisDebug.LogTag.Networking);
6464
}
6565
}
66-
67-
private static bool CreateAvatarBuffer(byte[] data, ref int offset, double secondsInterval, out BasisAvatarBuffer BasisAvatarBuffer)
66+
/// <summary>
67+
/// Creates A Avatar Buffer, removes NaN and infinite data
68+
/// </summary>
69+
/// <param name="data"></param>
70+
/// <param name="offset"></param>
71+
/// <param name="secondsInterval"></param>
72+
/// <param name="basisAvatarBuffer"></param>
73+
/// <returns></returns>
74+
private static bool TryCreateAvatarBuffer(byte[] data,ref int offset,double secondsInterval,out BasisAvatarBuffer basisAvatarBuffer)
6875
{
69-
BasisAvatarBuffer = BasisAvatarBufferPool.Get();
70-
BasisAvatarBuffer.Position = BasisUnityBitPackerExtensionsUnsafe.ReadPosition(ref data, ref offset);
71-
BasisAvatarBuffer.Rotation = SanitizeRotation(BasisUnityBitPackerExtensionsUnsafe.ReadQuaternionFromBytes(ref data, ref offset));
72-
BasisOrderedDataSet.DecompressAvatarMuscles_BitPacked(data, ref BasisAvatarBuffer.Muscles, ref offset);
73-
BasisAvatarBuffer.Scale = MuscleDecompress(BasisUnityBitPackerExtensionsUnsafe.ReadUShort(ref data, ref offset), MinimumValueSupported, MaximumValueSupported);
74-
// Reject NaN, Infinity, zero, negative, or insane values
76+
basisAvatarBuffer = null;
77+
int startOffset = offset;
7578
if (!math.isfinite(secondsInterval) || secondsInterval <= 0.0 || secondsInterval > 1.0)
7679
{
77-
BasisDebug.LogError($"SecondsInterval was {secondsInterval}, rejecting", BasisDebug.LogTag.Remote);
78-
BasisAvatarBufferPool.Release(BasisAvatarBuffer);
79-
return false;
80+
goto Fail;
8081
}
81-
BasisAvatarBuffer.SecondsInterval = secondsInterval;
82+
basisAvatarBuffer = BasisAvatarBufferPool.Get();
8283

83-
if (!math.all(math.isfinite(BasisAvatarBuffer.Position)))
84+
// Position
85+
if (!BasisUnityBitPackerExtensionsUnsafe.TryReadPosition(ref data, ref offset, out basisAvatarBuffer.Position))
8486
{
85-
BasisDebug.LogError("Non-finite Position detected, rejecting", BasisDebug.LogTag.Remote);
86-
BasisAvatarBufferPool.Release(BasisAvatarBuffer);
87-
return false;
87+
goto Fail;
8888
}
8989

90-
if (!math.all(math.isfinite(BasisAvatarBuffer.Scale)))
90+
// Rotation
91+
if (!BasisUnityBitPackerExtensionsUnsafe.TryReadQuaternionFromBytes( ref data, ref offset, out basisAvatarBuffer.Rotation))
9192
{
92-
BasisDebug.LogError("Non-finite Scale detected, rejecting", BasisDebug.LogTag.Remote);
93-
BasisAvatarBufferPool.Release(BasisAvatarBuffer);
94-
return false;
93+
goto Fail;
9594
}
96-
return true;
97-
}
98-
private static quaternion SanitizeRotation(quaternion q)
99-
{
100-
if (!math.isfinite(q.value.x) || !math.isfinite(q.value.y) || !math.isfinite(q.value.z) || !math.isfinite(q.value.w))
95+
BasisOrderedDataSet.DecompressAvatarMuscles_BitPacked( data, ref basisAvatarBuffer.Muscles, ref offset);
96+
97+
// Scale
98+
if (!BasisUnityBitPackerExtensionsUnsafe.TryReadUShort( ref data, ref offset, out ushort uScale))
10199
{
102-
return quaternion.identity;
100+
goto Fail;
103101
}
104102

105-
float magSq = q.value.x * q.value.x + q.value.y * q.value.y + q.value.z * q.value.z + q.value.w * q.value.w;
106-
if (magSq < 1e-8f)
103+
basisAvatarBuffer.Scale = MuscleDecompress(uScale, MinimumValueSupported, MaximumValueSupported);
104+
basisAvatarBuffer.SecondsInterval = secondsInterval;
105+
return true;
106+
107+
Fail:
108+
offset = startOffset; // optional but strongly recommended
109+
if (basisAvatarBuffer != null)
107110
{
108-
return quaternion.identity;
111+
BasisAvatarBufferPool.Release(basisAvatarBuffer);
112+
basisAvatarBuffer = null;
109113
}
110-
111-
return math.normalize(q);
114+
BasisDebug.LogError($"non finite data found in Decompression Stage, bailing.", BasisDebug.LogTag.Remote);
115+
return false;
112116
}
117+
118+
/// <summary>
119+
/// cant generate a nan unless min,max or floatrangedifference go bad (const cant)
120+
/// </summary>
121+
/// <param name="value"></param>
122+
/// <param name="minValue"></param>
123+
/// <param name="maxValue"></param>
124+
/// <returns></returns>
113125
public static float MuscleDecompress(ushort value, float minValue, float maxValue)
114126
{
115127
float normalized = value / FloatRangeDifference;

Basis/Packages/com.basis.framework/Networking/Utils/BasisOrderedDataSet.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ public static void DecompressAvatarMuscles_BitPacked(byte[] data, ref NativeArra
6666
float range = RangeMuscle[muscleIndex];
6767

6868
float value = min + norm * range;
69+
if (!math.isfinite(value))
70+
{
71+
value = min;
72+
}
73+
6974
outputArray[muscleIndex] = math.clamp(value, min, max);
7075
}
7176

Basis/ProjectSettings/ProjectSettings.asset

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ PlayerSettings:
525525
m_GraphicsJobMode: 2
526526
m_BuildTargetGraphicsAPIs:
527527
- m_BuildTarget: WindowsStandaloneSupport
528-
m_APIs: 15000000
528+
m_APIs: 1200000015000000
529529
m_Automatic: 0
530530
- m_BuildTarget: MacStandaloneSupport
531531
m_APIs: 10000000

0 commit comments

Comments
 (0)