Light and Fast bit and byte serialization for .NET Standard 2.0, .NET Standard 2.1, .NET 6 and .NET 8 (Mono, .NET Core, .NET Framework, Unity)
varbitWriter=newBitWriter();bitWriter.WriteBits(3,0b_101);bitWriter.Flush();byte[]data=bitWriter.Array;varbitReader=newBitReader(data);uintvalue=bitReader.ReadBits(3);Console.WriteLine(value);// output: 5Console.WriteLine(Convert.ToString(value,2));// output: 101varbitWriter=newBitWriter();bitWriter.Write(value:1f,min:0f,max:10f,precision:0.1f);Console.WriteLine(bitWriter.BitsCount);// 7bitWriter.Flush();Console.WriteLine(bitWriter.BitsCount);// 8vardata=bitWriter.Array;varbitReader=newBitReader(data);varvalue=bitReader.ReadFloat(min:0f,max:10f,precision:0.1f);Console.WriteLine(Math.Abs(value-1f)<0.1f);// TrueConsole.WriteLine(value);// 1varserializer=newTransformComponentSerializer();vardeserializer=newTransformComponentDeserializer();varbefore=newTransformComponent{Position=newVector3(10f,5f,10f),Pitch=30f,Yaw=60f};varafter=newTransformComponent{Position=newVector3(10.5f,5.5f,10.5f),Pitch=30f,Yaw=60f};varserializedComponent=serializer.Serialize(before,after);Console.WriteLine(serializedComponent.Length);// 3varupdated=deserializer.Deserialize(before,serializedComponent.Array);serializedComponent.Dispose();Console.WriteLine(updated);// Position: <10.5, 5.5, 10.5>, Yaw: 60, Pitch: 30publicrecordstructTransformComponent(Vector3Position,floatYaw,floatPitch);publicstructSerializedComponent{privatereadonlyArrayPool<byte>_arrayPool;publicbyte[]Array{get;}publicintLength{get;}publicSerializedComponent(ArrayPool<byte>arrayPool,byte[]array,intlength){_arrayPool=arrayPool;Array=array;Length=length;}publicvoidDispose(){_arrayPool.Return(Array);}}publicstaticclassLimits{publicstaticreadonlyFloatLimitRotation=newFloatLimit(0,360,0.1f);publicstaticreadonlyVector3LimitAbsolutePosition=newVector3Limit(newFloatLimit(-100f,100f,0.1f),newFloatLimit(-10f,10f,0.1f),newFloatLimit(-100f,100f,0.1f));publicstaticreadonlyVector3LimitDiffPosition=newVector3Limit(newFloatLimit(-1f,1f,0.1f),newFloatLimit(-1f,1f,0.1f),newFloatLimit(-1f,1f,0.1f));}publicclassTransformComponentSerializer{privateconstintMTU=1500;privatereadonlyBitWriter_bitWriter=newBitWriter();privatereadonlyArrayPool<byte>_arrayPool=ArrayPool<byte>.Shared;publicSerializedComponentSerialize(TransformComponentbaseline,TransformComponentupdated){vararray=_arrayPool.Rent(MTU);_bitWriter.SetArray(array);_bitWriter.WriteDiffIfChanged(baseline.Position.X,updated.Position.X,Limits.AbsolutePosition.X,Limits.DiffPosition.X);_bitWriter.WriteDiffIfChanged(baseline.Position.Y,updated.Position.Y,Limits.AbsolutePosition.Y,Limits.DiffPosition.Y);_bitWriter.WriteDiffIfChanged(baseline.Position.Z,updated.Position.Z,Limits.AbsolutePosition.Z,Limits.DiffPosition.Z);_bitWriter.WriteValueIfChanged(baseline.Yaw,updated.Yaw,Limits.Rotation);_bitWriter.WriteValueIfChanged(baseline.Pitch,updated.Pitch,Limits.Rotation);_bitWriter.Flush();returnnewSerializedComponent(_arrayPool,_bitWriter.Array,_bitWriter.BytesCount);}}publicclassTransformComponentDeserializer{privatereadonlyBitReader_bitReader=newBitReader();publicTransformComponentDeserialize(TransformComponentbefore,byte[]array){_bitReader.SetArray(array);TransformComponentresult=default;result.Position=newVector3(_bitReader.ReadFloat(before.Position.X,Limits.AbsolutePosition.X,Limits.DiffPosition.X),_bitReader.ReadFloat(before.Position.Y,Limits.AbsolutePosition.Y,Limits.DiffPosition.Y),_bitReader.ReadFloat(before.Position.Z,Limits.AbsolutePosition.Z,Limits.DiffPosition.Z));result.Yaw=_bitReader.ReadFloat(before.Yaw,Limits.Rotation);result.Pitch=_bitReader.ReadFloat(before.Pitch,Limits.Rotation);returnresult;}}PM> Install-Package NetCode
or
dotnet add package NetCode
- Fast
- Performance focused
- Uses high-perf memory accessors
- No array copying
- Zero memory allocations
- No array creation
- Reusable class instances
- Has a lot of benchmarks
- Performance focused
- Read \ Write bit values
- Read \ Write with delta compression
- Read \ Write quantized values
- Safe to use
- Covered by unit tests
- Supports a lot of frameworks:
- .NET Standard 2.0
- .NET Standard 2.1
- .NET 6
- .NET 8
Read benchmarks you can find here.
BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.5.2 (20G95) [Darwin 20.6.0]
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
| Method | Mean | Error | StdDev | Ratio | RatioSD | Allocated |
|----------------- |-----------:|--------:|--------:|------:|--------:|----------:|
| BinaryPrimitives | 328.4 ns | 1.24 ns | 1.10 ns | 1.00 | 0.00 | - |
| ByteReader | 329.4 ns | 1.71 ns | 1.60 ns | 1.00 | 0.01 | - |
| BitReader | 457.8 ns | 1.09 ns | 0.91 ns | 1.39 | 0.01 | - |
| BinaryReader | 1,205.8 ns | 6.75 ns | 6.31 ns | 3.67 | 0.02 | - |
Write benchmarks you can find here.
BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.5.2 (20G95) [Darwin 20.6.0]
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
| Method | Mean | Error | StdDev | Ratio | RatioSD | Allocated |
|----------------- |-----------:|---------:|---------:|------:|--------:|----------:|
| BinaryPrimitives | 325.7 ns | 1.39 ns | 1.30 ns | 1.00 | 0.00 | - |
| ByteWriter | 330.3 ns | 1.67 ns | 1.48 ns | 1.01 | 0.01 | - |
| BitWriter | 338.0 ns | 1.69 ns | 1.58 ns | 1.04 | 0.00 | - |
| BinaryWriter | 2,344.7 ns | 12.08 ns | 10.71 ns | 7.20 | 0.03 | - |