

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Utils;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Logging;
using XUnity.Common.Utilities;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("XUnity.AutoTranslator.Plugin.Core")]
[assembly: AssemblyCompany("gravydevsupreme")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Common dependencies shared between XUnity Auto Translator and Resource Redirector.")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("XUnity.Common")]
[assembly: AssemblyTitle("XUnity.Common")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
namespace XUnity.Common.Utilities
{
public static class ArrayHelper
{
public static T[] Null<T>()
{
return null;
}
}
public static class CabHelper
{
private static string CreateRandomCab()
{
return "CAB-" + Guid.NewGuid().ToString("N");
}
public static void RandomizeCab(byte[] assetBundleData)
{
string @string = Encoding.ASCII.GetString(assetBundleData, 0, Math.Min(1024, assetBundleData.Length - 4));
int num = @string.IndexOf("CAB-", StringComparison.Ordinal);
if (num >= 0)
{
int num2 = @string.Substring(num).IndexOf('\0');
if (num2 >= 0 && num2 <= 36)
{
string s = CreateRandomCab();
Buffer.BlockCopy(Encoding.ASCII.GetBytes(s), 36 - num2, assetBundleData, num, num2);
}
}
}
public static void RandomizeCabWithAnyLength(byte[] assetBundleData)
{
FindAndReplaceCab("CAB-", 0, assetBundleData, 2048);
}
private static void FindAndReplaceCab(string ansiStringToStartWith, byte byteToEndWith, byte[] data, int maxIterations = -1)
{
int num = Math.Min(data.Length, maxIterations);
if (num == -1)
{
num = data.Length;
}
int num2 = 0;
int length = ansiStringToStartWith.Length;
string text = Guid.NewGuid().ToString("N");
int num3 = 0;
for (int i = 0; i < num; i++)
{
char c = (char)data[i];
if (num2 == length)
{
while (data[i] != byteToEndWith && i < num)
{
if (num3 >= text.Length)
{
num3 = 0;
text = Guid.NewGuid().ToString("N");
}
data[i++] = (byte)text[num3++];
}
break;
}
num2 = ((c == ansiStringToStartWith[num2]) ? (num2 + 1) : 0);
}
}
}
internal static class CecilFastReflectionHelper
{
private static readonly Type[] DynamicMethodDelegateArgs = new Type[2]
{
typeof(object),
typeof(object[])
};
public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_0238: Unknown result type (might be due to invalid IL or missing references)
//IL_0225: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_028c: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
//IL_0297: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Expected O, but got Unknown
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Expected O, but got Unknown
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Expected O, but got Unknown
DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + method.DeclaringType.FullName + "." + method.Name + ">", typeof(object), DynamicMethodDelegateArgs);
ILProcessor iLProcessor = val.GetILProcessor();
ParameterInfo[] parameters = method.GetParameters();
bool flag = true;
if (!method.IsStatic)
{
iLProcessor.Emit(OpCodes.Ldarg_0);
if (method.DeclaringType.IsValueType)
{
Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, method.DeclaringType);
}
}
for (int i = 0; i < parameters.Length; i++)
{
Type type = parameters[i].ParameterType;
bool isByRef = type.IsByRef;
if (isByRef)
{
type = type.GetElementType();
}
bool isValueType = type.IsValueType;
if (isByRef && isValueType && !directBoxValueAccess)
{
iLProcessor.Emit(OpCodes.Ldarg_1);
iLProcessor.Emit(OpCodes.Ldc_I4, i);
}
iLProcessor.Emit(OpCodes.Ldarg_1);
iLProcessor.Emit(OpCodes.Ldc_I4, i);
if (isByRef && !isValueType)
{
Extensions.Emit(iLProcessor, OpCodes.Ldelema, typeof(object));
continue;
}
iLProcessor.Emit(OpCodes.Ldelem_Ref);
if (!isValueType)
{
continue;
}
if (!isByRef || !directBoxValueAccess)
{
Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, type);
if (isByRef)
{
Extensions.Emit(iLProcessor, OpCodes.Box, type);
iLProcessor.Emit(OpCodes.Dup);
Extensions.Emit(iLProcessor, OpCodes.Unbox, type);
if (flag)
{
flag = false;
val.Definition.Body.Variables.Add(new VariableDefinition((TypeReference)new PinnedType((TypeReference)new PointerType(((MemberReference)val.Definition).Module.TypeSystem.Void))));
}
iLProcessor.Emit(OpCodes.Stloc_0);
iLProcessor.Emit(OpCodes.Stelem_Ref);
iLProcessor.Emit(OpCodes.Ldloc_0);
}
}
else
{
Extensions.Emit(iLProcessor, OpCodes.Unbox, type);
}
}
if (method.IsConstructor)
{
Extensions.Emit(iLProcessor, OpCodes.Newobj, (MethodBase)(method as ConstructorInfo));
}
else if (method.IsFinal || !method.IsVirtual || forceNonVirtcall)
{
Extensions.Emit(iLProcessor, OpCodes.Call, (MethodBase)(method as MethodInfo));
}
else
{
Extensions.Emit(iLProcessor, OpCodes.Callvirt, (MethodBase)(method as MethodInfo));
}
Type type2 = (method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType);
if ((object)type2 != typeof(void))
{
if (type2.IsValueType)
{
Extensions.Emit(iLProcessor, OpCodes.Box, type2);
}
}
else
{
iLProcessor.Emit(OpCodes.Ldnull);
}
iLProcessor.Emit(OpCodes.Ret);
return (FastReflectionDelegate)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(FastReflectionDelegate));
}
public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
{
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
if ((object)fieldInfo == null)
{
throw new ArgumentNullException("fieldInfo");
}
if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
{
throw new ArgumentException("FieldInfo type does not match return type.");
}
if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
{
throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
}
DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + typeof(T).FullName + ".Get_" + fieldInfo.Name + ">", typeof(F), new Type[1] { typeof(T) });
ILProcessor iLProcessor = val.GetILProcessor();
if (!fieldInfo.IsStatic)
{
iLProcessor.Emit(OpCodes.Ldarg_0);
Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.DeclaringType);
}
Extensions.Emit(iLProcessor, fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
{
Extensions.Emit(iLProcessor, OpCodes.Box, fieldInfo.FieldType);
}
iLProcessor.Emit(OpCodes.Ret);
return (Func<T, F>)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(Func<T, F>));
}
public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
{
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
if ((object)fieldInfo == null)
{
throw new ArgumentNullException("fieldInfo");
}
if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
{
throw new ArgumentException("FieldInfo type does not match argument type.");
}
if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
{
throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
}
DynamicMethodDefinition val = new DynamicMethodDefinition("FastReflection<" + typeof(T).FullName + ".Set_" + fieldInfo.Name + ">", (Type)null, new Type[2]
{
typeof(T),
typeof(F)
});
ILProcessor iLProcessor = val.GetILProcessor();
if (!fieldInfo.IsStatic)
{
iLProcessor.Emit(OpCodes.Ldarg_0);
Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.DeclaringType);
}
iLProcessor.Emit(OpCodes.Ldarg_1);
if ((object)fieldInfo.FieldType != typeof(F))
{
if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
{
if (fieldInfo.FieldType.IsValueType)
{
Extensions.Emit(iLProcessor, OpCodes.Unbox_Any, fieldInfo.FieldType);
}
else
{
Extensions.Emit(iLProcessor, OpCodes.Box, fieldInfo.FieldType);
}
}
else
{
Extensions.Emit(iLProcessor, OpCodes.Castclass, fieldInfo.FieldType);
}
}
Extensions.Emit(iLProcessor, fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
iLProcessor.Emit(OpCodes.Ret);
return (Action<T, F>)Extensions.CreateDelegate((MethodBase)val.Generate(), typeof(Action<T, F>));
}
}
public static class CustomFastReflectionHelper
{
private struct FastReflectionDelegateKey
{
public MethodBase Method { get; }
public bool DirectBoxValueAccess { get; }
public bool ForceNonVirtCall { get; }
public FastReflectionDelegateKey(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
{
Method = method;
DirectBoxValueAccess = directBoxValueAccess;
ForceNonVirtCall = forceNonVirtCall;
}
public override bool Equals(object obj)
{
if (obj is FastReflectionDelegateKey fastReflectionDelegateKey && EqualityComparer<MethodBase>.Default.Equals(Method, fastReflectionDelegateKey.Method) && DirectBoxValueAccess == fastReflectionDelegateKey.DirectBoxValueAccess)
{
return ForceNonVirtCall == fastReflectionDelegateKey.ForceNonVirtCall;
}
return false;
}
public override int GetHashCode()
{
return ((1017116076 * -1521134295 + EqualityComparer<MethodBase>.Default.GetHashCode(Method)) * -1521134295 + DirectBoxValueAccess.GetHashCode()) * -1521134295 + ForceNonVirtCall.GetHashCode();
}
}
private static readonly Dictionary<FastReflectionDelegateKey, FastReflectionDelegate> MethodCache = new Dictionary<FastReflectionDelegateKey, FastReflectionDelegate>();
public static FastReflectionDelegate CreateFastDelegate(this MethodBase method, bool directBoxValueAccess = true, bool forceNonVirtCall = false)
{
FastReflectionDelegateKey key = new FastReflectionDelegateKey(method, directBoxValueAccess, forceNonVirtCall);
if (MethodCache.TryGetValue(key, out var value))
{
return value;
}
value = (((object)ClrTypes.DynamicMethodDefinition == null) ? GetFastDelegateForSRE(method, directBoxValueAccess, forceNonVirtCall) : GetFastDelegateForCecil(method, directBoxValueAccess, forceNonVirtCall));
MethodCache.Add(key, value);
return value;
}
public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
{
if ((object)ClrTypes.DynamicMethodDefinition != null)
{
return CreateFastFieldGetterForCecil<T, F>(fieldInfo);
}
return CreateFastFieldGetterForSRE<T, F>(fieldInfo);
}
public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
{
if ((object)ClrTypes.DynamicMethodDefinition != null)
{
return CreateFastFieldSetterForCecil<T, F>(fieldInfo);
}
return CreateFastFieldSetterForSRE<T, F>(fieldInfo);
}
private static FastReflectionDelegate GetFastDelegateForCecil(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
{
try
{
return CecilFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
}
catch (Exception e)
{
try
{
XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
return ReflectionEmitFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
}
catch (Exception e2)
{
XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
return (object target, object[] args) => method.Invoke(target, args);
}
}
}
private static Func<T, F> CreateFastFieldGetterForCecil<T, F>(FieldInfo fieldInfo)
{
try
{
return CecilFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
}
catch (Exception e)
{
try
{
XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
return ReflectionEmitFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
}
catch (Exception e2)
{
XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
return (T target) => (F)fieldInfo.GetValue(target);
}
}
}
private static Action<T, F> CreateFastFieldSetterForCecil<T, F>(FieldInfo fieldInfo)
{
try
{
return CecilFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
}
catch (Exception e)
{
try
{
XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with cecil. Retrying with reflection emit...");
return ReflectionEmitFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
}
catch (Exception e2)
{
XuaLogger.Common.Warn(e2, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
return delegate(T target, F value)
{
fieldInfo.SetValue(target, value);
};
}
}
}
private static FastReflectionDelegate GetFastDelegateForSRE(MethodBase method, bool directBoxValueAccess, bool forceNonVirtCall)
{
try
{
return ReflectionEmitFastReflectionHelper.CreateFastDelegate(method, directBoxValueAccess, forceNonVirtCall);
}
catch (Exception e)
{
XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
return (object target, object[] args) => method.Invoke(target, args);
}
}
private static Func<T, F> CreateFastFieldGetterForSRE<T, F>(FieldInfo fieldInfo)
{
try
{
return ReflectionEmitFastReflectionHelper.CreateFastFieldGetter<T, F>(fieldInfo);
}
catch (Exception e)
{
XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
return (T target) => (F)fieldInfo.GetValue(target);
}
}
private static Action<T, F> CreateFastFieldSetterForSRE<T, F>(FieldInfo fieldInfo)
{
try
{
return ReflectionEmitFastReflectionHelper.CreateFastFieldSetter<T, F>(fieldInfo);
}
catch (Exception e)
{
XuaLogger.Common.Warn(e, "Failed creating fast reflection delegate through with reflection emit. Falling back to standard reflection...");
return delegate(T target, F value)
{
fieldInfo.SetValue(target, value);
};
}
}
}
public static class DiacriticHelper
{
public static string RemoveAllDiacritics(this string input)
{
return new string((from c in input.SafeNormalize(NormalizationForm.FormD)
where CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark
select c).ToArray()).SafeNormalize();
}
private static string SafeNormalize(this string input, NormalizationForm normalizationForm = NormalizationForm.FormC)
{
return ReplaceNonCharacters(input, '?').Normalize(normalizationForm);
}
private static string ReplaceNonCharacters(string input, char replacement)
{
StringBuilder stringBuilder = new StringBuilder(input.Length);
for (int i = 0; i < input.Length; i++)
{
if (char.IsSurrogatePair(input, i))
{
int num = char.ConvertToUtf32(input, i);
i++;
if (IsValidCodePoint(num))
{
stringBuilder.Append(char.ConvertFromUtf32(num));
}
else
{
stringBuilder.Append(replacement);
}
}
else
{
char c = input[i];
if (IsValidCodePoint(c))
{
stringBuilder.Append(c);
}
else
{
stringBuilder.Append(replacement);
}
}
}
return stringBuilder.ToString();
}
private static bool IsValidCodePoint(int point)
{
if (point >= 64976)
{
if (point >= 65008 && (point & 0xFFFF) != 65535 && (point & 0xFFFE) != 65534)
{
return point <= 1114111;
}
return false;
}
return true;
}
}
public static class ExpressionHelper
{
public static Delegate CreateTypedFastInvoke(MethodBase method)
{
if ((object)method == null)
{
throw new ArgumentNullException("method");
}
return CreateTypedFastInvokeUnchecked(method);
}
public static Delegate CreateTypedFastInvokeUnchecked(MethodBase method)
{
if ((object)method == null)
{
return null;
}
if (method.IsGenericMethod)
{
throw new ArgumentException("The provided method must not be generic.", "method");
}
if (method is MethodInfo methodInfo)
{
Expression[] arguments;
if (method.IsStatic)
{
ParameterExpression[] array = (from p in methodInfo.GetParameters()
select Expression.Parameter(p.ParameterType, p.Name)).ToArray();
arguments = array;
return Expression.Lambda(Expression.Call(null, methodInfo, arguments), array).Compile();
}
List<ParameterExpression> list = (from p in methodInfo.GetParameters()
select Expression.Parameter(p.ParameterType, p.Name)).ToList();
list.Insert(0, Expression.Parameter(methodInfo.DeclaringType, "instance"));
ParameterExpression instance = list[0];
arguments = list.Skip(1).ToArray();
return Expression.Lambda(Expression.Call(instance, methodInfo, arguments), list.ToArray()).Compile();
}
if (method is ConstructorInfo constructorInfo)
{
ParameterExpression[] array2 = (from p in constructorInfo.GetParameters()
select Expression.Parameter(p.ParameterType, p.Name)).ToArray();
Expression[] arguments = array2;
return Expression.Lambda(Expression.New(constructorInfo, arguments), array2).Compile();
}
throw new ArgumentException("method", "This method only supports MethodInfo and ConstructorInfo.");
}
}
public static class ExtensionDataHelper
{
private static readonly object Sync;
private static readonly WeakDictionary<object, object> WeakDynamicFields;
public static int WeakReferenceCount
{
get
{
lock (Sync)
{
return WeakDynamicFields.Count;
}
}
}
static ExtensionDataHelper()
{
Sync = new object();
WeakDynamicFields = new WeakDictionary<object, object>();
MaintenanceHelper.AddMaintenanceFunction(Cull, 12);
}
public static void SetExtensionData<T>(this object obj, T t)
{
lock (Sync)
{
if (WeakDynamicFields.TryGetValue(obj, out var value))
{
if (value is Dictionary<Type, object> dictionary)
{
dictionary[typeof(T)] = t;
return;
}
Dictionary<Type, object> dictionary2 = new Dictionary<Type, object>();
dictionary2.Add(value.GetType(), value);
dictionary2[typeof(T)] = t;
WeakDynamicFields[obj] = dictionary2;
}
else
{
WeakDynamicFields[obj] = t;
}
}
}
public static T GetOrCreateExtensionData<T>(this object obj) where T : new()
{
if (obj == null)
{
return default(T);
}
lock (Sync)
{
if (WeakDynamicFields.TryGetValue(obj, out var value))
{
if (value is Dictionary<Type, object> dictionary)
{
if (dictionary.TryGetValue(typeof(T), out value))
{
return (T)value;
}
T val = new T();
dictionary[typeof(T)] = val;
return val;
}
if (!(value is T result))
{
Dictionary<Type, object> dictionary2 = new Dictionary<Type, object>();
dictionary2.Add(value.GetType(), value);
T val2 = new T();
dictionary2[typeof(T)] = val2;
WeakDynamicFields[obj] = dictionary2;
return val2;
}
return result;
}
T val3 = new T();
WeakDynamicFields[obj] = val3;
return val3;
}
}
public static T GetExtensionData<T>(this object obj)
{
if (obj == null)
{
return default(T);
}
lock (Sync)
{
if (WeakDynamicFields.TryGetValue(obj, out var value))
{
if (value is Dictionary<Type, object> dictionary && dictionary.TryGetValue(typeof(T), out value))
{
if (!(value is T result))
{
return default(T);
}
return result;
}
if (!(value is T result2))
{
return default(T);
}
return result2;
}
}
return default(T);
}
public static void Cull()
{
lock (Sync)
{
WeakDynamicFields.RemoveCollectedEntries();
}
}
public static List<KeyValuePair<object, object>> GetAllRegisteredObjects()
{
lock (Sync)
{
return IterateAllPairs().ToList();
}
}
public static void Remove(object obj)
{
lock (Sync)
{
WeakDynamicFields.Remove(obj);
}
}
private static IEnumerable<KeyValuePair<object, object>> IterateAllPairs()
{
foreach (KeyValuePair<object, object> kvp in WeakDynamicFields)
{
if (kvp.Value is Dictionary<Type, object> dictionary)
{
foreach (KeyValuePair<Type, object> item in dictionary)
{
yield return new KeyValuePair<object, object>(kvp.Key, item.Value);
}
}
else
{
yield return kvp;
}
}
}
}
public delegate object FastReflectionDelegate(object target, params object[] args);
public static class HookingHelper
{
private static readonly MethodInfo PatchMethod12;
private static readonly MethodInfo PatchMethod20;
private static readonly object Harmony;
private static bool _loggedHarmonyError;
static HookingHelper()
{
PatchMethod12 = ClrTypes.HarmonyInstance?.GetMethod("Patch", new Type[4]
{
ClrTypes.MethodBase,
ClrTypes.HarmonyMethod,
ClrTypes.HarmonyMethod,
ClrTypes.HarmonyMethod
});
PatchMethod20 = ClrTypes.Harmony?.GetMethod("Patch", new Type[5]
{
ClrTypes.MethodBase,
ClrTypes.HarmonyMethod,
ClrTypes.HarmonyMethod,
ClrTypes.HarmonyMethod,
ClrTypes.HarmonyMethod
});
_loggedHarmonyError = false;
try
{
if ((object)ClrTypes.HarmonyInstance != null)
{
Harmony = ClrTypes.HarmonyInstance.GetMethod("Create", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[1] { "xunity.common.hookinghelper" });
}
else if ((object)ClrTypes.Harmony != null)
{
Harmony = ClrTypes.Harmony.GetConstructor(new Type[1] { typeof(string) }).Invoke(new object[1] { "xunity.common.hookinghelper" });
}
else
{
XuaLogger.Common.Error("An unexpected exception occurred during harmony initialization, likely caused by unknown Harmony version. Harmony hooks will be unavailable!");
}
}
catch (Exception e)
{
XuaLogger.Common.Error(e, "An unexpected exception occurred during harmony initialization. Harmony hooks will be unavailable!");
}
}
public static void PatchAll(IEnumerable<Type> types, bool forceExternHooks)
{
foreach (Type type in types)
{
PatchType(type, forceExternHooks);
}
}
public static void PatchAll(IEnumerable<Type[]> types, bool forceMonoModHooks)
{
foreach (Type[] type in types)
{
for (int i = 0; i < type.Length && !PatchType(type[i], forceMonoModHooks); i++)
{
}
}
}
public static bool PatchType(Type type, bool forceExternHooks)
{
MethodBase methodBase = null;
IntPtr intPtr = IntPtr.Zero;
try
{
if (Harmony == null && !_loggedHarmonyError)
{
_loggedHarmonyError = true;
XuaLogger.Common.Warn("Harmony is not loaded or could not be initialized. Using fallback hooks instead.");
}
BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
MethodInfo method = type.GetMethod("Prepare", bindingAttr);
if ((object)method == null || (bool)method.Invoke(null, new object[1] { Harmony }))
{
try
{
methodBase = (MethodBase)(type.GetMethod("TargetMethod", bindingAttr)?.Invoke(null, new object[1] { Harmony }));
}
catch
{
}
try
{
intPtr = ((IntPtr?)type.GetMethod("TargetMethodPointer", bindingAttr)?.Invoke(null, null)) ?? IntPtr.Zero;
}
catch
{
}
if ((object)methodBase == null && intPtr == IntPtr.Zero)
{
if ((object)methodBase != null)
{
XuaLogger.Common.Warn("Could not hook '" + methodBase.DeclaringType.FullName + "." + methodBase.Name + "'. Likely due differences between different versions of the engine or text framework.");
}
else
{
XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
}
return false;
}
MethodInfo method2 = type.GetMethod("Prefix", bindingAttr);
MethodInfo method3 = type.GetMethod("Postfix", bindingAttr);
MethodInfo method4 = type.GetMethod("Finalizer", bindingAttr);
if ((object)methodBase == null || forceExternHooks || Harmony == null || ((object)method2 == null && (object)method3 == null && (object)method4 == null))
{
return PatchWithExternHooks(type, methodBase, intPtr, forced: true);
}
if ((object)methodBase != null)
{
try
{
int? priority = type.GetCustomAttributes(typeof(HookingHelperPriorityAttribute), inherit: false).OfType<HookingHelperPriorityAttribute>().FirstOrDefault()?.priority;
object obj3 = (((object)method2 != null) ? CreateHarmonyMethod(method2, priority) : null);
object obj4 = (((object)method3 != null) ? CreateHarmonyMethod(method3, priority) : null);
object obj5 = (((object)method4 != null) ? CreateHarmonyMethod(method4, priority) : null);
if ((object)PatchMethod12 != null)
{
PatchMethod12.Invoke(Harmony, new object[4] { methodBase, obj3, obj4, null });
}
else
{
PatchMethod20.Invoke(Harmony, new object[5] { methodBase, obj3, obj4, null, obj5 });
}
XuaLogger.Common.Debug("Hooked " + methodBase.DeclaringType.FullName + "." + methodBase.Name + " through Harmony hooks.");
return true;
}
catch (Exception e) when (((Func<bool>)delegate
{
// Could not convert BlockContainer to single expression
System.Runtime.CompilerServices.Unsafe.SkipInit(out int num);
if (e.FirstInnerExceptionOfType<PlatformNotSupportedException>() == null)
{
ArgumentException ex = e.FirstInnerExceptionOfType<ArgumentException>();
num = ((ex != null && ex.Message?.Contains("no body") == true) ? 1 : 0);
}
else
{
num = 1;
}
return num != 0;
}).Invoke())
{
return PatchWithExternHooks(type, methodBase, intPtr, forced: false);
}
}
XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
}
}
catch (Exception e2)
{
if ((object)methodBase != null)
{
XuaLogger.Common.Warn(e2, "An error occurred while patching property/method '" + methodBase.DeclaringType.FullName + "." + methodBase.Name + "'. Failing hook: '" + type.Name + "'.");
}
else
{
XuaLogger.Common.Warn(e2, "An error occurred while patching property/method. Failing hook: '" + type.Name + "'.");
}
}
return false;
}
private static bool PatchWithExternHooks(Type type, MethodBase original, IntPtr originalPtr, bool forced)
{
BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
if ((object)ClrTypes.Imports != null)
{
if (originalPtr == IntPtr.Zero)
{
XuaLogger.Common.Warn("Could not hook '" + type.Name + "'. Likely due differences between different versions of the engine or text framework.");
return false;
}
IntPtr? intPtr = type.GetMethod("ML_Detour", bindingAttr)?.MethodHandle.GetFunctionPointer();
if (intPtr.HasValue && intPtr.Value != IntPtr.Zero)
{
ClrTypes.Imports.GetMethod("Hook", bindingAttr).Invoke(null, new object[2] { originalPtr, intPtr.Value });
XuaLogger.Common.Debug("Hooked " + type.Name + " through MelonMod Imports.Hook method.");
return true;
}
XuaLogger.Common.Warn("Could not hook '" + type.Name + "' because no detour method was found.");
}
else
{
if ((object)original == null)
{
XuaLogger.Common.Warn("Cannot hook '" + type.Name + "'. Could not locate the original method. Failing hook: '" + type.Name + "'.");
return false;
}
if ((object)ClrTypes.Hook == null || (object)ClrTypes.NativeDetour == null)
{
XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. MonoMod hooks is not supported in this runtime as MonoMod is not loaded. Failing hook: '" + type.Name + "'.");
return false;
}
object obj = type.GetMethod("Get_MM_Detour", bindingAttr)?.Invoke(null, null) ?? type.GetMethod("MM_Detour", bindingAttr);
if (obj != null)
{
string text = "(managed)";
object obj2;
try
{
obj2 = ClrTypes.Hook.GetConstructor(new Type[2]
{
typeof(MethodBase),
typeof(MethodInfo)
}).Invoke(new object[2] { original, obj });
obj2.GetType().GetMethod("Apply").Invoke(obj2, null);
}
catch (Exception e) when (((Func<bool>)delegate
{
// Could not convert BlockContainer to single expression
System.Runtime.CompilerServices.Unsafe.SkipInit(out int num);
if (e.FirstInnerExceptionOfType<NullReferenceException>() == null)
{
NotSupportedException ex = e.FirstInnerExceptionOfType<NotSupportedException>();
num = ((ex != null && ex.Message?.Contains("Body-less") == true) ? 1 : 0);
}
else
{
num = 1;
}
return num != 0;
}).Invoke())
{
text = "(native)";
obj2 = ClrTypes.NativeDetour.GetConstructor(new Type[2]
{
typeof(MethodBase),
typeof(MethodBase)
}).Invoke(new object[2] { original, obj });
obj2.GetType().GetMethod("Apply").Invoke(obj2, null);
}
type.GetMethod("MM_Init", bindingAttr)?.Invoke(null, new object[1] { obj2 });
if (forced)
{
XuaLogger.Common.Debug("Hooked " + original.DeclaringType.FullName + "." + original.Name + " through forced MonoMod hooks. " + text);
}
else
{
XuaLogger.Common.Debug("Hooked " + original.DeclaringType.FullName + "." + original.Name + " through MonoMod hooks. " + text);
}
return true;
}
if (forced)
{
XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. Harmony is not supported in this runtime and no alternate MonoMod hook has been implemented. Failing hook: '" + type.Name + "'.");
}
else
{
XuaLogger.Common.Warn("Cannot hook '" + original.DeclaringType.FullName + "." + original.Name + "'. Harmony is not supported in this runtime and no alternate MonoMod hook has been implemented. Failing hook: '" + type.Name + "'.");
}
}
return false;
}
private static object CreateHarmonyMethod(MethodInfo method, int? priority)
{
object obj = ClrTypes.HarmonyMethod.GetConstructor(new Type[1] { typeof(MethodInfo) }).Invoke(new object[1] { method });
if (priority.HasValue)
{
(ClrTypes.HarmonyMethod.GetField("priority", BindingFlags.Instance | BindingFlags.Public) ?? ClrTypes.HarmonyMethod.GetField("prioritiy", BindingFlags.Instance | BindingFlags.Public)).SetValue(obj, priority.Value);
}
return obj;
}
}
public class HookingHelperPriorityAttribute : Attribute
{
public int priority;
public HookingHelperPriorityAttribute(int priority)
{
this.priority = priority;
}
}
public static class HookPriority
{
public const int Last = 0;
public const int VeryLow = 100;
public const int Low = 200;
public const int LowerThanNormal = 300;
public const int Normal = 400;
public const int HigherThanNormal = 500;
public const int High = 600;
public const int VeryHigh = 700;
public const int First = 800;
}
public static class ListExtensions
{
public static void BinarySearchInsert<T>(this List<T> items, T item) where T : IComparable<T>
{
int num = items.BinarySearch(item);
if (num < 0)
{
items.Insert(~num, item);
}
else
{
items.Insert(num, item);
}
}
}
public static class MaintenanceHelper
{
private class ActionRegistration
{
public Action Action { get; }
public int Filter { get; }
public ActionRegistration(Action action, int filter)
{
Action = action;
Filter = filter;
}
}
private static readonly object Sync = new object();
private static readonly List<ActionRegistration> RegisteredActions = new List<ActionRegistration>();
private static bool _initialized;
public static void AddMaintenanceFunction(Action action, int filter)
{
lock (Sync)
{
if (!_initialized)
{
_initialized = true;
StartMaintenance();
}
ActionRegistration item = new ActionRegistration(action, filter);
RegisteredActions.Add(item);
}
}
private static void StartMaintenance()
{
Thread thread = new Thread(MaintenanceLoop);
thread.IsBackground = true;
thread.Start();
}
private static void MaintenanceLoop(object state)
{
int num = 0;
while (true)
{
lock (Sync)
{
foreach (ActionRegistration registeredAction in RegisteredActions)
{
if (num % registeredAction.Filter == 0)
{
try
{
registeredAction.Action();
}
catch (Exception e)
{
XuaLogger.Common.Error(e, "An unexpected error occurred during maintenance.");
}
}
}
}
num++;
Thread.Sleep(5000);
}
}
}
public static class Paths
{
private static string _gameRoot;
public static string GameRoot
{
get
{
return _gameRoot ?? GetAndSetGameRoot();
}
set
{
_gameRoot = value;
}
}
public static void Initialize()
{
GetAndSetGameRoot();
}
private static string GetAndSetGameRoot()
{
return _gameRoot = new DirectoryInfo(Application.dataPath).Parent.FullName;
}
}
public static class ReflectionCache
{
private struct MemberLookupKey
{
public Type Type { get; set; }
public string MemberName { get; set; }
public MemberLookupKey(Type type, string memberName)
{
Type = type;
MemberName = memberName;
}
public override bool Equals(object obj)
{
if (obj is MemberLookupKey memberLookupKey)
{
if ((object)Type == memberLookupKey.Type)
{
return MemberName == memberLookupKey.MemberName;
}
return false;
}
return false;
}
public override int GetHashCode()
{
return Type.GetHashCode() + MemberName.GetHashCode();
}
}
private static Dictionary<MemberLookupKey, CachedMethod> Methods = new Dictionary<MemberLookupKey, CachedMethod>();
private static Dictionary<MemberLookupKey, CachedProperty> Properties = new Dictionary<MemberLookupKey, CachedProperty>();
private static Dictionary<MemberLookupKey, CachedField> Fields = new Dictionary<MemberLookupKey, CachedField>();
public static CachedMethod CachedMethod(this Type type, string name)
{
return type.CachedMethod(name, (Type[])null);
}
public static CachedMethod CachedMethod(this Type type, string name, params Type[] types)
{
MemberLookupKey key = new MemberLookupKey(type, name);
if (!Methods.TryGetValue(key, out var value))
{
Type type2 = type;
MethodInfo methodInfo = null;
while ((object)methodInfo == null && (object)type2 != null)
{
methodInfo = ((types != null && types.Length != 0) ? type2.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, types, null) : type2.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
type2 = type2.BaseType;
}
if ((object)methodInfo != null)
{
value = new CachedMethod(methodInfo);
}
Methods[key] = value;
}
return value;
}
public static CachedProperty CachedProperty(this Type type, string name)
{
MemberLookupKey key = new MemberLookupKey(type, name);
if (!Properties.TryGetValue(key, out var value))
{
Type type2 = type;
PropertyInfo propertyInfo = null;
while ((object)propertyInfo == null && (object)type2 != null)
{
propertyInfo = type2.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
type2 = type2.BaseType;
}
if ((object)propertyInfo != null)
{
value = new CachedProperty(propertyInfo);
}
Properties[key] = value;
}
return value;
}
public static CachedField CachedField(this Type type, string name)
{
MemberLookupKey key = new MemberLookupKey(type, name);
if (!Fields.TryGetValue(key, out var value))
{
Type type2 = type;
FieldInfo fieldInfo = null;
while ((object)fieldInfo == null && (object)type2 != null)
{
fieldInfo = type2.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
type2 = type2.BaseType;
}
if ((object)fieldInfo != null)
{
value = new CachedField(fieldInfo);
}
Fields[key] = value;
}
return value;
}
public static CachedField CachedFieldByIndex(this Type type, int index, Type fieldType, BindingFlags flags)
{
FieldInfo[] array = (from x in type.GetFields(flags)
where (object)x.FieldType == fieldType
select x).ToArray();
if (index < array.Length)
{
return new CachedField(array[index]);
}
return null;
}
}
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 FastReflectionDelegate _invoke;
internal CachedMethod(MethodInfo method)
{
_invoke = method.CreateFastDelegate();
}
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 FastReflectionDelegate _set;
private FastReflectionDelegate _get;
public Type PropertyType { get; }
internal CachedProperty(PropertyInfo propertyInfo)
{
if (propertyInfo.CanRead)
{
_get = propertyInfo.GetGetMethod(nonPublic: true).CreateFastDelegate();
}
if (propertyInfo.CanWrite)
{
_set = propertyInfo.GetSetMethod(nonPublic: true).CreateFastDelegate();
}
PropertyType = propertyInfo.PropertyType;
}
public void Set(object instance, object[] arguments)
{
if (_set != null)
{
_set(instance, arguments);
}
}
public void Set(object instance, object arg1)
{
if (_set == null)
{
return;
}
try
{
Args1[0] = arg1;
_set(instance, Args1);
}
finally
{
Args1[0] = null;
}
}
public object Get(object instance, object[] arguments)
{
if (_get == null)
{
return null;
}
return _get(instance, arguments);
}
public object Get(object instance)
{
if (_get == null)
{
return null;
}
return _get(instance, Args0);
}
}
public class CachedField
{
private Func<object, object> _get;
private Action<object, object> _set;
public Type FieldType { get; }
internal CachedField(FieldInfo fieldInfo)
{
_get = CustomFastReflectionHelper.CreateFastFieldGetter<object, object>(fieldInfo);
_set = CustomFastReflectionHelper.CreateFastFieldSetter<object, object>(fieldInfo);
FieldType = fieldInfo.FieldType;
}
public void Set(object instance, object value)
{
if (_set != null)
{
_set(instance, value);
}
}
public object Get(object instance)
{
if (_get == null)
{
return null;
}
return _get(instance);
}
}
internal static class ReflectionEmitFastReflectionHelper
{
private static readonly Type[] DynamicMethodDelegateArgs = new Type[2]
{
typeof(object),
typeof(object[])
};
public static FastReflectionDelegate CreateFastDelegate(MethodBase method, bool directBoxValueAccess, bool forceNonVirtcall)
{
DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + method.DeclaringType.FullName + "." + method.Name + ">", typeof(object), DynamicMethodDelegateArgs, method.DeclaringType.Module, skipVisibility: true);
ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
ParameterInfo[] parameters = method.GetParameters();
bool flag = true;
if (!method.IsStatic)
{
iLGenerator.Emit(OpCodes.Ldarg_0);
if (method.DeclaringType.IsValueType)
{
iLGenerator.Emit(OpCodes.Unbox_Any, method.DeclaringType);
}
}
for (int i = 0; i < parameters.Length; i++)
{
Type type = parameters[i].ParameterType;
bool isByRef = type.IsByRef;
if (isByRef)
{
type = type.GetElementType();
}
bool isValueType = type.IsValueType;
if (isByRef && isValueType && !directBoxValueAccess)
{
iLGenerator.Emit(OpCodes.Ldarg_1);
iLGenerator.Emit(OpCodes.Ldc_I4, i);
}
iLGenerator.Emit(OpCodes.Ldarg_1);
iLGenerator.Emit(OpCodes.Ldc_I4, i);
if (isByRef && !isValueType)
{
iLGenerator.Emit(OpCodes.Ldelema, typeof(object));
continue;
}
iLGenerator.Emit(OpCodes.Ldelem_Ref);
if (!isValueType)
{
continue;
}
if (!isByRef || !directBoxValueAccess)
{
iLGenerator.Emit(OpCodes.Unbox_Any, type);
if (isByRef)
{
iLGenerator.Emit(OpCodes.Box, type);
iLGenerator.Emit(OpCodes.Dup);
iLGenerator.Emit(OpCodes.Unbox, type);
if (flag)
{
flag = false;
throw new NotImplementedException("No idea how to implement this...");
}
iLGenerator.Emit(OpCodes.Stloc_0);
iLGenerator.Emit(OpCodes.Stelem_Ref);
iLGenerator.Emit(OpCodes.Ldloc_0);
}
}
else
{
iLGenerator.Emit(OpCodes.Unbox, type);
}
}
if (method.IsConstructor)
{
iLGenerator.Emit(OpCodes.Newobj, method as ConstructorInfo);
}
else if (method.IsFinal || !method.IsVirtual || forceNonVirtcall)
{
iLGenerator.Emit(OpCodes.Call, method as MethodInfo);
}
else
{
iLGenerator.Emit(OpCodes.Callvirt, method as MethodInfo);
}
Type type2 = (method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType);
if ((object)type2 != typeof(void))
{
if (type2.IsValueType)
{
iLGenerator.Emit(OpCodes.Box, type2);
}
}
else
{
iLGenerator.Emit(OpCodes.Ldnull);
}
iLGenerator.Emit(OpCodes.Ret);
return (FastReflectionDelegate)dynamicMethod.CreateDelegate(typeof(FastReflectionDelegate));
}
public static Func<T, F> CreateFastFieldGetter<T, F>(FieldInfo fieldInfo)
{
if ((object)fieldInfo == null)
{
throw new ArgumentNullException("fieldInfo");
}
if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
{
throw new ArgumentException("FieldInfo type does not match return type.");
}
if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
{
throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
}
DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + typeof(T).FullName + ".Get_" + fieldInfo.Name + ">", typeof(F), new Type[1] { typeof(T) }, fieldInfo.DeclaringType.Module, skipVisibility: true);
ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
if (!fieldInfo.IsStatic)
{
iLGenerator.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
}
iLGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
{
iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType);
}
iLGenerator.Emit(OpCodes.Ret);
return (Func<T, F>)dynamicMethod.CreateDelegate(typeof(Func<T, F>));
}
public static Action<T, F> CreateFastFieldSetter<T, F>(FieldInfo fieldInfo)
{
if ((object)fieldInfo == null)
{
throw new ArgumentNullException("fieldInfo");
}
if (!typeof(F).IsAssignableFrom(fieldInfo.FieldType))
{
throw new ArgumentException("FieldInfo type does not match argument type.");
}
if ((object)typeof(T) != typeof(object) && ((object)fieldInfo.DeclaringType == null || !fieldInfo.DeclaringType.IsAssignableFrom(typeof(T))))
{
throw new MissingFieldException(typeof(T).Name, fieldInfo.Name);
}
DynamicMethod dynamicMethod = new DynamicMethod("FastReflection<" + typeof(T).FullName + ".Set_" + fieldInfo.Name + ">", null, new Type[2]
{
typeof(T),
typeof(F)
}, fieldInfo.DeclaringType.Module, skipVisibility: true);
ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
if (!fieldInfo.IsStatic)
{
iLGenerator.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(OpCodes.Castclass, fieldInfo.DeclaringType);
}
iLGenerator.Emit(OpCodes.Ldarg_1);
if ((object)fieldInfo.FieldType != typeof(F))
{
if (fieldInfo.FieldType.IsValueType != typeof(F).IsValueType)
{
if (fieldInfo.FieldType.IsValueType)
{
iLGenerator.Emit(OpCodes.Unbox, fieldInfo.FieldType);
}
else
{
iLGenerator.Emit(OpCodes.Box, fieldInfo.FieldType);
}
}
else
{
iLGenerator.Emit(OpCodes.Castclass, fieldInfo.FieldType);
}
}
iLGenerator.Emit(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
iLGenerator.Emit(OpCodes.Ret);
return (Action<T, F>)dynamicMethod.CreateDelegate(typeof(Action<T, F>));
}
}
public static class TimeHelper
{
public static float realtimeSinceStartup => Time.realtimeSinceStartup;
}
public class UnityObjectReferenceComparer : IEqualityComparer<object>
{
public static readonly UnityObjectReferenceComparer Default = new UnityObjectReferenceComparer();
public new bool Equals(object x, object y)
{
return x == y;
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
}
public class WeakReference<T> : WeakReference where T : class
{
public new T Target => (T)base.Target;
public static WeakReference<T> Create(T target)
{
if (target == null)
{
return WeakNullReference<T>.Singleton;
}
return new WeakReference<T>(target);
}
protected WeakReference(T target)
: base(target, trackResurrection: false)
{
}
}
internal class WeakNullReference<T> : WeakReference<T> where T : class
{
public static readonly WeakNullReference<T> Singleton = new WeakNullReference<T>();
public override bool IsAlive => true;
private WeakNullReference()
: base((T)null)
{
}
}
internal sealed class WeakKeyReference<T> : WeakReference<T> where T : class
{
public readonly int HashCode;
public WeakKeyReference(T key, WeakKeyComparer<T> comparer)
: base(key)
{
HashCode = comparer.GetHashCode(key);
}
}
internal sealed class WeakKeyComparer<T> : IEqualityComparer<object> where T : class
{
private IEqualityComparer<T> comparer;
internal WeakKeyComparer(IEqualityComparer<T> comparer)
{
if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}
this.comparer = comparer;
}
public int GetHashCode(object obj)
{
if (obj is WeakKeyReference<T> weakKeyReference)
{
return weakKeyReference.HashCode;
}
return comparer.GetHashCode((T)obj);
}
public new bool Equals(object x, object y)
{
bool isDead;
T target = GetTarget(x, out isDead);
bool isDead2;
T target2 = GetTarget(y, out isDead2);
if (isDead)
{
if (!isDead2)
{
return false;
}
return x == y;
}
if (isDead2)
{
return false;
}
return comparer.Equals(target, target2);
}
private static T GetTarget(object obj, out bool isDead)
{
T result;
if (obj is WeakKeyReference<T> weakKeyReference)
{
result = weakKeyReference.Target;
isDead = !weakKeyReference.IsAlive;
}
else
{
result = (T)obj;
isDead = false;
}
return result;
}
}
public sealed class WeakDictionary<TKey, TValue> : BaseDictionary<TKey, TValue> where TKey : class
{
private Dictionary<object, TValue> dictionary;
private WeakKeyComparer<TKey> comparer;
public override int Count => dictionary.Count;
public WeakDictionary()
: this(0, (IEqualityComparer<TKey>)null)
{
}
public WeakDictionary(int capacity)
: this(capacity, (IEqualityComparer<TKey>)null)
{
}
public WeakDictionary(IEqualityComparer<TKey> comparer)
: this(0, comparer)
{
}
public WeakDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
this.comparer = new WeakKeyComparer<TKey>(comparer);
dictionary = new Dictionary<object, TValue>(capacity, this.comparer);
}
public override void Add(TKey key, TValue value)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
WeakReference<TKey> key2 = new WeakKeyReference<TKey>(key, comparer);
dictionary.Add(key2, value);
}
public override bool ContainsKey(TKey key)
{
return dictionary.ContainsKey(key);
}
public override bool Remove(TKey key)
{
return dictionary.Remove(key);
}
public override bool TryGetValue(TKey key, out TValue value)
{
if (dictionary.TryGetValue(key, out value))
{
return true;
}
value = default(TValue);
return false;
}
protected override void SetValue(TKey key, TValue value)
{
WeakReference<TKey> key2 = new WeakKeyReference<TKey>(key, comparer);
dictionary[key2] = value;
}
public override void Clear()
{
dictionary.Clear();
}
public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (KeyValuePair<object, TValue> item in dictionary)
{
WeakReference<TKey> obj = (WeakReference<TKey>)item.Key;
TValue value = item.Value;
TKey target = obj.Target;
if (obj.IsAlive)
{
yield return new KeyValuePair<TKey, TValue>(target, value);
}
}
}
public void RemoveCollectedEntries()
{
List<object> list = null;
foreach (KeyValuePair<object, TValue> item in dictionary)
{
WeakReference<TKey> weakReference = (WeakReference<TKey>)item.Key;
if (!weakReference.IsAlive)
{
if (list == null)
{
list = new List<object>();
}
list.Add(weakReference);
}
}
if (list == null)
{
return;
}
foreach (object item2 in list)
{
dictionary.Remove(item2);
}
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
public abstract class BaseDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
{
private abstract class Collection<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
protected readonly IDictionary<TKey, TValue> dictionary;
public int Count => dictionary.Count;
public bool IsReadOnly => true;
protected Collection(IDictionary<TKey, TValue> dictionary)
{
this.dictionary = dictionary;
}
public void CopyTo(T[] array, int arrayIndex)
{
BaseDictionary<TKey, TValue>.Copy((ICollection<T>)this, array, arrayIndex);
}
public virtual bool Contains(T item)
{
using (IEnumerator<T> enumerator = GetEnumerator())
{
while (enumerator.MoveNext())
{
T current = enumerator.Current;
if (EqualityComparer<T>.Default.Equals(current, item))
{
return true;
}
}
}
return false;
}
public IEnumerator<T> GetEnumerator()
{
foreach (KeyValuePair<TKey, TValue> item in dictionary)
{
yield return GetItem(item);
}
}
protected abstract T GetItem(KeyValuePair<TKey, TValue> pair);
public bool Remove(T item)
{
throw new NotSupportedException("Collection is read-only.");
}
public void Add(T item)
{
throw new NotSupportedException("Collection is read-only.");
}
public void Clear()
{
throw new NotSupportedException("Collection is read-only.");
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryKeyCollectionDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
private class KeyCollection : Collection<TKey>
{
public KeyCollection(IDictionary<TKey, TValue> dictionary)
: base(dictionary)
{
}
protected override TKey GetItem(KeyValuePair<TKey, TValue> pair)
{
return pair.Key;
}
public override bool Contains(TKey item)
{
return dictionary.ContainsKey(item);
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy("System.Collections.Generic.Mscorlib_DictionaryValueCollectionDebugView`2,mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089")]
private class ValueCollection : Collection<TValue>
{
public ValueCollection(IDictionary<TKey, TValue> dictionary)
: base(dictionary)
{
}
protected override TValue GetItem(KeyValuePair<TKey, TValue> pair)
{
return pair.Value;
}
}
private const string PREFIX = "System.Collections.Generic.Mscorlib_";
private const string SUFFIX = ",mscorlib,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089";
private KeyCollection keys;
private ValueCollection values;
public abstract int Count { get; }
public bool IsReadOnly => false;
public ICollection<TKey> Keys
{
get
{
if (keys == null)
{
keys = new KeyCollection(this);
}
return keys;
}
}
public ICollection<TValue> Values
{
get
{
if (values == null)
{
values = new ValueCollection(this);
}
return values;
}
}
public TValue this[TKey key]
{
get
{
if (!TryGetValue(key, out var value))
{
throw new KeyNotFoundException();
}
return value;
}
set
{
SetValue(key, value);
}
}
public abstract void Clear();
public abstract void Add(TKey key, TValue value);
public abstract bool ContainsKey(TKey key);
public abstract bool Remove(TKey key);
public abstract bool TryGetValue(TKey key, out TValue value);
public abstract IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
protected abstract void SetValue(TKey key, TValue value);
public void Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
if (!TryGetValue(item.Key, out var value))
{
return false;
}
return EqualityComparer<TValue>.Default.Equals(value, item.Value);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
Copy(this, array, arrayIndex);
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
if (!Contains(item))
{
return false;
}
return Remove(item.Key);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private static void Copy<T>(ICollection<T> source, T[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (arrayIndex < 0 || arrayIndex > array.Length)
{
throw new ArgumentOutOfRangeException("arrayIndex");
}
if (array.Length - arrayIndex < source.Count)
{
throw new ArgumentException("Destination array is not large enough. Check array.Length and arrayIndex.");
}
foreach (T item in source)
{
array[arrayIndex++] = item;
}
}
}
}
namespace XUnity.Common.MonoMod
{
public static class DetourExtensions
{
public static T GenerateTrampolineEx<T>(this object detour)
{
return (T)(from x in detour.GetType().GetMethods()
where x.Name == "GenerateTrampoline" && x.IsGenericMethod
select x).FirstOrDefault().MakeGenericMethod(typeof(T)).Invoke(detour, null);
}
}
}
namespace XUnity.Common.Logging
{
internal class ConsoleLogger : XuaLogger
{
public ConsoleLogger(string source)
: base(source)
{
}
protected override void Log(LogLevel level, string message)
{
Console.WriteLine(GetDefaultPrefix(level) + " " + message);
}
}
public enum LogLevel
{
Debug,
Info,
Warn,
Error
}
internal class ModLoaderSpecificLogger : XuaLogger
{
public static class BepInExLogLevel
{
public const int None = 0;
public const int Fatal = 1;
public const int Error = 2;
public const int Warning = 4;
public const int Message = 8;
public const int Info = 16;
public const int Debug = 32;
public const int All = 63;
}
private static Action<LogLevel, string> _logMethod;
public ModLoaderSpecificLogger(string source)
: base(source)
{
if (_logMethod != null)
{
return;
}
BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public;
BindingFlags bindingAttr2 = BindingFlags.Instance | BindingFlags.Public;
Type type = Type.GetType("BepInEx.Logging.LogLevel, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.LogLevel, BepInEx.Core", throwOnError: false);
if ((object)type != null)
{
if ((object)(Type.GetType("BepInEx.Logging.ManualLogSource, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.ManualLogSource, BepInEx.Core", throwOnError: false)) != null)
{
MethodInfo method = (Type.GetType("BepInEx.Logging.Logger, BepInEx", throwOnError: false) ?? Type.GetType("BepInEx.Logging.Logger, BepInEx.Core", throwOnError: false)).GetMethod("CreateLogSource", bindingAttr, null, new Type[1] { typeof(string) }, null);
object logInstance2 = method.Invoke(null, new object[1] { base.Source });
MethodInfo method2 = logInstance2.GetType().GetMethod("Log", bindingAttr2, null, new Type[2]
{
type,
typeof(object)
}, null);
FastReflectionDelegate log2 = method2.CreateFastDelegate();
_logMethod = delegate(LogLevel level, string msg)
{
int num2 = Convert(level);
log2(logInstance2, num2, msg);
};
}
else
{
Type type2 = Type.GetType("BepInEx.Logger, BepInEx", throwOnError: false);
object logInstance = type2.GetProperty("CurrentLogger", bindingAttr).GetValue(null, null);
MethodInfo method3 = logInstance.GetType().GetMethod("Log", bindingAttr2, null, new Type[2]
{
type,
typeof(object)
}, null);
FastReflectionDelegate log = method3.CreateFastDelegate();
_logMethod = delegate(LogLevel level, string msg)
{
int num = Convert(level);
log(logInstance, num, msg);
};
}
}
else
{
Type type3 = Type.GetType("MelonLoader.MelonLogger, MelonLoader.ModHandler", throwOnError: false);
if ((object)type3 != null)
{
MethodInfo method4 = type3.GetMethod("Log", bindingAttr, null, new Type[2]
{
typeof(ConsoleColor),
typeof(string)
}, null);
MethodInfo method5 = type3.GetMethod("Log", bindingAttr, null, new Type[1] { typeof(string) }, null);
MethodInfo method6 = type3.GetMethod("LogWarning", bindingAttr, null, new Type[1] { typeof(string) }, null);
MethodInfo method7 = type3.GetMethod("LogError", bindingAttr, null, new Type[1] { typeof(string) }, null);
FastReflectionDelegate logDebug = method4.CreateFastDelegate();
FastReflectionDelegate logInfo = method5.CreateFastDelegate();
FastReflectionDelegate logWarning = method6.CreateFastDelegate();
FastReflectionDelegate logError = method7.CreateFastDelegate();
_logMethod = delegate(LogLevel level, string msg)
{
switch (level)
{
case LogLevel.Debug:
logDebug(null, ConsoleColor.Gray, msg);
break;
case LogLevel.Info:
logInfo(null, msg);
break;
case LogLevel.Warn:
logWarning(null, msg);
break;
case LogLevel.Error:
logError(null, msg);
break;
default:
throw new ArgumentException("level");
}
};
}
}
if (_logMethod != null)
{
return;
}
throw new Exception("Did not recognize any mod loader!");
}
protected override void Log(LogLevel level, string message)
{
_logMethod(level, message);
}
public static int Convert(LogLevel level)
{
return level switch
{
LogLevel.Debug => 32,
LogLevel.Info => 16,
LogLevel.Warn => 4,
LogLevel.Error => 2,
_ => 0,
};
}
}
public abstract class XuaLogger
{
private static XuaLogger _default;
private static XuaLogger _common;
private static XuaLogger _resourceRedirector;
public static XuaLogger AutoTranslator
{
get
{
if (_default == null)
{
_default = CreateLogger("XUnity.AutoTranslator");
}
return _default;
}
set
{
_default = value ?? throw new ArgumentNullException("value");
}
}
public static XuaLogger Common
{
get
{
if (_common == null)
{
_common = CreateLogger("XUnity.Common");
}
return _common;
}
set
{
_common = value ?? throw new ArgumentNullException("value");
}
}
public static XuaLogger ResourceRedirector
{
get
{
if (_resourceRedirector == null)
{
_resourceRedirector = CreateLogger("XUnity.ResourceRedirector");
}
return _resourceRedirector;
}
set
{
_resourceRedirector = value ?? throw new ArgumentNullException("value");
}
}
public string Source { get; set; }
internal static XuaLogger CreateLogger(string source)
{
try
{
return new ModLoaderSpecificLogger(source);
}
catch (Exception)
{
return new ConsoleLogger(source);
}
}
public XuaLogger(string source)
{
Source = source;
}
public void Error(Exception e, string message)
{
Log(LogLevel.Error, message + Environment.NewLine + e);
}
public void Error(string message)
{
Log(LogLevel.Error, message);
}
public void Warn(Exception e, string message)
{
Log(LogLevel.Warn, message + Environment.NewLine + e);
}
public void Warn(string message)
{
Log(LogLevel.Warn, message);
}
public void Info(Exception e, string message)
{
Log(LogLevel.Info, message + Environment.NewLine + e);
}
public void Info(string message)
{
Log(LogLevel.Info, message);
}
public void Debug(Exception e, string message)
{
Log(LogLevel.Debug, message + Environment.NewLine + e);
}
public void Debug(string message)
{
Log(LogLevel.Debug, message);
}
protected abstract void Log(LogLevel level, string message);
protected string GetDefaultPrefix(LogLevel level)
{
return level switch
{
LogLevel.Debug => "[DEBUG][" + Source + "]: ",
LogLevel.Info => "[INFO][" + Source + "]: ",
LogLevel.Warn => "[WARN][" + Source + "]: ",
LogLevel.Error => "[ERROR][" + Source + "]: ",
_ => "[UNKNOW][" + Source + "]: ",
};
}
}
}
namespace XUnity.Common.Harmony
{
public static class AccessToolsShim
{
private static readonly BindingFlags All;
private static readonly Func<Type, string, Type[], Type[], MethodInfo> AccessTools_Method;
private static readonly Func<Type, string, PropertyInfo> AccessTools_Property;
static AccessToolsShim()
{
All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
MethodInfo method = ClrTypes.AccessTools.GetMethod("Method", All, null, new Type[4]
{
typeof(Type),
typeof(string),
typeof(Type[]),
typeof(Type[])
}, null);
MethodInfo? method2 = ClrTypes.AccessTools.GetMethod("Property", All, null, new Type[2]
{
typeof(Type),
typeof(string)
}, null);
AccessTools_Method = (Func<Type, string, Type[], Type[], MethodInfo>)ExpressionHelper.CreateTypedFastInvoke(method);
AccessTools_Property = (Func<Type, string, PropertyInfo>)ExpressionHelper.CreateTypedFastInvoke(method2);
}
public static MethodInfo Method(Type type, string name, params Type[] parameters)
{
return AccessTools_Method(type, name, parameters, null);
}
public static PropertyInfo Property(Type type, string name)
{
return AccessTools_Property(type, name);
}
}
}
namespace XUnity.Common.Extensions
{
public static class ExceptionExtensions
{
public static TException FirstInnerExceptionOfType<TException>(this Exception e) where TException : Exception
{
for (Exception ex = e; ex != null; ex = ex.InnerException)
{
if (ex is TException)
{
return (TException)ex;
}
}
return null;
}
}
public static class ObjectExtensions
{
public static Type GetUnityType(this object obj)
{
return obj.GetType();
}
public static bool TryCastTo<TObject>(this object obj, out TObject castedObject)
{
if (obj is TObject val)
{
castedObject = val;
return true;
}
castedObject = default(TObject);
return false;
}
}
public static class StreamExtensions
{
public static byte[] ReadFully(this Stream stream, int initialLength)
{
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] array = new byte[initialLength];
int num = 0;
int num2;
while ((num2 = stream.Read(array, num, array.Length - num)) > 0)
{
num += num2;
if (num == array.Length)
{
int num3 = stream.ReadByte();
if (num3 == -1)
{
return array;
}
byte[] array2 = new byte[array.Length * 2];
Array.Copy(array, array2, array.Length);
array2[num] = (byte)num3;
array = array2;
num++;
}
}
byte[] array3 = new byte[num];
Array.Copy(array, array3, num);
return array3;
}
}
public static class StringExtensions
{
private static readonly HashSet<char> InvalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars());
public static string UseCorrectDirectorySeparators(this string path)
{
if (Path.DirectorySeparatorChar == '\\')
{
return path.Replace('/', Path.DirectorySeparatorChar);
}
if (Path.DirectorySeparatorChar == '/')
{
return path.Replace('\\', Path.DirectorySeparatorChar);
}
return path;
}
public static bool IsNullOrWhiteSpace(this string value)
{
if (value == null)
{
return true;
}
for (int i = 0; i < value.Length; i++)
{
if (!char.IsWhiteSpace(value[i]))
{
return false;
}
}
return true;
}
public static string MakeRelativePath(this string fullOrRelativePath, string basePath)
{
StringBuilder stringBuilder = new StringBuilder();
int i = 0;
bool flag = false;
string[] array = basePath.Split(':', '\\', '/');
List<string> list = fullOrRelativePath.Split(':', '\\', '/').ToList();
if (array.Length == 0 || list.Count <= 0 || array[0] != list[0])
{
flag = true;
}
bool flag2 = false;
for (int j = 0; j < list.Count; j++)
{
if (list[j] == "..")
{
if (flag2)
{
int num = j - 1;
if (num >= 0)
{
list.RemoveAt(j);
list.RemoveAt(num);
j -= 2;
}
}
}
else
{
flag2 = true;
}
}
if (!flag)
{
for (i = 1; i < array.Length && !(array[i] != list[i]); i++)
{
}
for (int k = 0; k < array.Length - i; k++)
{
char directorySeparatorChar = Path.DirectorySeparatorChar;
stringBuilder.Append(".." + directorySeparatorChar);
}
}
for (int l = i; l < list.Count - 1; l++)
{
string value = list[l];
stringBuilder.Append(value).Append(Path.DirectorySeparatorChar);
}
string value2 = list[^1];
stringBuilder.Append(value2);
return stringBuilder.ToString();
}
public static string SanitizeForFileSystem(this string path)
{
StringBuilder stringBuilder = new StringBuilder(path.Length);
foreach (char c in path)
{
if (!InvalidFileNameChars.Contains(c))
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString();
}
public static string SplitToLines(this string text, int maxStringLength, params char[] splitOnCharacters)
{
StringBuilder stringBuilder = new StringBuilder();
int num;
for (int i = 0; text.Length > i; i += num)
{
if (i != 0)
{
stringBuilder.Append('\n');
}
num = ((i + maxStringLength <= text.Length) ? text.Substring(i, maxStringLength).LastIndexOfAny(splitOnCharacters) : (text.Length - i));
num = ((num == -1) ? maxStringLength : num);
stringBuilder.Append(text.Substring(i, num).Trim());
}
return stringBuilder.ToString();
}
public static bool StartsWithStrict(this string str, string prefix)
{
int num = Math.Min(str.Length, prefix.Length);
if (num < prefix.Length)
{
return false;
}
for (int i = 0; i < num; i++)
{
if (str[i] != prefix[i])
{
return false;
}
}
return true;
}
public static string GetBetween(this string strSource, string strStart, string strEnd)
{
int num = strSource.IndexOf(strStart);
if (num != -1)
{
num += strStart.Length;
int num2 = strSource.IndexOf(strEnd, num);
if (num2 > num)
{
return strSource.Substring(num, num2 - num);
}
}
return string.Empty;
}
public static bool RemindsOf(this string that, string other)
{
if (!that.StartsWith(other) && !other.StartsWith(that) && !that.EndsWith(other))
{
return other.EndsWith(that);
}
return true;
}
}
}
namespace XUnity.Common.Constants
{
public static class ClrTypes
{
public static readonly Type AccessTools = FindTypeStrict("Harmony.AccessTools, 0Harmony") ?? FindTypeStrict("HarmonyLib.AccessTools, 0Harmony") ?? FindTypeStrict("Harmony.AccessTools, MelonLoader.ModHandler") ?? FindTypeStrict("HarmonyLib.AccessTools, MelonLoader.ModHandler");
public static readonly Type HarmonyMethod = FindTypeStrict("Harmony.HarmonyMethod, 0Harmony") ?? FindTypeStrict("HarmonyLib.HarmonyMethod, 0Harmony") ?? FindTypeStrict("Harmony.HarmonyMethod, MelonLoader.ModHandler") ?? FindTypeStrict("HarmonyLib.HarmonyMethod, MelonLoader.ModHandler");
public static readonly Type HarmonyInstance = FindTypeStrict("Harmony.HarmonyInstance, 0Harmony") ?? FindTypeStrict("Harmony.HarmonyInstance, MelonLoader.ModHandler");
public static readonly Type Harmony = FindTypeStrict("HarmonyLib.Harmony, 0Harmony") ?? FindTypeStrict("HarmonyLib.Harmony, MelonLoader.ModHandler");
public static readonly Type Hook = FindTypeStrict("MonoMod.RuntimeDetour.Hook, MonoMod.RuntimeDetour");
public static readonly Type Detour = FindTypeStrict("MonoMod.RuntimeDetour.Detour, MonoMod.RuntimeDetour");
public static readonly Type NativeDetour = FindTypeStrict("MonoMod.RuntimeDetour.NativeDetour, MonoMod.RuntimeDetour");
public static readonly Type DynamicMethodDefinition = FindTypeStrict("MonoMod.Utils.DynamicMethodDefinition, MonoMod.Utils");
public static readonly Type Imports = FindTypeStrict("MelonLoader.Imports, MelonLoader.ModHandler");
public static readonly Type MethodBase = FindType("System.Reflection.MethodBase");
public static readonly Type Task = FindType("System.Threading.Tasks.Task");
private static Type FindType(string name)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
try
{
Type type = assembly.GetType(name, throwOnError: false);
if ((object)type != null)
{
return type;
}
}
catch
{
}
}
return null;
}
private static Type FindTypeStrict(string name)
{
return Type.GetType(name, throwOnError: false);
}
}
public class TypeContainer
{
public Type ClrType { get; }
public Type UnityType { get; }
public TypeContainer(Type type)
{
UnityType = type;
ClrType = type;
}
public bool IsAssignableFrom(Type unityType)
{
if ((object)UnityType != null)
{
return UnityType.IsAssignableFrom(unityType);
}
return false;
}
}
public static class UnityFeatures
{
private static readonly BindingFlags All;
public static bool SupportsMouseScrollDelta { get; }
public static bool SupportsClipboard { get; }
public static bool SupportsCustomYieldInstruction { get; }
public static bool SupportsSceneManager { get; }
public static bool SupportsWaitForSecondsRealtime { get; set; }
static UnityFeatures()
{
All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
SupportsMouseScrollDelta = false;
SupportsClipboard = false;
SupportsCustomYieldInstruction = false;
SupportsSceneManager = false;
SupportsWaitForSecondsRealtime = false;
try
{
SupportsClipboard = (object)UnityTypes.TextEditor?.ClrType.GetProperty("text")?.GetSetMethod() != null;
}
catch (Exception)
{
}
try
{
SupportsCustomYieldInstruction = UnityTypes.CustomYieldInstruction != null;
}
catch (Exception)
{
}
try
{
SupportsSceneManager = UnityTypes.Scene != null && UnityTypes.SceneManager != null && (object)UnityTypes.SceneManager.ClrType.GetMethod("add_sceneLoaded", All) != null;
}
catch (Exception)
{
}
try
{
SupportsMouseScrollDelta = (object)UnityTypes.Input?.ClrType.GetProperty("mouseScrollDelta") != null;
}
catch (Exception)
{
}
try
{
SupportsWaitForSecondsRealtime = UnityTypes.WaitForSecondsRealtime != null;
}
catch (Exception)
{
}
}
}
public static class UnityTypes
{
public static class TMP_Settings_Properties
{
public static CachedProperty Version = TMP_Settings?.ClrType.CachedProperty("version");
public static CachedProperty FallbackFontAssets = TMP_Settings?.ClrType.CachedProperty("fallbackFontAssets");
}
public static class TMP_FontAsset_Properties
{
public static CachedProperty Version = TMP_FontAsset?.ClrType.CachedProperty("version");
}
public static class AdvScenarioData_Properties
{
public static CachedProperty ScenarioLabels = AdvScenarioData?.ClrType.CachedProperty("ScenarioLabels");
}
public static class UguiNovelText_Properties
{
public static CachedProperty TextGenerator = UguiNovelText?.ClrType.CachedProperty("TextGenerator");
}
public static class UguiNovelText_Methods
{
public static CachedMethod SetAllDirty = UguiNovelText?.ClrType.CachedMethod("SetAllDirty");
}
public static class UguiNovelTextGenerator_Methods
{
public static CachedMethod Refresh = UguiNovelTextGenerator?.ClrType.CachedMethod("Refresh");
}
public static class AdvUguiMessageWindow_Properties
{
public static CachedProperty Text = AdvUguiMessageWindow?.ClrType.CachedProperty("Text");
public static CachedProperty Engine = AdvUguiMessageWindow?.ClrType.CachedProperty("Engine");
}
public static class AdvUiMessageWindow_Fields
{
public static CachedField text = AdvUiMessageWindow?.ClrType.CachedField("text");
public static CachedField nameText = AdvUiMessageWindow?.ClrType.CachedField("nameText");
}
public static class AdvUguiMessageWindow_Fields
{
public static FieldInfo text = AdvUguiMessageWindow?.ClrType.GetField("text", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
public static FieldInfo nameText = AdvUguiMessageWindow?.ClrType.GetField("nameText", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
public static FieldInfo engine = AdvUguiMessageWindow?.ClrType.GetField("engine", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
public static class AdvEngine_Properties
{
public static CachedProperty Page = AdvEngine?.ClrType.CachedProperty("Page");
}
public static class AdvPage_Methods
{
public static CachedMethod RemakeTextData = AdvPage?.ClrType.CachedMethod("RemakeTextData");
public static CachedMethod RemakeText = AdvPage?.ClrType.CachedMethod("RemakeText");
public static CachedMethod ChangeMessageWindowText = AdvPage?.ClrType.CachedMethod("ChangeMessageWindowText", typeof(string), typeof(string), typeof(string), typeof(string));
}
public static class UILabel_Properties
{
public static CachedProperty MultiLine = UILabel?.ClrType.CachedProperty("multiLine");
public static CachedProperty OverflowMethod = UILabel?.ClrType.CachedProperty("overflowMethod");
public static CachedProperty SpacingX = UILabel?.ClrType.CachedProperty("spacingX");
public static CachedProperty UseFloatSpacing = UILabel?.ClrType.CachedProperty("useFloatSpacing");
}
public static class Text_Properties
{
public static CachedProperty Font = Text?.ClrType.CachedProperty("font");
public static CachedProperty FontSize = Text?.ClrType.CachedProperty("fontSize");
public static CachedProperty HorizontalOverflow = Text?.ClrType.CachedProperty("horizontalOverflow");
public static CachedProperty VerticalOverflow = Text?.ClrType.CachedProperty("verticalOverflow");
public static CachedProperty LineSpacing = Text?.ClrType.CachedProperty("lineSpacing");
public static CachedProperty ResizeTextForBestFit = Text?.ClrType.CachedProperty("resizeTextForBestFit");
public static CachedProperty ResizeTextMinSize = Text?.ClrType.CachedProperty("resizeTextMinSize");
public static CachedProperty ResizeTextMaxSize = Text?.ClrType.CachedProperty("resizeTextMaxSize");
}
public static class InputField_Properties
{
public static CachedProperty Placeholder = InputField?.ClrType.CachedProperty("placeholder");
}
public static class TMP_InputField_Properties
{
public static CachedProperty Placeholder = TMP_InputField?.ClrType.CachedProperty("placeholder");
}
public static class Font_Properties
{
public static CachedProperty FontSize = Font?.ClrType.CachedProperty("fontSize");
}
public static class AssetBundle_Methods
{
public static CachedMethod LoadAll = AssetBundle?.ClrType.CachedMethod("LoadAll", typeof(Type));
public static CachedMethod LoadAllAssets = AssetBundle?.ClrType.CachedMethod("LoadAllAssets", typeof(Type));
public static CachedMethod LoadFromFile = AssetBundle?.ClrType.CachedMethod("LoadFromFile", typeof(string));
public static CachedMethod CreateFromFile = AssetBundle?.ClrType.CachedMethod("CreateFromFile", typeof(string));
}
public static class TextExpansion_Methods
{
public static CachedMethod SetMessageType = TextExpansion?.ClrType.CachedMethod("SetMessageType");
public static CachedMethod SkipTypeWriter = TextExpansion?.ClrType.CachedMethod("SkipTypeWriter");
}
public static class GameObject_Methods
{
}
public static class TextMesh_Methods
{
}
public static class Text_Methods
{
}
public static class InputField_Methods
{
}
public static class TMP_Text_Methods
{
}
public static class TMP_InputField_Methods
{
}
public static class TextMeshPro_Methods
{
}
public static class TextMeshProUGUI_Methods
{
}
public static class UILabel_Methods
{
}
public static class UIRect_Methods
{
}
public static class SceneManager_Methods
{
public static readonly Action<UnityAction<Scene, LoadSceneMode>> add_sceneLoaded = (Action<UnityAction<Scene, LoadSceneMode>>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(SceneManager).GetMethod("add_sceneLoaded", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(UnityAction<Scene, LoadSceneMode>) }, null));
}
public static class Texture2D_Methods
{
public static readonly Func<Texture2D, byte[], bool> LoadImage = (Func<Texture2D, byte[], bool>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(byte[]) }, null));
public static readonly Func<Texture2D, byte[]> EncodeToPNG = (Func<Texture2D, byte[]>)ExpressionHelper.CreateTypedFastInvokeUnchecked(typeof(Texture2D).GetMethod("EncodeToPNG", BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null));
}
public static class ImageConversion_Methods
{
public static readonly Func<Texture2D, byte[], bool, bool> LoadImage = (Func<Texture2D, byte[], bool, bool>)ExpressionHelper.CreateTypedFastInvokeUnchecked(ImageConversion?.ClrType.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3]
{
typeof(Texture2D),
typeof(byte[]),
typeof(bool)
}, null));
public static readonly Func<Texture2D, byte[]> EncodeToPNG = (Func<Texture2D, byte[]>)ExpressionHelper.CreateTypedFastInvokeUnchecked(ImageConversion?.ClrType.GetMethod("EncodeToPNG", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Texture2D) }, null));
}
public static readonly TypeContainer UILabel = FindType("UILabel");
public static readonly TypeContainer UIWidget = FindType("UIWidget");
public static readonly TypeContainer UIAtlas = FindType("UIAtlas");
public static readonly TypeContainer UISprite = FindType("UISprite");
public static readonly TypeContainer UITexture = FindType("UITexture");
public static readonly TypeContainer UI2DSprite = FindType("UI2DSprite");
public static readonly TypeContainer UIFont = FindType("UIFont");
public static readonly TypeContainer UIPanel = FindType("UIPanel");
public static readonly TypeContainer UIRect = FindType("UIRect");
public static readonly TypeContainer UIInput = FindType("UIInput");
public static readonly TypeContainer TextField = FindType("FairyGUI.TextField");
public static readonly TypeContainer TMP_InputField = FindType("TMPro.TMP_InputField");
public static readonly TypeContainer TMP_Text = FindType("TMPro.TMP_Text");
public static readonly TypeContainer TextMeshProUGUI = FindType("TMPro.TextMeshProUGUI");
public static readonly TypeContainer TextMeshPro = FindType("TMPro.TextMeshPro");
public static readonly TypeContainer TMP_FontAsset = FindType("TMPro.TMP_FontAsset");
public static readonly TypeContainer TMP_Settings = FindType("TMPro.TMP_Settings");
public static readonly TypeContainer GameObject = FindType("UnityEngine.GameObject");
public static readonly TypeContainer Transform = FindType("UnityEngine.Transform");
public static readonly TypeContainer TextMesh = FindType("UnityEngine.TextMesh");
public static readonly TypeContainer Text = FindType("UnityEngine.UI.Text");
public static readonly TypeContainer Image = FindType("UnityEngine.UI.Image");
public static readonly TypeContainer RawImage = FindType("UnityEngine.UI.RawImage");
public static readonly TypeContainer MaskableGraphic = FindType("UnityEngine.UI.MaskableGraphic");
public static readonly TypeContainer Graphic = FindType("UnityEngine.UI.Graphic");
public static readonly TypeContainer GUIContent = FindType("UnityEngine.GUIContent");
public static readonly TypeContainer WWW = FindType("UnityEngine.WWW");
public static readonly TypeContainer InputField = FindType("UnityEngine.UI.InputField");
public static readonly TypeContainer GUI = FindType("UnityEngine.GUI");
public static readonly TypeContainer GUI_ToolbarButtonSize = FindType("UnityEngine.GUI+ToolbarButtonSize");
public static readonly TypeContainer GUIStyle = FindType("UnityEngine.GUIStyle");
public static readonly TypeContainer ImageConversion = FindType("UnityEngine.ImageConversion");
public static readonly TypeContainer Texture2D = FindType("UnityEngine.Texture2D");
public static readonly TypeContainer Texture = FindType("UnityEngine.Texture");
public static readonly TypeContainer SpriteRenderer = FindType("UnityEngine.SpriteRenderer");
public static readonly TypeContainer Sprite = FindType("UnityEngine.Sprite");
public static readonly TypeContainer Object = FindType("UnityEngine.Object");
public static readonly TypeContainer TextEditor = FindType("UnityEngine.TextEditor");
public static readonly TypeContainer CustomYieldInstruction = FindType("UnityEngine.CustomYieldInstruction");
public static readonly TypeContainer SceneManager = FindType("UnityEngine.SceneManagement.SceneManager");
public static readonly TypeContainer Scene = FindType("UnityEngine.SceneManagement.Scene");
public static readonly TypeContainer UnityEventBase = FindType("UnityEngine.Events.UnityEventBase");
public static readonly TypeContainer BaseInvokableCall = FindType("UnityEngine.Events.BaseInvokableCall");
public static readonly TypeContainer Font = FindType("UnityEngine.Font");
public static readonly TypeContainer WaitForSecondsRealtime = FindType("UnityEngine.WaitForSecondsRealtime");
public static readonly TypeContainer Input = FindType("UnityEngine.Input");
public static readonly TypeContainer AssetBundleCreateRequest = FindType("UnityEngine.AssetBundleCreateRequest");
public static readonly TypeContainer AssetBundle = FindType("UnityEngine.AssetBundle");
public static readonly TypeContainer AssetBundleRequest = FindType("UnityEngine.AssetBundleRequest");
public static readonly TypeContainer Resources = FindType("UnityEngine.Resources");
public static readonly TypeContainer AsyncOperation = FindType("UnityEngine.AsyncOperation");
public static readonly TypeContainer TextAsset = FindType("UnityEngine.TextAsset");
public static readonly Type HorizontalWrapMode = FindClrType("UnityEngine.HorizontalWrapMode");
public static readonly Type TextOverflowModes = FindClrType("TMPro.TextOverflowModes");
public static readonly Type TextAlignmentOptions = FindClrType("TMPro.TextAlignmentOptions");
public static readonly Type VerticalWrapMode = FindClrType("UnityEngine.VerticalWrapMode");
public static readonly TypeContainer TextExpansion = FindType("UnityEngine.UI.TextExpansion");
public static readonly TypeContainer Typewriter = FindType("Typewriter");
public static readonly TypeContainer UguiNovelText = FindType("Utage.UguiNovelText");
public static readonly TypeContainer UguiNovelTextGenerator = FindType("Utage.UguiNovelTextGenerator");
public static readonly TypeContainer AdvEngine = FindType("Utage.AdvEngine");
public static readonly TypeContainer AdvPage = FindType("Utage.AdvPage");
public static readonly TypeContainer TextData = FindType("Utage.TextData");
public static readonly TypeContainer AdvUguiMessageWindow = FindType("Utage.AdvUguiMessageWindow") ?? FindType("AdvUguiMessageWindow");
public static readonly TypeContainer AdvUiMessageWindow = FindType("AdvUiMessageWindow");
public static readonly TypeContainer AdvDataManager = FindType("Utage.AdvDataManager");
public static readonly TypeContainer AdvScenarioData = FindType("Utage.AdvScenarioData");
public static readonly TypeContainer AdvScenarioLabelData = FindType("Utage.AdvScenarioLabelData");
public static readonly TypeContainer DicingTextures = FindType("Utage.DicingTextures");
public static readonly TypeContainer DicingImage = FindType("Utage.DicingImage");
public static readonly TypeContainer TextArea2D = FindType("Utage.TextArea2D");
public static readonly TypeContainer CubismRenderer = FindType("Live2D.Cubism.Rendering.CubismRenderer");
public static readonly TypeContainer TextWindow = FindType("Assets.System.Text.TextWindow");
private static Type FindClrType(string name)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
try
{
Type type = assembly.GetType(name, throwOnError: false);
if ((object)type != null)
{
return type;
}
}
catch
{
}
}
return null;
}
private static TypeContainer FindType(string name)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
try
{
Type type = assembly.GetType(name, throwOnError: false);
if ((object)type != null)
{
return new TypeContainer(type);
}
}
catch
{
}
}
return null;
}
}
}using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using AHook.Patches;
using AHook.Patches.util;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using XUnity.Common.Extensions;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("GameTranslator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GameTranslator")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("acc996e2-652f-4af2-ab3b-8062a6acc7e4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AHook
{
[BepInPlugin("AHook", "AHook", "1.0.0")]
public class AHookPlugin : BaseUnityPlugin
{
private const string PLUGIN_GUID = "AHook";
private const string PLUGIN_NAME = "AHook";
private const string PLUGIN_VERSION = "1.0.0";
internal static AHookPlugin Instance;
private readonly Harmony harmony = new Harmony("AHook");
public static string ConfigPath;
public static string DefaultPath;
public static string TexturesPath;
public static bool shouldTranslate;
public static ManualLogSource logger;
private void Awake()
{
logger = ((BaseUnityPlugin)this).Logger;
Instance = this;
((BaseUnityPlugin)this).Logger.LogInfo((object)"插件AHook已加载!");
ConfigPath = ((BaseUnityPlugin)this).Config.ConfigFilePath.Replace("AHook.cfg", "");
DefaultPath = ((BaseUnityPlugin)this).Config.ConfigFilePath.Replace("AHook.cfg", "translations\\zh-CN\\");
TranslateConfig.Load();
ModHook.PatchAll(harmony);
}
public static void LogInfo(string info)
{
if (logger != null)
{
logger.LogInfo((object)info);
}
}
}
public class TranslateConfig
{
public class TranslateConfigFile
{
public string ConfigFilePath;
public string ConfigFileName;
public bool shouldTranslate = false;
public int shouldTranslateMinLength = 200;
public int shouldTranslateMaxLength = 0;
public bool shouldLoad = true;
public IDictionary<string, string> normal = new Dictionary<string, string>();
public IDictionary<string, string> strong = new Dictionary<string, string>();
public IDictionary<string, string> special = new Dictionary<string, string>();
public IDictionary<string, string> useRex = new Dictionary<string, string>();
public static HashSet<TranslateConfigFile> configs = new HashSet<TranslateConfigFile>();
public Dictionary<string, string> translatePairs = new Dictionary<string, string>();
public bool isOrgin = false;
public static Regex regex = new Regex("(?<!\\\\)=");
private List<string> logs = new List<string>();
public TranslateConfigFile(string configName, bool saveOnInit, bool shouldLoad, bool origin = false)
{
ConfigFileName = configName;
isOrgin = origin;
if (origin)
{
ConfigFilePath = AHookPlugin.ConfigPath + configName + ".cfg";
}
else
{
ConfigFilePath = AHookPlugin.DefaultPath + configName + ".cfg";
}
this.shouldLoad = shouldLoad;
if (ConfigFilePath == null)
{
throw new ArgumentNullException("configPath");
}
ConfigFilePath = Path.GetFullPath(ConfigFilePath);
if (this.shouldLoad && File.Exists(ConfigFilePath))
{
Reload();
}
else if (saveOnInit)
{
Save();
}
configs.Add(this);
}
public void show()
{
foreach (KeyValuePair<string, string> item in normal)
{
string text = item.Key.Replace("=", "\\=");
string text2 = item.Value.Replace("=", "\\=");
AHookPlugin.LogInfo(text + "=" + text2);
}
}
public void Reload()
{
normal.Clear();
useRex.Clear();
string[] array = File.ReadAllLines(ConfigFilePath);
foreach (string text in array)
{
if (text.StartsWith("#") || !text.Contains("="))
{
continue;
}
string[] array2 = regex.Split(text);
if (array2.Length != 2)
{
continue;
}
string text2 = array2[0].Replace("\\=", "=");
string text3 = array2[1].Replace("\\=", "=");
if (isOrgin)
{
text2 = text2.Trim();
text3 = text3.Trim();
}
if (text2.StartsWith(rexName))
{
text2 = text2.Replace(rexName, "");
if (useRex.ContainsKey(text2))
{
useRex[text2] = text3;
}
else
{
useRex.Add(text2, text3);
}
}
else if (text2.StartsWith(strongName))
{
text2 = text2.Replace(strongName, "");
if (strong.ContainsKey(text2))
{
strong[text2] = text3;
}
else
{
strong.Add(text2, text3);
}
}
else if (normal.ContainsKey(text2))
{
normal[text2] = text3;
special[text3] = text2;
}
else
{
normal.Add(text2, text3);
if (!special.ContainsKey(text3))
{
special.Add(text3, text2);
}
}
if (text2.Length < shouldTranslateMinLength)
{
shouldTranslateMinLength = text2.Length;
}
if (text2.Length > shouldTranslateMaxLength)
{
shouldTranslateMaxLength = text2.Length;
}
}
}
public void Log(string text)
{
logs.Add(text);
string directoryName = Path.GetDirectoryName(ConfigFilePath);
if (directoryName == null)
{
Directory.CreateDirectory(directoryName);
}
List<string> list = new List<string>();
list.Add("##" + ConfigFileName);
File.WriteAllLines(ConfigFilePath, logs);
}
public void Save()
{
string directoryName = Path.GetDirectoryName(ConfigFilePath);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
if (!File.Exists(ConfigFilePath))
{
File.Create(ConfigFilePath).Close();
}
else
{
if (!shouldLoad)
{
return;
}
List<string> list = new List<string>();
list.Add("##" + ConfigFileName);
foreach (KeyValuePair<string, string> item in normal)
{
string text = item.Key.Replace("=", "\\=");
string text2 = item.Value.Replace("=", "\\=");
list.Add(text + "=" + text2);
}
list.Add("##强制替换");
foreach (KeyValuePair<string, string> item2 in strong)
{
string text3 = item2.Key.Replace("=", "\\=");
string text4 = item2.Value.Replace("=", "\\=");
list.Add(strongName + text3 + "=" + text4);
}
list.Add("##正则表达式");
foreach (KeyValuePair<string, string> item3 in useRex)
{
string text5 = item3.Key.Replace("=", "\\=");
string text6 = item3.Value.Replace("=", "\\=");
list.Add(rexName + text5 + "=" + text6);
}
File.WriteAllLines(ConfigFilePath, list.ToArray());
}
}
}
public static TranslateConfigFile mod;
public static TranslateConfigFile items;
public static string rexName = "rex:";
public static string strongName = "stg:";
public static void Load()
{
items = CreateNewConfig("Item-Translate");
mod = CreateConfig("GameTranslator");
}
private static TranslateConfigFile CreateConfig(string fileName)
{
return new TranslateConfigFile(fileName, saveOnInit: true, shouldLoad: true, origin: true);
}
private static TranslateConfigFile CreateNewConfig(string fileName, bool should)
{
return new TranslateConfigFile(fileName, saveOnInit: true, should);
}
private static TranslateConfigFile CreateNewConfig(string fileName)
{
AHookPlugin.logger.LogInfo((object)("GameTranslator正在载入配置文件" + fileName));
return new TranslateConfigFile(fileName, saveOnInit: true, shouldLoad: true);
}
public static string getRegex(string pattern)
{
StringBuilder stringBuilder = new StringBuilder(pattern);
stringBuilder.Replace("\\", "\\\\");
return stringBuilder.ToString();
}
public static bool IsStringContainsEnglish(string input)
{
Regex regex = new Regex("[a-zA-Z]");
return regex.IsMatch(input);
}
public static bool IsStringContainsChinese(string input)
{
Regex regex = new Regex("[\\u4e00-\\u9fa5]");
return regex.IsMatch(input);
}
public static string useRegularExpression(string raw, string pattern, string result)
{
pattern = pattern.Replace(rexName, "");
return Regex.Replace(raw, pattern, result);
}
public static string replaceByMap(string text, TranslateConfigFile file)
{
if (file.translatePairs.ContainsKey(text))
{
return file.translatePairs[text];
}
StringBuffer stringBuffer = new StringBuffer(text);
foreach (KeyValuePair<string, string> item in file.useRex)
{
string pattern = Regex.Unescape(getRegex(item.Key));
string result = Regex.Unescape(item.Value);
string str = useRegularExpression(stringBuffer.ToString(), pattern, result);
stringBuffer.Clear().Append(str);
}
foreach (KeyValuePair<string, string> item2 in file.strong)
{
string oldValue = Regex.Unescape(item2.Key);
string newValue = Regex.Unescape(item2.Value);
stringBuffer.Replace(oldValue, newValue);
}
foreach (KeyValuePair<string, string> item3 in file.normal)
{
string oldValue2 = Regex.Unescape(item3.Key);
string newValue2 = Regex.Unescape(item3.Value);
stringBuffer.ReplaceFull(oldValue2, newValue2);
}
file.translatePairs[text] = stringBuffer.ToString();
return stringBuffer.ToString();
}
}
}
namespace AHook.Patches
{
internal static class ModHook
{
internal class ReservedItemInfoHook
{
public static void Init(Harmony harmony)
{
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Expected O, but got Unknown
Type type = Type.GetType("ReservedItemSlotCore.ReservedItemInfo, ReservedItemSlotCore");
if (!(type == null))
{
AHookPlugin.LogInfo("Trying to be compatible with ReservedItemSlotCore");
ConstructorInfo constructor = type.GetConstructor(new Type[6]
{
typeof(string),
typeof(int),
typeof(bool),
typeof(bool),
typeof(bool),
typeof(bool)
});
MethodInfo method = typeof(ReservedItemInfoHook).GetMethod("Prefix");
harmony.Patch((MethodBase)constructor, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
}
public static bool Prefix(ref string itemName, int hotbarSlotPriority, bool forceUpdateCanBeGrabbedBeforeGameStart, bool canBeGrabbedBeforeGameStart, bool forceUpdateRequiresBattery, bool requiresBattery)
{
try
{
if (itemName != null && !StringExtensions.IsNullOrWhiteSpace(itemName) && TranslateConfig.mod.normal.ContainsKey("Translate Items") && TranslateConfig.mod.normal["Translate Items"].Equals("true"))
{
itemName = TranslateConfig.replaceByMap(itemName, TranslateConfig.items);
}
}
catch (Exception ex)
{
AHookPlugin.LogInfo("未找到GameTranslator模组:" + ex.Message);
}
return true;
}
}
public static void PatchAll(Harmony harmony)
{
ReservedItemInfoHook.Init(harmony);
}
}
}
namespace AHook.Patches.util
{
public class StringBuffer
{
private char[] value;
private int length;
private int capacity;
private const int DEFAULT_CAPACITY = 16;
public int Length
{
get
{
return length;
}
set
{
if (value < 0 || value > capacity)
{
throw new ArgumentOutOfRangeException("value");
}
if (value < length)
{
Array.Clear(this.value, value, length - value);
}
length = value;
}
}
public int Capacity
{
get
{
return capacity;
}
set
{
if (value < length)
{
throw new ArgumentOutOfRangeException("value");
}
if (value != capacity)
{
char[] destinationArray = new char[value];
Array.Copy(this.value, 0, destinationArray, 0, length);
this.value = destinationArray;
capacity = value;
}
}
}
public StringBuffer()
{
value = new char[16];
length = 0;
capacity = 16;
}
public StringBuffer(int capacity)
{
if (capacity < 0)
{
throw new ArgumentOutOfRangeException("capacity");
}
value = new char[capacity];
length = 0;
this.capacity = capacity;
}
public StringBuffer(string str)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
value = new char[str.Length + 16];
str.CopyTo(0, value, 0, str.Length);
length = str.Length;
capacity = str.Length + 16;
}
public void EnsureCapacity(int minimumCapacity)
{
if (minimumCapacity < 0)
{
throw new ArgumentOutOfRangeException("minimumCapacity");
}
if (minimumCapacity > capacity)
{
int num = capacity * 2;
if (num < minimumCapacity)
{
num = minimumCapacity;
}
Capacity = num;
}
}
public StringBuffer Append(object obj)
{
if (obj == null)
{
return this;
}
return Append(obj.ToString());
}
public StringBuffer Append(string str)
{
if (str == null)
{
return this;
}
int num = str.Length;
EnsureCapacity(length + num);
str.CopyTo(0, value, length, num);
length += num;
return this;
}
public StringBuffer Append(char c)
{
EnsureCapacity(length + 1);
value[length] = c;
length++;
return this;
}
public StringBuffer Insert(int index, object obj)
{
if (obj == null)
{
return this;
}
return Insert(index, obj.ToString());
}
public StringBuffer Insert(int index, string str)
{
if (index < 0 || index > length)
{
throw new ArgumentOutOfRangeException("index");
}
if (str == null)
{
return this;
}
int num = str.Length;
EnsureCapacity(length + num);
Array.Copy(value, index, value, index + num, length - index);
str.CopyTo(0, value, index, num);
length += num;
return this;
}
public StringBuffer Insert(int index, char c)
{
if (index < 0 || index > length)
{
throw new ArgumentOutOfRangeException("index");
}
EnsureCapacity(length + 1);
Array.Copy(value, index, value, index + 1, length - index);
value[index] = c;
length++;
return this;
}
public StringBuffer Remove(int startIndex, int length)
{
if (startIndex < 0 || startIndex > this.length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (length < 0 || startIndex + length > this.length)
{
throw new ArgumentOutOfRangeException("length");
}
Array.Copy(value, startIndex + length, value, startIndex, this.length - startIndex - length);
Array.Clear(value, this.length - length, length);
this.length -= length;
return this;
}
public StringBuffer Replace(char oldChar, char newChar)
{
for (int i = 0; i < length; i++)
{
if (value[i] == oldChar)
{
value[i] = newChar;
}
}
return this;
}
public StringBuffer Replace(string oldValue, string newValue)
{
if (oldValue == null)
{
throw new ArgumentNullException("oldValue");
}
if (oldValue.Length == 0)
{
throw new ArgumentException("oldValue cannot be empty");
}
if (newValue == null)
{
newValue = string.Empty;
}
int num = oldValue.Length;
int num2 = newValue.Length;
for (int num3 = IndexOf(oldValue); num3 >= 0; num3 = IndexOf(oldValue, num3 + num2))
{
Remove(num3, num);
Insert(num3, newValue);
}
return this;
}
public int IndexOf(char c)
{
return IndexOf(c, 0, length);
}
public int IndexOf(char c, int startIndex)
{
return IndexOf(c, startIndex, length - startIndex);
}
public int IndexOf(char c, int startIndex, int count)
{
if (startIndex < 0 || startIndex > length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > length)
{
throw new ArgumentOutOfRangeException("count");
}
return Array.IndexOf(value, c, startIndex, count);
}
public int IndexOf(string str)
{
return IndexOf(str, 0, length);
}
public int IndexOf(string str, int startIndex)
{
return IndexOf(str, startIndex, length - startIndex);
}
public int IndexOf(string str, int startIndex, int count)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
if (startIndex < 0 || startIndex > length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > length)
{
throw new ArgumentOutOfRangeException("count");
}
return ToString(value, startIndex, count).IndexOf(str);
}
public static string ToString(char[] value, int startIndex, int count)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (startIndex < 0 || startIndex > value.Length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > value.Length)
{
throw new ArgumentOutOfRangeException("count");
}
return new string(value, startIndex, count);
}
public string Substring(int startIndex)
{
return Substring(startIndex, length - startIndex);
}
public string Substring(int startIndex, int length)
{
if (startIndex < 0 || startIndex > this.length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (length < 0 || startIndex + length > this.length)
{
throw new ArgumentOutOfRangeException("length");
}
return new string(value, startIndex, length);
}
public bool Contains(string text)
{
return IndexOf(text) >= 0;
}
public StringBuffer ReplaceFull(string oldValue, string newValue)
{
if (oldValue == null)
{
throw new ArgumentNullException("oldValue");
}
if (oldValue.Length == 0)
{
throw new ArgumentException("oldValue cannot be empty");
}
if (newValue == null)
{
newValue = string.Empty;
}
int num = oldValue.Length;
int num2 = newValue.Length;
for (int num3 = IndexOfWord(oldValue); num3 >= 0; num3 = IndexOfWord(oldValue, num3 + num2))
{
Remove(num3, num);
Insert(num3, newValue);
}
return this;
}
private int IndexOfWord(string str)
{
return IndexOfWord(str, 0, length);
}
private int IndexOfWord(string str, int startIndex)
{
return IndexOfWord(str, startIndex, length - startIndex);
}
public int IndexOfWord(string str, int startIndex, int count)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
if (startIndex < 0 || startIndex > length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > length)
{
throw new ArgumentOutOfRangeException("count");
}
int num = str.Length;
int[] array = new int[num];
int num2 = 0;
computeLPSArray(str, num, array);
int num3 = startIndex;
while (num3 < startIndex + count)
{
if (str[num2] == value[num3])
{
num2++;
num3++;
}
if (num2 == num)
{
if ((num3 - num2 == 0 || !char.IsLetter(value[num3 - num2 - 1])) && (num3 == length || !char.IsLetter(value[num3])))
{
return num3 - num2;
}
num2 = array[num2 - 1];
}
else if (num3 < startIndex + count && str[num2] != value[num3])
{
if (num2 != 0)
{
num2 = array[num2 - 1];
}
else
{
num3++;
}
}
}
return -1;
}
private void computeLPSArray(string str, int M, int[] lps)
{
int num = 0;
int num2 = 1;
lps[0] = 0;
while (num2 < M)
{
if (str[num2] == str[num])
{
num = (lps[num2] = num + 1);
num2++;
}
else if (num != 0)
{
num = lps[num - 1];
}
else
{
lps[num2] = num;
num2++;
}
}
}
private static bool IsWordChar(char c)
{
return char.IsLetter(c) || c == '_';
}
public StringBuffer Clear()
{
Length = 0;
return this;
}
public override string ToString()
{
return new string(value, 0, length);
}
}
}using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameTranslator.Patches.Hooks.texture;
using GameTranslator.Patches.Translatons;
using GameTranslator.Patches.Translatons.Manipulator;
using GameTranslator.Patches.Utils;
using HarmonyLib;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.UIElements;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Harmony;
using XUnity.Common.Logging;
using XUnity.Common.MonoMod;
using XUnity.Common.Utilities;
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyProduct("GameTranslator")]
[assembly: AssemblyDescription("")]
[assembly: ComVisible(false)]
[assembly: Guid("acc996e2-652f-4af2-ab3b-8062a6acc7e4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyTrademark("")]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTitle("GameTranslator")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace GameTranslator
{
public class TranslateConfig
{
public class TranslateConfigFile
{
public string ConfigFilePath;
public string ConfigFileName;
public bool shouldTranslate = false;
public int shouldTranslateMinLength = 200;
public int shouldTranslateMaxLength = 0;
public bool shouldLoad = true;
public IDictionary<string, string> normal = new Dictionary<string, string>();
public IDictionary<string, string> strong = new Dictionary<string, string>();
public IDictionary<string, string> special = new Dictionary<string, string>();
public IDictionary<string, string> useRex = new Dictionary<string, string>();
public static HashSet<TranslateConfigFile> configs = new HashSet<TranslateConfigFile>();
public Dictionary<string, string> translatePairs = new Dictionary<string, string>();
public static Regex regex = new Regex("(?<!\\\\)=");
private List<string> logs = new List<string>();
public TranslateConfigFile(string configName, bool saveOnInit, bool shouldLoad)
{
ConfigFileName = configName;
ConfigFilePath = TranslatePlugin.DefaultPath + configName + ".xml";
this.shouldLoad = shouldLoad;
if (ConfigFilePath == null)
{
throw new ArgumentNullException("configPath");
}
ConfigFilePath = Path.GetFullPath(ConfigFilePath);
if (this.shouldLoad && File.Exists(ConfigFilePath))
{
Reload();
}
else if (saveOnInit)
{
Save();
}
configs.Add(this);
}
public void Reload()
{
normal.Clear();
useRex.Clear();
string[] array = File.ReadAllLines(ConfigFilePath);
foreach (string text in array)
{
if (text.StartsWith("#") || !text.Contains("="))
{
continue;
}
string[] array2 = regex.Split(text);
if (array2.Length != 2)
{
continue;
}
string text2 = array2[0].Replace("\\=", "=");
string text3 = array2[1].Replace("\\=", "=");
if (text2.StartsWith(rexName))
{
text2 = text2.Replace(rexName, "");
if (useRex.ContainsKey(text2))
{
useRex[text2] = text3;
}
else
{
useRex.Add(text2, text3);
}
}
else if (text2.StartsWith(strongName))
{
text2 = text2.Replace(strongName, "");
if (strong.ContainsKey(text2))
{
strong[text2] = text3;
}
else
{
strong.Add(text2, text3);
}
}
else if (normal.ContainsKey(text2))
{
normal[text2] = text3;
special[text3] = text2;
}
else
{
normal.Add(text2, text3);
if (!special.ContainsKey(text3))
{
special.Add(text3, text2);
}
}
if (text2.Length < shouldTranslateMinLength)
{
shouldTranslateMinLength = text2.Length;
}
if (text2.Length > shouldTranslateMaxLength)
{
shouldTranslateMaxLength = text2.Length;
}
}
}
public void Log(string text)
{
logs.Add(text);
string directoryName = Path.GetDirectoryName(ConfigFilePath);
if (directoryName == null)
{
Directory.CreateDirectory(directoryName);
}
List<string> list = new List<string>();
list.Add("##" + ConfigFileName);
File.WriteAllLines(ConfigFilePath, logs);
}
public void Save()
{
string directoryName = Path.GetDirectoryName(ConfigFilePath);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
if (!File.Exists(ConfigFilePath))
{
File.Create(ConfigFilePath).Close();
}
else
{
if (!shouldLoad)
{
return;
}
List<string> list = new List<string>();
list.Add("##" + ConfigFileName);
foreach (KeyValuePair<string, string> item in normal)
{
string text = item.Key.Replace("=", "\\=");
string text2 = item.Value.Replace("=", "\\=");
list.Add(text + "=" + text2);
}
list.Add("##强制替换");
foreach (KeyValuePair<string, string> item2 in strong)
{
string text3 = item2.Key.Replace("=", "\\=");
string text4 = item2.Value.Replace("=", "\\=");
list.Add(strongName + text3 + "=" + text4);
}
list.Add("##正则表达式");
foreach (KeyValuePair<string, string> item3 in useRex)
{
string text5 = item3.Key.Replace("=", "\\=");
string text6 = item3.Value.Replace("=", "\\=");
list.Add(rexName + text5 + "=" + text6);
}
File.WriteAllLines(ConfigFilePath, list.ToArray());
}
}
}
public static TranslateConfigFile normal;
public static TranslateConfigFile hud;
public static TranslateConfigFile items;
public static TranslateConfigFile terminal;
public static TranslateConfigFile text;
public static TranslateConfigFile cmd_py;
public static TranslateConfigFile cmd_zh;
public static TranslateConfigFile log;
public static TranslateConfigFile gui;
public static TranslateConfigFile command;
public static NormalTextTranslator normalText;
public static NormalTextTranslator hudText;
public static NormalTextTranslator guiText;
public static TextureTranslationCache cache;
public static string rexName = "rex:";
public static string strongName = "stg:";
public static void Load()
{
hud = CreateNewConfig("HUD-Translate", should: false);
hud.shouldTranslate = TranslatePlugin.shouldTranslateHUD.Value;
items = CreateNewConfig("Item-Translate");
items.shouldTranslate = TranslatePlugin.shouldTranslateItems.Value;
terminal = CreateNewConfig("Terminal-Translate");
terminal.shouldTranslate = TranslatePlugin.shouldTranslateTerimal.Value;
cmd_py = CreateNewConfig("CMD-PY-Translate");
cmd_zh = CreateNewConfig("CMD-ZH-Translate");
text = CreateNewConfig("SpecialText-Translate");
text.shouldTranslate = TranslatePlugin.shouldTranslateSpecialText.Value;
gui = CreateNewConfig("GuiText-Translate");
gui.shouldTranslate = TranslatePlugin.shouldTranslateGui.Value;
normal = CreateNewConfig("Normal-Translate", should: false);
normal.shouldTranslate = TranslatePlugin.shouldTranslateNormalText.Value;
normalText = new NormalTextTranslator(normal.ConfigFileName + ".xml");
normalText.Load();
hudText = new NormalTextTranslator(hud.ConfigFileName + ".xml");
hudText.Load();
cache = new TextureTranslationCache();
cache.LoadTranslationFiles();
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
string fullPath = Path.GetFullPath(TranslatePlugin.DefaultPath);
TranslatePlugin.logger.LogInfo((object)("开始监测" + fullPath));
fileSystemWatcher.Path = fullPath;
fileSystemWatcher.Filter = "*.xml";
fileSystemWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security;
fileSystemWatcher.Changed += OnFileChange;
fileSystemWatcher.IncludeSubdirectories = true;
fileSystemWatcher.EnableRaisingEvents = true;
}
private static void OnFileChange(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Created && e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
foreach (TranslateConfigFile config in TranslateConfigFile.configs)
{
if (config.shouldLoad && config.ConfigFilePath.ToLower().Contains(e.FullPath.ToLower()))
{
config.Reload();
TextTranslate.ChangeTime++;
}
}
}
public static void show(TranslateConfigFile file)
{
foreach (string key in file.normal.Keys)
{
TranslatePlugin.LogInfo(key + "=" + file.normal[key]);
}
}
private static TranslateConfigFile CreateNewConfig(string fileName, bool should)
{
TranslatePlugin.logger.LogInfo((object)("GameTranslator正在载入配置文件" + fileName));
return new TranslateConfigFile(fileName, saveOnInit: true, should);
}
private static TranslateConfigFile CreateNewConfig(string fileName)
{
TranslatePlugin.logger.LogInfo((object)("GameTranslator正在载入配置文件" + fileName));
return new TranslateConfigFile(fileName, saveOnInit: true, shouldLoad: true);
}
public static string getRegex(string pattern)
{
StringBuilder stringBuilder = new StringBuilder(pattern);
stringBuilder.Replace("\\", "\\\\");
return stringBuilder.ToString();
}
public static bool IsStringContainsEnglish(string input)
{
Regex regex = new Regex("[a-zA-Z]");
return regex.IsMatch(input);
}
public static bool IsStringContainsChinese(string input)
{
Regex regex = new Regex("[\\u4e00-\\u9fa5]");
return regex.IsMatch(input);
}
public static string useRegularExpression(string raw, string pattern, string result)
{
pattern = pattern.Replace(rexName, "");
return Regex.Replace(raw, pattern, result);
}
public static string replaceByMap(string text, TranslateConfigFile file)
{
if (!file.shouldTranslate)
{
return text;
}
if (file.translatePairs.ContainsKey(text))
{
return file.translatePairs[text];
}
StringBuffer stringBuffer = new StringBuffer(text);
foreach (KeyValuePair<string, string> item in file.useRex)
{
string pattern = Regex.Unescape(getRegex(item.Key));
string result = Regex.Unescape(item.Value);
string str = useRegularExpression(stringBuffer.ToString(), pattern, result);
stringBuffer.Clear().Append(str);
}
foreach (KeyValuePair<string, string> item2 in file.strong)
{
string oldValue = Regex.Unescape(item2.Key);
string newValue = Regex.Unescape(item2.Value);
stringBuffer.Replace(oldValue, newValue);
}
foreach (KeyValuePair<string, string> item3 in file.normal)
{
string oldValue2 = Regex.Unescape(item3.Key);
string newValue2 = Regex.Unescape(item3.Value);
stringBuffer.ReplaceFull(oldValue2, newValue2);
}
file.translatePairs[text] = stringBuffer.ToString();
return stringBuffer.ToString();
}
public static void Log(string text)
{
log.Log(text);
}
}
[BepInPlugin("GameTranslator", "GameTranslator", "1.8.33")]
public class TranslatePlugin : BaseUnityPlugin
{
public static ManualLogSource logger;
public static ConfigEntry<string> language;
public static ConfigEntry<bool> shouldHideModList;
public static ConfigEntry<bool> shouldFixTipErrors;
public static ConfigEntry<bool> shouldTranslateTerimal;
public static ConfigEntry<bool> shouldTranslateNormalText;
public static ConfigEntry<bool> shouldTranslateSpecialText;
public static ConfigEntry<bool> shouldTranslateItems;
public static ConfigEntry<bool> shouldTranslateHUD;
public static ConfigEntry<bool> shouldTranslateGui;
public static ConfigEntry<bool> TerimalCanUseChinese;
public static ConfigEntry<bool> TerimalCanUsePinyinAbbreviation;
public static ConfigEntry<bool> generateTerimalCommand;
public static ConfigEntry<bool> changeFont;
public static ConfigEntry<bool> changeTexture;
public static ConfigEntry<string> overrideFont;
public static ConfigEntry<string> alternateFontTextMeshPro;
public static ConfigEntry<string> overrideFontTextMeshPro;
public static ConfigEntry<string> shouldRemoveChar;
private const string PLUGIN_GUID = "GameTranslator";
private const string PLUGIN_NAME = "GameTranslator";
private const string PLUGIN_VERSION = "1.8.33";
internal static TranslatePlugin Instance;
private readonly Harmony harmony = new Harmony("GameTranslator");
public static string DefaultPath;
public static string TexturesPath;
public static bool shouldTranslate;
private void Awake()
{
logger = ((BaseUnityPlugin)this).Logger;
Instance = this;
((BaseUnityPlugin)this).Logger.LogInfo((object)"插件GameTranslator已加载!");
ConfigFile();
HookingHelper.PatchAll((IEnumerable<Type>)ImageHooks.All, false);
HookingHelper.PatchAll((IEnumerable<Type>)ImageHooks.Sprite, false);
HookingHelper.PatchAll((IEnumerable<Type>)ImageHooks.SpriteRenderer, false);
harmony.PatchAll();
}
private void ConfigFile()
{
language = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "Language", "zh-CN", "选择的语言,根据不同语言,目录位置不同");
shouldHideModList = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Hide Mod List", true, "是否隐藏mod列表弹窗");
shouldFixTipErrors = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Fix Tip Errors", true, "是否修复Tip提示界面乱码");
shouldTranslateTerimal = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Terimal", true, "是否翻译终端");
shouldTranslateGui = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Gui", true, "是否翻译Gui");
shouldTranslateNormalText = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Normal Text", true, "是否翻译普通文本【需要整段字满足才替换】");
shouldTranslateSpecialText = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Special Text", true, "是否翻译特殊文本【部分字满足就替换】");
TerimalCanUseChinese = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Terimal Can Use Chinese", true, "终端是否可以用中文执行指令");
TerimalCanUsePinyinAbbreviation = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Terimal Can Use Pinyin Abbreviation", true, "终端是否可以用拼音缩写执行指令");
shouldTranslateItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Items", true, "是否翻译物品");
shouldTranslateHUD = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate HUD", true, "是否翻译聊天栏和小提示内容");
changeFont = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Change Font", true, "是否更换字体(关闭后中文会乱码)");
overrideFont = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "OverrideFont", "微软雅黑", "替换的字体");
overrideFontTextMeshPro = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "OverrideFontTextMeshPro", "arialuni.cfg", "替换的字体文件");
alternateFontTextMeshPro = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "AlternateFontTextMeshPro", "", "备用字体文件(如果出现口口的话,可以添加备用字体来解决)");
shouldRemoveChar = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "shouldRemoveChars", "$0123456789*%", "需要移除的原版字体");
changeTexture = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Change Texture", true, "是否更换图片");
DefaultPath = ((BaseUnityPlugin)this).Config.ConfigFilePath.Replace("GameTranslator.cfg", "translations\\" + language.Value + "\\");
TexturesPath = DefaultPath + "Texture\\";
TranslateConfig.Load();
TranslateExtensions.Load();
}
public static List<char> getShouldRemoveChars()
{
return shouldRemoveChar.Value.ToCharArray().ToList();
}
public static void LogInfo(string info)
{
if (logger != null)
{
logger.LogInfo((object)info);
}
}
}
}
namespace GameTranslator.Patches.Translatons
{
public class NormalTextTranslator
{
public Dictionary<string, string> _translations = new Dictionary<string, string>();
public Dictionary<string, string> _strongTranslations = new Dictionary<string, string>();
public Dictionary<string, string> _reverseTranslations = new Dictionary<string, string>();
public Dictionary<string, string> _tokenTranslations = new Dictionary<string, string>();
public Dictionary<string, string> _reverseTokenTranslations = new Dictionary<string, string>();
private HashSet<string> _partialTranslations = new HashSet<string>();
public List<RegexTranslation> _defaultRegexes = new List<RegexTranslation>();
private HashSet<string> _registeredRegexes = new HashSet<string>();
public List<RegexTranslationSplitter> _splitterRegexes = new List<RegexTranslationSplitter>();
public HashSet<string> _registeredSplitterRegexes = new HashSet<string>();
private FileSystemWatcher _fileWatcher;
public string FileName;
public string FilePath;
public static Dictionary<string, NormalTextTranslator> keyValuePairs = new Dictionary<string, NormalTextTranslator>();
public NormalTextTranslator(string fileName)
{
try
{
FileName = fileName;
FilePath = TranslatePlugin.DefaultPath + fileName;
_fileWatcher = new FileSystemWatcher();
_fileWatcher.Path = Path.GetFullPath(TranslatePlugin.DefaultPath);
_fileWatcher.Filter = FileName;
_fileWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security;
_fileWatcher.Changed += OnFileChange;
_fileWatcher.IncludeSubdirectories = true;
_fileWatcher.EnableRaisingEvents = true;
_fileWatcher.Changed += OnFileChange;
keyValuePairs.Add(FileName, this);
}
catch (Exception ex)
{
TranslatePlugin.logger.LogWarning((object)"在初始化翻译文件时发生错误!");
TranslatePlugin.logger.LogError((object)ex);
}
}
private static void OnFileChange(object sender, FileSystemEventArgs e)
{
if (e.ChangeType != WatcherChangeTypes.Created && e.ChangeType != WatcherChangeTypes.Changed)
{
return;
}
foreach (NormalTextTranslator value in keyValuePairs.Values)
{
if (value.FileName.StartsWith(e.Name))
{
value.Load();
}
}
TextTranslate.ChangeTime++;
}
public void Load()
{
TranslatePlugin.logger.LogInfo((object)("--- 正在载入" + FileName + "文件 ---"));
try
{
_defaultRegexes.Clear();
_translations.Clear();
_reverseTranslations.Clear();
_partialTranslations.Clear();
_tokenTranslations.Clear();
_reverseTokenTranslations.Clear();
_splitterRegexes.Clear();
LoadTranslationsInStream(FilePath, FileName, isOutputFile: false, isLoad: true);
if (!FileName.StartsWith("HUD-Translate"))
{
return;
}
foreach (string key in TranslateConfig.items.normal.Keys)
{
_strongTranslations[key] = TranslateConfig.items.normal[key];
}
}
catch (Exception ex)
{
TranslatePlugin.logger.LogWarning((object)("在加载" + FileName + "文件时发生错误!"));
TranslatePlugin.logger.LogError((object)ex);
}
}
private void LoadTranslationsInStream(string stream, string fullFileName, bool isOutputFile, bool isLoad)
{
if (isLoad)
{
TranslatePlugin.logger.LogInfo((object)("正在加载文本文件: " + stream + "."));
}
StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
string[] array = streamReader.ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
string[] array2 = array;
foreach (string text in array2)
{
try
{
string[] array3 = TextHelper.ReadTranslationLineAndDecode(text);
if (array3 == null)
{
continue;
}
string text2 = array3[0];
string value = array3[1];
if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(value))
{
continue;
}
if (text2.StartsWith("sr:"))
{
try
{
RegexTranslationSplitter regex = new RegexTranslationSplitter(text2, value);
AddTranslationSplitterRegex(regex);
}
catch (Exception ex)
{
TranslatePlugin.logger.LogWarning((object)("在构造正则表达式翻译分割器时发生错误: '" + text + "'." + Environment.NewLine + ex));
}
}
else if (text2.StartsWith("r:"))
{
try
{
RegexTranslation regex2 = new RegexTranslation(text2, value);
AddTranslationRegex(regex2);
}
catch (Exception ex2)
{
TranslatePlugin.logger.LogWarning((object)("在构造正则表达式转换时发生错误: '" + text + "'." + Environment.NewLine + ex2));
}
}
else if (text2.StartsWith("sm:"))
{
try
{
text2 = text2.Substring(4, text2.Length - 5);
AddStrongTranslation(text2, value);
}
catch (Exception ex3)
{
TranslatePlugin.logger.LogWarning((object)("在添加强匹配文本时发生错误: " + Environment.NewLine + ex3));
}
}
else
{
AddTranslation(text2, value);
}
}
catch (Exception ex4)
{
TranslatePlugin.logger.LogWarning((object)("在读取翻译时发生错误: '" + text + "'." + Environment.NewLine + ex4));
}
}
streamReader.Close();
}
private void AddStrongTranslation(string key, string value)
{
if (key != null && value != null)
{
_strongTranslations[key] = value;
_reverseTranslations[value] = key;
}
}
private void AddTranslation(string key, string value)
{
if (key != null && value != null)
{
_translations[key] = value;
_reverseTranslations[value] = key;
}
}
private void AddTranslationSplitterRegex(RegexTranslationSplitter regex)
{
if (!_registeredSplitterRegexes.Contains(regex.Original))
{
_registeredSplitterRegexes.Add(regex.Original);
_splitterRegexes.Add(regex);
}
}
private void AddTranslationRegex(RegexTranslation regex)
{
if (!_registeredRegexes.Contains(regex.Original))
{
_registeredRegexes.Add(regex.Original);
_defaultRegexes.Add(regex);
}
}
private bool HasTranslated(string key)
{
return _translations.ContainsKey(key);
}
private bool IsTranslation(string translation)
{
if (_reverseTranslations.ContainsKey(translation))
{
return true;
}
return false;
}
private bool IsTokenTranslation(string translation)
{
return _reverseTokenTranslations.ContainsKey(translation);
}
public bool IsTranslatable(string text, bool isToken)
{
bool flag = !IsTranslation(text);
if (isToken && flag)
{
flag = !IsTokenTranslation(text);
}
return flag;
}
private string ChangeRegex(string text)
{
Regex regex = new Regex("\\$([0-9]+)");
return regex.Replace(text, ReplaceFunc);
static string ReplaceFunc(Match match)
{
int num = int.Parse(match.Groups[1].Value);
return "{" + (num - 1) + "}";
}
}
public string SplitterTranslate(string text, RegexTranslationSplitter splitter, bool strong, bool ignoreCase)
{
StringBuilder stringBuilder = new StringBuilder(text);
if (splitter.CompiledRegex != null)
{
MatchCollection matchCollection = splitter.CompiledRegex.Matches(text);
foreach (Match item in matchCollection)
{
if (!item.Success)
{
continue;
}
List<string> list = new List<string>();
string[] array = new string[item.Groups.Count];
for (int i = 1; i < item.Groups.Count; i++)
{
string value = item.Groups[i].Value;
StringBuffer stringBuffer = new StringBuffer(value);
if (strong)
{
foreach (string key in _strongTranslations.Keys)
{
if (value.Contains(key))
{
stringBuffer.ReplaceFull(key, _strongTranslations[key]);
}
}
}
else
{
foreach (string key2 in _translations.Keys)
{
if (value.Contains(key2))
{
stringBuffer.ReplaceFull(key2, _translations[key2]);
}
}
}
array[i - 1] = stringBuffer.ToString();
}
string format = Regex.Unescape(getRegex(ChangeRegex(splitter.Translation)));
object[] args = array;
string newValue = string.Format(format, args);
stringBuilder = stringBuilder.Replace(item.Value, newValue);
}
}
return stringBuilder.ToString();
}
public static string getRegex(string pattern)
{
StringBuilder stringBuilder = new StringBuilder(pattern);
stringBuilder.Replace("\\=", "\\\\=");
return stringBuilder.ToString();
}
public string SplitterTranslate(string text, RegexTranslationSplitter splitter, bool strong)
{
return SplitterTranslate(text, splitter, strong, ignoreCase: false);
}
public string TryTranslateByStrong(string text)
{
string text2 = text;
try
{
StringBuilder stringBuilder = new StringBuilder(text2);
foreach (string key in _translations.Keys)
{
stringBuilder.Replace(key, _translations[key]);
}
text2 = stringBuilder.ToString();
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"弱匹配翻译出现问题.");
}
try
{
foreach (string key2 in _translations.Keys)
{
if (text2.Trim().Equals(key2.Trim()))
{
text2 = _translations[key2];
}
}
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"强匹配出现问题.");
}
try
{
foreach (RegexTranslationSplitter splitterRegex in _splitterRegexes)
{
text2 = SplitterTranslate(text2, splitterRegex, strong: true, ignoreCase: true);
}
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"sr翻译出现问题.");
}
try
{
foreach (RegexTranslation defaultRegex in _defaultRegexes)
{
if (defaultRegex.CompiledRegex != null)
{
Match match = defaultRegex.CompiledRegex.Match(text2);
if (match.Success)
{
text2 = defaultRegex.CompiledRegex.Replace(text2, defaultRegex.Translation);
}
}
}
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"r翻译出现问题.");
}
return text2;
}
public string TryTranslate(string text)
{
string text2 = text;
try
{
foreach (string key in _translations.Keys)
{
if (text2.Trim().Equals(key.Trim()))
{
text2 = _translations[key];
}
}
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"强匹配翻译出现问题.");
}
try
{
StringBuilder stringBuilder = new StringBuilder(text2);
foreach (string key2 in _strongTranslations.Keys)
{
stringBuilder.Replace(key2, _strongTranslations[key2]);
}
text2 = stringBuilder.ToString();
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"弱匹配翻译出现问题.");
}
try
{
foreach (RegexTranslationSplitter splitterRegex in _splitterRegexes)
{
text2 = SplitterTranslate(text2, splitterRegex, strong: false);
}
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"sr翻译出现问题.");
}
try
{
foreach (RegexTranslation defaultRegex in _defaultRegexes)
{
if (defaultRegex.CompiledRegex != null)
{
Match match = defaultRegex.CompiledRegex.Match(text2);
if (match.Success)
{
text2 = defaultRegex.CompiledRegex.Replace(text2, defaultRegex.Translation);
}
}
}
}
catch (Exception)
{
TranslatePlugin.logger.LogInfo((object)"r翻译出现问题.");
}
return text2;
}
}
public class TextureTranslationCache
{
internal class FileSystemTranslatedImageSource : TranslatedImage.ITranslatedImageSource
{
private readonly string _fileName;
public FileSystemTranslatedImageSource(string fileName)
{
_fileName = fileName;
}
public byte[] GetData()
{
using FileStream fileStream = File.OpenRead(_fileName);
return StreamExtensions.ReadFully((Stream)fileStream, 16384);
}
}
internal static class HashHelper
{
private static readonly SHA1Managed SHA1 = new SHA1Managed();
private static readonly uint[] Lookup32 = CreateLookup32();
public static string Compute(byte[] data)
{
return ByteArrayToHexViaLookup32(SHA1.ComputeHash(data)).Substring(0, 10);
}
private static uint[] CreateLookup32()
{
uint[] array = new uint[256];
for (int i = 0; i < 256; i++)
{
string text = i.ToString("X2");
array[i] = text[0] + ((uint)text[1] << 16);
}
return array;
}
private static string ByteArrayToHexViaLookup32(byte[] bytes)
{
uint[] lookup = Lookup32;
char[] array = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
uint num = lookup[bytes[i]];
array[2 * i] = (char)num;
array[2 * i + 1] = (char)(num >> 16);
}
return new string(array);
}
}
public Dictionary<string, TranslatedImage> _translatedImages = new Dictionary<string, TranslatedImage>(StringComparer.InvariantCultureIgnoreCase);
public HashSet<string> _untranslatedImages = new HashSet<string>();
private Dictionary<string, string> _keyToFileName = new Dictionary<string, string>();
private bool _disposed;
public TextureTranslationCache()
{
try
{
Directory.CreateDirectory(TranslatePlugin.TexturesPath);
}
catch (Exception ex)
{
XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing translation file watching for textures.");
}
}
private void FileWatcher_DirectoryUpdated()
{
}
private IEnumerable<string> GetTextureFiles()
{
return from x in Directory.GetFiles(TranslatePlugin.TexturesPath, "*.*", SearchOption.AllDirectories)
where x.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || x.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)
select x;
}
public void LoadTranslationFiles()
{
try
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
_translatedImages.Clear();
_untranslatedImages.Clear();
_keyToFileName.Clear();
Directory.CreateDirectory(TranslatePlugin.TexturesPath);
foreach (string textureFile in GetTextureFiles())
{
RegisterImageFromFile(textureFile);
}
float realtimeSinceStartup2 = Time.realtimeSinceStartup;
XuaLogger.AutoTranslator.Debug($"Loaded texture files (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)");
}
catch (Exception ex)
{
XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations.");
}
}
private void RegisterImageFromStream(string fullFileName, TranslatedImage.ITranslatedImageSource source)
{
try
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullFileName);
int num = fileNameWithoutExtension.LastIndexOf("[");
int num2 = fileNameWithoutExtension.LastIndexOf("]");
if (num2 > -1 && num > -1 && num2 > num)
{
int num3 = num + 1;
string[] array = fileNameWithoutExtension.Substring(num3, num2 - num3).Split(new char[1] { '-' });
string key;
string x;
if (array.Length == 1)
{
key = array[0];
x = array[0];
}
else
{
if (array.Length != 2)
{
XuaLogger.AutoTranslator.Warn("Image not loaded (unknown hash): " + fullFileName + ".");
return;
}
key = array[0];
x = array[1];
}
byte[] data = source.GetData();
string y = HashHelper.Compute(data);
bool flag = StringComparer.InvariantCultureIgnoreCase.Compare(x, y) != 0;
_keyToFileName[key] = fullFileName;
if (flag)
{
RegisterTranslatedImage(fullFileName, key, data);
XuaLogger.AutoTranslator.Debug("Image loaded: " + fullFileName + ".");
}
else
{
RegisterUntranslatedImage(key);
XuaLogger.AutoTranslator.Warn("Image not loaded (unmodified): " + fullFileName + ".");
}
}
else
{
XuaLogger.AutoTranslator.Warn("Image not loaded (no hash): " + fullFileName + ".");
}
}
catch (Exception ex)
{
XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading texture file: " + fullFileName);
}
}
private void RegisterImageFromFile(string fullFileName)
{
if (File.Exists(fullFileName))
{
FileSystemTranslatedImageSource source = new FileSystemTranslatedImageSource(fullFileName);
RegisterImageFromStream(fullFileName, source);
}
}
public void RenameFileWithKey(string name, string key, string newKey)
{
try
{
if (_keyToFileName.TryGetValue(key, out var value))
{
_keyToFileName.Remove(key);
value.Replace(key, newKey);
if (!IsImageRegistered(newKey))
{
byte[] data = File.ReadAllBytes(value);
RegisterImageFromData(name, newKey, data);
File.Delete(value);
XuaLogger.AutoTranslator.Warn("Replaced old file with name '" + name + "' registered with key old '" + key + "'.");
}
}
}
catch (Exception ex)
{
XuaLogger.AutoTranslator.Error(ex, "An error occurred while trying to rename file with key '" + key + "'.");
}
}
internal void RegisterImageFromData(string textureName, string key, byte[] data)
{
string text = StringExtensions.SanitizeForFileSystem(textureName);
string text2 = HashHelper.Compute(data);
string text3 = ((!(key == text2)) ? (text + " [" + key + "-" + text2 + "].png") : (text + " [" + key + "].png"));
string text4 = Path.Combine(TranslatePlugin.TexturesPath, text3);
File.WriteAllBytes(text4, data);
XuaLogger.AutoTranslator.Info("Dumped texture file: " + text3);
_keyToFileName[key] = text4;
RegisterTranslatedImage(text4, key, data);
}
private void RegisterTranslatedImage(string fileName, string key, byte[] data)
{
_translatedImages[key] = new TranslatedImage(fileName, data, null);
}
private void RegisterUntranslatedImage(string key)
{
_untranslatedImages.Add(key);
}
internal bool IsImageRegistered(string key)
{
return _translatedImages.ContainsKey(key) || _untranslatedImages.Contains(key);
}
internal bool TryGetTranslatedImage(string key, out byte[] data, out TranslatedImage image)
{
if (_translatedImages.TryGetValue(key, out var value))
{
try
{
data = value.GetData();
image = value;
return data != null;
}
catch (Exception ex)
{
XuaLogger.AutoTranslator.Error(ex, "An error occurrd while attempting to load image: " + value.FileName);
_translatedImages.Remove(key);
}
}
data = null;
image = null;
return false;
}
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
}
_disposed = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
namespace GameTranslator.Patches.Utils
{
internal class TextTranslate
{
public static TextTranslate Instance = new TextTranslate();
public static long ChangeTime = 0L;
internal void Hook_TextChanged(object ui)
{
if (TerminalPatch.ig == null || !TerminalPatch.ig.Contains(ui))
{
TextTranslationInfo orCreateTextTranslationInfo = ui.GetOrCreateTextTranslationInfo();
bool ignoreComponentState = DiscoverComponent(ui, orCreateTextTranslationInfo);
if (TranslatePlugin.shouldTranslateSpecialText.Value || TranslatePlugin.shouldTranslateNormalText.Value)
{
TranslateImmediate(ui, null, orCreateTextTranslationInfo, TranslateConfig.normalText, TranslateConfig.text, ignoreComponentState);
}
}
}
internal void Hook_TextChanged(object ui, ref string value)
{
if (TerminalPatch.ig == null || !TerminalPatch.ig.Contains(ui))
{
TextTranslationInfo orCreateTextTranslationInfo = ui.GetOrCreateTextTranslationInfo();
bool ignoreComponentState = DiscoverComponent(ui, orCreateTextTranslationInfo);
if (TranslatePlugin.shouldTranslateSpecialText.Value || TranslatePlugin.shouldTranslateNormalText.Value)
{
value = TranslateImmediate(ui, value, orCreateTextTranslationInfo, TranslateConfig.normalText, TranslateConfig.text, ignoreComponentState);
}
}
}
public string TranslateImmediate(object ui, string text, TextTranslationInfo info, NormalTextTranslator normalText, TranslateConfig.TranslateConfigFile config, bool ignoreComponentState)
{
if (info != null && (info.IsCurrentlySettingText || info.MustIgnore))
{
return text;
}
text = text ?? ui.GetText(info);
if (Utility.IsNullOrWhiteSpace(text))
{
return text;
}
if (info != null && info.IsTranslated)
{
if (!info.OriginalText.Equals(text) || info.ChangeTime != ChangeTime)
{
info.Reset(text);
}
else if (info.OriginalText.Equals(text) || info.TranslatedText.Equals(text))
{
return info.TranslatedText;
}
}
string text2 = text;
if ((normalText == null || normalText.IsTranslatable(text, isToken: false)) && (ignoreComponentState || ui.IsComponentActive()))
{
if (normalText != null && TranslatePlugin.shouldTranslateNormalText.Value)
{
text2 = normalText.TryTranslate(text2);
}
text2 = TranslateConfig.replaceByMap(text2, config);
SetTranslatedText(ui, text2, text, info);
}
return text2;
}
internal void SetTranslatedText(object ui, string translatedText, string originalText, TextTranslationInfo info)
{
if (info != null)
{
info.OriginalText = originalText;
info.SetTranslatedText(translatedText);
}
SetText(ui, translatedText, isTranslated: true, originalText, info);
}
private void SetText(object ui, string text, bool isTranslated, string originalText, TextTranslationInfo info)
{
if (info == null || !info.IsCurrentlySettingText)
{
if (info != null)
{
info.IsCurrentlySettingText = true;
}
ui.SetText(text, info);
if (info != null)
{
info.IsCurrentlySettingText = false;
}
}
}
public bool DiscoverComponent(object ui, TextTranslationInfo info)
{
if (info == null || !TranslatePlugin.changeFont.Value)
{
return true;
}
try
{
bool flag = ui.IsComponentActive();
if (TranslatePlugin.overrideFontTextMeshPro.Value != null && flag)
{
info.ChangeFont(ui);
return true;
}
return flag;
}
catch (Exception ex)
{
TranslatePlugin.logger.LogWarning((object)("处理UI时发生错误." + Environment.NewLine + ex));
}
return false;
}
}
public class StringBuffer
{
private char[] value;
private int length;
private int capacity;
private const int DEFAULT_CAPACITY = 16;
public int Length
{
get
{
return length;
}
set
{
if (value < 0 || value > capacity)
{
throw new ArgumentOutOfRangeException("value");
}
if (value < length)
{
Array.Clear(this.value, value, length - value);
}
length = value;
}
}
public int Capacity
{
get
{
return capacity;
}
set
{
if (value < length)
{
throw new ArgumentOutOfRangeException("value");
}
if (value != capacity)
{
char[] destinationArray = new char[value];
Array.Copy(this.value, 0, destinationArray, 0, length);
this.value = destinationArray;
capacity = value;
}
}
}
public StringBuffer()
{
value = new char[16];
length = 0;
capacity = 16;
}
public StringBuffer(int capacity)
{
if (capacity < 0)
{
throw new ArgumentOutOfRangeException("capacity");
}
value = new char[capacity];
length = 0;
this.capacity = capacity;
}
public StringBuffer(string str)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
value = new char[str.Length + 16];
str.CopyTo(0, value, 0, str.Length);
length = str.Length;
capacity = str.Length + 16;
}
public void EnsureCapacity(int minimumCapacity)
{
if (minimumCapacity < 0)
{
throw new ArgumentOutOfRangeException("minimumCapacity");
}
if (minimumCapacity > capacity)
{
int num = capacity * 2;
if (num < minimumCapacity)
{
num = minimumCapacity;
}
Capacity = num;
}
}
public StringBuffer Append(object obj)
{
if (obj == null)
{
return this;
}
return Append(obj.ToString());
}
public StringBuffer Append(string str)
{
if (str == null)
{
return this;
}
int num = str.Length;
EnsureCapacity(length + num);
str.CopyTo(0, value, length, num);
length += num;
return this;
}
public StringBuffer Append(char c)
{
EnsureCapacity(length + 1);
value[length] = c;
length++;
return this;
}
public StringBuffer Insert(int index, object obj)
{
if (obj == null)
{
return this;
}
return Insert(index, obj.ToString());
}
public StringBuffer Insert(int index, string str)
{
if (index < 0 || index > length)
{
throw new ArgumentOutOfRangeException("index");
}
if (str == null)
{
return this;
}
int num = str.Length;
EnsureCapacity(length + num);
Array.Copy(value, index, value, index + num, length - index);
str.CopyTo(0, value, index, num);
length += num;
return this;
}
public StringBuffer Insert(int index, char c)
{
if (index < 0 || index > length)
{
throw new ArgumentOutOfRangeException("index");
}
EnsureCapacity(length + 1);
Array.Copy(value, index, value, index + 1, length - index);
value[index] = c;
length++;
return this;
}
public StringBuffer Remove(int startIndex, int length)
{
if (startIndex < 0 || startIndex > this.length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (length < 0 || startIndex + length > this.length)
{
throw new ArgumentOutOfRangeException("length");
}
Array.Copy(value, startIndex + length, value, startIndex, this.length - startIndex - length);
Array.Clear(value, this.length - length, length);
this.length -= length;
return this;
}
public StringBuffer Replace(char oldChar, char newChar)
{
for (int i = 0; i < length; i++)
{
if (value[i] == oldChar)
{
value[i] = newChar;
}
}
return this;
}
public StringBuffer Replace(string oldValue, string newValue)
{
if (oldValue == null)
{
throw new ArgumentNullException("oldValue");
}
if (oldValue.Length == 0)
{
throw new ArgumentException("oldValue cannot be empty");
}
if (newValue == null)
{
newValue = string.Empty;
}
int num = oldValue.Length;
int num2 = newValue.Length;
for (int num3 = IndexOf(oldValue); num3 >= 0; num3 = IndexOf(oldValue, num3 + num2))
{
Remove(num3, num);
Insert(num3, newValue);
}
return this;
}
public int IndexOf(char c)
{
return IndexOf(c, 0, length);
}
public int IndexOf(char c, int startIndex)
{
return IndexOf(c, startIndex, length - startIndex);
}
public int IndexOf(char c, int startIndex, int count)
{
if (startIndex < 0 || startIndex > length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > length)
{
throw new ArgumentOutOfRangeException("count");
}
return Array.IndexOf(value, c, startIndex, count);
}
public int IndexOf(string str)
{
return IndexOf(str, 0, length);
}
public int IndexOf(string str, int startIndex)
{
return IndexOf(str, startIndex, length - startIndex);
}
public int IndexOf(string str, int startIndex, int count)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
if (startIndex < 0 || startIndex > length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > length)
{
throw new ArgumentOutOfRangeException("count");
}
return value.ToString(startIndex, count).IndexOf(str);
}
public string Substring(int startIndex)
{
return Substring(startIndex, length - startIndex);
}
public string Substring(int startIndex, int length)
{
if (startIndex < 0 || startIndex > this.length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (length < 0 || startIndex + length > this.length)
{
throw new ArgumentOutOfRangeException("length");
}
return new string(value, startIndex, length);
}
public bool Contains(string text)
{
return IndexOf(text) >= 0;
}
public StringBuffer ReplaceFull(string oldValue, string newValue)
{
if (oldValue == null)
{
throw new ArgumentNullException("oldValue");
}
if (oldValue.Length == 0)
{
throw new ArgumentException("oldValue cannot be empty");
}
if (newValue == null)
{
newValue = string.Empty;
}
int num = oldValue.Length;
int num2 = newValue.Length;
for (int num3 = IndexOfWord(oldValue); num3 >= 0; num3 = IndexOfWord(oldValue, num3 + num2))
{
Remove(num3, num);
Insert(num3, newValue);
}
return this;
}
private int IndexOfWord(string str)
{
return IndexOfWord(str, 0, length);
}
private int IndexOfWord(string str, int startIndex)
{
return IndexOfWord(str, startIndex, length - startIndex);
}
public int IndexOfWord(string str, int startIndex, int count)
{
if (str == null)
{
throw new ArgumentNullException("str");
}
if (startIndex < 0 || startIndex > length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > length)
{
throw new ArgumentOutOfRangeException("count");
}
int num = str.Length;
int[] array = new int[num];
int num2 = 0;
computeLPSArray(str, num, array);
int num3 = startIndex;
while (num3 < startIndex + count)
{
if (str[num2] == value[num3])
{
num2++;
num3++;
}
if (num2 == num)
{
if ((num3 - num2 == 0 || !char.IsLetter(value[num3 - num2 - 1])) && (num3 == length || !char.IsLetter(value[num3])))
{
return num3 - num2;
}
num2 = array[num2 - 1];
}
else if (num3 < startIndex + count && str[num2] != value[num3])
{
if (num2 != 0)
{
num2 = array[num2 - 1];
}
else
{
num3++;
}
}
}
return -1;
}
private void computeLPSArray(string str, int M, int[] lps)
{
int num = 0;
int num2 = 1;
lps[0] = 0;
while (num2 < M)
{
if (str[num2] == str[num])
{
num = (lps[num2] = num + 1);
num2++;
}
else if (num != 0)
{
num = lps[num - 1];
}
else
{
lps[num2] = num;
num2++;
}
}
}
private static bool IsWordChar(char c)
{
return char.IsLetter(c) || c == '_';
}
public StringBuffer Clear()
{
Length = 0;
return this;
}
public override string ToString()
{
return new string(value, 0, length);
}
}
}
namespace GameTranslator.Patches.Hooks.texture
{
internal static class ImageHooks
{
public static readonly Type[] All = new Type[20]
{
typeof(MaskableGraphic_OnEnable_Hook),
typeof(Image_sprite_Hook),
typeof(Image_overrideSprite_Hook),
typeof(Image_material_Hook),
typeof(RawImage_texture_Hook),
typeof(Cursor_SetCursor_Hook),
typeof(Material_mainTexture_Hook),
typeof(CubismRenderer_MainTexture_Hook),
typeof(CubismRenderer_TryInitialize_Hook),
typeof(UIAtlas_spriteMaterial_Hook),
typeof(UISprite_OnInit_Hook),
typeof(UISprite_material_Hook),
typeof(UISprite_atlas_Hook),
typeof(UI2DSprite_sprite2D_Hook),
typeof(UI2DSprite_material_Hook),
typeof(UITexture_mainTexture_Hook),
typeof(UITexture_material_Hook),
typeof(UIPanel_clipTexture_Hook),
typeof(UIRect_OnInit_Hook),
typeof(DicingTextures_GetTexture_Hook)
};
public static readonly Type[] Sprite = new Type[1] { typeof(Sprite_texture_Hook) };
public static readonly Type[] SpriteRenderer = new Type[1] { typeof(SpriteRenderer_sprite_Hook) };
}
}
namespace GameTranslator.Patches.Translatons
{
internal static class TranslateExtensions
{
public enum ImageFormat
{
PNG,
TGA
}
private interface IPropertyMover
{
void MoveProperty(object source, object destination);
}
private class PropertyMover<T, TPropertyType> : IPropertyMover
{
private readonly Func<T, TPropertyType> _get;
private readonly Action<T, TPropertyType> _set;
public PropertyMover(PropertyInfo propertyInfo)
{
MethodInfo getMethod = propertyInfo.GetGetMethod();
MethodInfo setMethod = propertyInfo.GetSetMethod();
_get = (Func<T, TPropertyType>)ExpressionHelper.CreateTypedFastInvoke((MethodBase)getMethod);
_set = (Action<T, TPropertyType>)ExpressionHelper.CreateTypedFastInvoke((MethodBase)setMethod);
}
public void MoveProperty(object source, object destination)
{
TPropertyType arg = _get((T)source);
_set((T)destination, arg);
}
}
private static readonly Dictionary<Type, ITextComponentManipulator> Manipulators = new Dictionary<Type, ITextComponentManipulator>();
public static FieldInfo m_ChunkOffset = typeof(StringBuilder).GetField("m_ChunkOffset", BindingFlags.Instance | BindingFlags.NonPublic);
public static FieldInfo m_ChunkLength = typeof(StringBuilder).GetField("m_ChunkLength", BindingFlags.Instance | BindingFlags.NonPublic);
public static MethodInfo FindChunkForIndex = typeof(StringBuilder).GetMethod("FindChunkForIndex", BindingFlags.Instance | BindingFlags.NonPublic);
public static MethodInfo ReplaceAllInChunk = typeof(StringBuilder).GetMethod("ReplaceAllInChunk", BindingFlags.Instance | BindingFlags.NonPublic);
public static MethodInfo StartsWith = typeof(StringBuilder).GetMethod("StartsWith", BindingFlags.Instance | BindingFlags.NonPublic);
private static List<IPropertyMover> TexturePropertyMovers;
private static readonly string SetAllDirtyMethodName = "SetAllDirty";
private static readonly string TexturePropertyName = "texture";
private static readonly string MainTexturePropertyName = "mainTexture";
private static readonly string CapitalMainTexturePropertyName = "MainTexture";
private static readonly string MarkAsChangedMethodName = "MarkAsChanged";
private static readonly string SupportRichTextPropertyName = "supportRichText";
private static readonly string RichTextPropertyName = "richText";
public static FieldInfo m_AtlasPopulationMode = typeof(TMP_FontAsset).GetField("m_AtlasPopulationMode", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo m_SourceFontFile = typeof(TMP_FontAsset).GetField("m_SourceFontFile", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo m_FaceInfo = typeof(TMP_FontAsset).GetField("m_FaceInfo", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo s_MissingCharacterList = typeof(TMP_FontAsset).GetField("s_MissingCharacterList", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo m_MissingUnicodesFromFontFile = typeof(TMP_FontAsset).GetField("m_MissingUnicodesFromFontFile", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo m_CharacterLookupDictionary = typeof(TMP_FontAsset).GetField("m_CharacterLookupDictionary", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo m_CharacterTable = typeof(TMP_FontAsset).GetField("m_CharacterTable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo m_CharactersToAddLookup = typeof(TMP_FontAsset).GetField("m_CharactersToAddLookup", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static Type GetUnityType(this object obj)
{
return obj.GetType();
}
private static bool IsWordChar(char c)
{
return char.IsLetterOrDigit(c) || c == '_';
}
public static bool Contains(this string s, string value, bool ignoreCase = false)
{
return ignoreCase ? (s.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) : (s.IndexOf(value, StringComparison.Ordinal) >= 0);
}
public static string ToString(this char[] value, int startIndex, int count)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (startIndex < 0 || startIndex > value.Length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex + count > value.Length)
{
throw new ArgumentOutOfRangeException("count");
}
return new string(value, startIndex, count);
}
public static StringBuilder ReplaceFull(this StringBuilder builder, string oldValue, string newValue)
{
return builder.ReplaceFull(oldValue, newValue, 0, builder.Length);
}
private static StringBuilder ReplaceFull(this StringBuilder builder, string oldValue, string newValue, int startIndex, int count)
{
int length = builder.Length;
if ((uint)startIndex > (uint)length)
{
throw new ArgumentOutOfRangeException("startIndex");
}
if (count < 0 || startIndex > length - count)
{
throw new ArgumentOutOfRangeException("count");
}
if (oldValue == null)
{
throw new ArgumentNullException("oldValue");
}
if (oldValue.Length == 0)
{
throw new ArgumentException("oldValue");
}
if (newValue == null)
{
newValue = "";
}
int num = newValue.Length - oldValue.Length;
int[] array = null;
int num2 = 0;
StringBuilder stringBuilder = (StringBuilder)FindChunkForIndex.Invoke(builder, new object[1] { startIndex });
int num3 = startIndex - (int)m_ChunkOffset.GetValue(builder);
while (count > 0)
{
if ((num3 == 0 || !IsWordChar(stringBuilder[num3 - 1])) && (bool)StartsWith.Invoke(builder, new object[4] { stringBuilder, num3, count, oldValue }))
{
int num4 = num3 + oldValue.Length;
if (num4 == length || !IsWordChar(stringBuilder[num4]))
{
if (array == null)
{
array = new int[5];
}
else if (num2 >= array.Length)
{
int[] array2 = new int[array.Length * 3 / 2 + 4];
Array.Copy(array, array2, array.Length);
array = array2;
}
array[num2++] = num3;
}
num3 += oldValue.Length;
count -= oldValue.Length;
}
else
{
num3++;
count--;
}
if (num3 >= (int)m_ChunkLength.GetValue(stringBuilder) || count == 0)
{
int num5 = num3 + (int)m_ChunkOffset.GetValue(stringBuilder);
int num6 = num5;
ReplaceAllInChunk.Invoke(builder, new object[5] { array, num2, stringBuilder, oldValue.Length, newValue });
num5 += (newValue.Length - oldValue.Length) * num2;
num2 = 0;
stringBuilder = (StringBuilder)FindChunkForIndex.Invoke(builder, new object[1] { num5 });
num3 = num5 - (int)m_ChunkOffset.GetValue(stringBuilder);
}
}
return builder;
}
public static StringBuilder ReplaceFullWords(this StringBuilder s, string oldWord, string newWord, bool ignoreCase = false)
{
if (s == null)
{
return null;
}
string input = s.ToString();
string pattern = "(?<=^|\\W)" + Regex.Escape(oldWord) + "(?=$|\\W)";
string value = Regex.Replace(input, pattern, newWord, ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
return s.Clear().Append(value);
}
public static string ReplaceFullWords(this string s, string oldWord, string newWord, bool ignoreCase = false)
{
if (s == null)
{
return null;
}
string pattern = "(?<=^|\\W)" + Regex.Escape(oldWord) + "(?=$|\\W)";
return Regex.Replace(s, pattern, newWord, ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
}
public static bool EqualsIgnoreCase(this string value, string other)
{
return string.Equals(value, other, StringComparison.OrdinalIgnoreCase);
}
public static Texture2D GetTexture(this object ui)
{
if (ui == null)
{
return null;
}
SpriteRenderer val = default(SpriteRenderer);
if (!ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref val))
{
Type type = ui.GetType();
CachedProperty val2 = ReflectionCache.CachedProperty(type, MainTexturePropertyName);
object obj;
if ((obj = ((val2 != null) ? val2.Get(ui) : null)) == null)
{
CachedProperty val3 = ReflectionCache.CachedProperty(type, TexturePropertyName);
if ((obj = ((val3 != null) ? val3.Get(ui) : null)) == null)
{
CachedProperty val4 = ReflectionCache.CachedProperty(type, CapitalMainTexturePropertyName);
obj = ((val4 != null) ? val4.Get(ui) : null);
}
}
return (Texture2D)((obj is Texture2D) ? obj : null);
}
Sprite sprite = val.sprite;
if ((Object)(object)sprite == (Object)null)
{
return null;
}
return sprite.texture;
}
public static string GetTextureName(this object texture, string fallbackName)
{
Texture2D val = default(Texture2D);
if (ObjectExtensions.TryCastTo<Texture2D>(texture, ref val))
{
string name = ((Object)val).name;
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
return fallbackName;
}
private static byte[] EncodeToPNGEx(Texture2D texture)
{
if (ImageConversion_Methods.EncodeToPNG != null)
{
return ImageConversion_Methods.EncodeToPNG(texture);
}
if (Texture2D_Methods.EncodeToPNG != null)
{
return Texture2D_Methods.EncodeToPNG(texture);
}
throw new NotSupportedException("No way to encode the texture to PNG.");
}
public static Sprite SetTexture(this object ui, Texture2D texture, Sprite sprite, bool isPrefixHooked)
{
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Expected O, but got Unknown
if (ui == null)
{
return null;
}
Texture2D texture2 = ui.GetTexture();
if (!UnityObjectReferenceComparer.Default.Equals((object)texture2, (object)texture))
{
SpriteRenderer sr = null;
Sprite val = null;
if (ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref sr))
{
if (isPrefixHooked)
{
return SafeCreateSprite(sr, sprite, texture);
}
return SafeSetSprite(sr, sprite, texture);
}
Type type = ui.GetType();
CachedProperty val2 = ReflectionCache.CachedProperty(type, MainTexturePropertyName);
if (val2 != null)
{
val2.Set(ui, (object)texture);
}
CachedProperty val3 = ReflectionCache.CachedProperty(type, TexturePropertyName);
if (val3 != null)
{
val3.Set(ui, (object)texture);
}
CachedProperty val4 = ReflectionCache.CachedProperty(type, CapitalMainTexturePropertyName);
if (val4 != null)
{
val4.Set(ui, (object)texture);
}
CachedProperty val5 = ReflectionCache.CachedProperty(type, "material");
object obj = ((val5 != null) ? val5.Get(ui) : null);
if (obj != null)
{
CachedProperty val6 = ReflectionCache.CachedProperty(obj.GetType(), MainTexturePropertyName);
if ((Object)(Texture2D)((val6 != null) ? val6.Get(obj) : null) == (Object)(object)texture2 && val6 != null)
{
val6.Set(obj, (object)texture);
}
}
}
return null;
}
public static Sprite SafeSetSprite(SpriteRenderer sr, Sprite sprite, Texture2D texture)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
return sr.sprite = Sprite.Create(texture, ((Object)(object)sprite != (Object)null) ? sprite.rect : sr.sprite.rect, Vector2.zero);
}
public static bool IsComponentActive(this object ui)
{
Component val = (Component)((ui is Component) ? ui : null);
if ((Object)(object)val != (Object)null && Object.op_Implicit((Object)(object)val))
{
GameObject gameObject = val.gameObject;
if (Object.op_Implicit((Object)(object)gameObject))
{
Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
if ((Object)(object)val2 != (Object)null)
{
return gameObject.activeInHierarchy && val2.enabled;
}
return gameObject.activeInHierarchy;
}
}
return true;
}
public static TextureDataResult GetTextureData(this Texture2D texture)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
float realtimeSinceStartup = Time.realtimeSinceStartup;
int width = ((Texture)texture).width;
int height = ((Texture)texture).height;
byte[] array = null;
if (array == null)
{
RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)0);
GL.Clear(false, true, new Color(0f, 0f, 0f, 0f));
Graphics.Blit((Texture)(object)texture, temporary);
RenderTexture active = RenderTexture.active;
RenderTexture.active = temporary;
Texture2D val = new Texture2D(width, height);
val.ReadPixels(new Rect(0f, 0f, (float)((Texture)temporary).width, (float)((Texture)temporary).height), 0, 0);
array = EncodeToPNGEx(val);
Object.DestroyImmediate((Object)(object)val);
RenderTexture.active = (((Object)(object)active == (Object)(object)temporary) ? null : active);
RenderTexture.ReleaseTemporary(temporary);
}
float realtimeSinceStartup2 = Time.realtimeSinceStartup;
return new TextureDataResult(array, nonReadable: false, realtimeSinceStartup2 - realtimeSinceStartup);
}
public static bool IsCompatible(this object texture, ImageFormat dataType)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Invalid comparison between Unknown and I4
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Invalid comparison between Unknown and I4
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Invalid comparison between Unknown and I4
TextureFormat format = ((Texture2D)texture).format;
return dataType switch
{
ImageFormat.TGA => (int)format == 5 || (int)format == 4 || (int)format == 3,
ImageFormat.PNG => true,
_ => false,
};
}
public static bool IsKnownImageType(this object ui)
{
if (ui == null)
{
return false;
}
Type unityType = ui.GetUnityType();
Material val = default(Material);
SpriteRenderer val2 = default(SpriteRenderer);
if (!ObjectExtensions.TryCastTo<Material>(ui, ref val) && !ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref val2) && (UnityTypes.Image == null || !UnityTypes.Image.IsAssignableFrom(unityType)) && (UnityTypes.RawImage == null || !UnityTypes.RawImage.IsAssignableFrom(unityType)) && (UnityTypes.CubismRenderer == null || !UnityTypes.CubismRenderer.IsAssignableFrom(unityType)))
{
if (UnityTypes.UIWidget != null)
{
object objA = unityType;
TypeContainer uILabel = UnityTypes.UILabel;
if (!object.Equals(objA, (uILabel != null) ? uILabel.UnityType : null) && UnityTypes.UIWidget.IsAssignableFrom(unityType))
{
return true;
}
}
if ((UnityTypes.UIAtlas == null || !UnityTypes.UIAtlas.IsAssignableFrom(unityType)) && (UnityTypes.UITexture == null || !UnityTypes.UITexture.IsAssignableFrom(unityType)))
{
return UnityTypes.UIPanel != null && UnityTypes.UIPanel.IsAssignableFrom(unityType);
}
}
return true;
}
public static TextureTranslationInfo GetOrCreateTextureTranslationInfo(this Texture2D texture)
{
TextureTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<TextureTranslationInfo>((object)texture);
orCreateExtensionData.Initialize(texture);
return orCreateExtensionData;
}
public static ITextComponentManipulator GetTextManipulator(this object ui)
{
if (ui == null)
{
return null;
}
Type unityType = ui.GetUnityType();
if (!Manipulators.TryGetValue(unityType, out var value))
{
value = ((UnityTypes.TextField != null && UnityTypes.TextField.IsAssignableFrom(unityType)) ? new FairyGUITextComponentManipulator() : ((UnityTypes.TextArea2D != null && UnityTypes.TextArea2D.IsAssignableFrom(unityType)) ? new TextArea2DComponentManipulator() : ((UnityTypes.UguiNovelText == null || !UnityTypes.UguiNovelText.IsAssignableFrom(unityType)) ? ((ITextComponentManipulator)new DefaultTextComponentManipulator(ui.GetType())) : ((ITextComponentManipulator)new UguiNovelTextComponentManipulator(ui.GetType())))));
Manipulators[unityType] = value;
}
return value;
}
private static Sprite SafeCreateSprite(Sprite sprite, Texture2D texture)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
Rect rect = sprite.rect;
float x = ((Rect)(ref rect)).x;
rect = sprite.rect;
return Sprite.Create(texture, new Rect(x, ((Rect)(ref rect)).y, (float)((Texture)texture).width, (float)((Texture)texture).height), sprite.pivot);
}
private static Sprite SafeCreateSprite(SpriteRenderer sr, Sprite sprite, Texture2D texture)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
return Sprite.Create(texture, ((Object)(object)sprite != (Object)null) ? sprite.rect : sr.sprite.rect, Vector2.zero);
}
public static void SetAllDirtyEx(this object ui)
{
if (ui == null)
{
return;
}
Type unityType = ui.GetUnityType();
SpriteRenderer val = default(SpriteRenderer);
if (UnityTypes.Graphic != null && UnityTypes.Graphic.IsAssignableFrom(unityType))
{
ReflectionCache.CachedMethod(UnityTypes.Graphic.ClrType, SetAllDirtyMethodName).Invoke(ui);
}
else if (!ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref val))
{
MethodInfo methodInfo = AccessToolsShim.Method(ui.GetType(), MarkAsChangedMethodName, new Type[0]);
if (!(methodInfo == null))
{
methodInfo.Invoke(ui, null);
}
}
}
public static bool ShouldIgnoreTextComponent(this object ui)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Expected O, but got Unknown
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Expected O, but got Unknown
Component val = (Component)((ui is Component) ? ui : null);
if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val))
{
return false;
}
GameObject gameObject = val.gameObject;
Component firstComponentInSelfOrAncestor;
if (UnityTypes.InputField != null)
{
GameObject gameObject2 = val.gameObject;
TypeContainer inputField = UnityTypes.InputField;
firstComponentInSelfOrAncestor = gameObject2.GetFirstComponentInSelfOrAncestor((inputField != null) ? inputField.UnityType : null);
if ((Object)(object)firstComponentInSelfOrAncestor != (Object)null && InputField_Properties.Placeholder != null)
{
Component val2 = (Component)InputField_Properties.Placeholder.Get((object)firstComponentInSelfOrAncestor);
return !UnityObjectReferenceComparer.Default.Equals((object)val2, (object)val);
}
}
if (UnityTypes.TMP_InputField != null)
{
GameObject gameObject3 = val.gameObject;
TypeContainer tMP_InputField = UnityTypes.TMP_InputField;
firstComponentInSelfOrAncestor = gameObject3.GetFirstComponentInSelfOrAncestor((tMP_InputField != null) ? tMP_InputField.UnityType : null);
if ((Object)(object)firstComponentInSelfOrAncestor != (Object)null && TMP_InputField_Properties.Placeholder != null)
{
Component val3 = (Component)TMP_InputField_Properties.Placeholder.Get((object)firstComponentInSelfOrAncestor);
return !UnityObjectReferenceComparer.Default.Equals((object)val3, (object)val);
}
}
GameObject go = gameObject;
TypeContainer uIInput = UnityTypes.UIInput;
firstComponentInSelfOrAncestor = go.GetFirstComponentInSelfOrAncestor((uIInput != null) ? uIInput.UnityType : null);
return (Object)(object)firstComponentInSelfOrAncestor != (Object)null;
}
public static Component GetFirstComponentInSelfOrAncestor(this GameObject go, Type type)
{
if (type == null)
{
return null;
}
GameObject val = go;
while ((Object)(object)val != (Object)null)
{
Component component = val.GetComponent(type);
if ((Object)(object)component != (Object)null)
{
return component;
}
Transform transform = val.transform;
GameObject val2;
if ((Object)(object)transform == (Object)null)
{
val2 = null;
}
else
{
Transform parent = transform.parent;
val2 = (((Object)(object)parent != (Object)null) ? ((Component)parent).gameObject : null);
}
val = val2;
}
return null;
}
public static ImageTranslationInfo GetOrCreateImageTranslationInfo(this object obj, Texture2D originalTexture)
{
if (obj == null)
{
return null;
}
ImageTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<ImageTranslationInfo>(obj);
if (orCreateExtensionData.Original == null)
{
orCreateExtensionData.Initialize(originalTexture);
}
return orCreateExtensionData;
}
public static void Load()
{
TexturePropertyMovers = new List<IPropertyMover>();
LoadProperty<Object, string>("name");
LoadProperty<Texture, int>("anisoLevel");
LoadProperty<Texture, FilterMode>("filterMode");
LoadProperty<Texture, float>("mipMapBias");
LoadProperty<Texture, TextureWrapMode>("wrapMode");
}
private static void LoadProperty<TObject, TPropertyType>(string propertyName)
{
PropertyInfo property = typeof(TObject).GetProperty(propertyName);
if (property != null && property.CanWrite && property.CanRead)
{
TexturePropertyMovers.Add(new PropertyMover<TObject, TPropertyType>(property));
}
}
public static void LoadImageEx(this Texture2D texture, Texture2D originalTexture)
{
if (!((Object)(object)originalTexture != (Object)null))
{
return;
}
foreach (IPropertyMover texturePropertyMover in TexturePropertyMovers)
{
texturePropertyMover.MoveProperty(originalTexture, texture);
}
}
public static TextTranslationInfo GetOrCreateTextTranslationInfo(this object ui)
{
TextTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<TextTranslationInfo>(ui);
orCreateExtensionData.Init(ui);
return orCreateExtensionData;
}
public static void SetText(this object ui, string text, TextTranslationInfo info)
{
if (ui != null)
{
info?.TextManipulator.SetText(ui, text);
}
}
public static string GetText(this object ui, TextTranslationInfo info)
{
if (ui == null)
{
return null;
}
return info?.TextManipulator.GetText(ui);
}
public static void TryRemoveCharacter(this TMP_FontAsset fontAsset, uint unicode)
{
((List<uint>)s_MissingCharacterList.GetValue(fontAsset)).Add(unicode);
((HashSet<uint>)m_MissingUnicodesFromFontFile.GetValue(fontAsset)).Add(unicode);
((HashSet<uint>)m_CharactersToAddLookup.GetValue(fontAsset)).Remove(unicode);
((Dictionary<uint, TMP_Character>)m_CharacterLookupDictionary.GetValue(fontAsset)).Remove(unicode);
((List<TMP_Character>)m_CharacterTable.GetValue(fontAsset)).RemoveAll((TMP_Character character) => ((TMP_TextElement)character).unicode == unicode);
}
public static void TryRemoveCharacters(this TMP_FontAsset fontAsset, uint[] unicodes)
{
for (int i = 0; i < unicodes.Length; i++)
{
fontAsset.TryRemoveCharacter(unicodes[i]);
}
}
}
}
namespace GameTranslator.Patches
{
[HarmonyPatch(typeof(GrabbableObject))]
internal class GrabbableObjectPatcher
{
public static Dictionary<string, string> originToTranslated = new Dictionary<string, string>();
public static HashSet<string> translatedItems = new HashSet<string>();
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void start(ref GrabbableObject __instance)
{
if (!((Object)(object)__instance.itemProperties != (Object)null) || !TranslatePlugin.shouldTranslateItems.Value || Utility.IsNullOrWhiteSpace(__instance.itemProperties.itemName))
{
return;
}
if (!translatedItems.Contains(__instance.itemProperties.itemName))
{
originToTranslated[__instance.itemProperties.itemName] = TranslateConfig.replaceByMap(__instance.itemProperties.itemName, TranslateConfig.items);
translatedItems.Add(originToTranslated[__instance.itemProperties.itemName]);
__instance.itemProperties.itemName = originToTranslated[__instance.itemProperties.itemName];
}
if (originToTranslated.ContainsKey(__instance.itemProperties.itemName))
{
__instance.itemProperties.itemName = originToTranslated[__instance.itemProperties.itemName];
}
ScanNodeProperties componentInChildren = ((Component)__instance).GetComponentInChildren<ScanNodeProperties>();
if ((Object)(object)componentInChildren != (Object)null && componentInChildren.headerText != null)
{
if (!translatedItems.Contains(componentInChildren.headerText))
{
originToTranslated[componentInChildren.headerText] = TranslateConfig.replaceByMap(componentInChildren.headerText, TranslateConfig.items);
translatedItems.Add(originToTranslated[componentInChildren.headerText]);
componentInChildren.headerText = originToTranslated[componentInChildren.headerText];
}
if (originToTranslated.ContainsKey(componentInChildren.headerText))
{
componentInChildren.headerText = originToTranslated[componentInChildren.headerText];
}
}
}
}
[HarmonyPatch(typeof(HUDManager))]
internal class HUDManagerPatcher
{
public static TextMeshProUGUI tipText;
public static bool fadeTipText = false;
public static TextMeshProUGUI notificationText;
public static bool fadeNotificationTextt = false;
public static int tipShowTime = 0;
public static int notificationShowTime = 0;
public static FieldInfo scanNodes = typeof(HUDManager).GetField("scanNodes", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo nodesOnScreen = typeof(HUDManager).GetField("nodesOnScreen", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static Dictionary<string, string> originToTranslated = new Dictionary<string, string>();
public static HashSet<string> translatedItems = new HashSet<string>();
private static string lastChat = "";
private static readonly BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
private static MethodInfo CanTipDisplay = typeof(HUDManager).GetMethod("CanTipDisplay", All);
private static MethodInfo StopCoroutine = typeof(HUDManager).GetMethod("StopCoroutine", All, null, new Type[1] { typeof(IEnumerator) }, null);
private static MethodInfo StartCoroutine = typeof(HUDManager).GetMethod("StartCoroutine", All, null, new Type[1] { typeof(IEnumerator) }, null);
private static MethodInfo TipsPanelTimer = typeof(HUDManager).GetMethod("TipsPanelTimer", All);
private static FieldInfo tipsPanelCoroutine = typeof(HUDManager).GetField("tipsPanelCoroutine", All);
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void start(ref HUDManager __instance)
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)__instance.holdButtonToEndGameEarlyText != (Object)null)
{
((Graphic)__instance.holdButtonToEndGameEarlyText).color = Color.yellow;
}
GameObject val = new GameObject("TipHUDDisplay");
val.AddComponent<RectTransform>();
tipText = val.AddComponent<TextMeshProUGUI>();
RectTransform rectTransform = ((TMP_Text)tipText).rectTransform;
((Transform)rectTransform).SetParent(((Component)__instance.PTTIcon).transform, false);
rectTransform.anchoredPosition = new Vector2(310f, -130f);
((TMP_Text)tipText).fontSize = 9f;
((TMP_Text)tipText).overflowMode = (TextOverflowModes)0;
((Behaviour)tipText).enabled = false;
notificationText = new GameObject("NotificationHUDDisplay").AddComponent<TextMeshProUGUI>();
RectTransform component = ((Component)notificationText).gameObject.GetComponent<RectTransform>();
((Transform)component).SetParent(((Component)__instance.PTTIcon).transform, false);
component.anchoredPosition = new Vector2(153f, -200f);
((TMP_Text)notificationText).fontStyle = (FontStyles)1;
((TMP_Text)notificationText).fontSize = 10f;
((TMP_Text)notificationText).alignment = (TextAlignmentOptions)514;
((TMP_Text)notificationText).overflowMode = (TextOverflowModes)0;
((Behaviour)notificationText).enabled = false;
}
[HarmonyPostfix]
[HarmonyPatch("Update")]
private static void update(HUDManager __instance)
{
if (TranslatePlugin.shouldTranslateHUD.Value && lastChat.Length != ((TMP_Text)__instance.chatText).text.Length)
{
((TMP_Text)__instance.chatText).text = TranslateConfig.hudText.TryTranslateByStrong(((TMP_Text)__instance.chatText).text);
}
lastChat = ((TMP_Text)__instance.chatText).text;
if (tipShowTime > 0)
{
tipShowTime--;
}
else if (((Behaviour)tipText).enabled && !fadeTipText)
{
fadeText(tipText, ref fadeTipText, 200f, 0f);
}
if (notificationShowTime > 0)
{
notificationShowTime--;
}
else if (((Behaviour)notificationText).enabled && !fadeNotificationTextt)
{
fadeText(notificationText, ref fadeNotificationTextt, 200f, 0f);
}
}
private static void fadeText(TextMeshProUGUI text, ref bool fade, float duration, float newAlpha)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
float a = ((Graphic)text).color.a;
float num = 0f;
fade = true;
while (num < duration)
{
num += Time.deltaTime;
float num2 = Mathf.Lerp(a, newAlpha, num / duration);
((Graphic)text).color = new Color(((Graphic)text).color.r, ((Graphic)text).color.g, ((Graphic)text).color.b, num2);
}
((Behaviour)text).enabled = false;
fade = false;
}
public static void addNotification(string text, int time)
{
((TMP_Text)notificationText).text = text;
((Behaviour)notificationText).enabled = true;
((TMP_Text)notificationText).alpha = 100f;
notificationShowTime = time;
}
public static void addTip(string text, int time, bool isWarning)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
((Graphic)tipText).color = (isWarning ? Color.red : Color.yellow);
((TMP_Text)tipText).text = text;
((Behaviour)tipText).enabled = true;
((TMP_Text)tipText).alpha = 100f;
tipShowTime = time;
}
[HarmonyPatch("DisplayGlobalNotification")]
[HarmonyPriority(int.MaxValue)]
[HarmonyPrefix]
private static void changeNotification(HUDManager __instance, ref string displayText)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (TranslatePlugin.shouldTranslateHUD.Value)
{
displayText = TranslateConfig.hudText.TryTranslateByStrong(displayText);
}
if (!TranslatePlugin.shouldFixTipErrors.Value)
{
((Graphic)__instance.globalNotificationText).color = Color.white;
return;
}
addNotification(displayText, 300);
((Behaviour)__instance.globalNotificationAnimator).enabled = false;
((TMP_Text)__instance.globalNotificationText).text = "";
}
[HarmonyPostfix]
[HarmonyPatch("AddChatMessage")]
private static void changeChatMessage(HUDManager __instance, string chatMessage, string nameOfUserWhoTyped)
{
if (TranslatePlugin.shouldTranslateHUD.Value)
{
((TMP_Text)__instance.chatText).text = TranslateConfig.hudText.TryTranslateByStrong(((TMP_Text)__instance.chatText).text);
}
}
[HarmonyPriority(int.MaxValue)]
[HarmonyPrefix]
[HarmonyPatch("DisplayTip")]
private static bool changeTip(HUDManager __instance, ref string headerText, ref string bodyText, bool isWarning = false, bool useSave = false, string prefsKey = "LC_Tip1")
{
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
if ((headerText.ToLower().Contains("mod list") || bodyText.ToLower().Contains("mod list")) && TranslatePlugin.shouldHideModList.Value)
{
return false;
}
if (TranslatePlugin.shouldTranslateHUD.Value)
{
headerText = TranslateConfig.hudText.TryTranslateByStrong(headerText);
bodyText = TranslateConfig.hudText.TryTranslateByStrong(bodyText);
}
if (TranslatePlugin.shouldFixTipErrors.Value)
{
return addTip(__instance, headerText, bodyText, isWarning, useSave, prefsKey);
}
((Graphic)__instance.tipsPanelHeader).color = Color.white;
((Graphic)__instance.tipsPanelBody).color = Color.white;
return true;
}
private static bool addTip(HUDManager __instance, string headerText, string bodyText, bool isWarning = false, bool useSave = false, string prefsKey = "LC_Tip1")
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Invalid comparison between Unknown and O
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Expected O, but got Unknown
string text = headerText + "\n" + bodyText;
try
{
if (!(bool)CanTipDisplay.Invoke(__instance, new object[3] { isWarning, useSave, prefsKey }))
{
return false;
}
if (useSave)
{
if ((object)(Coroutine)tipsPanelCoroutine.GetValue(__instance) != null)
{
StopCoroutine.Invoke(__instance, new object[1] { tipsPanelCoroutine });
}
tipsPanelCoroutine.SetValue(__instance, (object?)(Coroutine)StartCoroutine.Invoke(__instance, new object[1] { (IEnumerator)TipsPanelTimer.Invoke(__instance, new object[1] { prefsKey }) }));
}
((Behaviour)__instance.tipsPanelAnimator).enabled = false;
addTip(text, 320, isWarning);
}
catch (Exception ex)
{
TranslatePlugin.logger.LogError((object)ex);
}
return false;
}
}
[HarmonyPatch(typeof(Terminal))]
internal class TerminalPatch
{
public class Translator
{
public Dictionary<string, TerminalKeyword> keyValuePairs = new Dictionary<string, TerminalKeyword>();
public Dictionary<string, string> keys = new Dictionary<string, string>();
public TerminalKeyword getTranslateKey(TerminalKeyword old, bool useC)
{
if (!keyValuePairs.ContainsKey(((Object)old).name + old.word))
{
if ((useC && !HaveChineseCMD(old.word)) || (!useC && !HavePinyinCMD(old.word)))
{
keyValuePairs.Add(((Object)old).name + old.word, old);
return old;
}
string text = (useC ? getChineseCMD(old.word) : getPinyinCMD(old.word));
if (text == old.word)
{
keyValuePairs.Add(((Object)old).name + old.word, old);
return old;
}
TerminalKeyword val = Copy(old);
val.word = text;
keyValuePairs.Add(((Object)old).name + old.word, val);
if (val.compatibleNouns != null)
{
List<CompatibleNoun> list = val.compatibleNouns.ToList();
CompatibleNoun[] compatibleNouns = val.compatibleNouns;
foreach (CompatibleNoun val2 in compatibleNouns)
{
if (!getTranslateKey(val2.noun, useC).word.Equals(val2.noun.word))
{
CompatibleNoun val3 = TransReflection<CompatibleNoun>(val2);
val3.noun = getTranslateKey(val2.noun, useC);
list.Add(val3);
}
}
val.compatibleNouns = list.ToArray();
}
if ((Object)(object)val.defaultVerb != (Object)null && val.defaultVerb.compatibleNouns != null)
{
List<CompatibleNoun> list2 = val.defaultVerb.compatibleNouns.ToList();
CompatibleNoun[] compatibleNouns2 = val.defaultVerb.compatibleNouns;
foreach (CompatibleNoun val4 in compatibleNouns2)
{
if (!getTranslateKey(val4.noun, useC).word.Equals(val4.noun.word))
{
CompatibleNoun val5 = TransReflection<CompatibleNoun>(val4);
val5.noun = getTranslateKey(val4.noun, useC);
list2.Add(val5);
}
}
val.defaultVerb.compatibleNouns = list2.ToArray();
}
return val;
}
return keyValuePairs[((Object)old).name + old.word];
}
public void getTranslateKey(TerminalKeyword old)
{
if (keys.ContainsKey(old.word))
{
return;
}
keys.Add(old.word, old.word);
if (old.compatibleNouns != null)
{
List<CompatibleNoun> list = old.compatibleNouns.ToList();
CompatibleNoun[] compatibleNouns = old.compatibleNouns;
foreach (CompatibleNoun val in compatibleNouns)
{
getTranslateKey(val.noun);
}
}
if ((Object)(object)old.defaultVerb != (Object)null && old.defaultVerb.compatibleNouns != null)
{
List<CompatibleNoun> list2 = old.defaultVerb.compatibleNouns.ToList();
CompatibleNoun[] compatibleNouns2 = old.defaultVerb.compatibleNouns;
foreach (CompatibleNoun val2 in compatibleNouns2)
{
getTranslateKey(val2.noun);
}
}
}
}
public static FieldInfo hasGottenVerb = typeof(Terminal).GetField("hasGottenVerb", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static FieldInfo hasGottenNoun = typeof(Terminal).GetField("hasGottenNoun", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static bool shouldTranslate = false;
public static bool noText = false;
public static int texdAdded = 0;
public static FieldInfo modifyingText = typeof(Terminal).GetField("modifyingText", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
public static Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
public static TMP_InputField screenText = null;
public static TextTranslationInfo info;
public static List<object> ig = new List<object>();
private static int CheckForPlayerNameCommand(string firstWord, string secondWord)
{
if (firstWord == "radar")
{
return -1;
}
if (secondWord.Length <= 2)
{
return -1;
}
Debug.Log((object)("first word: " + firstWord + "; second word: " + secondWord));
List<string> list = new List<string>();
for (int i = 0; i < StartOfRound.Instance.mapScreen.radarTargets.Count; i++)
{
list.Add(StartOfRound.Instance.mapScreen.radarTargets[i].name);
Debug.Log((object)$"name {i}: {list[i]}");
}
secondWord = secondWord.ToLower();
for (int j = 0; j < list.Count; j++)
{
string text = list[j].ToLower();
if (text == secondWord)
{
return j;
}
}
Debug.Log((object)$"Target names length: {list.Count}");
for (int k = 0; k < list.Count; k++)
{
Debug.Log((object)"A");
string text2 = list[k].ToLower();
Debug.Log((object)$"Word #{k}: {text2}; length: {text2.Length}");
for (int num = secondWord.Length; num > 2; num--)
{
Debug.Log((object)$"c: {num}");
Debug.Log((object)secondWord.Substring(0, num));
if (text2.StartsWith(secondWord.Substring(0, num)))
{
return k;
}
}
}
return -1;
}
[HarmonyPostfix]
[HarmonyPatch("ParseWordOverrideOptions")]
private static void ParseWordOverrideOptions(string playerWord, CompatibleNoun[] options, ref TerminalNode __result)
{
for (int i = 0; i < options.Length; i++)
{
for (int num = playerWord.Length; num > 0; num--)
{
if (getChineseCMD(options[i].noun.word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
{
__result = options[i].result;
return;
}
if (getPinyinCMD(options[i].noun.word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
{
__result = options[i].result;
return;
}
}
}
}
[HarmonyPatch("CheckForExactSentences")]
[HarmonyPostfix]
private static void CheckForExactSentences(Terminal __instance, string playerWord, ref TerminalKeyword __result)
{
for (int i = 0; i < __instance.terminalNodes.allKeywords.Length; i++)
{
if (getChineseCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
{
__result = __instance.terminalNodes.allKeywords[i];
break;
}
if (getPinyinCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
{
__result = __instance.terminalNodes.allKeywords[i];
break;
}
}
}
private static string RemovePunctuation(string s)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (char c in s)
{
if (!char.IsPunctuation(c))
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().ToLower();
}
[HarmonyPostfix]
[HarmonyPatch("CallFunctionInAccessibleTerminalObject")]
private static void CallFunctionInAccessibleTerminalObject(Terminal __instance, string word)
{
TerminalAccessibleObject[] array = Object.FindObjectsOfType<TerminalAccessibleObject>();
for (int i = 0; i < array.Length; i++)
{
if (getChineseCMD(array[i].objectCode).EqualsIgnoreCase(word) || getPinyinCMD(array[i].objectCode).EqualsIgnoreCase(word))
{
Debug.Log((object)"Found accessible terminal object with corresponding string, calling function");
((object)__instance).GetType().GetField("broadcastedCodeThisFrame", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(TranslateConfig.terminal, true);
array[i].CallFunctionFromTerminal();
break;
}
}
}
[HarmonyPatch("ParseWord")]
[HarmonyPostfix]
private static void ParseWord(Terminal __instance, string playerWord, int specificityRequired, ref TerminalKeyword __result)
{
if (!TranslatePlugin.TerimalCanUseChinese.Value && !TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value)
{
return;
}
if (playerWord.Length < specificityRequired)
{
__result = null;
return;
}
TerminalKeyword val = null;
for (int i = 0; i < __instance.terminalNodes.allKeywords.Length; i++)
{
if (__instance.terminalNodes.allKeywords[i].isVerb && (bool)hasGottenVerb.GetValue(__instance))
{
continue;
}
_ = __instance.terminalNodes.allKeywords[i].accessTerminalObjects;
if (getChineseCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
{
__result = __instance.terminalNodes.allKeywords[i];
return;
}
if (getPinyinCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
{
__result = __instance.terminalNodes.allKeywords[i];
return;
}
if (!((Object)(object)val == (Object)null))
{
continue;
}
for (int num = playerWord.Length; num > specificityRequired; num--)
{
if (getChineseCMD(__instance.terminalNodes.allKeywords[i].word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
{
val = __instance.terminalNodes.allKeywords[i];
}
if (getPinyinCMD(__instance.terminalNodes.allKeywords[i].word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
{
val = __instance.terminalNodes.allKeywords[i];
}
}
}
if ((Object)(object)val != (Object)null)
{
__result = val;
}
}
[HarmonyPatch("ParsePlayerSentence")]
[HarmonyPostfix]
private static void customParser(Terminal __instance, ref TerminalNode __result)
{
string s = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded);
s = RemovePunctuation(s);
string[] array = s.Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries);
if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("transmit") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["transmit"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("transmit") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["transmit"]))))
{
try
{
string text = array[1];
SignalTranslator val = Object.FindObjectOfType<SignalTranslator>();
if ((Object)(object)val != (Object)null && Time.realtimeSinceStartup - val.timeLastUsingSignalTranslator > 8f && text.Length > 1)
{
if (!((NetworkBehaviour)__instance).IsServer)
{
val.timeLastUsingSignalTranslator = Time.realtimeSinceStartup;
}
__result = __instance.terminalNodes.specialNodes[22];
HUDManager.Instance.UseSignalTranslatorServerRpc(text.Substring(0, Mathf.Min(text.Length, 10)));
}
return;
}
catch (Exception ex)
{
TranslateConfig.Log(ex.Message);
return;
}
}
if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("switch") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["switch"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("switch") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["switch"]))))
{
int num = CheckForPlayerNameCommand(array[0], array[1]);
if (num != -1)
{
StartOfRound.Instance.mapScreen.SwitchRadarTargetAndSync(num);
__result = __instance.terminalNodes.specialNodes[20];
}
}
else if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("ping") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["ping"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("ping") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["ping"]))))
{
int num2 = CheckForPlayerNameCommand(array[0], array[1]);
if (num2 != -1)
{
StartOfRound.Instance.mapScreen.PingRadarBooster(num2);
__result = __instance.terminalNodes.specialNodes[21];
}
}
else if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("flash") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["flash"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("flash") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["flash"]))))
{
int num3 = CheckForPlayerNameCommand(array[0], array[1]);
if (num3 != -1)
{
StartOfRound.Instance.mapScreen.FlashRadarBooster(num3);
__result = __instance.terminalNodes.specialNodes[23];
}
else if (StartOfRound.Instance.mapScreen.radarTargets[StartOfRound.Instance.mapScreen.targetTransformIndex].isNonPlayer)
{
StartOfRound.Instance.mapScreen.FlashRadarBooster(StartOfRound.Instance.mapScreen.targetTransformIndex);
__result = __instance.terminalNodes.specialNodes[23];
}
}
}
private static bool HaveChineseCMD(string name)
{
return TranslateConfig.cmd_zh.normal.ContainsKey(name);
}
private static bool HavePinyinCMD(string name)
{
return TranslateConfig.cmd_py.normal.ContainsKey(name);
}
private static string getChineseCMD(string name)
{
if (TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey(name))
{
return TranslateConfig.cmd_zh.normal[name];
}
return "";
}
private static string getPinyinCMD(string name)
{
if (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey(name))
{
return TranslateConfig.cmd_py.normal[name];
}
return "";
}
private static string getOrginByChineseCMD(string name)
{
if (TranslateConfig.cmd_zh.special.ContainsKey(name))
{
return TranslateConfig.cmd_zh.special[name];
}
return name;
}
private static string getOrginByPinyinCMD(string name)
{
if (TranslateConfig.cmd_py.special.ContainsKey(name))
{
return TranslateConfig.cmd_py.special[name];
}
return name;
}
private static T TransReflection<T>(T tIn)
{
T val = Activator.CreateInstance<T>();
foreach (FieldInfo runtimeField in tIn.GetType().GetRuntimeFields())
{
val.GetType().GetRuntimeField(runtimeField.Name).SetValue(val, runtimeField.GetValue(tIn));
}
return val;
}
public static TerminalKeyword Copy(TerminalKeyword oldOne)
{
return TransReflection<TerminalKeyword>(oldOne);
}
[HarmonyPatch("LoadNewNode")]
[HarmonyPostfix]
private static void changeNewNodeText(Terminal __instance, TerminalNode node)
{
if (info != null)
{
info.Reset(__instance.screenText.text);
}
}
[HarmonyPrefix]
[HarmonyPatch("OnSubmit")]
private static void changeSubmit(Terminal __instance)
{
if (info != null)
{
texdAdded = __instance.currentText.Length - info.OriginalText.Length;
if (texdAdded != 0)
{
info.Reset(__instance.currentText);
}
}
}
[HarmonyPatch("Update")]
[HarmonyPostfix]
private static void changeUpdateText(Terminal __instance)
{
try
{
if ((info == null || !info.IsTranslated) && info != null && !info.IsTranslated && TranslatePlugin.shouldTranslateTerimal.Value)
{
string translatedText = TranslateConfig.replaceByMap(__instance.currentText, TranslateConfig.terminal);
info.SetTranslatedText(translatedText);
SetText(info.TranslatedText, __instance);
info.OriginalText = __instance.currentText;
}
}
catch (Exception ex)
{
TranslatePlugin.logger.LogWarning((object)ex);
}
}
public static void SetText(string text, Terminal Instance)
{
if (!((Object)(object)Instance == (Object)null))
{
modifyingText.SetValue(Instance, true);
((Selectable)Instance.screenText).interactable = true;
Instance.screenText.text = text;
Instance.currentText = Instance.screenText.text;
if ((Object)(object)Instance.screenText.verticalScrollbar != (Object)null)
{
Instance.screenText.verticalScrollbar.value = 0f;
}
}
}
[HarmonyPostfix]
[HarmonyPatch("Start")]
private static void startTerminal(Terminal __instance)
{
info = __instance.screenText.GetOrCreateTextTranslationInfo();
ig.Clear();
foreach (FieldInfo runtimeField in ((object)__instance).GetType().GetRuntimeFields())
{
if (runtimeField.GetValue(__instance) != null && UnityTypes.TMP_Text.IsAssignableFrom(runtimeField.GetValue(__instance).GetType()))
{
ig.Add(runtimeField.GetValue(__instance));
}
}
info.MustIgnore = true;
}
}
}
namespace GameTranslator.Patches.Translatons
{
internal class TextTranslationInfo
{
private Action<object> _unfont;
private bool _initialized = false;
private HashSet<string> _redirectedTranslations;
public long changeTime = 0L;
public static TMP_FontAsset origin;
public ITextComponentManipulator TextManipulator { get; set; }
public string OriginalText { get; set; }
public string TranslatedText { get; set; }
public bool IsTranslated { get; set; }
public bool IsCurrentlySettingText { get; set; }
public bool IsStabilizingText { get; set; }
public bool IsKnownTextComponent { get; set; }
public bool SupportsStabilization { get; set; }
public bool ShouldIgnore { get; set; }
public bool MustIgnore { get; set; }
public long ChangeTime
{
get
{
return changeTime;
}
set
{
changeTime = value;
}
}
public HashSet<string> RedirectedTranslations => _redirectedTranslations ?? (_redirectedTranslations = new HashSet<string>());
public void Init(object ui)
{
i