Decompiled source of Tuneups v1.0.1

plugins/Tuneups.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Tuneups")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Tuneups")]
[assembly: AssemblyTitle("Tuneups")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Tuneups;

[BepInPlugin("anwo.Tuneups", "Tuneups", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class TuneupsPlugin : BaseUnityPlugin
{
	public const string Guid = "anwo.Tuneups";

	public const string Name = "Tuneups";

	public const string Version = "1.0.1";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> BackpacksFix;

	internal static ConfigEntry<bool> FindFix;

	internal static Harmony Harmony;

	private void Awake()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Harmony = new Harmony("anwo.Tuneups");
		BackpacksFix = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Adventure Backpacks", "Faster backpack check", true, "Adventure Backpacks asks of every networked object, every time the game asks whether this PC is in charge of it, whether it is a backpack, by reading the object's name. That's thousands of times a frame at a big base, and each read makes a little garbage for the game to clean up. A backpack never has network data of its own, so this fix lets every object that has network data skip the name check; for objects without it, Adventure Backpacks' own check runs as before. Every answer stays the same, nothing is saved or changed, and backpacks and their contents work exactly as before. It only switches on when Adventure Backpacks' check is exactly the one this fix was made for (version 2.2.10's), and switches itself off if a backpack ever shows up with network data. Can be turned on and off while you play.");
		BackpacksFix.SettingChanged += delegate
		{
			AdventureBackpacksFix.Apply(BackpacksFix.Value);
		};
		FindFix = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Server Devcommands", "Find distance from you", true, "Server Devcommands' find command (\"find boar\") lists what it finds with a distance and shows the closest ones first. On the game that hosts the world (playing on your own, or hosting for friends) it measured from the middle of the world (near the start) instead of from you, because it only adds your position when it sends the command on to a server. This fix adds your position before the command runs, so the distances are from where you stand and the closest to you come first. A position you type yourself (find boar 5 x,z,y) is left as it is. Only the find command is touched, nothing is saved or changed. Can be turned on and off while you play.");
		FindFix.SettingChanged += delegate
		{
			FindDistanceFix.Apply(FindFix.Value);
		};
		Log.LogInfo((object)"Tuneups 1.0.1 loaded.");
	}

	private void Start()
	{
		AdventureBackpacksFix.Apply(BackpacksFix.Value);
		FindDistanceFix.Apply(FindFix.Value);
	}
}
internal static class FindDistanceFix
{
	internal const string Guid = "server_devcommands";

	private const string CommandType = "ServerDevcommands.FindCommand";

	private const string Marker = "Missing the search term.";

	private const string DefaultCount = "10";

	private static MethodInfo s_find;

	internal static string State = "not set up";

	internal static bool Active { get; private set; }

	internal static void Apply(bool on)
	{
		try
		{
			if (on && !Active)
			{
				TurnOn();
			}
			else if (!on && Active)
			{
				TuneupsPlugin.Harmony.Unpatch((MethodBase)s_find, AccessTools.Method(typeof(FindDistanceFix), "AddPosition", (Type[])null, (Type[])null));
				Active = false;
				State = "off: turned off in the settings";
				ManualLogSource log = TuneupsPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"Find distance fix off.");
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log2 = TuneupsPlugin.Log;
			if (log2 != null)
			{
				log2.LogWarning((object)("Find distance fix: " + ex.Message + "; find is left as Server Devcommands made it."));
			}
			State = "off (error)";
		}
	}

	private static void TurnOn()
	{
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Expected O, but got Unknown
		s_find = Find(out var why);
		if (s_find == null)
		{
			State = "off: " + why;
			ManualLogSource log = TuneupsPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Find distance fix not used: " + why + "."));
			}
			return;
		}
		TuneupsPlugin.Harmony.Patch((MethodBase)s_find, new HarmonyMethod(typeof(FindDistanceFix), "AddPosition", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		Active = true;
		State = "on";
		ManualLogSource log2 = TuneupsPlugin.Log;
		if (log2 != null)
		{
			log2.LogInfo((object)"Find distance fix on: find measures from where you stand.");
		}
	}

	private static MethodInfo Find(out string why)
	{
		why = null;
		Type type = AccessTools.TypeByName("ServerDevcommands.FindCommand");
		if (type == null)
		{
			why = "Server Devcommands (or its find command) isn't there";
			return null;
		}
		List<MethodInfo> list = new List<MethodInfo>();
		foreach (Type item in new Type[1] { type }.Concat(type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)))
		{
			MethodInfo[] methods = item.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (methodInfo.ReturnType != typeof(void) || parameters.Length != 1 || parameters[0].ParameterType != typeof(ConsoleEventArgs))
				{
					continue;
				}
				try
				{
					if (IL.Read(methodInfo).Any((Instruction ci) => ci.Op == OpCodes.Ldstr && ci.Operand as string == "Missing the search term."))
					{
						list.Add(methodInfo);
					}
				}
				catch
				{
				}
			}
		}
		if (list.Count != 1)
		{
			why = ((list.Count == 0) ? "its find command isn't the one this fix was made for" : "it has more than one find command");
			return null;
		}
		return list[0];
	}

	internal static string[] WithPosition(string[] args, Vector3 p)
	{
		if (args == null || args.Length < 2 || args.Length > 3)
		{
			return null;
		}
		List<string> list = new List<string>(args);
		if (list.Count < 3)
		{
			list.Add("10");
		}
		list.Add(p.x.ToString(CultureInfo.InvariantCulture) + "," + p.z.ToString(CultureInfo.InvariantCulture) + "," + p.y.ToString(CultureInfo.InvariantCulture));
		return list.ToArray();
	}

	internal static void AddPosition(ConsoleEventArgs __0)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && __0 != null)
			{
				string[] array = WithPosition(__0.Args, ((Component)localPlayer).transform.position);
				if (array != null)
				{
					__0.Args = array;
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = TuneupsPlugin.Log;
			if (log != null)
			{
				log.LogDebug((object)("Find distance fix: " + ex.Message));
			}
		}
	}
}
internal static class AdventureBackpacksFix
{
	internal delegate bool CheckFn(ZNetView view, ref bool result);

	internal const string Guid = "vapok.mods.adventurebackpacks";

	private const string ProxyName = "AB_BackpackProxy";

	private const string IsOwnerPatchType = "AdventureBackpacks.Patches.ContainerPatches+ZNetViewIsOwnerPatch";

	private const string AwakePatchType = "AdventureBackpacks.Patches.ContainerPatches+ZNetViewAwakePatch";

	private const string ProxyMaker = "AdventureBackpacks.Extensions.PlayerExtensions";

	private static CheckFn s_theirs;

	private static MethodInfo s_theirMethod;

	private static Patch s_theirPatch;

	private static MethodInfo s_proxyMaker;

	internal static string State = "not set up";

	private static bool s_givenUp;

	internal static bool Active { get; private set; }

	private static MethodBase IsOwner => AccessTools.Method(typeof(ZNetView), "IsOwner", (Type[])null, (Type[])null);

	private static MethodBase ZNetViewAwake => AccessTools.Method(typeof(ZNetView), "Awake", (Type[])null, (Type[])null);

	internal static bool FastIsOwner(ZNetView __instance, ref bool __result)
	{
		if (__instance.GetZDO() != null)
		{
			return true;
		}
		return s_theirs(__instance, ref __result);
	}

	internal static void AfterProxy(Container __result)
	{
		try
		{
			if (Active && !((Object)(object)__result == (Object)null))
			{
				ZNetView component = ((Component)__result).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.GetZDO() != null)
				{
					GiveUp("a backpack had network data of its own");
				}
			}
		}
		catch (Exception ex)
		{
			GiveUp("looking at a backpack failed: " + ex.Message);
		}
	}

	internal static void Apply(bool on)
	{
		try
		{
			if (on && !Active && !s_givenUp)
			{
				TurnOn();
			}
			else if (!on && Active)
			{
				TurnOff("turned off in the settings");
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = TuneupsPlugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Adventure Backpacks fix: " + ex.Message + "; left as Adventure Backpacks made it."));
			}
			try
			{
				if (Active)
				{
					TurnOff("an error");
				}
			}
			catch
			{
			}
			State = "off (error)";
		}
	}

	private static void TurnOn()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Expected O, but got Unknown
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		if (!Find(out var why))
		{
			State = "off: " + why;
			ManualLogSource log = TuneupsPlugin.Log;
			if (log != null)
			{
				log.LogInfo((object)("Adventure Backpacks fix not used: " + why + "."));
			}
			return;
		}
		Harmony harmony = TuneupsPlugin.Harmony;
		HarmonyMethod val = new HarmonyMethod(typeof(AdventureBackpacksFix), "FastIsOwner", (Type[])null)
		{
			priority = s_theirPatch.priority,
			before = s_theirPatch.before,
			after = s_theirPatch.after
		};
		harmony.Patch(IsOwner, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Unpatch(IsOwner, s_theirMethod);
		if (s_proxyMaker != null)
		{
			harmony.Patch((MethodBase)s_proxyMaker, (HarmonyMethod)null, new HarmonyMethod(typeof(AdventureBackpacksFix), "AfterProxy", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		Active = true;
		State = "on";
		ManualLogSource log2 = TuneupsPlugin.Log;
		if (log2 != null)
		{
			log2.LogInfo((object)"Adventure Backpacks fix on: objects with network data skip the backpack name check.");
		}
	}

	private static void TurnOff(string why)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		Harmony harmony = TuneupsPlugin.Harmony;
		HarmonyMethod val = new HarmonyMethod(s_theirMethod)
		{
			priority = s_theirPatch.priority,
			before = s_theirPatch.before,
			after = s_theirPatch.after
		};
		harmony.Patch(IsOwner, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Unpatch(IsOwner, AccessTools.Method(typeof(AdventureBackpacksFix), "FastIsOwner", (Type[])null, (Type[])null));
		if (s_proxyMaker != null)
		{
			harmony.Unpatch((MethodBase)s_proxyMaker, AccessTools.Method(typeof(AdventureBackpacksFix), "AfterProxy", (Type[])null, (Type[])null));
		}
		Active = false;
		State = "off: " + why;
		ManualLogSource log = TuneupsPlugin.Log;
		if (log != null)
		{
			log.LogInfo((object)("Adventure Backpacks fix off (" + why + "); Adventure Backpacks' own check is back."));
		}
	}

	private static void GiveUp(string why)
	{
		s_givenUp = true;
		ManualLogSource log = TuneupsPlugin.Log;
		if (log != null)
		{
			log.LogWarning((object)("Adventure Backpacks fix switched itself off: " + why + ". Nothing was changed; it stays off until the game restarts."));
		}
		if (Active)
		{
			TurnOff(why);
		}
	}

	private static bool Find(out string why)
	{
		why = null;
		s_theirPatch = ((IEnumerable<Patch>)Harmony.GetPatchInfo(IsOwner)?.Prefixes).FirstOrDefault((Func<Patch, bool>)((Patch p) => p.PatchMethod != null && p.PatchMethod.DeclaringType != null && p.PatchMethod.DeclaringType.FullName == "AdventureBackpacks.Patches.ContainerPatches+ZNetViewIsOwnerPatch" && p.PatchMethod.Name == "Prefix"));
		if (s_theirPatch == null)
		{
			why = "Adventure Backpacks (or its check) isn't there";
			return false;
		}
		s_theirMethod = s_theirPatch.PatchMethod;
		ParameterInfo[] parameters = s_theirMethod.GetParameters();
		if (s_theirMethod.ReturnType != typeof(bool) || parameters.Length != 2 || parameters[0].ParameterType != typeof(ZNetView) || parameters[1].ParameterType != typeof(bool).MakeByRefType())
		{
			why = "its check takes different arguments than expected";
			return false;
		}
		if (!LooksLike(s_theirMethod, setsAnswer: true, out var diff))
		{
			why = "its check isn't the one this fix was made for (" + diff + ")";
			return false;
		}
		Patch val = ((IEnumerable<Patch>)Harmony.GetPatchInfo(ZNetViewAwake)?.Prefixes).FirstOrDefault((Func<Patch, bool>)((Patch p) => p.PatchMethod != null && p.PatchMethod.DeclaringType != null && p.PatchMethod.DeclaringType.FullName == "AdventureBackpacks.Patches.ContainerPatches+ZNetViewAwakePatch" && p.PatchMethod.Name == "Prefix"));
		if (val == null)
		{
			why = "its network setup skip for backpacks isn't there";
			return false;
		}
		if (!LooksLike(val.PatchMethod, setsAnswer: false, out diff))
		{
			why = "its network setup skip isn't the one this fix was made for (" + diff + ")";
			return false;
		}
		s_theirs = (CheckFn)Delegate.CreateDelegate(typeof(CheckFn), s_theirMethod);
		Type type = s_theirMethod.DeclaringType.Assembly.GetType("AdventureBackpacks.Extensions.PlayerExtensions");
		s_proxyMaker = ((type != null) ? AccessTools.Method(type, "GetBackpackContainerProxy", (Type[])null, (Type[])null) : null);
		if (s_proxyMaker == null || s_proxyMaker.ReturnType != typeof(Container))
		{
			why = "the place it makes backpacks isn't there";
			return false;
		}
		return true;
	}

	internal static bool LooksLike(MethodInfo method, bool setsAnswer, out string diff)
	{
		diff = null;
		HashSet<string> hashSet = new HashSet<string> { "op_Inequality", "get_gameObject", "get_name", "StartsWith" };
		List<string> list = new List<string>();
		int num = 0;
		foreach (Instruction item in IL.Read(method))
		{
			if (item.Op == OpCodes.Call || item.Op == OpCodes.Callvirt || item.Op == OpCodes.Newobj)
			{
				MethodBase methodBase = item.Operand as MethodBase;
				if (methodBase == null || !hashSet.Contains(methodBase.Name))
				{
					diff = "calls " + ((methodBase != null) ? (methodBase.DeclaringType?.Name + "." + methodBase.Name) : "something");
					return false;
				}
			}
			else if (item.Op == OpCodes.Ldstr)
			{
				list.Add(item.Operand as string);
			}
			else if (item.Op == OpCodes.Stind_I1)
			{
				num++;
			}
			else if (item.Op == OpCodes.Stfld || item.Op == OpCodes.Stsfld || item.Op == OpCodes.Starg || item.Op == OpCodes.Starg_S || item.Op == OpCodes.Calli || item.Op == OpCodes.Jmp)
			{
				diff = "does something else";
				return false;
			}
		}
		if (list.Count != 1 || list[0] != "AB_BackpackProxy")
		{
			diff = "compares other text";
			return false;
		}
		if (setsAnswer && num != 1)
		{
			diff = "sets its answer differently";
			return false;
		}
		if (!setsAnswer && num != 0)
		{
			diff = "sets an answer";
			return false;
		}
		return true;
	}
}
internal struct Instruction
{
	public OpCode Op;

	public object Operand;
}
internal static class IL
{
	private static readonly Dictionary<short, OpCode> Ops = BuildOps();

	private static Dictionary<short, OpCode> BuildOps()
	{
		Dictionary<short, OpCode> dictionary = new Dictionary<short, OpCode>();
		FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public);
		for (int i = 0; i < fields.Length; i++)
		{
			if (fields[i].GetValue(null) is OpCode value)
			{
				dictionary[value.Value] = value;
			}
		}
		return dictionary;
	}

	internal static List<Instruction> Read(MethodInfo method)
	{
		List<Instruction> list = new List<Instruction>();
		byte[] array = method.GetMethodBody()?.GetILAsByteArray();
		if (array == null)
		{
			throw new InvalidOperationException("no code to read");
		}
		Module module = method.Module;
		Type[] genericTypeArguments = ((method.DeclaringType != null && method.DeclaringType.IsGenericType) ? method.DeclaringType.GetGenericArguments() : null);
		Type[] genericMethodArguments = (method.IsGenericMethod ? method.GetGenericArguments() : null);
		int num = 0;
		while (num < array.Length)
		{
			short num2 = array[num++];
			if (num2 == 254)
			{
				num2 = (short)(0xFE00 | array[num++]);
			}
			if (!Ops.TryGetValue(num2, out var value))
			{
				throw new InvalidOperationException("unknown instruction " + num2);
			}
			object operand = null;
			switch (value.OperandType)
			{
			case OperandType.ShortInlineBrTarget:
			case OperandType.ShortInlineI:
			case OperandType.ShortInlineVar:
				num++;
				break;
			case OperandType.InlineVar:
				num += 2;
				break;
			case OperandType.InlineMethod:
				try
				{
					operand = module.ResolveMethod(BitConverter.ToInt32(array, num), genericTypeArguments, genericMethodArguments);
				}
				catch
				{
					operand = null;
				}
				num += 4;
				break;
			case OperandType.InlineString:
				operand = module.ResolveString(BitConverter.ToInt32(array, num));
				num += 4;
				break;
			case OperandType.InlineI8:
			case OperandType.InlineR:
				num += 8;
				break;
			case OperandType.InlineSwitch:
			{
				int num3 = BitConverter.ToInt32(array, num);
				num += 4 + 4 * num3;
				break;
			}
			default:
				num += 4;
				break;
			case OperandType.InlineNone:
				break;
			}
			list.Add(new Instruction
			{
				Op = value,
				Operand = operand
			});
		}
		return list;
	}
}