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<byte> {};
```

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
This commit is contained in:
Paul Pacheco 2019-03-22 05:51:20 -05:00 committed by GitHub
parent aa5e5a104f
commit 6f19489721
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 72 deletions

View File

@ -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;
}
}
}

View File

@ -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<System.Single>/MirrorTest.MirrorTestPlayer/MyGenericStruct`1<System.Single>]. 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