mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
feat: allowing lists to automatically be sent in Commands, Rpc, and Messages (#2151)
* weaver tests for list read write * generated tests for list read write * adding method to check for list type * temp * weaver functions for creating read write for list * generating tests for lists
This commit is contained in:
parent
5b179e8917
commit
381e5a115b
@ -94,6 +94,24 @@ public static bool IsArrayType(this TypeReference tr)
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsArraySegment(this TypeDefinition td)
|
||||
{
|
||||
return td.FullName.StartsWith("System.ArraySegment`1", System.StringComparison.Ordinal);
|
||||
}
|
||||
public static bool IsArraySegment(this TypeReference td)
|
||||
{
|
||||
return td.FullName.StartsWith("System.ArraySegment`1", System.StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static bool IsList(this TypeDefinition td)
|
||||
{
|
||||
return td.FullName.StartsWith("System.Collections.Generic.List`1", System.StringComparison.Ordinal);
|
||||
}
|
||||
public static bool IsList(this TypeReference td)
|
||||
{
|
||||
return td.FullName.StartsWith("System.Collections.Generic.List`1", System.StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static bool CanBeResolved(this TypeReference parent)
|
||||
{
|
||||
while (parent != null)
|
||||
|
@ -43,13 +43,13 @@ public static MethodReference GetReadFunc(TypeReference variable, int recursionC
|
||||
return newReaderFunc;
|
||||
}
|
||||
|
||||
TypeDefinition td = variable.Resolve();
|
||||
if (td == null)
|
||||
TypeDefinition variableType = variable.Resolve();
|
||||
if (variableType == null)
|
||||
{
|
||||
Weaver.Error($"{variable.Name} is not a supported type", variable);
|
||||
return null;
|
||||
}
|
||||
if (td.IsDerivedFrom(WeaverTypes.ComponentType))
|
||||
if (variableType.IsDerivedFrom(WeaverTypes.ComponentType))
|
||||
{
|
||||
Weaver.Error($"Cannot generate reader for component type {variable.Name}. Use a supported type or provide a custom reader", variable);
|
||||
return null;
|
||||
@ -70,25 +70,29 @@ public static MethodReference GetReadFunc(TypeReference variable, int recursionC
|
||||
Weaver.Error($"Cannot pass type {variable.Name} by reference", variable);
|
||||
return null;
|
||||
}
|
||||
if (td.HasGenericParameters && !td.FullName.StartsWith("System.ArraySegment`1", System.StringComparison.Ordinal))
|
||||
if (variableType.HasGenericParameters && !variableType.IsArraySegment() && !variableType.IsList())
|
||||
{
|
||||
Weaver.Error($"Cannot generate reader for generic variable {variable.Name}. Use a supported type or provide a custom reader", variable);
|
||||
return null;
|
||||
}
|
||||
if (td.IsInterface)
|
||||
if (variableType.IsInterface)
|
||||
{
|
||||
Weaver.Error($"Cannot generate reader for interface {variable.Name}. Use a supported type or provide a custom reader", variable);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (td.IsEnum)
|
||||
if (variableType.IsEnum)
|
||||
{
|
||||
return GetReadFunc(td.GetEnumUnderlyingType(), recursionCount);
|
||||
return GetReadFunc(variableType.GetEnumUnderlyingType(), recursionCount);
|
||||
}
|
||||
else if (variable.FullName.StartsWith("System.ArraySegment`1", System.StringComparison.Ordinal))
|
||||
else if (variableType.IsArraySegment())
|
||||
{
|
||||
newReaderFunc = GenerateArraySegmentReadFunc(variable, recursionCount);
|
||||
}
|
||||
else if (variableType.IsList())
|
||||
{
|
||||
newReaderFunc = GenerateListReadFunc(variable, recursionCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
newReaderFunc = GenerateClassOrStructReadFunction(variable, recursionCount);
|
||||
@ -222,7 +226,7 @@ static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, int
|
||||
return null;
|
||||
}
|
||||
|
||||
string functionName = "_ReadArraySegment_" + variable.GetElementType().Name + "_";
|
||||
string functionName = "_ReadArraySegment_" + elementType.Name + "_";
|
||||
if (variable.DeclaringType != null)
|
||||
{
|
||||
functionName += variable.DeclaringType.Name;
|
||||
@ -301,6 +305,111 @@ static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable, int
|
||||
return readerFunc;
|
||||
}
|
||||
|
||||
static MethodDefinition GenerateListReadFunc(TypeReference variable, int recursionCount)
|
||||
{
|
||||
GenericInstanceType genericInstance = (GenericInstanceType)variable;
|
||||
TypeReference elementType = genericInstance.GenericArguments[0];
|
||||
|
||||
MethodReference elementReadFunc = GetReadFunc(elementType, recursionCount + 1);
|
||||
if (elementReadFunc == null)
|
||||
{
|
||||
Weaver.Error($"Cannot generate reader for List because element {elementType.Name} does not have a reader. Use a supported type or provide a custom reader", variable);
|
||||
return null;
|
||||
}
|
||||
|
||||
string functionName = "_ReadList_" + elementType.Name + "_";
|
||||
if (variable.DeclaringType != null)
|
||||
{
|
||||
functionName += variable.DeclaringType.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
functionName += "None";
|
||||
}
|
||||
|
||||
// create new reader for this type
|
||||
MethodDefinition readerFunc = new MethodDefinition(functionName,
|
||||
MethodAttributes.Public |
|
||||
MethodAttributes.Static |
|
||||
MethodAttributes.HideBySig,
|
||||
variable);
|
||||
|
||||
readerFunc.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(WeaverTypes.NetworkReaderType)));
|
||||
|
||||
readerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.int32Type));
|
||||
readerFunc.Body.Variables.Add(new VariableDefinition(variable));
|
||||
readerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.int32Type));
|
||||
readerFunc.Body.InitLocals = true;
|
||||
|
||||
ILProcessor worker = readerFunc.Body.GetILProcessor();
|
||||
|
||||
// int count = reader.ReadPackedInt32();
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetReadFunc(WeaverTypes.int32Type)));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
|
||||
// -1 is null list, so if count is less than 0 return null
|
||||
// if (count < 0) {
|
||||
// return null
|
||||
// }
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
|
||||
Instruction labelEmptyArray = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Bge, labelEmptyArray));
|
||||
// return null
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Append(labelEmptyArray);
|
||||
|
||||
// List<T> list = new List<T>();
|
||||
worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.ListConstructorReference.MakeHostInstanceGeneric(genericInstance)));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_1));
|
||||
|
||||
// loop through array and deserialize each element
|
||||
// generates code like this
|
||||
// for (int i=0; i< length ; i++)
|
||||
// {
|
||||
// list[i] = reader.ReadXXX();
|
||||
// }
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_2));
|
||||
Instruction labelHead = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Br, labelHead));
|
||||
|
||||
// loop body
|
||||
Instruction labelBody = worker.Create(OpCodes.Nop);
|
||||
worker.Append(labelBody);
|
||||
|
||||
MethodReference addItem = WeaverTypes.ListAddReference.MakeHostInstanceGeneric(genericInstance);
|
||||
|
||||
// list.Add(reader.ReadT());
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1)); // list
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0)); // reader
|
||||
worker.Append(worker.Create(OpCodes.Call, elementReadFunc)); // Read
|
||||
worker.Append(worker.Create(OpCodes.Call, addItem)); // set_Item
|
||||
|
||||
// end for loop
|
||||
|
||||
// for loop i++
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_2));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
|
||||
worker.Append(worker.Create(OpCodes.Add));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_2));
|
||||
|
||||
// loop while check
|
||||
worker.Append(labelHead);
|
||||
// for loop i < count
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_2));
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Blt, labelBody));
|
||||
|
||||
// return value;
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
return readerFunc;
|
||||
}
|
||||
|
||||
|
||||
static MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable, int recursionCount)
|
||||
{
|
||||
if (recursionCount > MaxRecursionCount)
|
||||
|
@ -63,6 +63,13 @@ public static class WeaverTypes
|
||||
public static MethodReference ArraySegmentOffsetReference;
|
||||
public static MethodReference ArraySegmentCountReference;
|
||||
|
||||
// list
|
||||
public static TypeReference ListType;
|
||||
public static MethodReference ListConstructorReference;
|
||||
public static MethodReference ListCountReference;
|
||||
public static MethodReference ListGetItemReference;
|
||||
public static MethodReference ListAddReference;
|
||||
|
||||
// system types
|
||||
public static TypeReference voidType;
|
||||
public static TypeReference singleType;
|
||||
@ -159,6 +166,12 @@ public static void SetupTargetTypes(AssemblyDefinition unityAssembly, AssemblyDe
|
||||
ArraySegmentOffsetReference = Resolvers.ResolveProperty(ArraySegmentType, currentAssembly, "Offset");
|
||||
ArraySegmentConstructorReference = Resolvers.ResolveMethod(ArraySegmentType, currentAssembly, ".ctor");
|
||||
|
||||
ListType = ImportSystemModuleType(currentAssembly, systemModule, "System.Collections.Generic.List`1");
|
||||
ListCountReference = Resolvers.ResolveProperty(ListType, currentAssembly, "Count");
|
||||
ListGetItemReference = Resolvers.ResolveMethod(ListType, currentAssembly, "get_Item");
|
||||
ListAddReference = Resolvers.ResolveMethod(ListType, currentAssembly, "Add");
|
||||
ListConstructorReference = Resolvers.ResolveMethod(ListType, currentAssembly, ".ctor");
|
||||
|
||||
NetworkReaderType = mirrorAssembly.MainModule.GetType("Mirror.NetworkReader");
|
||||
NetworkWriterType = mirrorAssembly.MainModule.GetType("Mirror.NetworkWriter");
|
||||
TypeReference pooledNetworkWriterTmp = mirrorAssembly.MainModule.GetType("Mirror.PooledNetworkWriter");
|
||||
|
@ -50,13 +50,14 @@ public static MethodReference GetWriteFunc(TypeReference variable, int recursion
|
||||
Weaver.Error($"Cannot pass {variable.Name} by reference", variable);
|
||||
return null;
|
||||
}
|
||||
TypeDefinition td = variable.Resolve();
|
||||
if (td == null)
|
||||
|
||||
TypeDefinition variableType = variable.Resolve();
|
||||
if (variableType == null)
|
||||
{
|
||||
Weaver.Error($"{variable.Name} is not a supported type. Use a supported type or provide a custom writer", variable);
|
||||
return null;
|
||||
}
|
||||
if (td.IsDerivedFrom(WeaverTypes.ComponentType))
|
||||
if (variableType.IsDerivedFrom(WeaverTypes.ComponentType))
|
||||
{
|
||||
Weaver.Error($"Cannot generate writer for component type {variable.Name}. Use a supported type or provide a custom writer", variable);
|
||||
return null;
|
||||
@ -71,12 +72,12 @@ public static MethodReference GetWriteFunc(TypeReference variable, int recursion
|
||||
Weaver.Error($"Cannot generate writer for {variable.Name}. Use a supported type or provide a custom writer", variable);
|
||||
return null;
|
||||
}
|
||||
if (td.HasGenericParameters && !td.FullName.StartsWith("System.ArraySegment`1", System.StringComparison.Ordinal))
|
||||
if (variableType.HasGenericParameters && !variableType.IsArraySegment() && !variableType.IsList())
|
||||
{
|
||||
Weaver.Error($"Cannot generate writer for generic type {variable.Name}. Use a supported type or provide a custom writer", variable);
|
||||
return null;
|
||||
}
|
||||
if (td.IsInterface)
|
||||
if (variableType.IsInterface)
|
||||
{
|
||||
Weaver.Error($"Cannot generate writer for interface {variable.Name}. Use a supported type or provide a custom writer", variable);
|
||||
return null;
|
||||
@ -86,10 +87,14 @@ public static MethodReference GetWriteFunc(TypeReference variable, int recursion
|
||||
{
|
||||
return GetWriteFunc(variable.Resolve().GetEnumUnderlyingType(), recursionCount);
|
||||
}
|
||||
else if (variable.FullName.StartsWith("System.ArraySegment`1", System.StringComparison.Ordinal))
|
||||
else if (variable.IsArraySegment())
|
||||
{
|
||||
newWriterFunc = GenerateArraySegmentWriteFunc(variable, recursionCount);
|
||||
}
|
||||
else if (variable.IsList())
|
||||
{
|
||||
newWriterFunc = GenerateListWriteFunc(variable, recursionCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
newWriterFunc = GenerateClassOrStructWriterFunction(variable, recursionCount);
|
||||
@ -243,8 +248,10 @@ static MethodDefinition GenerateArrayWriteFunc(TypeReference variable, int recur
|
||||
worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.int32Type)));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
|
||||
// int length = value.Length;
|
||||
// else not null
|
||||
worker.Append(labelNull);
|
||||
|
||||
// int length = value.Length;
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Ldlen));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
@ -267,8 +274,8 @@ static MethodDefinition GenerateArrayWriteFunc(TypeReference variable, int recur
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1));
|
||||
worker.Append(worker.Create(OpCodes.Ldelema, variable.GetElementType()));
|
||||
worker.Append(worker.Create(OpCodes.Ldobj, variable.GetElementType()));
|
||||
worker.Append(worker.Create(OpCodes.Ldelema, elementType));
|
||||
worker.Append(worker.Create(OpCodes.Ldobj, elementType));
|
||||
worker.Append(worker.Create(OpCodes.Call, elementWriteFunc));
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1));
|
||||
@ -384,5 +391,115 @@ static MethodDefinition GenerateArraySegmentWriteFunc(TypeReference variable, in
|
||||
return writerFunc;
|
||||
}
|
||||
|
||||
static MethodDefinition GenerateListWriteFunc(TypeReference variable, int recursionCount)
|
||||
{
|
||||
GenericInstanceType genericInstance = (GenericInstanceType)variable;
|
||||
TypeReference elementType = genericInstance.GenericArguments[0];
|
||||
MethodReference elementWriteFunc = GetWriteFunc(elementType, recursionCount + 1);
|
||||
|
||||
if (elementWriteFunc == null)
|
||||
{
|
||||
Weaver.Error($"Cannot generate writer for List because element {elementType.Name} does not have a writer. Use a supported type or provide a custom writer", variable);
|
||||
return null;
|
||||
}
|
||||
|
||||
string functionName = "_WriteList_" + elementType.Name + "_";
|
||||
if (variable.DeclaringType != null)
|
||||
{
|
||||
functionName += variable.DeclaringType.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
functionName += "None";
|
||||
}
|
||||
|
||||
// create new writer for this type
|
||||
MethodDefinition writerFunc = new MethodDefinition(functionName,
|
||||
MethodAttributes.Public |
|
||||
MethodAttributes.Static |
|
||||
MethodAttributes.HideBySig,
|
||||
WeaverTypes.voidType);
|
||||
|
||||
writerFunc.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.CurrentAssembly.MainModule.ImportReference(WeaverTypes.NetworkWriterType)));
|
||||
writerFunc.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.None, variable));
|
||||
|
||||
writerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.int32Type));
|
||||
writerFunc.Body.Variables.Add(new VariableDefinition(WeaverTypes.int32Type));
|
||||
writerFunc.Body.InitLocals = true;
|
||||
|
||||
ILProcessor worker = writerFunc.Body.GetILProcessor();
|
||||
|
||||
// if (value == null)
|
||||
// {
|
||||
// writer.WritePackedInt32(-1);
|
||||
// return;
|
||||
// }
|
||||
Instruction labelNull = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, labelNull));
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_M1));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.int32Type)));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
|
||||
// else not null
|
||||
worker.Append(labelNull);
|
||||
|
||||
MethodReference countref = WeaverTypes.ListCountReference.MakeHostInstanceGeneric(genericInstance);
|
||||
|
||||
// int count = value.Count;
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Call, countref));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
|
||||
// writer.WritePackedInt32(count);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.int32Type)));
|
||||
|
||||
// Loop through the List<T> and call the writer for each element.
|
||||
// generates this:
|
||||
// for (int i=0; i < count; i++)
|
||||
// {
|
||||
// writer.WriteT(value[i]);
|
||||
// }
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_1));
|
||||
Instruction labelHead = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Br, labelHead));
|
||||
|
||||
// loop body
|
||||
Instruction labelBody = worker.Create(OpCodes.Nop);
|
||||
worker.Append(labelBody);
|
||||
|
||||
MethodReference getItem = WeaverTypes.ListGetItemReference.MakeHostInstanceGeneric(genericInstance);
|
||||
|
||||
// writer.Write(value[i]);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0)); // writer
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1)); // value
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1)); // i
|
||||
worker.Append(worker.Create(OpCodes.Call, getItem)); //get_Item
|
||||
worker.Append(worker.Create(OpCodes.Call, elementWriteFunc)); // Write
|
||||
|
||||
|
||||
// end for loop
|
||||
|
||||
// for loop i++
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
|
||||
worker.Append(worker.Create(OpCodes.Add));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_1));
|
||||
|
||||
worker.Append(labelHead);
|
||||
// for loop i < count
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_1));
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Blt, labelBody));
|
||||
|
||||
// return
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
return writerFunc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Generated by CollectionWriterGenerator.cs
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mirror.Tests.Generators;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
@ -716,4 +717,324 @@ public void SendsData()
|
||||
Assert.That(unpackedCollection.Array[unpackedCollection.Offset + 2].a, Is.EqualTo(new ClassWithNoConstructor { a = 5 }.a));
|
||||
}
|
||||
}
|
||||
|
||||
public class List_int_Test
|
||||
{
|
||||
class Message : MessageBase
|
||||
{
|
||||
public List<int> collection;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsNull()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = default
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<int> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.That(unpackedCollection, Is.Null.Or.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsEmpty()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<int> { }
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<int> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsEmpty(unpackedCollection);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsData()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<int>
|
||||
{
|
||||
3, 4, 5
|
||||
}
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<int> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsNotEmpty(unpackedCollection);
|
||||
Assert.That(unpackedCollection[0], Is.EqualTo(3));
|
||||
Assert.That(unpackedCollection[1], Is.EqualTo(4));
|
||||
Assert.That(unpackedCollection[2], Is.EqualTo(5));
|
||||
}
|
||||
}
|
||||
|
||||
public class List_string_Test
|
||||
{
|
||||
class Message : MessageBase
|
||||
{
|
||||
public List<string> collection;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsNull()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = default
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<string> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.That(unpackedCollection, Is.Null.Or.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsEmpty()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<string> { }
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<string> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsEmpty(unpackedCollection);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsData()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<string>
|
||||
{
|
||||
"Some", "String", "Value"
|
||||
}
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<string> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsNotEmpty(unpackedCollection);
|
||||
Assert.That(unpackedCollection[0], Is.EqualTo("Some"));
|
||||
Assert.That(unpackedCollection[1], Is.EqualTo("String"));
|
||||
Assert.That(unpackedCollection[2], Is.EqualTo("Value"));
|
||||
}
|
||||
}
|
||||
|
||||
public class List_Vector3_Test
|
||||
{
|
||||
class Message : MessageBase
|
||||
{
|
||||
public List<Vector3> collection;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsNull()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = default
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<Vector3> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.That(unpackedCollection, Is.Null.Or.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsEmpty()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<Vector3> { }
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<Vector3> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsEmpty(unpackedCollection);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsData()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<Vector3>
|
||||
{
|
||||
new Vector3(1, 2, 3), new Vector3(4, 5, 6), new Vector3(7, 8, 9)
|
||||
}
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<Vector3> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsNotEmpty(unpackedCollection);
|
||||
Assert.That(unpackedCollection[0], Is.EqualTo(new Vector3(1, 2, 3)));
|
||||
Assert.That(unpackedCollection[1], Is.EqualTo(new Vector3(4, 5, 6)));
|
||||
Assert.That(unpackedCollection[2], Is.EqualTo(new Vector3(7, 8, 9)));
|
||||
}
|
||||
}
|
||||
|
||||
public class List_FloatStringStruct_Test
|
||||
{
|
||||
class Message : MessageBase
|
||||
{
|
||||
public List<FloatStringStruct> collection;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsNull()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = default
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<FloatStringStruct> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.That(unpackedCollection, Is.Null.Or.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsEmpty()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<FloatStringStruct> { }
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<FloatStringStruct> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsEmpty(unpackedCollection);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsData()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<FloatStringStruct>
|
||||
{
|
||||
new FloatStringStruct { value = 3, anotherValue = "Some" }, new FloatStringStruct { value = 4, anotherValue = "String" }, new FloatStringStruct { value = 5, anotherValue = "Values" }
|
||||
}
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<FloatStringStruct> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsNotEmpty(unpackedCollection);
|
||||
Assert.That(unpackedCollection[0], Is.EqualTo(new FloatStringStruct { value = 3, anotherValue = "Some" }));
|
||||
Assert.That(unpackedCollection[1], Is.EqualTo(new FloatStringStruct { value = 4, anotherValue = "String" }));
|
||||
Assert.That(unpackedCollection[2], Is.EqualTo(new FloatStringStruct { value = 5, anotherValue = "Values" }));
|
||||
}
|
||||
}
|
||||
|
||||
public class List_ClassWithNoConstructor_Test
|
||||
{
|
||||
class Message : MessageBase
|
||||
{
|
||||
public List<ClassWithNoConstructor> collection;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsNull()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = default
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<ClassWithNoConstructor> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.That(unpackedCollection, Is.Null.Or.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsEmpty()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<ClassWithNoConstructor> { }
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<ClassWithNoConstructor> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsEmpty(unpackedCollection);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SendsData()
|
||||
{
|
||||
Message message = new Message
|
||||
{
|
||||
collection = new List<ClassWithNoConstructor>
|
||||
{
|
||||
new ClassWithNoConstructor { a = 3 }, new ClassWithNoConstructor { a = 4 }, new ClassWithNoConstructor { a = 5 }
|
||||
}
|
||||
};
|
||||
|
||||
byte[] data = MessagePacker.Pack(message);
|
||||
|
||||
Message unpacked = MessagePacker.Unpack<Message>(data);
|
||||
List<ClassWithNoConstructor> unpackedCollection = unpacked.collection;
|
||||
|
||||
Assert.IsNotNull(unpackedCollection);
|
||||
Assert.IsNotEmpty(unpackedCollection);
|
||||
Assert.That(unpackedCollection[0].a, Is.EqualTo(new ClassWithNoConstructor { a = 3 }.a));
|
||||
Assert.That(unpackedCollection[1].a, Is.EqualTo(new ClassWithNoConstructor { a = 4 }.a));
|
||||
Assert.That(unpackedCollection[2].a, Is.EqualTo(new ClassWithNoConstructor { a = 5 }.a));
|
||||
}
|
||||
}
|
||||
}
|
@ -75,8 +75,8 @@ static IEnumerable<string> valuesForType(string elementType)
|
||||
static readonly string[] collectionTypes = new string[]
|
||||
{
|
||||
ArrayType,
|
||||
//ListType,
|
||||
ArraySegmentType
|
||||
ArraySegmentType,
|
||||
ListType,
|
||||
};
|
||||
|
||||
const string NameSpace = BaseNameSpace + ".CollectionWriters";
|
||||
@ -86,6 +86,7 @@ static string Main(IEnumerable<string> classes)
|
||||
string mergedClasses = Merge(classes);
|
||||
return $@"// Generated by {nameof(CollectionWriterGenerator)}.cs
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mirror.Tests.Generators;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>_WeaverTests2.csproj</RootNamespace>
|
||||
@ -72,13 +72,16 @@
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForClassWithValidConstructor.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForEnums.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForInheritedFromScriptableObject.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForList.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForStructFromDifferentAssemblies.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForStructs.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForStuctArraySegment.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\CreatesForStuctList.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\ExcludesNonSerializedFields.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorForClassWithNoValidConstructor.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorForInvalidArraySegmentType.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorForInvalidArrayType.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorForInvalidListType.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorForJaggedArray.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorForMultidimensionalArray.cs" />
|
||||
<Compile Include="GeneratedReaderWriter~\GivesErrorWhenUsingInterface.cs" />
|
||||
|
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using Mirror;
|
||||
|
||||
namespace GeneratedReaderWriter.CreatesForList
|
||||
{
|
||||
public class CreatesForList : NetworkBehaviour
|
||||
{
|
||||
[ClientRpc]
|
||||
public void RpcDoSomething(List<int> data)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using Mirror;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeneratedReaderWriter.CreatesForStructList
|
||||
{
|
||||
public class CreatesForStructList : NetworkBehaviour
|
||||
{
|
||||
[ClientRpc]
|
||||
public void RpcDoSomething(List<MyStruct> data)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
public struct MyStruct
|
||||
{
|
||||
public int someValue;
|
||||
public Vector3 anotherValue;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Mirror;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeneratedReaderWriter.GivesErrorForInvalidListType
|
||||
{
|
||||
public class GivesErrorForInvalidListType : NetworkBehaviour
|
||||
{
|
||||
[ClientRpc]
|
||||
public void RpcDoSomething(List<MonoBehaviour> data)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
@ -179,5 +179,24 @@ public void GivesErrorForInvalidArraySegmentType()
|
||||
Assert.That(weaverErrors, Contains.Item("Cannot generate writer for ArraySegment because element MonoBehaviour does not have a writer. Use a supported type or provide a custom writer (at System.ArraySegment`1<UnityEngine.MonoBehaviour>)"));
|
||||
Assert.That(weaverErrors, Contains.Item("Cannot generate reader for ArraySegment because element MonoBehaviour does not have a reader. Use a supported type or provide a custom reader (at System.ArraySegment`1<UnityEngine.MonoBehaviour>)"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreatesForList()
|
||||
{
|
||||
Assert.That(weaverErrors, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreatesForStructList()
|
||||
{
|
||||
Assert.That(weaverErrors, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GivesErrorForInvalidListType()
|
||||
{
|
||||
Assert.That(weaverErrors, Contains.Item("Cannot generate writer for List because element MonoBehaviour does not have a writer. Use a supported type or provide a custom writer (at System.Collections.Generic.List`1<UnityEngine.MonoBehaviour>)"));
|
||||
Assert.That(weaverErrors, Contains.Item("Cannot generate reader for List because element MonoBehaviour does not have a reader. Use a supported type or provide a custom reader (at System.Collections.Generic.List`1<UnityEngine.MonoBehaviour>)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user