// SDK Info|Utilities|90040 namespace VRTK { using UnityEngine; using System; using System.Collections.Generic; using System.Linq; /// /// Holds all the info necessary to describe an SDK. /// [Serializable] public sealed class VRTK_SDKInfo : ISerializationCallbackReceiver { /// /// The type of the SDK. /// public Type type { get; private set; } /// /// The name of the type of which this SDK info was created from. This is only used if said type wasn't found. /// public string originalTypeNameWhenFallbackIsUsed { get; private set; } /// /// The description of the SDK. /// public SDK_DescriptionAttribute description { get; private set; } [SerializeField] private string baseTypeName; [SerializeField] private string fallbackTypeName; [SerializeField] private string typeName; [SerializeField] private int descriptionIndex; /// /// Creates new SDK infos for a type that is known at compile time. /// /// The SDK base type. Must be a subclass of SDK_Base. /// The SDK type to fall back on if problems occur. Must be a subclass of `BaseType`. /// The SDK type to use. Must be a subclass of `BaseType`. /// Multiple newly created instances. public static VRTK_SDKInfo[] Create() where BaseType : SDK_Base where FallbackType : BaseType where ActualType : BaseType { return Create(typeof(ActualType)); } /// /// Creates new SDK infos for a type. /// /// The SDK base type. Must be a subclass of SDK_Base. /// The SDK type to fall back on if problems occur. Must be a subclass of `BaseType. /// The SDK type to use. Must be a subclass of `BaseType. /// Multiple newly created instances. public static VRTK_SDKInfo[] Create(Type actualType) where BaseType : SDK_Base where FallbackType : BaseType { string actualTypeName = actualType.FullName; SDK_DescriptionAttribute[] descriptions = SDK_DescriptionAttribute.GetDescriptions(actualType); if (descriptions.Length == 0) { VRTK_Logger.Fatal(string.Format("'{0}' doesn't specify any SDK descriptions via '{1}'.", actualTypeName, typeof(SDK_DescriptionAttribute).Name)); return new VRTK_SDKInfo[0]; } HashSet sdkInfos = new HashSet(); foreach (SDK_DescriptionAttribute description in descriptions) { VRTK_SDKInfo sdkInfo = new VRTK_SDKInfo(); sdkInfo.SetUp(typeof(BaseType), typeof(FallbackType), actualTypeName, description.index); sdkInfos.Add(sdkInfo); } return sdkInfos.ToArray(); } private VRTK_SDKInfo() { } /// /// Creates a new SDK info by copying an existing one. /// /// The SDK info to copy. public VRTK_SDKInfo(VRTK_SDKInfo infoToCopy) { SetUp(Type.GetType(infoToCopy.baseTypeName), Type.GetType(infoToCopy.fallbackTypeName), infoToCopy.typeName, infoToCopy.descriptionIndex); } private void SetUp(Type baseType, Type fallbackType, string actualTypeName, int descriptionIndex) { if (baseType == null || fallbackType == null) return; if (!VRTK_SharedMethods.IsTypeSubclassOf(baseType, typeof(SDK_Base))) { VRTK_Logger.Fatal(new ArgumentOutOfRangeException("baseType", baseType, string.Format("'{0}' is not a subclass of the SDK base type '{1}'.", baseType.Name, typeof(SDK_Base).Name))); return; } if (!VRTK_SharedMethods.IsTypeSubclassOf(fallbackType, baseType)) { VRTK_Logger.Fatal(new ArgumentOutOfRangeException("fallbackType", fallbackType, string.Format("'{0}' is not a subclass of the SDK base type '{1}'.", fallbackType.Name, baseType.Name))); return; } baseTypeName = baseType.FullName; fallbackTypeName = fallbackType.FullName; typeName = actualTypeName; if (string.IsNullOrEmpty(actualTypeName)) { type = fallbackType; originalTypeNameWhenFallbackIsUsed = null; this.descriptionIndex = -1; description = new SDK_DescriptionAttribute(typeof(SDK_FallbackSystem)); return; } Type actualType = Type.GetType(actualTypeName); if (actualType == null) { type = fallbackType; originalTypeNameWhenFallbackIsUsed = actualTypeName; this.descriptionIndex = -1; description = new SDK_DescriptionAttribute(typeof(SDK_FallbackSystem)); VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SDK_NOT_FOUND, actualTypeName, fallbackType.Name)); return; } if (!VRTK_SharedMethods.IsTypeSubclassOf(actualType, baseType)) { VRTK_Logger.Fatal(new ArgumentOutOfRangeException("actualTypeName", actualTypeName, string.Format("'{0}' is not a subclass of the SDK base type '{1}'.", actualTypeName, baseType.Name))); return; } SDK_DescriptionAttribute[] descriptions = SDK_DescriptionAttribute.GetDescriptions(actualType); if (descriptions.Length <= descriptionIndex) { VRTK_Logger.Fatal(new ArgumentOutOfRangeException("descriptionIndex", descriptionIndex, string.Format("'{0}' has no '{1}' at that index.", actualTypeName, typeof(SDK_DescriptionAttribute).Name))); return; } type = actualType; originalTypeNameWhenFallbackIsUsed = null; this.descriptionIndex = descriptionIndex; description = descriptions[descriptionIndex]; } #region ISerializationCallbackReceiver public void OnBeforeSerialize() { } public void OnAfterDeserialize() { SetUp(Type.GetType(baseTypeName), Type.GetType(fallbackTypeName), typeName, descriptionIndex); } #endregion #region Equality via type and descriptionIndex public override bool Equals(object obj) { VRTK_SDKInfo other = obj as VRTK_SDKInfo; if ((object)other == null) { return false; } return this == other; } public bool Equals(VRTK_SDKInfo other) { return this == other; } public override int GetHashCode() { return type.GetHashCode(); } public static bool operator ==(VRTK_SDKInfo x, VRTK_SDKInfo y) { if (ReferenceEquals(x, y)) { return true; } if ((object)x == null || (object)y == null) { return false; } return x.type == y.type && x.descriptionIndex == y.descriptionIndex; } public static bool operator !=(VRTK_SDKInfo x, VRTK_SDKInfo y) { return !(x == y); } #endregion } }