diff --git a/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs b/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs new file mode 100644 index 000000000..20a48a163 --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; +using Mono.CecilX; + +namespace Mirror.Weaver +{ + public class GenericArgumentResolver + { + readonly Stack stack = new Stack(); + readonly int maxGenericArgument; + + public GenericArgumentResolver(int maxGenericArgument) + { + this.maxGenericArgument = maxGenericArgument; + } + + public bool GetGenericFromBaseClass(TypeDefinition td, int genericArgument, TypeReference baseType, out TypeReference itemType) + { + itemType = null; + if (GetGenericBaseType(td, baseType, out GenericInstanceType parent)) + { + TypeReference arg = parent.GenericArguments[genericArgument]; + if (arg.IsGenericParameter) + { + itemType = FindParameterInStack(genericArgument); + } + else + { + itemType = Weaver.CurrentAssembly.MainModule.ImportReference(arg); + } + } + + return itemType != null; + } + + TypeReference FindParameterInStack(int genericArgument) + { + while (stack.Count > 0) + { + TypeReference next = stack.Pop(); + + if (!(next is GenericInstanceType genericType)) + { + // if type is not GenericInstanceType something has gone wrong + return null; + } + + if (genericType.GenericArguments.Count < genericArgument) + { + // if less than `genericArgument` then we didnt find generic argument + return null; + } + + if (genericType.GenericArguments.Count > maxGenericArgument) + { + // if greater than `genericArgument` it is hard to know which generic arg we want + // See SyncListGenericInheritanceWithMultipleGeneric test + Weaver.Error($"Too many generic argument for {next}"); + return null; + } + + TypeReference genericArg = genericType.GenericArguments[genericArgument]; + if (!genericArg.IsGenericParameter) + { + // if not generic, sucessfully found type + return Weaver.CurrentAssembly.MainModule.ImportReference(genericArg); + } + } + + // nothing left in stack, something went wrong + return null; + } + + bool GetGenericBaseType(TypeDefinition td, TypeReference baseType, out GenericInstanceType found) + { + stack.Clear(); + TypeReference parent = td.BaseType; + found = null; + + while (parent != null) + { + string parentName = parent.FullName; + + // strip generic parameters + int index = parentName.IndexOf('<'); + if (index != -1) + { + parentName = parentName.Substring(0, index); + } + + if (parentName == baseType.FullName) + { + found = parent as GenericInstanceType; + break; + } + try + { + stack.Push(parent); + parent = parent.Resolve().BaseType; + } + catch (AssemblyResolutionException) + { + // this can happen for plugins. + break; + } + } + + return found != null; + } + } +} diff --git a/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta b/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta new file mode 100644 index 000000000..685f9145e --- /dev/null +++ b/Assets/Mirror/Editor/Weaver/Processors/GenericArgumentResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd67b3f7c2d66074a9bc7a23787e2ffb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs index 22cd99c84..b7ba67fc7 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncDictionaryProcessor.cs @@ -11,8 +11,26 @@ static class SyncDictionaryProcessor /// The synclist class public static void Process(TypeDefinition td) { - SyncObjectProcessor.GenerateSerialization(td, 0, "SerializeKey", "DeserializeKey"); - SyncObjectProcessor.GenerateSerialization(td, 1, "SerializeItem", "DeserializeItem"); + GenericArgumentResolver resolver = new GenericArgumentResolver(2); + + if (resolver.GetGenericFromBaseClass(td, 0, Weaver.SyncDictionaryType, out TypeReference keyType)) + { + SyncObjectProcessor.GenerateSerialization(td, keyType, "SerializeKey", "DeserializeKey"); + } + else + { + Weaver.Error($"Could not find generic arguments for {Weaver.SyncDictionaryType} using {td}"); + return; + } + + if (resolver.GetGenericFromBaseClass(td, 1, Weaver.SyncDictionaryType, out TypeReference itemType)) + { + SyncObjectProcessor.GenerateSerialization(td, itemType, "SerializeItem", "DeserializeItem"); + } + else + { + Weaver.Error($"Could not find generic arguments for {Weaver.SyncDictionaryType} using {td}"); + } } } } diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs index ef710904d..cff414344 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncListProcessor.cs @@ -9,9 +9,18 @@ static class SyncListProcessor /// Generates serialization methods for synclists /// /// The synclist class - public static void Process(TypeDefinition td) + public static void Process(TypeDefinition td, TypeReference baseType) { - SyncObjectProcessor.GenerateSerialization(td, 0, "SerializeItem", "DeserializeItem"); + GenericArgumentResolver resolver = new GenericArgumentResolver(1); + + if (resolver.GetGenericFromBaseClass(td, 0, baseType, out TypeReference itemType)) + { + SyncObjectProcessor.GenerateSerialization(td, itemType, "SerializeItem", "DeserializeItem"); + } + else + { + Weaver.Error($"Could not find generic arguments for {baseType} using {td}"); + } } } } diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs index 0c998866d..ded5533eb 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs @@ -41,7 +41,7 @@ static void GenerateSyncObjectInstanceInitializer(ILProcessor ctorWorker, FieldD MethodDefinition ctor = fieldType.Methods.FirstOrDefault(x => x.Name == ".ctor" && !x.HasParameters); if (ctor == null) { - Weaver.Error($"{fd} does not have a default constructor"); + Weaver.Error($"{fd} Can not intialize field because no default constructor was found. Manually intialize the field (call the constructor) or add constructor without Parameter"); return; } MethodReference objectConstructor = Weaver.CurrentAssembly.MainModule.ImportReference(ctor); diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs index 498ba84c9..f12286e05 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectProcessor.cs @@ -10,19 +10,11 @@ public static class SyncObjectProcessor /// /// The type of the class that needs serialization methods /// Which generic argument to serialize, 0 is the first one + /// the type that has generic arguments /// The name of the serialize method /// The name of the deserialize method - public static void GenerateSerialization(TypeDefinition td, int genericArgument, string serializeMethod, string deserializeMethod) + public static void GenerateSerialization(TypeDefinition td, TypeReference itemType, string serializeMethod, string deserializeMethod) { - // find item type - GenericInstanceType gt = (GenericInstanceType)td.BaseType; - if (gt.GenericArguments.Count <= genericArgument) - { - Weaver.Error($"{td} should have {genericArgument} generic arguments"); - return; - } - TypeReference itemType = Weaver.CurrentAssembly.MainModule.ImportReference(gt.GenericArguments[genericArgument]); - Weaver.DLog(td, "SyncObjectProcessor Start item:" + itemType.FullName); MethodReference writeItemFunc = GenerateSerialization(serializeMethod, td, itemType); @@ -47,6 +39,15 @@ static MethodReference GenerateSerialization(string methodName, TypeDefinition t if (existing != null) return existing; + + // this check needs to happen inside GenerateSerialization because + // we need to check if user has made custom function above + if (itemType.IsGenericInstance) + { + Weaver.Error($"{td} Can not create Serialize or Deserialize for generic element. Override virtual methods with custom Serialize and Deserialize to use {itemType} in SyncList"); + return null; + } + MethodDefinition serializeFunc = new MethodDefinition(methodName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Public | @@ -57,12 +58,6 @@ static MethodReference GenerateSerialization(string methodName, TypeDefinition t serializeFunc.Parameters.Add(new ParameterDefinition("item", ParameterAttributes.None, itemType)); ILProcessor serWorker = serializeFunc.Body.GetILProcessor(); - if (itemType.IsGenericInstance) - { - Weaver.Error($"{td} cannot have generic elements {itemType}"); - return null; - } - MethodReference writeFunc = Writers.GetWriteFunc(itemType); if (writeFunc != null) { @@ -88,6 +83,14 @@ static MethodReference GenerateDeserialization(string methodName, TypeDefinition if (existing != null) return existing; + // this check needs to happen inside GenerateDeserialization because + // we need to check if user has made custom function above + if (itemType.IsGenericInstance) + { + Weaver.Error($"{td} Can not create Serialize or Deserialize for generic element. Override virtual methods with custom Serialize and Deserialize to use {itemType} in SyncList"); + return null; + } + MethodDefinition deserializeFunction = new MethodDefinition(methodName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Public | diff --git a/Assets/Mirror/Editor/Weaver/Weaver.cs b/Assets/Mirror/Editor/Weaver/Weaver.cs index e93a08399..9453125b0 100644 --- a/Assets/Mirror/Editor/Weaver/Weaver.cs +++ b/Assets/Mirror/Editor/Weaver/Weaver.cs @@ -406,31 +406,37 @@ static bool WeaveMessage(TypeDefinition td) static bool WeaveSyncObject(TypeDefinition td) { - if (!td.IsClass) - return false; - + bool modified = false; + // ignore generic classes // we can not process generic classes // we give error if a generic syncObject is used in NetworkBehaviour if (td.HasGenericParameters) return false; - bool modified = false; + // ignore abstract classes + // we dont need to process abstract classes because classes that + // inherit from them will be processed instead - if (td.IsDerivedFrom(SyncListType)) + // We cant early return with non classes or Abstract classes + // because we still need to check for embeded types + if (td.IsClass || !td.IsAbstract) { - SyncListProcessor.Process(td); - modified = true; - } - else if (td.IsDerivedFrom(SyncSetType)) - { - SyncListProcessor.Process(td); - modified = true; - } - else if (td.IsDerivedFrom(SyncDictionaryType)) - { - SyncDictionaryProcessor.Process(td); - modified = true; + if (td.IsDerivedFrom(SyncListType)) + { + SyncListProcessor.Process(td, SyncListType); + modified = true; + } + else if (td.IsDerivedFrom(SyncSetType)) + { + SyncListProcessor.Process(td, SyncSetType); + modified = true; + } + else if (td.IsDerivedFrom(SyncDictionaryType)) + { + SyncDictionaryProcessor.Process(td); + modified = true; + } } // check for embedded types diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs index 3a921ecca..e32559c4e 100644 --- a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs @@ -5,7 +5,43 @@ namespace Mirror.Weaver.Tests public class WeaverSyncListTests : WeaverTestsBuildFromTestName { [Test] - public void SyncListValid() + public void SyncList() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListByteValid() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListGenericAbstractInheritance() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListGenericInheritance() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListGenericInheritanceWithMultipleGeneric() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); + Assert.That(weaverErrors, Has.Some.Match(@"Mirror\.Weaver error: Could not find generic arguments for Mirror\.SyncList`1 using MirrorTest\.SomeListInt")); + Assert.That(weaverErrors, Has.Some.Match(@"Mirror\.Weaver error: Too many generic argument for MirrorTest\.SomeList`2")); + } + + [Test] + public void SyncListInheritance() { Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); Assert.That(weaverErrors, Is.Empty); @@ -15,11 +51,116 @@ public void SyncListValid() public void SyncListMissingParamlessCtor() { Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); - Assert.That(weaverErrors, Contains.Item("Mirror.Weaver error: MirrorTest.MirrorTestPlayer/SyncListString2 MirrorTest.MirrorTestPlayer::Foo does not have a default constructor")); + string weaverError = @"Mirror\.Weaver error:"; + string fieldType = @"MirrorTest\.SyncListString2 MirrorTest\.SyncListMissingParamlessCtor::Foo"; + string errorMessage = @"Can not intialize field because no default constructor was found\. Manually intialize the field \(call the constructor\) or add constructor without Parameter"; + Assert.That(weaverErrors, Has.Some.Match($"{weaverError} {fieldType} {errorMessage}")); + } + + [Test] + public void SyncListMissingParamlessCtorManuallyInitialized() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); } [Test] - public void SyncListByteValid() + public void SyncListNestedStruct() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListNestedInAbstractClass() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListNestedInAbstractClassWithInvalid() + { + // we need this negative test to make sure that SyncList is being processed + Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); + Assert.That(weaverErrors, Has.Some.Match(@"Mirror\.Weaver error: UnityEngine\.Object MirrorTest\.SomeAbstractClass/MyNestedStruct::target has unsupported type\. Use a type supported by Mirror instead")); + } + + [Test] + public void SyncListNestedInStruct() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListNestedInStructWithInvalid() + { + // we need this negative test to make sure that SyncList is being processed + Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); + Assert.That(weaverErrors, Has.Some.Match(@"Mirror\.Weaver error: UnityEngine\.Object MirrorTest\.SomeData::target has unsupported type\. Use a type supported by Mirror instead")); + } + + [Test] + public void SyncListStruct() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListStructWithCustomDeserializeOnly() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListStructWithCustomMethods() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListStructWithCustomSerializeOnly() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); + Assert.That(weaverErrors, Is.Empty); + } + + [Test] + public void SyncListErrorForGenericStruct() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); + string weaverError = @"Mirror\.Weaver error:"; + string type = @"MirrorTest\.MyGenericStructList"; + string errorMessage = @"Can not create Serialize or Deserialize for generic element\. Override virtual methods with custom Serialize and Deserialize to use MirrorTest.MyGenericStruct`1 in SyncList"; + Assert.That(weaverErrors, Has.Some.Match($"{weaverError} {type} {errorMessage}")); + } + + [Test] + public void SyncListErrorForGenericStructWithCustomDeserializeOnly() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); + string weaverError = @"Mirror\.Weaver error:"; + string type = @"MirrorTest\.MyGenericStructList"; + string errorMessage = @"Can not create Serialize or Deserialize for generic element\. Override virtual methods with custom Serialize and Deserialize to use MirrorTest.MyGenericStruct`1 in SyncList"; + Assert.That(weaverErrors, Has.Some.Match($"{weaverError} {type} {errorMessage}")); + } + + [Test] + public void SyncListErrorForGenericStructWithCustomSerializeOnly() + { + Assert.That(CompilationFinishedHook.WeaveFailed, Is.True); + string weaverError = @"Mirror\.Weaver error:"; + string type = @"MirrorTest\.MyGenericStructList"; + string errorMessage = @"Can not create Serialize or Deserialize for generic element\. Override virtual methods with custom Serialize and Deserialize to use MirrorTest.MyGenericStruct`1 in SyncList"; + Assert.That(weaverErrors, Has.Some.Match($"{weaverError} {type} {errorMessage}")); + } + + [Test] + public void SyncListGenericStructWithCustomMethods() { Assert.That(CompilationFinishedHook.WeaveFailed, Is.False); Assert.That(weaverErrors, Is.Empty); diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListValid.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncList.cs similarity index 69% rename from Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListValid.cs rename to Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncList.cs index 7ce3b83f2..2858a8622 100644 --- a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListValid.cs +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncList.cs @@ -3,7 +3,7 @@ namespace MirrorTest { - class MirrorTestPlayer : NetworkBehaviour + class SyncListValid : NetworkBehaviour { public SyncListInt Foo; } diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListByteValid.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListByteValid.cs index 0c1e57bf8..1133dc827 100644 --- a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListByteValid.cs +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListByteValid.cs @@ -3,7 +3,7 @@ namespace MirrorTest { - class MirrorTestPlayer : NetworkBehaviour + class SyncListByteValid : NetworkBehaviour { class MyByteClass : SyncList {}; diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStruct.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStruct.cs new file mode 100644 index 000000000..8ee0fe3cd --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStruct.cs @@ -0,0 +1,16 @@ +using Mirror; + +namespace MirrorTest +{ + class SyncListErrorForGenericStruct : NetworkBehaviour + { + MyGenericStructList harpseals; + } + + struct MyGenericStruct + { + T genericpotato; + } + + class MyGenericStructList : SyncList> { }; +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStructWithCustomDeserializeOnly.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStructWithCustomDeserializeOnly.cs new file mode 100644 index 000000000..834785802 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStructWithCustomDeserializeOnly.cs @@ -0,0 +1,22 @@ +using Mirror; + +namespace MirrorTest +{ + class SyncListErrorForGenericStructWithCustomDeserializeOnly : NetworkBehaviour + { + MyGenericStructList harpseals; + } + + struct MyGenericStruct + { + public T genericpotato; + } + + class MyGenericStructList : SyncList> + { + protected override MyGenericStruct DeserializeItem(NetworkReader reader) + { + return new MyGenericStruct() { genericpotato = reader.ReadSingle() }; + } + }; +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStructWithCustomSerializeOnly.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStructWithCustomSerializeOnly.cs new file mode 100644 index 000000000..344a35fce --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListErrorForGenericStructWithCustomSerializeOnly.cs @@ -0,0 +1,22 @@ +using Mirror; + +namespace MirrorTest +{ + class SyncListErrorForGenericStructWithCustomSerializeOnly : NetworkBehaviour + { + MyGenericStructList harpseals; + } + + struct MyGenericStruct + { + public T genericpotato; + } + + class MyGenericStructList : SyncList> + { + protected override void SerializeItem(NetworkWriter writer, MyGenericStruct item) + { + writer.WriteSingle(item.genericpotato); + } + }; +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericAbstractInheritance.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericAbstractInheritance.cs new file mode 100644 index 000000000..b0a384b1a --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericAbstractInheritance.cs @@ -0,0 +1,13 @@ +using Mirror; + +namespace MirrorTest +{ + class SyncListGenericAbstractInheritance : NetworkBehaviour + { + readonly SomeListInt superSyncListString = new SomeListInt(); + } + + public abstract class SomeList : SyncList { } + + public class SomeListInt : SomeList { } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericInheritance.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericInheritance.cs new file mode 100644 index 000000000..2de7a0a02 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericInheritance.cs @@ -0,0 +1,13 @@ +using Mirror; + +namespace MirrorTest +{ + class SyncListGenericInheritance : NetworkBehaviour + { + readonly SomeListInt someList = new SomeListInt(); + } + + public class SomeList : SyncList { } + + public class SomeListInt : SomeList { } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericInheritanceWithMultipleGeneric.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericInheritanceWithMultipleGeneric.cs new file mode 100644 index 000000000..3c8131007 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericInheritanceWithMultipleGeneric.cs @@ -0,0 +1,19 @@ +using Mirror; + +namespace MirrorTest +{ + /* + This test will fail + It is hard to know which generic argument we want from `SomeList` + So instead give a useful error for this edge case + */ + + class SyncListGenericInheritanceWithMultipleGeneric : NetworkBehaviour + { + readonly SomeListInt someList = new SomeListInt(); + } + + public class SomeList : SyncList { } + + public class SomeListInt : SomeList { } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericStructWithCustomMethods.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericStructWithCustomMethods.cs new file mode 100644 index 000000000..b9c1ef5af --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListGenericStructWithCustomMethods.cs @@ -0,0 +1,27 @@ +using Mirror; + +namespace MirrorTest +{ + class SyncListGenericStructWithCustomMethods : NetworkBehaviour + { + MyGenericStructList harpseals; + } + + struct MyGenericStruct + { + public T genericpotato; + } + + class MyGenericStructList : SyncList> + { + protected override void SerializeItem(NetworkWriter writer, MyGenericStruct item) + { + writer.WriteSingle(item.genericpotato); + } + + protected override MyGenericStruct DeserializeItem(NetworkReader reader) + { + return new MyGenericStruct() { genericpotato = reader.ReadSingle() }; + } + }; +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListInheritance.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListInheritance.cs new file mode 100644 index 000000000..ffe60b59f --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListInheritance.cs @@ -0,0 +1,15 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListInheritance : NetworkBehaviour + { + readonly SuperSyncListString superSyncListString = new SuperSyncListString(); + } + + public class SuperSyncListString : SyncListString + { + + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtor.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtor.cs index 4847e5860..8c69509fc 100644 --- a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtor.cs +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtor.cs @@ -3,15 +3,15 @@ namespace MirrorTest { - class MirrorTestPlayer : NetworkBehaviour + class SyncListMissingParamlessCtor : NetworkBehaviour { - public class SyncListString2 : SyncList - { - public SyncListString2(int phooey) {} - protected override void SerializeItem(NetworkWriter w, string item) {} - protected override string DeserializeItem(NetworkReader r) => ""; - } - public SyncListString2 Foo; } + + public class SyncListString2 : SyncList + { + public SyncListString2(int phooey) {} + protected override void SerializeItem(NetworkWriter w, string item) {} + protected override string DeserializeItem(NetworkReader r) => ""; + } } diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtorManuallyInitialized.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtorManuallyInitialized.cs new file mode 100644 index 000000000..c1657114a --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListMissingParamlessCtorManuallyInitialized.cs @@ -0,0 +1,17 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListMissingParamlessCtorManuallyInitialized : NetworkBehaviour + { + public SyncListString2 Foo = new SyncListString2(20); + } + + public class SyncListString2 : SyncList + { + public SyncListString2(int phooey) {} + protected override void SerializeItem(NetworkWriter w, string item) {} + protected override string DeserializeItem(NetworkReader r) => ""; + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInAbstractClass.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInAbstractClass.cs new file mode 100644 index 000000000..ad48d94f3 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInAbstractClass.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListNestedStruct : NetworkBehaviour + { + SomeAbstractClass.MyNestedStructList Foo; + } + + public abstract class SomeAbstractClass + { + public struct MyNestedStruct + { + public int potato; + public float floatingpotato; + public double givemetwopotatoes; + } + public class MyNestedStructList : SyncList { } + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInAbstractClassWithInvalid.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInAbstractClassWithInvalid.cs new file mode 100644 index 000000000..8f5b6b09c --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInAbstractClassWithInvalid.cs @@ -0,0 +1,20 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListNestedStructWithInvalid : NetworkBehaviour + { + SomeAbstractClass.MyNestedStructList Foo; + } + + public abstract class SomeAbstractClass + { + public struct MyNestedStruct + { + public int potato; + public Object target; + } + public class MyNestedStructList : SyncList { } + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInStruct.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInStruct.cs new file mode 100644 index 000000000..810316294 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInStruct.cs @@ -0,0 +1,17 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListNestedStruct : NetworkBehaviour + { + SomeData.SyncList Foo; + } + + public struct SomeData + { + public int usefulNumber; + + public class SyncList : Mirror.SyncList { } + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInStructWithInvalid.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInStructWithInvalid.cs new file mode 100644 index 000000000..6226a3faf --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedInStructWithInvalid.cs @@ -0,0 +1,18 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListNestedInStructWithInvalid : NetworkBehaviour + { + SomeData.SyncList Foo; + } + + public struct SomeData + { + public int usefulNumber; + public Object target; + + public class SyncList : Mirror.SyncList { } + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructValid.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedStruct.cs similarity index 50% rename from Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructValid.cs rename to Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedStruct.cs index d43a7ccc1..262179cef 100644 --- a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructValid.cs +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListNestedStruct.cs @@ -3,15 +3,16 @@ namespace MirrorTest { - class MirrorTestPlayer : NetworkBehaviour + class SyncListNestedStruct : NetworkBehaviour { - struct MyStruct + MyNestedStructList Foo; + + struct MyNestedStruct { int potato; float floatingpotato; double givemetwopotatoes; } - class MyStructClass : SyncList {}; - MyStructClass Foo; + class MyNestedStructList : SyncList { } } } diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStruct.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStruct.cs new file mode 100644 index 000000000..4fa4c3093 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStruct.cs @@ -0,0 +1,17 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListStruct : NetworkBehaviour + { + MyStructList Foo; + } + struct MyStruct + { + int potato; + float floatingpotato; + double givemetwopotatoes; + } + class MyStructList : SyncList { } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomDeserializeOnly.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomDeserializeOnly.cs new file mode 100644 index 000000000..739126a7a --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomDeserializeOnly.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListStructWithCustomDeserializeOnly : NetworkBehaviour + { + MyStructList Foo; + } + struct MyStruct + { + int potato; + float floatingpotato; + double givemetwopotatoes; + } + class MyStructList : SyncList + { + protected override MyStruct DeserializeItem(NetworkReader reader) + { + return new MyStruct() { /* read some stuff here */ }; + } + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomMethods.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomMethods.cs new file mode 100644 index 000000000..0c352d27e --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomMethods.cs @@ -0,0 +1,28 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListStructWithCustomMethods : NetworkBehaviour + { + MyStructList Foo; + } + struct MyStruct + { + int potato; + float floatingpotato; + double givemetwopotatoes; + } + class MyStructList : SyncList + { + protected override void SerializeItem(NetworkWriter writer, MyStruct item) + { + // write some stuff here + } + + protected override MyStruct DeserializeItem(NetworkReader reader) + { + return new MyStruct() { /* read some stuff here */ }; + } + } +} diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomSerializeOnly.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomSerializeOnly.cs new file mode 100644 index 000000000..e08253877 --- /dev/null +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests~/SyncListStructWithCustomSerializeOnly.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using Mirror; + +namespace MirrorTest +{ + class SyncListStructWithCustomSerializeOnly : NetworkBehaviour + { + MyStructList Foo; + } + struct MyStruct + { + int potato; + float floatingpotato; + double givemetwopotatoes; + } + class MyStructList : SyncList + { + protected override void SerializeItem(NetworkWriter writer, MyStruct item) + { + // write some stuff here + } + } +}