Decompiled source of RadamantoFix v1.0.1

BepInEx/plugins/RadamantoFix/PlantationsFix.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[BepInPlugin("local.radamantofix.plantations", "PlantationsFix", "1.0.1")]
public sealed class PlantationsFix : BaseUnityPlugin
{
	private const string PluginGuid = "local.radamantofix.plantations";

	private const string PluginName = "PlantationsFix";

	private const string PluginVersion = "1.0.1";

	private const string HarmonyId = "local.radamantofix.plantations.harmony";

	private const string TargetAssemblyName = "Plantations";

	private const string CategoryTypeName = "PieceManager.BuildingPieceCategory";

	private const string BadCategory = "Silvestres";

	private const int KnownSafeSetToken = 100663458;

	private static Harmony _harmony;

	private static ManualLogSource _log;

	private static bool _finished;

	private static MethodInfo _safeSet;

	private static int _expectedMatches;

	private static int _changedMatches;

	private ConfigFile _sharedConfig;

	private void Awake()
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		_log = ((BaseUnityPlugin)this).Logger;
		try
		{
			if (!LoadEnabledFromSharedConfig())
			{
				LogInfo("DISABLED BY CONFIG.");
				_finished = true;
				return;
			}
			_harmony = new Harmony("local.radamantofix.plantations.harmony");
			TryHandleLoadedPlantations();
			if (!_finished)
			{
				AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
				LogInfo("Target assembly is not loaded yet; waiting for Plantations.");
			}
		}
		catch (Exception ex)
		{
			RollbackQuietly();
			LogWarn("Startup guard caught an exception; fix disabled safely. " + ex.GetType().Name + ": " + ex.Message);
			_finished = true;
		}
	}

	private bool LoadEnabledFromSharedConfig()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		string text = Path.Combine(Paths.ConfigPath, "RadamantoFix.cfg");
		_sharedConfig = new ConfigFile(text, false);
		ConfigEntry<bool> val = _sharedConfig.Bind<bool>("Plantations", "Enabled", true, "Enable the SafeGuard fix for the unwanted Silvestres hammer tab from Plantations.");
		_sharedConfig.Bind<bool>("Producers", "Enabled", true, "Enable the SafeGuard fix for the duplicate Crafting hammer tab from Producers.");
		_sharedConfig.Save();
		return val.Value;
	}

	private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs e)
	{
		if (_finished || e == null || e.LoadedAssembly == null)
		{
			return;
		}
		try
		{
			if (string.Equals(e.LoadedAssembly.GetName().Name, "Plantations", StringComparison.OrdinalIgnoreCase))
			{
				TryHandle(e.LoadedAssembly);
			}
		}
		catch (Exception ex)
		{
			LogWarn("Assembly-load guard caught an exception; fix disabled safely. " + ex.GetType().Name + ": " + ex.Message);
			RollbackQuietly();
			Finish();
		}
	}

	private static void TryHandleLoadedPlantations()
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			if (assembly != null && string.Equals(assembly.GetName().Name, "Plantations", StringComparison.OrdinalIgnoreCase))
			{
				TryHandle(assembly);
				break;
			}
		}
	}

	private static void TryHandle(Assembly target)
	{
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: Expected O, but got Unknown
		if (_finished)
		{
			return;
		}
		try
		{
			List<MethodInfo> list = new List<MethodInfo>();
			int num = 0;
			MethodInfo methodInfo = null;
			Type[] types;
			try
			{
				types = target.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				types = ex.Types;
			}
			foreach (Type type in types)
			{
				if (type == null)
				{
					continue;
				}
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				for (int j = 0; j < methods.Length; j++)
				{
					MethodInfo brokenSet;
					int num2 = CountTargetPattern(methods[j], out brokenSet);
					if (num2 > 0)
					{
						list.Add(methods[j]);
						num += num2;
						if (methodInfo == null)
						{
							methodInfo = brokenSet;
						}
					}
				}
			}
			if (num == 0)
			{
				LogInfo("No vulnerable 'Silvestres' Set(string) pattern found. Nothing was patched. Plantations may already be fixed by its author; this DLL is safe to remove if the tab is correct.");
				Finish();
				return;
			}
			_safeSet = ResolveSafeSet(methodInfo);
			if (_safeSet == null)
			{
				LogWarn("Vulnerable pattern was found, but the known-safe Set target cannot be proven. Plantations/PieceManager has changed. FAIL-CLOSED: no methods were patched.");
				Finish();
				return;
			}
			_expectedMatches = num;
			_changedMatches = 0;
			for (int k = 0; k < list.Count; k++)
			{
				_harmony.Patch((MethodBase)list[k], (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(PlantationsFix), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (_changedMatches != _expectedMatches)
			{
				LogWarn("Safety verification failed after patching: expected " + _expectedMatches + " replacement(s), got " + _changedMatches + ". Rolling back this fix completely.");
				RollbackQuietly();
				Finish();
			}
			else
			{
				LogInfo("SAFEGUARD OK: patched methods=" + list.Count + "; replacements=" + _changedMatches + "/" + _expectedMatches + ".");
				Finish();
			}
		}
		catch (Exception ex2)
		{
			RollbackQuietly();
			LogWarn("Compatibility guard caught an exception. FAIL-CLOSED: fix rolled back/disabled. " + ex2.GetType().Name + ": " + ex2.Message);
			Finish();
		}
	}

	private static int CountTargetPattern(MethodInfo method, out MethodInfo brokenSet)
	{
		brokenSet = null;
		int num = 0;
		try
		{
			MethodBody methodBody = method.GetMethodBody();
			if (methodBody == null)
			{
				return 0;
			}
			byte[] iLAsByteArray = methodBody.GetILAsByteArray();
			if (iLAsByteArray == null)
			{
				return 0;
			}
			for (int i = 0; i + 9 < iLAsByteArray.Length; i++)
			{
				if (iLAsByteArray[i] != 114 || iLAsByteArray[i + 5] != 111)
				{
					continue;
				}
				string a = method.Module.ResolveString(BitConverter.ToInt32(iLAsByteArray, i + 1));
				if (!string.Equals(a, "Silvestres", StringComparison.Ordinal))
				{
					continue;
				}
				MethodInfo methodInfo = method.Module.ResolveMethod(BitConverter.ToInt32(iLAsByteArray, i + 6)) as MethodInfo;
				if (IsBrokenSetString(methodInfo))
				{
					if (brokenSet == null)
					{
						brokenSet = methodInfo;
					}
					num++;
				}
			}
			return num;
		}
		catch
		{
			return 0;
		}
	}

	private static bool IsBrokenSetString(MethodInfo method)
	{
		if (method == null || !string.Equals(method.Name, "Set", StringComparison.Ordinal))
		{
			return false;
		}
		if (method.DeclaringType == null || !string.Equals(method.DeclaringType.FullName, "PieceManager.BuildingPieceCategory", StringComparison.Ordinal))
		{
			return false;
		}
		ParameterInfo[] parameters = method.GetParameters();
		if (parameters.Length == 1)
		{
			return parameters[0].ParameterType == typeof(string);
		}
		return false;
	}

	private static MethodInfo ResolveSafeSet(MethodInfo brokenSet)
	{
		if (brokenSet == null || brokenSet.Module == null)
		{
			return null;
		}
		try
		{
			MethodInfo methodInfo = brokenSet.Module.ResolveMethod(100663458) as MethodInfo;
			if (methodInfo == null || methodInfo == brokenSet)
			{
				return null;
			}
			if (!string.Equals(methodInfo.Name, "Set", StringComparison.Ordinal))
			{
				return null;
			}
			if (methodInfo.DeclaringType == null || !string.Equals(methodInfo.DeclaringType.FullName, "PieceManager.BuildingPieceCategory", StringComparison.Ordinal))
			{
				return null;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (parameters.Length != 1)
			{
				return null;
			}
			if (parameters[0].ParameterType == typeof(string))
			{
				return null;
			}
			return methodInfo;
		}
		catch
		{
			return null;
		}
	}

	private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		if (_safeSet == null)
		{
			return list;
		}
		for (int i = 0; i + 1 < list.Count; i++)
		{
			if (!(list[i].opcode != OpCodes.Ldstr) && string.Equals(list[i].operand as string, "Silvestres", StringComparison.Ordinal))
			{
				MethodInfo method = list[i + 1].operand as MethodInfo;
				if (IsBrokenSetString(method))
				{
					CodeInstruction val = new CodeInstruction(OpCodes.Ldc_I4_0, (object)null);
					val.labels.AddRange(list[i].labels);
					val.blocks.AddRange(list[i].blocks);
					list[i] = val;
					list[i + 1].operand = _safeSet;
					_changedMatches++;
					i++;
				}
			}
		}
		return list;
	}

	private static void Finish()
	{
		_finished = true;
	}

	private static void RollbackQuietly()
	{
		try
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
	}

	private static void LogInfo(string message)
	{
		try
		{
			if (_log != null)
			{
				_log.LogInfo((object)("[RadamantoFix/PlantationsFix] " + message));
			}
		}
		catch
		{
		}
	}

	private static void LogWarn(string message)
	{
		try
		{
			if (_log != null)
			{
				_log.LogWarning((object)("[RadamantoFix/PlantationsFix] " + message));
			}
		}
		catch
		{
		}
	}

	private void OnDestroy()
	{
		try
		{
			AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
		}
		catch
		{
		}
		RollbackQuietly();
	}
}

BepInEx/plugins/RadamantoFix/ProducersFix.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[BepInPlugin("local.radamantofix.producers", "ProducersFix", "1.0.1")]
public sealed class ProducersFix : BaseUnityPlugin
{
	private const string PluginGuid = "local.radamantofix.producers";

	private const string PluginName = "ProducersFix";

	private const string PluginVersion = "1.0.1";

	private const string HarmonyId = "local.radamantofix.producers.harmony";

	private const string TargetAssemblyName = "Producers";

	private const string TargetTypeName = "PieceManager.PiecePrefabManager";

	private const string BadCategory = "Crafting";

	private const int ExpectedCallCount = 1;

	private static Harmony _harmony;

	private static ManualLogSource _log;

	private static bool _finished;

	private ConfigFile _sharedConfig;

	private void Awake()
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		_log = ((BaseUnityPlugin)this).Logger;
		try
		{
			if (!LoadEnabledFromSharedConfig())
			{
				LogInfo("DISABLED BY CONFIG.");
				_finished = true;
				return;
			}
			_harmony = new Harmony("local.radamantofix.producers.harmony");
			TryPatchLoadedProducers();
			if (!_finished)
			{
				AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
				LogInfo("Target assembly is not loaded yet; waiting for Producers.");
			}
		}
		catch (Exception ex)
		{
			RollbackQuietly();
			_finished = true;
			LogWarn("SAFEGUARD ERROR/ROLLBACK: " + ex.GetType().Name + ": " + ex.Message);
		}
	}

	private bool LoadEnabledFromSharedConfig()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		string text = Path.Combine(Paths.ConfigPath, "RadamantoFix.cfg");
		_sharedConfig = new ConfigFile(text, false);
		_sharedConfig.Bind<bool>("Plantations", "Enabled", true, "Enable the SafeGuard fix for the unwanted Silvestres hammer tab from Plantations.");
		ConfigEntry<bool> val = _sharedConfig.Bind<bool>("Producers", "Enabled", true, "Enable the SafeGuard fix for the duplicate Crafting hammer tab from Producers.");
		_sharedConfig.Save();
		return val.Value;
	}

	private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs e)
	{
		if (_finished || e == null || e.LoadedAssembly == null)
		{
			return;
		}
		try
		{
			if (string.Equals(e.LoadedAssembly.GetName().Name, "Producers", StringComparison.OrdinalIgnoreCase))
			{
				TryPatch(e.LoadedAssembly);
			}
		}
		catch (Exception ex)
		{
			RollbackQuietly();
			_finished = true;
			LogWarn("SAFEGUARD ERROR/ROLLBACK: " + ex.GetType().Name + ": " + ex.Message);
		}
	}

	private static void TryPatchLoadedProducers()
	{
		if (_finished)
		{
			return;
		}
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			if (assembly != null && string.Equals(assembly.GetName().Name, "Producers", StringComparison.OrdinalIgnoreCase))
			{
				TryPatch(assembly);
				break;
			}
		}
	}

	private static void TryPatch(Assembly target)
	{
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Expected O, but got Unknown
		if (_finished)
		{
			return;
		}
		try
		{
			List<MethodInfo> list = new List<MethodInfo>();
			int num = 0;
			Type[] types;
			try
			{
				types = target.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				types = ex.Types;
			}
			foreach (Type type in types)
			{
				if (type == null)
				{
					continue;
				}
				MethodInfo[] methods;
				try
				{
					methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				catch
				{
					continue;
				}
				for (int j = 0; j < methods.Length; j++)
				{
					int num2 = CountTargetPattern(methods[j]);
					if (num2 > 0)
					{
						list.Add(methods[j]);
						num += num2;
					}
				}
			}
			if (list.Count != 1 || num != 1)
			{
				_finished = true;
				LogInfo("SAFEGUARD SKIPPED");
			}
			else
			{
				_harmony.Patch((MethodBase)list[0], new HarmonyMethod(typeof(ProducersFix), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				_finished = true;
				LogInfo("SAFEGUARD OK");
			}
		}
		catch (Exception ex2)
		{
			RollbackQuietly();
			_finished = true;
			LogWarn("SAFEGUARD ERROR/ROLLBACK: " + ex2.GetType().Name + ": " + ex2.Message);
		}
	}

	private static int CountTargetPattern(MethodInfo method)
	{
		if (!IsGetCustomTag(method))
		{
			return 0;
		}
		int num = 0;
		MethodBody methodBody = method.GetMethodBody();
		if (methodBody == null)
		{
			return 0;
		}
		byte[] iLAsByteArray = methodBody.GetILAsByteArray();
		if (iLAsByteArray == null)
		{
			return 0;
		}
		for (int i = 0; i + 4 < iLAsByteArray.Length; i++)
		{
			if (iLAsByteArray[i] == 40 && iLAsByteArray[i + 4] == 6)
			{
				MethodInfo method2 = method.Module.ResolveMethod(BitConverter.ToInt32(iLAsByteArray, i + 1)) as MethodInfo;
				if (ResolveRegCall(method2) != null)
				{
					num++;
				}
			}
		}
		if (num != 1)
		{
			return 0;
		}
		return num;
	}

	private static bool IsGetCustomTag(MethodBase methodBase)
	{
		MethodInfo methodInfo = methodBase as MethodInfo;
		if (methodInfo == null)
		{
			return false;
		}
		if (!string.Equals(methodInfo.Name, "GetCustomTag", StringComparison.Ordinal))
		{
			return false;
		}
		if (methodInfo.DeclaringType == null || !string.Equals(methodInfo.DeclaringType.FullName, "PieceManager.PiecePrefabManager", StringComparison.Ordinal))
		{
			return false;
		}
		ParameterInfo[] parameters = methodInfo.GetParameters();
		if (parameters.Length == 1)
		{
			return parameters[0].ParameterType == typeof(string);
		}
		return false;
	}

	private static MethodInfo ResolveRegCall(MethodInfo method)
	{
		if (method == null)
		{
			return null;
		}
		if (!string.Equals(method.Name, "RegisterCustomCategory", StringComparison.Ordinal))
		{
			return null;
		}
		if (method.DeclaringType == null || !string.Equals(method.DeclaringType.FullName, "PieceManager.PiecePrefabManager", StringComparison.Ordinal))
		{
			return null;
		}
		ParameterInfo[] parameters = method.GetParameters();
		if (parameters.Length != 1 || parameters[0].ParameterType != typeof(string))
		{
			return null;
		}
		return method;
	}

	private static bool Prefix(string name)
	{
		return !string.Equals(name, "Crafting", StringComparison.Ordinal);
	}

	private static void RollbackQuietly()
	{
		try
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
	}

	private static void LogInfo(string message)
	{
		try
		{
			if (_log != null)
			{
				_log.LogInfo((object)("[RadamantoFix/ProducersFix] " + message));
			}
		}
		catch
		{
		}
	}

	private static void LogWarn(string message)
	{
		try
		{
			if (_log != null)
			{
				_log.LogWarning((object)("[RadamantoFix/ProducersFix] " + message));
			}
		}
		catch
		{
		}
	}

	private void OnDestroy()
	{
		try
		{
			AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
		}
		catch
		{
		}
		RollbackQuietly();
	}
}