diff --git a/Assets/Mirror/Editor/Weaver/Extensions.cs b/Assets/Mirror/Editor/Weaver/Extensions.cs
index ff21f9548..874224f3e 100644
--- a/Assets/Mirror/Editor/Weaver/Extensions.cs
+++ b/Assets/Mirror/Editor/Weaver/Extensions.cs
@@ -253,5 +253,46 @@ public static bool HasMethodInBaseType(this TypeDefinition td, string methodName
return false;
}
+
+ ///
+ /// Finds public fields in type and base type
+ ///
+ ///
+ ///
+ public static IEnumerable FindAllPublicFields(this TypeReference variable)
+ {
+ return FindAllPublicFields(variable.Resolve());
+ }
+
+ ///
+ /// Finds public fields in type and base type
+ ///
+ ///
+ ///
+ public static IEnumerable FindAllPublicFields(this TypeDefinition typeDefinition)
+ {
+ while (typeDefinition != null)
+ {
+ foreach (FieldDefinition field in typeDefinition.Fields)
+ {
+ if (field.IsStatic || field.IsPrivate)
+ continue;
+
+ if (field.IsNotSerialized)
+ continue;
+
+ yield return field;
+ }
+
+ try
+ {
+ typeDefinition = typeDefinition.BaseType.Resolve();
+ }
+ catch (System.Exception e)
+ {
+ break;
+ }
+ }
+ }
}
}
diff --git a/Assets/Mirror/Editor/Weaver/Readers.cs b/Assets/Mirror/Editor/Weaver/Readers.cs
index 6d186bef6..11b977bb9 100644
--- a/Assets/Mirror/Editor/Weaver/Readers.cs
+++ b/Assets/Mirror/Editor/Weaver/Readers.cs
@@ -332,7 +332,7 @@ static MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable
TypeDefinition td = variable.Resolve();
CreateNew(variable, worker, td);
- DeserializeFields(variable, recursionCount, worker);
+ ReadAllFields(variable, recursionCount, worker);
worker.Append(worker.Create(OpCodes.Ldloc_0));
worker.Append(worker.Create(OpCodes.Ret));
@@ -373,17 +373,11 @@ static void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition
}
}
- static void DeserializeFields(TypeReference variable, int recursionCount, ILProcessor worker)
+ static void ReadAllFields(TypeReference variable, int recursionCount, ILProcessor worker)
{
uint fields = 0;
- foreach (FieldDefinition field in variable.Resolve().Fields)
+ foreach (FieldDefinition field in variable.FindAllPublicFields())
{
- if (field.IsStatic || field.IsPrivate)
- continue;
-
- if (field.IsNotSerialized)
- continue;
-
// mismatched ldloca/ldloc for struct/class combinations is invalid IL, which causes crash at runtime
OpCode opcode = variable.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc;
worker.Append(worker.Create(opcode, 0));
@@ -403,6 +397,7 @@ static void DeserializeFields(TypeReference variable, int recursionCount, ILProc
worker.Append(worker.Create(OpCodes.Stfld, fieldRef));
fields++;
}
+
if (fields == 0)
{
Log.Warning($"{variable} has no public or non-static fields to deserialize");
diff --git a/Assets/Mirror/Editor/Weaver/Writers.cs b/Assets/Mirror/Editor/Weaver/Writers.cs
index cf7df3021..ece8b13c8 100644
--- a/Assets/Mirror/Editor/Weaver/Writers.cs
+++ b/Assets/Mirror/Editor/Weaver/Writers.cs
@@ -139,15 +139,25 @@ static MethodDefinition GenerateClassOrStructWriterFunction(TypeReference variab
ILProcessor worker = writerFunc.Body.GetILProcessor();
+ if (!WriteAllFields(variable, recursionCount, worker))
+ return null;
+
+ worker.Append(worker.Create(OpCodes.Ret));
+ return writerFunc;
+ }
+
+ ///
+ /// Fiends all fields in
+ ///
+ ///
+ ///
+ ///
+ /// false if fail
+ static bool WriteAllFields(TypeReference variable, int recursionCount, ILProcessor worker)
+ {
uint fields = 0;
- foreach (FieldDefinition field in variable.Resolve().Fields)
+ foreach (FieldDefinition field in variable.FindAllPublicFields())
{
- if (field.IsStatic || field.IsPrivate)
- continue;
-
- if (field.IsNotSerialized)
- continue;
-
MethodReference writeFunc = GetWriteFunc(field.FieldType, recursionCount + 1);
if (writeFunc != null)
{
@@ -162,20 +172,20 @@ static MethodDefinition GenerateClassOrStructWriterFunction(TypeReference variab
else
{
Weaver.Error($"{field.Name} has unsupported type. Use a type supported by Mirror instead", field);
- return null;
+ return false;
}
}
+
if (fields == 0)
{
- Log.Warning($" {variable} has no no public or non-static fields to serialize");
+ Log.Warning($"{variable} has no no public or non-static fields to serialize");
}
- worker.Append(worker.Create(OpCodes.Ret));
- return writerFunc;
+
+ return true;
}
static MethodDefinition GenerateArrayWriteFunc(TypeReference variable, int recursionCount)
{
-
if (!variable.IsArrayType())
{
Weaver.Error($"{variable.Name} is an unsupported type. Jagged and multidimensional arrays are not supported", variable);
diff --git a/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs
new file mode 100644
index 000000000..f72600ed0
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs
@@ -0,0 +1,53 @@
+using System;
+using Mirror.Tests.RemoteAttrributeTest;
+using NUnit.Framework;
+
+namespace Mirror.Tests.GeneratedWriterTests
+{
+ public class BaseData
+ {
+ public bool toggle;
+ }
+ public class SomeOtherData : BaseData
+ {
+ public int usefulNumber;
+ }
+
+ public class DataSenderBehaviour : NetworkBehaviour
+ {
+ public event Action onData;
+ [Command]
+ public void CmdSendData(SomeOtherData otherData)
+ {
+ onData?.Invoke(otherData);
+ }
+ }
+
+ public class FieldsInBaseClasses : RemoteTestBase
+ {
+ [Test]
+ public void WriterShouldIncludeFieldsInBaseClass()
+ {
+ DataSenderBehaviour hostBehaviour = CreateHostObject(true);
+
+ const bool toggle = true;
+ const int usefulNumber = 10;
+
+ int callCount = 0;
+ hostBehaviour.onData += data =>
+ {
+ callCount++;
+ Assert.That(data.usefulNumber, Is.EqualTo(usefulNumber));
+ Assert.That(data.toggle, Is.EqualTo(toggle));
+ };
+ hostBehaviour.CmdSendData(new SomeOtherData
+ {
+ usefulNumber = usefulNumber,
+ toggle = toggle
+ });
+
+ ProcessMessages();
+ Assert.That(callCount, Is.EqualTo(1));
+ }
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta
new file mode 100644
index 000000000..67a428572
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/FieldsInBaseClasses.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 518288ffe7c7215458a98466131fc7af
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Mirror/Tests/Editor/Weaver/.WeaverTests.csproj b/Assets/Mirror/Tests/Editor/Weaver/.WeaverTests.csproj
index 53394768a..31c9c8853 100644
--- a/Assets/Mirror/Tests/Editor/Weaver/.WeaverTests.csproj
+++ b/Assets/Mirror/Tests/Editor/Weaver/.WeaverTests.csproj
@@ -67,6 +67,7 @@
+
diff --git a/Assets/Mirror/Tests/Editor/Weaver/GeneratedReaderWriter~/CreatesForClassInherited.cs b/Assets/Mirror/Tests/Editor/Weaver/GeneratedReaderWriter~/CreatesForClassInherited.cs
new file mode 100644
index 000000000..81ad2cec1
--- /dev/null
+++ b/Assets/Mirror/Tests/Editor/Weaver/GeneratedReaderWriter~/CreatesForClassInherited.cs
@@ -0,0 +1,23 @@
+using Mirror;
+
+
+namespace GeneratedReaderWriter.CreatesForClassInherited
+{
+ public class CreatesForClassInherited : NetworkBehaviour
+ {
+ [ClientRpc]
+ public void RpcDoSomething(SomeOtherData data)
+ {
+ // empty
+ }
+ }
+
+ public class BaseData
+ {
+ public bool yes;
+ }
+ public class SomeOtherData : BaseData
+ {
+ public int usefulNumber;
+ }
+}
diff --git a/Assets/Mirror/Tests/Editor/Weaver/WeaverGeneratedReaderWriterTests.cs b/Assets/Mirror/Tests/Editor/Weaver/WeaverGeneratedReaderWriterTests.cs
index 184cef56f..8853c5fad 100644
--- a/Assets/Mirror/Tests/Editor/Weaver/WeaverGeneratedReaderWriterTests.cs
+++ b/Assets/Mirror/Tests/Editor/Weaver/WeaverGeneratedReaderWriterTests.cs
@@ -30,6 +30,12 @@ public void CreatesForClass()
Assert.That(weaverErrors, Is.Empty);
}
+ [Test]
+ public void CreatesForClassInherited()
+ {
+ Assert.That(weaverErrors, Is.Empty);
+ }
+
[Test]
public void CreatesForClassWithValidConstructor()
{