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 SkilledCarryWeight v1.4.3
SkilledCarryWeight.dll
Decompiled 5 days agousing System; using System.Collections; 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.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using ServerSync; using SkilledCarryWeight.Configs; using SkilledCarryWeight.Extensions; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SkilledCarryWeight")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SkilledCarryWeight")] [assembly: AssemblyCopyright("Copyright © 2023")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.4.3")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.3.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ServerSync { internal class ConfigSync { private class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List<ZNetPeer> peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List<string> CurrentList = new List<string>(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List<string>(adminList.GetList()); List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return (listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })); }).ToList(); List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList(); SendAdmin(nonAdminPeer, isAdmin: false); SendAdmin(adminPeer, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public Dictionary<string, OwnConfigEntryBase> configEntries = new Dictionary<string, OwnConfigEntryBase>(); public Dictionary<string, CustomSyncedValueBase> customValues = new Dictionary<string, CustomSyncedValueBase>(); } private class PackageEntry { public string section = ""; public string key = ""; public Type? type; public object? value; } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } private static bool ProcessingServerUpdate; private static readonly HashSet<ConfigSync> configSyncs; private static bool isServer; private static bool lockExempt; private static long packageCounter; public string Name; public bool IsSourceOfTruth = true; public bool InitialSyncDone; public string DisplayName = ""; public string CurrentVersion = ""; public string MinimumRequiredVersion = ""; public bool ModRequired; private OwnConfigEntryBase? lockedConfig; private Action lockedConfigChanged = delegate { }; private readonly List<OwnConfigEntryBase> allConfigs = new List<OwnConfigEntryBase>(); internal event Action<bool> SourceOfTruthChanged = delegate { }; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet<ConfigSync>(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } private bool isLockExempt(ZRpc rpc) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (lockExempt) { return true; } if (isServer) { SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); string hostName = rpc.GetSocket().GetHostName(); return (methodInfo == null) ? val.Contains(hostName) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, hostName })); } return false; } private OwnConfigEntryBase configData(ConfigEntryBase config) { return allConfigs.First((OwnConfigEntryBase x) => x.BaseConfig == config); } public SyncedConfigEntry<T> AddConfigEntry<T>(ConfigEntry<T> configEntry) { OwnConfigEntryBase ownConfigEntryBase = allConfigs.FirstOrDefault((OwnConfigEntryBase x) => (object)x.BaseConfig == configEntry); SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry<T>(configEntry); configEntry.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(0L, (ConfigEntryBase)(object)configEntry); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry<T> AddLockingConfigEntry<T>(ConfigEntry<T> lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry<T>(lockingConfig); lockingConfig.SettingChanged += delegate { lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry<T>)lockedConfig; } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { if (isServer) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged = (Action)Delegate.Combine(lockedConfigChanged, new Action(serverLockedSettingChanged)); IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void serverLockedSettingChanged() { if (lockedConfig != null) { ((SyncedConfigEntry<IConvertible>)lockedConfig).AssignLocalValue(((SyncedConfigEntry<IConvertible>)lockedConfig).Value); } } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { ParsedConfigs parsedConfigs = ParseConfigs(package); foreach (KeyValuePair<string, OwnConfigEntryBase> item in parsedConfigs.configEntries.Where((KeyValuePair<string, OwnConfigEntryBase> x) => x.Value.SynchronizedConfig)) { OwnConfigEntryBase value = item.Value; if (value is SyncedConfigEntry<IConvertible> syncedConfigEntry && (value != lockedConfig || isLockExempt(SnatchCurrentlyHandlingRPC.currentRpc))) { syncedConfigEntry.AssignLocalValue(syncedConfigEntry.Value); } } if (clientUpdate && isServer) { Broadcast(0L, package); } return true; } private ParsedConfigs ParseConfigs(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string section = package.ReadString(); string key = package.ReadString(); string typeName = package.ReadString(); Type valueType = Type.GetType(typeName); object obj = null; if (valueType != null) { MethodInfo methodInfo = typeof(ZPackage).GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "Read" && m.ReturnType == valueType && m.GetParameters().Length == 0); if (methodInfo != null) { obj = methodInfo.Invoke(package, null); } } string key2 = section + "." + key; OwnConfigEntryBase ownConfigEntryBase = allConfigs.FirstOrDefault((OwnConfigEntryBase x) => x.BaseConfig.Definition.Section == section && x.BaseConfig.Definition.Key == key); if (ownConfigEntryBase != null) { parsedConfigs.configEntries[key2] = ownConfigEntryBase; } } return parsedConfigs; } private static ZPackage ConfigsToPackage(IEnumerable<ConfigEntryBase>? configs = null, IEnumerable<CustomSyncedValueBase>? customValues = null, IEnumerable<PackageEntry>? packageEntries = null, bool partial = true) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(partial ? 1 : 0); List<ConfigEntryBase> list = configs?.ToList() ?? new List<ConfigEntryBase>(); List<CustomSyncedValueBase> list2 = customValues?.ToList() ?? new List<CustomSyncedValueBase>(); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (ConfigEntryBase item in list) { val.Write(item.Definition.Section); val.Write(item.Definition.Key); val.Write(item.SettingType.FullName ?? ""); AccessTools.DeclaredMethod(typeof(ZPackage), "Write", new Type[1] { item.SettingType }, (Type[])null)?.Invoke(val, new object[1] { item.BoxedValue }); } foreach (CustomSyncedValueBase item2 in list2) { val.Write("CustomSyncedValue"); val.Write(item2.Identifier); val.Write(item2.Type?.FullName ?? ""); item2.WriteToPackage(val); } if (packageEntries != null) { foreach (PackageEntry packageEntry in packageEntries) { val.Write(packageEntry.section); val.Write(packageEntry.key); val.Write(packageEntry.type?.FullName ?? ""); AccessTools.DeclaredMethod(typeof(ZPackage), "Write", new Type[1] { packageEntry.type }, (Type[])null)?.Invoke(val, new object[1] { packageEntry.value }); } } return val; } private void Broadcast(long target, ConfigEntryBase config) { Broadcast(target, ConfigsToPackage((IEnumerable<ConfigEntryBase>?)(object)new ConfigEntryBase[1] { config })); } private void Broadcast(long target, ZPackage package) { if (ZRoutedRpc.instance != null) { if (isServer) { ZRoutedRpc.instance.InvokeRoutedRPC(target, Name + " ConfigSync", new object[1] { package }); } else { ZRoutedRpc.instance.InvokeRoutedRPC(0L, Name + " ConfigSync", new object[1] { package }); } } } private void BroadcastToPeers(List<ZNetPeer> peers, ZPackage package) { foreach (ZNetPeer peer in peers) { peer.m_rpc.Invoke(Name + " ConfigSync", new object[1] { package }); } } private IEnumerator sendZPackage(List<ZNetPeer> peers, ZPackage package) { yield return null; BroadcastToPeers(peers, package); } private void resetConfigsFromServer() { foreach (OwnConfigEntryBase allConfig in allConfigs) { if (allConfig.SynchronizedConfig && allConfig.LocalBaseValue != null) { if (allConfig is SyncedConfigEntry<IConvertible> syncedConfigEntry) { syncedConfigEntry.AssignLocalValue(syncedConfigEntry.Value); } allConfig.LocalBaseValue = null; } } } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field)] internal class ConfigurationManagerAttributes : Attribute { public bool? ShowRangeButtons; public string? Category; public string? Name; public string? Description; public int? Order; public bool? ReadOnly; public bool? Browsable; public string? CustomDrawer; public bool? IsAdminOnly; } internal class CustomSyncedValue<T> : CustomSyncedValueBase { private bool localIsOwner = true; private object? boxedValue; public override object? BoxedValue { get { return boxedValue; } set { boxedValue = value; } } public T Value { get { return (T)boxedValue; } set { boxedValue = value; } } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } internal abstract class CustomSyncedValueBase { public object? LocalBaseValue; public readonly ConfigSync Config; public readonly string Identifier; public readonly int Priority; public readonly Type? Type; public bool SynchronizedConfig = true; private bool localIsOwner = true; public abstract object? BoxedValue { get; set; } protected CustomSyncedValueBase(ConfigSync config, string identifier, Type type, int priority = 0) { Config = config; Identifier = identifier; Type = type; Priority = priority; config.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } public void WriteToPackage(ZPackage package) { AccessTools.DeclaredMethod(typeof(ZPackage), "Write", new Type[1] { Type }, (Type[])null)?.Invoke(package, new object[1] { BoxedValue }); } } internal abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } internal class SyncedConfigEntry<T> : OwnConfigEntryBase { public readonly ConfigEntry<T> SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry<T> sourceConfig) { SourceConfig = sourceConfig; } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } [HarmonyPatch] internal class VersionCheck { private static readonly HashSet<VersionCheck> versionChecks; private static readonly Dictionary<string, string> notProcessedNames; public string Name; private string? displayName; private string? currentVersion; private string? minimumRequiredVersion; public bool ModRequired = true; private string? ReceivedCurrentVersion; private string? ReceivedMinimumRequiredVersion; private readonly List<ZRpc> ValidatedClients = new List<ZRpc>(); private ConfigSync? ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { return minimumRequiredVersion ?? (ModRequired ? CurrentVersion : "0.0.0"); } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet<VersionCheck>(); notProcessedNames = new Dictionary<string, string>(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool flag = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion); bool flag2 = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion); return flag && flag2; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } return (new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion)) ? (DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + ".") : (DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."); } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error(ZRpc? rpc = null) { return (rpc == null) ? ErrorClient() : ErrorServer(rpc); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action<ZRpc, ZPackage>? original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; VersionCheck[] array3 = array2; foreach (VersionCheck versionCheck in array3) { Debug.LogWarning((object)versionCheck.Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action<ZRpc, ZPackage> action = (Action<ZRpc, ZPackage>)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register<ZPackage>("ServerSync VersionCheck", (Action<ZRpc, ZPackage>)delegate(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, action); }); } else { peer.m_rpc.Register<ZPackage>("ServerSync VersionCheck", (Action<ZRpc, ZPackage>)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] [HarmonyPostfix] private static void ShowConnectionError(FejdStartup __instance) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair<string, string> item in notProcessedNames.OrderBy((KeyValuePair<string, string> kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent<RectTransform>(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent<RectTransform>(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } } namespace SkilledCarryWeight { [BepInPlugin("Searica.Valheim.SkilledCarryWeight", "SkilledCarryWeight", "1.4.3")] internal sealed class SkilledCarryWeight : BaseUnityPlugin { internal class SkillConfig { public ConfigEntry<bool> enabledConfig; public ConfigEntry<float> coeffConfig; public ConfigEntry<float> powConfig; public bool IsEnabled => enabledConfig.Value; public float Coeff => coeffConfig.Value; public float Pow => powConfig.Value; } internal const string Author = "Searica"; public const string PluginName = "SkilledCarryWeight"; public const string PluginGUID = "Searica.Valheim.SkilledCarryWeight"; public const string PluginVersion = "1.4.3"; private static readonly ConfigSync configSync = new ConfigSync("Searica.Valheim.SkilledCarryWeight") { DisplayName = "SkilledCarryWeight", CurrentVersion = "1.4.3", MinimumRequiredVersion = "1.4.3" }; internal static readonly Dictionary<SkillType, SkillConfig> SkillConfigsMap = new Dictionary<SkillType, SkillConfig>(); internal static ConfigEntry<bool> EnableCartPatch; internal static ConfigEntry<float> CartPower; internal static ConfigEntry<float> MaxMassReduction; internal static ConfigEntry<float> MinCarryWeight; internal static ConfigEntry<KeyCode> QuickCartKey; internal static ConfigEntry<float> AttachDistance; internal static ConfigEntry<bool> AttachOutOfPlace; private static readonly string MainSection = ConfigManager.SetStringPriority("Global", 3); private static readonly string CartSection = ConfigManager.SetStringPriority("Cart Mass", 2); private static readonly string QuickCartSection = ConfigManager.SetStringPriority("Quick Cart", 1); private static bool SettingsUpdated = false; public void Awake() { Log.Init(((BaseUnityPlugin)this).Logger); ConfigManager.Init("Searica.Valheim.SkilledCarryWeight", ((BaseUnityPlugin)this).Config); Initialize(); ConfigManager.Save(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.SkilledCarryWeight"); Game.isModded = true; ConfigManager.SetupWatcher(); ConfigManager.CheckForConfigManager(); ConfigManager.OnConfigWindowClosed += delegate { if (SettingsUpdated) { ConfigManager.Save(); SettingsUpdated = false; } }; } public void OnDestroy() { ConfigManager.Save(); } private static void OnSettingChanged(object sender, EventArgs e) { if (!SettingsUpdated) { SettingsUpdated = true; } } internal unsafe static void Initialize() { //IL_01d7: 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_01df: Invalid comparison between Unknown and I4 //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) Log.Verbosity = ConfigManager.BindConfig(MainSection, "Verbosity", LogLevel.Low, "Low will log basic information about the mod. Medium will log information that is useful for troubleshooting. High will log a lot of information, do not set it to this without good reason as it will slow down your game.", null, synced: false, configSync); Log.Verbosity.SettingChanged += OnSettingChanged; EnableCartPatch = ConfigManager.BindConfig(CartSection, "CarryWeightAffectsCart", value: true, "Set to true/enabled to allow your max carry weight affect how easy carts are to pull by reducing the mass of carts you pull.", null, synced: true, configSync); EnableCartPatch.SettingChanged += OnSettingChanged; CartPower = ConfigManager.BindConfig(CartSection, "Power", 1f, "Affects how much your maximum carry weight making pulling carts easier. Higher powers make your maximum carry weight reduce the mass of carts more.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), synced: true, configSync); CartPower.SettingChanged += OnSettingChanged; MaxMassReduction = ConfigManager.BindConfig(CartSection, "MaxMassReduction", 0.7f, "Maximum reduction in cart mass due to increased max carry weight. Limits effective cart mass to always be equal to or greater than Mass * (1 - MaxMassReduction)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), synced: true, configSync); MaxMassReduction.SettingChanged += OnSettingChanged; MinCarryWeight = ConfigManager.BindConfig(CartSection, "MinCarryWeight", 300f, "Minimum value your maximum carry weight must be before it starts making carts easier to pull.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(300f, 1000f), synced: true, configSync); MinCarryWeight.SettingChanged += OnSettingChanged; QuickCartKey = ConfigManager.BindConfig<KeyCode>(QuickCartSection, "QuickCartKey", (KeyCode)103, "The hotkey used to attach to or detach from a nearby cart.", null, synced: false, configSync); AttachDistance = ConfigManager.BindConfig(QuickCartSection, "AttachDistance", 5f, "Maximum distance to attach a cart from.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 8f), synced: true, configSync); AttachOutOfPlace = ConfigManager.BindConfig(QuickCartSection, "AttachOutOfPlace", value: true, "Allow attaching the cart even when out of place.", null, synced: true, configSync); SkillType[] s_allSkills = Skills.s_allSkills; for (int i = 0; i < s_allSkills.Length; i++) { SkillType val = s_allSkills[i]; if ((int)val != 999) { string section = ((object)(*(SkillType*)(&val))/*cast due to .constrained prefix*/).ToString(); SkillConfig skillConfig = new SkillConfig(); skillConfig.enabledConfig = ConfigManager.BindConfig(section, ConfigManager.SetStringPriority("Enabled", 1), GetDefaultEnabledValue(val), "Set to true/enabled to allow this skill to increase your max carry weight.", null, synced: true, configSync); skillConfig.enabledConfig.SettingChanged += OnSettingChanged; skillConfig.coeffConfig = ConfigManager.BindConfig(section, "Coefficient", 0.25f, "Value to multiply the skill level by to determine how much extra carry weight it grants.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), synced: true, configSync); skillConfig.coeffConfig.SettingChanged += OnSettingChanged; skillConfig.powConfig = ConfigManager.BindConfig(section, "Power", 1f, "Power the skill level is raised to before multiplying by Coefficient to determine extra carry weight.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), synced: true, configSync); skillConfig.powConfig.SettingChanged += OnSettingChanged; SkillConfigsMap[val] = skillConfig; } } } private static bool GetDefaultEnabledValue(SkillType skillType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: 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_0008: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if ((int)skillType <= 13) { if ((int)skillType == 12) { return true; } if ((int)skillType == 13) { return true; } } else { switch (skillType - 100) { case 2: return true; case 0: return true; case 3: return true; case 1: return true; } if ((int)skillType == 110) { return true; } } return false; } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(QuickCartKey.Value) && PlayerCanAttach() && TryGetClosestVagon(out var closestVagon) && (Object)(object)closestVagon != (Object)null) { closestVagon.Interact((Humanoid)(object)Player.m_localPlayer, false, false); } } private static bool PlayerCanAttach() { return Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead() && !((Character)Player.m_localPlayer).InPlaceMode(); } private static bool TryGetClosestVagon(out Vagon closestVagon) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) closestVagon = null; float num = float.PositiveInfinity; Vector3 val = ((Component)Player.m_localPlayer).transform.position + Vector3.up; Collider[] array = Physics.OverlapSphere(val, AttachDistance.Value); foreach (Collider val2 in array) { if (TryGetVagon(val2, out var vagon) && Object.op_Implicit((Object)(object)val2.attachedRigidbody) && (vagon.IsAttached((Character)(object)Player.m_localPlayer) || !vagon.InUse())) { float num2 = Vector3.Distance(val2.ClosestPoint(val), val); if (num2 < num) { Log.LogInfo($"Found cart {num2} away", LogLevel.Medium); num = num2; closestVagon = vagon; } } } return num < AttachDistance.Value; } private static bool TryGetVagon(Collider collider, out Vagon vagon) { vagon = ((Component)collider).gameObject.GetComponent<Vagon>(); if (!Object.op_Implicit((Object)(object)vagon) && Object.op_Implicit((Object)(object)((Component)collider).transform.parent)) { vagon = ((Component)((Component)collider).transform.parent).GetComponent<Vagon>(); } return Object.op_Implicit((Object)(object)vagon); } } internal enum LogLevel { Low, Medium, High } internal static class Log { internal static ManualLogSource _logSource; internal static ConfigEntry<LogLevel> Verbosity { get; set; } internal static LogLevel VerbosityLevel => Verbosity.Value; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void LogDebug(object data) { _logSource.LogDebug(data); } internal static void LogError(object data) { _logSource.LogError(data); } internal static void LogFatal(object data) { _logSource.LogFatal(data); } internal static void LogInfo(object data, LogLevel level = LogLevel.Low) { if (Verbosity == null || VerbosityLevel >= level) { _logSource.LogInfo(data); } } internal static void LogMessage(object data) { _logSource.LogMessage(data); } internal static void LogWarning(object data) { _logSource.LogWarning(data); } internal static void LogGameObject(GameObject prefab, bool includeChildren = false) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown LogInfo("***** " + ((Object)prefab).name + " *****"); Component[] components = prefab.GetComponents<Component>(); foreach (Component compo in components) { LogComponent(compo); } if (!includeChildren) { return; } LogInfo("***** " + ((Object)prefab).name + " (children) *****"); foreach (Transform item in prefab.transform) { Transform val = item; LogInfo(" - " + ((Object)((Component)val).gameObject).name); Component[] components2 = ((Component)val).gameObject.GetComponents<Component>(); foreach (Component compo2 in components2) { LogComponent(compo2); } } } internal static void LogComponent(Component compo) { LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---"); PropertyInfo[] properties = ((object)compo).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); PropertyInfo[] array = properties; foreach (PropertyInfo propertyInfo in array) { LogInfo($" - {propertyInfo.Name} = {propertyInfo.GetValue(compo)}"); } FieldInfo[] fields = ((object)compo).GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); FieldInfo[] array2 = fields; foreach (FieldInfo fieldInfo in array2) { LogInfo($" - {fieldInfo.Name} = {fieldInfo.GetValue(compo)}"); } } } } namespace SkilledCarryWeight.Patches { [HarmonyPatch(typeof(Player))] internal static class PlayerPatch { [HarmonyPostfix] [HarmonyPatch("GetMaxCarryWeight")] private static void GetMaxCarryWeight(Player __instance, ref float __result) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Skills skills = ((Character)__instance).GetSkills(); foreach (SkillDef skill in skills.m_skills) { if (SkilledCarryWeight.SkillConfigsMap.TryGetValue(skill.m_skill, out var value) && value.IsEnabled) { __result += value.Coeff * Mathf.Pow(skills.GetSkillLevel(skill.m_skill), value.Pow); if (float.IsInfinity(__result)) { __result = float.MaxValue; break; } } } } } [HarmonyPatch(typeof(Vagon))] internal static class VagonPatch { [HarmonyPrefix] [HarmonyPatch("SetMass")] private static void SetMassPrefix(Vagon __instance, ref float mass) { if (SkilledCarryWeight.EnableCartPatch.Value && Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsOwner() && __instance.IsAttached((Character)(object)Player.m_localPlayer)) { Player localPlayer = Player.m_localPlayer; float num = mass * Mathf.Pow(SkilledCarryWeight.MinCarryWeight.Value / localPlayer.GetMaxCarryWeight(), SkilledCarryWeight.CartPower.Value); mass = Mathf.Max(num, mass * (1f - SkilledCarryWeight.MaxMassReduction.Value)); } } [HarmonyPrefix] [HarmonyPatch("CanAttach")] private static bool CanAttachPrefix(Vagon __instance, GameObject go, ref bool __result) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (!SkilledCarryWeight.AttachOutOfPlace.Value || ((Component)__instance).transform.up.y < 0.1f || (Object)(object)go != (Object)(object)((Component)Player.m_localPlayer).gameObject) { __instance.m_detachDistance = SkilledCarryWeight.AttachDistance.Value; return true; } float num = Vector3.Distance(go.transform.position + __instance.m_attachOffset, __instance.m_attachPoint.position); bool flag = num < SkilledCarryWeight.AttachDistance.Value; __result = !((Character)Player.m_localPlayer).IsTeleporting() && !((Character)Player.m_localPlayer).InDodge() && flag; return false; } [HarmonyPostfix] [HarmonyPatch("GetHoverText")] private static void GetHoverTextPostfix(Vagon __instance, ref string __result) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) KeyCode value = SkilledCarryWeight.QuickCartKey.Value; __result = $"{__instance.m_name}\n[<color=yellow>{value}</color>] Quick Attach/Detach"; } } } namespace SkilledCarryWeight.Extensions { internal static class EventExtensions { public static void SafeInvoke(this Action events) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action action = (Action)invocationList[i]; try { action(); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}"); } } } public static void SafeInvoke<TArg1>(this Action<TArg1> events, TArg1 arg1) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action<TArg1> action = (Action<TArg1>)invocationList[i]; try { action(arg1); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}"); } } } public static void SafeInvoke<TArg1, TArg2>(this Action<TArg1, TArg2> events, TArg1 arg1, TArg2 arg2) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { Action<TArg1, TArg2> action = (Action<TArg1, TArg2>)invocationList[i]; try { action(arg1, arg2); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{ex}"); } } } public static void SafeInvoke<TEventArg>(this EventHandler<TEventArg> events, object sender, TEventArg arg1) { if (events == null) { return; } Delegate[] invocationList = events.GetInvocationList(); for (int i = 0; i < invocationList.Length; i++) { EventHandler<TEventArg> eventHandler = (EventHandler<TEventArg>)invocationList[i]; try { eventHandler(sender, arg1); } catch (Exception ex) { Log.LogWarning($"Exception thrown at event {new StackFrame(1).GetMethod().Name} in {eventHandler.Method.DeclaringType.Name}.{eventHandler.Method.Name}:\n{ex}"); } } } } internal static class ReflectionUtils { public const BindingFlags AllBindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty; internal static MethodInfo GetMethod(Type type, string name, Type[] types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == name && HasMatchingParameterTypes(0, types, methodInfo.GetParameters())) { return methodInfo; } } return null; } internal static MethodInfo GetGenericMethod(Type type, string name, int genericParameterCount, Type[] types) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty); foreach (MethodInfo methodInfo in methods) { if (methodInfo.IsGenericMethod && methodInfo.ContainsGenericParameters && methodInfo.Name == name && HasMatchingParameterTypes(genericParameterCount, types, methodInfo.GetParameters())) { return methodInfo; } } return null; } private static bool HasMatchingParameterTypes(int genericParameterCount, Type[] types, ParameterInfo[] parameters) { if (parameters.Length < genericParameterCount || parameters.Length != types.Length) { return false; } int num = 0; for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType.IsGenericParameter) { num++; } else if (types[i] != parameters[i].ParameterType) { return false; } } if (num != genericParameterCount) { return false; } return true; } } } namespace SkilledCarryWeight.Configs { internal static class ConfigManager { private static string ConfigFileName; private static string ConfigFileFullPath; private static ConfigFile configFile; private static BaseUnityPlugin ConfigurationManager; private const string ConfigManagerGUID = "com.bepis.bepinex.configurationmanager"; private static readonly ConfigurationManagerAttributes AdminConfig = new ConfigurationManagerAttributes { IsAdminOnly = true }; private static readonly ConfigurationManagerAttributes ClientConfig = new ConfigurationManagerAttributes { IsAdminOnly = false }; private const char ZWS = '\u200b'; internal static event Action OnConfigWindowClosed; internal static event Action OnConfigFileReloaded; private static void InvokeOnConfigWindowClosed() { ConfigManager.OnConfigWindowClosed?.SafeInvoke(); } private static void InvokeOnConfigFileReloaded() { ConfigManager.OnConfigFileReloaded?.SafeInvoke(); } internal static ConfigEntry<T> BindConfig<T>(string section, string name, T value, string description, AcceptableValueBase acceptVals = null, bool synced = true, ConfigSync configSync = null) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown string extendedDescription = GetExtendedDescription(description, synced); ConfigEntry<T> val = configFile.Bind<T>(section, name, value, new ConfigDescription(extendedDescription, acceptVals, new object[1] { synced ? AdminConfig : ClientConfig })); if (synced && configSync != null) { configSync.AddConfigEntry<T>(val).SynchronizedConfig = true; } return val; } internal static string SetStringPriority(string sectionName, int priority) { if (priority == 0) { return sectionName; } return new string('\u200b', priority) + sectionName; } internal static string GetExtendedDescription(string description, bool synchronizedSetting) { return description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"); } internal static void Init(string GUID, ConfigFile config, bool saveOnConfigSet = false) { configFile = config; configFile.SaveOnConfigSet = saveOnConfigSet; ConfigFileName = GUID + ".cfg"; ConfigFileFullPath = Path.Combine(Paths.ConfigPath, ConfigFileName); } internal static bool DisableSaveOnConfigSet() { bool saveOnConfigSet = configFile.SaveOnConfigSet; configFile.SaveOnConfigSet = false; return saveOnConfigSet; } internal static void SaveOnConfigSet(bool value) { configFile.SaveOnConfigSet = value; } internal static void Save() { configFile.Save(); } internal static void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReloadConfigFile; fileSystemWatcher.Created += ReloadConfigFile; fileSystemWatcher.Renamed += ReloadConfigFile; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private static void ReloadConfigFile(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { Log.LogInfo("Reloading config file"); bool value = DisableSaveOnConfigSet(); configFile.Reload(); SaveOnConfigSet(value); InvokeOnConfigFileReloaded(); } catch { Log.LogError("There was an issue loading your " + ConfigFileName); Log.LogError("Please check your config entries for spelling and format!"); } } internal static void CheckForConfigManager() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType != 4 && Chainloader.PluginInfos.TryGetValue("com.bepis.bepinex.configurationmanager", out var value) && Object.op_Implicit((Object)(object)value.Instance)) { ConfigurationManager = value.Instance; Log.LogDebug("Configuration manager found, hooking DisplayingWindowChanged"); EventInfo eventInfo = ((object)ConfigurationManager).GetType().GetEvent("DisplayingWindowChanged"); if (eventInfo != null) { Action<object, object> action = OnConfigManagerDisplayingWindowChanged; Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, action.Target, action.Method); eventInfo.AddEventHandler(ConfigurationManager, handler); } } } private static void OnConfigManagerDisplayingWindowChanged(object sender, object e) { PropertyInfo property = ((object)ConfigurationManager).GetType().GetProperty("DisplayingWindow"); if (!(bool)property.GetValue(ConfigurationManager, null)) { InvokeOnConfigWindowClosed(); } } } }