using 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>();
}
}