From 6ef8abe69f38d2f8f9ac5ccbe054a6b21bbb340b Mon Sep 17 00:00:00 2001 From: quabug Date: Mon, 28 Jun 2021 20:36:49 +0800 Subject: [PATCH 01/13] upgrade unity --- Packages/manifest.json | 6 +++--- Packages/packages-lock.json | 10 ++++++---- ProjectSettings/ProjectVersion.txt | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Packages/manifest.json b/Packages/manifest.json index 7299c19..62d2220 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,9 +1,9 @@ { "dependencies": { - "com.unity.ide.rider": "3.0.5", - "com.unity.ide.visualstudio": "2.0.7", + "com.unity.ide.rider": "3.0.7", + "com.unity.ide.visualstudio": "2.0.9", "com.unity.ide.vscode": "1.2.3", - "com.unity.test-framework": "1.1.24" + "com.unity.test-framework": "1.1.27" }, "scopedRegistries": [ { diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index fadb29f..c65f24a 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -16,14 +16,16 @@ "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.5", + "version": "3.0.7", "depth": 0, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.7", + "version": "2.0.9", "depth": 0, "source": "registry", "dependencies": { @@ -48,7 +50,7 @@ "url": "https://packages.unity.com" }, "com.unity.test-framework": { - "version": "1.1.24", + "version": "1.1.27", "depth": 0, "source": "registry", "dependencies": { diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 4db0bd0..79c71bc 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2020.3.0f1 -m_EditorVersionWithRevision: 2020.3.0f1 (c7b5465681fb) +m_EditorVersion: 2020.3.12f1 +m_EditorVersionWithRevision: 2020.3.12f1 (b3b2c6512326) From f7cc9c04d23fb70a45de4e647dcc1cebb74de57e Mon Sep 17 00:00:00 2001 From: quabug Date: Mon, 28 Jun 2021 20:36:58 +0800 Subject: [PATCH 02/13] fix scene --- Assets/Sample/Test.unity | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Assets/Sample/Test.unity b/Assets/Sample/Test.unity index fc49b1b..a5c10b7 100644 --- a/Assets/Sample/Test.unity +++ b/Assets/Sample/Test.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_IndirectSpecularColor: {r: 0.3731193, g: 0.38073996, b: 0.35872698, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -235,11 +235,7 @@ MonoBehaviour: m_EditorClassIdentifier: __Value: id: 0 - _serializedFoo: - id: 1 references: version: 1 00000000: type: {class: MyMonoBehavior/__generic_serialize_reference/MyIntObject, ns: , asm: GenericSerializeReference.Sample} - 00000001: - type: {class: MyMonoBehavior/__generic_serialize_reference/MyIntObject, ns: , asm: GenericSerializeReference.Sample} From e2a1bd3dec61b41db79d054ceeae5849b87fe9f6 Mon Sep 17 00:00:00 2001 From: quabug Date: Mon, 28 Jun 2021 20:45:33 +0800 Subject: [PATCH 03/13] structure of library sample --- .../GenericSerializeReference.Sample.asmdef | 2 +- Assets/Sample/Library.meta | 8 ++++++++ ...icSerializeReference.Sample.Library.asmdef | 17 +++++++++++++++++ ...ializeReference.Sample.Library.asmdef.meta | 7 +++++++ Assets/Sample/Library/Implement.meta | 8 ++++++++ ...eReference.Sample.Library.Implement.asmdef | 16 ++++++++++++++++ ...rence.Sample.Library.Implement.asmdef.meta | 7 +++++++ Assets/Sample/Library/Implement/Implement.cs | 2 ++ .../Library/Implement/Implement.cs.meta | 3 +++ Assets/Sample/Library/Interface.meta | 8 ++++++++ ...eReference.Sample.Library.Interface.asmdef | 14 ++++++++++++++ ...rence.Sample.Library.Interface.asmdef.meta | 7 +++++++ Assets/Sample/Library/Interface/Interface.cs | 1 + .../Library/Interface/Interface.cs.meta | 3 +++ Assets/Sample/Library/LibBehavior.cs | 7 +++++++ Assets/Sample/Library/LibBehavior.cs.meta | 11 +++++++++++ Assets/Sample/Test.unity | 19 +++++++++++++++++++ 17 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 Assets/Sample/Library.meta create mode 100644 Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef create mode 100644 Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef.meta create mode 100644 Assets/Sample/Library/Implement.meta create mode 100644 Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef create mode 100644 Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef.meta create mode 100644 Assets/Sample/Library/Implement/Implement.cs create mode 100644 Assets/Sample/Library/Implement/Implement.cs.meta create mode 100644 Assets/Sample/Library/Interface.meta create mode 100644 Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef create mode 100644 Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef.meta create mode 100644 Assets/Sample/Library/Interface/Interface.cs create mode 100644 Assets/Sample/Library/Interface/Interface.cs.meta create mode 100644 Assets/Sample/Library/LibBehavior.cs create mode 100644 Assets/Sample/Library/LibBehavior.cs.meta diff --git a/Assets/Sample/GenericSerializeReference.Sample.asmdef b/Assets/Sample/GenericSerializeReference.Sample.asmdef index f3ab22d..ec08cd8 100644 --- a/Assets/Sample/GenericSerializeReference.Sample.asmdef +++ b/Assets/Sample/GenericSerializeReference.Sample.asmdef @@ -3,7 +3,7 @@ "rootNamespace": "", "references": [ "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", - "GUID:7db2c3edd9cbf4a0c84e314cca3ddf42" + "GUID:36fd0010d4685b4408721d3172136183" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Sample/Library.meta b/Assets/Sample/Library.meta new file mode 100644 index 0000000..f40e97a --- /dev/null +++ b/Assets/Sample/Library.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1365f989be438cc4582240be1ec876d7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef new file mode 100644 index 0000000..8ae996e --- /dev/null +++ b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef @@ -0,0 +1,17 @@ +{ + "name": "GenericSerializeReference.Sample.Library", + "rootNamespace": "", + "references": [ + "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", + "GUID:bb7127c6ea4789d41b77cdef13d93652" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef.meta b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef.meta new file mode 100644 index 0000000..49ad1d0 --- /dev/null +++ b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b5701f8ff0277214388e4ff5f836be88 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Library/Implement.meta b/Assets/Sample/Library/Implement.meta new file mode 100644 index 0000000..3a6f91b --- /dev/null +++ b/Assets/Sample/Library/Implement.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9e8371a213f7444cae03c97a9ba85e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef b/Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef new file mode 100644 index 0000000..4c8784d --- /dev/null +++ b/Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef @@ -0,0 +1,16 @@ +{ + "name": "GenericSerializeReference.Sample.Library.Implement", + "rootNamespace": "", + "references": [ + "GUID:bb7127c6ea4789d41b77cdef13d93652" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef.meta b/Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef.meta new file mode 100644 index 0000000..fa348ee --- /dev/null +++ b/Assets/Sample/Library/Implement/GenericSerializeReference.Sample.Library.Implement.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 36fd0010d4685b4408721d3172136183 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Library/Implement/Implement.cs b/Assets/Sample/Library/Implement/Implement.cs new file mode 100644 index 0000000..fa77438 --- /dev/null +++ b/Assets/Sample/Library/Implement/Implement.cs @@ -0,0 +1,2 @@ +public class LibIntObject : ILibInterface {} +public class LibGenericObject : ILibInterface {} diff --git a/Assets/Sample/Library/Implement/Implement.cs.meta b/Assets/Sample/Library/Implement/Implement.cs.meta new file mode 100644 index 0000000..0c188bf --- /dev/null +++ b/Assets/Sample/Library/Implement/Implement.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2bbe89902cff4f4d9d5cda7b54fe71eb +timeCreated: 1624884126 \ No newline at end of file diff --git a/Assets/Sample/Library/Interface.meta b/Assets/Sample/Library/Interface.meta new file mode 100644 index 0000000..f5cb4b6 --- /dev/null +++ b/Assets/Sample/Library/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bdae992b0433a4146a6a29cc1d4368f0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef new file mode 100644 index 0000000..3903225 --- /dev/null +++ b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef @@ -0,0 +1,14 @@ +{ + "name": "GenericSerializeReference.Sample.Library.Interface", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef.meta b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef.meta new file mode 100644 index 0000000..d4922d2 --- /dev/null +++ b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bb7127c6ea4789d41b77cdef13d93652 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Library/Interface/Interface.cs b/Assets/Sample/Library/Interface/Interface.cs new file mode 100644 index 0000000..943fd81 --- /dev/null +++ b/Assets/Sample/Library/Interface/Interface.cs @@ -0,0 +1 @@ +public interface ILibInterface {} diff --git a/Assets/Sample/Library/Interface/Interface.cs.meta b/Assets/Sample/Library/Interface/Interface.cs.meta new file mode 100644 index 0000000..9dba9f5 --- /dev/null +++ b/Assets/Sample/Library/Interface/Interface.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9d48cc3c31964df1902d2fd8d233ee35 +timeCreated: 1624884110 \ No newline at end of file diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs new file mode 100644 index 0000000..54a4d61 --- /dev/null +++ b/Assets/Sample/Library/LibBehavior.cs @@ -0,0 +1,7 @@ +using GenericSerializeReference; +using UnityEngine; +public class LibBehavior : MonoBehaviour +{ + [GenericSerializeReference] + public ILibInterface Value { get; set; } +} diff --git a/Assets/Sample/Library/LibBehavior.cs.meta b/Assets/Sample/Library/LibBehavior.cs.meta new file mode 100644 index 0000000..fba8bd7 --- /dev/null +++ b/Assets/Sample/Library/LibBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66e141599402ff44f8de6aef9ccd07f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Sample/Test.unity b/Assets/Sample/Test.unity index a5c10b7..f179b7f 100644 --- a/Assets/Sample/Test.unity +++ b/Assets/Sample/Test.unity @@ -134,6 +134,7 @@ GameObject: - component: {fileID: 366887100} - component: {fileID: 366887099} - component: {fileID: 366887101} + - component: {fileID: 366887102} m_Layer: 0 m_Name: GameObject m_TagString: Untagged @@ -239,3 +240,21 @@ MonoBehaviour: version: 1 00000000: type: {class: MyMonoBehavior/__generic_serialize_reference/MyIntObject, ns: , asm: GenericSerializeReference.Sample} +--- !u!114 &366887102 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 366887098} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 66e141599402ff44f8de6aef9ccd07f2, type: 3} + m_Name: + m_EditorClassIdentifier: + __Value: + id: 0 + references: + version: 1 + 00000000: + type: {class: , ns: , asm: } From cd8f7797cea5b589079d332d68f1f2911ea626de Mon Sep 17 00:00:00 2001 From: quabug Date: Wed, 30 Jun 2021 13:11:17 +0800 Subject: [PATCH 04/13] able to generate interface only for `GenericSerializeReference` properties. --- Assets/Sample/Library/LibBehavior.cs | 2 +- .../GenericSerializeReferencePostProcessor.cs | 20 +++++++++++++++---- .../GenericSerializeReferenceAttribute.cs | 8 +++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs index 54a4d61..c2b450a 100644 --- a/Assets/Sample/Library/LibBehavior.cs +++ b/Assets/Sample/Library/LibBehavior.cs @@ -2,6 +2,6 @@ using UnityEngine; public class LibBehavior : MonoBehaviour { - [GenericSerializeReference] + [GenericSerializeReference(mode: GenericSerializeReferenceAttribute.Mode.Library)] public ILibInterface Value { get; set; } } diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index 6a08553..624ae93 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -83,9 +83,14 @@ from attribute in GetAttributesOf(property) continue; } - var serializedFieldInterface = CreateWrapperClass(property); + var wrapper = CreateWrapper(property); + var serializedFieldInterface = CreateInterface(wrapper); + + var mode = (GenericSerializeReferenceAttribute.Mode)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.MODE_INDEX].Value; + if (mode == GenericSerializeReferenceAttribute.Mode.Game) CreateDerivedClasses(property, wrapper, serializedFieldInterface); + logger.Info($"generate nested class with interface {serializedFieldInterface.FullName}"); - var fieldNamePrefix = (string)attribute.ConstructorArguments[0].Value; + var fieldNamePrefix = (string)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.PREFIX_INDEX].Value; var serializedField = CreateSerializeReferenceField(property, serializedFieldInterface, fieldNamePrefix); InjectGetter(property, serializedField); InjectSetter(property, serializedField); @@ -161,7 +166,7 @@ CustomAttribute CreateCustomAttribute(params Type[] constructorTypes) where T return new CustomAttribute(module.ImportReference(typeof(T).GetConstructor(constructorTypes))); } - TypeDefinition/*interface*/ CreateWrapperClass(PropertyDefinition property) + TypeDefinition CreateWrapper(PropertyDefinition property) { // .class nested public abstract sealed auto ansi beforefieldinit // <$PropertyName>__generic_serialize_reference @@ -174,7 +179,11 @@ CustomAttribute CreateCustomAttribute(params Type[] constructorTypes) where T var wrapper = new TypeDefinition("", $"<{property.Name}>__generic_serialize_reference", typeAttributes); wrapper.BaseType = property.Module.ImportReference(typeof(System.Object)); property.DeclaringType.NestedTypes.Add(wrapper); + return wrapper; + } + TypeDefinition CreateInterface(TypeDefinition wrapper) + { // .class interface nested public abstract auto ansi var interfaceAttributes = TypeAttributes.Class | TypeAttributes.Interface | @@ -182,14 +191,17 @@ CustomAttribute CreateCustomAttribute(params Type[] constructorTypes) where T TypeAttributes.Abstract; var baseInterface = new TypeDefinition("", "IBase", interfaceAttributes); wrapper.NestedTypes.Add(baseInterface); + return baseInterface; + } + void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, TypeDefinition baseInterface) + { logger.Debug($"get derived {property.PropertyType.Module} {property.PropertyType} {property.PropertyType.Resolve()}"); var propertyTypeDefinition = property.PropertyType.Resolve(); var derivedTypes = typeTree.GetDirectDerived(propertyTypeDefinition); // TODO: should avoid recursive process with side effect? // return an enumerable of type reference with info to generate? foreach (var derivedDef in derivedTypes) RecursiveProcess(derivedDef, property.PropertyType); - return baseInterface; void RecursiveProcess(TypeDefinition type, TypeReference baseType) { diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs index bf66999..d603b70 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs @@ -5,8 +5,10 @@ namespace GenericSerializeReference [AttributeUsage(AttributeTargets.Property)] public class GenericSerializeReferenceAttribute : Attribute { - public string SerializedFieldPrefix { get; } - public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__") => - SerializedFieldPrefix = serializedFieldPrefix; + public enum Mode { Game, Library } + public const int PREFIX_INDEX = 0; + public const int MODE_INDEX = 1; + public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", Mode mode = Mode.Game) => + (_, _) = (serializedFieldPrefix, mode); } } \ No newline at end of file From 8f2e3f776763d368f6ef6903349893dda8cc40e4 Mon Sep 17 00:00:00 2001 From: quabug Date: Thu, 1 Jul 2021 23:34:23 +0800 Subject: [PATCH 05/13] interface only mode --- .gitignore | 2 + ...icSerializeReference.Sample.Library.asmdef | 8 +++- Assets/Sample/Library/LibBehavior.cs | 2 +- Assets/Sample/Test.unity | 10 ++-- .../GenericSerializeReferencePostProcessor.cs | 46 ++++++++++++++----- ...y.GenericSerializeReference.CodeGen.asmdef | 8 +++- .../Runtime/GenericSerializeReference.asmdef | 8 +++- .../GenericSerializeReferenceAttribute.cs | 9 ++-- ...rializeReferenceGeneratedFieldAttribute.cs | 6 ++- .../Tests~/Test.cs | 24 ---------- .../Tests~/Test.cs.meta | 3 -- .../Tests~/TestTypeTree.cs | 2 - 12 files changed, 73 insertions(+), 55 deletions(-) delete mode 100644 Packages/generic-serialize-reference/Tests~/Test.cs delete mode 100644 Packages/generic-serialize-reference/Tests~/Test.cs.meta diff --git a/.gitignore b/.gitignore index 9a9ec55..c580ab8 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,5 @@ Assets/Plugins/Animancer/Examples.meta # OS .DS_Store .vsconfig +Packages/generic-serialize-reference/Test +Packages/generic-serialize-reference/Test.meta diff --git a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef index 8ae996e..56a43a1 100644 --- a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef +++ b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef @@ -12,6 +12,12 @@ "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "Select...", + "expression": "", + "define": "" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs index c2b450a..c42d6f6 100644 --- a/Assets/Sample/Library/LibBehavior.cs +++ b/Assets/Sample/Library/LibBehavior.cs @@ -2,6 +2,6 @@ using UnityEngine; public class LibBehavior : MonoBehaviour { - [GenericSerializeReference(mode: GenericSerializeReferenceAttribute.Mode.Library)] + [GenericSerializeReference(mode: GenericSerializeReferenceAttribute.Mode.InterfaceOnly)] public ILibInterface Value { get; set; } } diff --git a/Assets/Sample/Test.unity b/Assets/Sample/Test.unity index f179b7f..b6653a7 100644 --- a/Assets/Sample/Test.unity +++ b/Assets/Sample/Test.unity @@ -175,12 +175,11 @@ MonoBehaviour: data: V: 0 00000001: - type: {class: TestMonoBehavior/__generic_serialize_reference/SubObject, ns: GenericSerializeReference.Sample, asm: GenericSerializeReference.Sample} + type: {class: TestMonoBehavior/__generic_serialize_reference/PartialObject, ns: GenericSerializeReference.Sample, asm: GenericSerializeReference.Sample} data: ValueT: 0 ValueU: 0 - SubValueT: [] - SubValueU: + ValueDouble: 0 00000002: type: {class: TestMonoBehavior/__generic_serialize_reference/PartialObject, ns: GenericSerializeReference.Sample, asm: GenericSerializeReference.Sample} data: @@ -192,10 +191,9 @@ MonoBehaviour: data: Value: 0 00000004: - type: {class: TestMonoBehavior/__generic_serialize_reference/SubObject, ns: GenericSerializeReference.Sample, asm: GenericSerializeReference.Sample} + type: {class: TestMonoBehavior/__generic_serialize_reference/DoubleObject, ns: GenericSerializeReference.Sample, asm: GenericSerializeReference.Sample} data: Value: 0 - SubValue: [] 00000005: type: {class: TestMonoBehavior/__generic_serialize_reference/SubObject, ns: GenericSerializeReference.Sample, asm: GenericSerializeReference.Sample} data: @@ -239,7 +237,7 @@ MonoBehaviour: references: version: 1 00000000: - type: {class: MyMonoBehavior/__generic_serialize_reference/MyIntObject, ns: , asm: GenericSerializeReference.Sample} + type: {class: MyMonoBehavior/__generic_serialize_reference/MyGenericObject, ns: , asm: GenericSerializeReference.Sample} --- !u!114 &366887102 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index 624ae93..c224194 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -83,15 +83,27 @@ from attribute in GetAttributesOf(property) continue; } - var wrapper = CreateWrapper(property); - var serializedFieldInterface = CreateInterface(wrapper); - var mode = (GenericSerializeReferenceAttribute.Mode)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.MODE_INDEX].Value; - if (mode == GenericSerializeReferenceAttribute.Mode.Game) CreateDerivedClasses(property, wrapper, serializedFieldInterface); + var isInterfaceOnly = mode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly; + + TypeDefinition serializedFieldInterface; + if (isInterfaceOnly) + { + serializedFieldInterface = CreateInterface(property.DeclaringType, $"<{property.Name}>__IBase"); + } + else + { + var wrapper = CreateWrapper(property); + serializedFieldInterface = CreateInterface(wrapper); + CreateDerivedClasses(property, wrapper, serializedFieldInterface); + } logger.Info($"generate nested class with interface {serializedFieldInterface.FullName}"); var fieldNamePrefix = (string)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.PREFIX_INDEX].Value; - var serializedField = CreateSerializeReferenceField(property, serializedFieldInterface, fieldNamePrefix); + var serializedField = CreateSerializeReferenceField(property, serializedFieldInterface, fieldNamePrefix, mode); + if (isInterfaceOnly) + { + } InjectGetter(property, serializedField); InjectSetter(property, serializedField); modified = true; @@ -141,7 +153,12 @@ void InjectSetter(PropertyDefinition property, FieldDefinition serializedField) instructions.Insert(retIndex + 2, Instruction.Create(OpCodes.Stfld, serializedField)); } - FieldDefinition CreateSerializeReferenceField(PropertyDefinition property, TypeReference @interface, string namePrefix) + FieldDefinition CreateSerializeReferenceField( + PropertyDefinition property + , TypeReference @interface + , string namePrefix + , GenericSerializeReferenceAttribute.Mode mode + ) { //.field private class GenericSerializeReference.Tests.TestMonoBehavior/__generic_serialize_reference_GenericInterface__/IBase _GenericInterface // .custom instance void [UnityEngine.CoreModule]UnityEngine.SerializeReference::.ctor() @@ -151,11 +168,16 @@ FieldDefinition CreateSerializeReferenceField(PropertyDefinition property, TypeR , FieldAttributes.Private , @interface ); + serializedField.CustomAttributes.Add(CreateCustomAttribute()); - serializedField.CustomAttributes.Add(CreateCustomAttribute()); - // var backingField = property.DeclaringType.Fields.First(field => field.Name == $"<{property.Name}>k__BackingField"); - // foreach (var customAttribute in backingField.CustomAttributes) - // serializedField.CustomAttributes.Add(customAttribute); + + var attribute = CreateCustomAttribute( + typeof(GenericSerializeReferenceAttribute.Mode) + ); + var modeTypeDef = module.ImportReference(typeof(GenericSerializeReferenceAttribute.Mode)); + attribute.ConstructorArguments.Add(new CustomAttributeArgument(modeTypeDef, mode)); + serializedField.CustomAttributes.Add(attribute); + property.DeclaringType.Fields.Add(serializedField); logger.Debug($"add field into {property.DeclaringType.FullName}"); return serializedField; @@ -182,14 +204,14 @@ TypeDefinition CreateWrapper(PropertyDefinition property) return wrapper; } - TypeDefinition CreateInterface(TypeDefinition wrapper) + TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "IBase") { // .class interface nested public abstract auto ansi var interfaceAttributes = TypeAttributes.Class | TypeAttributes.Interface | TypeAttributes.NestedPublic | TypeAttributes.Abstract; - var baseInterface = new TypeDefinition("", "IBase", interfaceAttributes); + var baseInterface = new TypeDefinition("", interfaceName, interfaceAttributes); wrapper.NestedTypes.Add(baseInterface); return baseInterface; } diff --git a/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef b/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef index 081d39f..5e074ac 100644 --- a/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef +++ b/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef @@ -18,6 +18,12 @@ ], "autoReferenced": false, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "com.quabug.generic-serialize-reference-library-codegen", + "expression": "0.1.0", + "define": "ENABLE_LIBRARY_CODEGEN" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef b/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef index 5316e9c..bccb06c 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef @@ -9,6 +9,12 @@ "precompiledReferences": [], "autoReferenced": false, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "com.quabug.generic-serialize-reference-library-codegen", + "expression": "0.1.0", + "define": "ENABLE_LIBRARY_CODEGEN" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs index d603b70..ca0923a 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs @@ -5,10 +5,13 @@ namespace GenericSerializeReference [AttributeUsage(AttributeTargets.Property)] public class GenericSerializeReferenceAttribute : Attribute { - public enum Mode { Game, Library } public const int PREFIX_INDEX = 0; public const int MODE_INDEX = 1; - public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", Mode mode = Mode.Game) => - (_, _) = (serializedFieldPrefix, mode); + + public enum Mode { EmbedClasses, InterfaceOnly } + public Mode GenerateMode { get; } + + public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", Mode mode = Mode.EmbedClasses) => + GenerateMode = mode; } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs index e70312b..831b9df 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs @@ -7,5 +7,9 @@ namespace GenericSerializeReference { [AttributeUsage(AttributeTargets.Field)] - internal class GenericSerializeReferenceGeneratedFieldAttribute : PropertyAttribute {} + internal class GenericSerializeReferenceGeneratedFieldAttribute : PropertyAttribute + { + public GenericSerializeReferenceAttribute.Mode Mode { get; } + public GenericSerializeReferenceGeneratedFieldAttribute(GenericSerializeReferenceAttribute.Mode mode) => Mode = mode; + } } diff --git a/Packages/generic-serialize-reference/Tests~/Test.cs b/Packages/generic-serialize-reference/Tests~/Test.cs deleted file mode 100644 index 3cf8ac8..0000000 --- a/Packages/generic-serialize-reference/Tests~/Test.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NUnit.Framework; - -namespace GenericSerializeReference.Tests -{ - public class A - { - [GenericSerializeReference] public SingleGeneric.IInterface Value { get; set; } - } - - public class Test - { - interface IBase {} - class MultipleGenericObject : MultipleGeneric.Object, IBase {} - - [Test] - public void t() - { - IBase value = null; - // var value = (new MultipleGenericObject()); - var obj = (MultipleGeneric.Object)value; - // var value = (MultipleGenericObject) obj; - } - } -} \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Tests~/Test.cs.meta b/Packages/generic-serialize-reference/Tests~/Test.cs.meta deleted file mode 100644 index 0d96857..0000000 --- a/Packages/generic-serialize-reference/Tests~/Test.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: cb6442db98ce4eee95659bc9970a637b -timeCreated: 1615127797 \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs b/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs index 8e5230b..39fbf26 100644 --- a/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs +++ b/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs @@ -8,7 +8,6 @@ namespace GenericSerializeReference.Tests public class TestTypeTree : CecilTestBase { private TypeTree _tree; - private ModuleDefinition _module; interface IGeneric {} class TInt : IGeneric {} @@ -20,7 +19,6 @@ class TIntSub : TInt {} protected override void OnSetUp() { - _module = _assemblyDefinition.MainModule; _tree = new TypeTree(_module.GetTypes()); } From 0bed18508c124ee36d445e1e16b8024b3c5e264f Mon Sep 17 00:00:00 2001 From: quabug Date: Thu, 1 Jul 2021 23:37:51 +0800 Subject: [PATCH 06/13] remove useless version define from assemblies. --- .../GenericSerializeReference.Sample.Library.asmdef | 8 +------- .../Editor/Unity.GenericSerializeReference.CodeGen.asmdef | 8 +------- .../Runtime/GenericSerializeReference.asmdef | 8 +------- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef index 56a43a1..8ae996e 100644 --- a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef +++ b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef @@ -12,12 +12,6 @@ "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [ - { - "name": "Select...", - "expression": "", - "define": "" - } - ], + "versionDefines": [], "noEngineReferences": false } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef b/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef index 5e074ac..081d39f 100644 --- a/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef +++ b/Packages/generic-serialize-reference/Editor/Unity.GenericSerializeReference.CodeGen.asmdef @@ -18,12 +18,6 @@ ], "autoReferenced": false, "defineConstraints": [], - "versionDefines": [ - { - "name": "com.quabug.generic-serialize-reference-library-codegen", - "expression": "0.1.0", - "define": "ENABLE_LIBRARY_CODEGEN" - } - ], + "versionDefines": [], "noEngineReferences": false } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef b/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef index bccb06c..5316e9c 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReference.asmdef @@ -9,12 +9,6 @@ "precompiledReferences": [], "autoReferenced": false, "defineConstraints": [], - "versionDefines": [ - { - "name": "com.quabug.generic-serialize-reference-library-codegen", - "expression": "0.1.0", - "define": "ENABLE_LIBRARY_CODEGEN" - } - ], + "versionDefines": [], "noEngineReferences": false } \ No newline at end of file From dc800baa460825f1713ac35950aa31878116daea Mon Sep 17 00:00:00 2001 From: quabug Date: Fri, 2 Jul 2021 20:18:52 +0800 Subject: [PATCH 07/13] expose useful method for sharing with library gen. --- .../Editor/Extensions.cs | 52 ++++++++- .../GenericSerializeReferencePostProcessor.cs | 104 +++--------------- .../Editor/TypeTree.cs | 33 ++++++ .../GenericSerializeReferenceAttribute.cs | 8 +- ...rializeReferenceGeneratedFieldAttribute.cs | 7 +- .../Tests~/TestTypeTree.cs | 30 +++-- .../generic-serialize-reference/package.json | 4 +- 7 files changed, 126 insertions(+), 112 deletions(-) diff --git a/Packages/generic-serialize-reference/Editor/Extensions.cs b/Packages/generic-serialize-reference/Editor/Extensions.cs index 777d6a9..9f7a767 100644 --- a/Packages/generic-serialize-reference/Editor/Extensions.cs +++ b/Packages/generic-serialize-reference/Editor/Extensions.cs @@ -36,12 +36,6 @@ public static string ToReadableName(this Type type) internal static class CecilExtension { - public static TypeDefinition ToTypeDefinition(this ModuleDefinition module) => - module.ToTypeDefinition(typeof(T)); - - public static TypeDefinition ToTypeDefinition(this ModuleDefinition module, Type type) => - module.ImportReference(type).Resolve(); - public static string ToReadableName(this TypeReference type) { if (!type.IsGenericInstance) return type.Name; @@ -160,5 +154,51 @@ public static IEnumerable GetSelfAndAllDeclaringTypes(this TypeD type = type.DeclaringType; } } + + public static CustomAttribute AddCustomAttribute( + this ICustomAttributeProvider attributeProvider + , ModuleDefinition module + , params Type[] constructorTypes + ) where T : Attribute + { + var attribute = new CustomAttribute(module.ImportReference(typeof(T).GetConstructor(constructorTypes))); + attributeProvider.CustomAttributes.Add(attribute); + return attribute; + } + + public static TypeDefinition GenerateDerivedClass(this TypeReference baseType, IEnumerable genericArguments, string className) + { + // .class nested public auto ansi beforefieldinit + // Object + // extends class [GenericSerializeReference.Tests]GenericSerializeReference.Tests.MultipleGeneric/Object`2 + // implements GenericSerializeReference.Tests.TestMonoBehavior/IBase + // { + + // .method public hidebysig specialname rtspecialname instance void + // .ctor() cil managed + // { + // .maxstack 8 + + // IL_0000: ldarg.0 // this + // IL_0001: call instance void class [GenericSerializeReference.Tests]GenericSerializeReference.Tests.MultipleGeneric/Object`2::.ctor() + // IL_0006: nop + // IL_0007: ret + + // } // end of method Object::.ctor + // } // end of class Object + var classAttributes = TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.BeforeFieldInit; + var type = new TypeDefinition("", className, classAttributes); + type.BaseType = baseType.HasGenericParameters ? baseType.MakeGenericInstanceType(genericArguments.ToArray()) : baseType; + var ctor = baseType.Resolve().GetConstructors().First(c => !c.HasParameters); + var ctorCall = new MethodReference(ctor.Name, baseType.Module.ImportReference(ctor.ReturnType)) + { + DeclaringType = type.BaseType, + HasThis = ctor.HasThis, + ExplicitThis = ctor.ExplicitThis, + CallingConvention = ctor.CallingConvention, + }; + type.AddEmptyCtor(ctorCall); + return type; + } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index c224194..1dbb246 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -83,6 +83,12 @@ from attribute in GetAttributesOf(property) continue; } + if (!property.PropertyType.IsGenericInstance) + { + logger.Warning($"Cannot process on property {property} with non-generic type {property.PropertyType.Name}"); + continue; + } + var mode = (GenericSerializeReferenceAttribute.Mode)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.MODE_INDEX].Value; var isInterfaceOnly = mode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly; @@ -168,26 +174,13 @@ PropertyDefinition property , FieldAttributes.Private , @interface ); - - serializedField.CustomAttributes.Add(CreateCustomAttribute()); - - var attribute = CreateCustomAttribute( - typeof(GenericSerializeReferenceAttribute.Mode) - ); - var modeTypeDef = module.ImportReference(typeof(GenericSerializeReferenceAttribute.Mode)); - attribute.ConstructorArguments.Add(new CustomAttributeArgument(modeTypeDef, mode)); - serializedField.CustomAttributes.Add(attribute); - + serializedField.AddCustomAttribute(module); + serializedField.AddCustomAttribute(module); property.DeclaringType.Fields.Add(serializedField); logger.Debug($"add field into {property.DeclaringType.FullName}"); return serializedField; } - CustomAttribute CreateCustomAttribute(params Type[] constructorTypes) where T : Attribute - { - return new CustomAttribute(module.ImportReference(typeof(T).GetConstructor(constructorTypes))); - } - TypeDefinition CreateWrapper(PropertyDefinition property) { // .class nested public abstract sealed auto ansi beforefieldinit @@ -219,91 +212,28 @@ TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "I void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, TypeDefinition baseInterface) { logger.Debug($"get derived {property.PropertyType.Module} {property.PropertyType} {property.PropertyType.Resolve()}"); - var propertyTypeDefinition = property.PropertyType.Resolve(); - var derivedTypes = typeTree.GetDirectDerived(propertyTypeDefinition); - // TODO: should avoid recursive process with side effect? - // return an enumerable of type reference with info to generate? - foreach (var derivedDef in derivedTypes) RecursiveProcess(derivedDef, property.PropertyType); - - void RecursiveProcess(TypeDefinition type, TypeReference baseType) + foreach (var derived in typeTree.GetAllDerived(property.PropertyType)) { - logger.Info($"create {type}({type.Module.Name}) : {baseType.ToReadableName()}"); - if (!type.IsPublicOrNestedPublic()) return; - var baseCtor = type.GetConstructors().FirstOrDefault(ctor => !ctor.HasParameters); - if (baseCtor == null) return; - - var typeReference = module.ImportReference(type); - IReadOnlyList genericArguments = Array.Empty(); - try - { - genericArguments = type.ResolveGenericArguments(baseType); - } - catch (Exception ex) - { - logger.Debug($"cannot resolve {typeReference.ToReadableName()} : {baseType.ToReadableName()}: {ex}"); - return; - } + var genericArguments = derived.IsGenericInstance + ? ((GenericInstanceType) derived).GenericArguments + : (IEnumerable)Array.Empty() + ; - logger.Debug($"resolve generic arguments: {string.Join(",", genericArguments.Select(a => a.Name))}"); if (genericArguments.All(arg => !arg.IsGenericParameter)) { - - var className = typeReference.Name.Split('`')[0]; + var className = derived.Name.Split('`')[0]; if (wrapper.NestedTypes.Any(t => t.Name == className)) - className = typeReference.Resolve().NameWithOuterClasses(); + className = derived.Resolve().NameWithOuterClasses(); // TODO: should handle if the className is still the same with any of existing type. if (wrapper.NestedTypes.Any(t => t.Name == className)) logger.Warning($"Overwrite type with same name {className}"); - var generated = GenerateDerivedClass(typeReference, genericArguments, className); - logger.Debug($"generate {generated.ToReadableName()} : {baseType.ToReadableName()}"); + var generated = derived.GenerateDerivedClass(genericArguments, className); + logger.Debug($"generate {generated.ToReadableName()}"); generated.Interfaces.Add(new InterfaceImplementation(baseInterface)); wrapper.NestedTypes.Add(generated); } - - baseType = type.HasGenericParameters - ? (TypeReference) type.MakeGenericInstanceType(genericArguments.ToArray()) - : type - ; - logger.Debug($"baseType = {baseType}"); - var derivedTypes = typeTree.GetDirectDerived(type); - foreach (var derivedDef in derivedTypes) RecursiveProcess(derivedDef, baseType); } } - - TypeDefinition GenerateDerivedClass(TypeReference baseType, IReadOnlyList genericArguments, string className) - { - // .class nested public auto ansi beforefieldinit - // Object - // extends class [GenericSerializeReference.Tests]GenericSerializeReference.Tests.MultipleGeneric/Object`2 - // implements GenericSerializeReference.Tests.TestMonoBehavior/IBase - // { - - // .method public hidebysig specialname rtspecialname instance void - // .ctor() cil managed - // { - // .maxstack 8 - - // IL_0000: ldarg.0 // this - // IL_0001: call instance void class [GenericSerializeReference.Tests]GenericSerializeReference.Tests.MultipleGeneric/Object`2::.ctor() - // IL_0006: nop - // IL_0007: ret - - // } // end of method Object::.ctor - // } // end of class Object - var classAttributes = TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.BeforeFieldInit; - var type = new TypeDefinition("", className, classAttributes); - type.BaseType = baseType.HasGenericParameters ? baseType.MakeGenericInstanceType(genericArguments.ToArray()) : baseType; - var ctor = baseType.Resolve().GetConstructors().First(c => !c.HasParameters); - var ctorCall = new MethodReference(ctor.Name, module.ImportReference(ctor.ReturnType)) - { - DeclaringType = type.BaseType, - HasThis = ctor.HasThis, - ExplicitThis = ctor.ExplicitThis, - CallingConvention = ctor.CallingConvention, - }; - type.AddEmptyCtor(ctorCall); - return type; - } } private static (AssemblyDefinition compiled, AssemblyDefinition[] references) diff --git a/Packages/generic-serialize-reference/Editor/TypeTree.cs b/Packages/generic-serialize-reference/Editor/TypeTree.cs index 2f31ec3..d05bd4f 100644 --- a/Packages/generic-serialize-reference/Editor/TypeTree.cs +++ b/Packages/generic-serialize-reference/Editor/TypeTree.cs @@ -4,6 +4,7 @@ using System.Text; using JetBrains.Annotations; using Mono.Cecil; +using Mono.Cecil.Rocks; namespace GenericSerializeReference { @@ -149,6 +150,38 @@ public IEnumerable GetDirectDerived(TypeDefinition baseType) return node.Subs.Select(sub => sub.Type); } + public IEnumerable GetAllDerived(TypeReference rootType, bool publicOnly = true) + { + return GetDirectDerived(rootType.Resolve()).SelectMany(t => RecursiveProcess(t, rootType)); + + IEnumerable RecursiveProcess(TypeDefinition type, TypeReference baseType) + { + if (publicOnly && !type.IsPublicOrNestedPublic()) return Enumerable.Empty(); + var baseCtor = type.GetConstructors().FirstOrDefault(ctor => !ctor.HasParameters); + if (baseCtor == null) return Enumerable.Empty(); + + IReadOnlyList genericArguments = Array.Empty(); + try + { + genericArguments = type.ResolveGenericArguments(baseType); + } + catch + { + // logger.Debug($"cannot resolve {typeReference.ToReadableName()} : {baseType.ToReadableName()}: {ex}"); + return Enumerable.Empty(); + } + + baseType = type.HasGenericParameters + ? (TypeReference) type.MakeGenericInstanceType(genericArguments.ToArray()) + : type + ; + + return baseType.Yield().Concat( + GetDirectDerived(type).SelectMany(t => RecursiveProcess(t, baseType)) + ); + } + } + public override string ToString() { var builder = new StringBuilder(); diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs index ca0923a..a57bb1f 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs @@ -7,11 +7,15 @@ public class GenericSerializeReferenceAttribute : Attribute { public const int PREFIX_INDEX = 0; public const int MODE_INDEX = 1; - public enum Mode { EmbedClasses, InterfaceOnly } + + public string SerializedFieldPrefix { get; } public Mode GenerateMode { get; } - public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", Mode mode = Mode.EmbedClasses) => + public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", Mode mode = Mode.EmbedClasses) + { + SerializedFieldPrefix = serializedFieldPrefix; GenerateMode = mode; + } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs index 831b9df..b8a9806 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs @@ -3,13 +3,10 @@ using UnityEngine; [assembly: InternalsVisibleTo("Unity."+nameof(GenericSerializeReference)+".CodeGen")] +[assembly: InternalsVisibleTo("GenericSerializeReference.Library.Editor")] namespace GenericSerializeReference { [AttributeUsage(AttributeTargets.Field)] - internal class GenericSerializeReferenceGeneratedFieldAttribute : PropertyAttribute - { - public GenericSerializeReferenceAttribute.Mode Mode { get; } - public GenericSerializeReferenceGeneratedFieldAttribute(GenericSerializeReferenceAttribute.Mode mode) => Mode = mode; - } + internal class GenericSerializeReferenceGeneratedFieldAttribute : PropertyAttribute {} } diff --git a/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs b/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs index 39fbf26..7a126e6 100644 --- a/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs +++ b/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs @@ -25,13 +25,19 @@ protected override void OnSetUp() [Test] public void should_get_derived_from_generic_interface() { - CheckDerived(typeof(IGeneric<,>), typeof(TInt<>), typeof(IntU<>), typeof(IntInt), typeof(TFloat<>), typeof(AnotherTFloat<>), typeof(TIntSub)); + CheckDerivedIgnoreGenericParameters(typeof(IGeneric<,>), typeof(TInt<>), typeof(IntU<>), typeof(IntInt), typeof(TFloat<>), typeof(AnotherTFloat<>), typeof(TIntSub)); } [Test] - public void should_get_derived_from_generic_interface_without_type_constraint() + public void should_get_derived_from_generic_interface_by_ignoring_generic_parameters() { - CheckDerived(typeof(IGeneric), typeof(TInt), typeof(IntU), typeof(IntInt), typeof(TFloat), typeof(AnotherTFloat), typeof(TIntSub)); + CheckDerivedIgnoreGenericParameters(typeof(IGeneric), typeof(TInt), typeof(IntU), typeof(IntInt), typeof(TFloat), typeof(AnotherTFloat), typeof(TIntSub)); + } + + [Test] + public void should_get_derived_from_concrete_generic_interface() + { + CheckDerived(typeof(IGeneric), typeof(TInt), typeof(IntU), typeof(IntInt), typeof(TIntSub)); } interface I {} @@ -116,18 +122,22 @@ public void should_get_derived_from_interface() void CheckDerived(Type @base, params Type[] types) { - var tokens = _tree - .GetAllDerived(_module.ToTypeDefinition(@base)) - .Select(type => type.MetadataToken) + var derivedTypes = _tree + .GetAllDerived(_module.ImportReference(@base), publicOnly: false) + .Select(type => type.FullName) .ToArray() ; - IsTokensContains(tokens, types); + Assert.That(derivedTypes, Is.EquivalentTo(types.Select(type => _module.ImportReference(type).FullName))); } - void IsTokensContains(MetadataToken[] tokens, params Type[] types) + void CheckDerivedIgnoreGenericParameters(Type @base, params Type[] types) { - Assert.AreEqual(types.Length, tokens.Length); - foreach (var type in types) Assert.Contains(_module.ToTypeDefinition(type).MetadataToken, tokens); + var tokens = _tree + .GetAllDerived(_module.ImportReference(@base).Resolve()) + .Select(type => type.MetadataToken) + .ToArray() + ; + Assert.That(tokens, Is.EquivalentTo(types.Select(type => _module.ImportReference(type).Resolve().MetadataToken))); } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/package.json b/Packages/generic-serialize-reference/package.json index 8fa3ba2..d777052 100644 --- a/Packages/generic-serialize-reference/package.json +++ b/Packages/generic-serialize-reference/package.json @@ -1,7 +1,7 @@ { "name": "com.quabug.generic-serialize-reference", "description": "Automatically alter generic field of SerializeReference into its non-generic form", - "version": "1.1.1", + "version": "1.2.0", "unity": "2020.2", "displayName": "GenericSerializeReference", "samples": [ @@ -15,4 +15,4 @@ "com.unity.nuget.mono-cecil": "0.1.6-preview.2" }, "type": "library" -} +} \ No newline at end of file From 57e3df92f8abd786e3c72bdde1f7a81c512b250f Mon Sep 17 00:00:00 2001 From: quabug Date: Fri, 2 Jul 2021 20:25:59 +0800 Subject: [PATCH 08/13] docs and rename --- .../GenericSerializeReferencePostProcessor.cs | 2 +- .../Editor/TypeTree.cs | 19 +++++++++++++------ .../Tests~/TestTypeTree.cs | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index 1dbb246..cfa646d 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -212,7 +212,7 @@ TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "I void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, TypeDefinition baseInterface) { logger.Debug($"get derived {property.PropertyType.Module} {property.PropertyType} {property.PropertyType.Resolve()}"); - foreach (var derived in typeTree.GetAllDerived(property.PropertyType)) + foreach (var derived in typeTree.GetOrCreateAllDerivedReference(property.PropertyType)) { var genericArguments = derived.IsGenericInstance ? ((GenericInstanceType) derived).GenericArguments diff --git a/Packages/generic-serialize-reference/Editor/TypeTree.cs b/Packages/generic-serialize-reference/Editor/TypeTree.cs index d05bd4f..fceeeb1 100644 --- a/Packages/generic-serialize-reference/Editor/TypeTree.cs +++ b/Packages/generic-serialize-reference/Editor/TypeTree.cs @@ -114,12 +114,12 @@ public TypeTree([NotNull] IEnumerable sourceTypes) /// /// Get all derived class type of . - /// Ignore generic type argument if is a generic class with certain type argument. + /// Ignore generic type argument if is a generic class with certain type of arguments. /// /// /// Any type of classes derived from directly or indirectly. /// - public IEnumerable GetAllDerived(TypeDefinition baseType) + public IEnumerable GetAllDerivedDefinition(TypeDefinition baseType) { _typeTreeNodeMap.TryGetValue(new TypeKey(baseType), out var node); if (node == null) throw new ArgumentException($"{baseType} is not part of this tree"); @@ -143,16 +143,23 @@ select type /// /// Any type of classes derived from directly. /// - public IEnumerable GetDirectDerived(TypeDefinition baseType) + public IEnumerable GetDirectDerivedDefinition(TypeDefinition baseType) { _typeTreeNodeMap.TryGetValue(new TypeKey(baseType), out var node); if (node == null) throw new ArgumentException($"{baseType} is not part of this tree"); return node.Subs.Select(sub => sub.Type); } - public IEnumerable GetAllDerived(TypeReference rootType, bool publicOnly = true) + /// + /// Get all derived class type of . + /// Will make new TypeReference if derived type is generic. + /// + /// + /// including public only classes or also including private ones. + /// Any type of classes derived from directly or indirectly. + public IEnumerable GetOrCreateAllDerivedReference(TypeReference rootType, bool publicOnly = true) { - return GetDirectDerived(rootType.Resolve()).SelectMany(t => RecursiveProcess(t, rootType)); + return GetDirectDerivedDefinition(rootType.Resolve()).SelectMany(t => RecursiveProcess(t, rootType)); IEnumerable RecursiveProcess(TypeDefinition type, TypeReference baseType) { @@ -177,7 +184,7 @@ IEnumerable RecursiveProcess(TypeDefinition type, TypeReference b ; return baseType.Yield().Concat( - GetDirectDerived(type).SelectMany(t => RecursiveProcess(t, baseType)) + GetDirectDerivedDefinition(type).SelectMany(t => RecursiveProcess(t, baseType)) ); } } diff --git a/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs b/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs index 7a126e6..e48985a 100644 --- a/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs +++ b/Packages/generic-serialize-reference/Tests~/TestTypeTree.cs @@ -123,7 +123,7 @@ public void should_get_derived_from_interface() void CheckDerived(Type @base, params Type[] types) { var derivedTypes = _tree - .GetAllDerived(_module.ImportReference(@base), publicOnly: false) + .GetOrCreateAllDerivedReference(_module.ImportReference(@base), publicOnly: false) .Select(type => type.FullName) .ToArray() ; @@ -133,7 +133,7 @@ void CheckDerived(Type @base, params Type[] types) void CheckDerivedIgnoreGenericParameters(Type @base, params Type[] types) { var tokens = _tree - .GetAllDerived(_module.ImportReference(@base).Resolve()) + .GetAllDerivedDefinition(_module.ImportReference(@base).Resolve()) .Select(type => type.MetadataToken) .ToArray() ; From 354270477c65e521a13a5f053a9d6410ce6974c4 Mon Sep 17 00:00:00 2001 From: quabug Date: Sat, 3 Jul 2021 00:18:11 +0800 Subject: [PATCH 09/13] WIP: library codegen --- .../CodeGen.meta | 8 ++ .../CodeGen/CodeGen.cs | 4 + .../CodeGen/CodeGen.cs.meta | 11 ++ ...cSerializeReference.Library.CodeGen.asmdef | 3 + ...alizeReference.Library.CodeGen.asmdef.meta | 7 ++ .../Editor.meta | 8 ++ ...icSerializeReference.Library.Editor.asmdef | 25 ++++ ...ializeReference.Library.Editor.asmdef.meta | 7 ++ .../Editor/LibraryCodeGen.cs | 113 ++++++++++++++++++ .../Editor/LibraryCodeGen.cs.meta | 3 + .../package.json | 12 ++ .../package.json.meta | 7 ++ .../Editor/AssemblyInfo.cs | 3 +- .../Editor/Extensions.cs | 16 +++ .../GenericSerializeReferencePostProcessor.cs | 19 +-- Packages/packages-lock.json | 9 ++ ProjectSettings/UnityConnectSettings.asset | 1 + 17 files changed, 238 insertions(+), 18 deletions(-) create mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen.meta create mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs create mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta create mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef create mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Editor.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta create mode 100644 Packages/generic-serialize-reference-library-gen/package.json create mode 100644 Packages/generic-serialize-reference-library-gen/package.json.meta diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen.meta b/Packages/generic-serialize-reference-library-gen/CodeGen.meta new file mode 100644 index 0000000..998a7da --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/CodeGen.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89802ac55e5713c4ea7ccd0ee05d144d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs b/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs new file mode 100644 index 0000000..b3c8012 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs @@ -0,0 +1,4 @@ +namespace GenericSerializeReference.Library.CodeGen +{ + internal static class _ {} +} diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta b/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta new file mode 100644 index 0000000..270fe6e --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5e51a09192c3854da4df1e7d5e7ac96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef b/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef new file mode 100644 index 0000000..1836880 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef @@ -0,0 +1,3 @@ +{ + "name": "GenericSerializeReference.Library.CodeGen" +} diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta b/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta new file mode 100644 index 0000000..527b161 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6f6d0ccb3fc514740a254c4934e11234 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Editor.meta b/Packages/generic-serialize-reference-library-gen/Editor.meta new file mode 100644 index 0000000..2766e96 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0e61dfaa77cc292468f59277e6410eae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef new file mode 100644 index 0000000..c6770eb --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef @@ -0,0 +1,25 @@ +{ + "name": "GenericSerializeReference.Library.Editor", + "rootNamespace": "", + "references": [ + "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", + "GUID:6f6d0ccb3fc514740a254c4934e11234", + "GUID:63b7bab1fdf9c49858cf30deda1e2c00" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "Mono.Cecil.dll", + "Mono.Cecil.Mdb.dll", + "Mono.Cecil.Pdb.dll", + "Mono.Cecil.Rocks.dll" + ], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef.meta b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef.meta new file mode 100644 index 0000000..3395bbf --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 94c3704331e58244aa4951fb15668cca +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs new file mode 100644 index 0000000..bd86056 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Mono.Cecil; +using Mono.Cecil.Cil; +using UnityEditor; +using UnityEditor.Compilation; +using UnityEngine; +using FieldAttributes = Mono.Cecil.FieldAttributes; +using TypeAttributes = Mono.Cecil.TypeAttributes; + +namespace GenericSerializeReference.Library +{ + [InitializeOnLoad] + public static class LibraryCodeGen + { + public static string GetCurrentFilePath([System.Runtime.CompilerServices.CallerFilePath] string fileName = null) + { + return fileName; + } + + static LibraryCodeGen() + { + // CompilationPipeline.compilationFinished -= OnCompilationFinished; + // CompilationPipeline.compilationFinished += OnCompilationFinished; + // + // CompilationPipeline.assemblyCompilationFinished -= Log; + // CompilationPipeline.assemblyCompilationFinished += Log; + // } + // + // static void OnCompilationFinished(object _) + // { + Debug.Log("finished"); + try + { + EditorApplication.LockReloadAssemblies(); + + const string assemblyName = ""; + + var assemblyPath = $"{Path.GetDirectoryName(GetCurrentFilePath())}/../GenericSerializeReference.Library.CodeGen.dll"; + var resolver = new DefaultAssemblyResolver(); + resolver.AddSearchDirectory(Path.GetDirectoryName(typeof(LibraryCodeGen).Assembly.Location)); + var readerParameters = new ReaderParameters {AssemblyResolver = resolver, ReadWrite = true, ThrowIfSymbolsAreNotMatching = false}; + using var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, readerParameters); + var properties = InterfaceOnlyProperties().ToArray(); + var types = properties.Select(t => t.property.PropertyType.GetGenericTypeDefinition()) + .SelectMany(genericType => TypeCache.GetTypesDerivedFrom(genericType)) + .Select(type => assembly.MainModule.ImportReference(type).Resolve()) + ; + var typeTree = new TypeTree(types); + // var field = new FieldDefinition("test", FieldAttributes.Private, assembly.MainModule.ImportReference(typeof(string))); + // codeGenType.Fields.Add(field); + + foreach (var baseType in properties.Select(t => + assembly.MainModule.ImportReference(t.property.PropertyType))) + { + var wrapper = new TypeDefinition( + "" + , $"__{baseType.FullName.Replace('.', '_')}" + , TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.NotPublic | TypeAttributes.BeforeFieldInit + ); + wrapper.BaseType = assembly.MainModule.ImportReference(typeof(object)); + + assembly.MainModule.Types.Add(wrapper); + // var derived = typeTree.GetOrCreateAllDerivedReference(baseType); + // var genericArguments = derived.IsGenericInstance + // ? ((GenericInstanceType) derived).GenericArguments + // : (IEnumerable)Array.Empty() + // ; + } + + assembly.Write(); + } + catch (Exception ex) + { + Debug.LogWarning(ex); + } + finally + { + EditorApplication.UnlockReloadAssemblies(); + } + + static IEnumerable<(PropertyInfo property, GenericSerializeReferenceAttribute attribute)> InterfaceOnlyProperties() + { + return from asm in AppDomain.CurrentDomain.GetAssemblies() + from type in IgnoreException(asm.GetTypes, Array.Empty()) + from propertyInfo in IgnoreException( + () => type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + , Array.Empty()) + from attribute in IgnoreException( + propertyInfo.GetCustomAttributes + , Array.Empty()) + where attribute.GenerateMode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly + where propertyInfo.PropertyType.IsGenericType + select (propertyInfo, attribute); + } + } + + static T IgnoreException(this Func func, T @default = default) + { + try + { + return func(); + } + catch + { + return @default; + } + } + } +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta new file mode 100644 index 0000000..4f31b4e --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 46f202bb89739e24e906289c5665e884 +timeCreated: 1625049738 \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/package.json b/Packages/generic-serialize-reference-library-gen/package.json new file mode 100644 index 0000000..4fcc24b --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/package.json @@ -0,0 +1,12 @@ +{ + "name": "com.quabug.generic-serialize-reference-library-codegen", + "description": "Automatically alter generic field of SerializeReference into its non-generic form", + "version": "0.1.0", + "unity": "2020.2", + "displayName": "GenericSerializeReference-LibraryCodeGen", + "dependencies": { + "com.unity.nuget.mono-cecil": "0.1.6-preview.2", + "com.quabug.generic-serialize-reference": "1.2.0" + }, + "type": "library" +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/package.json.meta b/Packages/generic-serialize-reference-library-gen/package.json.meta new file mode 100644 index 0000000..047a9d8 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 58e1060cf85ba4e48ae5f515861a8cc1 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs b/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs index 7926c74..deaba44 100644 --- a/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs +++ b/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs @@ -1,3 +1,4 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("GenericSerializeReference.Tests")] \ No newline at end of file +[assembly: InternalsVisibleTo("GenericSerializeReference.Tests")] +[assembly: InternalsVisibleTo("GenericSerializeReference.Library.Editor")] diff --git a/Packages/generic-serialize-reference/Editor/Extensions.cs b/Packages/generic-serialize-reference/Editor/Extensions.cs index 9f7a767..e1a59c4 100644 --- a/Packages/generic-serialize-reference/Editor/Extensions.cs +++ b/Packages/generic-serialize-reference/Editor/Extensions.cs @@ -200,5 +200,21 @@ public static TypeDefinition GenerateDerivedClass(this TypeReference baseType, I type.AddEmptyCtor(ctorCall); return type; } + + public static TypeDefinition CreateNestedStaticPrivateClass(this TypeDefinition type, string name) + { + // .class nested private abstract sealed auto ansi beforefieldinit + // <$PropertyName>__generic_serialize_reference + // extends [mscorlib]System.Object + var typeAttributes = TypeAttributes.Class | + TypeAttributes.Sealed | + TypeAttributes.Abstract | + TypeAttributes.NestedPrivate | + TypeAttributes.BeforeFieldInit; + var nestedType = new TypeDefinition("", name, typeAttributes); + nestedType.BaseType = type.Module.ImportReference(typeof(object)); + type.NestedTypes.Add(nestedType); + return nestedType; + } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index cfa646d..bb37358 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -99,7 +99,8 @@ from attribute in GetAttributesOf(property) } else { - var wrapper = CreateWrapper(property); + var wrapperName = $"<{property.Name}>__generic_serialize_reference"; + var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); serializedFieldInterface = CreateInterface(wrapper); CreateDerivedClasses(property, wrapper, serializedFieldInterface); } @@ -181,22 +182,6 @@ PropertyDefinition property return serializedField; } - TypeDefinition CreateWrapper(PropertyDefinition property) - { - // .class nested public abstract sealed auto ansi beforefieldinit - // <$PropertyName>__generic_serialize_reference - // extends [mscorlib]System.Object - var typeAttributes = TypeAttributes.Class | - TypeAttributes.Sealed | - TypeAttributes.Abstract | - TypeAttributes.NestedPrivate | - TypeAttributes.BeforeFieldInit; - var wrapper = new TypeDefinition("", $"<{property.Name}>__generic_serialize_reference", typeAttributes); - wrapper.BaseType = property.Module.ImportReference(typeof(System.Object)); - property.DeclaringType.NestedTypes.Add(wrapper); - return wrapper; - } - TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "IBase") { // .class interface nested public abstract auto ansi diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index c65f24a..efe601b 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -8,6 +8,15 @@ "com.unity.nuget.mono-cecil": "0.1.6-preview.2" } }, + "com.quabug.generic-serialize-reference-library-codegen": { + "version": "file:generic-serialize-reference-library-gen", + "depth": 0, + "source": "embedded", + "dependencies": { + "com.unity.nuget.mono-cecil": "0.1.6-preview.2", + "com.quabug.generic-serialize-reference": "1.2.0" + } + }, "com.unity.ext.nunit": { "version": "1.0.6", "depth": 1, diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset index fa0b146..6125b30 100644 --- a/ProjectSettings/UnityConnectSettings.asset +++ b/ProjectSettings/UnityConnectSettings.asset @@ -9,6 +9,7 @@ UnityConnectSettings: m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events m_EventUrl: https://cdp.cloud.unity3d.com/v1/events m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com m_TestInitMode: 0 CrashReportingSettings: m_EventUrl: https://perf-events.cloud.unity3d.com From 31e9fc2ea17d9680bc5f07d1c01dfb4dc2424f70 Mon Sep 17 00:00:00 2001 From: quabug Date: Sun, 4 Jul 2021 19:40:58 +0800 Subject: [PATCH 10/13] WIP --- Assets/Sample/Library/LibBehavior.cs | 2 + Assets/_ | 0 Assets/_.meta | 7 - .../CodeGen/CodeGen.cs => Assets/__.cs | 3 +- .../CodeGen.cs.meta => Assets/__.cs.meta | 0 .../CodeGen.meta | 8 - ...cSerializeReference.Library.CodeGen.asmdef | 3 - ...alizeReference.Library.CodeGen.asmdef.meta | 7 - ...cSerializeReferenceLibraryPostProcessor.cs | 153 ++++++++++++++++++ ...alizeReferenceLibraryPostProcessor.cs.meta | 3 + .../Editor/LibraryCodeGen.cs | 103 +++--------- ...SerializeReference.Library.CodeGen.asmdef} | 4 +- ...lizeReference.Library.CodeGen.asmdef.meta} | 0 .../Editor/AssemblyInfo.cs | 2 +- .../Editor/Extensions.cs | 17 +- .../GenericSerializeReferencePostProcessor.cs | 22 +-- .../Editor/PostProcessorAssemblyResolver.cs | 4 +- .../GenericSerializeReference.Tests.asmdef | 2 +- .../generic-serialize-reference/package.json | 2 +- Packages/packages-lock.json | 15 +- 20 files changed, 214 insertions(+), 143 deletions(-) delete mode 100644 Assets/_ delete mode 100644 Assets/_.meta rename Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs => Assets/__.cs (62%) rename Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta => Assets/__.cs.meta (100%) delete mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef delete mode 100644 Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs.meta rename Packages/generic-serialize-reference-library-gen/Editor/{GenericSerializeReference.Library.Editor.asmdef => Unity.GenericSerializeReference.Library.CodeGen.asmdef} (86%) rename Packages/generic-serialize-reference-library-gen/Editor/{GenericSerializeReference.Library.Editor.asmdef.meta => Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta} (100%) diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs index c42d6f6..fb3c4a2 100644 --- a/Assets/Sample/Library/LibBehavior.cs +++ b/Assets/Sample/Library/LibBehavior.cs @@ -1,5 +1,7 @@ using GenericSerializeReference; using UnityEngine; + +[assembly: GenericSerializeReferenceLoggerAttribute(LogLevel.Debug)] public class LibBehavior : MonoBehaviour { [GenericSerializeReference(mode: GenericSerializeReferenceAttribute.Mode.InterfaceOnly)] diff --git a/Assets/_ b/Assets/_ deleted file mode 100644 index e69de29..0000000 diff --git a/Assets/_.meta b/Assets/_.meta deleted file mode 100644 index 52ed60a..0000000 --- a/Assets/_.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 91abd8f746c824d8eb9cdc0f40251dbc -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs b/Assets/__.cs similarity index 62% rename from Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs rename to Assets/__.cs index b3c8012..2c2c9fc 100644 --- a/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs +++ b/Assets/__.cs @@ -1,4 +1,5 @@ namespace GenericSerializeReference.Library.CodeGen { - internal static class _ {} + internal static class ___ {} + } diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta b/Assets/__.cs.meta similarity index 100% rename from Packages/generic-serialize-reference-library-gen/CodeGen/CodeGen.cs.meta rename to Assets/__.cs.meta diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen.meta b/Packages/generic-serialize-reference-library-gen/CodeGen.meta deleted file mode 100644 index 998a7da..0000000 --- a/Packages/generic-serialize-reference-library-gen/CodeGen.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 89802ac55e5713c4ea7ccd0ee05d144d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef b/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef deleted file mode 100644 index 1836880..0000000 --- a/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "GenericSerializeReference.Library.CodeGen" -} diff --git a/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta b/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta deleted file mode 100644 index 527b161..0000000 --- a/Packages/generic-serialize-reference-library-gen/CodeGen/GenericSerializeReference.Library.CodeGen.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 6f6d0ccb3fc514740a254c4934e11234 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs new file mode 100644 index 0000000..014d67b --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using JetBrains.Annotations; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; +using UnityEngine; + +namespace GenericSerializeReference.Library +{ + public class GenericSerializeReferenceLibraryPostProcessor : ILPostProcessor + { + public override ILPostProcessor GetInstance() + { + return this; + } + + public override bool WillProcess(ICompiledAssembly compiledAssembly) + { + return compiledAssembly.Name == "Assembly-CSharp"; + } + + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) + { + var logger = new ILPostProcessorLogger(new List()); + var (assembly, referenceAssemblies) = GenericSerializeReferencePostProcessor.LoadAssemblyDefinition( + compiledAssembly, name => name.StartsWith("Library") + ); + + try + { + var allTypes = referenceAssemblies.Append(assembly) + .Where(asm => !asm.Name.Name.StartsWith("Unity.") && + !asm.Name.Name.StartsWith("UnityEditor.") && + !asm.Name.Name.StartsWith("UnityEngine.") + ) + .SelectMany(asm => asm.MainModule.GetAllTypes()) + .ToArray() + ; + var modified = Process(assembly.MainModule, allTypes, logger); + if (!modified) return new ILPostProcessResult(null, logger.Messages); + + var pe = new MemoryStream(); + var pdb = new MemoryStream(); + var writerParameters = new WriterParameters + { + SymbolWriterProvider = new PortablePdbWriterProvider(), SymbolStream = pdb, WriteSymbols = true + }; + assembly.Write(pe, writerParameters); + return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), logger.Messages); + } + finally + { + assembly.Dispose(); + foreach (var reference in referenceAssemblies) reference.Dispose(); + + // if (Directory.Exists(GenericSerializeReferencePostProcessor.TempDirectory)) + // Directory.Delete(GenericSerializeReferencePostProcessor.TempDirectory, true); + } + } + + private bool IsInterfaceOnlyAttribute(CustomAttribute attribute) + { + var mode = (GenericSerializeReferenceAttribute.Mode) + attribute.ConstructorArguments[GenericSerializeReferenceAttribute.MODE_INDEX].Value; + return mode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly; + } + + private bool Process(ModuleDefinition module, IReadOnlyList types, ILPostProcessorLogger logger) + { + var modified = false; + + var typeTree = new TypeTree(types); + logger.Info($"tree: {typeTree}"); + + foreach (var (type, property, attribute) in + from type in types + where type.IsClass && !type.IsAbstract + from property in type.Properties + where property.PropertyType.IsGenericInstance + from attribute in property.GetAttributesOf() + where IsInterfaceOnlyAttribute(attribute) + select (type, property, attribute) + ) + { + var fieldNamePrefix = (string)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.PREFIX_INDEX].Value; + var fieldName = $"{fieldNamePrefix}{property.Name}"; + var field = type.Fields.FirstOrDefault(field => field.Name == fieldName); + if (field == null) + { + logger.Warning($"Cannot process on property {property} without corresponding field by name of {fieldName} ({string.Join(",", type.Fields.Select(f => f.FullName))})"); + continue; + } + + var baseInterface = field.FieldType; + var baseGeneric = property.PropertyType; + + var wrapper = new TypeDefinition( + "." + type.FullName.Replace('.', '_') + , $"{property.Name}" + , TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.Public | TypeAttributes.BeforeFieldInit + ); + module.Types.Add(wrapper); + + logger.Warning($"create implementation: {baseInterface.FullName} {baseGeneric.FullName}"); + CreateDerived(module, typeTree, wrapper, baseGeneric, baseInterface); + + modified = true; + } + return modified; + } + + void CreateDerived(ModuleDefinition module, TypeTree typeTree, TypeDefinition wrapper, TypeReference genericRoot, TypeReference baseInterface) + { + foreach (var d in typeTree.GetOrCreateAllDerivedReference(genericRoot)) + { + var derived = module.ImportReference(d); + var genericArguments = derived.IsGenericInstance + ? ((GenericInstanceType) derived).GenericArguments + : (IEnumerable)Array.Empty() + ; + if (genericArguments.All(arg => !arg.IsGenericParameter)) + { + var className = derived.Name.Split('`')[0]; + if (wrapper.NestedTypes.Any(t => t.Name == className)) + className = derived.Resolve().NameWithOuterClasses(); + // TODO: should handle if the className is still the same with any of existing type. + if (wrapper.NestedTypes.Any(t => t.Name == className)) + Debug.LogWarning($"Overwrite type with same name {className}"); + var classAttributes = TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.BeforeFieldInit; + var generated = new TypeDefinition("", className, classAttributes); + generated.BaseType = derived.HasGenericParameters ? derived.MakeGenericInstanceType(genericArguments.ToArray()) : derived; + var ctor = module.ImportReference(derived.Resolve().GetConstructors().First(c => !c.HasParameters)).Resolve(); + var ctorCall = new MethodReference(ctor.Name, module.ImportReference(ctor.ReturnType)) + { + DeclaringType = generated.BaseType, + HasThis = ctor.HasThis, + ExplicitThis = ctor.ExplicitThis, + CallingConvention = ctor.CallingConvention, + }; + generated.AddEmptyCtor(ctorCall); + var interfaceImplementation = new InterfaceImplementation(baseInterface); + generated.Interfaces.Add(interfaceImplementation); + wrapper.NestedTypes.Add(generated); + } + } + } + } +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs.meta b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs.meta new file mode 100644 index 0000000..b3f4eb6 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 96eeecf641524af79225003122a4fddd +timeCreated: 1625371957 \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs index bd86056..766bcd3 100644 --- a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs +++ b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; using UnityEditor; using UnityEditor.Compilation; -using UnityEngine; -using FieldAttributes = Mono.Cecil.FieldAttributes; +using Debug = UnityEngine.Debug; using TypeAttributes = Mono.Cecil.TypeAttributes; namespace GenericSerializeReference.Library @@ -16,97 +17,39 @@ namespace GenericSerializeReference.Library [InitializeOnLoad] public static class LibraryCodeGen { - public static string GetCurrentFilePath([System.Runtime.CompilerServices.CallerFilePath] string fileName = null) - { - return fileName; - } + internal const string AssemblyName = "GenericSerializeReference.Library"; + private const string _assemblyFile = AssemblyName + ".dll"; + + private static HashSet _compiledAssemblies = new HashSet(); static LibraryCodeGen() { - // CompilationPipeline.compilationFinished -= OnCompilationFinished; - // CompilationPipeline.compilationFinished += OnCompilationFinished; - // - // CompilationPipeline.assemblyCompilationFinished -= Log; - // CompilationPipeline.assemblyCompilationFinished += Log; - // } - // - // static void OnCompilationFinished(object _) - // { - Debug.Log("finished"); - try - { - EditorApplication.LockReloadAssemblies(); + CompilationPipeline.compilationStarted -= OnCompilationStarted; + CompilationPipeline.compilationStarted += OnCompilationStarted; - const string assemblyName = ""; + CompilationPipeline.compilationFinished -= OnCompilationFinished; + CompilationPipeline.compilationFinished += OnCompilationFinished; - var assemblyPath = $"{Path.GetDirectoryName(GetCurrentFilePath())}/../GenericSerializeReference.Library.CodeGen.dll"; - var resolver = new DefaultAssemblyResolver(); - resolver.AddSearchDirectory(Path.GetDirectoryName(typeof(LibraryCodeGen).Assembly.Location)); - var readerParameters = new ReaderParameters {AssemblyResolver = resolver, ReadWrite = true, ThrowIfSymbolsAreNotMatching = false}; - using var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, readerParameters); - var properties = InterfaceOnlyProperties().ToArray(); - var types = properties.Select(t => t.property.PropertyType.GetGenericTypeDefinition()) - .SelectMany(genericType => TypeCache.GetTypesDerivedFrom(genericType)) - .Select(type => assembly.MainModule.ImportReference(type).Resolve()) - ; - var typeTree = new TypeTree(types); - // var field = new FieldDefinition("test", FieldAttributes.Private, assembly.MainModule.ImportReference(typeof(string))); - // codeGenType.Fields.Add(field); + CompilationPipeline.assemblyCompilationFinished -= OnAssemblyCompilationFinished; + CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; - foreach (var baseType in properties.Select(t => - assembly.MainModule.ImportReference(t.property.PropertyType))) - { - var wrapper = new TypeDefinition( - "" - , $"__{baseType.FullName.Replace('.', '_')}" - , TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.NotPublic | TypeAttributes.BeforeFieldInit - ); - wrapper.BaseType = assembly.MainModule.ImportReference(typeof(object)); - - assembly.MainModule.Types.Add(wrapper); - // var derived = typeTree.GetOrCreateAllDerivedReference(baseType); - // var genericArguments = derived.IsGenericInstance - // ? ((GenericInstanceType) derived).GenericArguments - // : (IEnumerable)Array.Empty() - // ; - } - - assembly.Write(); - } - catch (Exception ex) + static void OnAssemblyCompilationFinished(string assembly, CompilerMessage[] _) { - Debug.LogWarning(ex); - } - finally - { - EditorApplication.UnlockReloadAssemblies(); + _compiledAssemblies.Add(Path.GetFileName(assembly)); } - static IEnumerable<(PropertyInfo property, GenericSerializeReferenceAttribute attribute)> InterfaceOnlyProperties() + static void OnCompilationStarted(object _) { - return from asm in AppDomain.CurrentDomain.GetAssemblies() - from type in IgnoreException(asm.GetTypes, Array.Empty()) - from propertyInfo in IgnoreException( - () => type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - , Array.Empty()) - from attribute in IgnoreException( - propertyInfo.GetCustomAttributes - , Array.Empty()) - where attribute.GenerateMode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly - where propertyInfo.PropertyType.IsGenericType - select (propertyInfo, attribute); + _compiledAssemblies.Clear(); } - } - static T IgnoreException(this Func func, T @default = default) - { - try + static void OnCompilationFinished(object _) { - return func(); - } - catch - { - return @default; + if (!_compiledAssemblies.Contains(_assemblyFile)) + { + var file = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(AssemblyName); + AssetDatabase.ImportAsset(file, ImportAssetOptions.ForceUpdate); + } } } } diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef similarity index 86% rename from Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef rename to Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef index c6770eb..f9efb41 100644 --- a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef +++ b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef @@ -1,5 +1,5 @@ { - "name": "GenericSerializeReference.Library.Editor", + "name": "Unity.GenericSerializeReference.Library.CodeGen", "rootNamespace": "", "references": [ "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", @@ -18,7 +18,7 @@ "Mono.Cecil.Pdb.dll", "Mono.Cecil.Rocks.dll" ], - "autoReferenced": true, + "autoReferenced": false, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef.meta b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta similarity index 100% rename from Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReference.Library.Editor.asmdef.meta rename to Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta diff --git a/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs b/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs index deaba44..4a83c9a 100644 --- a/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs +++ b/Packages/generic-serialize-reference/Editor/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("GenericSerializeReference.Tests")] -[assembly: InternalsVisibleTo("GenericSerializeReference.Library.Editor")] +[assembly: InternalsVisibleTo("Unity.GenericSerializeReference.Library.CodeGen")] diff --git a/Packages/generic-serialize-reference/Editor/Extensions.cs b/Packages/generic-serialize-reference/Editor/Extensions.cs index e1a59c4..8988f83 100644 --- a/Packages/generic-serialize-reference/Editor/Extensions.cs +++ b/Packages/generic-serialize-reference/Editor/Extensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using JetBrains.Annotations; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; @@ -166,7 +167,7 @@ this ICustomAttributeProvider attributeProvider return attribute; } - public static TypeDefinition GenerateDerivedClass(this TypeReference baseType, IEnumerable genericArguments, string className) + public static TypeDefinition GenerateDerivedClass(this TypeReference baseType, IEnumerable genericArguments, string className, ModuleDefinition module = null) { // .class nested public auto ansi beforefieldinit // Object @@ -186,11 +187,12 @@ public static TypeDefinition GenerateDerivedClass(this TypeReference baseType, I // } // end of method Object::.ctor // } // end of class Object + module ??= baseType.Module; var classAttributes = TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.BeforeFieldInit; var type = new TypeDefinition("", className, classAttributes); type.BaseType = baseType.HasGenericParameters ? baseType.MakeGenericInstanceType(genericArguments.ToArray()) : baseType; - var ctor = baseType.Resolve().GetConstructors().First(c => !c.HasParameters); - var ctorCall = new MethodReference(ctor.Name, baseType.Module.ImportReference(ctor.ReturnType)) + var ctor = module.ImportReference(baseType.Resolve().GetConstructors().First(c => !c.HasParameters)).Resolve(); + var ctorCall = new MethodReference(ctor.Name, module.ImportReference(ctor.ReturnType)) { DeclaringType = type.BaseType, HasThis = ctor.HasThis, @@ -216,5 +218,14 @@ public static TypeDefinition CreateNestedStaticPrivateClass(this TypeDefinition type.NestedTypes.Add(nestedType); return nestedType; } + + public static IEnumerable GetAttributesOf([NotNull] this ICustomAttributeProvider provider) where T : Attribute + { + return provider.HasCustomAttributes ? + provider.CustomAttributes.Where(IsAttributeOf) : + Enumerable.Empty(); + + static bool IsAttributeOf(CustomAttribute attribute) => attribute.AttributeType.FullName == typeof(T).FullName; + } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index bb37358..47365d9 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using JetBrains.Annotations; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; @@ -30,8 +29,8 @@ public override bool WillProcess(ICompiledAssembly compiledAssembly) public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) { var logger = new ILPostProcessorLogger(new List()); - var (assembly, referenceAssemblies) = LoadAssemblyDefinition(compiledAssembly, name => name.StartsWith("Library/ScriptAssemblies")); - var loggerAttributes = GetAttributesOf(assembly); + var (assembly, referenceAssemblies) = LoadAssemblyDefinition(compiledAssembly, name => name.StartsWith("Library")); + var loggerAttributes = assembly.GetAttributesOf(); if (loggerAttributes.Any()) logger.LogLevel = (LogLevel)loggerAttributes.First().ConstructorArguments[0].Value; logger.Info($"process GenericSerializeReference on {assembly.Name.Name}({string.Join(",", referenceAssemblies.Select(r => r.Name.Name))})"); try @@ -56,7 +55,9 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) SymbolWriterProvider = new PortablePdbWriterProvider(), SymbolStream = pdb, WriteSymbols = true }; assembly.Write(pe, writerParameters); - return new ILPostProcessResult(new InMemoryAssembly(pe.ToArray(), pdb.ToArray()), logger.Messages); + // assembly.Write(); + var inMemoryAssembly = new InMemoryAssembly(pe.ToArray(), pdb.ToArray()); + return new ILPostProcessResult(inMemoryAssembly, logger.Messages); } finally { @@ -73,7 +74,7 @@ from type in module.GetAllTypes() where type.IsClass && !type.IsAbstract from property in type.Properties.ToArray() // able to change `Properties` during looping where property.PropertyType.IsGenericInstance - from attribute in GetAttributesOf(property) + from attribute in property.GetAttributesOf() select (type, property, attribute) ) { @@ -221,7 +222,7 @@ void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, T } } - private static (AssemblyDefinition compiled, AssemblyDefinition[] references) + internal static (AssemblyDefinition compiled, AssemblyDefinition[] references) LoadAssemblyDefinition(ICompiledAssembly compiledAssembly, Func referencePredicate) { var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); @@ -239,14 +240,5 @@ private static (AssemblyDefinition compiled, AssemblyDefinition[] references) var referenceAssemblies = compiledAssembly.References.Where(referencePredicate).Select(resolver.Resolve).ToArray(); return (assembly, referenceAssemblies); } - - private IEnumerable GetAttributesOf([NotNull] ICustomAttributeProvider provider) where T : Attribute - { - return provider.HasCustomAttributes ? - provider.CustomAttributes.Where(IsAttributeOf) : - Enumerable.Empty(); - - static bool IsAttributeOf(CustomAttribute attribute) => attribute.AttributeType.FullName == typeof(T).FullName; - } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/PostProcessorAssemblyResolver.cs b/Packages/generic-serialize-reference/Editor/PostProcessorAssemblyResolver.cs index 8400d1c..18fef6d 100644 --- a/Packages/generic-serialize-reference/Editor/PostProcessorAssemblyResolver.cs +++ b/Packages/generic-serialize-reference/Editor/PostProcessorAssemblyResolver.cs @@ -14,9 +14,9 @@ internal class PostProcessorAssemblyResolver : IAssemblyResolver private readonly IDictionary _cache = new Dictionary(); private readonly IReadOnlyList _references; - public PostProcessorAssemblyResolver([NotNull] IReadOnlyList references) + public PostProcessorAssemblyResolver([NotNull] IEnumerable references) { - _references = references; + _references = references.ToArray(); } public void Dispose() diff --git a/Packages/generic-serialize-reference/Tests~/GenericSerializeReference.Tests.asmdef b/Packages/generic-serialize-reference/Tests~/GenericSerializeReference.Tests.asmdef index 4597da1..56960fc 100644 --- a/Packages/generic-serialize-reference/Tests~/GenericSerializeReference.Tests.asmdef +++ b/Packages/generic-serialize-reference/Tests~/GenericSerializeReference.Tests.asmdef @@ -15,8 +15,8 @@ "precompiledReferences": [ "nunit.framework.dll", "Mono.Cecil.dll", - "Mono.Cecil.Pdb.dll", "Mono.Cecil.Mdb.dll", + "Mono.Cecil.Pdb.dll", "Mono.Cecil.Rocks.dll" ], "autoReferenced": false, diff --git a/Packages/generic-serialize-reference/package.json b/Packages/generic-serialize-reference/package.json index d777052..1829e1c 100644 --- a/Packages/generic-serialize-reference/package.json +++ b/Packages/generic-serialize-reference/package.json @@ -12,7 +12,7 @@ } ], "dependencies": { - "com.unity.nuget.mono-cecil": "0.1.6-preview.2" + "com.unity.nuget.mono-cecil": "1.10.1" }, "type": "library" } \ No newline at end of file diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index efe601b..79014f0 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -5,7 +5,7 @@ "depth": 0, "source": "embedded", "dependencies": { - "com.unity.nuget.mono-cecil": "0.1.6-preview.2" + "com.unity.nuget.mono-cecil": "1.10.1" } }, "com.quabug.generic-serialize-reference-library-codegen": { @@ -50,12 +50,10 @@ "url": "https://packages.unity.com" }, "com.unity.nuget.mono-cecil": { - "version": "0.1.6-preview.2", + "version": "1.10.1", "depth": 1, "source": "registry", - "dependencies": { - "nuget.mono-cecil": "0.1.6-preview" - }, + "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.test-framework": { @@ -69,13 +67,6 @@ }, "url": "https://packages.unity.com" }, - "nuget.mono-cecil": { - "version": "0.1.6-preview", - "depth": 2, - "source": "registry", - "dependencies": {}, - "url": "https://packages.unity.com" - }, "com.unity.modules.imgui": { "version": "1.0.0", "depth": 1, From 685cba2013725968e01c992ee78844bfdbe35b73 Mon Sep 17 00:00:00 2001 From: quabug Date: Sun, 4 Jul 2021 21:17:45 +0800 Subject: [PATCH 11/13] TBD --- ...icSerializeReference.Sample.Library.asmdef | 3 +- Assets/Sample/Library/Implement/Implement.cs | 1 + Assets/Sample/Library/LibBehavior.cs | 4 +- Assets/__.cs | 1 - ...ssor.cs => AssemblyCSharpPostProcessor.cs} | 62 ++---- ...ta => AssemblyCSharpPostProcessor.cs.meta} | 0 .../Editor/GenerateFieldPostProcessor.cs | 68 +++++++ .../Editor/GenerateFieldPostProcessor.cs.meta | 3 + .../Editor/LibraryCodeGen.cs | 56 ----- .../Editor/LibraryCodeGen.cs.meta | 3 - ...cSerializeReference.Library.CodeGen.asmdef | 4 +- .../Runtime.meta | 8 + ...cSerializeReference.Library.Runtime.asmdef | 3 + ...alizeReference.Library.Runtime.asmdef.meta | 7 + ...alizeReferenceInAssemblyCSharpAttribute.cs | 10 + ...ReferenceInAssemblyCSharpAttribute.cs.meta | 3 + .../Editor/Extensions.cs | 34 ++++ .../GenericSerializeReferencePostProcessor.cs | 192 ++++++++---------- .../GenericSerializeReferenceAttribute.cs | 13 +- 19 files changed, 250 insertions(+), 225 deletions(-) rename Packages/generic-serialize-reference-library-gen/Editor/{GenericSerializeReferenceLibraryPostProcessor.cs => AssemblyCSharpPostProcessor.cs} (69%) rename Packages/generic-serialize-reference-library-gen/Editor/{GenericSerializeReferenceLibraryPostProcessor.cs.meta => AssemblyCSharpPostProcessor.cs.meta} (100%) create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs create mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Runtime.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef create mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta create mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs create mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta diff --git a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef index 8ae996e..8b94415 100644 --- a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef +++ b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef @@ -3,7 +3,8 @@ "rootNamespace": "", "references": [ "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", - "GUID:bb7127c6ea4789d41b77cdef13d93652" + "GUID:bb7127c6ea4789d41b77cdef13d93652", + "GUID:535461a790301fe4fa3992f73817cb6f" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Sample/Library/Implement/Implement.cs b/Assets/Sample/Library/Implement/Implement.cs index fa77438..c74074b 100644 --- a/Assets/Sample/Library/Implement/Implement.cs +++ b/Assets/Sample/Library/Implement/Implement.cs @@ -1,2 +1,3 @@ public class LibIntObject : ILibInterface {} public class LibGenericObject : ILibInterface {} +public class LibGenericObject_2 : ILibInterface {} diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs index fb3c4a2..3b36d5f 100644 --- a/Assets/Sample/Library/LibBehavior.cs +++ b/Assets/Sample/Library/LibBehavior.cs @@ -1,9 +1,11 @@ using GenericSerializeReference; +using GenericSerializeReference.Library; using UnityEngine; [assembly: GenericSerializeReferenceLoggerAttribute(LogLevel.Debug)] public class LibBehavior : MonoBehaviour { - [GenericSerializeReference(mode: GenericSerializeReferenceAttribute.Mode.InterfaceOnly)] + private interface Value_IBase {} + [GenericSerializeReferenceInAssemblyCSharp(typeof(Value_IBase))] public ILibInterface Value { get; set; } } diff --git a/Assets/__.cs b/Assets/__.cs index 2c2c9fc..0334868 100644 --- a/Assets/__.cs +++ b/Assets/__.cs @@ -1,5 +1,4 @@ namespace GenericSerializeReference.Library.CodeGen { internal static class ___ {} - } diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs b/Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs similarity index 69% rename from Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs rename to Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs index 014d67b..930a4cd 100644 --- a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs +++ b/Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs @@ -12,7 +12,7 @@ namespace GenericSerializeReference.Library { - public class GenericSerializeReferenceLibraryPostProcessor : ILPostProcessor + public class AssemblyCSharpPostProcessor : ILPostProcessor { public override ILPostProcessor GetInstance() { @@ -27,9 +27,9 @@ public override bool WillProcess(ICompiledAssembly compiledAssembly) public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) { var logger = new ILPostProcessorLogger(new List()); - var (assembly, referenceAssemblies) = GenericSerializeReferencePostProcessor.LoadAssemblyDefinition( - compiledAssembly, name => name.StartsWith("Library") - ); + using var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); + using var assembly = compiledAssembly.LoadAssembly(resolver); + var referenceAssemblies = compiledAssembly.LoadLibraryAssemblies(resolver).ToArray(); try { @@ -55,48 +55,24 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) } finally { - assembly.Dispose(); foreach (var reference in referenceAssemblies) reference.Dispose(); - - // if (Directory.Exists(GenericSerializeReferencePostProcessor.TempDirectory)) - // Directory.Delete(GenericSerializeReferencePostProcessor.TempDirectory, true); } } - private bool IsInterfaceOnlyAttribute(CustomAttribute attribute) - { - var mode = (GenericSerializeReferenceAttribute.Mode) - attribute.ConstructorArguments[GenericSerializeReferenceAttribute.MODE_INDEX].Value; - return mode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly; - } - private bool Process(ModuleDefinition module, IReadOnlyList types, ILPostProcessorLogger logger) { var modified = false; - var typeTree = new TypeTree(types); - logger.Info($"tree: {typeTree}"); - foreach (var (type, property, attribute) in from type in types where type.IsClass && !type.IsAbstract from property in type.Properties where property.PropertyType.IsGenericInstance - from attribute in property.GetAttributesOf() - where IsInterfaceOnlyAttribute(attribute) + from attribute in property.GetAttributesOf() select (type, property, attribute) ) { - var fieldNamePrefix = (string)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.PREFIX_INDEX].Value; - var fieldName = $"{fieldNamePrefix}{property.Name}"; - var field = type.Fields.FirstOrDefault(field => field.Name == fieldName); - if (field == null) - { - logger.Warning($"Cannot process on property {property} without corresponding field by name of {fieldName} ({string.Join(",", type.Fields.Select(f => f.FullName))})"); - continue; - } - - var baseInterface = field.FieldType; + var baseInterface = module.ImportReference((TypeDefinition)attribute.ConstructorArguments[0].Value); var baseGeneric = property.PropertyType; var wrapper = new TypeDefinition( @@ -106,19 +82,22 @@ where IsInterfaceOnlyAttribute(attribute) ); module.Types.Add(wrapper); - logger.Warning($"create implementation: {baseInterface.FullName} {baseGeneric.FullName}"); - CreateDerived(module, typeTree, wrapper, baseGeneric, baseInterface); - - modified = true; + foreach (var derived in typeTree + .GetOrCreateAllDerivedReference(baseGeneric) + .Select(module.ImportReference)) + { + var generated = CreateDerived(module, wrapper, derived, baseInterface); + if (generated != null) + { + wrapper.NestedTypes.Add(generated); + modified = true; + } + } } return modified; - } - void CreateDerived(ModuleDefinition module, TypeTree typeTree, TypeDefinition wrapper, TypeReference genericRoot, TypeReference baseInterface) - { - foreach (var d in typeTree.GetOrCreateAllDerivedReference(genericRoot)) + TypeDefinition CreateDerived(ModuleDefinition module, TypeDefinition wrapper, TypeReference derived, TypeReference baseInterface) { - var derived = module.ImportReference(d); var genericArguments = derived.IsGenericInstance ? ((GenericInstanceType) derived).GenericArguments : (IEnumerable)Array.Empty() @@ -130,7 +109,7 @@ void CreateDerived(ModuleDefinition module, TypeTree typeTree, TypeDefinition wr className = derived.Resolve().NameWithOuterClasses(); // TODO: should handle if the className is still the same with any of existing type. if (wrapper.NestedTypes.Any(t => t.Name == className)) - Debug.LogWarning($"Overwrite type with same name {className}"); + logger.Warning($"Overwrite type with same name {className}"); var classAttributes = TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.BeforeFieldInit; var generated = new TypeDefinition("", className, classAttributes); generated.BaseType = derived.HasGenericParameters ? derived.MakeGenericInstanceType(genericArguments.ToArray()) : derived; @@ -145,8 +124,9 @@ void CreateDerived(ModuleDefinition module, TypeTree typeTree, TypeDefinition wr generated.AddEmptyCtor(ctorCall); var interfaceImplementation = new InterfaceImplementation(baseInterface); generated.Interfaces.Add(interfaceImplementation); - wrapper.NestedTypes.Add(generated); + return generated; } + return null; } } } diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs.meta b/Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs.meta similarity index 100% rename from Packages/generic-serialize-reference-library-gen/Editor/GenericSerializeReferenceLibraryPostProcessor.cs.meta rename to Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs.meta diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs b/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs new file mode 100644 index 0000000..e59d96a --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; +using UnityEngine; + +namespace GenericSerializeReference.Library +{ + public class GenericSerializeReferenceGenerateFieldPostProcessor : ILPostProcessor + { + public override ILPostProcessor GetInstance() + { + return this; + } + + public override bool WillProcess(ICompiledAssembly compiledAssembly) + { + var thisAssemblyName = GetType().Assembly.GetName().Name; + var runtimeAssemblyName = typeof(GenericSerializeReferenceInAssemblyCSharpAttribute).Assembly.GetName().Name; + return compiledAssembly.Name != thisAssemblyName && + compiledAssembly.References.Any(f => Path.GetFileNameWithoutExtension(f) == runtimeAssemblyName); + } + + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) + { + var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); + var assembly = compiledAssembly.LoadAssembly(resolver); + var logger = assembly.CreateLogger(); + logger.Info($"process GenericSerializeReference_FieldOnly on {assembly.Name.Name}"); + var module = assembly.MainModule; + var modified = false; + + foreach (var (type, property, attribute) in + from type in module.GetAllTypes() + where type.IsClass && !type.IsAbstract + from property in type.Properties.ToArray() // able to change `Properties` during looping + where property.PropertyType.IsGenericInstance + from attribute in property.GetAttributesOf() + select (type, property, attribute) + ) + { + var fieldType = (TypeDefinition) attribute.ConstructorArguments[0].Value; + var fieldPrefix = (string)attribute.ConstructorArguments[1].Value; + logger.Info($"generate field {fieldPrefix}{property.Name} on {property.DeclaringType.FullName}"); + GenericSerializeReferencePostProcessor.GenerateField(module, property, fieldType, fieldPrefix); + modified = true; + } + + if (!modified) return new ILPostProcessResult(null, logger.Messages); + + var pe = new MemoryStream(); + var pdb = new MemoryStream(); + var writerParameters = new WriterParameters + { + SymbolWriterProvider = new PortablePdbWriterProvider(), SymbolStream = pdb, WriteSymbols = true + }; + assembly.Write(pe, writerParameters); + // assembly.Write(); + var inMemoryAssembly = new InMemoryAssembly(pe.ToArray(), pdb.ToArray()); + return new ILPostProcessResult(inMemoryAssembly, logger.Messages); + } + } +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta b/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta new file mode 100644 index 0000000..0eb47f0 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c429dfd2c2354342a343673009d25d3a +timeCreated: 1625400804 \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs deleted file mode 100644 index 766bcd3..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; -using UnityEditor; -using UnityEditor.Compilation; -using Debug = UnityEngine.Debug; -using TypeAttributes = Mono.Cecil.TypeAttributes; - -namespace GenericSerializeReference.Library -{ - [InitializeOnLoad] - public static class LibraryCodeGen - { - internal const string AssemblyName = "GenericSerializeReference.Library"; - private const string _assemblyFile = AssemblyName + ".dll"; - - private static HashSet _compiledAssemblies = new HashSet(); - - static LibraryCodeGen() - { - CompilationPipeline.compilationStarted -= OnCompilationStarted; - CompilationPipeline.compilationStarted += OnCompilationStarted; - - CompilationPipeline.compilationFinished -= OnCompilationFinished; - CompilationPipeline.compilationFinished += OnCompilationFinished; - - CompilationPipeline.assemblyCompilationFinished -= OnAssemblyCompilationFinished; - CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; - - static void OnAssemblyCompilationFinished(string assembly, CompilerMessage[] _) - { - _compiledAssemblies.Add(Path.GetFileName(assembly)); - } - - static void OnCompilationStarted(object _) - { - _compiledAssemblies.Clear(); - } - - static void OnCompilationFinished(object _) - { - if (!_compiledAssemblies.Contains(_assemblyFile)) - { - var file = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(AssemblyName); - AssetDatabase.ImportAsset(file, ImportAssetOptions.ForceUpdate); - } - } - } - } -} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta b/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta deleted file mode 100644 index 4f31b4e..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor/LibraryCodeGen.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 46f202bb89739e24e906289c5665e884 -timeCreated: 1625049738 \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef index f9efb41..e307987 100644 --- a/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef +++ b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef @@ -3,8 +3,8 @@ "rootNamespace": "", "references": [ "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", - "GUID:6f6d0ccb3fc514740a254c4934e11234", - "GUID:63b7bab1fdf9c49858cf30deda1e2c00" + "GUID:63b7bab1fdf9c49858cf30deda1e2c00", + "GUID:535461a790301fe4fa3992f73817cb6f" ], "includePlatforms": [ "Editor" diff --git a/Packages/generic-serialize-reference-library-gen/Runtime.meta b/Packages/generic-serialize-reference-library-gen/Runtime.meta new file mode 100644 index 0000000..26ba953 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d475d48392d24dab8df79f57dfbeb935 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef new file mode 100644 index 0000000..1ae66e9 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef @@ -0,0 +1,3 @@ +{ + "name": "GenericSerializeReference.Library.Runtime" +} diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta new file mode 100644 index 0000000..2396e7d --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 535461a790301fe4fa3992f73817cb6f +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs new file mode 100644 index 0000000..d15ced1 --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace GenericSerializeReference.Library +{ + [AttributeUsage(AttributeTargets.Property)] + public class GenericSerializeReferenceInAssemblyCSharpAttribute : Attribute + { + public GenericSerializeReferenceInAssemblyCSharpAttribute(Type interfaceType, string serializedFieldPrefix = "__") {} + } +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta new file mode 100644 index 0000000..0bfa35a --- /dev/null +++ b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2aca2c9aecb2477588b0542d160ca5d4 +timeCreated: 1625400568 \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/Extensions.cs b/Packages/generic-serialize-reference/Editor/Extensions.cs index 8988f83..65dd1e8 100644 --- a/Packages/generic-serialize-reference/Editor/Extensions.cs +++ b/Packages/generic-serialize-reference/Editor/Extensions.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text.RegularExpressions; using JetBrains.Annotations; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; namespace GenericSerializeReference { @@ -35,6 +38,37 @@ public static string ToReadableName(this Type type) } } + internal static class PostProcessorExtension + { + public static AssemblyDefinition LoadAssembly(this ICompiledAssembly compiledAssembly, IAssemblyResolver resolver) + { + var symbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData.ToArray()); + var readerParameters = new ReaderParameters + { + SymbolStream = symbolStream, + SymbolReaderProvider = new PortablePdbReaderProvider(), + AssemblyResolver = resolver, + ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(), + ReadingMode = ReadingMode.Immediate, + }; + var peStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PeData.ToArray()); + return AssemblyDefinition.ReadAssembly(peStream, readerParameters); + } + + public static IEnumerable LoadLibraryAssemblies(this ICompiledAssembly compiledAssembly, PostProcessorAssemblyResolver resolver) + { + return compiledAssembly.References.Where(name => name.StartsWith("Library")).Select(resolver.Resolve); + } + + public static ILPostProcessorLogger CreateLogger(this AssemblyDefinition assembly) + { + var logger = new ILPostProcessorLogger(new List()); + var loggerAttributes = assembly.GetAttributesOf(); + if (loggerAttributes.Any()) logger.LogLevel = (LogLevel)loggerAttributes.First().ConstructorArguments[0].Value; + return logger; + } + } + internal static class CecilExtension { public static string ToReadableName(this TypeReference type) diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index 47365d9..0e0c305 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -29,12 +29,14 @@ public override bool WillProcess(ICompiledAssembly compiledAssembly) public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) { var logger = new ILPostProcessorLogger(new List()); - var (assembly, referenceAssemblies) = LoadAssemblyDefinition(compiledAssembly, name => name.StartsWith("Library")); - var loggerAttributes = assembly.GetAttributesOf(); - if (loggerAttributes.Any()) logger.LogLevel = (LogLevel)loggerAttributes.First().ConstructorArguments[0].Value; - logger.Info($"process GenericSerializeReference on {assembly.Name.Name}({string.Join(",", referenceAssemblies.Select(r => r.Name.Name))})"); + using var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); + using var assembly = compiledAssembly.LoadAssembly(resolver); + var referenceAssemblies = compiledAssembly.LoadLibraryAssemblies(resolver).ToArray(); try { + var loggerAttributes = assembly.GetAttributesOf(); + if (loggerAttributes.Any()) logger.LogLevel = (LogLevel)loggerAttributes.First().ConstructorArguments[0].Value; + logger.Info($"process GenericSerializeReference on {assembly.Name.Name}({string.Join(",", referenceAssemblies.Select(r => r.Name.Name))})"); var allTypes = referenceAssemblies.Append(assembly) .Where(asm => !asm.Name.Name.StartsWith("Unity.") && !asm.Name.Name.StartsWith("UnityEditor.") @@ -61,7 +63,6 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) } finally { - assembly.Dispose(); foreach (var reference in referenceAssemblies) reference.Dispose(); } } @@ -90,99 +91,18 @@ from attribute in property.GetAttributesOf() continue; } - var mode = (GenericSerializeReferenceAttribute.Mode)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.MODE_INDEX].Value; - var isInterfaceOnly = mode == GenericSerializeReferenceAttribute.Mode.InterfaceOnly; - - TypeDefinition serializedFieldInterface; - if (isInterfaceOnly) - { - serializedFieldInterface = CreateInterface(property.DeclaringType, $"<{property.Name}>__IBase"); - } - else - { - var wrapperName = $"<{property.Name}>__generic_serialize_reference"; - var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); - serializedFieldInterface = CreateInterface(wrapper); - CreateDerivedClasses(property, wrapper, serializedFieldInterface); - } + var wrapperName = $"<{property.Name}>__generic_serialize_reference"; + var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); + var serializedFieldInterface = CreateInterface(wrapper); + CreateDerivedClasses(property, wrapper, serializedFieldInterface); logger.Info($"generate nested class with interface {serializedFieldInterface.FullName}"); - var fieldNamePrefix = (string)attribute.ConstructorArguments[GenericSerializeReferenceAttribute.PREFIX_INDEX].Value; - var serializedField = CreateSerializeReferenceField(property, serializedFieldInterface, fieldNamePrefix, mode); - if (isInterfaceOnly) - { - } - InjectGetter(property, serializedField); - InjectSetter(property, serializedField); + var fieldNamePrefix = (string)attribute.ConstructorArguments[0].Value; + GenerateField(module, property, serializedFieldInterface, fieldNamePrefix); modified = true; } return modified; - void InjectGetter(PropertyDefinition property, FieldDefinition serializedField) - { - // --------add-------- - // IL_0000: ldarg.0 // this - // IL_0001: ldfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::_Value - // IL_0006: dup - // IL_0007: brtrue.s IL_0010 - // IL_0009: pop - // --------add-------- - - // IL_000a: ldarg.0 // this - // IL_000b: ldfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::k__BackingField - // IL_0010: ret - if (property.GetMethod == null) return; - var instructions = property.GetMethod.Body.Instructions; - var ret = instructions.Last(i => i.OpCode == OpCodes.Ret); - instructions.Insert(0, Instruction.Create(OpCodes.Ldarg_0)); - instructions.Insert(1, Instruction.Create(OpCodes.Ldfld, serializedField)); - instructions.Insert(2, Instruction.Create(OpCodes.Dup)); - instructions.Insert(3, Instruction.Create(OpCodes.Brtrue_S, ret)); - instructions.Insert(4, Instruction.Create(OpCodes.Pop)); - } - - void InjectSetter(PropertyDefinition property, FieldDefinition serializedField) - { - //IL_0000: ldarg.0 // this - //IL_0001: ldarg.1 // 'value' - //IL_0002: stfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::'k__BackingField' - // before ret - // -------add------- - // IL_0008: ldarg.0 // this - // IL_0009: ldnull - // IL_000a: stfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::_Value - // -------add------- - //IL_0007: ret - if (property.SetMethod == null) return; - var instructions = property.SetMethod.Body.Instructions; - var retIndex = instructions.FindLastIndexOf(i => i.OpCode == OpCodes.Ret); - instructions.Insert(retIndex + 0, Instruction.Create(OpCodes.Ldarg_0)); - instructions.Insert(retIndex + 1, Instruction.Create(OpCodes.Ldnull)); - instructions.Insert(retIndex + 2, Instruction.Create(OpCodes.Stfld, serializedField)); - } - - FieldDefinition CreateSerializeReferenceField( - PropertyDefinition property - , TypeReference @interface - , string namePrefix - , GenericSerializeReferenceAttribute.Mode mode - ) - { - //.field private class GenericSerializeReference.Tests.TestMonoBehavior/__generic_serialize_reference_GenericInterface__/IBase _GenericInterface - // .custom instance void [UnityEngine.CoreModule]UnityEngine.SerializeReference::.ctor() - // = (01 00 00 00 ) - var serializedField = new FieldDefinition( - $"{namePrefix}{property.Name}" - , FieldAttributes.Private - , @interface - ); - serializedField.AddCustomAttribute(module); - serializedField.AddCustomAttribute(module); - property.DeclaringType.Fields.Add(serializedField); - logger.Debug($"add field into {property.DeclaringType.FullName}"); - return serializedField; - } - TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "IBase") { // .class interface nested public abstract auto ansi @@ -222,23 +142,79 @@ void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, T } } - internal static (AssemblyDefinition compiled, AssemblyDefinition[] references) - LoadAssemblyDefinition(ICompiledAssembly compiledAssembly, Func referencePredicate) + internal static void GenerateField( + ModuleDefinition module, + PropertyDefinition property, + TypeDefinition fieldType, + string fieldNamePrefix) { - var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); - var symbolStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PdbData.ToArray()); - var readerParameters = new ReaderParameters - { - SymbolStream = symbolStream, - SymbolReaderProvider = new PortablePdbReaderProvider(), - AssemblyResolver = resolver, - ReflectionImporterProvider = new PostProcessorReflectionImporterProvider(), - ReadingMode = ReadingMode.Immediate, - }; - var peStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PeData.ToArray()); - var assembly = AssemblyDefinition.ReadAssembly(peStream, readerParameters); - var referenceAssemblies = compiledAssembly.References.Where(referencePredicate).Select(resolver.Resolve).ToArray(); - return (assembly, referenceAssemblies); + var serializedField = CreateSerializeReferenceField(module, property, fieldType, fieldNamePrefix); + InjectGetter(property, serializedField); + InjectSetter(property, serializedField); + } + + internal static FieldDefinition CreateSerializeReferenceField( + ModuleDefinition module, + PropertyDefinition property, + TypeReference @interface, + string namePrefix) + { + //.field private class GenericSerializeReference.Tests.TestMonoBehavior/__generic_serialize_reference_GenericInterface__/IBase _GenericInterface + // .custom instance void [UnityEngine.CoreModule]UnityEngine.SerializeReference::.ctor() + // = (01 00 00 00 ) + var serializedField = new FieldDefinition( + $"{namePrefix}{property.Name}" + , FieldAttributes.Private + , @interface + ); + serializedField.AddCustomAttribute(module); + serializedField.AddCustomAttribute(module); + property.DeclaringType.Fields.Add(serializedField); + return serializedField; } + + internal static void InjectGetter(PropertyDefinition property, FieldDefinition serializedField) + { + // --------add-------- + // IL_0000: ldarg.0 // this + // IL_0001: ldfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::_Value + // IL_0006: dup + // IL_0007: brtrue.s IL_0010 + // IL_0009: pop + // --------add-------- + + // IL_000a: ldarg.0 // this + // IL_000b: ldfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::k__BackingField + // IL_0010: ret + if (property.GetMethod == null) return; + var instructions = property.GetMethod.Body.Instructions; + var ret = instructions.Last(i => i.OpCode == OpCodes.Ret); + instructions.Insert(0, Instruction.Create(OpCodes.Ldarg_0)); + instructions.Insert(1, Instruction.Create(OpCodes.Ldfld, serializedField)); + instructions.Insert(2, Instruction.Create(OpCodes.Dup)); + instructions.Insert(3, Instruction.Create(OpCodes.Brtrue_S, ret)); + instructions.Insert(4, Instruction.Create(OpCodes.Pop)); + } + + internal static void InjectSetter(PropertyDefinition property, FieldDefinition serializedField) + { + //IL_0000: ldarg.0 // this + //IL_0001: ldarg.1 // 'value' + //IL_0002: stfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::'k__BackingField' + // before ret + // -------add------- + // IL_0008: ldarg.0 // this + // IL_0009: ldnull + // IL_000a: stfld class GenericSerializeReference.Tests.SingleGeneric/IInterface`1 GenericSerializeReference.Tests.A::_Value + // -------add------- + //IL_0007: ret + if (property.SetMethod == null) return; + var instructions = property.SetMethod.Body.Instructions; + var retIndex = instructions.FindLastIndexOf(i => i.OpCode == OpCodes.Ret); + instructions.Insert(retIndex + 0, Instruction.Create(OpCodes.Ldarg_0)); + instructions.Insert(retIndex + 1, Instruction.Create(OpCodes.Ldnull)); + instructions.Insert(retIndex + 2, Instruction.Create(OpCodes.Stfld, serializedField)); + } + } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs index a57bb1f..8b44bec 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs @@ -5,17 +5,6 @@ namespace GenericSerializeReference [AttributeUsage(AttributeTargets.Property)] public class GenericSerializeReferenceAttribute : Attribute { - public const int PREFIX_INDEX = 0; - public const int MODE_INDEX = 1; - public enum Mode { EmbedClasses, InterfaceOnly } - - public string SerializedFieldPrefix { get; } - public Mode GenerateMode { get; } - - public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", Mode mode = Mode.EmbedClasses) - { - SerializedFieldPrefix = serializedFieldPrefix; - GenerateMode = mode; - } + public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__") {} } } \ No newline at end of file From 536ab1bf276abc970d031dbd460972b3bca6fa0c Mon Sep 17 00:00:00 2001 From: quabug Date: Mon, 5 Jul 2021 00:24:10 +0800 Subject: [PATCH 12/13] integrate two packages into one --- ...eReference.Sample.Library.Interface.asmdef | 4 +- Assets/Sample/Library/LibBehavior.cs | 9 +- Assets/Sample/MyMonoBehavior.cs | 2 +- Assets/Sample/Test.unity | 8 +- Assets/Sample/TestMonoBehavior.cs | 14 +- .../Editor.meta | 8 - .../Editor/GenerateFieldPostProcessor.cs | 68 ----- .../Editor/GenerateFieldPostProcessor.cs.meta | 3 - ...cSerializeReference.Library.CodeGen.asmdef | 25 -- ...alizeReference.Library.CodeGen.asmdef.meta | 7 - .../Runtime.meta | 8 - ...cSerializeReference.Library.Runtime.asmdef | 3 - ...alizeReference.Library.Runtime.asmdef.meta | 7 - ...alizeReferenceInAssemblyCSharpAttribute.cs | 10 - ...ReferenceInAssemblyCSharpAttribute.cs.meta | 3 - .../package.json | 12 - .../package.json.meta | 7 - .../Editor/AssemblyCSharpPostProcessor.cs | 50 ++-- .../AssemblyCSharpPostProcessor.cs.meta | 0 ...cSerializeReferenceFieldAttributeDrawer.cs | 271 ++++++++---------- .../GenericSerializeReferencePostProcessor.cs | 30 +- .../GenericSerializeReferenceAttribute.cs | 6 +- ...rializeReferenceGeneratedFieldAttribute.cs | 6 +- .../Runtime/IBase.cs | 4 + .../Runtime/IBase.cs.meta | 3 + Packages/packages-lock.json | 9 - 26 files changed, 214 insertions(+), 363 deletions(-) delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef delete mode 100644 Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/Runtime.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef delete mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs delete mode 100644 Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta delete mode 100644 Packages/generic-serialize-reference-library-gen/package.json delete mode 100644 Packages/generic-serialize-reference-library-gen/package.json.meta rename Packages/{generic-serialize-reference-library-gen => generic-serialize-reference}/Editor/AssemblyCSharpPostProcessor.cs (76%) rename Packages/{generic-serialize-reference-library-gen => generic-serialize-reference}/Editor/AssemblyCSharpPostProcessor.cs.meta (100%) create mode 100644 Packages/generic-serialize-reference/Runtime/IBase.cs create mode 100644 Packages/generic-serialize-reference/Runtime/IBase.cs.meta diff --git a/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef index 3903225..d430408 100644 --- a/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef +++ b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef @@ -1,7 +1,9 @@ { "name": "GenericSerializeReference.Sample.Library.Interface", "rootNamespace": "", - "references": [], + "references": [ + "GUID:535461a790301fe4fa3992f73817cb6f" + ], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs index 3b36d5f..82ae87a 100644 --- a/Assets/Sample/Library/LibBehavior.cs +++ b/Assets/Sample/Library/LibBehavior.cs @@ -1,11 +1,12 @@ using GenericSerializeReference; -using GenericSerializeReference.Library; using UnityEngine; [assembly: GenericSerializeReferenceLoggerAttribute(LogLevel.Debug)] public class LibBehavior : MonoBehaviour { - private interface Value_IBase {} - [GenericSerializeReferenceInAssemblyCSharp(typeof(Value_IBase))] - public ILibInterface Value { get; set; } + [GenericSerializeReference(mode: GenerateMode.AssemblyCSharp)] + public ILibInterface Int { get; set; } + + [GenericSerializeReference(mode: GenerateMode.AssemblyCSharp)] + public ILibInterface Float { get; set; } } diff --git a/Assets/Sample/MyMonoBehavior.cs b/Assets/Sample/MyMonoBehavior.cs index ac55895..676d63c 100644 --- a/Assets/Sample/MyMonoBehavior.cs +++ b/Assets/Sample/MyMonoBehavior.cs @@ -7,7 +7,7 @@ public class MyGenericObject : IMyInterface {} public struct StructWillNotShow : IMyInterface {} public class MyMonoBehavior : MonoBehaviour { - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public IMyInterface Value { get; set; } // // [GenericSerializeReference("_serialized")] diff --git a/Assets/Sample/Test.unity b/Assets/Sample/Test.unity index b6653a7..23d792e 100644 --- a/Assets/Sample/Test.unity +++ b/Assets/Sample/Test.unity @@ -250,9 +250,13 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 66e141599402ff44f8de6aef9ccd07f2, type: 3} m_Name: m_EditorClassIdentifier: - __Value: + __Int: id: 0 + __Float: + id: 1 references: version: 1 00000000: - type: {class: , ns: , asm: } + type: {class: ILibInterface`1/LibGenericObject, ns: , asm: Assembly-CSharp} + 00000001: + type: {class: ILibInterface`1/LibGenericObject_2, ns: , asm: Assembly-CSharp} diff --git a/Assets/Sample/TestMonoBehavior.cs b/Assets/Sample/TestMonoBehavior.cs index 9c68d0f..633adeb 100644 --- a/Assets/Sample/TestMonoBehavior.cs +++ b/Assets/Sample/TestMonoBehavior.cs @@ -14,25 +14,25 @@ public class Object : MultipleGeneric.IInterface public int V; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public MultipleGeneric.IInterface IntFloat { get; set; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public MultipleGeneric.IInterface FloatInt { get; set; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public MultipleGeneric.IInterface IntInt { get; set; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public SingleGeneric.IInterface Int { get; set; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public SingleGeneric.IInterface Double { get; set; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public SingleGeneric.Object IntObject { get; set; } - [GenericSerializeReference] + [GenericSerializeReference(mode: GenerateMode.Embed)] public MultipleGeneric.Object IntIntObject { get; set; } private void Awake() diff --git a/Packages/generic-serialize-reference-library-gen/Editor.meta b/Packages/generic-serialize-reference-library-gen/Editor.meta deleted file mode 100644 index 2766e96..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0e61dfaa77cc292468f59277e6410eae -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs b/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs deleted file mode 100644 index e59d96a..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; -using Unity.CompilationPipeline.Common.Diagnostics; -using Unity.CompilationPipeline.Common.ILPostProcessing; -using UnityEngine; - -namespace GenericSerializeReference.Library -{ - public class GenericSerializeReferenceGenerateFieldPostProcessor : ILPostProcessor - { - public override ILPostProcessor GetInstance() - { - return this; - } - - public override bool WillProcess(ICompiledAssembly compiledAssembly) - { - var thisAssemblyName = GetType().Assembly.GetName().Name; - var runtimeAssemblyName = typeof(GenericSerializeReferenceInAssemblyCSharpAttribute).Assembly.GetName().Name; - return compiledAssembly.Name != thisAssemblyName && - compiledAssembly.References.Any(f => Path.GetFileNameWithoutExtension(f) == runtimeAssemblyName); - } - - public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) - { - var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References); - var assembly = compiledAssembly.LoadAssembly(resolver); - var logger = assembly.CreateLogger(); - logger.Info($"process GenericSerializeReference_FieldOnly on {assembly.Name.Name}"); - var module = assembly.MainModule; - var modified = false; - - foreach (var (type, property, attribute) in - from type in module.GetAllTypes() - where type.IsClass && !type.IsAbstract - from property in type.Properties.ToArray() // able to change `Properties` during looping - where property.PropertyType.IsGenericInstance - from attribute in property.GetAttributesOf() - select (type, property, attribute) - ) - { - var fieldType = (TypeDefinition) attribute.ConstructorArguments[0].Value; - var fieldPrefix = (string)attribute.ConstructorArguments[1].Value; - logger.Info($"generate field {fieldPrefix}{property.Name} on {property.DeclaringType.FullName}"); - GenericSerializeReferencePostProcessor.GenerateField(module, property, fieldType, fieldPrefix); - modified = true; - } - - if (!modified) return new ILPostProcessResult(null, logger.Messages); - - var pe = new MemoryStream(); - var pdb = new MemoryStream(); - var writerParameters = new WriterParameters - { - SymbolWriterProvider = new PortablePdbWriterProvider(), SymbolStream = pdb, WriteSymbols = true - }; - assembly.Write(pe, writerParameters); - // assembly.Write(); - var inMemoryAssembly = new InMemoryAssembly(pe.ToArray(), pdb.ToArray()); - return new ILPostProcessResult(inMemoryAssembly, logger.Messages); - } - } -} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta b/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta deleted file mode 100644 index 0eb47f0..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor/GenerateFieldPostProcessor.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: c429dfd2c2354342a343673009d25d3a -timeCreated: 1625400804 \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef deleted file mode 100644 index e307987..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Unity.GenericSerializeReference.Library.CodeGen", - "rootNamespace": "", - "references": [ - "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", - "GUID:63b7bab1fdf9c49858cf30deda1e2c00", - "GUID:535461a790301fe4fa3992f73817cb6f" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": true, - "precompiledReferences": [ - "Mono.Cecil.dll", - "Mono.Cecil.Mdb.dll", - "Mono.Cecil.Pdb.dll", - "Mono.Cecil.Rocks.dll" - ], - "autoReferenced": false, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta b/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta deleted file mode 100644 index 3395bbf..0000000 --- a/Packages/generic-serialize-reference-library-gen/Editor/Unity.GenericSerializeReference.Library.CodeGen.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 94c3704331e58244aa4951fb15668cca -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Runtime.meta b/Packages/generic-serialize-reference-library-gen/Runtime.meta deleted file mode 100644 index 26ba953..0000000 --- a/Packages/generic-serialize-reference-library-gen/Runtime.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d475d48392d24dab8df79f57dfbeb935 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef deleted file mode 100644 index 1ae66e9..0000000 --- a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "GenericSerializeReference.Library.Runtime" -} diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta deleted file mode 100644 index 2396e7d..0000000 --- a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReference.Library.Runtime.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 535461a790301fe4fa3992f73817cb6f -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs deleted file mode 100644 index d15ced1..0000000 --- a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace GenericSerializeReference.Library -{ - [AttributeUsage(AttributeTargets.Property)] - public class GenericSerializeReferenceInAssemblyCSharpAttribute : Attribute - { - public GenericSerializeReferenceInAssemblyCSharpAttribute(Type interfaceType, string serializedFieldPrefix = "__") {} - } -} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta b/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta deleted file mode 100644 index 0bfa35a..0000000 --- a/Packages/generic-serialize-reference-library-gen/Runtime/GenericSerializeReferenceInAssemblyCSharpAttribute.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 2aca2c9aecb2477588b0542d160ca5d4 -timeCreated: 1625400568 \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/package.json b/Packages/generic-serialize-reference-library-gen/package.json deleted file mode 100644 index 4fcc24b..0000000 --- a/Packages/generic-serialize-reference-library-gen/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "com.quabug.generic-serialize-reference-library-codegen", - "description": "Automatically alter generic field of SerializeReference into its non-generic form", - "version": "0.1.0", - "unity": "2020.2", - "displayName": "GenericSerializeReference-LibraryCodeGen", - "dependencies": { - "com.unity.nuget.mono-cecil": "0.1.6-preview.2", - "com.quabug.generic-serialize-reference": "1.2.0" - }, - "type": "library" -} \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/package.json.meta b/Packages/generic-serialize-reference-library-gen/package.json.meta deleted file mode 100644 index 047a9d8..0000000 --- a/Packages/generic-serialize-reference-library-gen/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 58e1060cf85ba4e48ae5f515861a8cc1 -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs b/Packages/generic-serialize-reference/Editor/AssemblyCSharpPostProcessor.cs similarity index 76% rename from Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs rename to Packages/generic-serialize-reference/Editor/AssemblyCSharpPostProcessor.cs index 930a4cd..01b068c 100644 --- a/Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/AssemblyCSharpPostProcessor.cs @@ -10,7 +10,7 @@ using Unity.CompilationPipeline.Common.ILPostProcessing; using UnityEngine; -namespace GenericSerializeReference.Library +namespace GenericSerializeReference { public class AssemblyCSharpPostProcessor : ILPostProcessor { @@ -63,40 +63,48 @@ private bool Process(ModuleDefinition module, IReadOnlyList type { var modified = false; var typeTree = new TypeTree(types); + var wrappers = new Dictionary(); foreach (var (type, property, attribute) in from type in types where type.IsClass && !type.IsAbstract from property in type.Properties where property.PropertyType.IsGenericInstance - from attribute in property.GetAttributesOf() + from attribute in property.GetAttributesOf() + where IsAssemblyCSharpMode(attribute) select (type, property, attribute) ) { - var baseInterface = module.ImportReference((TypeDefinition)attribute.ConstructorArguments[0].Value); + var baseInterface = module.ImportReference(typeof(IBase)); var baseGeneric = property.PropertyType; - var wrapper = new TypeDefinition( - "." + type.FullName.Replace('.', '_') - , $"{property.Name}" - , TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.Public | TypeAttributes.BeforeFieldInit - ); - module.Types.Add(wrapper); - - foreach (var derived in typeTree - .GetOrCreateAllDerivedReference(baseGeneric) - .Select(module.ImportReference)) + if (!wrappers.TryGetValue(baseGeneric, out var wrapper)) { - var generated = CreateDerived(module, wrapper, derived, baseInterface); - if (generated != null) + wrapper = new TypeDefinition( + "" + baseGeneric.Namespace, + baseGeneric.FullName.Replace('.', '_'), + TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.Public | TypeAttributes.BeforeFieldInit + ); + wrappers[baseGeneric] = wrapper; + + foreach (var derived in typeTree + .GetOrCreateAllDerivedReference(baseGeneric) + .Select(module.ImportReference)) { - wrapper.NestedTypes.Add(generated); - modified = true; + var generated = CreateDerived(wrapper, derived, baseInterface); + if (generated != null) + { + wrapper.NestedTypes.Add(generated); + modified = true; + } } } + module.Types.Add(wrapper); + + modified = true; } return modified; - TypeDefinition CreateDerived(ModuleDefinition module, TypeDefinition wrapper, TypeReference derived, TypeReference baseInterface) + TypeDefinition CreateDerived(TypeDefinition wrapper, TypeReference derived, TypeReference baseInterface) { var genericArguments = derived.IsGenericInstance ? ((GenericInstanceType) derived).GenericArguments @@ -129,5 +137,11 @@ TypeDefinition CreateDerived(ModuleDefinition module, TypeDefinition wrapper, Ty return null; } } + + static bool IsAssemblyCSharpMode(CustomAttribute attribute) + { + var mode = (GenerateMode) attribute.ConstructorArguments[1].Value; + return mode == GenerateMode.AssemblyCSharp; + } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs.meta b/Packages/generic-serialize-reference/Editor/AssemblyCSharpPostProcessor.cs.meta similarity index 100% rename from Packages/generic-serialize-reference-library-gen/Editor/AssemblyCSharpPostProcessor.cs.meta rename to Packages/generic-serialize-reference/Editor/AssemblyCSharpPostProcessor.cs.meta diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferenceFieldAttributeDrawer.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferenceFieldAttributeDrawer.cs index eb45702..845abe2 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferenceFieldAttributeDrawer.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferenceFieldAttributeDrawer.cs @@ -47,108 +47,155 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten var labelPosition = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); EditorGUI.LabelField(labelPosition, label); - DrawSelectionButtonForManagedReference(property, position); + DrawSelectionButtonForManagedReference(); EditorGUI.PropertyField(position, property, GUIContent.none, true); EditorGUI.EndProperty(); - } - private void DrawSelectionButtonForManagedReference(SerializedProperty property, Rect position, IEnumerable> filters = null) - { - var backgroundColor = new Color(0.1f, 0.55f, 0.9f, 1f); + void DrawSelectionButtonForManagedReference() + { + var backgroundColor = new Color(0.1f, 0.55f, 0.9f, 1f); - var buttonPosition = position; - buttonPosition.x += EditorGUIUtility.labelWidth + 1 * EditorGUIUtility.standardVerticalSpacing; - buttonPosition.width = position.width - EditorGUIUtility.labelWidth - 1 * EditorGUIUtility.standardVerticalSpacing; - buttonPosition.height = EditorGUIUtility.singleLineHeight; + var buttonPosition = position; + buttonPosition.x += EditorGUIUtility.labelWidth + 1 * EditorGUIUtility.standardVerticalSpacing; + buttonPosition.width = position.width - EditorGUIUtility.labelWidth - 1 * EditorGUIUtility.standardVerticalSpacing; + buttonPosition.height = EditorGUIUtility.singleLineHeight; - var storedIndent = EditorGUI.indentLevel; - EditorGUI.indentLevel = 0; - var storedColor = GUI.backgroundColor; - GUI.backgroundColor = backgroundColor; + var storedIndent = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + var storedColor = GUI.backgroundColor; + GUI.backgroundColor = backgroundColor; - var names = GetSplitNamesFromTypename(property.managedReferenceFullTypename); - var className = string.IsNullOrEmpty(names.ClassName) ? "Null (Assign)" : names.ClassName; - className = className.Split('/').Last(); - var assemblyName = names.AssemblyName; - if (GUI.Button(buttonPosition, new GUIContent(className, className + " ( "+ assemblyName +" )" ))) - ShowContextMenuForManagedReference(property, filters); + var names = GetSplitNamesFromTypename(property.managedReferenceFullTypename); + var className = string.IsNullOrEmpty(names.ClassName) ? "Null (Assign)" : names.ClassName; + className = className.Split('/').Last(); + var assemblyName = names.AssemblyName; + if (GUI.Button(buttonPosition, new GUIContent(className, className + " ( "+ assemblyName +" )" ))) + ShowContextMenuForManagedReference(); - GUI.backgroundColor = storedColor; - EditorGUI.indentLevel = storedIndent; - } + GUI.backgroundColor = storedColor; + EditorGUI.indentLevel = storedIndent; + } - private (string AssemblyName, string ClassName) GetSplitNamesFromTypename(string typename) - { - if (string.IsNullOrEmpty(typename)) - return ("",""); + (string AssemblyName, string ClassName) GetSplitNamesFromTypename(string typename) + { + if (string.IsNullOrEmpty(typename)) + return ("",""); - var typeSplitString = typename.Split(char.Parse(" ")); - var typeClassName = typeSplitString[1]; - var typeAssemblyName = typeSplitString[0]; - return (typeAssemblyName, typeClassName); - } + var typeSplitString = typename.Split(char.Parse(" ")); + var typeClassName = typeSplitString[1]; + var typeAssemblyName = typeSplitString[0]; + return (typeAssemblyName, typeClassName); + } - private void ShowContextMenuForManagedReference(SerializedProperty property, IEnumerable> filters = null) - { - var context = new GenericMenu(); - FillContextMenu(filters, context, property); - context.ShowAsContext(); - } + void ShowContextMenuForManagedReference() + { + var context = new GenericMenu(); + FillContextMenu(context); + context.ShowAsContext(); + } - private void FillContextMenu(IEnumerable> enumerableFilters, GenericMenu contextMenu, SerializedProperty property) - { - var filters = new List>(); - if (enumerableFilters != null) filters.AddRange(enumerableFilters); + void FillContextMenu(GenericMenu contextMenu) + { + // Adds "Make Null" menu command + contextMenu.AddItem(new GUIContent("Null"), false, SetManagedReferenceToNull()); - // Adds "Make Null" menu command - contextMenu.AddItem(new GUIContent("Null"), false, SetManagedReferenceToNull(property)); + // Collects appropriate types + var appropriateTypes = GetAppropriateTypesForAssigningToManagedReference(); - // Collects appropriate types - var appropriateTypes = GetAppropriateTypesForAssigningToManagedReference(property, filters); + // Adds appropriate types to menu + foreach (var appropriateType in appropriateTypes) + AddItemToContextMenu(appropriateType, contextMenu); + } - // Adds appropriate types to menu - foreach (var appropriateType in appropriateTypes) - AddItemToContextMenu(appropriateType, contextMenu, property); - } + GenericMenu.MenuFunction SetManagedReferenceToNull() + { + return () => + { + property.serializedObject.Update(); + property.managedReferenceValue = null; + property.serializedObject.ApplyModifiedProperties(); + }; + } - private GenericMenu.MenuFunction SetManagedReferenceToNull(SerializedProperty serializedProperty) - { - return () => + void AddItemToContextMenu(Type type, GenericMenu genericMenuContext) + { + // it must have a BaseType + var assemblyName = type.BaseType.Assembly.ToString().Split('(', ',')[0]; + var entryName = type.BaseType.ToReadableName() + " ( " + assemblyName + " )"; + genericMenuContext.AddItem(new GUIContent(entryName), false, AssignNewInstanceCommand, new GenericMenuParameterForAssignInstanceCommand(type, property)); + } + + void AssignNewInstanceCommand(object objectGenericMenuParameter ) { + var parameter = (GenericMenuParameterForAssignInstanceCommand) objectGenericMenuParameter; + var type = parameter.Type; + var property = parameter.Property; + AssignNewInstanceOfTypeToManagedReference(property, type); + } + + object AssignNewInstanceOfTypeToManagedReference(SerializedProperty serializedProperty, Type type) + { + var instance = Activator.CreateInstance(type); + serializedProperty.serializedObject.Update(); - serializedProperty.managedReferenceValue = null; + serializedProperty.managedReferenceValue = instance; serializedProperty.serializedObject.ApplyModifiedProperties(); - }; - } - private void AddItemToContextMenu(Type type, GenericMenu genericMenuContext, SerializedProperty property) - { - // it must have a BaseType - var assemblyName = type.BaseType.Assembly.ToString().Split('(', ',')[0]; - var entryName = type.BaseType.ToReadableName() + " ( " + assemblyName + " )"; - genericMenuContext.AddItem(new GUIContent(entryName), false, AssignNewInstanceCommand, new GenericMenuParameterForAssignInstanceCommand(type, property)); - } + return instance; + } - private void AssignNewInstanceCommand(object objectGenericMenuParameter ) - { - var parameter = (GenericMenuParameterForAssignInstanceCommand) objectGenericMenuParameter; - var type = parameter.Type; - var property = parameter.Property; - AssignNewInstanceOfTypeToManagedReference(property, type); - } + IEnumerable GetAppropriateTypesForAssigningToManagedReference() + { + var fieldType = GetManagedReferenceFieldType(); + return GetAppropriateTypesForAssigningToManagedReferenceOfField(fieldType); + } - private object AssignNewInstanceOfTypeToManagedReference(SerializedProperty serializedProperty, Type type) - { - var instance = Activator.CreateInstance(type); + // Gets real type of managed reference + Type GetManagedReferenceFieldType() + { + var realPropertyType = GetRealTypeFromTypename(property.managedReferenceFieldTypename); + if (realPropertyType != null) + return realPropertyType; - serializedProperty.serializedObject.Update(); - serializedProperty.managedReferenceValue = instance; - serializedProperty.serializedObject.ApplyModifiedProperties(); + Debug.LogError($"Can not get field type of managed reference : {property.managedReferenceFieldTypename}"); + return null; + } - return instance; + // Gets real type of managed reference's field typeName + Type GetRealTypeFromTypename(string stringType) + { + var names = GetSplitNamesFromTypename(stringType); + var realType = Type.GetType($"{names.ClassName}, {names.AssemblyName}"); + return realType; + } + + IEnumerable GetAppropriateTypesForAssigningToManagedReferenceOfField(Type fieldType) + { + var appropriateTypes = new List(); + + var propertyType = ((GenericSerializeReferenceGeneratedFieldAttribute) this.attribute).PropertyType; + // Get and filter all appropriate types + var derivedTypes = TypeCache.GetTypesDerivedFrom(fieldType).Intersect(TypeCache.GetTypesDerivedFrom(propertyType)); + foreach (var type in derivedTypes) + { + // Skips unity engine Objects (because they are not serialized by SerializeReference) + if (type.IsSubclassOf(typeof(UnityEngine.Object))) + continue; + // Skip abstract classes because they should not be instantiated + if (type.IsAbstract) + continue; + // Skip types that has no public empty constructors (activator can not create them) + if (type.IsClass && type.GetConstructor(Type.EmptyTypes) == null) // Structs still can be created (strangely) + continue; + + appropriateTypes.Add(type); + } + + return appropriateTypes; + } } private readonly struct GenericMenuParameterForAssignInstanceCommand @@ -162,77 +209,5 @@ public GenericMenuParameterForAssignInstanceCommand(Type type, SerializedPropert public readonly SerializedProperty Property; public readonly Type Type; } - - private IEnumerable GetAppropriateTypesForAssigningToManagedReference(SerializedProperty property, List> filters = null) - { - var fieldType = GetManagedReferenceFieldType(property); - return GetAppropriateTypesForAssigningToManagedReference(fieldType, filters); - } - - /// Gets real type of managed reference - private Type GetManagedReferenceFieldType(SerializedProperty property) - { - var realPropertyType = GetRealTypeFromTypename(property.managedReferenceFieldTypename); - if (realPropertyType != null) - return realPropertyType; - - Debug.LogError($"Can not get field type of managed reference : {property.managedReferenceFieldTypename}"); - return null; - } - - /// Gets real type of managed reference's field typeName - private Type GetRealTypeFromTypename(string stringType) - { - var names = GetSplitNamesFromTypename(stringType); - var realType = Type.GetType($"{names.ClassName}, {names.AssemblyName}"); - return realType; - } - - private IEnumerable GetAppropriateTypesForAssigningToManagedReference(Type fieldType, List> filters = null) - { - var appropriateTypes = new List(); - - // Get and filter all appropriate types - var derivedTypes = TypeCache.GetTypesDerivedFrom(fieldType); - foreach (var type in derivedTypes) - { - // Skips unity engine Objects (because they are not serialized by SerializeReference) - if (type.IsSubclassOf(typeof(UnityEngine.Object))) - continue; - // Skip abstract classes because they should not be instantiated - if (type.IsAbstract) - continue; - // Skip types that has no public empty constructors (activator can not create them) - if (type.IsClass && type.GetConstructor(Type.EmptyTypes) == null) // Structs still can be created (strangely) - continue; - // Filter types by provided filters if there is ones - if (filters != null && filters.All(f => f == null || f.Invoke(type)) == false) - continue; - - appropriateTypes.Add(type); - } - - return appropriateTypes; - } - // - // private IEnumerable> GetAllBuiltInTypeRestrictions(FieldInfo fieldInfo) - // { - // var result = new List>(); - // - // var attributeObjects = fieldInfo.GetCustomAttributes(false); - // foreach (var attributeObject in attributeObjects) - // { - // switch (attributeObject) - // { - // case SerializeReferenceUIRestrictionIncludeTypes includeTypes: - // result.Add(SerializeReferenceTypeRestrictionFilters.TypeIsSubclassOrEqualOrHasInterface(includeTypes.Types)); - // continue; - // case SerializeReferenceUIRestrictionExcludeTypes excludeTypes: - // result.Add(SerializeReferenceTypeRestrictionFilters.TypeIsNotSubclassOrEqualOrHasInterface(excludeTypes.Types)); - // continue; - // } - // } - // return result; - // } } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs index 0e0c305..e5fad54 100644 --- a/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs +++ b/Packages/generic-serialize-reference/Editor/GenericSerializeReferencePostProcessor.cs @@ -74,7 +74,6 @@ private bool Process(ModuleDefinition module, TypeTree typeTree, ILPostProcessor from type in module.GetAllTypes() where type.IsClass && !type.IsAbstract from property in type.Properties.ToArray() // able to change `Properties` during looping - where property.PropertyType.IsGenericInstance from attribute in property.GetAttributesOf() select (type, property, attribute) ) @@ -91,14 +90,24 @@ from attribute in property.GetAttributesOf() continue; } - var wrapperName = $"<{property.Name}>__generic_serialize_reference"; - var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); - var serializedFieldInterface = CreateInterface(wrapper); - CreateDerivedClasses(property, wrapper, serializedFieldInterface); + TypeReference baseInterface; + var mode = (GenerateMode)attribute.ConstructorArguments[1].Value; + if (mode == GenerateMode.Embed) + { + var wrapperName = $"<{property.Name}>__generic_serialize_reference"; + var wrapper = property.DeclaringType.CreateNestedStaticPrivateClass(wrapperName); + baseInterface = CreateInterface(wrapper); + CreateDerivedClasses(property, wrapper, baseInterface); + } + else + { + baseInterface = module.ImportReference(typeof(IBase)); + } - logger.Info($"generate nested class with interface {serializedFieldInterface.FullName}"); + logger.Info($"generate nested class with interface {baseInterface.FullName}"); var fieldNamePrefix = (string)attribute.ConstructorArguments[0].Value; - GenerateField(module, property, serializedFieldInterface, fieldNamePrefix); + GenerateField(module, property, baseInterface, fieldNamePrefix); + modified = true; } return modified; @@ -115,7 +124,7 @@ TypeDefinition CreateInterface(TypeDefinition wrapper, string interfaceName = "I return baseInterface; } - void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, TypeDefinition baseInterface) + void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, TypeReference baseInterface) { logger.Debug($"get derived {property.PropertyType.Module} {property.PropertyType} {property.PropertyType.Resolve()}"); foreach (var derived in typeTree.GetOrCreateAllDerivedReference(property.PropertyType)) @@ -145,7 +154,7 @@ void CreateDerivedClasses(PropertyDefinition property, TypeDefinition wrapper, T internal static void GenerateField( ModuleDefinition module, PropertyDefinition property, - TypeDefinition fieldType, + TypeReference fieldType, string fieldNamePrefix) { var serializedField = CreateSerializeReferenceField(module, property, fieldType, fieldNamePrefix); @@ -168,7 +177,8 @@ internal static FieldDefinition CreateSerializeReferenceField( , @interface ); serializedField.AddCustomAttribute(module); - serializedField.AddCustomAttribute(module); + var attribute = serializedField.AddCustomAttribute(module, typeof(Type)); + attribute.ConstructorArguments.Add(new CustomAttributeArgument(module.ImportReference(typeof(Type)), property.PropertyType)); property.DeclaringType.Fields.Add(serializedField); return serializedField; } diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs index 8b44bec..520a402 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceAttribute.cs @@ -2,9 +2,13 @@ namespace GenericSerializeReference { + public enum GenerateMode { Embed, AssemblyCSharp } + [AttributeUsage(AttributeTargets.Property)] public class GenericSerializeReferenceAttribute : Attribute { - public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__") {} + public const int FIELD_PREFIX_INDEX = 0; + public const int MODE_PREFIX = 1; + public GenericSerializeReferenceAttribute(string serializedFieldPrefix = "__", GenerateMode mode = GenerateMode.AssemblyCSharp) {} } } \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs index b8a9806..3af2317 100644 --- a/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs +++ b/Packages/generic-serialize-reference/Runtime/GenericSerializeReferenceGeneratedFieldAttribute.cs @@ -8,5 +8,9 @@ namespace GenericSerializeReference { [AttributeUsage(AttributeTargets.Field)] - internal class GenericSerializeReferenceGeneratedFieldAttribute : PropertyAttribute {} + internal class GenericSerializeReferenceGeneratedFieldAttribute : PropertyAttribute + { + public Type PropertyType { get; } + public GenericSerializeReferenceGeneratedFieldAttribute(Type propertyType) => PropertyType = propertyType; + } } diff --git a/Packages/generic-serialize-reference/Runtime/IBase.cs b/Packages/generic-serialize-reference/Runtime/IBase.cs new file mode 100644 index 0000000..a5f7410 --- /dev/null +++ b/Packages/generic-serialize-reference/Runtime/IBase.cs @@ -0,0 +1,4 @@ +namespace GenericSerializeReference +{ + public interface IBase {} +} \ No newline at end of file diff --git a/Packages/generic-serialize-reference/Runtime/IBase.cs.meta b/Packages/generic-serialize-reference/Runtime/IBase.cs.meta new file mode 100644 index 0000000..6b09ab5 --- /dev/null +++ b/Packages/generic-serialize-reference/Runtime/IBase.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 17e90c5379eb45488acdb0e64b044392 +timeCreated: 1625411010 \ No newline at end of file diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 79014f0..17bae5a 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -8,15 +8,6 @@ "com.unity.nuget.mono-cecil": "1.10.1" } }, - "com.quabug.generic-serialize-reference-library-codegen": { - "version": "file:generic-serialize-reference-library-gen", - "depth": 0, - "source": "embedded", - "dependencies": { - "com.unity.nuget.mono-cecil": "0.1.6-preview.2", - "com.quabug.generic-serialize-reference": "1.2.0" - } - }, "com.unity.ext.nunit": { "version": "1.0.6", "depth": 1, From 41c05ca6eeccd18966262bd93b9c7b22a6bb08db Mon Sep 17 00:00:00 2001 From: quabug Date: Mon, 5 Jul 2021 00:51:58 +0800 Subject: [PATCH 13/13] add debug logs --- Assets/Sample/GenericSerializeReference.Sample.asmdef | 2 +- .../GenericSerializeReference.Sample.Library.asmdef | 3 +-- Assets/Sample/Library/Implement/Implement.cs | 1 + ...ericSerializeReference.Sample.Library.Interface.asmdef | 4 +--- Assets/Sample/Library/LibBehavior.cs | 7 +++++++ Assets/Sample/MyMonoBehavior.cs | 6 ++++++ ProjectSettings/EditorBuildSettings.asset | 5 ++++- ProjectSettings/ProjectSettings.asset | 8 +++++++- 8 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Assets/Sample/GenericSerializeReference.Sample.asmdef b/Assets/Sample/GenericSerializeReference.Sample.asmdef index ec08cd8..a727630 100644 --- a/Assets/Sample/GenericSerializeReference.Sample.asmdef +++ b/Assets/Sample/GenericSerializeReference.Sample.asmdef @@ -10,7 +10,7 @@ "allowUnsafeCode": false, "overrideReferences": true, "precompiledReferences": [], - "autoReferenced": false, + "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false diff --git a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef index 8b94415..8ae996e 100644 --- a/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef +++ b/Assets/Sample/Library/GenericSerializeReference.Sample.Library.asmdef @@ -3,8 +3,7 @@ "rootNamespace": "", "references": [ "GUID:e68bcd447d2cc4be2b6d31311e6ca7e9", - "GUID:bb7127c6ea4789d41b77cdef13d93652", - "GUID:535461a790301fe4fa3992f73817cb6f" + "GUID:bb7127c6ea4789d41b77cdef13d93652" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Sample/Library/Implement/Implement.cs b/Assets/Sample/Library/Implement/Implement.cs index c74074b..b545a2d 100644 --- a/Assets/Sample/Library/Implement/Implement.cs +++ b/Assets/Sample/Library/Implement/Implement.cs @@ -1,3 +1,4 @@ public class LibIntObject : ILibInterface {} public class LibGenericObject : ILibInterface {} public class LibGenericObject_2 : ILibInterface {} +public class LibFloatObject : ILibInterface {} diff --git a/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef index d430408..3903225 100644 --- a/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef +++ b/Assets/Sample/Library/Interface/GenericSerializeReference.Sample.Library.Interface.asmdef @@ -1,9 +1,7 @@ { "name": "GenericSerializeReference.Sample.Library.Interface", "rootNamespace": "", - "references": [ - "GUID:535461a790301fe4fa3992f73817cb6f" - ], + "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, diff --git a/Assets/Sample/Library/LibBehavior.cs b/Assets/Sample/Library/LibBehavior.cs index 82ae87a..ac957d5 100644 --- a/Assets/Sample/Library/LibBehavior.cs +++ b/Assets/Sample/Library/LibBehavior.cs @@ -1,3 +1,4 @@ +using System; using GenericSerializeReference; using UnityEngine; @@ -9,4 +10,10 @@ public class LibBehavior : MonoBehaviour [GenericSerializeReference(mode: GenerateMode.AssemblyCSharp)] public ILibInterface Float { get; set; } + + private void Awake() + { + Debug.Log($"{nameof(LibBehavior)}.{nameof(Int)} is {Int.GetType()}"); + Debug.Log($"{nameof(LibBehavior)}.{nameof(Float)} is {Float.GetType()}"); + } } diff --git a/Assets/Sample/MyMonoBehavior.cs b/Assets/Sample/MyMonoBehavior.cs index 676d63c..1c735ae 100644 --- a/Assets/Sample/MyMonoBehavior.cs +++ b/Assets/Sample/MyMonoBehavior.cs @@ -1,3 +1,4 @@ +using System; using GenericSerializeReference; using UnityEngine; @@ -13,4 +14,9 @@ public class MyMonoBehavior : MonoBehaviour // [GenericSerializeReference("_serialized")] // public IMyInterface Foo { get; set; } // private int __Foo; + + private void Awake() + { + Debug.Log($"{name}.{nameof(Value)} is {Value.GetType()}"); + } } \ No newline at end of file diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index 0147887..cad91f3 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -4,5 +4,8 @@ EditorBuildSettings: m_ObjectHideFlags: 0 serializedVersion: 2 - m_Scenes: [] + m_Scenes: + - enabled: 1 + path: Assets/Sample/Test.unity + guid: 0a484f69d999d4c6997ce7aa86edc14d m_configObjects: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 9c1f134..8a9eb39 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -93,7 +93,7 @@ PlayerSettings: xboxEnableFitness: 0 visibleInBackground: 1 allowFullscreenSwitch: 1 - fullscreenMode: 1 + fullscreenMode: 0 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 xboxEnableGuest: 0 @@ -371,6 +371,7 @@ PlayerSettings: switchTitleNames_12: switchTitleNames_13: switchTitleNames_14: + switchTitleNames_15: switchPublisherNames_0: switchPublisherNames_1: switchPublisherNames_2: @@ -386,6 +387,7 @@ PlayerSettings: switchPublisherNames_12: switchPublisherNames_13: switchPublisherNames_14: + switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} @@ -401,6 +403,7 @@ PlayerSettings: switchIcons_12: {fileID: 0} switchIcons_13: {fileID: 0} switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} switchSmallIcons_0: {fileID: 0} switchSmallIcons_1: {fileID: 0} switchSmallIcons_2: {fileID: 0} @@ -416,6 +419,7 @@ PlayerSettings: switchSmallIcons_12: {fileID: 0} switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} switchManualHTML: switchAccessibleURLs: switchLegalInformation: @@ -479,6 +483,8 @@ PlayerSettings: switchNetworkInterfaceManagerInitializeEnabled: 1 switchPlayerConnectionEnabled: 1 switchUseNewStyleFilepaths: 0 + switchUseMicroSleepForYield: 1 + switchMicroSleepForYieldTime: 25 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: