From 1d05dfc952949d0c8708d9e5569738a9f9b54cba Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Mon, 12 Oct 2020 02:37:26 -0500 Subject: [PATCH] breaking: Users must initialize synclists (#391) (#2330) * Users must initialize syncobjects (#391) Previously we initialized syncobjects, so this is valid: ```cs public class Pepe : NetworkBehavior { public SyncList mylist; } ``` With this change, users must initialize their own fields: ```cs public class Pepe : NetworkBehavior { public SyncList mylist = new SyncList(); } ``` BREAKING CHANGE: You must initialize all your SyncLists * Add null check * This is no longer a weaver error * Update Assets/Mirror/Runtime/NetworkBehaviour.cs Co-authored-by: James Frowen * Remove unnecesary using Co-authored-by: James Frowen --- .../Processors/SyncObjectInitializer.cs | 47 ------------------- Assets/Mirror/Runtime/NetworkBehaviour.cs | 5 +- .../Editor/Weaver/WeaverSyncListTests.cs | 3 +- 3 files changed, 5 insertions(+), 50 deletions(-) diff --git a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs index f2e43e048..b404fc336 100644 --- a/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs +++ b/Assets/Mirror/Editor/Weaver/Processors/SyncObjectInitializer.cs @@ -1,4 +1,3 @@ -using System.Linq; using Mono.CecilX; using Mono.CecilX.Cil; @@ -8,56 +7,10 @@ public static class SyncObjectInitializer { public static void GenerateSyncObjectInitializer(ILProcessor worker, FieldDefinition fd) { - // call syncobject constructor - GenerateSyncObjectInstanceInitializer(worker, fd); - // register syncobject in network behaviour GenerateSyncObjectRegistration(worker, fd); } - // generates 'syncListInt = new SyncListInt()' if user didn't do that yet - static void GenerateSyncObjectInstanceInitializer(ILProcessor worker, FieldDefinition fd) - { - // check the ctor's instructions for an Stfld op-code for this specific sync list field. - foreach (Instruction ins in worker.Body.Instructions) - { - if (ins.OpCode.Code == Code.Stfld) - { - FieldDefinition field = (FieldDefinition)ins.Operand; - if (field.DeclaringType == fd.DeclaringType && field.Name == fd.Name) - { - // Already initialized by the user in the field definition, e.g: - // public SyncListInt Foo = new SyncListInt(); - return; - } - } - } - - // Not initialized by the user in the field definition, e.g: - // public SyncListInt Foo; - - TypeDefinition fieldType = fd.FieldType.Resolve(); - // find ctor with no parameters - MethodDefinition ctor = fieldType.Methods.FirstOrDefault(x => x.Name == ".ctor" && !x.HasParameters); - if (ctor == null) - { - Weaver.Error($"Can not initialize field {fd.Name} because no default constructor was found. Manually initialize the field (call the constructor) or add constructor without Parameter", fd); - return; - } - MethodReference objectConstructor = Weaver.CurrentAssembly.MainModule.ImportReference(ctor); - - // if is SyncList instead of SyncListInt then we need to make the ctor generic - if (fd.FieldType.IsGenericInstance) - { - GenericInstanceType genericInstance = (GenericInstanceType)fd.FieldType; - objectConstructor = objectConstructor.MakeHostInstanceGeneric(genericInstance); - } - - worker.Append(worker.Create(OpCodes.Ldarg_0)); - worker.Append(worker.Create(OpCodes.Newobj, objectConstructor)); - worker.Append(worker.Create(OpCodes.Stfld, fd)); - } - public static bool ImplementsSyncObject(TypeReference typeRef) { try diff --git a/Assets/Mirror/Runtime/NetworkBehaviour.cs b/Assets/Mirror/Runtime/NetworkBehaviour.cs index 2ad5586a4..424882e58 100644 --- a/Assets/Mirror/Runtime/NetworkBehaviour.cs +++ b/Assets/Mirror/Runtime/NetworkBehaviour.cs @@ -154,7 +154,10 @@ public int ComponentIndex // We collect all of them and we synchronize them with OnSerialize/OnDeserialize protected void InitSyncObject(SyncObject syncObject) { - syncObjects.Add(syncObject); + if (syncObject == null) + Debug.LogError("Uninitialized SyncObject. Manually call the constructor on your SyncList, SyncSet or SyncDictionary", this); + else + syncObjects.Add(syncObject); } #region Commands diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs index 85d1b0824..00a9f2f5a 100644 --- a/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs +++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverSyncListTests.cs @@ -43,8 +43,7 @@ public void SyncListInheritance() [Test] public void SyncListMissingParamlessCtor() { - HasError("Can not initialize field Foo because no default constructor was found. Manually initialize the field (call the constructor) or add constructor without Parameter", - "WeaverSyncListTests.SyncListMissingParamlessCtor.SyncListMissingParamlessCtor/SyncListString2 WeaverSyncListTests.SyncListMissingParamlessCtor.SyncListMissingParamlessCtor::Foo"); + IsSuccess(); } [Test]