ObjectExtensions.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using XUnity.AutoTranslator.Plugin.Core.Configuration;
  7. using UnityEngine.UI;
  8. using XUnity.AutoTranslator.Plugin.Core.Constants;
  9. using XUnity.AutoTranslator.Plugin.Core.Utilities;
  10. using UnityEngine;
  11. namespace XUnity.AutoTranslator.Plugin.Core.Extensions
  12. {
  13. public static class ObjectExtensions
  14. {
  15. private static readonly string RichTextPropertyName = "richText";
  16. private static readonly object Sync = new object();
  17. private static readonly WeakDictionary<object, object> DynamicFields = new WeakDictionary<object, object>();
  18. public static bool IsKnownTextType( this object ui )
  19. {
  20. if( ui == null ) return false;
  21. var type = ui.GetType();
  22. return ( Settings.EnableUGUI && ui is Text )
  23. || ( Settings.EnableIMGUI && ui is GUIContent )
  24. || ( Settings.EnableNGUI && ClrTypes.UILabel != null && ClrTypes.UILabel.IsAssignableFrom( type ) )
  25. || ( Settings.EnableTextMeshPro && ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) )
  26. || ( Settings.EnableUtage && ClrTypes.AdvCommand != null && ClrTypes.AdvCommand.IsAssignableFrom( type ) );
  27. }
  28. public static bool IsKnownImageType( this object ui )
  29. {
  30. var type = ui.GetType();
  31. return ( ui is Material || ui is Image || ui is RawImage )
  32. || ( ClrTypes.UIWidget != null && type != ClrTypes.UILabel && ClrTypes.UIWidget.IsAssignableFrom( type ) )
  33. || ( ClrTypes.UIAtlas != null && ClrTypes.UIAtlas.IsAssignableFrom( type ) )
  34. || ( ClrTypes.UITexture != null && ClrTypes.UITexture.IsAssignableFrom( type ) )
  35. || ( ClrTypes.UIPanel != null && ClrTypes.UIPanel.IsAssignableFrom( type ) );
  36. }
  37. public static bool SupportsStabilization( this object ui )
  38. {
  39. if( ui == null ) return false;
  40. // shortcircuit for spammy component, to avoid reflective calls
  41. if( ui is GUIContent ) return false;
  42. var type = ui.GetType();
  43. return ui is Text
  44. || ( ClrTypes.UILabel != null && ClrTypes.UILabel.IsAssignableFrom( type ) )
  45. || ( ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) );
  46. }
  47. public static bool SupportsRichText( this object ui )
  48. {
  49. if( ui == null ) return false;
  50. var type = ui.GetType();
  51. return ( ui as Text )?.supportRichText == true
  52. || ( ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) && Equals( type.GetProperty( RichTextPropertyName )?.GetValue( ui, null ), true ) )
  53. || ( ClrTypes.AdvCommand != null && ClrTypes.AdvCommand.IsAssignableFrom( type ) )
  54. || ( ClrTypes.UguiNovelText != null && ClrTypes.UguiNovelText.IsAssignableFrom( type ) );
  55. }
  56. public static bool IsSpammingComponent( this object ui )
  57. {
  58. if( ui == null ) return false;
  59. return ui is UnityEngine.GUIContent;
  60. }
  61. public static bool IsWhitelistedForImmediateRichTextTranslation( this object ui )
  62. {
  63. if( ui == null ) return false;
  64. var type = ui.GetType();
  65. return ClrTypes.AdvCommand != null && ClrTypes.AdvCommand.IsAssignableFrom( type );
  66. }
  67. public static bool IsNGUI( this object ui )
  68. {
  69. if( ui == null ) return false;
  70. var type = ui.GetType();
  71. return ClrTypes.UILabel != null && ClrTypes.UILabel.IsAssignableFrom( type );
  72. }
  73. public static TextTranslationInfo GetTextTranslationInfo( this object obj )
  74. {
  75. if( !Settings.EnableObjectTracking ) return null;
  76. if( !obj.SupportsStabilization() ) return null;
  77. var info = obj.Get<TextTranslationInfo>();
  78. return info;
  79. }
  80. public static ImageTranslationInfo GetImageTranslationInfo( this object obj )
  81. {
  82. return obj.Get<ImageTranslationInfo>();
  83. }
  84. public static TextureTranslationInfo GetTextureTranslationInfo( this Texture texture )
  85. {
  86. return texture.Get<TextureTranslationInfo>();
  87. }
  88. public static T Get<T>( this object obj )
  89. where T : new()
  90. {
  91. if( obj == null ) return default( T );
  92. lock( Sync )
  93. {
  94. if( DynamicFields.TryGetValue( obj, out object value ) )
  95. {
  96. if( value is Dictionary<Type, object> existingDictionary )
  97. {
  98. if( existingDictionary.TryGetValue( typeof( T ), out value ) )
  99. {
  100. return (T)value;
  101. }
  102. else
  103. {
  104. var t = new T();
  105. existingDictionary[ typeof( T ) ] = t;
  106. return t;
  107. }
  108. }
  109. if( !( value is T ) )
  110. {
  111. var newDictionary = new Dictionary<Type, object>();
  112. newDictionary.Add( value.GetType(), value );
  113. var t = new T();
  114. newDictionary[ typeof( T ) ] = t;
  115. DynamicFields[ obj ] = newDictionary;
  116. return t;
  117. }
  118. else
  119. {
  120. return (T)value;
  121. }
  122. }
  123. else
  124. {
  125. var t = new T();
  126. DynamicFields[ obj ] = t;
  127. return t;
  128. }
  129. }
  130. }
  131. public static void Cull()
  132. {
  133. lock( Sync )
  134. {
  135. DynamicFields.RemoveCollectedEntries();
  136. }
  137. }
  138. public static List<KeyValuePair<object, object>> GetAllRegisteredObjects()
  139. {
  140. lock( Sync )
  141. {
  142. return IterateAllPairs().ToList();
  143. }
  144. }
  145. public static void Remove( object obj )
  146. {
  147. lock( Sync )
  148. {
  149. DynamicFields.Remove( obj );
  150. }
  151. }
  152. private static IEnumerable<KeyValuePair<object, object>> IterateAllPairs()
  153. {
  154. foreach( var kvp in DynamicFields )
  155. {
  156. if( kvp.Value is Dictionary<Type, object> dictionary )
  157. {
  158. foreach( var kvp2 in dictionary )
  159. {
  160. yield return new KeyValuePair<object, object>( kvp.Key, kvp2.Value );
  161. }
  162. }
  163. else
  164. {
  165. yield return kvp;
  166. }
  167. }
  168. }
  169. }
  170. }