Please disclose if your mod was created primarily 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 SkillControl v1.0.5
SkillControl.dll
Decompiled 2 years ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using SkillControl.Managers; using SkillControl.Professions; using SkillControl.UI; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Core.Tokens; using YamlDotNet.Helpers; using YamlDotNet.Serialization; using YamlDotNet.Serialization.BufferedDeserialization; using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators; using YamlDotNet.Serialization.Converters; using YamlDotNet.Serialization.EventEmitters; using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NodeDeserializers; using YamlDotNet.Serialization.NodeTypeResolvers; using YamlDotNet.Serialization.ObjectFactories; using YamlDotNet.Serialization.ObjectGraphTraversalStrategies; using YamlDotNet.Serialization.ObjectGraphVisitors; using YamlDotNet.Serialization.Schemas; using YamlDotNet.Serialization.TypeInspectors; using YamlDotNet.Serialization.TypeResolvers; using YamlDotNet.Serialization.Utilities; using YamlDotNet.Serialization.ValueDeserializers; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("SkillControl")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyProduct("SkillControl")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.0.5")] [assembly: AssemblyCompany("RustyMods")] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.5.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<92279cac-f02a-492f-8688-a3b9c598b742>Embedded] internal sealed class <92279cac-f02a-492f-8688-a3b9c598b742>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [<92279cac-f02a-492f-8688-a3b9c598b742>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [CompilerGenerated] internal sealed class <c06f07ea-e12a-4405-ac6d-a489aadd8da6>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <c06f07ea-e12a-4405-ac6d-a489aadd8da6>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <c06f07ea-e12a-4405-ac6d-a489aadd8da6>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [<92279cac-f02a-492f-8688-a3b9c598b742>Embedded] internal sealed class <bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContextAttribute : Attribute { public readonly byte Flag; public <bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace SkillControl { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] [BepInPlugin("RustyMods.SkillControl", "SkillControl", "1.0.5")] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] public class SkillControlPlugin : BaseUnityPlugin { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] public enum Toggle { On = 1, Off = 0 } [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] [UsedImplicitly] public string Category; [UsedImplicitly] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(new byte[] { 2, 1 })] public Action<ConfigEntryBase> CustomDrawer; } internal const string ModName = "SkillControl"; internal const string ModVersion = "1.0.5"; internal const string Author = "RustyMods"; private const string ModGUID = "RustyMods.SkillControl"; private static string ConfigFileName = "RustyMods.SkillControl.cfg"; private static string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("RustyMods.SkillControl"); public static readonly ManualLogSource SkillControlLogger; public static readonly ConfigSync ConfigSync; public static readonly AssetBundle _AssetBundle; private static ConfigEntry<Toggle> _serverConfigLocked; public static ConfigEntry<KeyCode> _UIKey; public static ConfigEntry<int> _JobLimit; public static ConfigEntry<string> _Currency; public static ConfigEntry<int> _CostToRemove; public static ConfigEntry<Toggle> _ForceJob; public static ConfigEntry<Vector2> _UIPosition; public static ConfigEntry<Toggle> _RemoveSkillExperience; public static ConfigEntry<Toggle> _OverrideDefaults; public void Awake() { Localizer.Load(); PluginPaths.CreateDirectories(); FileWaterManager.InitFileWatcher(); SpriteManager.GetIcons(); JobManager.InitJobs(); InitConfigs(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); } private void Update() { LoadUI.UpdateUI(); } private static AssetBundle GetAssetBundle(string fileName) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = executingAssembly.GetManifestResourceNames().Single([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (string str) => str.EndsWith(fileName)); using Stream stream = executingAssembly.GetManifestResourceStream(name); return AssetBundle.LoadFromStream(stream); } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { SkillControlLogger.LogDebug((object)"ReadConfigValues called"); ((BaseUnityPlugin)this).Config.Reload(); } catch { SkillControlLogger.LogError((object)("There was an issue loading your " + ConfigFileName)); SkillControlLogger.LogError((object)"Please check your config entries for spelling and format!"); } } private void InitConfigs() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); _UIKey = config<KeyCode>("2 - Settings", "Key", (KeyCode)288, "Set key code to open job menu", synchronizedSetting: false); _JobLimit = config("2 - Settings", "Limit", 2, new ConfigDescription("Set the amount of jobs a player can have", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); _Currency = config("2 - Settings", "Currency", "Coins", "Set the currency used for skill controller, if invalid, defaults to coins"); _CostToRemove = config("2 - Settings", "Cost To Remove", 999, new ConfigDescription("Set the cost to remove job", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), Array.Empty<object>())); _ForceJob = config("2 - Settings", "Force Employment", Toggle.Off, "If on, job menu will stay open until player chooses at least one job"); _UIPosition = config<Vector2>("2 - Settings", "Position", Vector2.zero, "Set the position of the UI", synchronizedSetting: false); _UIPosition.SettingChanged += LoadUI.OnPositionChange; _RemoveSkillExperience = config("2 - Settings", "Lose Skills", Toggle.Off, "If on, removing jobs, also removes skill experiences"); _OverrideDefaults = config("2 - Settings", "Override Defaults", Toggle.On, "If on, plugin overrides default skill gain"); } private ConfigEntry<T> config<[<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> config<[<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } static SkillControlPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; SkillControlLogger = Logger.CreateLogSource("SkillControl"); ConfigSync = new ConfigSync("RustyMods.SkillControl") { DisplayName = "SkillControl", CurrentVersion = "1.0.5", MinimumRequiredVersion = "1.0.5" }; _AssetBundle = GetAssetBundle("jobsbundle"); _serverConfigLocked = null; _UIKey = null; _JobLimit = null; _Currency = null; _CostToRemove = null; _ForceJob = null; _UIPosition = null; _RemoveSkillExperience = null; _OverrideDefaults = null; } } public static class KeyboardExtensions { public static bool IsKeyDown(this KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } public static bool IsKeyHeld(this KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public static class RegisterAndCheckVersion { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] private static void Prefix(ZNetPeer peer, ref ZNet __instance) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown SkillControlPlugin.SkillControlLogger.LogDebug((object)"Registering version RPC handler"); peer.m_rpc.Register<ZPackage>("SkillControl_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_SkillControl_Version); SkillControlPlugin.SkillControlLogger.LogInfo((object)"Invoking version check"); ZPackage val = new ZPackage(); val.Write("1.0.5"); peer.m_rpc.Invoke("SkillControl_VersionCheck", new object[1] { val }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] public static class VerifyClient { private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance) { if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc)) { return true; } SkillControlPlugin.SkillControlLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting")); rpc.Invoke("Error", new object[1] { 3 }); return false; } private static void Postfix(ZNet __instance) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "SkillControlRequestAdminSync", new object[1] { (object)new ZPackage() }); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] public class ShowConnectionError { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] private static void Postfix(FejdStartup __instance) { if (__instance.m_connectionFailedPanel.activeSelf) { __instance.m_connectionFailedError.fontSizeMax = 25f; __instance.m_connectionFailedError.fontSizeMin = 15f; TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + SkillControlPlugin.ConnectionError; } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] public static class RemoveDisconnectedPeerFromVerified { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] private static void Prefix(ZNetPeer peer, ref ZNet __instance) { if (__instance.IsServer()) { SkillControlPlugin.SkillControlLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list")); RpcHandlers.ValidatedPeers.Remove(peer.m_rpc); } } } [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] public static class RpcHandlers { public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>(); public static void RPC_SkillControl_Version(ZRpc rpc, ZPackage pkg) { string text = pkg.ReadString(); SkillControlPlugin.SkillControlLogger.LogInfo((object)("Version check, local: 1.0.5, remote: " + text)); if (text != "1.0.5") { SkillControlPlugin.ConnectionError = "SkillControl Installed: 1.0.5\n Needed: " + text; if (ZNet.instance.IsServer()) { SkillControlPlugin.SkillControlLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting...")); rpc.Invoke("Error", new object[1] { 3 }); } } else if (!ZNet.instance.IsServer()) { SkillControlPlugin.SkillControlLogger.LogInfo((object)"Received same version from server!"); } else { SkillControlPlugin.SkillControlLogger.LogInfo((object)("Adding peer (" + rpc.m_socket.GetHostName() + ") to validated list")); ValidatedPeers.Add(rpc); } } public static string ComputeHashForMod() { using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(File.ReadAllBytes(Assembly.GetExecutingAssembly().Location)); StringBuilder stringBuilder = new StringBuilder(); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("X2")); } return stringBuilder.ToString(); } } } namespace SkillControl.UI { [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] public static class LoadUI { [HarmonyPatch(typeof(InventoryGui), "Awake")] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] private static class Load_Jobs_UI { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] private static void Postfix(InventoryGui __instance) { if (Object.op_Implicit((Object)(object)__instance)) { InitUI(__instance); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] private static class Override_ForceEmployment { private static void Postfix() { OverrideUI(); } } private static Text m_title = null; private static Image m_icon = null; private static Text m_description = null; private static Text m_availableSkills = null; private static Text m_lockedSkills = null; private static Text m_selectedTitle = null; private static Text m_selectButtonText = null; private static Button m_selectButton = null; private static Button m_closeButton = null; private static Transform m_partAvailable = null; private static Transform m_partLocked = null; private static Transform m_partTabs = null; private static Transform m_selected = null; private static GameObject m_selectedContainer = null; private static GameObject m_UI = null; private static GameObject m_skillElement = null; private static GameObject m_tabElement = null; private static RectTransform m_position = null; private static Sprite m_defaultBackground = null; private static ItemDrop m_defaultCurrency = null; private static JobData m_selectedJob = new JobData { Name = "$msg_select_job", Description = "" }; private static void GetGameAssets(InventoryGui instance, out ButtonSfx sfx, out Button button) { Transform val = instance.m_trophiesPanel.transform.Find("TrophiesFrame/Closebutton"); sfx = ((Component)val).GetComponent<ButtonSfx>(); button = ((Component)val).GetComponent<Button>(); } private static void AddGameAssets(List<Button> buttons, ButtonSfx sfx, Button button) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) foreach (Button button2 in buttons) { ((Component)button2).gameObject.AddComponent<ButtonSfx>().m_sfxPrefab = sfx.m_sfxPrefab; ((Selectable)button2).transition = (Transition)2; ((Selectable)button2).spriteState = ((Selectable)button).spriteState; } } private static void OverrideUI() { if (SkillControlPlugin._ForceJob.Value == SkillControlPlugin.Toggle.On && JobManager.m_jobs.Count == 0) { ShowUI(); } } public static void OnPositionChange(object sender, EventArgs e) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (sender is ConfigEntry<Vector2> val) { m_position.anchoredPosition = val.Value; } } private static void InitUI(InventoryGui instance) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) GetGameAssets(instance, out var sfx, out var button); m_UI = Object.Instantiate<GameObject>(SkillControlPlugin._AssetBundle.LoadAsset<GameObject>("UI"), ((Component)instance).transform); m_position = m_UI.GetComponent<RectTransform>(); m_position.anchoredPosition = SkillControlPlugin._UIPosition.Value; m_UI.SetActive(false); m_skillElement = SkillControlPlugin._AssetBundle.LoadAsset<GameObject>("Skill_Element"); m_tabElement = SkillControlPlugin._AssetBundle.LoadAsset<GameObject>("Tab_Element"); Object.DontDestroyOnLoad((Object)(object)m_UI); Object.DontDestroyOnLoad((Object)(object)m_skillElement); Object.DontDestroyOnLoad((Object)(object)m_tabElement); Text[] componentsInChildren = m_UI.GetComponentsInChildren<Text>(); Text[] componentsInChildren2 = m_skillElement.GetComponentsInChildren<Text>(); Text[] componentsInChildren3 = m_tabElement.GetComponentsInChildren<Text>(); Font font = GetFont("Norsebold"); AddFonts(componentsInChildren, font); AddFonts(componentsInChildren2, font); AddFonts(componentsInChildren3, font); List<Button> list = m_UI.GetComponentsInChildren<Button>().ToList(); list.Add(m_tabElement.GetComponent<Button>()); AddGameAssets(list, sfx, button); m_title = ((Component)Utils.FindChild(m_UI.transform, "$text_title", (IterativeSearchType)0)).GetComponent<Text>(); m_icon = ((Component)Utils.FindChild(m_UI.transform, "$image_icon", (IterativeSearchType)0)).GetComponent<Image>(); m_description = ((Component)Utils.FindChild(m_UI.transform, "$text_description", (IterativeSearchType)0)).GetComponent<Text>(); m_availableSkills = ((Component)Utils.FindChild(m_UI.transform, "$text_available", (IterativeSearchType)0)).GetComponent<Text>(); m_lockedSkills = ((Component)Utils.FindChild(m_UI.transform, "$text_locked", (IterativeSearchType)0)).GetComponent<Text>(); m_partAvailable = Utils.FindChild(m_UI.transform, "$part_available_content", (IterativeSearchType)0); m_partLocked = Utils.FindChild(m_UI.transform, "$part_locked_content", (IterativeSearchType)0); m_partTabs = Utils.FindChild(m_UI.transform, "$part_tabs_content", (IterativeSearchType)0); Transform val = Utils.FindChild(m_UI.transform, "$button_accept", (IterativeSearchType)0); m_selectButtonText = ((Component)val.Find("$text_button")).GetComponent<Text>(); m_selectButton = ((Component)val).GetComponent<Button>(); m_closeButton = ((Component)Utils.FindChild(m_UI.transform, "$button_close", (IterativeSearchType)0)).GetComponent<Button>(); m_selectedTitle = ((Component)Utils.FindChild(m_UI.transform, "$text_selected_title", (IterativeSearchType)0)).GetComponent<Text>(); m_selected = Utils.FindChild(m_UI.transform, "$part_selected_content", (IterativeSearchType)0); m_selectedContainer = ((Component)m_UI.transform.Find("Select")).gameObject; SetStaticEvents(); SkillControlPlugin.SkillControlLogger.LogDebug((object)"Initialized skill control UI"); } private static void SetStaticEvents() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown ((UnityEvent)m_closeButton.onClick).AddListener(new UnityAction(HideUI)); ((UnityEvent)m_selectButton.onClick).AddListener(new UnityAction(SelectJob)); m_availableSkills.text = Localization.instance.Localize("$text_benefit"); m_lockedSkills.text = Localization.instance.Localize("$text_detriment"); m_selectedTitle.text = Localization.instance.Localize("$text_my_jobs"); if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { GameObject prefab = ZNetScene.instance.GetPrefab("Coins"); ItemDrop defaultCurrency = default(ItemDrop); if (!prefab.TryGetComponent<ItemDrop>(ref defaultCurrency)) { return; } m_defaultCurrency = defaultCurrency; } Sprite val = ((IEnumerable<Sprite>)Resources.FindObjectsOfTypeAll<Sprite>()).FirstOrDefault((Func<Sprite, bool>)([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (Sprite x) => ((Object)x).name == "biome_blackforest")); if (!((Object)(object)val == (Object)null)) { m_defaultBackground = val; m_icon.sprite = m_defaultBackground; } } private static void SelectJob() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (JobManager.m_jobs.Contains(m_selectedJob)) { if (!CheckCost()) { return; } if (SkillControlPlugin._RemoveSkillExperience.Value == SkillControlPlugin.Toggle.On) { foreach (SkillData skillModifier in m_selectedJob.SkillModifiers) { string skillName = skillModifier.SkillName; if (!(skillModifier.Modifier > 0f) && JobManager.GetSkillType(skillName, out var output)) { Player.m_localPlayer.m_skills.ResetSkill(output); SkillControlPlugin.SkillControlLogger.LogDebug((object)("Reset " + skillName + " to zero")); } } } JobManager.m_jobs.Remove(m_selectedJob); } else { if (m_selectedJob.Name == "$msg_select_job") { ShowUI(); return; } if (JobManager.m_jobs.Count >= SkillControlPlugin._JobLimit.Value) { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_job_limit", 0, (Sprite)null); return; } JobManager.m_jobs.Add(m_selectedJob); } ShowUI(); } private static void AddFonts(Text[] array, [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] Font font) { foreach (Text val in array) { val.font = font; } } [return: <c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] private static Font GetFont(string name) { Font[] source = Resources.FindObjectsOfTypeAll<Font>(); return ((IEnumerable<Font>)source).FirstOrDefault((Func<Font, bool>)([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (Font x) => ((Object)x).name == name)); } public static bool IsUIActive() { return Object.op_Implicit((Object)(object)m_UI) && m_UI.activeInHierarchy; } private static void ToggleUI(bool value) { if (Object.op_Implicit((Object)(object)m_UI)) { m_UI.SetActive(value); } } public static void UpdateUI() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)m_UI)) { return; } if (Input.GetKeyDown((KeyCode)27)) { HideUI(); } if (Input.GetKeyDown(SkillControlPlugin._UIKey.Value)) { if (IsUIActive()) { HideUI(); } else { ShowUI(); } } } private static void DestroyUIElements() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown foreach (Transform partTab in m_partTabs) { Transform val = partTab; Object.Destroy((Object)(object)((Component)val).gameObject); } foreach (Transform item in m_partAvailable) { Transform val2 = item; Object.Destroy((Object)(object)((Component)val2).gameObject); } foreach (Transform item2 in m_partLocked) { Transform val3 = item2; Object.Destroy((Object)(object)((Component)val3).gameObject); } foreach (Transform item3 in m_selected) { Transform val4 = item3; Object.Destroy((Object)(object)((Component)val4).gameObject); } } private static void CreateTabs() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown Button val2 = default(Button); foreach (KeyValuePair<string, JobData> registeredJob in JobManager.RegisteredJobs) { JobData job = registeredJob.Value; GameObject val = Object.Instantiate<GameObject>(m_tabElement, m_partTabs); val.GetComponentInChildren<Text>().text = Localization.instance.Localize(job.Name); if (val.TryGetComponent<Button>(ref val2)) { ((UnityEvent)val2.onClick).AddListener((UnityAction)delegate { m_selectedJob = job; ShowUI(); }); } } } private static void SetStaticElements() { if (Object.op_Implicit((Object)(object)m_title) && Object.op_Implicit((Object)(object)m_icon) && Object.op_Implicit((Object)(object)m_description)) { m_title.text = Localization.instance.Localize(m_selectedJob.Name); Sprite val = SpriteManager.TryGetIcon(m_selectedJob.Image.Replace(".png", string.Empty)); m_icon.sprite = (Object.op_Implicit((Object)(object)val) ? val : m_defaultBackground); string text = ((SkillControlPlugin._RemoveSkillExperience.Value == SkillControlPlugin.Toggle.On) ? "<color=red>$text_skill_loss</color>" : ""); m_description.text = Localization.instance.Localize(m_selectedJob.Description + "\n" + text); } } private static void CreateContentElements() { //IL_0096: Unknown result type (might be due to invalid IL or missing references) Image val2 = default(Image); Text val3 = default(Text); Text val4 = default(Text); foreach (SkillData skillModifier in m_selectedJob.SkillModifiers) { if (JobManager.GetSkillType(skillModifier.SkillName, out var output)) { GameObject val = Object.Instantiate<GameObject>(m_skillElement, (!Utility.IsNullOrWhiteSpace(skillModifier.type)) ? ((skillModifier.type == "minus") ? m_partLocked : m_partAvailable) : ((skillModifier.Modifier < 1f) ? m_partLocked : m_partAvailable)); SkillDef skillDef = Player.m_localPlayer.m_skills.GetSkillDef(output); if (skillDef != null && ((Component)Utils.FindChild(val.transform, "$image_icon", (IterativeSearchType)0)).TryGetComponent<Image>(ref val2)) { val2.sprite = skillDef.m_icon; } if (((Component)Utils.FindChild(val.transform, "$text_skill_name", (IterativeSearchType)0)).TryGetComponent<Text>(ref val3)) { val3.text = Localization.instance.Localize(Utility.IsNullOrWhiteSpace(skillModifier.DisplayName) ? skillModifier.SkillName : skillModifier.DisplayName); } if (((Component)Utils.FindChild(val.transform, "$text_skill_description", (IterativeSearchType)0)).TryGetComponent<Text>(ref val4)) { val4.text = GetTooltip(skillModifier); } } } } private static void ShowUI() { if (Object.op_Implicit((Object)(object)m_selectButtonText)) { if (Utility.IsNullOrWhiteSpace(m_selectedJob.Name) && JobManager.RegisteredJobs.Count > 0) { m_selectedJob = JobManager.RegisteredJobs.Values.First(); } m_selectButtonText.text = Localization.instance.Localize(JobManager.m_jobs.Contains(m_selectedJob) ? "$text_remove" : "$text_select"); DestroyUIElements(); UpdateSelectedJobs(); CreateTabs(); SetStaticElements(); CreateContentElements(); ToggleUI(value: true); } } public static void ReloadUI() { m_selectedJob = JobManager.RegisteredJobs.Values.FirstOrDefault([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (JobData x) => x.Name == m_selectedJob.Name) ?? m_selectedJob; ShowUI(); } private static void UpdateSelectedJobs() { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)m_selectedContainer)) { return; } if (JobManager.m_jobs.Count > 0) { m_selectedContainer.SetActive(true); { Text val2 = default(Text); Button val3 = default(Button); foreach (JobData job in JobManager.m_jobs) { GameObject val = Object.Instantiate<GameObject>(m_tabElement, m_selected); if (((Component)val.transform.GetChild(0)).TryGetComponent<Text>(ref val2)) { val2.text = Localization.instance.Localize("<color=yellow>" + job.Name + "</color>" + $"\n$text_cost_to $text_remove <color=orange>{SkillControlPlugin._CostToRemove.Value}</color> {GetCurrency().m_itemData.m_shared.m_name}"); } if (!val.TryGetComponent<Button>(ref val3)) { continue; } ((UnityEvent)val3.onClick).AddListener((UnityAction)delegate { //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (CheckCost()) { JobManager.m_jobs.Remove(job); if (SkillControlPlugin._RemoveSkillExperience.Value == SkillControlPlugin.Toggle.On) { foreach (SkillData skillModifier in job.SkillModifiers) { string skillName = skillModifier.SkillName; if (!(skillModifier.Modifier > 0f) && JobManager.GetSkillType(skillName, out var output)) { Player.m_localPlayer.m_skills.ResetSkill(output); SkillControlPlugin.SkillControlLogger.LogDebug((object)("Reset " + skillName + " to zero")); } } } ShowUI(); } }); } return; } } m_selectedContainer.SetActive(false); } private static ItemDrop GetCurrency() { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(SkillControlPlugin._Currency.Value); if ((Object)(object)itemPrefab == (Object)null) { return m_defaultCurrency; } ItemDrop val = default(ItemDrop); return itemPrefab.TryGetComponent<ItemDrop>(ref val) ? val : m_defaultCurrency; } private static bool CheckCost() { string name = GetCurrency().m_itemData.m_shared.m_name; int num = ((Humanoid)Player.m_localPlayer).GetInventory().CountItems(name, -1, true); if (num >= SkillControlPlugin._CostToRemove.Value) { ((Humanoid)Player.m_localPlayer).GetInventory().RemoveItem(name, SkillControlPlugin._CostToRemove.Value, -1, true); return true; } ((Character)Player.m_localPlayer).Message((MessageType)2, GetCurrency().m_itemData.m_shared.m_name + " $msg_cost_required", 0, (Sprite)null); return false; } private static string GetTooltip(SkillData data) { return Localization.instance.Localize($"$text_modifier: <color=orange>{data.Modifier * 100f}</color>%"); } private static void HideUI() { if (SkillControlPlugin._ForceJob.Value == SkillControlPlugin.Toggle.On && JobManager.m_jobs.Count == 0) { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_job_required", 0, (Sprite)null); } ToggleUI(value: false); } } public static class Patches { [HarmonyPatch(typeof(PlayerController), "FixedUpdate")] private static class PlayerController_UI_Patch { private static bool Prefix() { return !LoadUI.IsUIActive(); } } [HarmonyPatch(typeof(StoreGui), "IsVisible")] private static class IsUI_Visible_Patch1 { private static void Postfix(ref bool __result) { __result |= LoadUI.IsUIActive(); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] private static class IsUI_Visible_Patch2 { private static bool Prefix() { return !LoadUI.IsUIActive(); } } } } namespace SkillControl.Professions { [Serializable] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] public class JobData { public string Name = ""; public string Description = ""; public string Image = ""; public List<SkillData> SkillModifiers = new List<SkillData>(); } [Serializable] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] public class SkillData { public string SkillName = ""; public string DisplayName = ""; public float Modifier; public string type = ""; } [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] public static class JobManager { public static readonly CustomSyncedValue<string> ServerJobData = new CustomSyncedValue<string>(SkillControlPlugin.ConfigSync, "ServerSkillControlData", ""); private static readonly string m_dataKey = "SkillControlData"; public static Dictionary<string, JobData> RegisteredJobs = new Dictionary<string, JobData>(); public static List<JobData> m_jobs = new List<JobData>(); public static void SaveJobsToPlayer() { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { List<string> graph = m_jobs.Select([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (JobData job) => job.Name).ToList(); ISerializer serializer = new SerializerBuilder().Build(); string value = serializer.Serialize(graph); Player.m_localPlayer.m_customData[m_dataKey] = value; SkillControlPlugin.SkillControlLogger.LogDebug((object)"Saved data to player file"); } } public static void RetrieveJobsFromPlayer() { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Player.m_localPlayer.m_customData.TryGetValue(m_dataKey, out var value)) { return; } m_jobs.Clear(); IDeserializer deserializer = new DeserializerBuilder().Build(); List<string> list = deserializer.Deserialize<List<string>>(value); foreach (string item in list) { if (RegisteredJobs.TryGetValue(Regex.Replace(item, "<.*?>", string.Empty), out var value2)) { m_jobs.Add(value2); } } SkillControlPlugin.SkillControlLogger.LogDebug((object)"Retrieved data from player file"); } public static Dictionary<SkillType, float> GetCollectedModifiers() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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) Dictionary<SkillType, float> dictionary = new Dictionary<SkillType, float>(); foreach (SkillData item in m_jobs.SelectMany([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (JobData job) => job.SkillModifiers)) { if (GetSkillType(item.SkillName, out var output)) { if (dictionary.TryGetValue(output, out var value)) { dictionary[output] = Mathf.Clamp(value + item.Modifier, 0f, 5f); } else { dictionary[output] = item.Modifier; } } } return dictionary; } public static void InitJobs() { string[] files = Directory.GetFiles(PluginPaths.folderPath, "*.yml"); if (files.Length == 0) { CreateExampleFile(); } else { IDeserializer deserializer = new DeserializerBuilder().Build(); string[] array = files; foreach (string path in array) { string input = File.ReadAllText(path); JobData jobData = deserializer.Deserialize<JobData>(input); RegisteredJobs[Regex.Replace(jobData.Name, "<.*?>", string.Empty)] = jobData; } } SkillControlPlugin.SkillControlLogger.LogDebug((object)"Initialized skill controller"); } public static void UpdateServerData() { ISerializer serializer = new SerializerBuilder().Build(); string value = serializer.Serialize(RegisteredJobs); ServerJobData.Value = value; SkillControlPlugin.SkillControlLogger.LogDebug((object)"Updated server data"); } public static void OnServerDataChange() { if (!Utility.IsNullOrWhiteSpace(ServerJobData.Value)) { IDeserializer deserializer = new DeserializerBuilder().Build(); Dictionary<string, JobData> registeredJobs = deserializer.Deserialize<Dictionary<string, JobData>>(ServerJobData.Value); RegisteredJobs = registeredJobs; SkillControlPlugin.SkillControlLogger.LogDebug((object)"Client: received server data"); UpdateCurrentJobs(); if (LoadUI.IsUIActive()) { LoadUI.ReloadUI(); } } } private static void UpdateCurrentJobs() { m_jobs = m_jobs.Select([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (JobData job) => RegisteredJobs.Values.FirstOrDefault([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (JobData x) => Regex.Replace(x.Name, "<.*?>", string.Empty) == Regex.Replace(job.Name, "<.*?>", string.Empty))).ToList(); } private static void CreateExampleFile() { List<JobData> list = new List<JobData> { new JobData { Name = "Peasant", Description = "For the one that cares for the well-being of the populace", SkillModifiers = new List<SkillData> { new SkillData { SkillName = "Farming", Modifier = 1.2f }, new SkillData { SkillName = "Foraging", Modifier = 1.2f }, new SkillData { SkillName = "Ranching", Modifier = 1.2f }, new SkillData { SkillName = "Blacksmithing", Modifier = 0f }, new SkillData { SkillName = "Sailing", Modifier = 0.5f }, new SkillData { SkillName = "Knives", Modifier = 1.3f } } }, new JobData { Name = "Blacksmith", Description = "For whom has a great deal of attention to the details of survival", SkillModifiers = new List<SkillData> { new SkillData { SkillName = "Blacksmithing", Modifier = 1.2f }, new SkillData { SkillName = "Farming", Modifier = 0.5f }, new SkillData { SkillName = "Foraging", Modifier = 0.5f }, new SkillData { SkillName = "Sailing", Modifier = 0.5f }, new SkillData { SkillName = "Swords", Modifier = 1.1f }, new SkillData { SkillName = "Axes", Modifier = 1.1f }, new SkillData { SkillName = "Clubs", Modifier = 1.1f } } }, new JobData { Name = "Sailor", Description = "The heavy toll of sea-fairing is one that comes with great honor", SkillModifiers = new List<SkillData> { new SkillData { SkillName = "Blacksmithing", Modifier = 0f }, new SkillData { SkillName = "Farming", Modifier = 0f }, new SkillData { SkillName = "Foraging", Modifier = 1.1f }, new SkillData { SkillName = "Sailing", Modifier = 1.5f }, new SkillData { SkillName = "Spears", Modifier = 1.3f } } } }; ISerializer serializer = new SerializerBuilder().Build(); foreach (JobData item in list) { string folderPath = PluginPaths.folderPath; char directorySeparatorChar = Path.DirectorySeparatorChar; string path = folderPath + directorySeparatorChar + item.Name + ".yml"; string contents = serializer.Serialize(item); File.WriteAllText(path, contents); RegisteredJobs[Regex.Replace(item.Name, "<.*?>", string.Empty)] = item; } } public static bool GetSkillType(string input, out SkillType output) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected I4, but got Unknown if (Enum.TryParse<SkillType>(input, out SkillType result)) { output = (SkillType)(int)result; return true; } int stableHashCode = StringExtensionMethods.GetStableHashCode(input); output = (SkillType)Math.Abs(stableHashCode); return !Object.op_Implicit((Object)(object)Player.m_localPlayer) || Player.m_localPlayer.m_skills.GetSkillDef(output) != null; } } public static class Patches { [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class RaiseSkill_Patch { private static void Prefix(SkillType skillType, ref float factor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((int)skillType != 0 && JobManager.GetCollectedModifiers().TryGetValue(skillType, out var value)) { Skill skill = Player.m_localPlayer.m_skills.GetSkill(skillType); if (SkillControlPlugin._OverrideDefaults.Value == SkillControlPlugin.Toggle.On) { originalIncreaseStep = skill.m_info.m_increseStep; skill.m_info.m_increseStep = value; m_modified = true; } else { factor *= value; } } } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class RaiseSkill_Patch2 { private static void Postfix(SkillType skillType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if ((int)skillType != 0) { Skill skill = Player.m_localPlayer.m_skills.GetSkill(skillType); if (JobManager.GetCollectedModifiers().TryGetValue(skillType, out var _) && SkillControlPlugin._OverrideDefaults.Value != 0 && m_modified && !(originalIncreaseStep <= 0f)) { skill.m_info.m_increseStep = originalIncreaseStep; m_modified = false; } } } } [HarmonyPatch(typeof(Player), "Save")] private static class SaveJobData_Patch { private static void Postfix() { JobManager.SaveJobsToPlayer(); } } [HarmonyPatch(typeof(PlayerProfile), "LoadPlayerData")] private static class LoadJobData_Patch { private static void Postfix() { JobManager.RetrieveJobsFromPlayer(); } } [HarmonyPatch(typeof(ZNet), "Start")] private static class Initialize_ServerSynced_JobData { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] private static void Postfix(ZNet __instance) { if (Object.op_Implicit((Object)(object)__instance)) { if (!__instance.IsServer()) { JobManager.ServerJobData.ValueChanged += JobManager.OnServerDataChange; } else { JobManager.UpdateServerData(); } } } } private static float originalIncreaseStep; private static bool m_modified; private static float CalculateTotalExperience(float currentLevel) { float num = 0f; for (float num2 = 1f; num2 <= currentLevel; num2 += 1f) { float num3 = Mathf.Pow(Mathf.Floor(num2), 1.5f) * 0.5f + 0.5f; num += num3; } return num; } } [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] public static class PluginPaths { public static readonly string folderPath; public static readonly string iconPath; public static void CreateDirectories() { if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } if (!Directory.Exists(iconPath)) { Directory.CreateDirectory(iconPath); } } static PluginPaths() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; folderPath = configPath + directorySeparatorChar + "SkillControl"; string text = folderPath; directorySeparatorChar = Path.DirectorySeparatorChar; iconPath = text + directorySeparatorChar + "Icons"; } } } namespace SkillControl.Managers { [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] public static class FileWaterManager { public static void InitFileWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(PluginPaths.folderPath) { Filter = "*.yml", EnableRaisingEvents = true, IncludeSubdirectories = true, SynchronizingObject = ThreadingHelper.SynchronizingObject, NotifyFilter = NotifyFilters.LastWrite }; fileSystemWatcher.Created += OnFileChange; fileSystemWatcher.Changed += OnFileChange; fileSystemWatcher.Deleted += OnFileDelete; FileSystemWatcher fileSystemWatcher2 = new FileSystemWatcher(PluginPaths.iconPath) { Filter = "*.png", EnableRaisingEvents = true, IncludeSubdirectories = true, SynchronizingObject = ThreadingHelper.SynchronizingObject, NotifyFilter = NotifyFilters.LastWrite }; fileSystemWatcher2.Created += OnImageChange; fileSystemWatcher2.Changed += OnImageChange; fileSystemWatcher2.Deleted += OnImageDelete; } private static void OnImageChange(object sender, FileSystemEventArgs e) { SpriteManager.RegisterSprite(e.FullPath); } private static void OnImageDelete(object sender, FileSystemEventArgs e) { string fileName = Path.GetFileName(e.Name); fileName = fileName.Replace(".png", string.Empty); SpriteManager.RegisteredSprites.Remove(fileName); } private static void OnFileChange(object sender, FileSystemEventArgs e) { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer()) { IDeserializer deserializer = new DeserializerBuilder().Build(); string input = File.ReadAllText(e.FullPath); JobData jobData = deserializer.Deserialize<JobData>(input); JobManager.RegisteredJobs[Regex.Replace(jobData.Name, "<.*?>", string.Empty)] = jobData; JobManager.UpdateServerData(); } } private static void OnFileDelete(object sender, FileSystemEventArgs e) { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer()) { JobManager.RegisteredJobs.Clear(); string[] files = Directory.GetFiles(PluginPaths.folderPath, "*.yml"); IDeserializer deserializer = new DeserializerBuilder().Build(); string[] array = files; foreach (string path in array) { string input = File.ReadAllText(path); JobData jobData = deserializer.Deserialize<JobData>(input); JobManager.RegisteredJobs[jobData.Name] = jobData; } JobManager.UpdateServerData(); } } } [PublicAPI] [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] public class Localizer { private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors; private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts; private static readonly ConditionalWeakTable<Localization, string> localizationLanguage; private static readonly List<WeakReference<Localization>> localizationObjects; [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] private static BaseUnityPlugin _plugin; private static readonly List<string> fileExtensions; private static BaseUnityPlugin plugin { get { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown if (_plugin == null) { IEnumerable<TypeInfo> source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } private static void UpdatePlaceholderText(Localization localization, string key) { localizationLanguage.TryGetValue(localization, out var value); string text = loadedTexts[value][key]; if (PlaceholderProcessors.TryGetValue(key, out var value2)) { text = value2.Aggregate(text, [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } localization.AddWord(key, text); } public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null) { if (convertConfigValue == null) { convertConfigValue = [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] [return: <c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(1)] (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (object _, EventArgs _) => { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value); UpdatePlaceholderText(Localization.instance, key); } } public static void AddText(string key, string text) { List<WeakReference<Localization>> list = new List<WeakReference<Localization>>(); foreach (WeakReference<Localization> localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference<Localization> item in list) { localizationObjects.Remove(item); } } public static void Load() { LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage()); } private static void LoadLocalization(Localization __instance, string language) { if (!localizationLanguage.Remove(__instance)) { localizationObjects.Add(new WeakReference<Localization>(__instance)); } localizationLanguage.Add(__instance, language); Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories) where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0 select f) { string text = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' })[1]; if (dictionary.ContainsKey(text)) { Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped.")); } else { dictionary[text] = item; } } byte[] array = LoadTranslationFromAssembly("English"); if (array == null) { throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected an embedded resource translations/English.json or translations/English.yml."); } Dictionary<string, string> dictionary2 = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(Encoding.UTF8.GetString(array)); if (dictionary2 == null) { throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text2 = null; if (language != "English") { if (dictionary.ContainsKey(language)) { text2 = File.ReadAllText(dictionary[language]); } else { byte[] array2 = LoadTranslationFromAssembly(language); if (array2 != null) { text2 = Encoding.UTF8.GetString(array2); } } } if (text2 == null && dictionary.ContainsKey("English")) { text2 = File.ReadAllText(dictionary["English"]); } if (text2 != null) { foreach (KeyValuePair<string, string> item2 in new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>()) { dictionary2[item2.Key] = item2.Value; } } loadedTexts[language] = dictionary2; foreach (KeyValuePair<string, string> item3 in dictionary2) { UpdatePlaceholderText(__instance, item3.Key); } } static Localizer() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>(); loadedTexts = new Dictionary<string, Dictionary<string, string>>(); localizationLanguage = new ConditionalWeakTable<Localization, string>(); localizationObjects = new List<WeakReference<Localization>>(); fileExtensions = new List<string> { ".json", ".yml" }; Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } [return: <c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] private static byte[] LoadTranslationFromAssembly(string language) { foreach (string fileExtension in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension); if (array != null) { return array; } } return null; } [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } [<bc980902-82d7-4f37-bbab-e96d8dc776f6>NullableContext(1)] [<c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(0)] public static class SpriteManager { public static readonly Dictionary<string, Sprite> RegisteredSprites = new Dictionary<string, Sprite>(); [return: <c06f07ea-e12a-4405-ac6d-a489aadd8da6>Nullable(2)] public static Sprite TryGetIcon(string name) { Sprite value; return RegisteredSprites.TryGetValue(name, out value) ? value : null; } public static void GetIcons() { string[] files = Directory.GetFiles(PluginPaths.iconPath, "*.png"); string[] array = files; foreach (string filePath in array) { RegisterSprite(filePath); } } public static void RegisterSprite(string filePath) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) byte[] array = File.ReadAllBytes(filePath); Texture2D val = new Texture2D(2, 2); Sprite val2 = (ImageConversion.LoadImage(val, array) ? Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero) : null); if (!((Object)(object)val2 == (Object)null)) { string text2 = (((Object)val2).name = filePath.Replace(".png", string.Empty).Replace(PluginPaths.iconPath, string.Empty).Replace("\\", string.Empty)); RegisteredSprites[text2] = val2; SkillControlPlugin.SkillControlLogger.LogDebug((object)("Successfully registered sprite: " + text2)); } } } } namespace Microsoft.CodeAnalysis { [<e8a4bb93-2968-43d3-970a-24369ae8be5b>Embedded] [CompilerGenerated] internal sealed class <e8a4bb93-2968-43d3-970a-24369ae8be5b>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [<e8a4bb93-2968-43d3-970a-24369ae8be5b>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [CompilerGenerated] internal sealed class <8b10d8e2-857c-474f-99b5-8484e8376530>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <8b10d8e2-857c-474f-99b5-8484e8376530>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <8b10d8e2-857c-474f-99b5-8484e8376530>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [<e8a4bb93-2968-43d3-970a-24369ae8be5b>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class <28448d17-30d8-4081-a1b6-b9595297003d>NullableContextAttribute : Attribute { public readonly byte Flag; public <28448d17-30d8-4081-a1b6-b9595297003d>NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [<e8a4bb93-2968-43d3-970a-24369ae8be5b>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 ServerSync { [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [PublicAPI] [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] internal abstract class OwnConfigEntryBase { [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public object LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] internal class SyncedConfigEntry<[<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] 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; } } } [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(2)] internal abstract class CustomSyncedValueBase { public object LocalBaseValue; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(1)] public readonly string Identifier; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(1)] public readonly Type Type; private object boxedValue; protected bool localIsOwner; public readonly int Priority; public object BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(); } } public event Action ValueChanged; [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [PublicAPI] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] internal sealed class CustomSyncedValue<[<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] T> : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.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 class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] internal class ConfigSync { [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public static ZRpc currentRpc; [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [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()); } [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] 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)); } } [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] 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 ((object)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")] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] private static class RegisterClientRPCPatch { [HarmonyPostfix] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] 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); } } } [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] private class ParsedConfigs { [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 1, 1, 2 })] public readonly Dictionary<OwnConfigEntryBase, object> configValues = new Dictionary<OwnConfigEntryBase, object>(); [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 1, 1, 2 })] public readonly Dictionary<CustomSyncedValueBase, object> customValues = new Dictionary<CustomSyncedValueBase, object>(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] private class BufferingSocket : ISocket { public volatile bool finished = false; public volatile int versionMatchQueued = -1; public readonly List<ZPackage> Package = new List<ZPackage>(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix([<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 2, 1, 1 })] ref Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if (__instance.IsServer()) { BufferingSocket value = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, value); object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend > 0) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, value); } if (__state == null) { __state = new Dictionary<Assembly, BufferingSocket>(); } __state[Assembly.GetExecutingAssembly()] = value; } } [HarmonyPostfix] private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc) { ZNetPeer peer; if (__instance.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List<PackageEntry> entries = new List<PackageEntry>(); if (configSync.CurrentVersion != null) { entries.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); entries.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2] { adminList, rpc.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false); yield return ((MonoBehaviour)__instance).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package)); } SendBufferedData(); } } } [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] private class PackageEntry { public string section = null; public string key = null; public Type type = null; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public object value; } [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] private static class PreventConfigRereadChangingValues { [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(1)] [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] private class InvalidDeserializationTypeException : Exception { public string expected = null; public string received = null; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public string DisplayName; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public string CurrentVersion; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public string MinimumRequiredVersion; public bool ModRequired = false; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet<ConfigSync> configSyncs; private readonly HashSet<OwnConfigEntryBase> allConfigs = new HashSet<OwnConfigEntryBase>(); private HashSet<CustomSyncedValueBase> allCustomValues = new HashSet<CustomSyncedValueBase>(); private static bool isServer; private static bool lockExempt; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] private OwnConfigEntryBase lockedConfig = null; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary<string, SortedDictionary<int, byte[]>> configValueCache = new Dictionary<string, SortedDictionary<int, byte[]>>(); [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 1, 0, 1 })] private readonly List<KeyValuePair<long, string>> cacheExpirations = new List<KeyValuePair<long, string>>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0052; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag.GetValueOrDefault(); } if (!num) { goto IL_0052; } int result = ((!lockExempt) ? 1 : 0); goto IL_0053; IL_0053: return (byte)result != 0; IL_0052: result = 0; goto IL_0053; } set { forceConfigLocking = value; } } public bool IsAdmin => lockExempt || isSourceOfTruth; public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } = false; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] [method: <28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(2)] [field: <8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] public event Action<bool> SourceOfTruthChanged; [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] [method: <28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(2)] [field: <8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] private event Action lockedConfigChanged; 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); } public SyncedConfigEntry<T> AddConfigEntry<[<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] T>(ConfigEntry<T> configEntry) { OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry); SyncedConfigEntry<T> syncedEntry = ownConfigEntryBase as SyncedConfigEntry<T>; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry<T>(configEntry); AccessTools.DeclaredField(typeof(ConfigDescription), "<Tags>k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry).Description.Tags ?? Array.Empty<object>()).Concat(new SyncedConfigEntry<T>[1] { syncedEntry }).ToArray()); configEntry.SettingChanged += [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (object _, EventArgs _) => { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry<T> AddLockingConfigEntry<[<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(0)] T>(ConfigEntry<T> lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry<T>(lockingConfig); lockingConfig.SettingChanged += [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (object _, EventArgs _) => { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry<T>)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { if (allCustomValues.Select([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue); allCustomValues = new HashSet<CustomSyncedValueBase>(allCustomValues.OrderByDescending([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (CustomSyncedValueBase v) => v.Priority)); customValue.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue); } }; } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(([<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 0, 1 })] KeyValuePair<long, string> kv) => { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2u) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out var value)) { value = new SortedDictionary<int, byte[]>(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair<long, string>(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4u) != 0) { byte[] buffer = package.ReadByteArray(); MemoryStream stream = new MemoryStream(buffer); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair<OwnConfigEntryBase, object> configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; } foreach (KeyValuePair<CustomSyncedValueBase, object> customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary<string, OwnConfigEntryBase> dictionary = allConfigs.Where([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (OwnConfigEntryBase c) => c); Dictionary<string, CustomSyncedValueBase> dictionary2 = allCustomValues.ToDictionary([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (CustomSyncedValueBase c) => c.Identifier, [<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { ConfigSync configSync = configSyncs.FirstOrDefault([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (ConfigSync cs) => cs.allConfigs.Contains(config)); if (configSync == null) { return true; } return configSync.IsSourceOfTruth || !config.SynchronizedConfig || config.LocalBaseValue == null || (!configSync.IsLocked && (config != configSync.lockedConfig || lockExempt)); } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute<ConfigurationManagerAttributes>(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator<bool> distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer.m_socket.IsConnected()) { ZPackage fragmentedPackage = new ZPackage(); fragmentedPackage.Write((byte)2); fragmentedPackage.Write(packageIdentifier); fragmentedPackage.Write(fragment); fragmentedPackage.Write(fragments); fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(fragmentedPackage); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, text, new object[1] { pkg }); } } IEnumerable<bool> waitForQueue() { float timeout = Time.time + 30f; while (peer.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer.m_uid} after 30 seconds config sending timeout"); peer.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 }); ZNet.instance.Disconnect(peer); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return Enumerable.Empty<object>().GetEnumerator(); } List<ZNetPeer> list = (List<ZNetPeer>)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance); if (target != ZRoutedRpc.Everybody) { list = list.Where([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List<ZNetPeer> peers, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { yield break; } byte[] rawData = package.GetArray(); if (rawData != null && rawData.LongLength > 10000) { ZPackage compressedPackage = new ZPackage(); compressedPackage.Write((byte)4); MemoryStream output = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal)) { deflateStream.Write(rawData, 0, rawData.Length); } compressedPackage.Write(output.ToArray()); package = compressedPackage; } List<IEnumerator<bool>> writers = (from peer in peers where peer.IsReady() select peer into p select distributeConfigToPeers(p, package)).ToList(); writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator<bool> writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } [return: <8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] private static OwnConfigEntryBase configData(ConfigEntryBase config) { return config.Description.Tags?.OfType<OwnConfigEntryBase>().SingleOrDefault(); } [return: <8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 2, 1 })] public static SyncedConfigEntry<T> ConfigData<[<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] T>(ConfigEntry<T> config) { return ((ConfigEntryBase)config).Description.Tags?.OfType<SyncedConfigEntry<T>>().SingleOrDefault(); } private static T configAttribute<[<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] T>(ConfigEntryBase config) { return config.Description.Tags.OfType<T>().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { return type.IsEnum ? Enum.GetUnderlyingType(type) : type; } private static ZPackage ConfigsToPackage([<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 2, 1 })] IEnumerable<ConfigEntryBase> configs = null, [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 2, 1 })] IEnumerable<CustomSyncedValueBase> customValues = null, [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(new byte[] { 2, 1 })] IEnumerable<PackageEntry> packageEntries = null, bool partial = true) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown List<ConfigEntryBase> list = configs?.Where([<28448d17-30d8-4081-a1b6-b9595297003d>NullableContext(0)] (ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List<ConfigEntryBase>(); List<CustomSyncedValueBase> list2 = customValues?.ToList() ?? new List<CustomSyncedValueBase>(); ZPackage val = new ZPackage(); val.Write((byte)(partial ? 1 : 0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty<PackageEntry>()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, [<8b10d8e2-857c-474f-99b5-8484e8376530>Nullable(2)] object value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null &&