From 6f19489721b8e195edd7c548d43988ef21c05676 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Fri, 22 Mar 2019 05:51:20 -0500 Subject: [PATCH] feature(synclist): allow SyncList of primitive types (#622) * feature(synclist): allow SyncList of primitive types As it turns out this never really worked: ```cs class SyncListByte : SyncList {}; ``` You had to write your own serializeItem / deserialize item for native types. This change lifts the restriction, now you can use a synclist of anything that mirror can serialize/deserialize * fix: fix unit tests error messages --- .../Weaver/Processors/SyncListProcessor.cs | 91 +++++-------------- Assets/Mirror/Tests/WeaverTest.cs | 19 ++-- 2 files changed, 38 insertions(+), 72 deletions(-) diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs index 9cb491747..cade18f3d 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs @@ -60,39 +60,17 @@ static MethodReference GenerateSerialization(TypeDefinition td, TypeReference it return null; } - foreach (FieldDefinition field in itemType.Resolve().Fields) + MethodReference writeFunc = Weaver.GetWriteFunc(itemType); + if (writeFunc != null) { - if (field.IsStatic || field.IsPrivate || field.IsSpecialName) - continue; - - FieldReference importedField = Weaver.CurrentAssembly.MainModule.ImportReference(field); - TypeDefinition ft = importedField.FieldType.Resolve(); - - if (ft.HasGenericParameters) - { - Weaver.Error("GenerateSerialization for " + td.Name + " [" + ft + "/" + ft.FullName + "]. [SyncList] member cannot have generic parameters."); - return null; - } - - if (ft.IsInterface) - { - Weaver.Error("GenerateSerialization for " + td.Name + " [" + ft + "/" + ft.FullName + "]. [SyncList] member cannot be an interface."); - return null; - } - - MethodReference writeFunc = Weaver.GetWriteFunc(field.FieldType); - if (writeFunc != null) - { - serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); - serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); - serWorker.Append(serWorker.Create(OpCodes.Ldfld, importedField)); - serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); - } - else - { - Weaver.Error("GenerateSerialization for " + td.Name + " unknown type [" + ft + "/" + ft.FullName + "]. [SyncList] member variables must be basic types."); - return null; - } + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + serWorker.Append(serWorker.Create(OpCodes.Ldarg_2)); + serWorker.Append(serWorker.Create(OpCodes.Call, writeFunc)); + } + else + { + Weaver.Error("GenerateSerialization for " + td.Name + " unknown type [" + itemType + "/" + itemType.FullName + "]. [SyncList] member variables must be basic types."); + return null; } serWorker.Append(serWorker.Create(OpCodes.Ret)); @@ -109,50 +87,31 @@ static MethodReference GenerateDeserialization(TypeDefinition td, TypeReference return m; } - MethodDefinition serializeFunc = new MethodDefinition("DeserializeItem", MethodAttributes.Public | + MethodDefinition deserializeFunction = new MethodDefinition("DeserializeItem", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.HideBySig, itemType); - serializeFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); + deserializeFunction.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(Weaver.NetworkReaderType))); - ILProcessor serWorker = serializeFunc.Body.GetILProcessor(); + ILProcessor serWorker = deserializeFunction.Body.GetILProcessor(); - serWorker.Body.InitLocals = true; - serWorker.Body.Variables.Add(new VariableDefinition(itemType)); - - // init item instance - serWorker.Append(serWorker.Create(OpCodes.Ldloca, 0)); - serWorker.Append(serWorker.Create(OpCodes.Initobj, itemType)); - - foreach (FieldDefinition field in itemType.Resolve().Fields) + MethodReference readerFunc = Weaver.GetReadFunc(itemType); + if (readerFunc != null) { - if (field.IsStatic || field.IsPrivate || field.IsSpecialName) - continue; - - FieldReference importedField = Weaver.CurrentAssembly.MainModule.ImportReference(field); - TypeDefinition ft = importedField.FieldType.Resolve(); - - MethodReference readerFunc = Weaver.GetReadFunc(field.FieldType); - if (readerFunc != null) - { - serWorker.Append(serWorker.Create(OpCodes.Ldloca, 0)); - serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); - serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc)); - serWorker.Append(serWorker.Create(OpCodes.Stfld, importedField)); - } - else - { - Weaver.Error("GenerateDeserialization for " + td.Name + " unknown type [" + ft + "]. [SyncList] member variables must be basic types."); - return null; - } + serWorker.Append(serWorker.Create(OpCodes.Ldarg_1)); + serWorker.Append(serWorker.Create(OpCodes.Call, readerFunc)); + serWorker.Append(serWorker.Create(OpCodes.Ret)); + } + else + { + Weaver.Error("GenerateDeserialization for " + td.Name + " unknown type [" + itemType + "]. [SyncList] member variables must be basic types."); + return null; } - serWorker.Append(serWorker.Create(OpCodes.Ldloc_0)); - serWorker.Append(serWorker.Create(OpCodes.Ret)); - td.Methods.Add(serializeFunc); - return serializeFunc; + td.Methods.Add(deserializeFunction); + return deserializeFunction; } } } diff --git a/Assets/Mirror/Tests/WeaverTest.cs b/Assets/Mirror/Tests/WeaverTest.cs index 86e535c52..e0512bf99 100644 --- a/Assets/Mirror/Tests/WeaverTest.cs +++ b/Assets/Mirror/Tests/WeaverTest.cs @@ -263,6 +263,13 @@ public void SyncListMissingParamlessCtor() Assert.That(m_weaverErrors.Count, Is.EqualTo(1)); Assert.That(m_weaverErrors[0], Does.Match("Missing parameter-less constructor")); } + + [Test] + public void SyncListByteValid() { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(m_weaverErrors.Count, Is.EqualTo(0)); + } + #endregion #region SyncListStruct tests @@ -285,25 +292,25 @@ public void SyncListStructGenericGeneric() public void SyncListStructMemberGeneric() { Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); - Assert.That(m_weaverErrors.Count, Is.EqualTo(1)); - Assert.That(m_weaverErrors[0], Does.Match("member cannot have generic parameters")); + Assert.That(m_weaverErrors.Count, Is.EqualTo(2)); + Assert.That(m_weaverErrors[0], Is.EqualTo("Mirror.Weaver error: WriteReadFunc for potato [MirrorTest.MirrorTestPlayer/MyGenericStruct`1/MirrorTest.MirrorTestPlayer/MyGenericStruct`1]. Cannot have generic parameters.")); } [Test] public void SyncListStructMemberInterface() { Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); - Assert.That(m_weaverErrors.Count, Is.EqualTo(1)); - Assert.That(m_weaverErrors[0], Does.Match("member cannot be an interface")); + Assert.That(m_weaverErrors.Count, Is.EqualTo(2)); + Assert.That(m_weaverErrors[0], Is.EqualTo( "Mirror.Weaver error: WriteReadFunc for potato [MirrorTest.MirrorTestPlayer/IPotato/MirrorTest.MirrorTestPlayer/IPotato]. Cannot be an interface.")); } [Test] public void SyncListStructMemberBasicType() { Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); - Assert.That(m_weaverErrors.Count, Is.EqualTo(2)); + Assert.That(m_weaverErrors.Count, Is.EqualTo(3)); Assert.That(m_weaverErrors[0], Does.Match("please make sure to use a valid type")); - Assert.That(m_weaverErrors[1], Does.Match("member variables must be basic types")); + Assert.That(m_weaverErrors[1], Does.Match("Mirror.Weaver error: WriteReadFunc for nonbasicpotato type System.Object no supported")); } #endregion