Decompiled source of HoldToCommand v0.2.0

BepInEx\plugins\Vonny1412.HoldToCommand\HoldToCommand.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using HoldToCommand.ValheimAPI;
using HoldToCommand.ValheimAPI.LowLevel;
using HoldToCommand.ValheimAPI.LowLevel.Core;
using HoldToCommand.ValheimAPI.LowLevel.Core.Invokers;
using HoldToCommand.ValheimAPI.LowLevel.Core.Signatures;
using HoldToCommand.ValheimAPI.LowLevel.UnityEngine;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Yvonne Pautz")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © Yvonne Pautz 2026")]
[assembly: AssemblyFileVersion("0.0.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+build.202602150113.98b2dd55ddde1cffdba93f64c4ae8fc97c4b57f4")]
[assembly: AssemblyProduct("HoldToCommand")]
[assembly: AssemblyTitle("HoldToCommand")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace HoldToCommand
{
	[BepInPlugin("Vonny1412.HoldToCommand", "HoldToCommand", "0.2.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string LangFileName = "HoldToCommand.Translations.txt";

		internal static readonly Dictionary<string, (string holdTpl, string commandVerb)> TranslationsByLanguage = new Dictionary<string, (string, string)>(StringComparer.OrdinalIgnoreCase);

		public const string Version = "0.2.0";

		public const string ModName = "HoldToCommand";

		public const string ModGuid = "Vonny1412.HoldToCommand";

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
			LoadTranslationsFile();
		}

		private static void LoadTranslationsFile()
		{
			try
			{
				string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "HoldToCommand.Translations.txt");
				if (!File.Exists(text))
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)("Translations file not found: " + text + " (will use English fallback)"));
					}
					return;
				}
				string[] array = File.ReadAllLines(text);
				foreach (string text2 in array)
				{
					string text3 = text2.Trim();
					if (text3.Length == 0 || text3.StartsWith("#"))
					{
						continue;
					}
					string[] array2 = text3.Split(new char[1] { '|' });
					if (array2.Length < 3)
					{
						ManualLogSource log2 = Log;
						if (log2 != null)
						{
							log2.LogWarning((object)("Invalid translations line (expected 3 columns): " + text2));
						}
						continue;
					}
					string text4 = array2[0].Trim();
					string text5 = array2[1].Trim();
					string text6 = array2[2].Trim();
					if (text4.Length == 0)
					{
						continue;
					}
					if (text5.Length == 0 || text6.Length == 0)
					{
						ManualLogSource log3 = Log;
						if (log3 != null)
						{
							log3.LogWarning((object)("Empty values in translations line: " + text2));
						}
					}
					else
					{
						TranslationsByLanguage[text4] = (text5, text6);
					}
				}
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogInfo((object)$"Loaded {TranslationsByLanguage.Count} translation entries from HoldToCommand.Translations.txt");
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log5 = Log;
				if (log5 != null)
				{
					log5.LogError((object)$"Failed to load translations file: {arg}");
				}
			}
		}
	}
}
namespace HoldToCommand.ValheimAPI
{
	internal static class LocalizationExtensions
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void AddWord(this Localization local, string key, string text)
		{
			Localization.__IAPI_AddWord_Invoker1.Invoke(local, key, text);
		}
	}
	internal static class TameableExtensions
	{
		private const float HoldThreshold = 0.45f;

		private static Tameable lastTarget;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void SetName(this Tameable tameable)
		{
			Tameable.__IAPI_SetName_Invoker1.Invoke(tameable);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float GetLastPetTime(this Tameable tameable)
		{
			return Tameable.__IAPI_m_lastPetTime_Invoker.Get(tameable);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void SetLastPetTime(this Tameable tameable, float t)
		{
			Tameable.__IAPI_m_lastPetTime_Invoker.Set(tameable, t);
		}

		public static bool CustomInteract(this Tameable tameable, Humanoid user, bool hold, bool alt)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = ((Component)tameable).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return false;
			}
			if (alt)
			{
				tameable.SetName();
				return true;
			}
			if (!tameable.IsTamed())
			{
				return false;
			}
			float time = Time.time;
			float lastPetTime = tameable.GetLastPetTime();
			if (hold)
			{
				if (!tameable.m_commandable)
				{
					return false;
				}
				if (time - lastPetTime < 0.45f)
				{
					return false;
				}
				if ((Object)(object)lastTarget == (Object)(object)tameable)
				{
					return false;
				}
				lastTarget = tameable;
				tameable.Command(user, true);
				return true;
			}
			lastTarget = null;
			if (time - lastPetTime <= 1f)
			{
				return false;
			}
			tameable.SetLastPetTime(time);
			EffectList petEffect = tameable.m_petEffect;
			if (petEffect != null)
			{
				petEffect.Create(((Component)tameable).transform.position, ((Component)tameable).transform.rotation, (Transform)null, 1f, -1);
			}
			string text = null;
			if (tameable.m_tameTextGetter != null)
			{
				string text2 = tameable.m_tameTextGetter.Invoke();
				if (!string.IsNullOrEmpty(text2))
				{
					text = text2;
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				string hoverName = tameable.GetHoverName();
				string text3 = tameable.m_tameText ?? "";
				text = (tameable.m_nameBeforeText ? (hoverName + " " + text3) : text3);
			}
			if (!string.IsNullOrEmpty(text))
			{
				((Character)user).Message((MessageType)2, text, 0, (Sprite)null);
			}
			return true;
		}
	}
}
namespace HoldToCommand.ValheimAPI.LowLevel
{
	public class AnimalAI : BaseAI
	{
		public AnimalAI(AnimalAI instance)
			: base((BaseAI)(object)instance)
		{
		}
	}
	public class BaseAI : MonoBehaviour
	{
		public BaseAI(BaseAI instance)
			: base((MonoBehaviour)(object)instance)
		{
		}
	}
	public class Localization : ClassPublicizer
	{
		public static readonly VoidMethodInvoker __IAPI_AddWord_Invoker1 = new VoidMethodInvoker(typeof(Localization), "AddWord", new ParamSig[2]
		{
			new NonGenericParamSig(typeof(string), IsByRef: false),
			new NonGenericParamSig(typeof(string), IsByRef: false)
		});

