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 Valheim ServerGuard Client v1.6.0
Valheim-ServerGuard-Client.dll
Decompiled a month agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using ValheimServerGuard.Shared; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("yesu0725")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim ServerGuard Client - companion plugin that attests the client's mod list to a ServerGuard-protected server")] [assembly: AssemblyFileVersion("1.6.0.0")] [assembly: AssemblyInformationalVersion("1.6.0+1f31bf8116fc4846821d0c6e643692b47cd65e03")] [assembly: AssemblyProduct("Valheim-ServerGuard-Client")] [assembly: AssemblyTitle("Valheim-ServerGuard-Client")] [assembly: AssemblyVersion("1.6.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 ValheimServerGuard.Shared { public static class ModsetFingerprint { public static string ComputeStrict(IEnumerable<KeyValuePair<string, string>> entries) { return Sha256Hex(Canonicalize(entries, withHash: true)); } public static string ComputeLoose(IEnumerable<KeyValuePair<string, string>> entries) { return Sha256Hex(Canonicalize(entries, withHash: false)); } public static string Short(string fullHex) { if (!string.IsNullOrEmpty(fullHex) && fullHex.Length >= 8) { return fullHex.Substring(0, 8); } return fullHex ?? ""; } private static string Canonicalize(IEnumerable<KeyValuePair<string, string>> entries, bool withHash) { if (entries == null) { return ""; } List<string> list = (from e in entries where !string.IsNullOrWhiteSpace(e.Key) select (!withHash) ? (e.Key ?? "").ToLowerInvariant() : ((e.Key ?? "").ToLowerInvariant() + "|" + (e.Value ?? "").ToLowerInvariant())).Distinct<string>(StringComparer.Ordinal).OrderBy<string, string>((string s) => s, StringComparer.Ordinal).ToList(); if (list.Count != 0) { return string.Join("\n", list); } return ""; } private static string Sha256Hex(string input) { using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(input ?? ""))).Replace("-", "").ToLowerInvariant(); } } [Serializable] public class ModManifestEntry { public string Guid; public string Name; public string Version; public string Sha256; } [Serializable] public class ModManifest { public string SchemaVersion = "1"; public string Challenge; public long TimestampUtc; public List<ModManifestEntry> Mods = new List<ModManifestEntry>(); public string Hmac; public string CanonicalForHmac() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(SchemaVersion ?? "").Append('|'); stringBuilder.Append(Challenge ?? "").Append('|'); stringBuilder.Append(TimestampUtc).Append('|'); List<ModManifestEntry> list = new List<ModManifestEntry>(Mods ?? new List<ModManifestEntry>()); list.Sort(delegate(ModManifestEntry a, ModManifestEntry b) { string strA = ((!string.IsNullOrEmpty(a?.Guid)) ? a.Guid : (a?.Name ?? "")); string strB = ((!string.IsNullOrEmpty(b?.Guid)) ? b.Guid : (b?.Name ?? "")); return string.CompareOrdinal(strA, strB); }); foreach (ModManifestEntry item in list) { stringBuilder.Append(item?.Guid ?? "").Append(':'); stringBuilder.Append(item?.Name ?? "").Append(':'); stringBuilder.Append(item?.Version ?? "").Append(':'); stringBuilder.Append(item?.Sha256 ?? "").Append(';'); } return stringBuilder.ToString(); } public static string ComputeHmac(string canonical, string secret) { if (string.IsNullOrEmpty(secret)) { return ""; } using HMACSHA256 hMACSHA = new HMACSHA256(Encoding.UTF8.GetBytes(secret)); return Convert.ToBase64String(hMACSHA.ComputeHash(Encoding.UTF8.GetBytes(canonical ?? ""))); } public static bool ConstantTimeEquals(string a, string b) { if (a == null || b == null) { return false; } if (a.Length != b.Length) { return false; } int num = 0; for (int i = 0; i < a.Length; i++) { num |= a[i] ^ b[i]; } return num == 0; } } } namespace ValheimServerGuardClient { [BepInPlugin("com.taeguk.valheim.serverguard.client", "Valheim ServerGuard Client", "1.6.0")] public class ClientPlugin : BaseUnityPlugin { private class ClientSettings { public string SharedSecret { get; set; } = ""; public bool QuickLoginEnabled { get; set; } public string ServerAddress { get; set; } = ""; public int ServerPort { get; set; } = 2456; public string ServerPassword { get; set; } = ""; public string ServerName { get; set; } = ""; public string ServerDescription { get; set; } = ""; public string ServerLogoPath { get; set; } = ""; } [HarmonyPatch(typeof(Player), "PlacePiece")] public static class Patch_PlacePiece_Report { public static void Postfix(Player __instance, Piece piece, Vector3 pos) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) try { if (IsActiveMultiplayerClient() && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)piece == (Object)null)) { GameObject gameObject = ((Component)piece).gameObject; string text = ((gameObject != null) ? ((Object)gameObject).name : null) ?? "unknown"; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num > 0) { text = text.Substring(0, num).Trim(); } Instance?.SendBuildPlace(text, pos); } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] PlacePiece hook error: " + ex.Message)); } } } } private sealed class LastHitInfo { public Character Attacker; public DateTime At; } [HarmonyPatch(typeof(WearNTear), "Damage")] public static class Patch_WearNTear_Damage_TrackClient { public static void Prefix(WearNTear __instance, HitData hit) { try { if (IsActiveMultiplayerClient() && !((Object)(object)__instance == (Object)null) && hit != null) { Character attacker = null; try { attacker = hit.GetAttacker(); } catch { } LastHitInfo value = new LastHitInfo { Attacker = attacker, At = DateTime.UtcNow }; _clientLastHitOnPiece.Remove(__instance); _clientLastHitOnPiece.Add(__instance, value); } } catch { } } } [HarmonyPatch(typeof(WearNTear), "Destroy")] public static class Patch_WearNTear_Destroy_ClientReport { public static void Prefix(WearNTear __instance) { //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) try { if (!IsActiveMultiplayerClient() || (Object)(object)__instance == (Object)null) { return; } GameObject gameObject = ((Component)__instance).gameObject; string text = ((gameObject != null) ? ((Object)gameObject).name : null) ?? "unknown"; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num > 0) { text = text.Substring(0, num).Trim(); } Vector3 position; try { position = ((Component)__instance).transform.position; } catch { return; } string text2 = "unknown"; string text3 = ""; if (_clientLastHitOnPiece.TryGetValue(__instance, out var value) && value != null) { _clientLastHitOnPiece.Remove(__instance); Character attacker = value.Attacker; if ((Object)(object)attacker != (Object)null) { Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val != null) { if ((Object)(object)val == (Object)(object)Player.m_localPlayer) { text2 = "self"; text3 = ""; } else { text2 = "player"; try { text3 = val.GetPlayerName() ?? ""; } catch { text3 = ""; } } } else { text2 = "creature"; try { text3 = attacker.GetHoverName() ?? ((Object)attacker).name ?? ""; } catch { text3 = ((Object)attacker).name ?? ""; } int num2 = text3.IndexOf("(Clone)", StringComparison.Ordinal); if (num2 > 0) { text3 = text3.Substring(0, num2).Trim(); } } } } if (text2 == "unknown") { text2 = "self"; text3 = ""; } Instance?.SendBuildDestroy(text, position, text2, text3); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] WearNTear.Destroy hook error: " + ex.Message)); } } } } [HarmonyPatch(typeof(Player), "OnDeath")] public static class Patch_Player_OnDeath_Report { public static void Prefix(Player __instance) { try { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && IsActiveMultiplayerClient()) { Instance?.SendDeathReport(__instance); } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Death hook error: " + ex.Message)); } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public static class Patch_RegisterClientHandler { public static void Postfix(ZNetPeer peer) { try { if (peer == null || peer.m_rpc == null || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())) { return; } peer.m_rpc.Register<string>("ServerGuard_RequestManifest", (Action<ZRpc, string>)delegate(ZRpc rpc, string challenge) { try { string text = Instance.BuildManifestJson(challenge); rpc.Invoke("ServerGuard_Manifest", new object[1] { text }); LogS.LogInfo((object)$"[ServerGuard.Client] Sent manifest ({text.Length} bytes, {Instance._cachedManifest?.Count ?? 0} mods)."); } catch (Exception ex2) { LogS.LogError((object)("[ServerGuard.Client] Manifest send failed: " + ex2.Message)); } }); if ((Object)(object)Instance != (Object)null) { Instance._serverRpc = peer.m_rpc; } peer.m_rpc.Register<string>("ServerGuard_AdminCommandReply", (Action<ZRpc, string>)delegate(ZRpc rpc, string text) { try { Instance?.DisplayAdminReply(text); } catch (Exception ex2) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)("[ServerGuard.Client] Admin reply display failed: " + ex2.Message)); } } }); peer.m_rpc.Register<string>("ServerGuard_RemoveItems", (Action<ZRpc, string>)delegate(ZRpc rpc, string itemList) { try { Instance?.OnRemoveItemsReceived(itemList); } catch (Exception ex2) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)("[ServerGuard.Client] RemoveItems handler error: " + ex2.Message)); } } }); LogS.LogInfo((object)"[ServerGuard.Client] Registered manifest request handler on server peer."); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogError((object)("[ServerGuard.Client] Register handler failed: " + ex.Message)); } } } } [HarmonyPatch(typeof(Player), "StartEmote")] public static class Patch_Player_StartEmote_BlockDuringAttack { public static bool Prefix(Player __instance) { try { if (ShouldBlockAnimationCancel(__instance)) { Instance?.ReportAnimationCancel("emote"); return false; } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Emote gate error: " + ex.Message)); } } return true; } } [HarmonyPatch(typeof(Humanoid), "HideHandItems")] public static class Patch_Humanoid_HideHandItems_BlockDuringAttack { public static bool Prefix(Humanoid __instance) { try { Player val = (Player)(object)((__instance is Player) ? __instance : null); if ((Object)(object)val == (Object)null) { return true; } if (ShouldBlockAnimationCancel(val)) { Instance?.ReportAnimationCancel("sheathe"); return false; } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Sheathe gate error: " + ex.Message)); } } return true; } } [HarmonyPatch(typeof(Terminal), "TryRunCommand")] public static class Patch_TryRunCommand { public static bool Prefix(string text) { try { if (string.IsNullOrWhiteSpace(text)) { return true; } string text2 = text.TrimStart(Array.Empty<char>()); int num = text2.IndexOf(' '); string text3 = ((num >= 0) ? text2.Substring(0, num) : text2); string text4 = (text3.StartsWith("/", StringComparison.Ordinal) ? text3.Substring(1) : text3); if (string.Equals(text4, "sg", StringComparison.OrdinalIgnoreCase)) { string command = ((num >= 0) ? text2.Substring(num + 1).TrimStart(Array.Empty<char>()) : ""); Instance?.SendAdminCommand(command); return false; } if (!IsActiveMultiplayerClient()) { return true; } bool num2 = BlockedCommands.Contains(text4); bool flag = !num2 && IsRegisteredCheatCommand(text4); if (num2 || flag) { Instance?.ReportDevcommand(text4); return false; } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Devcommand gate error: " + ex.Message)); } } return true; } } [HarmonyPatch(typeof(Chat), "SendText")] public static class Patch_Chat_SendText_Report { public static void Prefix(Type __0, string __1) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected I4, but got Unknown try { if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && (int)__0 == 2 && !string.IsNullOrWhiteSpace(__1)) { Instance?.SendChatReport((int)__0, __1); } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Chat hook error: " + ex.Message)); } } } } [HarmonyPatch(typeof(FejdStartup), "SetupGui")] public static class Patch_FejdStartup_SetupGui { public static bool Prepare() { bool num = AccessTools.Method(typeof(FejdStartup), "SetupGui", (Type[])null, (Type[])null) != null; if (!num) { ManualLogSource logS = LogS; if (logS == null) { return num; } logS.LogWarning((object)"[ServerGuard.Client] FejdStartup.SetupGui not found — Quick Login panel disabled for this build."); } return num; } public static void Postfix(FejdStartup __instance) { try { Instance?.BuildQuickLoginPanel(__instance); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] SetupGui patch error: " + ex.Message)); } } } } [HarmonyPatch(typeof(FejdStartup), "OnCharacterStart")] public static class Patch_FejdStartup_OnCharacterStart { public static bool Prepare() { return AccessTools.Method(typeof(FejdStartup), "OnCharacterStart", (Type[])null, (Type[])null) != null; } public static void Prefix(FejdStartup __instance) { ClientPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && instance._quickJoinArmed) { ManualLogSource logS = LogS; if (logS != null) { logS.LogInfo((object)"[ServerGuard.Client] OnCharacterStart: re-asserting quick-join target."); } instance.ReassertServerToJoin(__instance); } } } [HarmonyPatch(typeof(FejdStartup), "OnSelelectCharacterBack")] public static class Patch_FejdStartup_CharacterBack { public static bool Prepare() { return AccessTools.Method(typeof(FejdStartup), "OnSelelectCharacterBack", (Type[])null, (Type[])null) != null; } public static void Postfix() { Instance?.DisarmQuickJoin(); } } public const string GUID = "com.taeguk.valheim.serverguard.client"; public const string NAME = "Valheim ServerGuard Client"; public const string VERSION = "1.6.0"; internal static ClientPlugin Instance; internal static ManualLogSource LogS; private Harmony _harmony; private string _sharedSecret = ""; private List<ModManifestEntry> _cachedManifest; private ClientSettings _clientSettings = new ClientSettings(); private GameObject _quickLoginPanel; private Component _playerCountText; private bool _quickJoinArmed; private object _armedJoinData; private string _armedPassword; internal ZRpc _serverRpc; private static readonly HashSet<string> BlockedCommands = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "devcommands", "debugmode", "imacheater", "god", "ghost", "fly", "nocost", "noplacementcost", "spawn", "pos", "goto", "tame", "killall", "event", "stopevent", "tod", "skiptime", "sleep", "raiseskill", "resetcharacter", "heal", "puke", "damage", "setkey", "resetkeys", "removedrops", "freefly" }; private static readonly string ConfDir = Path.Combine(Paths.ConfigPath, "ServerGuard"); private static readonly string ClientYaml = Path.Combine(ConfDir, "client.yaml"); private static readonly string ExportYaml = Path.Combine(ConfDir, "mods_for_allowed_mods.yaml"); private static MethodInfo _consoleWriteMethod; private static int _consoleWriteArity; private static object _consoleInstance; private static readonly ConditionalWeakTable<WearNTear, LastHitInfo> _clientLastHitOnPiece = new ConditionalWeakTable<WearNTear, LastHitInfo>(); private static FieldInfo _playerLastHitField; private static MethodInfo _hitGetAttackerMethod; private static FieldInfo _hitDamageField; private const float SkillReportIntervalSeconds = 60f; private static FieldInfo _playerSkillsField; private static FieldInfo _skillsDataField; private static FieldInfo _skillLevelField; private void Awake() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown Instance = this; LogS = ((BaseUnityPlugin)this).Logger; EnsureConfig(); _harmony = new Harmony("com.taeguk.valheim.serverguard.client"); _harmony.PatchAll(); ((MonoBehaviour)this).StartCoroutine(DeferredInit()); } private IEnumerator DeferredInit() { yield return null; yield return (object)new WaitForSeconds(2f); BuildManifestCache(); ExportAllowedModsSnippet(); ((MonoBehaviour)this).StartCoroutine(SkillReportLoop()); string text = ""; string text2 = ""; try { List<KeyValuePair<string, string>> entries = (_cachedManifest ?? new List<ModManifestEntry>()).Select((ModManifestEntry m) => new KeyValuePair<string, string>((!string.IsNullOrEmpty(m.Guid)) ? m.Guid : (m.Name ?? ""), m.Sha256 ?? "")).ToList(); text = ModsetFingerprint.Short(ModsetFingerprint.ComputeLoose(entries)); text2 = ModsetFingerprint.Short(ModsetFingerprint.ComputeStrict(entries)); } catch (Exception ex) { LogS.LogWarning((object)("[ServerGuard.Client] Fingerprint compute failed: " + ex.Message)); } LogS.LogInfo((object)string.Format("[ServerGuard.Client] Loaded v{0}. Manifest entries: {1}. HMAC: {2}", "1.6.0", _cachedManifest?.Count ?? 0, string.IsNullOrEmpty(_sharedSecret) ? "OFF (no shared_secret configured)" : "ON")); LogS.LogInfo((object)("[ServerGuard.Client] Modset fingerprint loose=" + text + " strict=" + text2)); } private void ExportAllowedModsSnippet() { try { if (File.Exists(ExportYaml)) { LogS.LogInfo((object)("[ServerGuard.Client] Allowed-mods export already present at " + ExportYaml + ". Delete the file to regenerate.")); return; } List<ModManifestEntry> list = _cachedManifest ?? new List<ModManifestEntry>(); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# ServerGuard - allowed_mods snippet generated by ServerGuard.Client v1.6.0"); stringBuilder.AppendLine($"# Generated: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}Z Mods on this client: {list.Count}"); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# How to use:"); stringBuilder.AppendLine("# 1. Open <server>/BepInEx/config/ServerGuard/conf/allowed_mods.yaml"); stringBuilder.AppendLine("# 2. Replace the `allowed_mods:` block with the one below"); stringBuilder.AppendLine("# (or merge if you already have entries you want to keep)."); stringBuilder.AppendLine("# 3. Save. The server hot-reloads within ~1 second."); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# Each entry is `<GUID>|<sha256>` (GUID-keyed, hash-pinned)."); stringBuilder.AppendLine("# To loosen, drop the `|<sha256>` suffix - the entry will then accept any hash."); stringBuilder.AppendLine("# To tighten further, leave it as-is - the server will require an exact DLL match."); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# The companion plugin (this DLL) is intentionally listed under required_mods,"); stringBuilder.AppendLine("# NOT allowed_mods - the server demands its presence."); stringBuilder.AppendLine(); ModManifestEntry modManifestEntry = list.FirstOrDefault((ModManifestEntry m) => string.Equals(m.Guid, "com.taeguk.valheim.serverguard.client", StringComparison.OrdinalIgnoreCase)); stringBuilder.AppendLine("required_mods:"); if (modManifestEntry != null && !string.IsNullOrEmpty(modManifestEntry.Sha256)) { stringBuilder.AppendLine(" - " + modManifestEntry.Guid + "|" + modManifestEntry.Sha256 + " # " + modManifestEntry.Name + " v" + modManifestEntry.Version); } else { stringBuilder.AppendLine(" - com.taeguk.valheim.serverguard.client # Valheim ServerGuard Client v1.6.0"); } stringBuilder.AppendLine(); stringBuilder.AppendLine("allowed_mods:"); List<ModManifestEntry> list2 = list.Where((ModManifestEntry m) => !string.Equals(m.Guid, "com.taeguk.valheim.serverguard.client", StringComparison.OrdinalIgnoreCase)).OrderBy<ModManifestEntry, string>((ModManifestEntry m) => m.Name ?? "", StringComparer.OrdinalIgnoreCase).ToList(); if (list2.Count == 0) { stringBuilder.AppendLine(" []"); } else { int num = 0; foreach (ModManifestEntry item in list2) { int num2 = (((!string.IsNullOrEmpty(item.Guid)) ? item.Guid : item.Name) ?? "").Length + ((!string.IsNullOrEmpty(item.Sha256)) ? (1 + item.Sha256.Length) : 0); if (num2 > num) { num = num2; } } foreach (ModManifestEntry item2 in list2) { string text = ((!string.IsNullOrEmpty(item2.Guid)) ? item2.Guid : (item2.Name ?? "")); string text2 = (string.IsNullOrEmpty(item2.Sha256) ? text : (text + "|" + item2.Sha256)); string text3 = new string(' ', Math.Max(1, num - text2.Length + 2)); string text4 = (string.IsNullOrEmpty(item2.Name) ? "" : (item2.Name + " v" + item2.Version)); if (string.IsNullOrEmpty(item2.Guid)) { stringBuilder.AppendLine(" - " + text2 + text3 + "# " + text4 + " (no GUID; consider replacing the key with the mod's BepInPlugin GUID)"); } else { stringBuilder.AppendLine(" - " + text2 + text3 + "# " + text4); } } } stringBuilder.AppendLine(); stringBuilder.AppendLine("banned_mods: []"); stringBuilder.AppendLine(); Directory.CreateDirectory(ConfDir); File.WriteAllText(ExportYaml, stringBuilder.ToString()); LogS.LogWarning((object)"[ServerGuard.Client] First-run mod export written:"); LogS.LogWarning((object)("[ServerGuard.Client] " + ExportYaml)); LogS.LogWarning((object)$"[ServerGuard.Client] ({list.Count} plugins). Paste its contents into the server's allowed_mods.yaml."); } catch (Exception ex) { LogS.LogError((object)("[ServerGuard.Client] ExportAllowedModsSnippet failed: " + ex.Message)); } } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } private void EnsureConfig() { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown try { Directory.CreateDirectory(ConfDir); if (!File.Exists(ClientYaml)) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Valheim ServerGuard - Client config"); stringBuilder.AppendLine(""); stringBuilder.AppendLine("# sharedSecret MUST match the server's settings.yaml `sharedSecret` value"); stringBuilder.AppendLine("# verbatim. The server will reject manifests whose HMAC does not match."); stringBuilder.AppendLine("# Leave empty only if the server has `requireHmac: false` (insecure)."); stringBuilder.AppendLine("sharedSecret: \"\""); stringBuilder.AppendLine(""); stringBuilder.AppendLine("# ---------------------------------------------------------------"); stringBuilder.AppendLine("# Quick Login panel (title screen)"); stringBuilder.AppendLine("# When enabled, a panel is shown on the main menu so players can"); stringBuilder.AppendLine("# connect to your server with one click - no IP/password dialog."); stringBuilder.AppendLine("# ---------------------------------------------------------------"); stringBuilder.AppendLine("quickLoginEnabled: false"); stringBuilder.AppendLine("serverAddress: \"\" # e.g. 192.168.1.1 or my.server.com"); stringBuilder.AppendLine("serverPort: 2456"); stringBuilder.AppendLine("serverPassword: \"\" # stored in plain text; leave empty for public servers"); stringBuilder.AppendLine("serverName: \"\" # displayed as the panel heading"); stringBuilder.AppendLine("serverDescription: \"\" # shown below the name"); stringBuilder.AppendLine("serverLogoPath: \"\" # PNG/JPG filename in BepInEx/config/ServerGuard/"); File.WriteAllText(ClientYaml, stringBuilder.ToString()); } ClientSettings clientSettings = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).IgnoreUnmatchedProperties().Build() .Deserialize<ClientSettings>(File.ReadAllText(ClientYaml)) ?? new ClientSettings(); _sharedSecret = clientSettings.SharedSecret ?? ""; _clientSettings = clientSettings; } catch (Exception ex) { LogS.LogWarning((object)("[ServerGuard.Client] EnsureConfig failed: " + ex.Message)); } } private void BuildManifestCache() { _cachedManifest = new List<ModManifestEntry>(); try { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { PluginInfo value = pluginInfo.Value; BepInPlugin val = ((value != null) ? value.Metadata : null); string sha = ""; try { string text = ((value != null) ? value.Location : null); if (!string.IsNullOrEmpty(text) && File.Exists(text)) { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(text); sha = BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "").ToLowerInvariant(); } } catch { } _cachedManifest.Add(new ModManifestEntry { Guid = (((val != null) ? val.GUID : null) ?? ""), Name = (((val != null) ? val.Name : null) ?? ""), Version = (((val == null) ? null : val.Version?.ToString()) ?? ""), Sha256 = sha }); } } catch (Exception ex) { LogS.LogError((object)("[ServerGuard.Client] BuildManifestCache failed: " + ex.Message)); } } public string BuildManifestJson(string challenge) { BuildManifestCache(); ModManifest obj = new ModManifest { SchemaVersion = "1", Challenge = (challenge ?? ""), TimestampUtc = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), Mods = (_cachedManifest ?? new List<ModManifestEntry>()) }; obj.Hmac = ModManifest.ComputeHmac(obj.CanonicalForHmac(), _sharedSecret); return JsonConvert.SerializeObject((object)obj); } internal void SendAdminCommand(string command) { if (!IsActiveMultiplayerClient()) { DisplayAdminReply("[ServerGuard] sg commands only work while connected to a multiplayer server."); return; } if (_serverRpc == null) { DisplayAdminReply("[ServerGuard] Not connected to a server peer yet."); return; } try { _serverRpc.Invoke("ServerGuard_AdminCommand", new object[1] { command ?? "" }); ManualLogSource logS = LogS; if (logS != null) { logS.LogInfo((object)("[ServerGuard.Client] Sent admin command: " + command)); } } catch (Exception ex) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)("[ServerGuard.Client] Admin command send failed: " + ex.Message)); } DisplayAdminReply("[ServerGuard] Send failed: " + ex.Message); } } internal void DisplayAdminReply(string text) { if (string.IsNullOrEmpty(text)) { return; } string[] array = text.Split(new char[1] { '\n' }); try { object obj = ResolveConsoleInstance(); string[] array2; if (obj == null || _consoleWriteMethod == null) { array2 = array; foreach (string text2 in array2) { ManualLogSource logS = LogS; if (logS != null) { logS.LogInfo((object)("[ServerGuard] " + text2)); } } return; } array2 = array; foreach (string text3 in array2) { if (string.IsNullOrWhiteSpace(text3)) { continue; } try { object[] parameters = ((_consoleWriteArity != 1) ? new object[2] { text3, false } : new object[1] { text3 }); _consoleWriteMethod.Invoke(obj, parameters); } catch { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogInfo((object)("[ServerGuard] " + text3)); } } } } catch (Exception ex) { ManualLogSource logS3 = LogS; if (logS3 != null) { logS3.LogWarning((object)("[ServerGuard.Client] DisplayAdminReply error: " + ex.Message)); } } } private object ResolveConsoleInstance() { if (_consoleInstance != null && _consoleWriteMethod != null) { return _consoleInstance; } Type type = typeof(Terminal).Assembly.GetType("Console"); object obj = null; if (type != null) { try { PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { obj = property.GetValue(null); } } catch { } if (obj == null) { try { FieldInfo field = type.GetField("m_instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { obj = field.GetValue(null); } } catch { } } } if (obj == null) { try { obj = Object.FindObjectOfType<Terminal>(); } catch { } } if (obj == null) { return null; } MethodInfo methodInfo = null; int num = 0; string[] array = new string[2] { "Print", "AddString" }; foreach (string text in array) { MethodInfo[] methods = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.Name != text)) { ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string)) { methodInfo = methodInfo2; num = 1; break; } if (parameters.Length == 2 && parameters[0].ParameterType == typeof(string) && parameters[1].ParameterType == typeof(bool) && methodInfo == null) { methodInfo = methodInfo2; num = 2; } } } if (methodInfo != null && num == 1) { break; } } if (methodInfo == null) { return null; } _consoleInstance = obj; _consoleWriteMethod = methodInfo; _consoleWriteArity = num; return _consoleInstance; } internal void SendBuildPlace(string pieceName, Vector3 pos) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (_serverRpc == null) { return; } try { string text = SanitiseShort(pieceName, 64); string text2 = string.Format(CultureInfo.InvariantCulture, "{0}|{1:F1}|{2:F1}|{3:F1}", text, pos.x, pos.y, pos.z); _serverRpc.Invoke("ServerGuard_BuildPlace", new object[1] { text2 }); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] BuildPlace RPC failed: " + ex.Message)); } } } internal void SendBuildDestroy(string pieceName, Vector3 pos, string attackerKind, string attackerLabel) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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) if (_serverRpc == null) { return; } try { string text = SanitiseShort(pieceName, 64); string text2 = SanitiseShort(attackerKind ?? "unknown", 16); string text3 = SanitiseShort(attackerLabel ?? "", 48); string text4 = string.Format(CultureInfo.InvariantCulture, "{0}|{1:F1}|{2:F1}|{3:F1}|{4}|{5}", text, pos.x, pos.y, pos.z, text2, text3); _serverRpc.Invoke("ServerGuard_BuildDestroy", new object[1] { text4 }); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] BuildDestroy RPC failed: " + ex.Message)); } } } private static string SanitiseShort(string s, int max) { string text = (s ?? "").Replace('|', ' ').Replace('\n', ' ').Trim(); if (text.Length > max) { text = text.Substring(0, max); } return text; } internal void SendDeathReport(Player p) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) if (_serverRpc == null) { return; } try { Vector3 position = ((Component)p).transform.position; string text = "environment"; string text2 = ""; string text3 = ""; if (_playerLastHitField == null) { FieldInfo[] fields = typeof(Player).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(HitData)) { _playerLastHitField = fieldInfo; break; } } } object? obj = _playerLastHitField?.GetValue(p); HitData val = (HitData)((obj is HitData) ? obj : null); if (val != null && val != null) { text3 = DominantDamageType(val); if (_hitGetAttackerMethod == null) { _hitGetAttackerMethod = typeof(HitData).GetMethod("GetAttacker", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } Character val2 = null; if (_hitGetAttackerMethod != null) { try { object? obj2 = _hitGetAttackerMethod.Invoke(val, null); val2 = (Character)((obj2 is Character) ? obj2 : null); } catch { } } if ((Object)(object)val2 != (Object)null) { Player val3 = (Player)(object)((val2 is Player) ? val2 : null); if (val3 != null) { if ((Object)(object)val3 == (Object)(object)p) { text = "self"; text2 = ""; } else { text = "player"; text2 = val3.GetPlayerName() ?? ""; } } else { text = "creature"; try { text2 = val2.GetHoverName() ?? ((Object)val2).name ?? ""; } catch { text2 = ((Object)val2).name ?? ""; } } } } text2 = (text2 ?? "").Replace('|', ' ').Replace('\n', ' ').Trim(); text3 = (text3 ?? "").Replace('|', ' ').Replace('\n', ' ').Trim(); string text4 = string.Format(CultureInfo.InvariantCulture, "{0:F1}|{1:F1}|{2:F1}|{3}|{4}|{5}", position.x, position.y, position.z, text, text2, text3); try { _serverRpc.Invoke("ServerGuard_PlayerDeath", new object[1] { text4 }); LogS.LogInfo((object)("[ServerGuard.Client] Death report sent (" + text + " / " + text2 + " / " + text3 + ").")); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Death report RPC failed: " + ex.Message)); } } } catch (Exception ex2) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)("[ServerGuard.Client] SendDeathReport error: " + ex2.Message)); } } } private static string DominantDamageType(HitData hit) { if (hit == null) { return ""; } FieldInfo[] fields; if (_hitDamageField == null) { fields = typeof(HitData).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.Name.Equals("m_damage", StringComparison.OrdinalIgnoreCase)) { _hitDamageField = fieldInfo; break; } } } if (_hitDamageField == null) { return ""; } object value; try { value = _hitDamageField.GetValue(hit); } catch { return ""; } if (value == null) { return ""; } string text = ""; float num = 0f; fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo2 in fields) { if (!(fieldInfo2.FieldType != typeof(float))) { float num2; try { num2 = (float)fieldInfo2.GetValue(value); } catch { continue; } if (num2 > num) { num = num2; text = fieldInfo2.Name; } } } if (text.StartsWith("m_", StringComparison.Ordinal)) { text = text.Substring(2); } if (text.Length > 0) { text = char.ToUpperInvariant(text[0]) + text.Substring(1); } return text; } private IEnumerator SkillReportLoop() { yield return (object)new WaitForSeconds(15f); while (true) { yield return (object)new WaitForSeconds(60f); try { SendSkillReportNow(); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Skill report tick error: " + ex.Message)); } } } } private static Skills GetPlayerSkills(Player p) { if ((Object)(object)p == (Object)null) { return null; } if (_playerSkillsField == null) { FieldInfo[] fields = typeof(Player).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(Skills)) { _playerSkillsField = fieldInfo; break; } } if (_playerSkillsField == null) { return null; } } object? value = _playerSkillsField.GetValue(p); return (Skills)((value is Skills) ? value : null); } private static IEnumerable<KeyValuePair<string, float>> EnumerateSkills(Skills skills) { if ((Object)(object)skills == (Object)null) { yield break; } if (_skillsDataField == null) { FieldInfo[] fields = typeof(Skills).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (typeof(IDictionary).IsAssignableFrom(fieldInfo.FieldType)) { _skillsDataField = fieldInfo; break; } } if (_skillsDataField == null) { yield break; } } if (!(_skillsDataField.GetValue(skills) is IDictionary dictionary)) { yield break; } foreach (DictionaryEntry item in dictionary) { string text = item.Key?.ToString(); if (string.IsNullOrEmpty(text)) { continue; } object value = item.Value; if (value == null) { continue; } if (_skillLevelField == null) { FieldInfo[] fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo2 in fields) { if (fieldInfo2.FieldType == typeof(float) && fieldInfo2.Name.IndexOf("level", StringComparison.OrdinalIgnoreCase) >= 0) { _skillLevelField = fieldInfo2; break; } } if (_skillLevelField == null) { yield break; } } float value2; try { value2 = (float)_skillLevelField.GetValue(value); } catch { continue; } yield return new KeyValuePair<string, float>(text, value2); } } private void SendSkillReportNow() { if (_serverRpc == null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Skills playerSkills = GetPlayerSkills(localPlayer); if ((Object)(object)playerSkills == (Object)null) { return; } StringBuilder stringBuilder = new StringBuilder(); bool flag = true; foreach (KeyValuePair<string, float> item in EnumerateSkills(playerSkills)) { string key = item.Key; float value = item.Value; if (!string.IsNullOrEmpty(key) && key.IndexOf(':') < 0 && key.IndexOf('|') < 0 && key.Length <= 32) { if (!flag) { stringBuilder.Append('|'); } stringBuilder.Append(key); stringBuilder.Append(':'); stringBuilder.Append(value.ToString("F1", CultureInfo.InvariantCulture)); flag = false; } } if (stringBuilder.Length == 0) { return; } try { _serverRpc.Invoke("ServerGuard_SkillReport", new object[1] { stringBuilder.ToString() }); } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Skill report send failed: " + ex.Message)); } } } private static bool IsActiveMultiplayerClient() { try { if ((Object)(object)ZNet.instance == (Object)null) { return false; } if (ZNet.instance.IsServer()) { return false; } return true; } catch { return false; } } internal void ReportDevcommand(string command) { try { LogS.LogWarning((object)("[ServerGuard.Client] Blocked cheat attempt: `" + command + "` (multiplayer client)")); if (_serverRpc != null) { try { _serverRpc.Invoke("ServerGuard_DevcommandAttempt", new object[1] { command ?? "" }); return; } catch (Exception ex) { LogS.LogWarning((object)("[ServerGuard.Client] Could not report devcommand to server: " + ex.Message)); return; } } } catch { } } internal void ReportAnimationCancel(string source) { try { LogS.LogInfo((object)("[ServerGuard.Client] Blocked animation cancel via " + source + " (mid-attack).")); if (_serverRpc != null) { try { _serverRpc.Invoke("ServerGuard_AnimationCancelAttempt", new object[1] { source ?? "" }); return; } catch (Exception ex) { LogS.LogWarning((object)("[ServerGuard.Client] Could not report animation-cancel: " + ex.Message)); return; } } } catch { } } private static bool IsRegisteredCheatCommand(string cmd) { if (string.IsNullOrEmpty(cmd)) { return false; } try { Type? typeFromHandle = typeof(Terminal); IDictionary dictionary = null; FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (typeof(IDictionary).IsAssignableFrom(fieldInfo.FieldType) && fieldInfo.GetValue(null) is IDictionary dictionary2) { dictionary = dictionary2; break; } } if (dictionary == null) { return false; } object obj = null; foreach (DictionaryEntry item in dictionary) { if (item.Key is string a && string.Equals(a, cmd, StringComparison.OrdinalIgnoreCase)) { obj = item.Value; break; } } if (obj == null) { return false; } Type type = obj.GetType(); string[] array = new string[5] { "IsCheat", "isCheat", "m_isCheat", "Cheat", "cheat" }; bool flag = default(bool); bool flag2 = default(bool); foreach (string name in array) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(bool)) { object value = field.GetValue(obj); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(bool)) { object value = property.GetValue(obj); int num2; if (value is bool) { flag2 = (bool)value; num2 = 1; } else { num2 = 0; } return (byte)((uint)num2 & (flag2 ? 1u : 0u)) != 0; } } } catch { } return false; } private static bool ShouldBlockAnimationCancel(Player p) { try { if (!IsActiveMultiplayerClient()) { return false; } if ((Object)(object)p == (Object)null) { return false; } if ((Object)(object)p != (Object)(object)Player.m_localPlayer) { return false; } return ((Character)p).InAttack(); } catch { return false; } } internal void SendChatReport(int type, string text) { try { ZNet instance = ZNet.instance; ZRpc val = ((instance != null) ? instance.GetServerRPC() : null); if (val == null) { return; } text = text.Replace('\n', ' ').Trim(); if (text.Length > 256) { text = text.Substring(0, 256); } if (text.Length != 0) { val.Invoke("ServerGuard_Chat", new object[1] { $"{type}|{text}" }); ManualLogSource logS = LogS; if (logS != null) { logS.LogInfo((object)"[ServerGuard.Client] Shout report sent."); } } } catch (Exception ex) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)("[ServerGuard.Client] Chat report failed: " + ex.Message)); } } } internal void OnRemoveItemsReceived(string itemList) { try { if (!string.IsNullOrWhiteSpace(itemList)) { string[] array = (from s in itemList.Split(new char[1] { ',' }) select s.Trim() into s where !string.IsNullOrEmpty(s) select s).ToArray(); if (array.Length != 0) { ((MonoBehaviour)this).StartCoroutine(RemoveItemsFromInventory(array)); } } } catch (Exception ex) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] OnRemoveItemsReceived error: " + ex.Message)); } } } private IEnumerator RemoveItemsFromInventory(string[] prefabNames) { for (float elapsed = 0f; elapsed < 90f; elapsed += 0.5f) { if ((Object)(object)Player.m_localPlayer != (Object)null && ((Humanoid)Player.m_localPlayer).GetInventory() != null) { break; } yield return (object)new WaitForSeconds(0.5f); } if ((Object)(object)Player.m_localPlayer == (Object)null) { yield break; } try { Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); if (inventory == null) { yield break; } List<ItemData> list = new List<ItemData>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (!((Object)(object)allItem?.m_dropPrefab == (Object)null) && prefabNames.Contains<string>(((Object)allItem.m_dropPrefab).name, StringComparer.OrdinalIgnoreCase)) { list.Add(allItem); } } foreach (ItemData item in list) { inventory.RemoveItem(item); } if (list.Count <= 0) { yield break; } ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)string.Format("[ServerGuard.Client] Removed {0} cheat item(s) from inventory: {1}", list.Count, string.Join(", ", list.Select((ItemData i) => ((Object)i.m_dropPrefab).name)))); } } catch (Exception ex) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)("[ServerGuard.Client] RemoveItemsFromInventory error: " + ex.Message)); } } } internal void BuildQuickLoginPanel(FejdStartup menu) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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_0304: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) if (_clientSettings == null || !_clientSettings.QuickLoginEnabled || string.IsNullOrWhiteSpace(_clientSettings.ServerAddress)) { return; } if ((Object)(object)_quickLoginPanel != (Object)null) { Object.Destroy((Object)(object)_quickLoginPanel); _quickLoginPanel = null; _playerCountText = null; } Transform val = null; object field = GetField(menu, "m_characterSelectScreen"); GameObject val2 = (GameObject)((field is GameObject) ? field : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.transform.parent != (Object)null) { val = val2.transform.parent; } if ((Object)(object)val == (Object)null) { Canvas componentInChildren = ((Component)menu).GetComponentInChildren<Canvas>(true); val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).transform : null); } if ((Object)(object)val == (Object)null) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)"[ServerGuard.Client] BuildQuickLoginPanel: no GUI root found."); } return; } _quickLoginPanel = new GameObject("SG_QuickLogin"); _quickLoginPanel.transform.SetParent(val, false); RectTransform obj = _quickLoginPanel.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(1f, 1f); obj.anchorMax = new Vector2(1f, 1f); obj.pivot = new Vector2(1f, 1f); obj.sizeDelta = new Vector2(320f, 440f); obj.anchoredPosition = new Vector2(-30f, -70f); ((Graphic)_quickLoginPanel.AddComponent<Image>()).color = new Color(0.05f, 0.05f, 0.05f, 0.82f); float num = -10f; if (!string.IsNullOrWhiteSpace(_clientSettings.ServerLogoPath)) { Texture2D val3 = LoadTexture(Path.Combine(ConfDir, _clientSettings.ServerLogoPath)); if ((Object)(object)val3 != (Object)null) { GameObject obj2 = CreateChild("SG_Logo", _quickLoginPanel.transform); RectTransform obj3 = obj2.AddComponent<RectTransform>(); obj3.anchorMin = new Vector2(0.05f, 1f); obj3.anchorMax = new Vector2(0.95f, 1f); obj3.pivot = new Vector2(0.5f, 1f); obj3.anchoredPosition = new Vector2(0f, num); float num2 = (float)((Texture)val3).width / (float)((Texture)val3).height; float num3 = Mathf.Min(120f, 300f / num2); obj3.sizeDelta = new Vector2(0f, num3); Image obj4 = obj2.AddComponent<Image>(); obj4.sprite = Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f)); obj4.preserveAspect = true; num -= num3 + 8f; } } Component tmpTemplate = (Component)(((object)GetMenuButtonLabelTemplate(menu)) ?? ((object)/*isinst with value type is only supported in some contexts*/)); num = AddThemedLabel("SG_Name", _quickLoginPanel.transform, tmpTemplate, _clientSettings.ServerName, 24f, bold: false, Color.white, num, 32f); if (!string.IsNullOrWhiteSpace(_clientSettings.ServerDescription)) { num = AddThemedLabel("SG_Desc", _quickLoginPanel.transform, tmpTemplate, _clientSettings.ServerDescription, 16f, bold: false, new Color(0.85f, 0.85f, 0.85f, 1f), num, 64f); } _playerCountText = CreateThemedLabelComponent("SG_PlayerCount", _quickLoginPanel.transform, tmpTemplate, "Players: querying...", 17f, bold: false, new Color(0.7f, 0.9f, 0.7f, 1f), num - 6f, 26f); AddConnectButton(menu, _quickLoginPanel.transform); _quickLoginPanel.transform.SetAsLastSibling(); ((MonoBehaviour)this).StartCoroutine(RefreshPlayerCount(_clientSettings.ServerAddress, _clientSettings.ServerPort)); } private static GameObject CreateChild(string name, Transform parent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown GameObject val = new GameObject(name); val.transform.SetParent(parent, false); return val; } private static object GetField(object obj, string name) { return (obj?.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(obj); } private static Component GetMenuButtonLabelTemplate(FejdStartup menu) { Button val = (GetField(menu, "m_menuButtons") as Button[])?.FirstOrDefault((Func<Button, bool>)((Button b) => (Object)(object)b != (Object)null)); if ((Object)(object)val == (Object)null) { return null; } Component[] componentsInChildren = ((Component)val).GetComponentsInChildren<Component>(true); foreach (Component val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null)) { string name = ((object)val2).GetType().Name; if (name == "TextMeshProUGUI" || name == "TMP_Text") { return val2; } } } return null; } private float AddThemedLabel(string name, Transform parent, Component tmpTemplate, string text, float fontSize, bool bold, Color color, float topOffset, float height) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) CreateThemedLabelComponent(name, parent, tmpTemplate, text, fontSize, bold, color, topOffset, height); return topOffset - (height + 4f); } private Component CreateThemedLabelComponent(string name, Transform parent, Component tmpTemplate, string text, float fontSize, bool bold, Color color, float topOffset, float height) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) GameObject val = (((Object)(object)tmpTemplate != (Object)null) ? Object.Instantiate<GameObject>(tmpTemplate.gameObject, parent, false) : CreateChild(name, parent)); ((Object)val).name = name; val.SetActive(true); ContentSizeFitter component = val.GetComponent<ContentSizeFitter>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } LayoutElement component2 = val.GetComponent<LayoutElement>(); if ((Object)(object)component2 != (Object)null) { Object.Destroy((Object)(object)component2); } RectTransform obj = val.GetComponent<RectTransform>() ?? val.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0.05f, 1f); obj.anchorMax = new Vector2(0.95f, 1f); obj.pivot = new Vector2(0.5f, 1f); obj.anchoredPosition = new Vector2(0f, topOffset); obj.sizeDelta = new Vector2(0f, height); ((Transform)obj).localScale = Vector3.one; if ((Object)(object)tmpTemplate != (Object)null) { Component component3 = val.GetComponent(((object)tmpTemplate).GetType()); SetTmpProperty(component3, "text", text); SetTmpProperty(component3, "fontSize", fontSize); SetTmpProperty(component3, "color", color); SetTmpProperty(component3, "enableAutoSizing", false); SetTmpProperty(component3, "enableWordWrapping", true); SetTmpEnum(component3, "overflowMode", "Overflow"); SetTmpEnum(component3, "alignment", "Top"); SetTmpEnum(component3, "fontStyle", bold ? "Bold" : "Normal"); return component3; } Text obj2 = val.AddComponent<Text>(); obj2.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); obj2.fontSize = Mathf.RoundToInt(fontSize); obj2.fontStyle = (FontStyle)(bold ? 1 : 0); ((Graphic)obj2).color = color; obj2.alignment = (TextAnchor)1; obj2.horizontalOverflow = (HorizontalWrapMode)0; obj2.verticalOverflow = (VerticalWrapMode)1; obj2.text = text; return (Component)(object)obj2; } private void AddConnectButton(FejdStartup menu, Transform parent) { //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Expected O, but got Unknown Button val = (GetField(menu, "m_menuButtons") as Button[])?.FirstOrDefault((Func<Button, bool>)((Button b) => (Object)(object)b != (Object)null)); if ((Object)(object)val != (Object)null) { GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false); ((Object)obj).name = "SG_ConnectBtn"; obj.SetActive(true); RectTransform component = obj.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0f); component.anchorMax = new Vector2(0.5f, 0f); component.pivot = new Vector2(0.5f, 0f); component.anchoredPosition = new Vector2(0f, 16f); component.sizeDelta = new Vector2(240f, 48f); ((Transform)component).localScale = Vector3.one; SetAnyText(obj, "Connect"); Button component2 = obj.GetComponent<Button>(); component2.onClick = new ButtonClickedEvent(); ((UnityEvent)component2.onClick).AddListener((UnityAction)delegate { ConnectToConfiguredServer(menu); }); return; } GameObject val2 = CreateChild("SG_ConnectBtn", parent); RectTransform obj2 = val2.AddComponent<RectTransform>(); obj2.anchorMin = new Vector2(0.5f, 0f); obj2.anchorMax = new Vector2(0.5f, 0f); obj2.pivot = new Vector2(0.5f, 0f); obj2.anchoredPosition = new Vector2(0f, 16f); obj2.sizeDelta = new Vector2(240f, 44f); ((Graphic)val2.AddComponent<Image>()).color = new Color(0.15f, 0.45f, 0.15f, 1f); Button obj3 = val2.AddComponent<Button>(); GameObject obj4 = CreateChild("SG_ConnectBtnText", val2.transform); RectTransform obj5 = obj4.AddComponent<RectTransform>(); obj5.anchorMin = Vector2.zero; obj5.anchorMax = Vector2.one; obj5.offsetMin = Vector2.zero; obj5.offsetMax = Vector2.zero; Text obj6 = obj4.AddComponent<Text>(); obj6.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); obj6.fontSize = 18; obj6.fontStyle = (FontStyle)1; ((Graphic)obj6).color = Color.white; obj6.alignment = (TextAnchor)4; obj6.text = "Connect"; ((UnityEvent)obj3.onClick).AddListener((UnityAction)delegate { ConnectToConfiguredServer(menu); }); } private static void SetAnyText(GameObject go, string text) { Component[] componentsInChildren = go.GetComponentsInChildren<Component>(true); foreach (Component val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((object)val).GetType().Name; if (name == "TextMeshProUGUI" || name == "TMP_Text") { SetTmpProperty(val, "text", text); continue; } Text val2 = (Text)(object)((val is Text) ? val : null); if (val2 != null) { val2.text = text; } } } private static void SetAnyText(Component comp, string text) { if (!((Object)(object)comp == (Object)null)) { Text val = (Text)(object)((comp is Text) ? comp : null); if (val != null) { val.text = text; } else { SetTmpProperty(comp, "text", text); } } } private static void SetTmpProperty(object tmp, string prop, object val) { if (tmp == null) { return; } PropertyInfo property = tmp.GetType().GetProperty(prop, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property != null) || !property.CanWrite) { return; } try { property.SetValue(tmp, val, null); } catch { } } private static void SetTmpEnum(object tmp, string prop, string enumName) { if (tmp == null) { return; } PropertyInfo property = tmp.GetType().GetProperty(prop, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null) { return; } try { object value = Enum.Parse(property.PropertyType, enumName); property.SetValue(tmp, value, null); } catch { } } private static Texture2D LoadTexture(string path) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown try { if (!File.Exists(path)) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)("[ServerGuard.Client] Logo file not found: " + path)); } return null; } byte[] array = File.ReadAllBytes(path); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); MethodInfo methodInfo = AppDomain.CurrentDomain.GetAssemblies().Select(delegate(Assembly a) { try { return a.GetType("UnityEngine.ImageConversion"); } catch { return (Type)null; } }).FirstOrDefault((Type t) => t != null)?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Texture2D), typeof(byte[]) }, null); if (methodInfo != null) { object obj = methodInfo.Invoke(null, new object[2] { val, array }); if (obj is bool && !(bool)obj) { ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogWarning((object)"[ServerGuard.Client] ImageConversion.LoadImage returned false — unsupported image (use PNG or JPG)."); } } return val; } MethodInfo method = typeof(Texture2D).GetMethod("LoadImage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(byte[]) }, null); if (method != null) { method.Invoke(val, new object[1] { array }); return val; } ManualLogSource logS3 = LogS; if (logS3 != null) { logS3.LogWarning((object)"[ServerGuard.Client] Could not resolve LoadImage; logo not displayed."); } return null; } catch (Exception ex) { ManualLogSource logS4 = LogS; if (logS4 != null) { logS4.LogWarning((object)("[ServerGuard.Client] LoadTexture failed: " + ex.Message)); } return null; } } private void ConnectToConfiguredServer(FejdStartup menu) { try { if ((Object)(object)menu == (Object)null) { return; } Assembly assembly = typeof(FejdStartup).Assembly; Type type = assembly.GetType("ServerJoinDataDedicated"); Type type2 = assembly.GetType("ServerJoinData"); if (type == null || type2 == null) { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)"[ServerGuard.Client] ServerJoinData types not found; cannot connect."); } return; } object obj = type.GetConstructor(new Type[2] { typeof(string), typeof(ushort) }).Invoke(new object[2] { _clientSettings.ServerAddress, (ushort)_clientSettings.ServerPort }); ConstructorInfo constructor = type2.GetConstructor(new Type[1] { type }); _armedJoinData = constructor.Invoke(new object[1] { obj }); _armedPassword = _clientSettings.ServerPassword ?? ""; _quickJoinArmed = true; ReassertServerToJoin(menu, keepArmed: true); object field = GetField(menu, "m_characterSelectScreen"); GameObject val = (GameObject)((field is GameObject) ? field : null); if ((Object)(object)val != (Object)null && val.activeInHierarchy) { typeof(FejdStartup).GetMethod("OnCharacterStart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Invoke(menu, null); ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogInfo((object)$"[ServerGuard.Client] Connecting to {_clientSettings.ServerAddress}:{_clientSettings.ServerPort} with selected character."); } } else { typeof(FejdStartup).GetMethod("OnStartGame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Invoke(menu, null); ManualLogSource logS3 = LogS; if (logS3 != null) { logS3.LogInfo((object)$"[ServerGuard.Client] Quick-join armed for {_clientSettings.ServerAddress}:{_clientSettings.ServerPort}; select a character to connect."); } } } catch (Exception ex) { ManualLogSource logS4 = LogS; if (logS4 != null) { logS4.LogWarning((object)("[ServerGuard.Client] ConnectToConfiguredServer failed: " + ex.Message)); } } } internal void ReassertServerToJoin(FejdStartup menu, bool keepArmed = false) { try { if ((Object)(object)menu == (Object)null || _armedJoinData == null) { return; } FieldInfo field = typeof(FejdStartup).GetField("m_queuedJoinServer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(menu, _armedJoinData); } else { ManualLogSource logS = LogS; if (logS != null) { logS.LogWarning((object)"[ServerGuard.Client] m_queuedJoinServer not found; falling back to SetServerToJoin."); } typeof(FejdStartup).GetMethod("SetServerToJoin", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(menu, new object[1] { _armedJoinData }); } PropertyInfo propertyInfo = typeof(FejdStartup).GetProperty("ServerPassword", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? typeof(FejdStartup).GetProperty("ServerPassword", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo != null) { MethodInfo? getMethod = propertyInfo.GetGetMethod(nonPublic: true); object obj = (((object)getMethod != null && getMethod.IsStatic) ? null : menu); propertyInfo.SetValue(obj, _armedPassword ?? "", null); } ManualLogSource logS2 = LogS; if (logS2 != null) { logS2.LogInfo((object)"[ServerGuard.Client] Quick-join server + password asserted on FejdStartup."); } if (!keepArmed) { _quickJoinArmed = false; } } catch (Exception ex) { ManualLogSource logS3 = LogS; if (logS3 != null) { logS3.LogWarning((object)("[ServerGuard.Client] ReassertServerToJoin failed: " + ex.Message)); } } } internal void DisarmQuickJoin() { _quickJoinArmed = false; } private IEnumerator RefreshPlayerCount(string host, int gamePort) { yield return null; string text = "Players: ?"; try { byte[] array = new byte[25]; byte b = byte.MaxValue; array[3] = byte.MaxValue; array[0] = (array[1] = (array[2] = b)); array[4] = 84; Encoding.ASCII.GetBytes("Source Engine Query\0").CopyTo(array, 5); int[] obj = new int[2] { gamePort, gamePort + 1 }; byte[] array2 = null; int[] array3 = obj; foreach (int port in array3) { try { using UdpClient udpClient = new UdpClient(); udpClient.Client.ReceiveTimeout = 2000; udpClient.Connect(host, port); udpClient.Send(array, array.Length); IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); array2 = udpClient.Receive(ref remoteEP); if (array2 != null && array2.Length > 14) { break; } array2 = null; continue; } catch { array2 = null; continue; } } if (array2 != null && array2.Length > 14 && array2[4] == 73) { int num = 6; for (int j = 0; j < 4; j++) { if (num >= array2.Length) { break; } while (num < array2.Length && array2[num++] != 0) { } } num += 2; if (num < array2.Length) { int num2 = array2[num]; int num3 = ((num + 1 < array2.Length) ? array2[num + 1] : 0); text = ((num3 > 0) ? $"Players: {num2} / {num3}" : $"Players: {num2}"); } } } catch { } if ((Object)(object)_playerCountText != (Object)null) { SetAnyText(_playerCountText, text); } } } }