Skip to content

Commit

Permalink
feat: attributes to use new vector bit packers (#905)
Browse files Browse the repository at this point in the history
* new exceptions

* adding attributes and tests

* starting weaver tests

* implementing packers and finishing weaver tests

* docs

* rough notes

* adding other headers
  • Loading branch information
James-Frowen committed Aug 31, 2021
1 parent dfd3b6b commit 149bf5a
Show file tree
Hide file tree
Showing 86 changed files with 2,951 additions and 115 deletions.
12 changes: 11 additions & 1 deletion Assets/Mirage/Runtime/Serialization/Packers/Vector2Packer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
MIT License
Copyright (c) 2021 James Frowen
Expand Down Expand Up @@ -31,6 +31,16 @@ public sealed class Vector2Packer
readonly FloatPacker xPacker;
readonly FloatPacker yPacker;

public Vector2Packer(float xMax, float yMax, int xBitCount, int yBitCount)
{
xPacker = new FloatPacker(xMax, xBitCount);
yPacker = new FloatPacker(yMax, yBitCount);
}
public Vector2Packer(float xMax, float yMax, float xPrecision, float yPrecision)
{
xPacker = new FloatPacker(xMax, xPrecision);
yPacker = new FloatPacker(yMax, yPrecision);
}
public Vector2Packer(Vector2 max, Vector2 precision)
{
xPacker = new FloatPacker(max.x, precision.x);
Expand Down
12 changes: 12 additions & 0 deletions Assets/Mirage/Runtime/Serialization/Packers/Vector3Packer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ public sealed class Vector3Packer
readonly FloatPacker yPacker;
readonly FloatPacker zPacker;

public Vector3Packer(float xMax, float yMax, float zMax, int xBitCount, int yBitCount, int zBitCount)
{
xPacker = new FloatPacker(xMax, xBitCount);
yPacker = new FloatPacker(yMax, yBitCount);
zPacker = new FloatPacker(zMax, zBitCount);
}
public Vector3Packer(float xMax, float yMax, float zMax, float xPrecision, float yPrecision, float zPrecision)
{
xPacker = new FloatPacker(xMax, xPrecision);
yPacker = new FloatPacker(yMax, yPrecision);
zPacker = new FloatPacker(zMax, zPrecision);
}
public Vector3Packer(Vector3 max, Vector3 precision)
{
xPacker = new FloatPacker(max.x, precision.x);
Expand Down
34 changes: 33 additions & 1 deletion Assets/Mirage/Runtime/Serialization/WeaverAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,40 @@ public class FloatPackAttribute : Attribute
public FloatPackAttribute(float max, float precision) { }

/// <param name="max">Max value of the float</param>
/// <param name="bitCount">number of bits to pack the field into.</param>
/// <param name="bitCount">number of bits to pack the field into</param>
public FloatPackAttribute(float max, int bitCount) { }
}

/// <summary>
///
/// </summary>
public class Vector3PackAttribute : Attribute
{
public Vector3PackAttribute(float xMax, float yMax, float zMax, float xPrecision, float yPrecision, float zPrecision) { }
public Vector3PackAttribute(float xMax, float yMax, float zMax, float precision) { }

public Vector3PackAttribute(float xMax, float yMax, float zMax, int xBitCount, int yBitCount, int ZBitCount) { }
public Vector3PackAttribute(float xMax, float yMax, float zMax, int bitCount) { }
}

/// <summary>
///
/// </summary>
public class Vector2PackAttribute : Attribute
{
public Vector2PackAttribute(float xMax, float yMax, float xPrecision, float yPrecision) { }
public Vector2PackAttribute(float xMax, float yMax, float precision) { }

public Vector2PackAttribute(float xMax, float yMax, int xBitCount, int yBitCount) { }
public Vector2PackAttribute(float xMax, float yMax, int bitCount) { }
}

/// <summary>
///
/// </summary>
public class QuaternionPackAttribute : Attribute
{
public QuaternionPackAttribute(int bitPerElement) { }
}
#pragma warning restore IDE0060 // Remove unused parameter
}
92 changes: 54 additions & 38 deletions Assets/Mirage/Weaver/Processors/NetworkBehaviourProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
Expand Down Expand Up @@ -89,45 +90,11 @@ void RegisterRpcs()
{
Weaver.DebugLog(netBehaviourSubclass, " GenerateConstants ");

// find static constructor
MethodDefinition cctor = netBehaviourSubclass.GetMethod(".cctor");
if (cctor != null)
{
// remove the return opcode from end of function. will add our own later.
if (cctor.Body.Instructions.Count != 0)
{
Instruction retInstr = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1];
if (retInstr.OpCode == OpCodes.Ret)
{
cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1);
}
else
{
logger.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor);
return;
}
}
}
else
AddToStaticConstructor(netBehaviourSubclass, (worker) =>
{
// make one!
cctor = netBehaviourSubclass.AddMethod(".cctor", MethodAttributes.Private |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName |
MethodAttributes.Static);
}

ILProcessor cctorWorker = cctor.Body.GetILProcessor();

serverRpcProcessor.RegisterServerRpcs(cctorWorker);

clientRpcProcessor.RegisterClientRpcs(cctorWorker);

cctorWorker.Append(cctorWorker.Create(OpCodes.Ret));

// in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late
netBehaviourSubclass.Attributes &= ~TypeAttributes.BeforeFieldInit;
serverRpcProcessor.RegisterServerRpcs(worker);
clientRpcProcessor.RegisterClientRpcs(worker);
});
}

void ProcessRpcs()
Expand Down Expand Up @@ -169,5 +136,54 @@ void ProcessRpcs()

RegisterRpcs();
}

/// <summary>
/// Adds code to static Constructor
/// <para>
/// If Constructor is missing a new one will be created
/// </para>
/// </summary>
/// <param name="body">code to write</param>
public static void AddToStaticConstructor(TypeDefinition typeDefinition, Action<ILProcessor> body)
{
MethodDefinition cctor = typeDefinition.GetMethod(".cctor");
if (cctor != null)
{
// remove the return opcode from end of function. will add our own later.
if (cctor.Body.Instructions.Count != 0)
{
Instruction retInstr = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1];
if (retInstr.OpCode == OpCodes.Ret)
{
cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1);
}
else
{
throw new NetworkBehaviourException($"{typeDefinition.Name} has invalid static constructor", cctor, cctor.GetSequencePoint(retInstr));
}
}
}
else
{
// make one!
cctor = typeDefinition.AddMethod(".cctor", MethodAttributes.Private |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName |
MethodAttributes.Static);
}

ILProcessor worker = cctor.Body.GetILProcessor();

// add new code to bottom of constructor
// todo should we be adding new code to top of function instead? incase user has early return in custom constructor?
body.Invoke(worker);

// re-add return bececause we removed it earlier
worker.Append(worker.Create(OpCodes.Ret));

// in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late
typeDefinition.Attributes &= ~TypeAttributes.BeforeFieldInit;
}
}
}

0 comments on commit 149bf5a

Please sign in to comment.