Эх сурвалжийг харах

removed unityengine.ui dependency

randoman 5 жил өмнө
parent
commit
b383e1dac3
25 өөрчлөгдсөн 430 нэмэгдсэн , 128 устгасан
  1. 4 1
      CHANGELOG.md
  2. 1 0
      README.md
  3. 0 3
      src/XUnity.AutoTranslator.Plugin.BepIn-5x/XUnity.AutoTranslator.Plugin.BepIn-5x.csproj
  4. 0 3
      src/XUnity.AutoTranslator.Plugin.BepIn/XUnity.AutoTranslator.Plugin.BepIn.csproj
  5. 24 14
      src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs
  6. 2 0
      src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs
  7. 5 1
      src/XUnity.AutoTranslator.Plugin.Core/Constants/ClrTypes.cs
  8. 36 0
      src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs
  9. 17 24
      src/XUnity.AutoTranslator.Plugin.Core/Extensions/TextComponentExtensions.cs
  10. 11 18
      src/XUnity.AutoTranslator.Plugin.Core/Extensions/TextureComponentExtensions.cs
  11. 3 3
      src/XUnity.AutoTranslator.Plugin.Core/Extensions/TextureExtensions.cs
  12. 12 0
      src/XUnity.AutoTranslator.Plugin.Core/Features.cs
  13. 8 7
      src/XUnity.AutoTranslator.Plugin.Core/Hooks/ImageHooks.cs
  14. 1 1
      src/XUnity.AutoTranslator.Plugin.Core/Parsing/GameLogTextParser.cs
  15. 6 6
      src/XUnity.AutoTranslator.Plugin.Core/Parsing/RichTextParser.cs
  16. 49 36
      src/XUnity.AutoTranslator.Plugin.Core/TextTranslationInfo.cs
  17. 0 1
      src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs
  18. 40 0
      src/XUnity.AutoTranslator.Plugin.Core/UI/GUIUtil.cs
  19. 2 2
      src/XUnity.AutoTranslator.Plugin.Core/UI/TranslationAggregatorOptionsWindow.cs
  20. 2 2
      src/XUnity.AutoTranslator.Plugin.Core/UI/TranslationAggregatorWindow.cs
  21. 2 2
      src/XUnity.AutoTranslator.Plugin.Core/UI/XuaWindow.cs
  22. 8 0
      src/XUnity.AutoTranslator.Plugin.Core/UntranslatedText.cs
  23. 0 1
      src/XUnity.AutoTranslator.Plugin.Core/Utilities/ObjectReferenceMapper.cs
  24. 0 3
      src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj
  25. 197 0
      src/XUnity.RuntimeHooker.Core/Utilities/ReflectionCache.cs

+ 4 - 1
CHANGELOG.md

@@ -1,4 +1,7 @@
-### 3.5.0
+### 3.6.0
+ * MISC - Removed hard dependency on UnityEngine.UI to support older versions of UnityEngine
+
+### 3.5.0
  * FEATURE - Harmony 2.0-prerelease support (in order to support BepInEx 5.0.0-RC1)
  * BUG FIX - Fixed a bug where the plugin would sometimes dump textures if 'DetectDuplicateTextureNames' was turned on, even though 'EnableTextureDumping' was turned off
  * BUG FIX - Correct whitespace handling of source languages requiring whitelines between words

+ 1 - 0
README.md

@@ -173,6 +173,7 @@ The supported translators are:
  * LecPowerTranslator15, based on LEC's Power Translator. Does not require authentication, but does require the software installed.
    * No limitations.
  * CustomTranslate. Alternatively you can also specify any custom HTTP url that can be used as a translation endpoint (GET request). This must use the query parameters "from", "to" and "text" and return only a string with the result (try HTTP without SSL first, as unity-mono often has issues with SSL).
+   * *NOTE: This is a developer-centric option. You cannot simply specify "CustomTranslate" and expect it to work with any arbitrary translation service you find online. See [FAQ](#frequently-asked-questions)*
    * Example Configuration:
      * Endpoint=CustomTranslate
      * [Custom]

+ 0 - 3
src/XUnity.AutoTranslator.Plugin.BepIn-5x/XUnity.AutoTranslator.Plugin.BepIn-5x.csproj

@@ -19,9 +19,6 @@
     <Reference Include="UnityEngine">
       <HintPath>..\..\libs\UnityEngine.dll</HintPath>
     </Reference>
-    <Reference Include="UnityEngine.UI">
-      <HintPath>..\..\libs\UnityEngine.UI.dll</HintPath>
-    </Reference>
   </ItemGroup>
 
   <Target Name="PostBuild" AfterTargets="PostBuildEvent">

+ 0 - 3
src/XUnity.AutoTranslator.Plugin.BepIn/XUnity.AutoTranslator.Plugin.BepIn.csproj

@@ -19,9 +19,6 @@
       <Reference Include="UnityEngine">
          <HintPath>..\..\libs\UnityEngine.dll</HintPath>
       </Reference>
-      <Reference Include="UnityEngine.UI">
-         <HintPath>..\..\libs\UnityEngine.UI.dll</HintPath>
-      </Reference>
    </ItemGroup>
 
    <Target Name="PostBuild" AfterTargets="PostBuildEvent">

+ 24 - 14
src/XUnity.AutoTranslator.Plugin.Core/AutoTranslationPlugin.cs

@@ -10,10 +10,8 @@ using System.Text.RegularExpressions;
 using System.Threading;
 using ExIni;
 using UnityEngine;
-using UnityEngine.UI;
 using System.Globalization;
 using XUnity.AutoTranslator.Plugin.Core.Extensions;
-using UnityEngine.EventSystems;
 using XUnity.AutoTranslator.Plugin.Core.Configuration;
 using XUnity.AutoTranslator.Plugin.Core.Utilities;
 using XUnity.AutoTranslator.Plugin.Core.Web;
@@ -236,23 +234,35 @@ namespace XUnity.AutoTranslator.Plugin.Core
          }
 
          // check if font is supported
