Decompiled source of ModlistHashChecker v0.1.2

logmodlist.dll

Decompiled 10 months ago
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Steamworks;
using Steamworks.Data;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("logmodlist")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("logmodlist")]
[assembly: AssemblyTitle("logmodlist")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace ModListHashChecker
{
	public class ConfigManager
	{
		public static ConfigManager Instance { get; private set; }

		public static ConfigFile config { get; private set; }

		public static ConfigEntry<string> ExpectedModListHash { get; private set; }

		public static ConfigEntry<bool> NoExpectedHashMessage { get; private set; }

		public static ConfigEntry<bool> MenuWarning { get; private set; }

		public static ConfigEntry<bool> JoinWarning { get; private set; }

		public static ConfigEntry<string> WarningMessageText { get; private set; }

		public static ConfigEntry<string> JoinWarningText { get; private set; }

		public static ConfigEntry<int> JoinWarningDelay { get; private set; }

		public static ConfigEntry<string> WarningButtonIgnoreText { get; private set; }

		public static ConfigEntry<string> WarningButtonResetText { get; private set; }

		public static ConfigEntry<string> NoHashMessageText { get; private set; }

		public static ConfigEntry<string> NoHashRightButtonText { get; private set; }

		public static ConfigEntry<string> NoHashLeftButtonText { get; private set; }

		public static void Init(ConfigFile config)
		{
			Instance = new ConfigManager(config);
		}

		private ConfigManager(ConfigFile loadconfig)
		{
			config = loadconfig;
			ExpectedModListHash = config.Bind<string>("General", "ExpectedModListHash", "", "The expected modlist hash for this modpack. Do not change this unless you know what you're doing.");
			NoExpectedHashMessage = config.Bind<bool>("General", "NoExpectedHashMessage", true, "Enable or Disable displaying a warning message in the menus when the expected hash is empty. Do not change this unless you know what you're doing.");
			NoHashMessageText = config.Bind<string>("Menu Warning", "NoHashMessageText", "ExpectedModListHash configuration item is blank.\n\nWould you like to set it to the currently loaded list of mods?", "Menu Message to display when the expected hash is empty");
			NoHashRightButtonText = config.Bind<string>("Menu Warning", "NoHashRightButtonText", "No", "Button text for leaving the ExpectedModListHash blank");
			NoHashLeftButtonText = config.Bind<string>("Menu Warning", "NoHashLeftButtonText", "Yes", "Button text for setting the ExpectedModListHashto the detected hash");
			MenuWarning = config.Bind<bool>("General", "MenuWarning", true, "Enable or Disable displaying a warning message in the menus when the hash does not match the expected hash.");
			JoinWarning = config.Bind<bool>("General", "JoinWarning", true, "Enable or Disable displaying a warning message when a client joins and the hash does not match the host hash.");
			JoinWarningText = config.Bind<string>("Join Warning", "JoinWarningText", "Your modlist does not match the expected modlist hash.\n\n You may experience issues.", "Message to display in Hash Mismatch Menu Warning Message");
			JoinWarningDelay = config.Bind<int>("Join Warning", "JoinWarningDelay", 5, "Seconds delay until hud warning is displayed for mismatched hash on client join.");
			WarningMessageText = config.Bind<string>("Menu Warning", "WarningMessageText", "Your modlist does not match the expected modlist hash.\n\n You may experience issues.", "Message to display in Hash Mismatch Menu Warning Message");
			WarningButtonIgnoreText = config.Bind<string>("Menu Warning", "WarningButtonIgnoreText", "Okay", "Button text for ignoring the Hash Mismatch Menu Warning Message");
			WarningButtonResetText = config.Bind<string>("Menu Warning", "WarningButtonResetText", "Reset", "Button text for reseting ExpectedModListHash to the detected hash in Hash Mismatch Menu Warning Message");
		}
	}
	[HarmonyPatch(typeof(PreInitSceneScript))]
	public class HashGeneration : MonoBehaviour
	{
		public class DictionaryHashGenerator
		{
			public static string GenerateHash(Dictionary<string, PluginInfo> inputDictionary)
			{
				IOrderedEnumerable<KeyValuePair<string, PluginInfo>> source = inputDictionary.OrderBy((KeyValuePair<string, PluginInfo> entry) => entry.Key);
				string s = string.Join(",", source.Select((KeyValuePair<string, PluginInfo> entry) => $"{entry.Key}:{entry.Value}"));
				byte[] bytes = Encoding.UTF8.GetBytes(s);
				using SHA256 sHA = SHA256.Create();
				byte[] array = sHA.ComputeHash(bytes);
				StringBuilder stringBuilder = new StringBuilder();
				byte[] array2 = array;
				foreach (byte b in array2)
				{
					stringBuilder.Append(b.ToString("x2"));
				}
				return stringBuilder.ToString();
			}
		}

		private static Dictionary<string, PluginInfo> PluginsLoaded = new Dictionary<string, PluginInfo>();

		public static string generatedHash { get; internal set; } = "";


		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void Postfix()
		{
			ModListHashChecker.Log.LogInfo((object)"Creating Modlist Hash.");
			PluginsLoaded = Chainloader.PluginInfos;
			generatedHash = DictionaryHashGenerator.GenerateHash(PluginsLoaded);
			ModListHashChecker.Log.LogInfo((object)"==========================");
			ModListHashChecker.Log.LogInfo((object)("Modlist Hash: " + generatedHash));
			if (ConfigManager.ExpectedModListHash.Value != "")
			{
				ModListHashChecker.Log.LogInfo((object)("Expected Hash (from modpack): " + ConfigManager.ExpectedModListHash.Value));
				if (generatedHash == ConfigManager.ExpectedModListHash.Value)
				{
					ModListHashChecker.Log.LogWarning((object)"Your modlist matches the expected modlist hash.");
				}
				else
				{
					ModListHashChecker.Log.LogError((object)"Your modlist does not match the expected modlist hash.");
					ModListHashChecker.Log.LogWarning((object)"You may experience issues.");
					ModListHashChecker.instance.hashMismatch = true;
				}
			}
			else
			{
				ModListHashChecker.Log.LogWarning((object)"No expected hash found");
				if (ConfigManager.NoExpectedHashMessage.Value)
				{
					ModListHashChecker.instance.noHashFound = true;
				}
			}
			ModListHashChecker.Log.LogInfo((object)"==========================");
			ModListHashChecker.Log.LogInfo((object)"[Modlist Contents]");
			ModListHashChecker.Log.LogInfo((object)"Mod GUID: Mod Version");
			foreach (KeyValuePair<string, PluginInfo> item in PluginsLoaded)
			{
				ModListHashChecker.Log.LogInfo((object)$"{item.Key}: {item.Value}");
			}
			ModListHashChecker.Log.LogInfo((object)"==========================");
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	public class LobbyCreatedPatch
	{
		[HarmonyPatch("SteamMatchmaking_OnLobbyCreated")]
		[HarmonyPostfix]
		private static void Postfix(Result result, ref Lobby lobby)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)result == 1)
			{
				((Lobby)(ref lobby)).SetData("ModListHash", HashGeneration.DictionaryHashGenerator.GenerateHash(Chainloader.PluginInfos));
				ModListHashChecker.Log.LogInfo((object)("Setting lobby ModHashList to " + HashGeneration.generatedHash));
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	public class StartRoundPatch
	{
		private static int delayTask = ConfigManager.JoinWarningDelay.Value * 1000;

		public static void Postfix()
		{
			if (ModListHashChecker.instance.clientMismatch)
			{
				ModListHashChecker.Log.LogInfo((object)"hash mismatch detected");
				Task.Run(delegate
				{
					Thread.Sleep(delayTask);
					ModListHashChecker.Log.LogInfo((object)"display warning");
					HUDManager.Instance.DisplayTip("Modlist Hash Mismatch", ConfigManager.JoinWarningText.Value ?? "", false, false, "clientHashMismatch");
				});
			}
			else
			{
				ModListHashChecker.Log.LogInfo((object)"no hash mismatch");
			}
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	public class LobbyJoinPatch
	{
		[HarmonyPatch("StartClient")]
		[HarmonyPostfix]
		private static void Postfix(SteamId id)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			ModListHashChecker.Log.LogInfo((object)"Comparing your modlist with the host's modlist.");
			Lobby? currentLobby = GameNetworkManager.Instance.currentLobby;
			object obj;
			if (!currentLobby.HasValue)
			{
				obj = null;
			}
			else
			{
				Lobby valueOrDefault = currentLobby.GetValueOrDefault();
				obj = ((Lobby)(ref valueOrDefault)).GetData("ModListHash");
			}
			string text = (string)obj;
			if (text == null)
			{
				ModListHashChecker.Log.LogWarning((object)"Host does not have a modlist hash.");
				return;
			}
			ModListHashChecker.Log.LogInfo((object)("Host's modlist hash: " + text));
			ModListHashChecker.Log.LogInfo((object)("Your modlist hash: " + HashGeneration.generatedHash));
			if (text == HashGeneration.generatedHash)
			{
				ModListHashChecker.Log.LogInfo((object)"Your modlist matches the host's modlist.");
				return;
			}
			ModListHashChecker.Log.LogWarning((object)"Your modlist does not match the host's modlist.");
			ModListHashChecker.Log.LogWarning((object)"You may experience issues.");
			ModListHashChecker.instance.clientMismatch = true;
		}
	}
	public class MenuMessagesPatch
	{
		[HarmonyPatch(typeof(MenuManager), "OnEnable")]
		public class EnablePatch : MonoBehaviour
		{
			public static void Postfix(ref MenuManager __instance)
			{
				if (ModListHashChecker.instance.hashMismatch && ConfigManager.MenuWarning.Value)
				{
					MenuMessage(__instance, ConfigManager.WarningButtonResetText.Value, ConfigManager.WarningButtonIgnoreText.Value, ConfigManager.WarningMessageText.Value);
				}
				else if (ModListHashChecker.instance.noHashFound && ConfigManager.NoExpectedHashMessage.Value)
				{
					MenuMessage(__instance, ConfigManager.NoHashLeftButtonText.Value, ConfigManager.NoHashRightButtonText.Value, ConfigManager.NoHashMessageText.Value);
				}
				else
				{
					ModListHashChecker.Log.LogInfo((object)"Not sending any messages");
				}
			}

			private static void ResetConfigHash()
			{
				ModListHashChecker.Log.LogInfo((object)"Setting expected hash to current hash.");
				ConfigManager.ExpectedModListHash.Value = HashGeneration.generatedHash;
				ModListHashChecker.instance.hashMismatch = false;
				ModListHashChecker.instance.noHashFound = false;
			}

			private static void MenuMessage(MenuManager menuInstance, string leftButton, string rightButton, string messageText)
			{
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Expected O, but got Unknown
				//IL_016f: Unknown result type (might be due to invalid IL or missing references)
				//IL_014c: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)menuInstance != (Object)null && (Object)(object)menuInstance.menuNotification != (Object)null)
				{
					Button val = Object.Instantiate<Button>(menuInstance.menuNotification.GetComponentInChildren<Button>());
					((Component)val).transform.SetParent(menuInstance.menuNotification.transform, false);
					TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>();
					((TMP_Text)componentInChildren).text = "[ " + leftButton + " ]";
					((UnityEvent)val.onClick).AddListener(new UnityAction(ResetConfigHash));
					if (!menuInstance.isInitScene)
					{
						Debug.Log((object)("Displaying menu notification: " + messageText));
						((TMP_Text)menuInstance.menuNotificationText).text = messageText;
						((TMP_Text)menuInstance.menuNotificationButtonText).text = "[ " + rightButton + " ]";
						menuInstance.menuNotification.SetActive(true);
						Vector3 localPosition = default(Vector3);
						((Vector3)(ref localPosition))..ctor(62f, -45f, 0f);
						Vector3 localPosition2 = default(Vector3);
						((Vector3)(ref localPosition2))..ctor(-78f, -45f, 0f);
						for (int i = 0; i < menuInstance.menuNotification.GetComponentsInChildren<Button>().Length; i++)
						{
							if (i == 0)
							{
								EventSystem.current.SetSelectedGameObject(((Component)menuInstance.menuNotification.GetComponentsInChildren<Button>()[i]).gameObject);
								((Component)menuInstance.menuNotification.GetComponentsInChildren<Button>()[i]).gameObject.transform.localPosition = localPosition;
							}
							else
							{
								((Component)menuInstance.menuNotification.GetComponentsInChildren<Button>()[i]).gameObject.transform.localPosition = localPosition2;
							}
						}
					}
					ModListHashChecker.Log.LogInfo((object)"menu message sent");
				}
				else
				{
					ModListHashChecker.Log.LogInfo((object)"handling null menuNotification");
				}
			}
		}
	}
	[BepInPlugin("TeamMLC.ModlistHashChecker", "ModlistHashChecker", "0.1.2")]
	public class ModListHashChecker : BaseUnityPlugin
	{
		public static class PluginInfo
		{
			public const string PLUGIN_GUID = "TeamMLC.ModlistHashChecker";

			public const string PLUGIN_NAME = "ModlistHashChecker";

			public const string PLUGIN_VERSION = "0.1.2";
		}

		public static ModListHashChecker instance;

		public bool noHashFound = false;

		public bool hashMismatch = false;

		public bool clientMismatch = false;

		internal static ManualLogSource Log;

		private void Awake()
		{
			instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"ModListHashChecker loaded with version 0.1.2!");
			ConfigManager.Init(((BaseUnityPlugin)this).Config);
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}