From 7ae59bfab7e0a2415beff019363cd0f9f0ac6724 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 27 Oct 2024 00:01:16 +0900 Subject: [PATCH 1/6] Add Example_Contravariance --- Assets/Example/Example_Contravariance.cs | 23 +++++++++++++++++++ Assets/Example/Example_Contravariance.cs.meta | 11 +++++++++ 2 files changed, 34 insertions(+) create mode 100644 Assets/Example/Example_Contravariance.cs create mode 100644 Assets/Example/Example_Contravariance.cs.meta diff --git a/Assets/Example/Example_Contravariance.cs b/Assets/Example/Example_Contravariance.cs new file mode 100644 index 0000000..c264ed5 --- /dev/null +++ b/Assets/Example/Example_Contravariance.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public interface IActor { } +public interface IStandardActor : IActor { } +public interface INetworkActor : IActor { } +public interface IAction where T : IActor { } + +public interface IActorAction : IAction { } +public interface IStandardActorAction : IAction { } +public interface INetworkActorAction : IAction { } + +[Serializable] +public sealed class NetworkActorAction : INetworkActorAction { } + +public class Example_Contravariance : MonoBehaviour +{ + + [SerializeReference, SubclassSelector] + public List> actions = new List>(); + +} diff --git a/Assets/Example/Example_Contravariance.cs.meta b/Assets/Example/Example_Contravariance.cs.meta new file mode 100644 index 0000000..e533ce3 --- /dev/null +++ b/Assets/Example/Example_Contravariance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dff76005e1dfac84287448b12c4b160e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 105f461ba8c17f69a0fc8afa8e3c963504637f3e Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 27 Oct 2024 14:56:48 +0900 Subject: [PATCH 2/6] Update generics example --- Assets/Example/Example_Contravariance.cs | 23 ----- Assets/Example/Example_Generics.cs | 93 +++++++++++++++++++ ...iance.cs.meta => Example_Generics.cs.meta} | 0 3 files changed, 93 insertions(+), 23 deletions(-) delete mode 100644 Assets/Example/Example_Contravariance.cs create mode 100644 Assets/Example/Example_Generics.cs rename Assets/Example/{Example_Contravariance.cs.meta => Example_Generics.cs.meta} (100%) diff --git a/Assets/Example/Example_Contravariance.cs b/Assets/Example/Example_Contravariance.cs deleted file mode 100644 index c264ed5..0000000 --- a/Assets/Example/Example_Contravariance.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -public interface IActor { } -public interface IStandardActor : IActor { } -public interface INetworkActor : IActor { } -public interface IAction where T : IActor { } - -public interface IActorAction : IAction { } -public interface IStandardActorAction : IAction { } -public interface INetworkActorAction : IAction { } - -[Serializable] -public sealed class NetworkActorAction : INetworkActorAction { } - -public class Example_Contravariance : MonoBehaviour -{ - - [SerializeReference, SubclassSelector] - public List> actions = new List>(); - -} diff --git a/Assets/Example/Example_Generics.cs b/Assets/Example/Example_Generics.cs new file mode 100644 index 0000000..bc4f604 --- /dev/null +++ b/Assets/Example/Example_Generics.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public interface IActor { } +public interface IStandardActor : IActor { } +public interface INetworkActor : IActor { } + +public interface IContravarianceAction where T : IActor { + void DoAction (T actor); +} + +public interface ICovarianceAction where T : IActor +{ + T Actor { get; } +} + +public interface IActorAction : IContravarianceAction, ICovarianceAction { } +public interface IStandardActorAction : IContravarianceAction, ICovarianceAction { } +public interface INetworkActorAction : IContravarianceAction, ICovarianceAction { } + +[Serializable] +public sealed class StandardActorAction : IContravarianceAction, ICovarianceAction +{ + public void DoAction (IStandardActor actor) + { + } + public IStandardActor Actor => null; +} + +[Serializable] +public sealed class ActorAction : IContravarianceAction, ICovarianceAction +{ + public void DoAction (IActor actor) + { + } + public IActor Actor => null; +} + +[Serializable] +public abstract class BaseAction : IContravarianceAction, ICovarianceAction where T : IActor +{ + public void DoAction (T actor) { + } + public T Actor => default; +} + +[Serializable] +public sealed class DerivedAction1 : BaseAction { } + +[Serializable] +public sealed class DerivedAction2 : BaseAction { } + +[Serializable] +public sealed class DerivedAction3 : BaseAction { } + +[Serializable] +public sealed class NetworkActorAction1 : INetworkActorAction +{ + public void DoAction (INetworkActor actor) + { + } + public INetworkActor Actor => null; +} + +[Serializable] +public sealed class NetworkActorAction2 : IContravarianceAction, ICovarianceAction +{ + public void DoAction (INetworkActor actor) + { + } + public INetworkActor Actor => null; +} + +[Serializable] +public sealed class NetworkActorAction3 : IContravarianceAction, ICovarianceAction +{ + public void DoAction (IActor actor) + { + } + public IActor Actor => null; +} + +public class Example_Generics : MonoBehaviour +{ + + [SerializeReference, SubclassSelector] + public List> contravarianceActions = new List>(); + + [SerializeReference, SubclassSelector] + public List> covarianceActions = new List>(); + +} diff --git a/Assets/Example/Example_Contravariance.cs.meta b/Assets/Example/Example_Generics.cs.meta similarity index 100% rename from Assets/Example/Example_Contravariance.cs.meta rename to Assets/Example/Example_Generics.cs.meta From 25350f7036a64f389547b4a0290e9982f1aaae08 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 27 Oct 2024 14:57:23 +0900 Subject: [PATCH 3/6] Implement TypeSearch with generics --- .../Editor/SubclassSelectorDrawer.cs | 2 +- .../Editor/TypeMenuUtility.cs | 16 +- .../Editor/TypeSearch.cs | 142 ++++++++++++++++++ .../Editor/TypeSearch.cs.meta | 2 + 4 files changed, 147 insertions(+), 15 deletions(-) create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs create mode 100644 Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs index 8c0e3f3..b99588f 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/SubclassSelectorDrawer.cs @@ -141,7 +141,7 @@ namespace MackySoft.SerializeReferenceExtensions.Editor Type baseType = ManagedReferenceUtility.GetType(managedReferenceFieldTypename); var popup = new AdvancedTypePopup( - TypeMenuUtility.GetTypes(baseType), + TypeSearch.GetTypes(baseType), k_MaxTypePopupLineCount, state ); diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs index 28d74b3..354d9d4 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeMenuUtility.cs @@ -3,23 +3,11 @@ using System.Linq; using System.Collections.Generic; using UnityEditor; -namespace MackySoft.SerializeReferenceExtensions.Editor { +namespace MackySoft.SerializeReferenceExtensions.Editor +{ public static class TypeMenuUtility { public const string k_NullDisplayName = ""; - static readonly Type k_UnityObjectType = typeof(UnityEngine.Object); - - public static IEnumerable GetTypes (Type baseType) - { - return TypeCache.GetTypesDerivedFrom(baseType).Append(baseType).Where(p => - (p.IsPublic || p.IsNestedPublic || p.IsNestedPrivate) && - !p.IsAbstract && - !p.IsGenericType && - !k_UnityObjectType.IsAssignableFrom(p) && - Attribute.IsDefined(p, typeof(SerializableAttribute)) && - !Attribute.IsDefined(p, typeof(HideInTypeMenuAttribute)) - ); - } public static AddTypeMenuAttribute GetAttribute (Type type) { return Attribute.GetCustomAttribute(type,typeof(AddTypeMenuAttribute)) as AddTypeMenuAttribute; diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs new file mode 100644 index 0000000..75009cf --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs @@ -0,0 +1,142 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using UnityEditor; +using System.Reflection; + +namespace MackySoft.SerializeReferenceExtensions.Editor +{ + public static class TypeSearch + { + +#if UNITY_2023_2_OR_NEWER + static readonly Dictionary> m_TypeCache = new Dictionary>(); +#endif + + public static IEnumerable GetTypes (Type baseType) + { +#if UNITY_2023_2_OR_NEWER + // NOTE: This is a workaround for Unity 2023.2 and later. + // 2023.2 because SerializeReference supports generic type instances and because the behaviour is stable. + if (baseType.IsGenericType) + { + return GetTypesWithGeneric(baseType); + } + else + { + return GetTypesUsingTypeCache(baseType); + } +#else + return GetTypesWithGeneric(baseType); +#endif + } + + static IEnumerable GetTypesUsingTypeCache (Type baseType) + { + return TypeCache.GetTypesDerivedFrom(baseType) + .Append(baseType) + .Where(IsValidType); + } + +#if UNITY_2023_2_OR_NEWER + static IEnumerable GetTypesWithGeneric (Type baseType) + { + if (m_TypeCache.TryGetValue(baseType, out List result)) + { + return result; + } + + result = new List(); + Type genericTypeDefinition = null; + Type[] targetTypeArguments = null; + Type[] genericTypeParameters = null; + + if (baseType.IsGenericType) + { + genericTypeDefinition = baseType.GetGenericTypeDefinition(); + targetTypeArguments = baseType.GetGenericArguments(); + genericTypeParameters = genericTypeDefinition.GetGenericArguments(); + } + else + { + genericTypeDefinition = baseType; + targetTypeArguments = Type.EmptyTypes; + genericTypeParameters = Type.EmptyTypes; + } + + IEnumerable types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(x => x.GetTypes()) + .Where(IsValidType); + + foreach (Type type in types) + { + Type[] interfaceTypes = type.GetInterfaces(); + foreach (Type interfaceType in interfaceTypes) + { + if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != genericTypeDefinition) + { + continue; + } + + Type[] sourceTypeArguments = interfaceType.GetGenericArguments(); + + bool allParametersMatch = true; + + for (int i = 0; i < genericTypeParameters.Length; i++) + { + var variance = genericTypeParameters[i].GenericParameterAttributes & GenericParameterAttributes.VarianceMask; + + Type sourceTypeArgument = sourceTypeArguments[i]; + Type targetTypeArgument = targetTypeArguments[i]; + + if (variance == GenericParameterAttributes.Contravariant) + { + if (!sourceTypeArgument.IsAssignableFrom(targetTypeArgument)) + { + allParametersMatch = false; + break; + } + } + else if (variance == GenericParameterAttributes.Covariant) + { + if (!targetTypeArgument.IsAssignableFrom(sourceTypeArgument)) + { + allParametersMatch = false; + break; + } + } + else + { + if (sourceTypeArgument != targetTypeArgument) + { + allParametersMatch = false; + break; + } + } + } + + if (allParametersMatch) + { + result.Add(type); + break; + } + } + } + + m_TypeCache.Add(baseType, result); + return result; + } +#endif + + static bool IsValidType (Type type) + { + return + (type.IsPublic || type.IsNestedPublic || type.IsNestedPrivate) && + !type.IsAbstract && + !type.IsGenericType && + !typeof(UnityEngine.Object).IsAssignableFrom(type) && + Attribute.IsDefined(type, typeof(SerializableAttribute)) && + !Attribute.IsDefined(type, typeof(HideInTypeMenuAttribute)); + } + } +} \ No newline at end of file diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta new file mode 100644 index 0000000..4198c09 --- /dev/null +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5ea24172520aa2646954c1d246e7ba5d \ No newline at end of file From 5ee76f7a92f5e2dd7de2d7caf83ef2bae29dd871 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 27 Oct 2024 14:57:26 +0900 Subject: [PATCH 4/6] Update Example.unity --- Assets/Example/Example.unity | 96 ++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/Assets/Example/Example.unity b/Assets/Example/Example.unity index 50af01c..09287f1 100644 --- a/Assets/Example/Example.unity +++ b/Assets/Example/Example.unity @@ -13,7 +13,7 @@ OcclusionCullingSettings: --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 - serializedVersion: 9 + serializedVersion: 10 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 @@ -38,13 +38,12 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 - m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 m_BounceScale: 1 @@ -67,9 +66,6 @@ LightmapSettings: m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 @@ -104,7 +100,7 @@ NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: - serializedVersion: 2 + serializedVersion: 3 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 @@ -117,7 +113,7 @@ NavMeshSettings: cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 - accuratePlacement: 0 + buildHeightMesh: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: @@ -163,9 +159,17 @@ Camera: m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 x: 0 @@ -199,13 +203,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 126803971} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 1, z: -10} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &586792171 GameObject: @@ -326,13 +330,70 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 586792171} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &994260143 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 994260145} + - component: {fileID: 994260144} + m_Layer: 0 + m_Name: Example_Generics + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &994260144 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 994260143} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dff76005e1dfac84287448b12c4b160e, type: 3} + m_Name: + m_EditorClassIdentifier: + contravarianceActions: + - rid: 3354424774140624943 + covarianceActions: + - rid: 3354424774140624944 + references: + version: 2 + RefIds: + - rid: 3354424774140624943 + type: {class: DerivedAction1, ns: , asm: Assembly-CSharp} + data: + - rid: 3354424774140624944 + type: {class: NetworkActorAction1, ns: , asm: Assembly-CSharp} + data: +--- !u!4 &994260145 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 994260143} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1127138992 GameObject: @@ -359,9 +420,8 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1127138992} m_Enabled: 1 - serializedVersion: 10 + serializedVersion: 11 m_Type: 1 - m_Shape: 0 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 @@ -420,11 +480,19 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1127138992} + serializedVersion: 2 m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 126803974} + - {fileID: 1127138994} + - {fileID: 586792173} + - {fileID: 994260145} From edbbe60a6b1f817edaf9e9da47bd1641be6f6c8f Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 27 Oct 2024 15:55:21 +0900 Subject: [PATCH 5/6] Update TypeSearch.cs --- .../MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs index 75009cf..4debaa4 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs @@ -16,7 +16,7 @@ namespace MackySoft.SerializeReferenceExtensions.Editor public static IEnumerable GetTypes (Type baseType) { #if UNITY_2023_2_OR_NEWER - // NOTE: This is a workaround for Unity 2023.2 and later. + // NOTE: This is a generics solution for Unity 2023.2 and later. // 2023.2 because SerializeReference supports generic type instances and because the behaviour is stable. if (baseType.IsGenericType) { From 0bbb71686447f720d581bac1da2614b1e3cc5406 Mon Sep 17 00:00:00 2001 From: Makihiro Date: Sun, 27 Oct 2024 15:57:50 +0900 Subject: [PATCH 6/6] Fix error --- .../MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs index 4debaa4..7b6bd97 100644 --- a/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs +++ b/Assets/MackySoft/MackySoft.SerializeReferenceExtensions/Editor/TypeSearch.cs @@ -27,7 +27,7 @@ namespace MackySoft.SerializeReferenceExtensions.Editor return GetTypesUsingTypeCache(baseType); } #else - return GetTypesWithGeneric(baseType); + return GetTypesUsingTypeCache(baseType); #endif }