Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of vhvac v1.8.5
vhvac.dll
Decompiled 5 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("vhvac")] [assembly: AssemblyDescription("Valheim Anti-Cheat - Überprüft Mod-Versionen und erlaubte Mods zwischen Server und Client")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("vh")] [assembly: AssemblyProduct("vhvac")] [assembly: AssemblyCopyright("Copyright © vh 2024-2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a1b2c3d4-e5f6-7890-abcd-ef1234567890")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace vhvac { public static class AntiCheatMonitor { public class PlayerStats { public long PlayerId { get; set; } public Vector3 LastPosition { get; set; } public float LastCheckTime { get; set; } public int ViolationCount { get; set; } } private static readonly Dictionary<long, PlayerStats> PlayerTracking = new Dictionary<long, PlayerStats>(); public static void RegisterPlayer(long playerId) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (!PlayerTracking.ContainsKey(playerId)) { PlayerTracking[playerId] = new PlayerStats { PlayerId = playerId, LastPosition = Vector3.zero, LastCheckTime = Time.time, ViolationCount = 0 }; } } public static void UnregisterPlayer(long playerId) { PlayerTracking.Remove(playerId); } } [HarmonyPatch(typeof(ZNet), "RPC_CharacterID")] public static class PlayerConnectionMonitor { private static void Postfix(ZNet __instance, ZRpc rpc, ZDOID characterID) { if (__instance.IsServer()) { ZNetPeer peer = __instance.GetPeer(rpc); if (peer != null) { VhVacPlugin.VhLogger.LogDebug((object)$"[VHVAC] Spieler verbunden: {peer.m_playerName} (UID: {peer.m_uid})"); AntiCheatMonitor.RegisterPlayer(peer.m_uid); } } } } [HarmonyPatch(typeof(ZNet), "RPC_Disconnect")] public static class PlayerDisconnectMonitor { private static void Prefix(ZNet __instance, ZRpc rpc) { if (__instance.IsServer()) { ZNetPeer peer = __instance.GetPeer(rpc); if (peer != null) { VhVacPlugin.VhLogger.LogDebug((object)("[VHVAC] Spieler getrennt: " + peer.m_playerName)); AntiCheatMonitor.UnregisterPlayer(peer.m_uid); } } } } public static class JotunnPatcher { private const string JotunnHarmonyId = "com.jotunn.jotunn"; public static void RemoveJotunnCompatibilityPatches() { try { VhVacPlugin.VhLogger.LogInfo((object)"[VHVAC] Suche nach Jotunn ModCompatibility Patches..."); List<MethodBase> list = Harmony.GetAllPatchedMethods().ToList(); int num = 0; foreach (MethodBase item in list) { Patches patchInfo = Harmony.GetPatchInfo(item); if (patchInfo == null) { continue; } List<Patch> list2 = patchInfo.Prefixes.Where((Patch p) => IsJotunnModCompatibilityPatch(p)).ToList(); List<Patch> list3 = patchInfo.Postfixes.Where((Patch p) => IsJotunnModCompatibilityPatch(p)).ToList(); if (list2.Count == 0 && list3.Count == 0) { continue; } string text = item.DeclaringType?.Name + "." + item.Name; foreach (Patch item2 in list2) { VhVacPlugin.VhLogger.LogInfo((object)("[VHVAC] Entferne Jotunn Prefix von " + text + ": " + item2.PatchMethod.Name)); RemovePatch(item, item2); num++; } foreach (Patch item3 in list3) { VhVacPlugin.VhLogger.LogInfo((object)("[VHVAC] Entferne Jotunn Postfix von " + text + ": " + item3.PatchMethod.Name)); RemovePatch(item, item3); num++; } } if (num > 0) { VhVacPlugin.VhLogger.LogInfo((object)$"[VHVAC] {num} Jotunn ModCompatibility Patches erfolgreich entfernt!"); } else { VhVacPlugin.VhLogger.LogDebug((object)"[VHVAC] Keine Jotunn ModCompatibility Patches gefunden (Jotunn nicht installiert oder bereits entfernt)"); } } catch (Exception ex) { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Fehler beim Entfernen von Jotunn Patches: " + ex.Message)); } } private static bool IsJotunnModCompatibilityPatch(Patch patch) { if (patch.owner == "com.jotunn.jotunn") { Type declaringType = patch.PatchMethod.DeclaringType; if (declaringType != null && (declaringType.FullName ?? declaringType.Name).Contains("ModCompatibility")) { return true; } } return false; } private static void RemovePatch(MethodBase original, Patch patch) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("vhvac.patcher").Unpatch(original, patch.PatchMethod); } catch (Exception ex) { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Konnte Patch nicht entfernen: " + ex.Message)); } } } [BepInPlugin("vhvac.core", "vhvac", "1.8.5")] public class VhVacPlugin : BaseUnityPlugin { internal const string ModName = "vhvac"; internal const string ModVersion = "1.8.5"; private const string ModGUID = "vhvac.core"; private static string ConfigFileName = "vhvac.core.cfg"; private static string ConfigFileFullPath; internal static string ConnectionError; internal static int ErrorCount; private readonly Harmony _harmony = new Harmony("vhvac.core"); public static readonly ManualLogSource VhLogger; public static readonly ConfigSync ConfigSync; internal static VhVacPlugin Instance; public static string PluginsHash; public static Dictionary<string, ModInfo> InstalledMods; private static bool _modsCollected; private static ConfigFile _effectiveConfig; private static bool _usingTempClientConfig; public static ConfigEntry<bool> ModEnabled; public static ConfigEntry<bool> ConfigLocked; public static ConfigEntry<bool> ForceExactMods; public static ConfigEntry<bool> AdminBypass; public static ConfigEntry<bool> EnableHashCheck; public static ConfigEntry<bool> EnableVersionCheck; public static ConfigEntry<bool> EnableAllowedModsCheck; public static ConfigEntry<string> AllowedMods; public static ConfigEntry<bool> DebugMode; public static ConfigEntry<string> KickMessageVersionMismatch; public static ConfigEntry<string> KickMessageHashMismatch; public static ConfigEntry<string> KickMessageUnallowedMod; public static ConfigEntry<string> KickMessageMissingMod; public static bool IsServer => (int)SystemInfo.graphicsDeviceType == 4; private void Awake() { Instance = this; InitializeEffectiveConfig(); InitConfig(); if (ModEnabled.Value) { _harmony.PatchAll(Assembly.GetExecutingAssembly()); JotunnPatcher.RemoveJotunnCompatibilityPatches(); VhLogger.LogInfo((object)"[VHVAC] Valheim Anti-Cheat v1.8.5 geladen!"); } } private void Start() { if (!ModEnabled.Value) { return; } CollectModInformation(); PluginsHash = HashHelper.CreateMd5ForPlugins(InstalledMods.Values.ToList()); VhLogger.LogInfo((object)("[VHVAC] Plugin Hash: " + PluginsHash)); VhLogger.LogInfo((object)$"[VHVAC] {InstalledMods.Count} Mods gefunden"); if (DebugMode.Value) { foreach (KeyValuePair<string, ModInfo> installedMod in InstalledMods) { VhLogger.LogDebug((object)("[VHVAC] Mod: " + installedMod.Key + " v" + installedMod.Value.Version + " - Hash: " + installedMod.Value.Hash)); } } if (IsServer) { VhLogger.LogInfo((object)"[VHVAC] Server-Modus aktiv - Warte auf Client-Verbindungen"); } else { VhLogger.LogInfo((object)"[VHVAC] Client-Modus aktiv"); } } public static void EnsureModsCollected() { if (!_modsCollected || InstalledMods.Count == 0) { Instance?.CollectModInformation(); } } private void InitConfig() { ModEnabled = _effectiveConfig.Bind<bool>("1. Allgemein", "Aktiviert", true, "Aktiviert oder deaktiviert den VHVAC Mod"); ConfigLocked = _effectiveConfig.Bind<bool>("1. Allgemein", "Config gesperrt", true, "Wenn aktiviert, können nur Admins die Konfiguration ändern"); ConfigSync.AddLockingConfigEntry<bool>(ConfigLocked); DebugMode = _effectiveConfig.Bind<bool>("1. Allgemein", "Debug Modus", false, "Aktiviert erweiterte Debug-Ausgaben"); ForceExactMods = _effectiveConfig.Bind<bool>("2. Anti-Cheat", "Exakte Mods erzwingen", true, "Client muss exakt die gleichen Mods wie der Server haben"); ConfigSync.AddConfigEntry<bool>(ForceExactMods); AdminBypass = _effectiveConfig.Bind<bool>("2. Anti-Cheat", "Admin Bypass", true, "Admins umgehen alle Prüfungen"); ConfigSync.AddConfigEntry<bool>(AdminBypass); EnableHashCheck = _effectiveConfig.Bind<bool>("2. Anti-Cheat", "Hash Prüfung", true, "Überprüft ob der MD5-Hash der Mods übereinstimmt"); ConfigSync.AddConfigEntry<bool>(EnableHashCheck); EnableVersionCheck = _effectiveConfig.Bind<bool>("2. Anti-Cheat", "Versions Prüfung", true, "Überprüft ob die Mod-Versionen übereinstimmen"); ConfigSync.AddConfigEntry<bool>(EnableVersionCheck); EnableAllowedModsCheck = _effectiveConfig.Bind<bool>("2. Anti-Cheat", "Erlaubte Mods Prüfung", true, "Nur Mods aus der erlaubten Liste werden akzeptiert"); ConfigSync.AddConfigEntry<bool>(EnableAllowedModsCheck); AllowedMods = _effectiveConfig.Bind<string>("2. Anti-Cheat", "Erlaubte Mods", "", "Komma-getrennte Liste von erlaubten Mod-GUIDs. Leer = alle Server-Mods sind erlaubt. Beispiel: author.modname,otherauthor.othermod"); ConfigSync.AddConfigEntry<string>(AllowedMods); KickMessageVersionMismatch = _effectiveConfig.Bind<string>("3. Nachrichten", "Kick Versions Mismatch", "Mod-Version stimmt nicht überein: {0} (Deine: {1}, Server: {2})", "Nachricht bei Versions-Mismatch. {0}=ModName, {1}=ClientVersion, {2}=ServerVersion"); KickMessageHashMismatch = _effectiveConfig.Bind<string>("3. Nachrichten", "Kick Hash Mismatch", "Mod-Dateien stimmen nicht überein. Bitte installiere die gleichen Mods wie der Server.", "Nachricht bei Hash-Mismatch"); KickMessageUnallowedMod = _effectiveConfig.Bind<string>("3. Nachrichten", "Kick Unerlaubter Mod", "Unerlaubter Mod gefunden: {0}", "Nachricht bei unerlaubtem Mod. {0}=ModName"); KickMessageMissingMod = _effectiveConfig.Bind<string>("3. Nachrichten", "Kick Fehlender Mod", "Fehlender Mod: {0}", "Nachricht bei fehlendem Mod. {0}=ModName"); } private void InitializeEffectiveConfig() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (_effectiveConfig != null) { return; } string path = Path.Combine(Paths.ConfigPath, "vhvac.core.cfg"); bool flag = Application.isBatchMode; try { flag |= Environment.GetCommandLineArgs().Any((string a) => string.Equals(a, "-server", StringComparison.OrdinalIgnoreCase)); } catch { } if (flag || File.Exists(path)) { _effectiveConfig = ((BaseUnityPlugin)this).Config; _usingTempClientConfig = false; return; } string cachePath = Paths.CachePath; string text = Path.Combine(cachePath, "vhvac.core.client.tmp.cfg"); try { Directory.CreateDirectory(cachePath); } catch { } _effectiveConfig = new ConfigFile(text, false); try { _effectiveConfig.SaveOnConfigSet = false; } catch { } _usingTempClientConfig = true; VhLogger.LogInfo((object)"[VHVAC] Client-Modus: Keine Config-Datei erstellt (kein vhvac.core.cfg)"); } private void CollectModInformation() { InstalledMods.Clear(); if (Chainloader.PluginInfos != null) { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; if (((value != null) ? value.Metadata : null) != null) { ModInfo value2 = new ModInfo { GUID = value.Metadata.GUID, Name = value.Metadata.Name, Version = value.Metadata.Version.ToString(), Hash = HashHelper.ComputeFileHash(value.Location) }; if (!InstalledMods.ContainsKey(value.Metadata.GUID)) { InstalledMods[value.Metadata.GUID] = value2; } } } } try { ScanPluginDlls(); } catch (Exception ex) { VhLogger.LogWarning((object)("[VHVAC] Fehler beim Scannen der Plugin-DLLs: " + ex.Message)); } _modsCollected = true; if (DebugMode.Value) { VhLogger.LogDebug((object)$"[VHVAC] Insgesamt {InstalledMods.Count} Mods nach vollständigem Scan"); } } private void ScanPluginDlls() { string[] files = Directory.GetFiles(Paths.PluginPath, "*.dll", SearchOption.AllDirectories); foreach (string text in files) { try { Type[] types = Assembly.LoadFrom(text).GetTypes(); for (int j = 0; j < types.Length; j++) { BepInPlugin customAttribute = ((MemberInfo)types[j]).GetCustomAttribute<BepInPlugin>(); if (customAttribute != null && !InstalledMods.ContainsKey(customAttribute.GUID)) { ModInfo modInfo = new ModInfo { GUID = customAttribute.GUID, Name = customAttribute.Name, Version = customAttribute.Version.ToString(), Hash = HashHelper.ComputeFileHash(text) }; InstalledMods[customAttribute.GUID] = modInfo; if (DebugMode.Value) { VhLogger.LogDebug((object)("[VHVAC] DLL-Scan gefunden: " + modInfo.GUID + " v" + modInfo.Version)); } } } } catch (ReflectionTypeLoadException) { } catch (BadImageFormatException) { } catch (Exception ex3) { if (DebugMode.Value) { VhLogger.LogDebug((object)("[VHVAC] Konnte DLL nicht scannen: " + Path.GetFileName(text) + " - " + ex3.Message)); } } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } static VhVacPlugin() { //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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; ErrorCount = 0; VhLogger = Logger.CreateLogSource("vhvac"); ConfigSync = new ConfigSync("vhvac.core") { DisplayName = "vhvac", CurrentVersion = "1.8.5", MinimumRequiredVersion = "1.8.5" }; PluginsHash = ""; InstalledMods = new Dictionary<string, ModInfo>(); _modsCollected = false; _usingTempClientConfig = false; } } public class ModInfo { public string GUID { get; set; } public string Name { get; set; } public string Version { get; set; } public string Hash { get; set; } public ZPackage ToZPackage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(GUID ?? ""); val.Write(Name ?? ""); val.Write(Version ?? ""); val.Write(Hash ?? ""); return val; } public static ModInfo FromZPackage(ZPackage pkg) { return new ModInfo { GUID = pkg.ReadString(), Name = pkg.ReadString(), Version = pkg.ReadString(), Hash = pkg.ReadString() }; } } public static class HashHelper { public static string CreateMd5ForPlugins(List<ModInfo> mods) { List<ModInfo> source = mods.OrderBy((ModInfo m) => m.GUID).ToList(); using MD5 mD = MD5.Create(); string s = string.Join("|", source.Select((ModInfo m) => m.GUID + ":" + m.Version)); byte[] bytes = Encoding.UTF8.GetBytes(s); return BitConverter.ToString(mD.ComputeHash(bytes)).Replace("-", "").ToLower(); } public static string CreateMd5ForFolder(string path) { List<string> list = (from p in Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories) orderby p select p).ToList(); using MD5 mD = MD5.Create(); for (int i = 0; i < list.Count; i++) { byte[] array = File.ReadAllBytes(list[i]); if (i == list.Count - 1) { mD.TransformFinalBlock(array, 0, array.Length); } else { mD.TransformBlock(array, 0, array.Length, array, 0); } } return BitConverter.ToString(mD.Hash).Replace("-", "").ToLower(); } public static string ComputeFileHash(string filePath) { if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) { return ""; } using MD5 mD = MD5.Create(); using FileStream inputStream = File.OpenRead(filePath); return BitConverter.ToString(mD.ComputeHash(inputStream)).Replace("-", "").ToLower(); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public static class RegisterAndCheckVersion { private const string RpcName = "VHVAC_ModCheck"; private const string RpcResponseName = "VHVAC_ModCheckResponse"; private static void Prefix(ZNetPeer peer, ref ZNet __instance) { VhVacPlugin.EnsureModsCollected(); VhVacPlugin.VhLogger.LogDebug((object)"[VHVAC] Registriere Mod-Check RPC Handler"); peer.m_rpc.Register<ZPackage>("VHVAC_ModCheck", (Action<ZRpc, ZPackage>)RPC_ModCheck); peer.m_rpc.Register<ZPackage>("VHVAC_ModCheckResponse", (Action<ZRpc, ZPackage>)RPC_ModCheckResponse); VhVacPlugin.VhLogger.LogInfo((object)$"[VHVAC] Sende Mod-Informationen zur Prüfung ({VhVacPlugin.InstalledMods.Count} Mods)"); ZPackage val = CreateModInfoPackage(); peer.m_rpc.Invoke("VHVAC_ModCheck", new object[1] { val }); } private static ZPackage CreateModInfoPackage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(VhVacPlugin.PluginsHash); val.Write(VhVacPlugin.InstalledMods.Count); foreach (ModInfo value in VhVacPlugin.InstalledMods.Values) { val.Write(value.GUID); val.Write(value.Name); val.Write(value.Version); val.Write(value.Hash); } return val; } private static void RPC_ModCheck(ZRpc rpc, ZPackage pkg) { //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown string text = pkg.ReadString(); int num = pkg.ReadInt(); Dictionary<string, ModInfo> dictionary = new Dictionary<string, ModInfo>(); for (int i = 0; i < num; i++) { ModInfo modInfo = new ModInfo { GUID = pkg.ReadString(), Name = pkg.ReadString(), Version = pkg.ReadString(), Hash = pkg.ReadString() }; dictionary[modInfo.GUID] = modInfo; } VhVacPlugin.VhLogger.LogInfo((object)$"[VHVAC] Empfangen: Hash={text}, {num} Mods"); if (!ZNet.instance.IsServer()) { return; } bool flag = false; string text2 = ""; if (VhVacPlugin.AdminBypass.Value) { string hostName = rpc.GetSocket().GetHostName(); if (ZNet.instance.m_adminList != null && ZNet.instance.m_adminList.Contains(hostName)) { VhVacPlugin.VhLogger.LogInfo((object)("[VHVAC] Admin-Bypass für " + hostName)); flag = true; } } if (!flag) { text2 = PerformModChecks(dictionary, text, rpc); flag = string.IsNullOrEmpty(text2); } if (flag) { VhVacPlugin.VhLogger.LogInfo((object)("[VHVAC] Client validiert: " + rpc.GetSocket().GetHostName())); RpcHandlers.ValidatedPeers.Add(rpc); ZPackage val = new ZPackage(); val.Write(true); val.Write(""); rpc.Invoke("VHVAC_ModCheckResponse", new object[1] { val }); } else { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Kick: " + rpc.GetSocket().GetHostName() + " - " + text2)); ZPackage val2 = new ZPackage(); val2.Write(false); val2.Write(text2); rpc.Invoke("VHVAC_ModCheckResponse", new object[1] { val2 }); rpc.Invoke("Error", new object[1] { 3 }); } } private static void RPC_ModCheckResponse(ZRpc rpc, ZPackage pkg) { bool num = pkg.ReadBool(); string text = pkg.ReadString(); if (num) { VhVacPlugin.VhLogger.LogInfo((object)"[VHVAC] Server hat Mod-Prüfung bestätigt!"); VhVacPlugin.ConnectionError = ""; } else { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Server hat Verbindung abgelehnt: " + text)); VhVacPlugin.ConnectionError = "[VHVAC] " + text; } } private static string PerformModChecks(Dictionary<string, ModInfo> remoteMods, string remoteHash, ZRpc rpc) { List<(string, string)> list = new List<(string, string)>(); List<(string, string)> list2 = new List<(string, string)>(); List<(string, string, string)> list3 = new List<(string, string, string)>(); if (VhVacPlugin.ForceExactMods.Value) { foreach (KeyValuePair<string, ModInfo> remoteMod in remoteMods) { if (!VhVacPlugin.InstalledMods.ContainsKey(remoteMod.Key)) { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Client hat unerlaubten Mod: " + remoteMod.Value.Name + " (" + remoteMod.Key + ")")); list.Add((remoteMod.Value.Name, remoteMod.Value.Version)); } } } if (VhVacPlugin.EnableAllowedModsCheck.Value) { List<string> allowedModsList = GetAllowedModsList(); if (allowedModsList.Count > 0) { foreach (KeyValuePair<string, ModInfo> clientMod in remoteMods) { if (!allowedModsList.Contains<string>(clientMod.Key, StringComparer.OrdinalIgnoreCase) && !list.Any<(string, string)>(((string Name, string Version) m) => m.Name == clientMod.Value.Name)) { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Client hat Mod der nicht auf der Whitelist ist: " + clientMod.Value.Name)); list.Add((clientMod.Value.Name, clientMod.Value.Version)); } } } } if (VhVacPlugin.ForceExactMods.Value) { foreach (KeyValuePair<string, ModInfo> installedMod in VhVacPlugin.InstalledMods) { if (!remoteMods.ContainsKey(installedMod.Key)) { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Client fehlt Mod: " + installedMod.Value.Name + " (" + installedMod.Key + ")")); list2.Add((installedMod.Value.Name, installedMod.Value.Version)); } } } if (VhVacPlugin.EnableVersionCheck.Value) { foreach (KeyValuePair<string, ModInfo> installedMod2 in VhVacPlugin.InstalledMods) { if (remoteMods.TryGetValue(installedMod2.Key, out var value) && value.Version != installedMod2.Value.Version) { VhVacPlugin.VhLogger.LogWarning((object)("[VHVAC] Version Mismatch: " + installedMod2.Value.Name + " - Client: " + value.Version + ", Server: " + installedMod2.Value.Version)); list3.Add((installedMod2.Value.Name, value.Version, installedMod2.Value.Version)); } } } if (list.Count > 0 || list2.Count > 0 || list3.Count > 0) { return FormatCombinedTable(list, list2, list3); } if (VhVacPlugin.EnableHashCheck.Value && remoteHash != VhVacPlugin.PluginsHash) { if (VhVacPlugin.DebugMode.Value) { VhVacPlugin.VhLogger.LogDebug((object)("[VHVAC] Hash-Mismatch: Server=" + VhVacPlugin.PluginsHash + ", Client=" + remoteHash)); } VhVacPlugin.VhLogger.LogWarning((object)"[VHVAC] Hash-Mismatch obwohl alle anderen Prüfungen bestanden"); return VhVacPlugin.KickMessageHashMismatch.Value; } return null; } private static string FormatCombinedTable(List<(string Name, string Version)> unallowed, List<(string Name, string ServerVersion)> missing, List<(string Name, string ClientVersion, string ServerVersion)> versionMismatch) { StringBuilder stringBuilder = new StringBuilder(); int num = (VhVacPlugin.ErrorCount = unallowed.Count + missing.Count + versionMismatch.Count); stringBuilder.AppendLine("<color=#AAAAAA> Typ Mod Client Server</color>"); stringBuilder.AppendLine(); int num2 = 0; foreach (var item in unallowed) { if (num2 >= 10) { break; } string text; if (item.Name.Length <= 22) { (text, _) = item; } else { text = item.Name.Substring(0, 19) + "..."; } string arg = text; stringBuilder.AppendLine($"<color=#FF6666> ✗ {arg,-24} {item.Version,-10} -</color>"); num2++; } foreach (var item2 in missing) { if (num2 >= 10) { break; } string text2; if (item2.Name.Length <= 22) { (text2, _) = item2; } else { text2 = item2.Name.Substring(0, 19) + "..."; } string arg2 = text2; stringBuilder.AppendLine($"<color=#FFCC66> ⚠ {arg2,-24} - {item2.ServerVersion}</color>"); num2++; } foreach (var item3 in versionMismatch) { if (num2 >= 10) { break; } string text3; if (item3.Name.Length <= 22) { (text3, _, _) = item3; } else { text3 = item3.Name.Substring(0, 19) + "..."; } string arg3 = text3; stringBuilder.AppendLine($"<color=#66CCFF> ↔ {arg3,-24}</color> <color=#FF8888>{item3.ClientVersion,-10}</color> <color=#88FF88>{item3.ServerVersion}</color>"); num2++; } int num3 = num - num2; if (num3 > 0) { stringBuilder.AppendLine($"<color=#AAAAAA> ... +{num3} weitere Probleme</color>"); } stringBuilder.AppendLine(); stringBuilder.Append("<color=#FF6666>✗ Unerlaubt</color> "); stringBuilder.Append("<color=#FFCC66>⚠ Fehlt</color> "); stringBuilder.Append("<color=#66CCFF>↔ Falsche Version</color>"); return stringBuilder.ToString(); } private static List<string> GetAllowedModsList() { if (string.IsNullOrWhiteSpace(VhVacPlugin.AllowedMods.Value)) { return new List<string>(); } return (from s in VhVacPlugin.AllowedMods.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim()).ToList(); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] public class ShowConnectionError { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__2_0; internal void <CreateCustomPanel>b__2_0() { Object.Destroy((Object)(object)_customPanel); _customPanel = null; } } private static GameObject _customPanel; private static void Postfix(FejdStartup __instance) { if (__instance.m_connectionFailedPanel.activeSelf && !string.IsNullOrEmpty(VhVacPlugin.ConnectionError)) { __instance.m_connectionFailedPanel.SetActive(false); CreateCustomPanel(__instance); VhVacPlugin.VhLogger.LogDebug((object)"[VHVAC] Custom Panel erstellt"); VhVacPlugin.ConnectionError = ""; } } private static void CreateCustomPanel(FejdStartup fejdStartup) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Expected O, but got Unknown //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_047d: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Expected O, but got Unknown if ((Object)(object)_customPanel != (Object)null) { Object.Destroy((Object)(object)_customPanel); } Transform parent = fejdStartup.m_connectionFailedPanel.transform.parent; if ((Object)(object)parent == (Object)null) { VhVacPlugin.VhLogger.LogWarning((object)"[VHVAC] Kein Parent Transform gefunden!"); return; } TMP_FontAsset font = fejdStartup.m_connectionFailedError.font; Material fontMaterial = fejdStartup.m_connectionFailedError.fontMaterial; int num = Math.Min(VhVacPlugin.ErrorCount, 10); int num2 = Math.Min(num, 10); float num3 = 700f; float val = 120f + (float)num2 * 30f + 60f + 30f + 50f + 20f; val = Math.Max(val, 370f); val = Math.Min(val, 670f); VhVacPlugin.VhLogger.LogInfo((object)$"[VHVAC] Panel size: {num3}x{val} for {num} errors"); _customPanel = new GameObject("VHVAC_ErrorPanel"); _customPanel.transform.SetParent(parent, false); RectTransform obj = _customPanel.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0.5f, 0.5f); obj.anchorMax = new Vector2(0.5f, 0.5f); obj.pivot = new Vector2(0.5f, 0.5f); obj.sizeDelta = new Vector2(num3, val); obj.anchoredPosition = Vector2.zero; ((Graphic)_customPanel.AddComponent<Image>()).color = new Color(0.15f, 0.1f, 0.05f, 0.98f); Outline obj2 = _customPanel.AddComponent<Outline>(); ((Shadow)obj2).effectColor = new Color(0.85f, 0.65f, 0.2f, 1f); ((Shadow)obj2).effectDistance = new Vector2(2f, -2f); GameObject val2 = new GameObject("ErrorText"); val2.transform.SetParent(_customPanel.transform, false); RectTransform obj3 = val2.AddComponent<RectTransform>(); obj3.anchorMin = new Vector2(0f, 0f); obj3.anchorMax = new Vector2(1f, 1f); obj3.offsetMin = new Vector2(20f, 85f); obj3.offsetMax = new Vector2(-20f, -10f); TextMeshProUGUI obj4 = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj4).font = font; ((TMP_Text)obj4).fontMaterial = fontMaterial; ((TMP_Text)obj4).fontSize = 24f; ((TMP_Text)obj4).alignment = (TextAlignmentOptions)258; ((Graphic)obj4).color = Color.white; ((TMP_Text)obj4).text = "<size=32><b>Verbindung fehlgeschlagen</b></size>\n\n<size=22>" + VhVacPlugin.ConnectionError.Replace("[VHVAC] ", "") + "</size>"; GameObject val3 = new GameObject("HelpText"); val3.transform.SetParent(_customPanel.transform, false); RectTransform obj5 = val3.AddComponent<RectTransform>(); obj5.anchorMin = new Vector2(0f, 0f); obj5.anchorMax = new Vector2(1f, 0f); obj5.pivot = new Vector2(0.5f, 0f); obj5.sizeDelta = new Vector2(0f, 25f); obj5.anchoredPosition = new Vector2(0f, 55f); TextMeshProUGUI obj6 = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj6).font = font; ((TMP_Text)obj6).fontMaterial = fontMaterial; ((TMP_Text)obj6).text = "Hilfe: https://valheim-server.de/forum"; ((TMP_Text)obj6).fontSize = 18f; ((TMP_Text)obj6).alignment = (TextAlignmentOptions)514; ((Graphic)obj6).color = new Color(0.7f, 0.7f, 0.7f, 1f); GameObject val4 = new GameObject("OKButton"); val4.transform.SetParent(_customPanel.transform, false); RectTransform obj7 = val4.AddComponent<RectTransform>(); obj7.anchorMin = new Vector2(0.5f, 0f); obj7.anchorMax = new Vector2(0.5f, 0f); obj7.pivot = new Vector2(0.5f, 0f); obj7.sizeDelta = new Vector2(180f, 40f); obj7.anchoredPosition = new Vector2(0f, 10f); Image val5 = val4.AddComponent<Image>(); ((Graphic)val5).color = new Color(0.6f, 0.4f, 0.2f, 1f); Button obj8 = val4.AddComponent<Button>(); ((Selectable)obj8).targetGraphic = (Graphic)(object)val5; ButtonClickedEvent onClick = obj8.onClick; object obj9 = <>c.<>9__2_0; if (obj9 == null) { UnityAction val6 = delegate { Object.Destroy((Object)(object)_customPanel); _customPanel = null; }; <>c.<>9__2_0 = val6; obj9 = (object)val6; } ((UnityEvent)onClick).AddListener((UnityAction)obj9); GameObject val7 = new GameObject("ButtonText"); val7.transform.SetParent(val4.transform, false); RectTransform obj10 = val7.AddComponent<RectTransform>(); obj10.anchorMin = Vector2.zero; obj10.anchorMax = Vector2.one; obj10.sizeDelta = Vector2.zero; TextMeshProUGUI obj11 = val7.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj11).font = font; ((TMP_Text)obj11).fontMaterial = fontMaterial; ((TMP_Text)obj11).text = "OK"; ((TMP_Text)obj11).fontSize = 28f; ((TMP_Text)obj11).alignment = (TextAlignmentOptions)514; ((Graphic)obj11).color = Color.white; } } [HarmonyPatch(typeof(ZNet), "Disconnect")] public static class RemoveDisconnectedPeerFromVerified { private static void Prefix(ZNetPeer peer, ref ZNet __instance) { if (__instance.IsServer()) { VhVacPlugin.VhLogger.LogInfo((object)("[VHVAC] Peer (" + peer.m_rpc.m_socket.GetHostName() + ") getrennt - entferne aus validierter Liste")); RpcHandlers.ValidatedPeers.Remove(peer.m_rpc); } } } public static class RpcHandlers { public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>(); } }