Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
7.9 KiB

  1. // SDK Info|Utilities|90040
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. /// <summary>
  9. /// Holds all the info necessary to describe an SDK.
  10. /// </summary>
  11. [Serializable]
  12. public sealed class VRTK_SDKInfo : ISerializationCallbackReceiver
  13. {
  14. /// <summary>
  15. /// The type of the SDK.
  16. /// </summary>
  17. public Type type { get; private set; }
  18. /// <summary>
  19. /// The name of the type of which this SDK info was created from. This is only used if said type wasn't found.
  20. /// </summary>
  21. public string originalTypeNameWhenFallbackIsUsed { get; private set; }
  22. /// <summary>
  23. /// The description of the SDK.
  24. /// </summary>
  25. public SDK_DescriptionAttribute description { get; private set; }
  26. [SerializeField]
  27. private string baseTypeName;
  28. [SerializeField]
  29. private string fallbackTypeName;
  30. [SerializeField]
  31. private string typeName;
  32. [SerializeField]
  33. private int descriptionIndex;
  34. /// <summary>
  35. /// Creates new SDK infos for a type that is known at compile time.
  36. /// </summary>
  37. /// <typeparam name="BaseType">The SDK base type. Must be a subclass of SDK_Base.</typeparam>
  38. /// <typeparam name="FallbackType">The SDK type to fall back on if problems occur. Must be a subclass of `BaseType`.</typeparam>
  39. /// <typeparam name="ActualType">The SDK type to use. Must be a subclass of `BaseType`.</typeparam>
  40. /// <returns>Multiple newly created instances.</returns>
  41. public static VRTK_SDKInfo[] Create<BaseType, FallbackType, ActualType>() where BaseType : SDK_Base where FallbackType : BaseType where ActualType : BaseType
  42. {
  43. return Create<BaseType, FallbackType>(typeof(ActualType));
  44. }
  45. /// <summary>
  46. /// Creates new SDK infos for a type.
  47. /// </summary>
  48. /// <typeparam name="BaseType">The SDK base type. Must be a subclass of SDK_Base.</typeparam>
  49. /// <typeparam name="FallbackType">The SDK type to fall back on if problems occur. Must be a subclass of `BaseType.</typeparam>
  50. /// <param name="actualType">The SDK type to use. Must be a subclass of `BaseType.</param>
  51. /// <returns>Multiple newly created instances.</returns>
  52. public static VRTK_SDKInfo[] Create<BaseType, FallbackType>(Type actualType) where BaseType : SDK_Base where FallbackType : BaseType
  53. {
  54. string actualTypeName = actualType.FullName;
  55. SDK_DescriptionAttribute[] descriptions = SDK_DescriptionAttribute.GetDescriptions(actualType);
  56. if (descriptions.Length == 0)
  57. {
  58. VRTK_Logger.Fatal(string.Format("'{0}' doesn't specify any SDK descriptions via '{1}'.", actualTypeName, typeof(SDK_DescriptionAttribute).Name));
  59. return new VRTK_SDKInfo[0];
  60. }
  61. HashSet<VRTK_SDKInfo> sdkInfos = new HashSet<VRTK_SDKInfo>();
  62. foreach (SDK_DescriptionAttribute description in descriptions)
  63. {
  64. VRTK_SDKInfo sdkInfo = new VRTK_SDKInfo();
  65. sdkInfo.SetUp(typeof(BaseType), typeof(FallbackType), actualTypeName, description.index);
  66. sdkInfos.Add(sdkInfo);
  67. }
  68. return sdkInfos.ToArray();
  69. }
  70. private VRTK_SDKInfo()
  71. {
  72. }
  73. /// <summary>
  74. /// Creates a new SDK info by copying an existing one.
  75. /// </summary>
  76. /// <param name="infoToCopy">The SDK info to copy.</param>
  77. public VRTK_SDKInfo(VRTK_SDKInfo infoToCopy)
  78. {
  79. SetUp(Type.GetType(infoToCopy.baseTypeName),
  80. Type.GetType(infoToCopy.fallbackTypeName),
  81. infoToCopy.typeName,
  82. infoToCopy.descriptionIndex);
  83. }
  84. private void SetUp(Type baseType, Type fallbackType, string actualTypeName, int descriptionIndex)
  85. {
  86. if (baseType == null || fallbackType == null)
  87. return;
  88. if (!VRTK_SharedMethods.IsTypeSubclassOf(baseType, typeof(SDK_Base)))
  89. {
  90. 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)));
  91. return;
  92. }
  93. if (!VRTK_SharedMethods.IsTypeSubclassOf(fallbackType, baseType))
  94. {
  95. VRTK_Logger.Fatal(new ArgumentOutOfRangeException("fallbackType", fallbackType, string.Format("'{0}' is not a subclass of the SDK base type '{1}'.", fallbackType.Name, baseType.Name)));
  96. return;
  97. }
  98. baseTypeName = baseType.FullName;
  99. fallbackTypeName = fallbackType.FullName;
  100. typeName = actualTypeName;
  101. if (string.IsNullOrEmpty(actualTypeName))
  102. {
  103. type = fallbackType;
  104. originalTypeNameWhenFallbackIsUsed = null;
  105. this.descriptionIndex = -1;
  106. description = new SDK_DescriptionAttribute(typeof(SDK_FallbackSystem));
  107. return;
  108. }
  109. Type actualType = Type.GetType(actualTypeName);
  110. if (actualType == null)
  111. {
  112. type = fallbackType;
  113. originalTypeNameWhenFallbackIsUsed = actualTypeName;
  114. this.descriptionIndex = -1;
  115. description = new SDK_DescriptionAttribute(typeof(SDK_FallbackSystem));
  116. VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SDK_NOT_FOUND, actualTypeName, fallbackType.Name));
  117. return;
  118. }
  119. if (!VRTK_SharedMethods.IsTypeSubclassOf(actualType, baseType))
  120. {
  121. VRTK_Logger.Fatal(new ArgumentOutOfRangeException("actualTypeName", actualTypeName, string.Format("'{0}' is not a subclass of the SDK base type '{1}'.", actualTypeName, baseType.Name)));
  122. return;
  123. }
  124. SDK_DescriptionAttribute[] descriptions = SDK_DescriptionAttribute.GetDescriptions(actualType);
  125. if (descriptions.Length <= descriptionIndex)
  126. {
  127. VRTK_Logger.Fatal(new ArgumentOutOfRangeException("descriptionIndex", descriptionIndex, string.Format("'{0}' has no '{1}' at that index.", actualTypeName, typeof(SDK_DescriptionAttribute).Name)));
  128. return;
  129. }
  130. type = actualType;
  131. originalTypeNameWhenFallbackIsUsed = null;
  132. this.descriptionIndex = descriptionIndex;
  133. description = descriptions[descriptionIndex];
  134. }
  135. #region ISerializationCallbackReceiver
  136. public void OnBeforeSerialize()
  137. {
  138. }
  139. public void OnAfterDeserialize()
  140. {
  141. SetUp(Type.GetType(baseTypeName), Type.GetType(fallbackTypeName), typeName, descriptionIndex);
  142. }
  143. #endregion
  144. #region Equality via type and descriptionIndex
  145. public override bool Equals(object obj)
  146. {
  147. VRTK_SDKInfo other = obj as VRTK_SDKInfo;
  148. if ((object)other == null)
  149. {
  150. return false;
  151. }
  152. return this == other;
  153. }
  154. public bool Equals(VRTK_SDKInfo other)
  155. {
  156. return this == other;
  157. }
  158. public override int GetHashCode()
  159. {
  160. return type.GetHashCode();
  161. }
  162. public static bool operator ==(VRTK_SDKInfo x, VRTK_SDKInfo y)
  163. {
  164. if (ReferenceEquals(x, y))
  165. {
  166. return true;
  167. }
  168. if ((object)x == null || (object)y == null)
  169. {
  170. return false;
  171. }
  172. return x.type == y.type && x.descriptionIndex == y.descriptionIndex;
  173. }
  174. public static bool operator !=(VRTK_SDKInfo x, VRTK_SDKInfo y)
  175. {
  176. return !(x == y);
  177. }
  178. #endregion
  179. }
  180. }