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.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("YourName")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Custom Mod Permission Checker for Valheim")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ModPermChecker")] [assembly: AssemblyTitle("ModPermChecker")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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 ModPermChecker { [BepInPlugin("com.custom.modpermchecker", "ModPermChecker", "1.0.0")] public class ModPermCheckerPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Game), "Awake")] public static class GameAwake_Patch { public static void Postfix() { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register("RPC_VerifyClientMods", (Action)RPC_VerifyClientMods); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] public static class ClientSendMods_Patch { public static void Postfix(ZNet __instance, ZRpc rpc) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (__instance.IsServer()) { return; } List list = Chainloader.PluginInfos.Keys.ToList(); ZPackage val = new ZPackage(); val.Write(list.Count); foreach (string item in list) { val.Write(item); } ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RPC_VerifyClientMods", new object[1] { val }); } } [Serializable] public class ConfigModel { public List SpecialMods = new List(); public List Permissions = new List(); } [Serializable] public class UserPermission { public string SteamID; public List AllowedMods = new List(); } public const string ModGUID = "com.custom.modpermchecker"; public const string ModName = "ModPermChecker"; public const string ModVersion = "1.0.0"; internal static ManualLogSource ModLogger; private static readonly string ConfigPath = Path.Combine(Paths.ConfigPath, "CustomModPermissions.json"); private static ConfigModel serverConfig; private static readonly Dictionary> AllowedPermissions = new Dictionary>(); private static readonly HashSet RestrictedMods = new HashSet(StringComparer.OrdinalIgnoreCase); private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) ModLogger = ((BaseUnityPlugin)this).Logger; new Harmony("com.custom.modpermchecker").PatchAll(); LoadPermissionsConfig(); ModLogger.LogInfo((object)"ModPermChecker v1.0.0 載入完成!"); } public static void LoadPermissionsConfig() { if (!File.Exists(ConfigPath)) { CreateDefaultConfig(); } try { serverConfig = JsonUtility.FromJson(File.ReadAllText(ConfigPath)); RestrictedMods.Clear(); AllowedPermissions.Clear(); if (serverConfig != null) { if (serverConfig.SpecialMods != null) { foreach (string specialMod in serverConfig.SpecialMods) { RestrictedMods.Add(specialMod.Trim()); } } if (serverConfig.Permissions != null) { foreach (UserPermission permission in serverConfig.Permissions) { string key = permission.SteamID.Trim(); if (!AllowedPermissions.ContainsKey(key)) { AllowedPermissions[key] = new HashSet(StringComparer.OrdinalIgnoreCase); } if (permission.AllowedMods == null) { continue; } foreach (string allowedMod in permission.AllowedMods) { AllowedPermissions[key].Add(allowedMod.Trim()); } } } } ManualLogSource modLogger = ModLogger; if (modLogger != null) { modLogger.LogInfo((object)$"成功載入受限模組: {RestrictedMods.Count} 個, 授權使用者: {AllowedPermissions.Count} 位。"); } } catch (Exception ex) { ManualLogSource modLogger2 = ModLogger; if (modLogger2 != null) { modLogger2.LogError((object)("解析 CustomModPermissions.json 失敗: " + ex.Message)); } } } private static void CreateDefaultConfig() { string contents = JsonUtility.ToJson((object)new ConfigModel { SpecialMods = new List { "com.author.infinityhammer", "com.author.worldeditcommands" }, Permissions = new List { new UserPermission { SteamID = "76561198000000000", AllowedMods = new List { "com.author.infinityhammer", "com.author.worldeditcommands" } } } }, true); File.WriteAllText(ConfigPath, contents); } private static void RPC_VerifyClientMods(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null) { return; } string hostName = peer.m_socket.GetHostName(); int num = pkg.ReadInt(); List list = new List(); for (int i = 0; i < num; i++) { list.Add(pkg.ReadString()); } foreach (string item in list) { if (RestrictedMods.Contains(item) && (!AllowedPermissions.ContainsKey(hostName) || !AllowedPermissions[hostName].Contains(item))) { ManualLogSource modLogger = ModLogger; if (modLogger != null) { modLogger.LogWarning((object)("玩家 " + hostName + " 未獲授權安裝受限模組: [" + item + "],已強制斷開連線!")); } peer.m_rpc.Invoke("Error", new object[1] { 8 }); ZNet.instance.Disconnect(peer); return; } } ManualLogSource modLogger2 = ModLogger; if (modLogger2 != null) { modLogger2.LogInfo((object)("玩家 " + hostName + " 模組權限驗證通過。")); } } } }