-         if( !string.IsNullOrEmpty( Settings.OverrideFont ) )
+         try
          {
-            var available = Font.GetOSInstalledFontNames();
-            if( !available.Contains( Settings.OverrideFont ) )
+            if( !string.IsNullOrEmpty( Settings.OverrideFont ) )
             {
-               XuaLogger.Current.Error( $"The specified override font is not available. Available fonts: " + string.Join( ", ", available ) );
-               Settings.OverrideFont = null;
-            }
-            else
-            {
-               _hasValidOverrideFont = true;
-            }
+               var available = GetSupportedFonts();
+               if( !available.Contains( Settings.OverrideFont ) )
+               {
+                  XuaLogger.Current.Error( $"The specified override font is not available. Available fonts: " + string.Join( ", ", available ) );
+                  Settings.OverrideFont = null;
+               }
+               else
+               {
+                  _hasValidOverrideFont = true;
+               }
 
-            _hasOverridenFont = _hasValidOverrideFont;
+               _hasOverridenFont = _hasValidOverrideFont;
+            }
+         }
+         catch( Exception e )
+         {
+            XuaLogger.Current.Error( e, "An error occurred while checking supported fonts." );
          }
       }
 
+      internal static string[] GetSupportedFonts()
+      {
+         return Font.GetOSInstalledFontNames();
+      }
+
       private void OnEndpointSelected( TranslationEndpointManager endpoint )
       {
          if( TranslationManager.CurrentEndpoint != endpoint )
@@ -669,7 +679,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
             if( !ignoreComponentState )
             {
                var behaviour = component as Behaviour;
-               if( behaviour?.isActiveAndEnabled == false )
+               if( !go.activeInHierarchy || behaviour?.enabled == false ) // legacy "isActiveAndEnabled"
                {
                   return false;
                }

+ 2 - 0
src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs

@@ -102,6 +102,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
       public static HashSet<string> DuplicateTextureNames;
       public static TextureHashGenerationStrategy TextureHashGenerationStrategy;
 
+      public static Dictionary<string, string> Replacements;
+
       public static bool CopyToClipboard;
       public static int MaxClipboardCopyCharacters;
 

+ 5 - 1
src/XUnity.AutoTranslator.Plugin.Core/Constants/ClrTypes.cs

@@ -25,10 +25,14 @@ namespace XUnity.AutoTranslator.Plugin.Core.Constants
       public static readonly Type UIInput = FindType( "UIInput" );
 
       // Unity
+      public static readonly Type Text = FindType( "UnityEngine.UI.Text" );
+      public static readonly Type Image = FindType( "UnityEngine.UI.Image" );
+      public static readonly Type RawImage = FindType( "UnityEngine.UI.RawImage" );
+      public static readonly Type MaskableGraphic = FindType( "UnityEngine.UI.MaskableGraphic" );
+      public static readonly Type Graphic = FindType( "UnityEngine.UI.Graphic" );
       public static readonly Type GUIContent = FindType( "UnityEngine.GUIContent" );
       public static readonly Type WWW = FindType( "UnityEngine.WWW" );
       public static readonly Type InputField = FindType( "UnityEngine.UI.InputField" );
-      public static readonly Type Text = FindType( "UnityEngine.UI.Text" );
       public static readonly Type GUI = FindType( "UnityEngine.GUI" );
       public static readonly Type ImageConversion = FindType( "UnityEngine.ImageConversion" );
       public static readonly Type Texture = FindType( "UnityEngine.Texture" );

+ 36 - 0
src/XUnity.AutoTranslator.Plugin.Core/Extensions/StringExtensions.cs

@@ -77,6 +77,42 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
          return builder.ToString();
       }
 
+      public static TemplatedString TemplatizeByReplacements( this string str )
+      {
+         if( Settings.Replacements == null || Settings.Replacements.Count == 0 ) return null;
+
+         var dict = new Dictionary<string, string>();
+         char arg = 'A';
+
+         foreach( var kvp in Settings.Replacements )
+         {
+            var original = kvp.Key;
+            var replacement = kvp.Value;
+
+            string key = null;
+            int idx = -1;
+            while( ( idx = str.IndexOf( original ) ) != -1 )
+            {
+               if( key == null )
+               {
+                  key = "{{" + arg++ + "}}";
+                  dict.Add( key, replacement );
+               }
+
+               str = str.Remove( idx, original.Length ).Insert( idx, key );
+            }
+         }
+
+         if( dict.Count > 0 )
+         {
+            return new TemplatedString( str, dict );
+         }
+         else
+         {
+            return null;
+         }
+      }
+
       public static TemplatedString TemplatizeByNumbers( this string str )
       {
          var dict = new Dictionary<string, string>();

+ 17 - 24
src/XUnity.AutoTranslator.Plugin.Core/Extensions/TextComponentExtensions.cs

@@ -6,32 +6,33 @@ using System.Linq;
 using System.Reflection;
 using System.Text;
 using UnityEngine;
-using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Configuration;
 using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Utilities;
+using XUnity.RuntimeHooker.Core.Utilities;
 
 namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 {
    internal static class TextComponentExtensions
    {
+      private static readonly string SupportRichTextPropertyName = "supportRichText";
+      private static readonly string RichTextPropertyName = "richText";
+      private static readonly string TextPropertyName = "text";
+
       //private static readonly GUIContent[] TemporaryGUIContents = ClrTypes.GUIContent
       //   .GetFields( BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic )
       //   .Where( x => x.DeclaringType == typeof( GUIContent ) && ( x.Name == "s_Text" || x.Name == "s_TextImage" ) )
       //   .Select( x => (GUIContent)x.GetValue( null ) )
       //   .ToArray();
 
-      private static readonly string RichTextPropertyName = "richText";
-      private static readonly string TextPropertyName = "text";
-
       public static bool IsKnownTextType( this object ui )
       {
          if( ui == null ) return false;
 
          var type = ui.GetType();
 
-         return ( Settings.EnableUGUI && ui is Text )
-            || ( Settings.EnableIMGUI && ui is GUIContent )
+         return ( Settings.EnableIMGUI && ui is GUIContent )
+            || ( Settings.EnableUGUI && ClrTypes.Text != null && ClrTypes.Text.IsAssignableFrom( type ) )
             || ( Settings.EnableNGUI && ClrTypes.UILabel != null && ClrTypes.UILabel.IsAssignableFrom( type ) )
             || ( Settings.EnableTextMeshPro && ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) )
             /*|| ( ClrTypes.AdvCommand != null && ClrTypes.AdvCommand.IsAssignableFrom( type ) )*/;
@@ -43,8 +44,8 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 
          var type = ui.GetType();
 
-         return ( ui as Text )?.supportRichText == true
-            || ( ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) && Equals( type.GetProperty( RichTextPropertyName )?.GetValue( ui, null ), true ) )
+         return ( ClrTypes.Text != null && ClrTypes.Text.IsAssignableFrom( type ) && Equals( type.CachedProperty( SupportRichTextPropertyName )?.Get( ui ), true ) )
+            || ( ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) && Equals( type.CachedProperty( RichTextPropertyName )?.Get( ui ), true ) )
             || ( ClrTypes.UguiNovelText != null && ClrTypes.UguiNovelText.IsAssignableFrom( type ) )
             /*|| ( ClrTypes.AdvCommand != null && ClrTypes.AdvCommand.IsAssignableFrom( type ) )*/;
       }
@@ -71,7 +72,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 
          var type = ui.GetType();
 
-         return ui is Text
+         return ( ClrTypes.Text != null && ClrTypes.Text.IsAssignableFrom( type ) )
             || ( ClrTypes.UILabel != null && ClrTypes.UILabel.IsAssignableFrom( type ) )
             || ( ClrTypes.TMP_Text != null && ClrTypes.TMP_Text.IsAssignableFrom( type ) );
       }