		public Localization(Localization instance)
			: base(instance)
		{
		}
	}
	public class MonsterAI : BaseAI
	{
		public MonsterAI(MonsterAI instance)
			: base((BaseAI)(object)instance)
		{
		}
	}
	public class Tameable : MonoBehaviour
	{
		public static readonly FieldMutateInvoker<float> __IAPI_m_lastPetTime_Invoker = new FieldMutateInvoker<float>(typeof(Tameable), "m_lastPetTime");

		public static readonly VoidMethodInvoker __IAPI_SetName_Invoker1 = new VoidMethodInvoker(typeof(Tameable), "SetName", new ParamSig[0]);

		public Tameable(Tameable instance)
			: base((MonoBehaviour)(object)instance)
		{
		}
	}
}
namespace HoldToCommand.ValheimAPI.LowLevel.UnityEngine
{
	public class Behaviour : Component
	{
		public Behaviour(Behaviour instance)
			: base((Component)(object)instance)
		{
		}
	}
	public class Component : Object
	{
		public Component(Component instance)
			: base((Object)(object)instance)
		{
		}
	}
	public class MonoBehaviour : Behaviour
	{
		public MonoBehaviour(MonoBehaviour instance)
			: base((Behaviour)(object)instance)
		{
		}
	}
	public class Object : ClassPublicizer
	{
		public Object(Object instance)
			: base(instance)
		{
		}
	}
}
namespace HoldToCommand.ValheimAPI.LowLevel.Core
{
	public abstract class ClassPublicizer
	{
		protected object __IAPI_instance;

		public ClassPublicizer(object instance)
		{
			__IAPI_instance = instance;
		}

		public ClassPublicizer()
		{
			__IAPI_instance = null;
		}

		public static Type __IAPI_GetInstanceType()
		{
			return typeof(void);
		}

		public object __IAPI_GetInstance()
		{
			return __IAPI_instance;
		}

		public void __IAPI_SetInstance(object instance)
		{
			__IAPI_instance = instance;
		}
	}
}
namespace HoldToCommand.ValheimAPI.LowLevel.Core.Signatures
{
	public abstract class CommonParamSig : ParamSig
	{
		public override bool Matches(ParameterInfo p)
		{
			if (p.IsOut != IsByRef && p.ParameterType.IsByRef != IsByRef)
			{
				return false;
			}
			Type type = p.ParameterType;
			if (type.IsByRef)
			{
				type = type.GetElementType();
			}
			if (IsGeneric)
			{
				if (!type.IsGenericParameter || type.GenericParameterPosition != GenericIndex)
				{
					return false;
				}
			}
			else if (type != ConcreteType)
			{
				return false;
			}
			return true;
		}
	}
	public class GenericContainerParamSig : ParamSig
	{
		private readonly Type _genericDef;

