mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
Split Utils into FloatBytePacker and NetworkManager. (#483)
This commit is contained in:
parent
96133d1583
commit
51458762d4
@ -77,14 +77,14 @@ static void SerializeIntoWriter(NetworkWriter writer, Vector3 position, Quaterni
|
||||
else if (compressRotation == Compression.Much)
|
||||
{
|
||||
// write 3 byte. scaling [0,360] to [0,255]
|
||||
writer.Write(Utils.ScaleFloatToByte(euler.x, 0, 360, byte.MinValue, byte.MaxValue));
|
||||
writer.Write(Utils.ScaleFloatToByte(euler.y, 0, 360, byte.MinValue, byte.MaxValue));
|
||||
writer.Write(Utils.ScaleFloatToByte(euler.z, 0, 360, byte.MinValue, byte.MaxValue));
|
||||
writer.Write(FloatBytePacker.ScaleFloatToByte(euler.x, 0, 360, byte.MinValue, byte.MaxValue));
|
||||
writer.Write(FloatBytePacker.ScaleFloatToByte(euler.y, 0, 360, byte.MinValue, byte.MaxValue));
|
||||
writer.Write(FloatBytePacker.ScaleFloatToByte(euler.z, 0, 360, byte.MinValue, byte.MaxValue));
|
||||
}
|
||||
else if (compressRotation == Compression.Lots)
|
||||
{
|
||||
// write 2 byte, 5 bits for each float
|
||||
writer.Write(Utils.PackThreeFloatsIntoUShort(euler.x, euler.y, euler.z, 0, 360));
|
||||
writer.Write(FloatBytePacker.PackThreeFloatsIntoUShort(euler.x, euler.y, euler.z, 0, 360));
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,15 +128,15 @@ void DeserializeFromReader(NetworkReader reader)
|
||||
else if (compressRotation == Compression.Much)
|
||||
{
|
||||
// read 3 byte. scaling [0,255] to [0,360]
|
||||
float x = Utils.ScaleByteToFloat(reader.ReadByte(), byte.MinValue, byte.MaxValue, 0, 360);
|
||||
float y = Utils.ScaleByteToFloat(reader.ReadByte(), byte.MinValue, byte.MaxValue, 0, 360);
|
||||
float z = Utils.ScaleByteToFloat(reader.ReadByte(), byte.MinValue, byte.MaxValue, 0, 360);
|
||||
float x = FloatBytePacker.ScaleByteToFloat(reader.ReadByte(), byte.MinValue, byte.MaxValue, 0, 360);
|
||||
float y = FloatBytePacker.ScaleByteToFloat(reader.ReadByte(), byte.MinValue, byte.MaxValue, 0, 360);
|
||||
float z = FloatBytePacker.ScaleByteToFloat(reader.ReadByte(), byte.MinValue, byte.MaxValue, 0, 360);
|
||||
temp.rotation = Quaternion.Euler(x, y, z);
|
||||
}
|
||||
else if (compressRotation == Compression.Lots)
|
||||
{
|
||||
// read 2 byte, 5 bits per float
|
||||
float[] xyz = Utils.UnpackUShortIntoThreeFloats(reader.ReadUInt16(), 0, 360);
|
||||
float[] xyz = FloatBytePacker.UnpackUShortIntoThreeFloats(reader.ReadUInt16(), 0, 360);
|
||||
temp.rotation = Quaternion.Euler(xyz[0], xyz[1], xyz[2]);
|
||||
}
|
||||
|
||||
|
58
Assets/Mirror/Runtime/FloatBytePacker.cs
Normal file
58
Assets/Mirror/Runtime/FloatBytePacker.cs
Normal file
@ -0,0 +1,58 @@
|
||||
namespace Mirror
|
||||
{
|
||||
public static class FloatBytePacker
|
||||
{
|
||||
// ScaleFloatToByte( -1f, -1f, 1f, byte.MinValue, byte.MaxValue) => 0
|
||||
// ScaleFloatToByte( 0f, -1f, 1f, byte.MinValue, byte.MaxValue) => 127
|
||||
// ScaleFloatToByte(0.5f, -1f, 1f, byte.MinValue, byte.MaxValue) => 191
|
||||
// ScaleFloatToByte( 1f, -1f, 1f, byte.MinValue, byte.MaxValue) => 255
|
||||
public static byte ScaleFloatToByte(float value, float minValue, float maxValue, byte minTarget, byte maxTarget)
|
||||
{
|
||||
// note: C# byte - byte => int, hence so many casts
|
||||
int targetRange = maxTarget - minTarget; // max byte - min byte only fits into something bigger
|
||||
float valueRange = maxValue - minValue;
|
||||
float valueRelative = value - minValue;
|
||||
return (byte)(minTarget + (byte)(valueRelative/valueRange * (float)targetRange));
|
||||
}
|
||||
|
||||
// ScaleByteToFloat( 0, byte.MinValue, byte.MaxValue, -1, 1) => -1
|
||||
// ScaleByteToFloat(127, byte.MinValue, byte.MaxValue, -1, 1) => -0.003921569
|
||||
// ScaleByteToFloat(191, byte.MinValue, byte.MaxValue, -1, 1) => 0.4980392
|
||||
// ScaleByteToFloat(255, byte.MinValue, byte.MaxValue, -1, 1) => 1
|
||||
public static float ScaleByteToFloat(byte value, byte minValue, byte maxValue, float minTarget, float maxTarget)
|
||||
{
|
||||
// note: C# byte - byte => int, hence so many casts
|
||||
float targetRange = maxTarget - minTarget;
|
||||
byte valueRange = (byte)(maxValue - minValue);
|
||||
byte valueRelative = (byte)(value - minValue);
|
||||
return minTarget + ((float)valueRelative/(float)valueRange * targetRange);
|
||||
}
|
||||
|
||||
// eulerAngles have 3 floats, putting them into 2 bytes of [x,y],[z,0]
|
||||
// would be a waste. instead we compress into 5 bits each => 15 bits.
|
||||
// so a ushort.
|
||||
public static ushort PackThreeFloatsIntoUShort(float u, float v, float w, float minValue, float maxValue)
|
||||
{
|
||||
// 5 bits max value = 1+2+4+8+16 = 31 = 0x1F
|
||||
byte lower = ScaleFloatToByte(u, minValue, maxValue, 0x00, 0x1F);
|
||||
byte middle = ScaleFloatToByte(v, minValue, maxValue, 0x00, 0x1F);
|
||||
byte upper = ScaleFloatToByte(w, minValue, maxValue, 0x00, 0x1F);
|
||||
ushort combined = (ushort)(upper << 10 | middle << 5 | lower);
|
||||
return combined;
|
||||
}
|
||||
|
||||
// see PackThreeFloatsIntoUShort for explanation
|
||||
public static float[] UnpackUShortIntoThreeFloats(ushort combined, float minTarget, float maxTarget)
|
||||
{
|
||||
byte lower = (byte)(combined & 0x1F);
|
||||
byte middle = (byte)((combined >> 5) & 0x1F);
|
||||
byte upper = (byte)(combined >> 10); // nothing on the left, no & needed
|
||||
|
||||
// note: we have to use 4 bits per float, so between 0x00 and 0x0F
|
||||
float u = ScaleByteToFloat(lower, 0x00, 0x1F, minTarget, maxTarget);
|
||||
float v = ScaleByteToFloat(middle, 0x00, 0x1F, minTarget, maxTarget);
|
||||
float w = ScaleByteToFloat(upper, 0x00, 0x1F, minTarget, maxTarget);
|
||||
return new float[]{u, v, w};
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Mirror/Runtime/FloatBytePacker.cs.meta
Normal file
11
Assets/Mirror/Runtime/FloatBytePacker.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afd3cca6a786d4208b1d0f7f2b168901
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -85,13 +85,19 @@ public virtual void Awake()
|
||||
InitializeSingleton();
|
||||
|
||||
// headless mode? then start the server
|
||||
if (Utils.IsHeadless() && startOnHeadless)
|
||||
if (IsHeadless() && startOnHeadless)
|
||||
{
|
||||
Application.targetFrameRate = 60;
|
||||
StartServer();
|
||||
}
|
||||
}
|
||||
|
||||
// headless mode detection
|
||||
public static bool IsHeadless()
|
||||
{
|
||||
return SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null;
|
||||
}
|
||||
|
||||
void InitializeSingleton()
|
||||
{
|
||||
if (singleton != null && singleton == this)
|
||||
|
@ -133,66 +133,4 @@ public static bool UnpackMessage(NetworkReader messageReader, out ushort msgType
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
// ScaleFloatToByte( -1f, -1f, 1f, byte.MinValue, byte.MaxValue) => 0
|
||||
// ScaleFloatToByte( 0f, -1f, 1f, byte.MinValue, byte.MaxValue) => 127
|
||||
// ScaleFloatToByte(0.5f, -1f, 1f, byte.MinValue, byte.MaxValue) => 191
|
||||
// ScaleFloatToByte( 1f, -1f, 1f, byte.MinValue, byte.MaxValue) => 255
|
||||
public static byte ScaleFloatToByte(float value, float minValue, float maxValue, byte minTarget, byte maxTarget)
|
||||
{
|
||||
// note: C# byte - byte => int, hence so many casts
|
||||
int targetRange = maxTarget - minTarget; // max byte - min byte only fits into something bigger
|
||||
float valueRange = maxValue - minValue;
|
||||
float valueRelative = value - minValue;
|
||||
return (byte)(minTarget + (byte)(valueRelative/valueRange * (float)targetRange));
|
||||
}
|
||||
|
||||
// ScaleByteToFloat( 0, byte.MinValue, byte.MaxValue, -1, 1) => -1
|
||||
// ScaleByteToFloat(127, byte.MinValue, byte.MaxValue, -1, 1) => -0.003921569
|
||||
// ScaleByteToFloat(191, byte.MinValue, byte.MaxValue, -1, 1) => 0.4980392
|
||||
// ScaleByteToFloat(255, byte.MinValue, byte.MaxValue, -1, 1) => 1
|
||||
public static float ScaleByteToFloat(byte value, byte minValue, byte maxValue, float minTarget, float maxTarget)
|
||||
{
|
||||
// note: C# byte - byte => int, hence so many casts
|
||||
float targetRange = maxTarget - minTarget;
|
||||
byte valueRange = (byte)(maxValue - minValue);
|
||||
byte valueRelative = (byte)(value - minValue);
|
||||
return minTarget + ((float)valueRelative/(float)valueRange * targetRange);
|
||||
}
|
||||
|
||||
// eulerAngles have 3 floats, putting them into 2 bytes of [x,y],[z,0]
|
||||
// would be a waste. instead we compress into 5 bits each => 15 bits.
|
||||
// so a ushort.
|
||||
public static ushort PackThreeFloatsIntoUShort(float u, float v, float w, float minValue, float maxValue)
|
||||
{
|
||||
// 5 bits max value = 1+2+4+8+16 = 31 = 0x1F
|
||||
byte lower = ScaleFloatToByte(u, minValue, maxValue, 0x00, 0x1F);
|
||||
byte middle = ScaleFloatToByte(v, minValue, maxValue, 0x00, 0x1F);
|
||||
byte upper = ScaleFloatToByte(w, minValue, maxValue, 0x00, 0x1F);
|
||||
ushort combined = (ushort)(upper << 10 | middle << 5 | lower);
|
||||
return combined;
|
||||
}
|
||||
|
||||
// see PackThreeFloatsIntoUShort for explanation
|
||||
public static float[] UnpackUShortIntoThreeFloats(ushort combined, float minTarget, float maxTarget)
|
||||
{
|
||||
byte lower = (byte)(combined & 0x1F);
|
||||
byte middle = (byte)((combined >> 5) & 0x1F);
|
||||
byte upper = (byte)(combined >> 10); // nothing on the left, no & needed
|
||||
|
||||
// note: we have to use 4 bits per float, so between 0x00 and 0x0F
|
||||
float u = ScaleByteToFloat(lower, 0x00, 0x1F, minTarget, maxTarget);
|
||||
float v = ScaleByteToFloat(middle, 0x00, 0x1F, minTarget, maxTarget);
|
||||
float w = ScaleByteToFloat(upper, 0x00, 0x1F, minTarget, maxTarget);
|
||||
return new float[]{u, v, w};
|
||||
}
|
||||
|
||||
// headless mode detection
|
||||
public static bool IsHeadless()
|
||||
{
|
||||
return SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
Assets/Mirror/Tests/FloatBytePackerTest.cs
Normal file
25
Assets/Mirror/Tests/FloatBytePackerTest.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using NUnit.Framework;
|
||||
namespace Mirror
|
||||
{
|
||||
[TestFixture]
|
||||
public class FloatBytePackerTest
|
||||
{
|
||||
[Test]
|
||||
public void TestScaleFloatToByte()
|
||||
{
|
||||
Assert.That(FloatBytePacker.ScaleFloatToByte( -1f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(0));
|
||||
Assert.That(FloatBytePacker.ScaleFloatToByte( 0f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(127));
|
||||
Assert.That(FloatBytePacker.ScaleFloatToByte(0.5f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(191));
|
||||
Assert.That(FloatBytePacker.ScaleFloatToByte( 1f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(255));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScaleByteToFloat()
|
||||
{
|
||||
Assert.That(FloatBytePacker.ScaleByteToFloat( 0, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(-1).Within(0.0001f));
|
||||
Assert.That(FloatBytePacker.ScaleByteToFloat(127, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(-0.003921569f).Within(0.0001f));
|
||||
Assert.That(FloatBytePacker.ScaleByteToFloat(191, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(0.4980392f).Within(0.0001f));
|
||||
Assert.That(FloatBytePacker.ScaleByteToFloat(255, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(1).Within(0.0001f));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using NUnit.Framework;
|
||||
namespace Mirror
|
||||
{
|
||||
[TestFixture]
|
||||
public class UtilsTest
|
||||
{
|
||||
[Test]
|
||||
public void TestScaleFloatToByte()
|
||||
{
|
||||
Assert.That(Utils.ScaleFloatToByte( -1f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(0));
|
||||
Assert.That(Utils.ScaleFloatToByte( 0f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(127));
|
||||
Assert.That(Utils.ScaleFloatToByte(0.5f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(191));
|
||||
Assert.That(Utils.ScaleFloatToByte( 1f, -1f, 1f, byte.MinValue, byte.MaxValue), Is.EqualTo(255));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ScaleByteToFloat()
|
||||
{
|
||||
Assert.That(Utils.ScaleByteToFloat( 0, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(-1).Within(0.0001f));
|
||||
Assert.That(Utils.ScaleByteToFloat(127, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(-0.003921569f).Within(0.0001f));
|
||||
Assert.That(Utils.ScaleByteToFloat(191, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(0.4980392f).Within(0.0001f));
|
||||
Assert.That(Utils.ScaleByteToFloat(255, byte.MinValue, byte.MaxValue, -1, 1), Is.EqualTo(1).Within(0.0001f));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user