From ad45a0eb0f749e6d8dd9a312afb2899107404b99 Mon Sep 17 00:00:00 2001 From: vis2k Date: Fri, 23 Jul 2021 12:05:38 +0800 Subject: [PATCH] feature: Compression.VarInt added again --- Assets/Mirror/Runtime/Compression.cs | 151 +++++++++++++++++- .../Mirror/Tests/Editor/CompressionTests.cs | 30 ++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/Assets/Mirror/Runtime/Compression.cs b/Assets/Mirror/Runtime/Compression.cs index 00776864d..5d46faba4 100644 --- a/Assets/Mirror/Runtime/Compression.cs +++ b/Assets/Mirror/Runtime/Compression.cs @@ -1,5 +1,5 @@ // Quaternion compression from DOTSNET - +using System; using UnityEngine; namespace Mirror @@ -189,5 +189,154 @@ public static Quaternion DecompressQuaternion(uint data) // in NaN from deserializing invalid values! return QuaternionNormalizeSafe(new Quaternion(value.x, value.y, value.z, value.w)); } + + // varint compression ////////////////////////////////////////////////// + // compress ulong varint. + // same result for int, short and byte. only need one function. + // NOT an extension. otherwise weaver might accidentally use it. + public static void CompressVarInt(NetworkWriter writer, ulong value) + { + if (value <= 240) + { + writer.Write((byte)value); + return; + } + if (value <= 2287) + { + writer.Write((byte)(((value - 240) >> 8) + 241)); + writer.Write((byte)((value - 240) & 0xFF)); + return; + } + if (value <= 67823) + { + writer.Write((byte)249); + writer.Write((byte)((value - 2288) >> 8)); + writer.Write((byte)((value - 2288) & 0xFF)); + return; + } + if (value <= 16777215) + { + writer.Write((byte)250); + writer.Write((byte)(value & 0xFF)); + writer.Write((byte)((value >> 8) & 0xFF)); + writer.Write((byte)((value >> 16) & 0xFF)); + return; + } + if (value <= 4294967295) + { + writer.Write((byte)251); + writer.Write((byte)(value & 0xFF)); + writer.Write((byte)((value >> 8) & 0xFF)); + writer.Write((byte)((value >> 16) & 0xFF)); + writer.Write((byte)((value >> 24) & 0xFF)); + return; + } + if (value <= 1099511627775) + { + writer.Write((byte)252); + writer.Write((byte)(value & 0xFF)); + writer.Write((byte)((value >> 8) & 0xFF)); + writer.Write((byte)((value >> 16) & 0xFF)); + writer.Write((byte)((value >> 24) & 0xFF)); + writer.Write((byte)((value >> 32) & 0xFF)); + return; + } + if (value <= 281474976710655) + { + writer.Write((byte)253); + writer.Write((byte)(value & 0xFF)); + writer.Write((byte)((value >> 8) & 0xFF)); + writer.Write((byte)((value >> 16) & 0xFF)); + writer.Write((byte)((value >> 24) & 0xFF)); + writer.Write((byte)((value >> 32) & 0xFF)); + writer.Write((byte)((value >> 40) & 0xFF)); + return; + } + if (value <= 72057594037927935) + { + writer.Write((byte)254); + writer.Write((byte)(value & 0xFF)); + writer.Write((byte)((value >> 8) & 0xFF)); + writer.Write((byte)((value >> 16) & 0xFF)); + writer.Write((byte)((value >> 24) & 0xFF)); + writer.Write((byte)((value >> 32) & 0xFF)); + writer.Write((byte)((value >> 40) & 0xFF)); + writer.Write((byte)((value >> 48) & 0xFF)); + return; + } + + // all others + { + writer.Write((byte)255); + writer.Write((byte)(value & 0xFF)); + writer.Write((byte)((value >> 8) & 0xFF)); + writer.Write((byte)((value >> 16) & 0xFF)); + writer.Write((byte)((value >> 24) & 0xFF)); + writer.Write((byte)((value >> 32) & 0xFF)); + writer.Write((byte)((value >> 40) & 0xFF)); + writer.Write((byte)((value >> 48) & 0xFF)); + writer.Write((byte)((value >> 56) & 0xFF)); + } + } + + // NOT an extension. otherwise weaver might accidentally use it. + public static ulong DecompressVarInt(NetworkReader reader) + { + byte a0 = reader.ReadByte(); + if (a0 < 241) + { + return a0; + } + + byte a1 = reader.ReadByte(); + if (a0 >= 241 && a0 <= 248) + { + return 240 + ((a0 - (ulong)241) << 8) + a1; + } + + byte a2 = reader.ReadByte(); + if (a0 == 249) + { + return 2288 + ((ulong)a1 << 8) + a2; + } + + byte a3 = reader.ReadByte(); + if (a0 == 250) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16); + } + + byte a4 = reader.ReadByte(); + if (a0 == 251) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24); + } + + byte a5 = reader.ReadByte(); + if (a0 == 252) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32); + } + + byte a6 = reader.ReadByte(); + if (a0 == 253) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40); + } + + byte a7 = reader.ReadByte(); + if (a0 == 254) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40) + (((ulong)a7) << 48); + } + + byte a8 = reader.ReadByte(); + if (a0 == 255) + { + return a1 + (((ulong)a2) << 8) + (((ulong)a3) << 16) + (((ulong)a4) << 24) + (((ulong)a5) << 32) + (((ulong)a6) << 40) + (((ulong)a7) << 48) + (((ulong)a8) << 56); + } + + throw new IndexOutOfRangeException("DecompressVarInt failure: " + a0); + } } } diff --git a/Assets/Mirror/Tests/Editor/CompressionTests.cs b/Assets/Mirror/Tests/Editor/CompressionTests.cs index 0e88c829d..b1b4be2d9 100644 --- a/Assets/Mirror/Tests/Editor/CompressionTests.cs +++ b/Assets/Mirror/Tests/Editor/CompressionTests.cs @@ -131,5 +131,35 @@ public void CompressAndDecompressQuaternion_2674() // 1 degree tolerance Assert.That(Mathf.Abs(angle), Is.LessThanOrEqualTo(1)); } + + [Test] + public void VarInt() + { + NetworkWriter writer = new NetworkWriter(); + Compression.CompressVarInt(writer, 0); + Compression.CompressVarInt(writer, 234); + Compression.CompressVarInt(writer, 2284); + Compression.CompressVarInt(writer, 67821); + Compression.CompressVarInt(writer, 16777210); + Compression.CompressVarInt(writer, 16777219); + Compression.CompressVarInt(writer, 4294967295); + Compression.CompressVarInt(writer, 1099511627775); + Compression.CompressVarInt(writer, 281474976710655); + Compression.CompressVarInt(writer, 72057594037927935); + Compression.CompressVarInt(writer, ulong.MaxValue); + + NetworkReader reader = new NetworkReader(writer.ToArray()); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(0)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(234)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(2284)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(67821)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(16777210)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(16777219)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(4294967295)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(1099511627775)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(281474976710655)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(72057594037927935)); + Assert.That(Compression.DecompressVarInt(reader), Is.EqualTo(ulong.MaxValue)); + } } }