		public GenericContainerParamSig(Type genericDef, bool isByRef)
		{
			_genericDef = genericDef;
			IsByRef = isByRef;
		}

		public override bool Matches(ParameterInfo p)
		{
			Type parameterType = p.ParameterType;
			if (parameterType.IsByRef != IsByRef)
			{
				return false;
			}
			if (!parameterType.IsGenericType)
			{
				return false;
			}
			if (parameterType.GetGenericTypeDefinition() != _genericDef)
			{
				return false;
			}
			return parameterType.GetGenericArguments().All((Type a) => a.IsGenericParameter);
		}
	}
	public class GenericParamSig : CommonParamSig
	{
		public GenericParamSig(int GenericIndex, bool IsByRef)
		{
			IsGeneric = true;
			base.GenericIndex = GenericIndex;
			ConcreteType = null;
			base.IsByRef = IsByRef;
		}
	}
	public class NonGenericParamSig : CommonParamSig
	{
		public NonGenericParamSig(Type ConcreteType, bool IsByRef)
		{
			IsGeneric = false;
			GenericIndex = -1;
			base.ConcreteType = ConcreteType;
			base.IsByRef = IsByRef;
		}
	}
	public abstract class ParamSig
	{
		public bool IsGeneric;

		public int GenericIndex;

		public Type ConcreteType;

		public bool IsByRef;

		public abstract bool Matches(ParameterInfo p);
	}
}
namespace HoldToCommand.ValheimAPI.LowLevel.Core.Invokers
{
	public class ConstFieldInvoker<R>
	{
		protected readonly FieldInfo member;

		protected readonly Func<object, R> _getter;

		public ConstFieldInvoker(Type type, string name)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			member = type.GetField(name, bindingAttr);
			if (member == null)
			{
				throw new MissingFieldException(type.FullName, name);
			}
			_ = member.IsLiteral;
			object rawConstantValue = member.GetRawConstantValue();
			R casted = (R)rawConstantValue;
			_getter = (object _) => casted;
		}