@@ -113,18 +114,14 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
          string text = null;
          var type = ui.GetType();
 
-         if( ui is Text )
-         {
-            text = ( (Text)ui ).text;
-         }
-         else if( ui is GUIContent )
+         if( ui is GUIContent )
          {
             text = ( (GUIContent)ui ).text;
          }
          else
          {
             // fallback to reflective approach
-            text = (string)ui.GetType()?.GetProperty( TextPropertyName )?.GetValue( ui, null );
+            text = (string)type.CachedProperty( TextPropertyName )?.Get( ui );
          }
 
          return text ?? string.Empty;
@@ -147,10 +144,10 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
                if( Equals( uguiNovelText, ui ) )
                {
                   string previousNameText = null;
-                  var nameText = (Text)uguiMessageWindow.GetType().GetField( "nameText", flags ).GetValue( uguiMessageWindow );
+                  var nameText = (UnityEngine.Object)uguiMessageWindow.GetType().GetField( "nameText", flags ).GetValue( uguiMessageWindow );
                   if( nameText )
                   {
-                     previousNameText = nameText.text;
+                     previousNameText = (string)ClrTypes.Text.CachedProperty( TextPropertyName ).Get( nameText );
                   }
 
                   var engine = uguiMessageWindow.GetType().GetProperty( "Engine", flags ).GetValue( uguiMessageWindow, null );
@@ -199,7 +196,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 
                   if( nameText )
                   {
-                     nameText.text = previousNameText;
+                     ClrTypes.Text.CachedProperty( TextPropertyName ).Set( nameText, previousNameText );
                   }
 
                   return;
@@ -207,18 +204,14 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
             }
          }
 
-         if( ui is Text )
-         {
-            ( (Text)ui ).text = text;
-         }
-         else if( ui is GUIContent )
+         if( ui is GUIContent )
          {
             ( (GUIContent)ui ).text = text;
          }
          else
          {
             // fallback to reflective approach
-            type.GetProperty( TextPropertyName )?.GetSetMethod()?.Invoke( ui, new[] { text } );
+            type.CachedProperty( TextPropertyName )?.Set( ui, text );
          }
       }
    }

+ 11 - 18
src/XUnity.AutoTranslator.Plugin.Core/Extensions/TextureComponentExtensions.cs

@@ -1,11 +1,13 @@
 using UnityEngine;
