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)
{
}
}
}