		public R Get(object instance)
		{
			return _getter(instance);
		}
	}
	public class FieldAccessInvoker<R>
	{
		protected readonly FieldInfo member;

		protected readonly Func<object, R> _getter;

		public FieldAccessInvoker(Type type, string name)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			member = type.GetField(name, bindingAttr);
			if (member == null)
			{
				throw new MissingFieldException(type.FullName, name);
			}
			_ = member.IsLiteral;
			_getter = CreateGetter(member);
		}

		public R Get(object instance)
		{
			return _getter(instance);
		}

		protected static Func<object, R> CreateGetter(FieldInfo field)
		{
			DynamicMethod dynamicMethod = new DynamicMethod(field.Name + "_Getter", typeof(R), new Type[1] { typeof(object) }, field.DeclaringType, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!field.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, field.DeclaringType);
			}
			iLGenerator.Emit(field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, field);
			if (field.FieldType.IsValueType && typeof(R) == typeof(object))
			{
				iLGenerator.Emit(OpCodes.Box, field.FieldType);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (Func<object, R>)dynamicMethod.CreateDelegate(typeof(Func<object, R>));
		}
	}
	public class FieldMutateInvoker<R> : FieldAccessInvoker<R>
	{
		protected readonly Action<object, R> _setter;

		public FieldMutateInvoker(Type type, string name)
			: base(type, name)
		{
			_setter = CreateSetter(member);
		}

		public void Set(object instance, R value)
		{
			_setter(instance, value);
		}

		protected static Action<object, R> CreateSetter(FieldInfo field)
		{
			DynamicMethod dynamicMethod = new DynamicMethod(field.Name + "_Setter", typeof(void), new Type[2]
			{
				typeof(object),
				typeof(R)
			}, field.DeclaringType, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!field.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, field.DeclaringType);
			}
			iLGenerator.Emit(OpCodes.Ldarg_1);
			if (field.FieldType.IsValueType && typeof(R) == typeof(object))
			{
				iLGenerator.Emit(OpCodes.Unbox_Any, field.FieldType);
			}
			iLGenerator.Emit(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field);
			iLGenerator.Emit(OpCodes.Ret);
			return (Action<object, R>)dynamicMethod.CreateDelegate(typeof(Action<object, R>));
		}
	}
	public abstract class GenericMethodInvoker : MethodInvoker
	{
		public static MethodInfo FindGenericMethod(Type type, string name, int genericCount, ParamSig[] signature)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != name || !methodInfo.IsGenericMethodDefinition || methodInfo.GetGenericArguments().Length != genericCount)
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length != signature.Length)
				{
					continue;
				}
				bool flag = true;
				for (int j = 0; j < parameters.Length; j++)
				{
					ParameterInfo p = parameters[j];
					if (!signature[j].Matches(p))
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					return methodInfo;
				}
			}
			throw new MissingMethodException(type.FullName, name);
		}
	}
	public abstract class MethodInvoker
	{
		protected delegate object MethodInvokerDelegate(object instance, object[] args);

		protected static MethodInvokerDelegate CreateInvokerDelegate(MethodInfo method)
		{
			ParameterInfo[] parameters = method.GetParameters();
			DynamicMethod dynamicMethod = new DynamicMethod(method.Name + "_Invoker", typeof(object), new Type[2]
			{
				typeof(object),
				typeof(object[])
			}, restrictedSkipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!method.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, method.DeclaringType);
			}
			for (int i = 0; i < parameters.Length; i++)
			{
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Ldc_I4, i);
				iLGenerator.Emit(OpCodes.Ldelem_Ref);
				Type parameterType = parameters[i].ParameterType;
				if (parameterType.IsByRef)
				{
					Type elementType = parameterType.GetElementType();
					iLGenerator.Emit(OpCodes.Unbox, elementType);
				}
				else
				{
					iLGenerator.Emit(OpCodes.Unbox_Any, parameterType);
				}
			}
			iLGenerator.Emit(method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, method);
			if (method.ReturnType == typeof(void))
			{
				iLGenerator.Emit(OpCodes.Ldnull);
			}
			else
			{
				iLGenerator.Emit(OpCodes.Box, method.ReturnType);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (MethodInvokerDelegate)dynamicMethod.CreateDelegate(typeof(MethodInvokerDelegate));
		}
	}
	public class PropertyInvoker<R>
	{
		protected readonly PropertyInfo member;

		private readonly Func<object, R> _getter;

		private readonly Action<object, R> _setter;

		public PropertyInvoker(Type type, string name)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			member = type.GetProperty(name, bindingAttr);
			if (member == null)
			{
				throw new MissingFieldException(type.FullName, name);
			}
			if (member.CanRead)
			{
				_getter = CreateGetter(member);
			}
			if (member.CanWrite)
			{
				_setter = CreateSetter(member);
			}
		}

		public R Get(object instance)
		{
			if (_getter == null)
			{
				throw new InvalidOperationException("Property has no getter");
			}
			return _getter(instance);
		}

		public void Set(object instance, R value)
		{
			if (_setter == null)
			{
				throw new InvalidOperationException("Property has no setter");
			}
			_setter(instance, value);
		}

		private static Func<object, R> CreateGetter(PropertyInfo prop)
		{
			MethodInfo getMethod = prop.GetGetMethod(nonPublic: true);
			if (getMethod == null)
			{
				return null;
			}
			DynamicMethod dynamicMethod = new DynamicMethod(prop.Name + "_Getter", typeof(R), new Type[1] { typeof(object) }, prop.DeclaringType, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!getMethod.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, prop.DeclaringType);
			}
			iLGenerator.Emit(getMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, getMethod);
			if (prop.PropertyType.IsValueType && typeof(R) == typeof(object))
			{
				iLGenerator.Emit(OpCodes.Box, prop.PropertyType);
			}
			iLGenerator.Emit(OpCodes.Ret);
			return (Func<object, R>)dynamicMethod.CreateDelegate(typeof(Func<object, R>));
		}

		private static Action<object, R> CreateSetter(PropertyInfo prop)
		{
			MethodInfo setMethod = prop.GetSetMethod(nonPublic: true);
			if (setMethod == null)
			{
				return null;
			}
			DynamicMethod dynamicMethod = new DynamicMethod(prop.Name + "_Setter", typeof(void), new Type[2]
			{
				typeof(object),
				typeof(R)
			}, prop.DeclaringType, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			if (!setMethod.IsStatic)
			{
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Castclass, prop.DeclaringType);
			}
			iLGenerator.Emit(OpCodes.Ldarg_1);
			if (prop.PropertyType.IsValueType && typeof(R) == typeof(object))
			{
				iLGenerator.Emit(OpCodes.Unbox_Any, prop.PropertyType);
			}
			iLGenerator.Emit(setMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt, setMethod);
			iLGenerator.Emit(OpCodes.Ret);
			return (Action<object, R>)dynamicMethod.CreateDelegate(typeof(Action<object, R>));
		}
	}
	public class TypedMethodInvoker<R> : MethodInvoker
	{
		protected readonly MethodInfo member;

		private readonly MethodInvokerDelegate _invoker;

		private readonly bool anyByRef;

		private static readonly object[] _args0 = Array.Empty<object>();

		[ThreadStatic]
		private static object[] _args1;

		[ThreadStatic]
		private static object[] _args2;

		[ThreadStatic]
		private static object[] _args3;

		[ThreadStatic]
		private static object[] _args4;

		[ThreadStatic]
		private static object[] _args5;

		public TypedMethodInvoker(Type type, string name, ParamSig[] parameters)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			anyByRef = parameters.Any((ParamSig p) => p.IsByRef);
			Type[] types = parameters.Select((ParamSig p) => (!p.IsByRef) ? p.ConcreteType : p.ConcreteType.MakeByRefType()).ToArray();
			member = type.GetMethod(name, bindingAttr, null, types, null);
			if (member == null)
			{
				throw new MissingMethodException(type.FullName, name);
			}
			_invoker = MethodInvoker.CreateInvokerDelegate(member);
		}

		public R Invoke(object instance, object[] args)
		{
			return (R)_invoker(instance, args);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public R Invoke(object instance)
		{
			return (R)_invoker(instance, _args0);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public R Invoke(object instance, object arg0)
		{
			if (anyByRef)
			{
				return (R)_invoker(instance, new object[1] { arg0 });
			}
			object[] array = _args1 ?? (_args1 = new object[1]);
			array[0] = arg0;
			return (R)_invoker(instance, array);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public R Invoke(object instance, object arg0, object arg1)
		{
			if (anyByRef)
			{
				return (R)_invoker(instance, new object[2] { arg0, arg1 });
			}
			object[] array = _args2 ?? (_args2 = new object[2]);
			array[0] = arg0;
			array[1] = arg1;
			return (R)_invoker(instance, array);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public R Invoke(object instance, object arg0, object arg1, object arg2)
		{
			if (anyByRef)
			{
				return (R)_invoker(instance, new object[3] { arg0, arg1, arg2 });
			}
			object[] array = _args3 ?? (_args3 = new object[3]);
			array[0] = arg0;
			array[1] = arg1;
			array[2] = arg2;
			return (R)_invoker(instance, array);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public R Invoke(object instance, object arg0, object arg1, object arg2, object arg3)
		{
			if (anyByRef)
			{
				return (R)_invoker(instance, new object[4] { arg0, arg1, arg2, arg3 });
			}
			object[] array = _args4 ?? (_args4 = new object[4]);
			array[0] = arg0;
			array[1] = arg1;
			array[2] = arg2;
			array[3] = arg3;
			return (R)_invoker(instance, array);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public R Invoke(object instance, object arg0, object arg1, object arg2, object arg3, object arg4)
		{
			if (anyByRef)
			{
				return (R)_invoker(instance, new object[5] { arg0, arg1, arg2, arg3, arg4 });
			}
			object[] array = _args5 ?? (_args5 = new object[5]);
			array[0] = arg0;
			array[1] = arg1;
			array[2] = arg2;
			array[3] = arg3;
			array[4] = arg4;
			return (R)_invoker(instance, array);
		}
	}
	public class VoidMethodInvoker : MethodInvoker
	{
		protected readonly MethodInfo member;

		private readonly MethodInvokerDelegate _invoker;

		private readonly bool anyByRef;

		private static readonly object[] _args0 = Array.Empty<object>();

		[ThreadStatic]
		private static object[] _args1;

		[ThreadStatic]
		private static object[] _args2;

		[ThreadStatic]
		private static object[] _args3;

		[ThreadStatic]
		private static object[] _args4;

		[ThreadStatic]
		private static object[] _args5;

		public VoidMethodInvoker(Type type, string name, ParamSig[] parameters)
		{
			BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
			anyByRef = parameters.Any((ParamSig p) => p.IsByRef);
			Type[] types = parameters.Select((ParamSig p) => (!p.IsByRef) ? p.ConcreteType : p.ConcreteType.MakeByRefType()).ToArray();
			member = type.GetMethod(name, bindingAttr, null, types, null);
			if (member == null)
			{
				throw new MissingMethodException(type.FullName, name);
			}
			_invoker = MethodInvoker.CreateInvokerDelegate(member);
		}

		public void Invoke(object instance, object[] args)
		{
			_invoker(instance, args);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Invoke(object instance)
		{
			_invoker(instance, _args0);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Invoke(object instance, object arg0)
		{
			if (anyByRef)
			{
				_invoker(instance, new object[1] { arg0 });
			}
			else
			{
				object[] array = _args1 ?? (_args1 = new object[1]);
				array[0] = arg0;
				_invoker(instance, array);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Invoke(object instance, object arg0, object arg1)
		{
			if (anyByRef)
			{
				_invoker(instance, new object[2] { arg0, arg1 });
			}
			else
			{
				object[] array = _args2 ?? (_args2 = new object[2]);
				array[0] = arg0;
				array[1] = arg1;
				_invoker(instance, array);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Invoke(object instance, object arg0, object arg1, object arg2)
		{
			if (anyByRef)
			{
				_invoker(instance, new object[3] { arg0, arg1, arg2 });
			}
			else
			{
				object[] array = _args3 ?? (_args3 = new object[3]);
				array[0] = arg0;
				array[1] = arg1;
				array[2] = arg2;
				_invoker(instance, array);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Invoke(object instance, object arg0, object arg1, object arg2, object arg3)
		{
			if (anyByRef)
			{
				_invoker(instance, new object[4] { arg0, arg1, arg2, arg3 });
			}
			else
			{
				object[] array = _args4 ?? (_args4 = new object[4]);
				array[0] = arg0;
				array[1] = arg1;
				array[2] = arg2;
				array[3] = arg3;
				_invoker(instance, array);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void Invoke(object instance, object arg0, object arg1, object arg2, object arg3, object arg4)
		{
			if (anyByRef)
			{
				_invoker(instance, new object[5] { arg0, arg1, arg2, arg3, arg4 });
			}
			else
			{
				object[] array = _args5 ?? (_args5 = new object[5]);
				array[0] = arg0;
				array[1] = arg1;
				array[2] = arg2;
				array[3] = arg3;
				array[4] = arg4;
				_invoker(instance, array);
			}
		}
	}
}
namespace HoldToCommand.Patches
{
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	internal static class Localization_SetupLanguage_Patch
	{
		internal const string keyHold = "htc_hold";

		internal const string keyCommand = "htc_command";

		private static void Postfix(Localization __instance, string language)
		{
			if (!Plugin.TranslationsByLanguage.TryGetValue(language, out (string, string) value) && !Plugin.TranslationsByLanguage.TryGetValue("English", out value))
			{
				value = ("Hold $1", "Command");
			}
			__instance.AddWord("htc_hold", value.Item1);
			__instance.AddWord("htc_command", value.Item2);
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class Tameable_GetHoverText_Patch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Tameable __instance, ref string __result)
		{
			if (__instance.IsTamed() && __instance.m_commandable)
			{
				string text = Localization.instance.Localize("$hud_pet");
				int num = __result.IndexOf(text, StringComparison.Ordinal);
				if (num >= 0)
				{
					string text2 = Localization.instance.Localize("$KEY_Use");
					string text3 = Localization.instance.Localize("$htc_hold", new string[1] { text2 });
					string value = Localization.instance.Localize("  [<color=yellow><b>" + text3 + "</b></color>] $htc_command");
					__result = __result.Insert(num + text.Length, value);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Interact")]
	internal static class Tameable_Interact_Patch
	{
		private static bool Prefix(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result)
		{
			__result = __instance.CustomInteract(user, hold, alt);
			return false;
		}
	}
}