-using UnityEngine.UI;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Hooks;
+using XUnity.RuntimeHooker.Core.Utilities;
 
 namespace XUnity.AutoTranslator.Plugin.Core.Extensions
 {
    internal static class TextureComponentExtensions
    {
+      private static readonly string SetAllDirtyMethodName = "SetAllDirty";
       private static readonly string TexturePropertyName = "texture";
       private static readonly string MainTexturePropertyName = "mainTexture";
       private static readonly string CapitalMainTexturePropertyName = "MainTexture";
@@ -25,15 +27,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
       {
          if( ui == null ) return null;
 
-         if( ui is Image image )
-         {
-            return image.mainTexture as Texture2D;
-         }
-         else if( ui is RawImage rawImage )
-         {
-            return rawImage.mainTexture as Texture2D;
-         }
-         else if( ui is SpriteRenderer spriteRenderer )
+         if( ui is SpriteRenderer spriteRenderer )
          {
             return spriteRenderer.sprite?.texture;
          }
@@ -41,9 +35,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
          {
             // lets attempt some reflection for several known types
             var type = ui.GetType();
-            var texture = type.GetProperty( MainTexturePropertyName )?.GetValue( ui, null )
-               ?? type.GetProperty( TexturePropertyName )?.GetValue( ui, null )
-               ?? type.GetProperty( CapitalMainTexturePropertyName )?.GetValue( ui, null );
+            var texture = type.CachedProperty( MainTexturePropertyName )?.Get( ui )
+               ?? type.CachedProperty( TexturePropertyName )?.Get( ui )
+               ?? type.CachedProperty( CapitalMainTexturePropertyName )?.Get( ui );
 
             return texture as Texture2D;
          }
@@ -53,15 +47,14 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
       {
          if( ui == null ) return;
 
-         if( ui is Graphic graphic )
+         var type = ui.GetType();
+
+         if( ClrTypes.Graphic != null && ClrTypes.Graphic.IsAssignableFrom( type ) )
          {
-            graphic.SetAllDirty();
+            ClrTypes.Graphic.CachedMethod( SetAllDirtyMethodName ).Invoke( ui );
          }
          else
          {
-            // lets attempt some reflection for several known types
-            var type = ui.GetType();
-
             AccessToolsShim.Method( type, MarkAsChangedMethodName )?.Invoke( ui, null );
          }
       }

+ 3 - 3
src/XUnity.AutoTranslator.Plugin.Core/Extensions/TextureExtensions.cs

@@ -1,11 +1,9 @@
 using System;
 using System.Collections.Generic;
-using System.Drawing;
 using System.Linq;
 using System.Reflection;
 using System.Text;
 using UnityEngine;
-using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Hooks;
 
@@ -25,7 +23,9 @@ namespace XUnity.AutoTranslator.Plugin.Core.Extensions
       {
          var type = ui.GetType();
 
-         return ( ui is Material || ui is UnityEngine.UI.Image || ui is RawImage || ui is SpriteRenderer )
+         return ( ui is Material || ui is SpriteRenderer )
+            || ( ClrTypes.Image != null && ClrTypes.Image.IsAssignableFrom( type ) )
+            || ( ClrTypes.RawImage != null && ClrTypes.RawImage.IsAssignableFrom( type ) )
             || ( ClrTypes.CubismRenderer != null && ClrTypes.CubismRenderer.IsAssignableFrom( type ) )
             || ( ClrTypes.UIWidget != null && type != ClrTypes.UILabel && ClrTypes.UIWidget.IsAssignableFrom( type ) )
             || ( ClrTypes.UIAtlas != null && ClrTypes.UIAtlas.IsAssignableFrom( type ) )

+ 12 - 0
src/XUnity.AutoTranslator.Plugin.Core/Features.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Text;
+using UnityEngine;
 using XUnity.AutoTranslator.Plugin.Core.Constants;
 
 namespace XUnity.AutoTranslator.Plugin.Core
@@ -10,6 +11,8 @@ namespace XUnity.AutoTranslator.Plugin.Core
    /// </summary>
    public static class Features
    {
+      internal static bool SupportsMouseScrollDelta { get; } = false;
+
       internal static bool SupportsClipboard { get; } = false;
 
       /// <summary>
@@ -64,6 +67,15 @@ namespace XUnity.AutoTranslator.Plugin.Core
          {
 
          }
+
+         try
+         {
+            SupportsMouseScrollDelta = typeof( Input ).GetProperty( "mouseScrollDelta" ) != null;
+         }
+         catch( Exception )
+         {
+
+         }
       }
    }
 }

+ 8 - 7
src/XUnity.AutoTranslator.Plugin.Core/Hooks/ImageHooks.cs

@@ -5,7 +5,6 @@ using System.Linq;
 using System.Reflection;
 using System.Text;
 using UnityEngine;
-using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Extensions;
 
@@ -169,12 +168,14 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
       static MethodBase TargetMethod( object instance )
       {
-         return AccessToolsShim.Method( typeof( MaskableGraphic ), "OnEnable" );
+         return AccessToolsShim.Method( ClrTypes.MaskableGraphic, "OnEnable" );
       }
 
       public static void Postfix( object __instance )
       {
-         if( __instance is Image || __instance is RawImage )
+         var type = __instance.GetType();
+         if( ( ClrTypes.Image != null && ClrTypes.Image.IsAssignableFrom( type ) )
+            || ( ClrTypes.RawImage != null && ClrTypes.RawImage.IsAssignableFrom( type ) ) )
          {
             AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent( __instance, null, false, true );
          }
@@ -190,7 +191,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
       static MethodBase TargetMethod( object instance )
       {
-         return AccessToolsShim.Property( typeof( Image ), "sprite" )?.GetSetMethod();
+         return AccessToolsShim.Property( ClrTypes.Image, "sprite" )?.GetSetMethod();
       }
 
       public static void Postfix( object __instance )
@@ -208,7 +209,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
       static MethodBase TargetMethod( object instance )
       {
-         return AccessToolsShim.Property( typeof( Image ), "overrideSprite" )?.GetSetMethod();
+         return AccessToolsShim.Property( ClrTypes.Image, "overrideSprite" )?.GetSetMethod();
       }
 
       public static void Postfix( object __instance )
@@ -226,7 +227,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
       static MethodBase TargetMethod( object instance )
       {
-         return AccessToolsShim.Property( typeof( Image ), "material" )?.GetSetMethod();
+         return AccessToolsShim.Property( ClrTypes.Image, "material" )?.GetSetMethod();
       }
 
       public static void Postfix( object __instance )
@@ -244,7 +245,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Hooks
 
       static MethodBase TargetMethod( object instance )
       {
-         return AccessToolsShim.Property( typeof( RawImage ), "texture" )?.GetSetMethod();
+         return AccessToolsShim.Property( ClrTypes.RawImage, "texture" )?.GetSetMethod();
       }
 
       public static void Prefix( object __instance, Texture value )

+ 1 - 1
src/XUnity.AutoTranslator.Plugin.Core/Parsing/GameLogTextParser.cs

@@ -45,7 +45,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
                   }
                   else
                   {
-                     var key = "{{" + ( arg++ ) + "}}";
+                     var key = "[[" + ( arg++ ) + "]]";
                      template.Append( key ).Append( '\n' );
                      args.Add( key, line );
                      reverseArgs[ line ] = key;

+ 6 - 6
src/XUnity.AutoTranslator.Plugin.Core/Parsing/RichTextParser.cs

@@ -86,7 +86,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
 
                if( !string.IsNullOrEmpty( text ) )
                {
-                  var argument = "{{" + ( arg++ ) + "}}";
+                  var argument = "[[" + ( arg++ ) + "]]";
                   args.Add( argument, text );
                   template.Append( argument );
                }
@@ -105,7 +105,7 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
          // catch any remaining text
          if( offset < input.Length )
          {
-            var argument = "{{" + ( arg++ ) + "}}";
+            var argument = "[[" + ( arg++ ) + "]]";
             var text = input.Substring( offset, input.Length - offset );
             args.Add( argument, text );
             template.Append( argument );
@@ -114,20 +114,20 @@ namespace XUnity.AutoTranslator.Plugin.Core.Parsing
 
          var templateString = template.ToString();
          int idx = -1;
-         while( ( idx = templateString.IndexOf( "}}{{" ) ) != -1 )
+         while( ( idx = templateString.IndexOf( "]][[" ) ) != -1 )
          {
             var arg1 = templateString[ idx - 1 ];
             var arg2 = templateString[ idx + 4 ];
 
-            var key1 = "{{" + arg1 + "}}";
-            var key2 = "{{" + arg2 + "}}";
+            var key1 = "[[" + arg1 + "]]";
+            var key2 = "[[" + arg2 + "]]";
 
             var text1 = args[ key1 ];
             var text2 = args[ key2 ];
 
             var fullText = text1 + text2;
             var fullKey = key1 + key2;
-            var newKey = "{{" + ( arg1 ) + "}}";
+            var newKey = "[[" + ( arg1 ) + "]]";
 
             args.Remove( key1 );
             args.Remove( key2 );

+ 49 - 36
src/XUnity.AutoTranslator.Plugin.Core/TextTranslationInfo.cs

@@ -3,12 +3,12 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using UnityEngine;
-using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Configuration;
 using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Extensions;
 using XUnity.AutoTranslator.Plugin.Core.Fonts;
 using XUnity.AutoTranslator.Plugin.Core.Hooks;
+using XUnity.RuntimeHooker.Core.Utilities;
 
 namespace XUnity.AutoTranslator.Plugin.Core
 {
@@ -49,7 +49,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
                var ui = graphic as Component;
                if( ui != null )
                {
-                  _typewriter = (MonoBehaviour)ui.GetComponent( Constants.ClrTypes.Typewriter );
+                  _typewriter = (MonoBehaviour)ui.GetComponent( ClrTypes.Typewriter );
                }
             }
          }
@@ -60,23 +60,26 @@ namespace XUnity.AutoTranslator.Plugin.Core
          }
       }
 
-      public void ChangeFont( object graphic )
+      public void ChangeFont( object ui )
       {
-         if( graphic == null ) return;
+         if( ui == null ) return;
+
+         var type = ui.GetType();
 
-         if( graphic is Text )
+         if( ClrTypes.Text != null && ClrTypes.Text.IsAssignableFrom( type ) )
          {
-            var ui = graphic as Text;
+            var fontProperty = ClrTypes.Text.CachedProperty( "font" );
+            var fontSizeProperty = ClrTypes.Text.CachedProperty( "fontSize" );
 
-            var previousFont = ui.font;
-            var newFont = FontCache.GetOrCreate( previousFont?.fontSize ?? ui.fontSize );
+            var previousFont = (Font)fontProperty.Get( ui );
+            var newFont = FontCache.GetOrCreate( previousFont?.fontSize ?? (int)fontSizeProperty.Get( ui ) );
 
             if( !ReferenceEquals( newFont, previousFont ) )
             {
-               ui.font = newFont;
+               fontProperty.Set( ui, newFont );
                _unfont = obj =>
                {
-                  ( (Text)obj ).font = previousFont;
+                  fontProperty.Set( obj, previousFont );
                };
             }
          }
@@ -90,48 +93,60 @@ namespace XUnity.AutoTranslator.Plugin.Core
          _unfont = null;
       }
 
-      public void ResizeUI( object graphic )
+      public static float GetComponentWidth( Component component )
+      {
+         // this is in it's own function because if "Text" does not exist, RectTransform likely wont exist either
+         return ( (RectTransform)component.transform ).rect.width;
+      }
+
+      public void ResizeUI( object ui )
       {
          // do not resize if there is no object of ir it is already resized
-         if( graphic == null ) return;
+         if( ui == null ) return;
+
+         var type = ui.GetType();
 
-         if( graphic is Text )
+         if( ClrTypes.Text != null && ClrTypes.Text.IsAssignableFrom( type ) )
          {
-            var ui = (Text)graphic;
+            var text = (Component)ui;
 
             // text is likely to be longer than there is space for, simply expand out anyway then
-            var componentWidth = ( (RectTransform)ui.transform ).rect.width;
+            var componentWidth = GetComponentWidth( text );
             var quarterScreenSize = Screen.width / 4;
             var isComponentWide = componentWidth > quarterScreenSize;
 
+            var horizontalOverflowProperty = ClrTypes.Text.CachedProperty( "horizontalOverflow" );
+            var verticalOverflowProperty = ClrTypes.Text.CachedProperty( "verticalOverflow" );
+            var lineSpacingProperty = ClrTypes.Text.CachedProperty( "lineSpacing" );
+            var resizeTextForBestFitProperty = ClrTypes.Text.CachedProperty( "resizeTextForBestFit" );
+
             // width < quarterScreenSize is used to determine the likelihood of a text using multiple lines
             // the idea is, if the UI element is larger than the width of half the screen, there is a larger
             // likelihood that it will go into multiple lines too.
-            var originalHorizontalOverflow = ui.horizontalOverflow;
-            var originalVerticalOverflow = ui.verticalOverflow;
-            var originalLineSpacing = ui.lineSpacing;
+            var originalHorizontalOverflow = horizontalOverflowProperty.Get( text );
+            var originalVerticalOverflow = verticalOverflowProperty.Get( text );
+            var originalLineSpacing = lineSpacingProperty.Get( text );
 
-            if( isComponentWide && !ui.resizeTextForBestFit )
+            if( isComponentWide && !(bool)resizeTextForBestFitProperty.Get( text ) )
             {
-               ui.horizontalOverflow = HorizontalWrapMode.Wrap;
-               ui.verticalOverflow = VerticalWrapMode.Overflow;
+               horizontalOverflowProperty.Set( text, 0 /* HorizontalWrapMode.Wrap */ );
+               verticalOverflowProperty.Set( text, 1 /* VerticalWrapMode.Overflow */ );
                if( Settings.ResizeUILineSpacingScale.HasValue && !Equals( _alteredSpacing, originalLineSpacing ) )
                {
-                  var alteredSpacing = originalLineSpacing * Settings.ResizeUILineSpacingScale.Value;
+                  var alteredSpacing = (float)originalLineSpacing * Settings.ResizeUILineSpacingScale.Value;
                   _alteredSpacing = alteredSpacing;
-                  ui.lineSpacing = alteredSpacing;
+                  lineSpacingProperty.Set( text, alteredSpacing );
                }
 
                if( _unresize == null )
                {
                   _unresize = g =>
                   {
-                     var gui = (Text)g;
-                     gui.horizontalOverflow = originalHorizontalOverflow;
-                     gui.verticalOverflow = originalVerticalOverflow;
+                     horizontalOverflowProperty.Set( g, originalHorizontalOverflow );
+                     verticalOverflowProperty.Set( g, originalVerticalOverflow );
                      if( Settings.ResizeUILineSpacingScale.HasValue )
                      {
-                        gui.lineSpacing = originalLineSpacing;
+                        lineSpacingProperty.Set( g, originalLineSpacing );
                      }
                   };
                }
@@ -139,17 +154,15 @@ namespace XUnity.AutoTranslator.Plugin.Core
          }
          else
          {
-            var type = graphic.GetType();
-
             // special handling for NGUI to better handle textbox sizing
             if( type == ClrTypes.UILabel )
             {
-               var originalMultiLine = type.GetProperty( MultiLinePropertyName )?.GetGetMethod()?.Invoke( graphic, null );
-               var originalOverflowMethod = type.GetProperty( OverflowMethodPropertyName )?.GetGetMethod()?.Invoke( graphic, null );
+               var originalMultiLine = type.GetProperty( MultiLinePropertyName )?.GetGetMethod()?.Invoke( ui, null );
+               var originalOverflowMethod = type.GetProperty( OverflowMethodPropertyName )?.GetGetMethod()?.Invoke( ui, null );
                //var originalSpacingY = graphic.GetSpacingY();
 
-               type.GetProperty( MultiLinePropertyName )?.GetSetMethod()?.Invoke( graphic, new object[] { true } );
-               type.GetProperty( OverflowMethodPropertyName )?.GetSetMethod()?.Invoke( graphic, new object[] { 0 } );
+               type.GetProperty( MultiLinePropertyName )?.GetSetMethod()?.Invoke( ui, new object[] { true } );
+               type.GetProperty( OverflowMethodPropertyName )?.GetSetMethod()?.Invoke( ui, new object[] { 0 } );
                //if( Settings.ResizeUILineSpacingScale.HasValue && !Equals( _alteredSpacing, originalSpacingY ) )
                //{
                //   var alteredSpacing = originalSpacingY.Multiply( Settings.ResizeUILineSpacingScale.Value );
@@ -173,14 +186,14 @@ namespace XUnity.AutoTranslator.Plugin.Core
             }
             else if( type == ClrTypes.TextMeshPro || type == ClrTypes.TextMeshProUGUI )
             {
-               var originalOverflowMode = ClrTypes.TMP_Text.GetProperty( OverflowModePropertyName )?.GetValue( graphic, null );
+               var originalOverflowMode = ClrTypes.TMP_Text.GetProperty( OverflowModePropertyName )?.GetValue( ui, null );
 
                // ellipsis (1) works
                // masking (2) has a tendency to break in some versions of TMP
                // truncate (3) works
                if( originalOverflowMode != null && (int)originalOverflowMode == 2 )
                {
-                  ClrTypes.TMP_Text.GetProperty( OverflowModePropertyName ).SetValue( graphic, 3, null );
+                  ClrTypes.TMP_Text.GetProperty( OverflowModePropertyName ).SetValue( ui, 3, null );
 
                   _unresize = g =>
                   {
@@ -195,7 +208,7 @@ namespace XUnity.AutoTranslator.Plugin.Core
       public void UnresizeUI( object graphic )
       {
          if( graphic == null ) return;
-         
+
          _unresize?.Invoke( graphic );
          _unresize = null;
       }

+ 0 - 1
src/XUnity.AutoTranslator.Plugin.Core/TranslationJob.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Net;
 using System.Text;
-using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Endpoints;
 using XUnity.AutoTranslator.Plugin.Core.Extensions;
 

+ 40 - 0
src/XUnity.AutoTranslator.Plugin.Core/UI/GUIUtil.cs

@@ -94,6 +94,26 @@ namespace XUnity.AutoTranslator.Plugin.Core.UI
          return WindowBackgroundStyle;
       }
 
+      public static bool IsAnyMouseButtonOrScrollWheelDownSafe
+      {
+         get
+         {
+            return Features.SupportsMouseScrollDelta
+               ? IsAnyMouseButtonOrScrollWheelDown
+               : IsAnyMouseButtonOrScrollWheelDownLegacy;
+         }
+      }
+
+      public static bool IsAnyMouseButtonOrScrollWheelDownLegacy
+      {
+         get
+         {
+            return Input.GetMouseButtonDown( 0 )
+               || Input.GetMouseButtonDown( 1 )
+               || Input.GetMouseButtonDown( 2 );
+         }
+      }
+
       public static bool IsAnyMouseButtonOrScrollWheelDown
       {
          get
@@ -105,6 +125,26 @@ namespace XUnity.AutoTranslator.Plugin.Core.UI
          }
       }
 
+      public static bool IsAnyMouseButtonOrScrollWheelSafe
+      {
+         get
+         {
+            return Features.SupportsMouseScrollDelta
+               ? IsAnyMouseButtonOrScrollWheel
+               : IsAnyMouseButtonOrScrollWheelLegacy;
+         }
+      }
+
+      public static bool IsAnyMouseButtonOrScrollWheelLegacy
+      {
+         get
+         {
+            return Input.GetMouseButton( 0 )
+               || Input.GetMouseButton( 1 )
+               || Input.GetMouseButton( 2 );
+         }
+      }
+
       public static bool IsAnyMouseButtonOrScrollWheel
       {
          get

+ 2 - 2
src/XUnity.AutoTranslator.Plugin.Core/UI/TranslationAggregatorOptionsWindow.cs

@@ -40,13 +40,13 @@ namespace XUnity.AutoTranslator.Plugin.Core.UI
 
          _windowRect = GUI.Window( WindowId, _windowRect, CreateWindowUI, "---- Translation Aggregator Options ----" );
 
-         if( GUIUtil.IsAnyMouseButtonOrScrollWheelDown )
+         if( GUIUtil.IsAnyMouseButtonOrScrollWheelDownSafe )
          {
             var point = new Vector2( Input.mousePosition.x, Screen.height - Input.mousePosition.y );
             _isMouseDownOnWindow = _windowRect.Contains( point );
          }
 
-         if( !_isMouseDownOnWindow || !GUIUtil.IsAnyMouseButtonOrScrollWheel )
+         if( !_isMouseDownOnWindow || !GUIUtil.IsAnyMouseButtonOrScrollWheelSafe )
             return;
 
          // make sure window is focused if scroll wheel is used to indicate we consumed that event

+ 2 - 2
src/XUnity.AutoTranslator.Plugin.Core/UI/TranslationAggregatorWindow.cs

@@ -45,13 +45,13 @@ namespace XUnity.AutoTranslator.Plugin.Core.UI
          _windowRect.width = _viewModel.Width;
          _windowRect = GUI.Window( WindowId, _windowRect, CreateWindowUI, "---- Translation Aggregator ----" );
 
-         if( GUIUtil.IsAnyMouseButtonOrScrollWheelDown )
+         if( GUIUtil.IsAnyMouseButtonOrScrollWheelDownSafe )
          {
             var point = new Vector2( Input.mousePosition.x, Screen.height - Input.mousePosition.y );
             _isMouseDownOnWindow = _windowRect.Contains( point );
          }
 
-         if( !_isMouseDownOnWindow || !GUIUtil.IsAnyMouseButtonOrScrollWheel )
+         if( !_isMouseDownOnWindow || !GUIUtil.IsAnyMouseButtonOrScrollWheelSafe )
             return;
 
          // make sure window is focused if scroll wheel is used to indicate we consumed that event

+ 2 - 2
src/XUnity.AutoTranslator.Plugin.Core/UI/XuaWindow.cs

@@ -36,13 +36,13 @@ namespace XUnity.AutoTranslator.Plugin.Core.UI
 
          _windowRect = GUI.Window( WindowId, _windowRect, CreateWindowUI, "---- XUnity.AutoTranslator UI ----" );
 
-         if( GUIUtil.IsAnyMouseButtonOrScrollWheelDown )
+         if( GUIUtil.IsAnyMouseButtonOrScrollWheelDownSafe )
          {
             var point = new Vector2( Input.mousePosition.x, Screen.height - Input.mousePosition.y );
             _isMouseDownOnWindow = _windowRect.Contains( point );
          }
 
-         if( !_isMouseDownOnWindow || !GUIUtil.IsAnyMouseButtonOrScrollWheel )
+         if( !_isMouseDownOnWindow || !GUIUtil.IsAnyMouseButtonOrScrollWheelSafe )
             return;
 
          // make sure window is focused if scroll wheel is used to indicate we consumed that event

+ 8 - 0
src/XUnity.AutoTranslator.Plugin.Core/UntranslatedText.cs

@@ -21,6 +21,14 @@ namespace XUnity.AutoTranslator.Plugin.Core
                text = TemplatedText.Template;
             }
          }
+         //else
+         //{
+         //   TemplatedText = text.TemplatizeByReplacements();
+         //   if( TemplatedText != null )
+         //   {
+         //      text = TemplatedText.Template;
+         //   }
+         //}
 
          int i = 0;
          int firstNonWhitespace = 0;

+ 0 - 1
src/XUnity.AutoTranslator.Plugin.Core/Utilities/ObjectReferenceMapper.cs

@@ -4,7 +4,6 @@ using System.Linq;
 using System.Text;
 using System.Threading;
 using XUnity.AutoTranslator.Plugin.Core.Configuration;
-using UnityEngine.UI;
 using XUnity.AutoTranslator.Plugin.Core.Constants;
 using XUnity.AutoTranslator.Plugin.Core.Utilities;
 using UnityEngine;

+ 0 - 3
src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj

@@ -19,9 +19,6 @@
       <Reference Include="UnityEngine">
          <HintPath>..\..\libs\UnityEngine.dll</HintPath>
       </Reference>
-      <Reference Include="UnityEngine.UI">
-         <HintPath>..\..\libs\UnityEngine.UI.dll</HintPath>
-      </Reference>
    </ItemGroup>
 
    <ItemGroup>

+ 197 - 0
src/XUnity.RuntimeHooker.Core/Utilities/ReflectionCache.cs

@@ -0,0 +1,197 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace XUnity.RuntimeHooker.Core.Utilities
+{
+   public static class ReflectionCache
+   {
+      private static Dictionary<MemberLookupKey, CachedMethod> Methods = new Dictionary<MemberLookupKey, CachedMethod>();
+      private static Dictionary<MemberLookupKey, CachedProperty> Properties = new Dictionary<MemberLookupKey, CachedProperty>();
+
+      public static CachedMethod CachedMethod( this Type type, string name )
+      {
+         var key = new MemberLookupKey( type, name );
+         if( !Methods.TryGetValue( key, out var cachedMember ) )
+         {
+            var currentType = type;
+            MethodInfo method = null;
+
+            while( method == null && currentType != null )
+            {
+               method = currentType.GetMethod( name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic );
+               currentType = currentType.BaseType;
+            }
+
+            if( method != null )
+            {
+               cachedMember = new CachedMethod( method );
+            }
+
+            // also cache nulls!
+            Methods[ key ] = cachedMember;
+         }
+
+         return cachedMember;
+      }
+
+      public static CachedProperty CachedProperty( this Type type, string name )
+      {
+         var key = new MemberLookupKey( type, name );
+         if( !Properties.TryGetValue( key, out var cachedMember ) )
+         {
+            var currentType = type;
+            PropertyInfo property = null;
+
+            while( property == null && currentType != null )
+            {
+               property = currentType.GetProperty( name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic );
+               currentType = currentType.BaseType;
+            }
+
+            if( property != null )
+            {
+               cachedMember = new CachedProperty( property );
+            }
+
+            // also cache nulls!
+            Properties[ key ] = cachedMember;
+         }
+
+         return cachedMember;
+      }
+
+      public struct MemberLookupKey
+      {
+         public MemberLookupKey( Type type, string memberName )
+         {
+            Type = type;
+            MemberName = memberName;
+         }
+
+         public Type Type { get; set; }
+
+         public string MemberName { get; set; }
+
+         // override object.Equals
+         public override bool Equals( object obj )
+         {
+            if( obj is MemberLookupKey key )
+            {
+               return Type == key.Type && MemberName == key.MemberName;
+            }
+            return false;
+         }
+
+         // override object.GetHashCode
+         public override int GetHashCode()
+         {
+            return Type.GetHashCode() + MemberName.GetHashCode();
+         }
+      }
+   }
+
+   public class CachedMethod
+   {
+      private static readonly object[] Args0 = new object[ 0 ];
+      private static readonly object[] Args1 = new object[ 1 ];
+      private static readonly object[] Args2 = new object[ 2 ];
+
+      private Func<object, object[], object> _invoke;
+
+      public CachedMethod( MethodInfo method )
+      {
+         _invoke = ExpressionHelper.CreateFastInvoke( method );
+      }
+
+      public object Invoke( object instance, object[] arguments )
+      {
+         return _invoke( instance, arguments );
+      }
+
+      public object Invoke( object instance )
+      {
+         return _invoke( instance, Args0 );
+      }
+
+      public object Invoke( object instance, object arg1 )
+      {
+         try
+         {
+            Args1[ 0 ] = arg1;
+            return _invoke( instance, Args1 );
+         }
+         finally
+         {
+            Args1[ 0 ] = null;
+         }
+      }
+
+      public object Invoke( object instance, object arg1, object arg2 )
+      {
+         try
+         {
+            Args2[ 0 ] = arg1;
+            Args2[ 1 ] = arg2;
+            return _invoke( instance, Args2 );
+         }
+         finally
+         {
+            Args2[ 0 ] = null;
+            Args2[ 1 ] = null;
+         }
+      }
+   }
+
+   public class CachedProperty
+   {
+      private static readonly object[] Args0 = new object[ 0 ];
+      private static readonly object[] Args1 = new object[ 1 ];
+
+      private Func<object, object[], object> _set;
+      private Func<object, object[], object> _get;
+
+      public CachedProperty( PropertyInfo propertyInfo )
+      {
+         if( propertyInfo.CanRead )
+         {
+            _get = ExpressionHelper.CreateFastInvoke( propertyInfo.GetGetMethod() );
+         }
+
+         if( propertyInfo.CanWrite )
+         {
+            _set = ExpressionHelper.CreateFastInvoke( propertyInfo.GetSetMethod() );
+         }
+      }
+
+      public object Set( object instance, object[] arguments )
+      {
+         return _set( instance, arguments );
+      }
+
+      public object Set( object instance, object arg1 )
+      {
+         try
+         {
+            Args1[ 0 ] = arg1;
+            return _set( instance, Args1 );
+         }
+         finally
+         {
+            Args1[ 0 ] = null;
+         }
+      }
+
+      public object Get( object instance, object[] arguments )
+      {
+         return _get( instance, arguments );
+      }
+
+      public object Get( object instance )
+      {
+         return _get( instance, Args0 );
+      }
+   }
+}