feat(clrcore-v2): Move to custom MsgPack serializer
Goal of this PR
Enable (de)serialization to and from custom types on events, exports, nui callbacks, and other refFuncs within the mono rt2 runtime. A highly requested feature for the C# environments, as a lot of extra work and workarounds are currently applied to compensate for the lack there-of.
- Optional parameters are also supported with this update.
- Performance is roughly 30% faster for single listeners, making it slower for 3+ listeners for each event (why would you even do this?).
Notes:
- This is the last big update for the mono rt2 scripting runtime before we exit the pilot stage.
- Issues are expected; unit tests are put in place for some situations, but not all and/or unforeseen use-cases are tested yet.
How is this PR achieving the goal
Allows for in place conversion of serialized data.
- Replaces deserializer on events, exports, nui callbacks, and other refFuncs with our custom and more extensive msgpack serialization.
- Has support for:
- Class/struct field/property (de)serialization.
- Class/struct constructor deserialization.
-
Dictionary<K, V>,List<T>, andT[]. - Primitives.
- Add msgpack-cs submodule (production branch)
- Temporary Player (de)serialization
- Command remapper no longer allows reordering of parameters, only remote/player id
Example:
[EventHandler("myEvent")]
public static async Coroutine GimmeAll(int a)
=> Debug.WriteLine($"GimmeAll1 {a}");
[EventHandler("myEvent")]
public static async Coroutine GimmeAll(string a, int b)
=> Debug.WriteLine($"GimmeAll2 {a} {b}");
[EventHandler("myEvent")]
public static async Coroutine GimmeAll(string a, int b, string c = "Hey")
=> Debug.WriteLine($"GimmeAll3 {a} {b} {c}");
[EventHandler("myEvent")]
public static async Coroutine GimmeAll(int a, string b, string c = "Oh", int d = 678)
=> Debug.WriteLine($"GimmeAll4 {a} {b} {c} {d}");
[EventHandler("myEvent")]
public static async Coroutine GimmeAll(int a, Player b, string c = "Oh", int d = 678)
=> Debug.WriteLine($"GimmeAll5 {a} {b} {c} {d}");
// Trigger it!
[Command("Gimme")]
public async Coroutine Gimme(uint source, object[] objects, string raw)
=> Events.TriggerServerEvent("myEvent", 1234, "5678");
gives the following output:
[ script:csharp_v2] GimmeAll1 1234
[ script:csharp_v2] GimmeAll2 1234 5678
[ script:csharp_v2] GimmeAll3 1234 5678 Hey
[ script:csharp_v2] GimmeAll4 1234 5678 Oh 678
[ script:csharp_v2] GimmeAll5 1234 Player(5678) Oh 678
This PR applies to the following area(s)
ScRT: C#
Successfully tested on
FXServer and
Game builds: N/A
Platforms: Windows
Checklist
- [x] Code compiles and has been tested successfully.
- [x] Code explains itself well and/or is documented.
- [x] My commit message explains what the changes do and what they are for.
- [x] No extra compilation warnings are added by these changes.
Fixes issues
closes thorium-cfx/mono_v2_get_started#20
Thanks / Contributors
A big thanks goes out @manups4e, showing me how his FxEvents project used a completely different approach, this became the base and eventually the way forward on MsgPack (de)serialization for the mono v2 scripting environment.
Ooo fancy!
Is it possible to provide an example of how to use the API.EventManagerPeekEvent as i am seeing this as still requiring an object to be passed as a reference ?
@thorium-cfx Looks like this has broken the export system and every time an export is executed an error is thrown.
Example code:
[Export("test")]
public static string ExportE2()
{
return "yeahh";
}
[ c-scripting-mono] Exception in Mono script environment: System.NotSupportedException: Requested serializer for MethodInfo.CustomAttributes of type System.Collections.Generic.IEnumerable`1[System.Reflection.CustomAttributeData] could not be found.
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializeMapBody (System.Type type, System.Reflection.Emit.ILGenerator g, CitizenFX.MsgPack.Detail.DynamicArray`1[T] members, System.Reflection.MethodInfo currentSerializer) [0x0023f] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:323
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializer (System.Type type, System.Reflection.Emit.TypeBuilder typeBuilder) [0x00117] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:170
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.Build (System.Type type) [0x000ce] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:79
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.CreateSerializer (System.Type type) [0x0008e] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:214
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.GetOrCreateSerializer (System.Type type) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:167
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializeMapBody (System.Type type, System.Reflection.Emit.ILGenerator g, CitizenFX.MsgPack.Detail.DynamicArray`1[T] members, System.Reflection.MethodInfo currentSerializer) [0x0015b] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:293
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializer (System.Type type, System.Reflection.Emit.TypeBuilder typeBuilder) [0x00117] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:170
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.Build (System.Type type) [0x000ce] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:79
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.CreateSerializer (System.Type type) [0x0008e] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:214
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.Serialize (CitizenFX.MsgPack.MsgPackSerializer serializer, System.Object obj) [0x0018a] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:143
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.Serialize (System.Object v) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:70
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.Serialize (System.Object[] v) [0x0000d] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:256
[ c-scripting-mono] at (wrapper dynamic-method) System.Object.MsgPackSerializer(CitizenFX.MsgPack.MsgPackSerializer,object)
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.Serialize (CitizenFX.MsgPack.MsgPackSerializer serializer, System.Object obj) [0x0017b] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:139
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.Serialize (System.Object v) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:70
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.SerializeToByteArray (System.Object value) [0x00005] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:59
[ c-scripting-mono] at CitizenFX.Core.Native.InPacket..ctor (System.Object obj) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Native\Types\NativeTypes.cs:80
[ c-scripting-mono] at CitizenFX.Core.Native.InPacket.Serialize (System.Object obj) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Native\Types\NativeTypes.cs:81
[ c-scripting-mono] at CitizenFX.Core.Native.InPacket.op_Implicit (System.Object[] obj) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Native\Types\NativeTypes.cs:82
[ c-scripting-mono] at CitizenFX.Core._LocalFunction.Invoke (System.Object[] args) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Interop\LocalFunction.cs:46
[ c-scripting-mono] at CitizenFX.Core.ExportsManager.IncomingRequest (System.String eventName, System.String sourceString, CitizenFX.Core.Binding origin, System.Byte* argsSerialized, System.Int32 serializedSize) [0x0003b] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Interop\ExportsManager.cs:34
[ c-scripting-mono] at CitizenFX.Core.ScriptInterface.TriggerEvent (System.String eventName, System.Byte* argsSerialized, System.Int32 serializedSize, System.String sourceString, System.UInt64 hostTime, System.Boolean profiling) [0x0003c] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\ScriptInterface.cs:151
[ c-scripting-mono] at (wrapper native-to-managed) CitizenFX.Core.ScriptInterface.TriggerEvent(string,byte*,int,string,ulong,bool,System.Exception&)
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializeMapBody (System.Type type, System.Reflection.Emit.ILGenerator g, CitizenFX.MsgPack.Detail.DynamicArray`1[T] members, System.Reflection.MethodInfo currentSerializer) [0x0023f] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:323
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializer (System.Type type, System.Reflection.Emit.TypeBuilder typeBuilder) [0x00117] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:170
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.Build (System.Type type) [0x000ce] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:79
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.CreateSerializer (System.Type type) [0x0008e] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:214
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.GetOrCreateSerializer (System.Type type) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:167
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializeMapBody (System.Type type, System.Reflection.Emit.ILGenerator g, CitizenFX.MsgPack.Detail.DynamicArray`1[T] members, System.Reflection.MethodInfo currentSerializer) [0x0015b] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:293
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.BuildSerializer (System.Type type, System.Reflection.Emit.TypeBuilder typeBuilder) [0x00117] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:170
[ c-scripting-mono] at CitizenFX.MsgPack.Formatters.TypeFormatter.Build (System.Type type) [0x000ce] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\Formatters\TypeFormatter.cs:79
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.CreateSerializer (System.Type type) [0x0008e] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:214
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.Serialize (CitizenFX.MsgPack.MsgPackSerializer serializer, System.Object obj) [0x0018a] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:143
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.Serialize (System.Object v) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:70
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.Serialize (System.Object[] v) [0x0000d] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:256
[ c-scripting-mono] at (wrapper dynamic-method) System.Object.MsgPackSerializer(CitizenFX.MsgPack.MsgPackSerializer,object)
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackRegistry.Serialize (CitizenFX.MsgPack.MsgPackSerializer serializer, System.Object obj) [0x0017b] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackRegistry.cs:139
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.Serialize (System.Object v) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:70
[ c-scripting-mono] at CitizenFX.MsgPack.MsgPackSerializer.SerializeToByteArray (System.Object value) [0x00005] in C:\gl\builds\cfx-fivem\master\fxserver\vendor\msgpack-cs\MsgPack\MsgPackSerializer.cs:59
[ c-scripting-mono] at CitizenFX.Core.Native.InPacket..ctor (System.Object obj) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Native\Types\NativeTypes.cs:80
[ c-scripting-mono] at CitizenFX.Core.Native.InPacket.Serialize (System.Object obj) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Native\Types\NativeTypes.cs:81
[ c-scripting-mono] at CitizenFX.Core.Native.InPacket.op_Implicit (System.Object[] obj) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Native\Types\NativeTypes.cs:82
[ c-scripting-mono] at CitizenFX.Core._LocalFunction.Invoke (System.Object[] args) [0x00000] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Interop\LocalFunction.cs:46
[ c-scripting-mono] at CitizenFX.Core.ExportsManager.IncomingRequest (System.String eventName, System.String sourceString, CitizenFX.Core.Binding origin, System.Byte* argsSerialized, System.Int32 serializedSize) [0x0003b] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\Interop\ExportsManager.cs:34
[ c-scripting-mono] at CitizenFX.Core.ScriptInterface.TriggerEvent (System.String eventName, System.Byte* argsSerialized, System.Int32 serializedSize, System.String sourceString, System.UInt64 hostTime, System.Boolean profiling) [0x0003c] in C:\gl\builds\cfx-fivem\master\fxserver\code\client\clrcore-v2\ScriptInterface.cs:151
[ c-scripting-mono] at (wrapper native-to-managed) CitizenFX.Core.ScriptInterface.TriggerEvent(string,byte*,int,string,ulong,bool,System.Exception&)Failed to execute event __cfx_export_monodb_testt - 80070057.
In case anyone decides to continue the work of this PR, I think that linking the crashes that were found when the changes of this PR were in effect could be useful: #2571 #2582 #2590 #2613 #2653
If someone fixes all those bugs will someone from cfx decide to merge the changes?