Merge pull request #689 from paulpach/zigzag

perf: Implement zigzag algorithm so negatives pack efficiently
This commit is contained in:
vis2k 2019-03-31 14:25:35 +02:00 committed by GitHub
commit b876e256eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 156 additions and 32 deletions

View File

@ -229,7 +229,7 @@ bool WriteParameters(NetworkWriter writer)
if (par.type == AnimatorControllerParameterType.Int)
{
int newIntValue = animator.GetInteger(par.nameHash);
writer.WritePackedUInt32((uint)newIntValue);
writer.WritePackedInt32(newIntValue);
}
else if (par.type == AnimatorControllerParameterType.Float)
{
@ -256,7 +256,7 @@ void ReadParameters(NetworkReader reader)
AnimatorControllerParameter par = parameters[i];
if (par.type == AnimatorControllerParameterType.Int)
{
int newIntValue = (int)reader.ReadPackedUInt32();
int newIntValue = reader.ReadPackedInt32();
animator.SetInteger(par.nameHash, newIntValue);
}
else if (par.type == AnimatorControllerParameterType.Float)

View File

@ -372,7 +372,7 @@ void GenerateSerialization()
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); // writer
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // base
serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked64));
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePackedUInt64));
// generate a writer call for any dirty variable in this class
@ -462,7 +462,7 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefi
// read id and store in a local variable
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkReaderReadPacked32));
serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkReaderReadPackedUInt32));
serWorker.Append(serWorker.Create(OpCodes.Stloc, tmpValue));
if (foundMethod != null)
@ -572,7 +572,7 @@ void GenerateDeSerialization()
// get dirty bits
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadPacked64));
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadPackedUInt64));
serWorker.Append(serWorker.Create(OpCodes.Stloc_0));
// conditionally read each syncvar

View File

@ -101,11 +101,15 @@ class Weaver
public static MethodReference NetworkServerGetLocalClientActive;
public static MethodReference NetworkClientGetActive;
public static MethodReference UBehaviourIsServer;
public static MethodReference NetworkReaderReadPacked32;
public static MethodReference NetworkReaderReadPacked64;
public static MethodReference NetworkReaderReadPackedUInt32;
public static MethodReference NetworkReaderReadPackedInt32;
public static MethodReference NetworkReaderReadPackedUInt64;
public static MethodReference NetworkReaderReadPackedInt64;
public static MethodReference NetworkReaderReadByte;
public static MethodReference NetworkWriterWritePacked32;
public static MethodReference NetworkWriterWritePacked64;
public static MethodReference NetworkWriterWritePackedUInt32;
public static MethodReference NetworkWriterWritePackedInt32;
public static MethodReference NetworkWriterWritePackedUInt64;
public static MethodReference NetworkWriterWritePackedInt64;
public static MethodReference NetworkReadUInt16;
public static MethodReference NetworkWriteUInt16;
@ -1101,12 +1105,16 @@ static void SetupTargetTypes()
NetworkWriterWriteInt32 = Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", int32Type);
NetworkWriterWriteInt16 = Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", int16Type);
NetworkReaderReadPacked32 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadPackedUInt32");
NetworkReaderReadPacked64 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadPackedUInt64");
NetworkReaderReadPackedUInt32 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadPackedUInt32");
NetworkReaderReadPackedInt32 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadPackedInt32");
NetworkReaderReadPackedUInt64 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadPackedUInt64");
NetworkReaderReadPackedInt64 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadPackedInt64");
NetworkReaderReadByte = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadByte");
NetworkWriterWritePacked32 = Resolvers.ResolveMethod(NetworkWriterType, CurrentAssembly, "WritePackedUInt32");
NetworkWriterWritePacked64 = Resolvers.ResolveMethod(NetworkWriterType, CurrentAssembly, "WritePackedUInt64");
NetworkWriterWritePackedUInt32 = Resolvers.ResolveMethod(NetworkWriterType, CurrentAssembly, "WritePackedUInt32");
NetworkWriterWritePackedInt32 = Resolvers.ResolveMethod(NetworkWriterType, CurrentAssembly, "WritePackedInt32");
NetworkWriterWritePackedUInt64 = Resolvers.ResolveMethod(NetworkWriterType, CurrentAssembly, "WritePackedUInt64");
NetworkWriterWritePackedInt64 = Resolvers.ResolveMethod(NetworkWriterType, CurrentAssembly, "WritePackedInt64");
NetworkReadUInt16 = Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadUInt16");
NetworkWriteUInt16 = Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", uint16Type);
@ -1180,10 +1188,10 @@ static void SetupReadFunctions()
{ doubleType.FullName, Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadDouble") },
{ boolType.FullName, Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadBoolean") },
{ stringType.FullName, Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadString") },
{ int64Type.FullName, NetworkReaderReadPacked64 },
{ uint64Type.FullName, NetworkReaderReadPacked64 },
{ int32Type.FullName, NetworkReaderReadPacked32 },
{ uint32Type.FullName, NetworkReaderReadPacked32 },
{ int64Type.FullName, NetworkReaderReadPackedInt64 },
{ uint64Type.FullName, NetworkReaderReadPackedUInt64 },
{ int32Type.FullName, NetworkReaderReadPackedInt32 },
{ uint32Type.FullName, NetworkReaderReadPackedUInt32 },
{ int16Type.FullName, Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadInt16") },
{ uint16Type.FullName, Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadUInt16") },
{ byteType.FullName, Resolvers.ResolveMethod(NetworkReaderType, CurrentAssembly, "ReadByte") },
@ -1218,10 +1226,10 @@ static void SetupWriteFunctions()
{ doubleType.FullName, Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", doubleType) },
{ boolType.FullName, Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", boolType) },
{ stringType.FullName, Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", stringType) },
{ int64Type.FullName, NetworkWriterWritePacked64 },
{ uint64Type.FullName, NetworkWriterWritePacked64 },
{ int32Type.FullName, NetworkWriterWritePacked32 },
{ uint32Type.FullName, NetworkWriterWritePacked32 },
{ int64Type.FullName, NetworkWriterWritePackedInt64 },
{ uint64Type.FullName, NetworkWriterWritePackedUInt64 },
{ int32Type.FullName, NetworkWriterWritePackedInt32 },
{ uint32Type.FullName, NetworkWriterWritePackedUInt32 },
{ int16Type.FullName, Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", int16Type) },
{ uint16Type.FullName, Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", uint16Type) },
{ byteType.FullName, Resolvers.ResolveMethodWithArg(NetworkWriterType, CurrentAssembly, "Write", byteType) },

View File

@ -99,12 +99,12 @@ public IntegerMessage(int v)
public override void Deserialize(NetworkReader reader)
{
value = (int)reader.ReadPackedUInt32();
value = reader.ReadPackedInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.WritePackedUInt32((uint)value);
writer.WritePackedInt32(value);
}
}

View File

@ -57,6 +57,13 @@ public byte[] ReadBytesAndSize()
return null;
}
// zigzag decoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba
public int ReadPackedInt32()
{
uint data = ReadPackedUInt32();
return (int)((data >> 1) ^ -(data & 1));
}
// http://sqlite.org/src4/doc/trunk/www/varint.wiki
// NOTE: big endian.
public uint ReadPackedUInt32()
@ -69,6 +76,13 @@ public uint ReadPackedUInt32()
return (uint)value;
}
// zigzag decoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba
public long ReadPackedInt64()
{
ulong data = ReadPackedUInt64();
return ((long)(data >> 1)) ^ -((long)data & 1);
}
public ulong ReadPackedUInt64()
{
byte a0 = ReadByte();
@ -145,12 +159,12 @@ public Vector4 ReadVector4()
public Vector2Int ReadVector2Int()
{
return new Vector2Int((int)ReadPackedUInt32(), (int)ReadPackedUInt32());
return new Vector2Int(ReadPackedInt32(), ReadPackedInt32());
}
public Vector3Int ReadVector3Int()
{
return new Vector3Int((int)ReadPackedUInt32(), (int)ReadPackedUInt32(), (int)ReadPackedUInt32());
return new Vector3Int(ReadPackedInt32(), ReadPackedInt32(), ReadPackedInt32());
}
public Color ReadColor()

View File

@ -100,6 +100,13 @@ public void WriteBytesAndSize(byte[] buffer)
WriteBytesAndSize(buffer, 0, buffer != null ? buffer.Length : 0);
}
// zigzag encoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba
public void WritePackedInt32(int i)
{
uint zigzagged = (uint)((i >> 31) ^ (i << 1));
WritePackedUInt32(zigzagged);
}
// http://sqlite.org/src4/doc/trunk/www/varint.wiki
public void WritePackedUInt32(uint value)
{
@ -108,6 +115,13 @@ public void WritePackedUInt32(uint value)
WritePackedUInt64(value);
}
// zigzag encoding https://gist.github.com/mfuerstenau/ba870a29e16536fdbaba
public void WritePackedInt64(long i)
{
ulong zigzagged = (ulong)((i >> 63) ^ (i << 1));
WritePackedUInt64(zigzagged);
}
public void WritePackedUInt64(ulong value)
{
if (value <= 240)
@ -216,15 +230,15 @@ public void Write(Vector4 value)
public void Write(Vector2Int value)
{
WritePackedUInt32((uint)value.x);
WritePackedUInt32((uint)value.y);
WritePackedInt32(value.x);
WritePackedInt32(value.y);
}
public void Write(Vector3Int value)
{
WritePackedUInt32((uint)value.x);
WritePackedUInt32((uint)value.y);
WritePackedUInt32((uint)value.z);
WritePackedInt32(value.x);
WritePackedInt32(value.y);
WritePackedInt32(value.z);
}
public void Write(Color value)

View File

@ -19,8 +19,8 @@ public class SyncListFloat : SyncList<float>
public class SyncListInt : SyncList<int>
{
protected override void SerializeItem(NetworkWriter writer, int item) => writer.WritePackedUInt32((uint)item);
protected override int DeserializeItem(NetworkReader reader) => (int)reader.ReadPackedUInt32();
protected override void SerializeItem(NetworkWriter writer, int item) => writer.WritePackedInt32(item);
protected override int DeserializeItem(NetworkReader reader) => reader.ReadPackedInt32();
}
public class SyncListUInt : SyncList<uint>

View File

@ -79,6 +79,42 @@ public void TestPackedUInt32()
Assert.That(reader.ReadPackedUInt32(), Is.EqualTo(uint.MaxValue));
}
[Test]
public void TestPackedInt32()
{
NetworkWriter writer = new NetworkWriter();
writer.WritePackedInt32(0);
writer.WritePackedInt32(234);
writer.WritePackedInt32(2284);
writer.WritePackedInt32(67821);
writer.WritePackedInt32(16777210);
writer.WritePackedInt32(16777219);
writer.WritePackedInt32(int.MaxValue);
writer.WritePackedInt32(-1);
writer.WritePackedInt32(-234);
writer.WritePackedInt32(-2284);
writer.WritePackedInt32(-67821);
writer.WritePackedInt32(-16777210);
writer.WritePackedInt32(-16777219);
writer.WritePackedInt32(int.MinValue);
NetworkReader reader = new NetworkReader(writer.ToArray());
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(0));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(234));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(2284));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(67821));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(16777210));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(16777219));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(int.MaxValue));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(-1));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(-234));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(-2284));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(-67821));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(-16777210));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(-16777219));
Assert.That(reader.ReadPackedInt32(), Is.EqualTo(int.MinValue));
}
[Test]
public void TestPackedUInt64()
{
@ -109,6 +145,58 @@ public void TestPackedUInt64()
Assert.That(reader.ReadPackedUInt64(), Is.EqualTo(ulong.MaxValue));
}
[Test]
public void TestPackedInt64()
{
NetworkWriter writer = new NetworkWriter();
writer.WritePackedInt64(0);
writer.WritePackedInt64(234);
writer.WritePackedInt64(2284);
writer.WritePackedInt64(67821);
writer.WritePackedInt64(16777210);
writer.WritePackedInt64(16777219);
writer.WritePackedInt64(4294967295);
writer.WritePackedInt64(1099511627775);
writer.WritePackedInt64(281474976710655);
writer.WritePackedInt64(72057594037927935);
writer.WritePackedInt64(long.MaxValue);
writer.WritePackedInt64(-1);
writer.WritePackedInt64(-234);
writer.WritePackedInt64(-2284);
writer.WritePackedInt64(-67821);
writer.WritePackedInt64(-16777210);
writer.WritePackedInt64(-16777219);
writer.WritePackedInt64(-4294967295);
writer.WritePackedInt64(-1099511627775);
writer.WritePackedInt64(-281474976710655);
writer.WritePackedInt64(-72057594037927935);
writer.WritePackedInt64(long.MinValue);
NetworkReader reader = new NetworkReader(writer.ToArray());
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(0));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(234));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(2284));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(67821));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(16777210));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(16777219));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(4294967295));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(1099511627775));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(281474976710655));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(72057594037927935));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(long.MaxValue));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-1));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-234));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-2284));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-67821));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-16777210));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-16777219));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-4294967295));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-1099511627775));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-281474976710655));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(-72057594037927935));
Assert.That(reader.ReadPackedInt64(), Is.EqualTo(long.MinValue));
}
[Test]
public void TestGuid()
{