Decompiled source of Glitnir Timekeeper v3.0.0
Timekeeper.dll
Decompiled a week 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.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; 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 BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Managers; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using ServerSync; using TMPro; using Timekeeper.Managers; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.UI; [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: ComVisible(false)] [assembly: AssemblyTrademark("")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyProduct("Timekeeper")] [assembly: AssemblyCompany("RustyMods")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("Timekeeper")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyConfiguration("")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<8a3d522f-b09c-4347-84a6-0e5db33282f8>Embedded] internal sealed class <8a3d522f-b09c-4347-84a6-0e5db33282f8>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [<8a3d522f-b09c-4347-84a6-0e5db33282f8>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class <67c466d5-4fad-4396-9408-d64f6873a1f4>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <67c466d5-4fad-4396-9408-d64f6873a1f4>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <67c466d5-4fad-4396-9408-d64f6873a1f4>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [CompilerGenerated] [<8a3d522f-b09c-4347-84a6-0e5db33282f8>Embedded] internal sealed class <82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContextAttribute : Attribute { public readonly byte Flag; public <82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace LocalizationManager { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [PublicAPI] 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; [<67c466d5-4fad-4396-9408-d64f6873a1f4>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([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>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, [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>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, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null) { if (convertConfigValue == null) { convertConfigValue = [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] [return: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(1)] (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>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) { //IL_01a6: Expected O, but got Unknown //IL_02a6: Expected O, but got Unknown 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."); } Dictionary<string, string> dictionary2; try { dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, string>>(Encoding.UTF8.GetString(array)); } catch (JsonException val) { JsonException val2 = val; throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Invalid JSON in English localization file. " + ((Exception)(object)val2).Message); } 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) { Dictionary<string, string> dictionary3; try { dictionary3 = JsonConvert.DeserializeObject<Dictionary<string, string>>(text2); } catch (JsonException val3) { JsonException val4 = val3; throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: Invalid JSON in " + language + " localization file. " + ((Exception)(object)val4).Message); } foreach (KeyValuePair<string, string> item2 in dictionary3 ?? 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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" }; 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: <67c466d5-4fad-4396-9408-d64f6873a1f4>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; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } } namespace Timekeeper { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [BepInPlugin("RustyMods.Timekeeper", "Timekeeper", "1.0.0")] public class TimekeeperPlugin : BaseUnityPlugin { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] public enum Toggle { On = 1, Off = 0 } internal const string ModName = "Timekeeper"; internal const string ModVersion = "1.0.0"; internal const string Author = "RustyMods"; private const string ModGUID = "RustyMods.Timekeeper"; private static readonly string ConfigFileName = "RustyMods.Timekeeper.cfg"; private static readonly string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("RustyMods.Timekeeper"); public static readonly ManualLogSource TimekeeperLogger; public static readonly ConfigSync ConfigSync; public static TimekeeperPlugin instance; private static ConfigEntry<Toggle> _serverConfigLocked; public void Awake() { instance = this; Timekeeper.Setup(); TimeMan.Setup(); Localizer.Load(); Webhook.Setup(); CommandManager.Setup(); _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); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); } 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 { TimekeeperLogger.LogDebug((object)"ReadConfigValues called"); ((BaseUnityPlugin)this).Config.Reload(); } catch { TimekeeperLogger.LogError((object)("There was an issue loading your " + ConfigFileName)); TimekeeperLogger.LogError((object)"Please check your config entries for spelling and format!"); } } public ConfigEntry<T> config<[<67c466d5-4fad-4396-9408-d64f6873a1f4>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; } public ConfigEntry<T> config<[<67c466d5-4fad-4396-9408-d64f6873a1f4>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 TimekeeperPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; TimekeeperLogger = Logger.CreateLogSource("Timekeeper"); ConfigSync = new ConfigSync("RustyMods.Timekeeper") { DisplayName = "Timekeeper", CurrentVersion = "1.0.0", MinimumRequiredVersion = "1.0.0" }; instance = null; _serverConfigLocked = null; } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public static class Helpers { public static void SetText(this GameObject prefab, string childName, string text) { Transform val = Utils.FindChild(prefab.transform, childName, (IterativeSearchType)0); Text val2 = default(Text); if (!((Object)(object)val == (Object)null) && ((Component)val).TryGetComponent<Text>(ref val2)) { val2.text = Localization.instance.Localize(text); } } public static void CopySpriteAndMaterial(this GameObject prefab, GameObject source, string childName, string sourceChildName = "") { Image component = ((Component)prefab.transform.Find(childName)).GetComponent<Image>(); Image component2 = ((Component)source.transform.Find(Utility.IsNullOrWhiteSpace(sourceChildName) ? childName : sourceChildName)).GetComponent<Image>(); component.sprite = component2.sprite; ((Graphic)component).material = ((Graphic)component2).material; } public static void CopyButtonState(this GameObject prefab, GameObject source, string childName, string sourceChildName = "") { //IL_002e: Unknown result type (might be due to invalid IL or missing references) ((Selectable)((Component)prefab.transform.Find(childName)).GetComponent<Button>()).spriteState = ((Selectable)((Component)source.transform.Find(Utility.IsNullOrWhiteSpace(sourceChildName) ? childName : sourceChildName)).GetComponent<Button>()).spriteState; } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class Timekeeper : MonoBehaviour { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] private enum PanelType { Opaque, Transparent } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] [HarmonyPatch(typeof(Menu), "Start")] private static class Menu_Start_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static void Postfix(Menu __instance) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown Sprite sprite = ((Component)((Component)((Component)__instance).transform.parent.Find("Inventory_screen")).GetComponent<InventoryGui>().m_trophieElementPrefab.transform.Find("icon_bkg")).GetComponent<Image>().sprite; GameObject val = Object.Instantiate<GameObject>(((Component)((Transform)__instance.menuEntriesParent).Find("Settings")).gameObject, (Transform)(object)__instance.menuEntriesParent); ((Object)val).name = "Timekeeper"; val.transform.SetAsFirstSibling(); TMP_Text MenuLabel = val.GetComponentInChildren<TMP_Text>(); MenuLabel.text = Localization.instance.Localize("$label_timekeeper"); ((UnityEventBase)val.GetComponent<Button>().onClick).RemoveAllListeners(); ((UnityEvent)val.GetComponent<Button>().onClick).AddListener(new UnityAction(OnOpen)); GameObject sfxPrefab = __instance.m_settingsPrefab.GetComponentInChildren<ButtonSfx>().m_sfxPrefab; ButtonSfx[] componentsInChildren = m_root.GetComponentsInChildren<ButtonSfx>(true); foreach (ButtonSfx val2 in componentsInChildren) { val2.m_sfxPrefab = sfxPrefab; } m_item.GetComponent<ButtonSfx>().m_sfxPrefab = sfxPrefab; ((Component)m_item.transform.Find("Background")).GetComponent<Image>().sprite = sprite; ((Component)m_star.transform.Find("Day")).gameObject.SetActive(false); m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel"); m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/TabContent"); m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/HeaderLine"); m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/Back"); m_root.CopySpriteAndMaterial(__instance.m_settingsPrefab, "Panel/Collect", "Panel/Ok"); m_root.CopyButtonState(__instance.m_settingsPrefab, "Panel/Back"); m_root.CopyButtonState(__instance.m_settingsPrefab, "Panel/Collect", "Panel/Ok"); FontManager.SetFont(m_root.GetComponentsInChildren<Text>(true)); FontManager.SetFont(m_item.GetComponentsInChildren<Text>(true)); FontManager.SetFont(m_star.GetComponentsInChildren<Text>(true)); m_root.AddComponent<Timekeeper>(); Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, (Action)delegate { MenuLabel.text = Localization.instance.Localize("$label_timekeeper"); }); } } private static GameObject m_root; private static GameObject m_item; private static GameObject m_star; private static ConfigEntry<float> m_scale; private static ConfigEntry<PanelType> m_panelBackground; private static ConfigEntry<TimekeeperPlugin.Toggle> m_sendOnCollect; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] private static Timekeeper instance; public Image m_panel = null; public Image m_darken = null; public Text m_title = null; public Text m_description = null; public Text m_timeLabel = null; public Text m_time = null; public GameObject m_tooltipParent = null; public VerticalLayoutGroup m_tooltipContent = null; public RectTransform m_tooltipRect = null; public Text m_tooltip = null; public RectTransform m_rewardListRoot = null; public Image m_lineFill = null; public RectTransform m_starListRoot = null; public Button m_collectButton = null; public Text m_collectButtonLabel = null; public Text m_backButtonLabel = null; private int m_selectedReward = -1; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] private GameObject m_selectedRewardObject; private readonly Dictionary<int, float> m_fillLevels = new Dictionary<int, float> { [0] = 0f, [1] = 0.1f, [2] = 0.23f, [3] = 0.35f, [4] = 0.48f, [5] = 0.6f, [6] = 0.73f, [7] = 0.85f, [8] = 1f }; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] [method: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] [field: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] private event Action<string> OnCollect; public static void Setup() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) m_root = AssetManager.GetAssetBundle("timekeeperbundle").LoadAsset<GameObject>("Timekeeper_UI"); m_item = AssetManager.GetAssetBundle("timekeeperbundle").LoadAsset<GameObject>("Timekeeper_Item"); m_star = AssetManager.GetAssetBundle("timekeeperbundle").LoadAsset<GameObject>("Timekeeper_Star"); m_scale = TimekeeperPlugin.instance.config("Settings", "Panel Scale", 1f, new ConfigDescription("Set scale of panel", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>())); m_panelBackground = TimekeeperPlugin.instance.config("Settings", "Background", PanelType.Opaque, "Set background panel"); m_panelBackground.SettingChanged += [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (object _, EventArgs _) => { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)instance == (Object)null)) { ((Graphic)instance.m_panel).color = ((m_panelBackground.Value == PanelType.Opaque) ? Color.white : Color.clear); ((Graphic)instance.m_darken).color = (Color)((m_panelBackground.Value == PanelType.Opaque) ? Color.clear : new Color(0f, 0f, 0f, 0.5f)); } }; RectTransform rect = m_root.GetComponent<RectTransform>(); ((Transform)rect).localScale = Vector3.one * m_scale.Value; m_scale.SettingChanged += [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (object _, EventArgs _) => { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) //IL_0049: Unknown result type (might be due to invalid IL or missing references) ((Transform)rect).localScale = Vector3.one * m_scale.Value; if ((Object)(object)instance != (Object)null) { ((Transform)((Component)instance).GetComponent<RectTransform>()).localScale = Vector3.one * m_scale.Value; } }; m_sendOnCollect = TimekeeperPlugin.instance.config("Discord", "On Collect", TimekeeperPlugin.Toggle.On, "If on, plugin will send message when player collects reward"); } private static void OnOpen() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Settings.instance)) { Settings.instance.OnBack(); } Object.Instantiate<GameObject>(m_root, ((Component)Menu.instance).transform); Menu.instance.m_closeMenuState = (CloseMenuState)0; } public void Awake() { //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Expected O, but got Unknown //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)instance); } instance = this; m_panel = ((Component)((Component)this).transform.Find("Panel")).GetComponent<Image>(); m_darken = ((Component)((Component)this).transform.Find("Panel/darken")).GetComponent<Image>(); m_title = ((Component)((Component)this).transform.Find("Panel/Title")).GetComponent<Text>(); m_description = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Text")).GetComponent<Text>(); m_timeLabel = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/TimeLabel")).GetComponent<Text>(); m_time = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Time")).GetComponent<Text>(); m_tooltipParent = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Tooltip")).gameObject; m_tooltipContent = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Tooltip/Viewport/Content")).GetComponent<VerticalLayoutGroup>(); m_tooltip = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Tooltip/Viewport/Content/Text")).GetComponent<Text>(); m_tooltipRect = ((Component)m_tooltip).GetComponent<RectTransform>(); m_rewardListRoot = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/RewardList/Viewport/Content")).GetComponent<RectTransform>(); m_lineFill = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Timeline/LineFill")).GetComponent<Image>(); m_starListRoot = ((Component)((Component)this).transform.Find("Panel/TabContent/Rewards/Timeline/StarGroup")).GetComponent<RectTransform>(); m_collectButton = ((Component)((Component)this).transform.Find("Panel/Collect")).GetComponent<Button>(); ((Selectable)m_collectButton).interactable = false; m_collectButtonLabel = ((Component)((Component)m_collectButton).transform.Find("Label")).GetComponent<Text>(); m_backButtonLabel = ((Component)((Component)this).transform.Find("Panel/Back/Label")).GetComponent<Text>(); Button component = ((Component)((Component)this).transform.Find("Panel/Back")).GetComponent<Button>(); ((UnityEvent)component.onClick).AddListener(new UnityAction(OnBack)); Button component2 = ((Component)((Component)this).transform.Find("Panel/Collect")).GetComponent<Button>(); ((UnityEvent)component2.onClick).AddListener(new UnityAction(Collect)); ((Graphic)m_panel).color = ((m_panelBackground.Value == PanelType.Opaque) ? Color.white : Color.clear); ((Graphic)m_darken).color = (Color)((m_panelBackground.Value == PanelType.Opaque) ? Color.clear : new Color(0f, 0f, 0f, 0.5f)); m_title.text = Localization.instance.Localize("Glitnir $label_timekeeper"); m_collectButtonLabel.text = Localization.instance.Localize("$label_collect"); m_backButtonLabel.text = Localization.instance.Localize("$label_back"); OnCollect += Webhook.SendNotice; } public void Start() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) LoadStars(); LoadRewardItems(); SetDescription(); m_timeLabel.text = Localization.instance.Localize("$msg_active_for: "); m_tooltipParent.SetActive(false); m_tooltip.text = ""; int day = TimeMan.GetDay(); string text = day + ((day > 1) ? " $msg_days" : " $msg_day") + " " + TimeMan.GetTimeDisplay(); m_time.text = Localization.instance.Localize(text); ((Graphic)m_time).color = new Color(1f, 0.5f, 0f, 1f); } public void OnDestroy() { instance = null; } public void Update() { if (ZInput.GetKeyDown((KeyCode)27, true)) { OnBack(); } } public void SetDescription() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("$msg_welcome_back " + Player.m_localPlayer.GetPlayerName() + "!\n"); stringBuilder.Append($"$msg_next_reward {TimeMan.GetNextRewardDay()}\n"); m_description.text = Localization.instance.Localize(stringBuilder.ToString()); } public void LoadStars() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown if (((Transform)m_starListRoot).childCount > 0) { foreach (Transform item in (Transform)m_starListRoot) { Transform val = item; Object.Destroy((Object)(object)((Component)val).gameObject); } } int day = TimeMan.GetDay(); List<KeyValuePair<int, TimeMan.Reward>> list = (from r in TimeMan.GetRewards() orderby r.Key select r).ToList(); int num = ((day > 0) ? GetCurrentChunkIndex(list, day) : 0); int num2 = num * 8; int num3 = Math.Min(num2 + 8, list.Count); int num4 = num3 - num2; KeyValuePair<int, TimeMan.Reward>[] array = new KeyValuePair<int, TimeMan.Reward>[num4]; for (int i = 0; i < num4; i++) { array[i] = list[num2 + i]; } if (num4 > 0) { float num5 = CalculateFillAmount(array, day, num4); if (Math.Abs(num5 - 1f) < 0.01f) { num++; num2 = num * 8; num3 = Math.Min(num2 + 8, list.Count); num4 = num3 - num2; if (num4 > 0) { if (array.Length != num4) { array = new KeyValuePair<int, TimeMan.Reward>[num4]; } for (int j = 0; j < num4; j++) { array[j] = list[num2 + j]; } num5 = CalculateFillAmount(array, day, num4); } } CreateStarsForRewards(array, num4, day); m_lineFill.fillAmount = num5; } else { m_lineFill.fillAmount = 0f; } CreatePlaceholderStars(8 - num4); } private void CreateStarsForRewards([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 0, 1 })] KeyValuePair<int, TimeMan.Reward>[] rewards, int count, int playerDay) { for (int i = 0; i < count; i++) { KeyValuePair<int, TimeMan.Reward> keyValuePair = rewards[i]; GameObject val = Object.Instantiate<GameObject>(m_star, (Transform)(object)m_starListRoot); Text component = ((Component)val.transform.Find("Label")).GetComponent<Text>(); GameObject gameObject = ((Component)val.transform.Find("Star/Star_Lit")).gameObject; component.text = keyValuePair.Key.ToString(); if (playerDay >= keyValuePair.Key) { gameObject.SetActive(true); } } } private void CreatePlaceholderStars(int count) { for (int i = 0; i < count; i++) { GameObject val = Object.Instantiate<GameObject>(m_star, (Transform)(object)m_starListRoot); Text component = ((Component)val.transform.Find("Label")).GetComponent<Text>(); GameObject gameObject = ((Component)val.transform.Find("Star/Star_Lit")).gameObject; component.text = "?"; gameObject.SetActive(false); } } private static int GetCurrentChunkIndex([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 0, 1 })] List<KeyValuePair<int, TimeMan.Reward>> rewards, int playerDay) { int count = rewards.Count; int num = (count + 8 - 1) / 8; for (int i = 0; i < num; i++) { int num2 = i * 8; int num3 = Math.Min(num2 + 8, count); if (num2 >= count) { break; } int key = rewards[num3 - 1].Key; if (playerDay <= key) { return i; } } return Math.Max(0, (count - 1) / 8); } private float CalculateFillAmount([<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 0, 1 })] KeyValuePair<int, TimeMan.Reward>[] chunkRewards, int playerDay, int count) { if (count == 0) { return 0f; } for (int i = 0; i < count; i++) { int key = chunkRewards[i].Key; if (playerDay > key) { continue; } if (playerDay == key) { return m_fillLevels[i + 1]; } if (i == 0) { if (playerDay >= key) { return m_fillLevels[1]; } float num = (float)(playerDay - 1) / (float)(key - 1); return Mathf.Lerp(m_fillLevels[0], m_fillLevels[1], num); } int key2 = chunkRewards[i - 1].Key; float num2 = (float)(playerDay - key2) / (float)(key - key2); return Mathf.Lerp(m_fillLevels[i], m_fillLevels[i + 1], num2); } return m_fillLevels[Math.Min(count, 8)]; } public void LoadRewardItems() { //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown ItemDrop val = default(ItemDrop); foreach (KeyValuePair<int, TimeMan.Reward> item2 in from kv in TimeMan.GetRewards() orderby kv.Key select kv) { int day = item2.Key; if (TimeMan.IsRewardCollected(day)) { continue; } TimeMan.Reward value = item2.Value; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(value.ItemPrefab); if (itemPrefab != null && itemPrefab.TryGetComponent<ItemDrop>(ref val)) { bool canInteract = TimeMan.CanCollectReward(day) && !TimeMan.IsRewardCollected(day); GameObject item = Object.Instantiate<GameObject>(m_item, (Transform)(object)m_rewardListRoot); Button component = item.GetComponent<Button>(); Text component2 = ((Component)item.transform.Find("Label")).GetComponent<Text>(); Image component3 = ((Component)item.transform.Find("Background/Icon")).GetComponent<Image>(); ItemData data = val.m_itemData.Clone(); data.m_stack = value.Amount; data.m_quality = value.Quality; data.m_variant = value.Variant; component2.text = Localization.instance.Localize("$msg_day " + day); component3.sprite = val.m_itemData.GetIcon(); ((Graphic)component3).color = (canInteract ? Color.white : Color.black); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { SetTooltip(data); m_selectedReward = day; ((Selectable)m_collectButton).interactable = canInteract; m_selectedRewardObject = item; }); } } } public void OnBack() { Object.Destroy((Object)(object)((Component)this).gameObject); if (Object.op_Implicit((Object)(object)Settings.instance)) { Settings.instance.OnBack(); } } public void Collect() { if (TimeMan.IsRewardCollected(m_selectedReward) || !TimeMan.GetRewards().TryGetValue(m_selectedReward, out var value)) { return; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(value.ItemPrefab); ItemDrop val = default(ItemDrop); if (itemPrefab == null || !itemPrefab.TryGetComponent<ItemDrop>(ref val)) { return; } ItemData val2 = val.m_itemData.Clone(); val2.m_dropPrefab = itemPrefab; val2.m_stack = value.Amount; val2.m_quality = value.Quality; val2.m_variant = value.Variant; if (!((Humanoid)Player.m_localPlayer).GetInventory().CanAddItem(val2, -1)) { ((Character)Player.m_localPlayer).Message((MessageType)1, "$inventory_full", 0, (Sprite)null); return; } ((Humanoid)Player.m_localPlayer).GetInventory().AddItem(val2); if (m_sendOnCollect.Value == TimekeeperPlugin.Toggle.On) { this.OnCollect?.Invoke($"{Player.m_localPlayer.GetPlayerName()} $msg_has_collected {m_selectedReward}"); } TimeMan.SetRewardCollected(m_selectedReward); m_tooltipParent.SetActive(false); m_selectedReward = -1; m_tooltip.text = ""; ((Selectable)m_collectButton).interactable = false; if ((Object)(object)m_selectedRewardObject != (Object)null) { Object.Destroy((Object)(object)m_selectedRewardObject); } ((Character)Player.m_localPlayer).Message((MessageType)1, "$msg_added " + val2.m_shared.m_name, val2.m_stack, val2.GetIcon()); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public void SetTooltip(ItemData item) { //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (item == null) { m_tooltip.text = ""; } else { m_tooltipParent.SetActive(true); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("<color=yellow>" + item.m_shared.m_name + "</color>" + ((item.m_stack > 1) ? $" x{item.m_stack}" : "") + "\n\n"); stringBuilder.Append(item.GetTooltip(-1) + "\n\n"); m_tooltip.text = Localization.instance.Localize(stringBuilder.ToString()); } Canvas.ForceUpdateCanvases(); float textPreferredHeight = GetTextPreferredHeight(m_tooltip, m_tooltipRect); textPreferredHeight += (float)(((LayoutGroup)m_tooltipContent).padding.top + ((LayoutGroup)m_tooltipContent).padding.bottom); float num = 260f; float num2 = Mathf.Max(textPreferredHeight, num); float x = m_tooltipRect.sizeDelta.x; Vector2 sizeDelta = m_tooltipRect.sizeDelta; ((Vector2)(ref sizeDelta)).Set(x, num2); } private static float GetTextPreferredHeight(Text text, RectTransform rect) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(text.text)) { return 0f; } TextGenerator cachedTextGenerator = text.cachedTextGenerator; Rect rect2 = rect.rect; TextGenerationSettings generationSettings = text.GetGenerationSettings(((Rect)(ref rect2)).size); return cachedTextGenerator.GetPreferredHeight(text.text, generationSettings); } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public static class TimeMan { [HarmonyPatch(typeof(Player), "SetControls")] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] private static class Player_SetControls_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static void Postfix(Player __instance, Vector3 movedir, bool attack, bool attackHold, bool secondaryAttack, bool secondaryAttackHold, bool block, bool blockHold, bool jump, bool crouch, bool run, bool autoRun, bool dodge) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { if (attack || attackHold || secondaryAttack || secondaryAttackHold || block || blockHold || jump || crouch || run || dodge || movedir != Vector3.zero) { m_active = true; m_timeSinceLastInput = Time.fixedDeltaTime; } else if (Time.fixedDeltaTime > m_timeSinceLastInput + m_afkDuration.Value) { m_active = false; } if (m_active) { m_activeTimer = Mathf.Max(0f, m_activeTimer); m_activeTimer += Mathf.Max(0f, Time.fixedDeltaTime); SendDayNotice(); } } } } [HarmonyPatch(typeof(Player), "Load")] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] private static class Player_Load_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static void Postfix(Player __instance) { Load(__instance); } } [HarmonyPatch(typeof(Player), "Save")] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] private static class Player_Save_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static void Prefix(Player __instance) { Save(__instance); } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNet_Awake_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static void Postfix(ZNet __instance) { if (__instance.IsServer()) { UpdateServerRewards(); } } } [Serializable] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class Reward { public string ItemPrefab; public int Amount; public int Quality; public int Variant; public Reward(string item, int amount = 1, int quality = 1, int variant = 0) { ItemPrefab = item; Amount = amount; Quality = quality; Variant = variant; } } private const string RootFolderName = "Timekeeper"; private const string FileName = "Rewards.json"; private static readonly string RootFolderPath; private static readonly string FilePath; private static readonly CustomSyncedValue<string> ServerRewards; private static Dictionary<int, Reward> m_rewards; private static List<int> m_collectedRewards; private static bool m_active; private static float m_timeSinceLastInput; public static float m_activeTimer; private static int m_lastDay; private static ConfigEntry<float> m_afkDuration; private static ConfigEntry<TimekeeperPlugin.Toggle> m_sendDay; private static void SendDayNotice() { if (m_sendDay.Value != 0) { int day = GetDay(); if (day != m_lastDay) { m_lastDay = day; Webhook.instance.SendNotification($"{Player.m_localPlayer.GetPlayerName()} $msg_has_been_active {day} $msg_days"); } } } private static void UpdateServerRewards() { string value = JsonConvert.SerializeObject((object)m_rewards); ServerRewards.Value = value; } public static Dictionary<int, Reward> GetRewards() { return m_rewards; } public static int GetDay() { if (m_activeTimer < 0f) { TimekeeperPlugin.TimekeeperLogger.LogWarning((object)$"Active timer is negative: {m_activeTimer}, resetting to 0"); m_activeTimer = 0f; } return Mathf.FloorToInt(m_activeTimer / 1800f); } private static float GetTimeOfDay() { return m_activeTimer % 1800f; } public static string GetTimeDisplay() { float timeOfDay = GetTimeOfDay(); float num = 1800f; float num2 = num / 24f; float num3 = num2 / 60f; int num4 = Mathf.FloorToInt(timeOfDay / num2); int num5 = Mathf.FloorToInt(timeOfDay % num2 / num3); return $"{num4}:{num5:D2}"; } public static void Clear(Player player) { player.m_customData.Remove("TimekeeperCollected"); player.m_customData.Remove("TimekeeperTime"); m_activeTimer = 0f; m_collectedRewards.Clear(); } private static void Save(Player player) { player.m_customData["TimekeeperCollected"] = JsonConvert.SerializeObject((object)m_collectedRewards); player.m_customData["TimekeeperTime"] = m_activeTimer.ToString(CultureInfo.CurrentCulture); } private static void Load(Player player) { m_activeTimer = 0f; if (player.m_customData.TryGetValue("TimekeeperCollected", out var value)) { try { List<int> list = JsonConvert.DeserializeObject<List<int>>(value); if (list != null) { m_collectedRewards = list; } } catch { TimekeeperPlugin.TimekeeperLogger.LogWarning((object)"Failed to parse collected timekeeper keys"); player.m_customData.Remove("TimekeeperCollected"); } } if (player.m_customData.TryGetValue("TimekeeperTime", out var value2) && float.TryParse(value2, out var result)) { m_activeTimer = Mathf.Max(0f, result); m_lastDay = GetDay(); } } public static bool IsRewardCollected(int key) { return m_collectedRewards.Contains(key); } public static void SetRewardCollected(int key) { m_collectedRewards.Add(key); } public static int GetNextRewardDay() { foreach (KeyValuePair<int, Reward> item in m_rewards.OrderBy([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (KeyValuePair<int, Reward> kvp) => kvp.Key)) { if (item.Key <= GetDay()) { continue; } return item.Key; } return -1; } public static bool CanCollectReward(int key) { return key <= GetDay(); } public static void Setup() { m_afkDuration = TimekeeperPlugin.instance.config("Settings", "AFK Duration", 10f, "Set seconds until no input triggers AFK status"); m_sendDay = TimekeeperPlugin.instance.config("Discord", "On New Day", TimekeeperPlugin.Toggle.Off, "If on, will send message when player reaches a new day"); ServerRewards.ValueChanged += delegate { if ((!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer()) && !Utility.IsNullOrWhiteSpace(ServerRewards.Value)) { Dictionary<int, Reward> dictionary3 = JsonConvert.DeserializeObject<Dictionary<int, Reward>>(ServerRewards.Value); if (dictionary3 != null) { m_rewards = dictionary3; } } }; LoadDefaults(); if (!Directory.Exists(RootFolderPath)) { Directory.CreateDirectory(RootFolderPath); } if (!File.Exists(FilePath)) { UpdateRewardFile(); } else { try { Dictionary<int, Reward> dictionary = JsonConvert.DeserializeObject<Dictionary<int, Reward>>(File.ReadAllText(FilePath)); if (dictionary != null) { m_rewards = dictionary; } } catch { TimekeeperPlugin.TimekeeperLogger.LogWarning((object)"Failed to parse file: Rewards.json"); } } FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(RootFolderPath, "Rewards.json"); fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; fileSystemWatcher.Changed += OnFileChange; fileSystemWatcher.Created += OnFileChange; static void OnFileChange(object sender, FileSystemEventArgs args) { if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsServer()) { return; } TimekeeperPlugin.TimekeeperLogger.LogDebug((object)"Timekeeper config changed, reloading rewards"); try { Dictionary<int, Reward> dictionary2 = JsonConvert.DeserializeObject<Dictionary<int, Reward>>(File.ReadAllText(FilePath)); if (dictionary2 != null) { m_rewards = dictionary2; } UpdateServerRewards(); } catch { TimekeeperPlugin.TimekeeperLogger.LogWarning((object)"Failed to parse file: Rewards.json"); } } } private static void LoadDefaults() { m_rewards[1] = new Reward("Coins"); m_rewards[2] = new Reward("Coins"); m_rewards[4] = new Reward("Coins"); m_rewards[6] = new Reward("Coins"); m_rewards[8] = new Reward("Coins"); m_rewards[10] = new Reward("Coins"); m_rewards[12] = new Reward("Coins"); m_rewards[14] = new Reward("Coins"); m_rewards[16] = new Reward("Coins"); m_rewards[18] = new Reward("Coins"); m_rewards[21] = new Reward("Coins"); m_rewards[24] = new Reward("Coins"); m_rewards[27] = new Reward("Coins"); m_rewards[30] = new Reward("Coins"); m_rewards[33] = new Reward("Coins"); m_rewards[36] = new Reward("Coins"); m_rewards[39] = new Reward("Coins"); m_rewards[42] = new Reward("Coins"); m_rewards[45] = new Reward("Coins"); m_rewards[48] = new Reward("Coins"); m_rewards[51] = new Reward("Coins"); m_rewards[54] = new Reward("Coins"); m_rewards[57] = new Reward("Coins"); m_rewards[60] = new Reward("Coins"); m_rewards[63] = new Reward("Coins"); m_rewards[66] = new Reward("Coins"); m_rewards[69] = new Reward("Coins"); m_rewards[72] = new Reward("Coins"); m_rewards[75] = new Reward("Coins"); m_rewards[78] = new Reward("Coins"); m_rewards[81] = new Reward("Coins"); m_rewards[84] = new Reward("Coins"); m_rewards[87] = new Reward("Coins"); m_rewards[90] = new Reward("Coins"); m_rewards[94] = new Reward("Coins"); m_rewards[98] = new Reward("Coins"); m_rewards[102] = new Reward("Coins"); m_rewards[106] = new Reward("Coins"); m_rewards[110] = new Reward("Coins"); m_rewards[114] = new Reward("Coins"); m_rewards[118] = new Reward("Coins"); m_rewards[122] = new Reward("Coins"); m_rewards[126] = new Reward("Coins"); m_rewards[130] = new Reward("Coins"); m_rewards[134] = new Reward("Coins"); m_rewards[138] = new Reward("Coins"); m_rewards[142] = new Reward("Coins"); m_rewards[146] = new Reward("Coins"); m_rewards[150] = new Reward("Coins"); m_rewards[154] = new Reward("Coins"); m_rewards[158] = new Reward("Coins"); m_rewards[162] = new Reward("Coins"); m_rewards[166] = new Reward("Coins"); m_rewards[170] = new Reward("Coins"); m_rewards[174] = new Reward("Coins"); m_rewards[178] = new Reward("Coins"); m_rewards[182] = new Reward("Coins"); m_rewards[187] = new Reward("Coins"); m_rewards[192] = new Reward("Coins"); m_rewards[197] = new Reward("Coins"); m_rewards[202] = new Reward("Coins"); m_rewards[207] = new Reward("Coins"); m_rewards[212] = new Reward("Coins"); m_rewards[217] = new Reward("Coins"); m_rewards[222] = new Reward("Coins"); m_rewards[227] = new Reward("Coins"); m_rewards[232] = new Reward("Coins"); m_rewards[237] = new Reward("Coins"); m_rewards[242] = new Reward("Coins"); m_rewards[247] = new Reward("Coins"); m_rewards[252] = new Reward("Coins"); m_rewards[257] = new Reward("Coins"); m_rewards[262] = new Reward("Coins"); m_rewards[267] = new Reward("Coins"); m_rewards[272] = new Reward("Coins"); m_rewards[277] = new Reward("Coins"); m_rewards[282] = new Reward("Coins"); m_rewards[287] = new Reward("Coins"); m_rewards[292] = new Reward("Coins"); m_rewards[297] = new Reward("Coins"); m_rewards[302] = new Reward("Coins"); m_rewards[307] = new Reward("Coins"); m_rewards[312] = new Reward("Coins"); m_rewards[317] = new Reward("Coins"); m_rewards[322] = new Reward("Coins"); m_rewards[326] = new Reward("Coins"); m_rewards[330] = new Reward("Coins"); m_rewards[334] = new Reward("Coins"); m_rewards[338] = new Reward("Coins"); m_rewards[341] = new Reward("Coins"); m_rewards[344] = new Reward("Coins"); m_rewards[347] = new Reward("Coins"); m_rewards[350] = new Reward("Coins"); m_rewards[353] = new Reward("Coins"); m_rewards[356] = new Reward("Coins"); m_rewards[358] = new Reward("Coins"); m_rewards[360] = new Reward("Coins"); m_rewards[362] = new Reward("Coins"); m_rewards[364] = new Reward("Coins"); m_rewards[365] = new Reward("Coins"); } public static void AddReward(int day, Reward reward) { m_rewards[day] = reward; } public static void UpdateRewardFile() { string contents = JsonConvert.SerializeObject((object)m_rewards, (Formatting)1); File.WriteAllText(FilePath, contents); } static TimeMan() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; RootFolderPath = configPath + directorySeparatorChar + "Timekeeper"; string rootFolderPath = RootFolderPath; directorySeparatorChar = Path.DirectorySeparatorChar; FilePath = rootFolderPath + directorySeparatorChar + "Rewards.json"; ServerRewards = new CustomSyncedValue<string>(TimekeeperPlugin.ConfigSync, "ServerTimekeeperRewards", ""); m_rewards = new Dictionary<int, Reward>(); m_collectedRewards = new List<int>(); m_activeTimer = 0f; m_lastDay = -1; m_afkDuration = null; m_sendDay = null; } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class Webhook : MonoBehaviour { [Serializable] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public class DiscordWebhookData { public string content; public bool tts; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] public Embed[] embeds; public string username; public string avatar_url; [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public DiscordWebhookData(string content) { this.content = Localization.instance.Localize(content); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public DiscordWebhookData(params Embed[] embeds) { this.embeds = embeds; } } [Serializable] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class Embed { public string title; public string description; public string url; public string timestamp; public int? color; public Footer footer; public EmbedImage image; public EmbedImage thumbnail; public EmbedVideo video; public EmbedProvider provider; public EmbedAuthor author; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] public EmbedField[] fields; public Embed() { timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public Embed(string title, string description) { this.title = Localization.instance.Localize(title); this.description = Localization.instance.Localize(description); timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public Embed(string title, params EmbedField[] fields) { this.title = title; this.fields = fields; timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public Embed(string description) { this.description = Localization.instance.Localize(description); timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public Embed(string title, List<EmbedField> fields) : this(title, fields.ToArray()) { } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public void AddImage(string imageUrl) { if (!string.IsNullOrEmpty(imageUrl)) { image = new EmbedImage(imageUrl); } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public void AddThumbnail(string thumbnailUrl) { if (!string.IsNullOrEmpty(thumbnailUrl)) { thumbnail = new EmbedImage(thumbnailUrl); } } public void SetColor(Color Color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) color = ColorToInt(Color); } } [Serializable] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] [Description("Discord image json object")] public class EmbedImage { [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] public string url; public int width; public int height; [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public EmbedImage(string url, int width = 256, int height = 256) { this.url = url; this.width = width; this.height = height; } } [Serializable] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] public class EmbedVideo { [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] public string url; public int height; public int width; } [Serializable] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class EmbedProvider { public string name; public string url; } [Serializable] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] [Description("Discord author json object")] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class EmbedAuthor { public string name; public string icon_url; } [Serializable] [Description("Discord embed json object")] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public class EmbedField { public string name; public string value; public bool inline; [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public EmbedField(string name, string value, bool inline = true) { this.name = Localization.instance.Localize(name); this.value = Localization.instance.Localize(value); this.inline = inline; } } [Serializable] [Description("Discord footer json object")] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class Footer { [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] public string text; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] public string icon_url; public Footer(string text) { this.text = Localization.instance.Localize(text); } public void AddIcon(string url) { if (!string.IsNullOrEmpty(url)) { icon_url = url; } } } [Serializable] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [Description("Discord message json object")] public class Message { public string id; public string channel_id; public User author; public string content; public string timestamp; public string edited_timestamp; public bool tts; public bool mention_everyone; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] public User[] mentions; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] public User[] mention_roles; public int type; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] public Embed[] embeds; } [Serializable] [Description("Discord user json object")] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public class User { public string id; public string username; public string global_name; public string discriminator; public bool bot; public string avatar; [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public string GetDisplayName() { return ((!string.IsNullOrEmpty(global_name)) ? global_name : username) ?? string.Empty; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public string GetFullUsername() { return (!string.IsNullOrEmpty(discriminator) && discriminator != "0") ? (username + "#" + discriminator) : (username ?? string.Empty); } } private static ConfigEntry<string> m_webhookURL; public static Webhook instance; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] [method: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] [field: <67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] public event Action<string> OnError; public static void Setup() { m_webhookURL = TimekeeperPlugin.instance.config("Discord", "Webhook URL", "", "Set webhook to receive notifications about timekeeper"); ((Component)TimekeeperPlugin.instance).gameObject.AddComponent<Webhook>(); } public void Awake() { instance = this; OnError += HandleError; } private static void HandleError(string message) { TimekeeperPlugin.TimekeeperLogger.LogWarning((object)message); } public static void SendNotice(string message) { instance.SendNotification(message); } public void SendNotification(string message) { DiscordWebhookData data = new DiscordWebhookData(message); ((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, m_webhookURL.Value)); } public static void SendEmbedNotice(string title, string content, string thumbnail = "") { instance.SendEmbedMessage(title, content, thumbnail); } public void SendEmbedMessage(string title, string content, string thumbnail = "") { Embed embed = new Embed(title, content); embed.AddThumbnail(thumbnail); DiscordWebhookData data = new DiscordWebhookData(embed); ((MonoBehaviour)this).StartCoroutine(SendWebhookMessage(data, m_webhookURL.Value)); } private IEnumerator SendWebhookMessage(DiscordWebhookData data, string webhookURL) { if (string.IsNullOrEmpty(webhookURL)) { this.OnError?.Invoke("Webhook URL is not set!"); yield break; } string jsonData = JsonConvert.SerializeObject((object)data); byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonData); UnityWebRequest request = new UnityWebRequest(webhookURL, "POST"); try { request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw); request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json"); yield return request.SendWebRequest(); if ((int)request.result != 1) { string error = "Failed to send message: " + request.error + " - " + request.downloadHandler.text; this.OnError?.Invoke(error); } } finally { ((IDisposable)request)?.Dispose(); } } public static int ColorToInt(Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.RoundToInt(color.r * 255f); int num2 = Mathf.RoundToInt(color.g * 255f); int num3 = Mathf.RoundToInt(color.b * 255f); return (num << 16) + (num2 << 8) + num3; } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public static class RegisterAndCheckVersion { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>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 TimekeeperPlugin.TimekeeperLogger.LogDebug((object)"Registering version RPC handler"); peer.m_rpc.Register<ZPackage>("Timekeeper_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_Timekeeper_Version); TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Invoking version check"); ZPackage val = new ZPackage(); val.Write("1.0.0"); peer.m_rpc.Invoke("Timekeeper_VersionCheck", new object[1] { val }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>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; } TimekeeperPlugin.TimekeeperLogger.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(), "TimekeeperRequestAdminSync", new object[1] { (object)new ZPackage() }); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] public class ShowConnectionError { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>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" + TimekeeperPlugin.ConnectionError; } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] public static class RemoveDisconnectedPeerFromVerified { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static void Prefix(ZNetPeer peer, ref ZNet __instance) { if (__instance.IsServer()) { TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list")); RpcHandlers.ValidatedPeers.Remove(peer.m_rpc); } } } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public static class RpcHandlers { public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>(); public static void RPC_Timekeeper_Version(ZRpc rpc, ZPackage pkg) { string text = pkg.ReadString(); TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Version check, local: 1.0.0, remote: " + text)); if (text != "1.0.0") { TimekeeperPlugin.ConnectionError = "Timekeeper Installed: 1.0.0\n Needed: " + text; if (ZNet.instance.IsServer()) { TimekeeperPlugin.TimekeeperLogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting...")); rpc.Invoke("Error", new object[1] { 3 }); } } else if (!ZNet.instance.IsServer()) { TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Received same version from server!"); } else { TimekeeperPlugin.TimekeeperLogger.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 Timekeeper.Managers { public static class CommandManager { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public class CommandData { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] [HarmonyPatch(typeof(Terminal), "updateSearch")] private static class Terminal_UpdateSearch_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static bool Prefix(Terminal __instance, string word) { if ((Object)(object)__instance.m_search == (Object)null) { return true; } string[] array = ((TMP_InputField)__instance.m_input).text.Split(new char[1] { ' ' }); if (array.Length < 3) { return true; } if (array[0] != m_startCommand) { return true; } return HandleSearch(__instance, word, array); } } [HarmonyPatch(typeof(Terminal), "tabCycle")] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] private static class Terminal_TabCycle_Patch { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] private static bool Prefix(Terminal __instance, string word, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1 })] List<string> options, bool usePrefix) { if (options == null || options.Count == 0) { return true; } usePrefix = usePrefix && __instance.m_tabPrefix > '\0'; if (usePrefix) { if (word.Length < 1 || word[0] != __instance.m_tabPrefix) { return true; } word = word.Substring(1); } return HandleTabCycle(__instance, word, options, usePrefix); } } public static readonly string m_startCommand = "timekeeper"; public static readonly Dictionary<string, CommandData> m_commands = new Dictionary<string, CommandData>(); public readonly string m_description; private readonly bool m_isSecret; private readonly bool m_adminOnly; private readonly Func<ConsoleEventArgs, bool> m_command; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1, 1 })] private readonly Func<List<string>> m_optionFetcher; public bool Run(ConsoleEventArgs args) { return !IsAdmin() || m_command(args); } private bool IsAdmin() { if (!Object.op_Implicit((Object)(object)ZNet.m_instance)) { return true; } if (!m_adminOnly || ZNet.m_instance.LocalPlayerIsAdminOrHost()) { return true; } Debug.LogWarning((object)"Admin only command"); return false; } public bool IsSecret() { return m_isSecret; } public List<string> FetchOptions() { return (m_optionFetcher == null) ? new List<string>() : m_optionFetcher(); } public bool HasOptions() { return m_optionFetcher != null; } public CommandData(string input, string description, Func<ConsoleEventArgs, bool> command, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 2, 1, 1 })] Func<List<string>> optionsFetcher = null, bool isSecret = false, bool adminOnly = false) { m_description = description; m_command = command; m_isSecret = isSecret; m_commands[input] = this; m_optionFetcher = optionsFetcher; m_adminOnly = adminOnly; } private static bool HandleSearch(Terminal __instance, string word, string[] strArray) { if (!m_commands.TryGetValue(strArray[1], out var value)) { return true; } if (value.HasOptions() && strArray.Length == 3) { List<string> list = value.FetchOptions(); string currentSearch = strArray[2]; List<string> list2; if (!Utility.IsNullOrWhiteSpace(currentSearch)) { int num = list.IndexOf(currentSearch); list2 = ((num != -1) ? list.GetRange(num, list.Count - num) : list); list2 = list2.FindAll((string x) => x.ToLower().Contains(currentSearch.ToLower())); } else { list2 = list; } if (list2.Count <= 0) { __instance.m_search.text = value.m_description; } else { __instance.m_lastSearch.Clear(); __instance.m_lastSearch.AddRange(list2); __instance.m_lastSearch.Remove(word); __instance.m_search.text = ""; int num2 = 10; int num3 = Math.Min(__instance.m_lastSearch.Count, num2); for (int i = 0; i < num3; i++) { string text = __instance.m_lastSearch[i]; TMP_Text search = __instance.m_search; search.text = search.text + text + " "; } if (__instance.m_lastSearch.Count <= num2) { return false; } int num4 = __instance.m_lastSearch.Count - num2; TMP_Text search2 = __instance.m_search; search2.text += $"... {num4} more."; } } else { __instance.m_search.text = value.m_description; } return false; } private static bool HandleTabCycle(Terminal __instance, string word, List<string> options, bool usePrefix) { string text = ((TMP_InputField)__instance.m_input).text; string[] array = text.Split(new char[1] { ' ' }); if (array.Length < 2 || !string.Equals(array[0], m_startCommand, StringComparison.CurrentCultureIgnoreCase) || !m_commands.ContainsKey(array[1].ToLower())) { return true; } if (__instance.m_tabCaretPosition == -1) { __instance.m_tabOptions.Clear(); __instance.m_tabCaretPosition = ((TMP_InputField)__instance.m_input).caretPosition; word = word.ToLower(); __instance.m_tabLength = word.Length; if (__instance.m_tabLength == 0) { __instance.m_tabOptions.AddRange(options); } else { foreach (string option in options) { if (option != null && option.Length > __instance.m_tabLength && option.Substring(0, __instance.m_tabLength).ToLower() == word) { __instance.m_tabOptions.Add(option); } } } __instance.m_tabOptions.Sort(); __instance.m_tabIndex = -1; } if (__instance.m_tabOptions.Count == 0) { __instance.m_tabOptions.AddRange(__instance.m_lastSearch); } if (__instance.m_tabOptions.Count == 0) { return false; } if (++__instance.m_tabIndex >= __instance.m_tabOptions.Count) { __instance.m_tabIndex = 0; } if (__instance.m_tabCaretPosition - __instance.m_tabLength >= 0) { int num = 0; int num2 = 0; for (int i = 0; i < text.Length; i++) { if (text[i] == ' ') { num++; if (num == 2) { num2 = i + 1; break; } } } if (array.Length >= 3 && num2 > 0) { string text2 = text.Substring(0, num2); ((TMP_InputField)__instance.m_input).text = text2 + __instance.m_tabOptions[__instance.m_tabIndex]; } else if (array.Length == 2) { ((TMP_InputField)__instance.m_input).text = text + " " + __instance.m_tabOptions[__instance.m_tabIndex]; } } int tabCaretPositionEnd = (((TMP_InputField)__instance.m_input).caretPosition = ((TMP_InputField)__instance.m_input).text.Length); __instance.m_tabCaretPositionEnd = tabCaretPositionEnd; return false; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEventFailable <>9__0_0; public static Func<KeyValuePair<string, CommandData>, bool> <>9__0_1; public static Func<KeyValuePair<string, CommandData>, string> <>9__0_2; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })] public static Func<ConsoleEventArgs, bool> <>9__0_3; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })] public static Func<ConsoleEventArgs, bool> <>9__0_4; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })] public static Func<ConsoleEventArgs, bool> <>9__0_5; [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 0, 1 })] public static Func<ConsoleEventArgs, bool> <>9__0_6; internal object <Setup>b__0_0(ConsoleEventArgs args) { if (args.Length < 2) { return false; } if (!CommandData.m_commands.TryGetValue(args[1], out var value)) { return false; } return value.Run(args); } internal bool <Setup>b__0_1(KeyValuePair<string, CommandData> x) { return !x.Value.IsSecret(); } internal string <Setup>b__0_2(KeyValuePair<string, CommandData> x) { return x.Key; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] internal bool <Setup>b__0_3(ConsoleEventArgs args) { if (args.Length < 3) { return false; } if (!float.TryParse(args[2], out var result)) { return false; } TimeMan.m_activeTimer += result; TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + result + " seconds to local player")); return true; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] internal bool <Setup>b__0_4(ConsoleEventArgs _) { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } TimeMan.Clear(Player.m_localPlayer); TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Cleared local player timekeeper data"); return true; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] internal bool <Setup>b__0_5(ConsoleEventArgs _) { if (!Object.op_Implicit((Object)(object)EnvMan.instance)) { return false; } TimeMan.m_activeTimer += EnvMan.instance.m_dayLengthSec; TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + EnvMan.instance.m_dayLengthSec + " seconds to local player")); return true; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] internal bool <Setup>b__0_6(ConsoleEventArgs args) { if (args.Length < 5) { return false; } if (!int.TryParse(args[2], out var result)) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(args[3].Trim()); if (itemPrefab == null) { return false; } if (!int.TryParse(args[4], out var result2)) { return false; } int num = 1; int num2 = 0; if (args.Length > 5) { num = (int.TryParse(args[5], out var result3) ? result3 : num); } if (args.Length > 6) { num2 = (int.TryParse(args[6], out var result4) ? result4 : num2); } TimeMan.Reward reward = new TimeMan.Reward(((Object)itemPrefab).name, result2, num, num2); TimeMan.AddReward(result, reward); TimeMan.UpdateRewardFile(); TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Updated rewards"); return true; } } public static void Setup() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown string startCommand = CommandData.m_startCommand; object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEventFailable val = delegate(ConsoleEventArgs args) { if (args.Length < 2) { return false; } CommandData value; return (!CommandData.m_commands.TryGetValue(args[1], out value)) ? ((object)false) : ((object)value.Run(args)); }; <>c.<>9__0_0 = val; obj = (object)val; } ConsoleCommand val2 = new ConsoleCommand(startCommand, "Use help to find commands", (ConsoleEventFailable)obj, false, false, false, false, false, new ConsoleOptionsFetcher(Enumerable.ToList), false, false, false); new CommandData("add", "adds seconds to player counter", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs args) => { if (args.Length < 3) { return false; } if (!float.TryParse(args[2], out var result5)) { return false; } TimeMan.m_activeTimer += result5; TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + result5 + " seconds to local player")); return true; }, null, isSecret: false, adminOnly: true); new CommandData("reset", "clears data from player save", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs _) => { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } TimeMan.Clear(Player.m_localPlayer); TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Cleared local player timekeeper data"); return true; }); new CommandData("add_day", "adds a full day (1800) to the player counter", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs _) => { if (!Object.op_Implicit((Object)(object)EnvMan.instance)) { return false; } TimeMan.m_activeTimer += EnvMan.instance.m_dayLengthSec; TimekeeperPlugin.TimekeeperLogger.LogInfo((object)("Added " + EnvMan.instance.m_dayLengthSec + " seconds to local player")); return true; }, null, isSecret: false, adminOnly: true); new CommandData("add_reward", "[day] [itemName] [Amount] [Quality] [Variant], add a new reward", [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] (ConsoleEventArgs args) => { if (args.Length < 5) { return false; } if (!int.TryParse(args[2], out var result)) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(args[3].Trim()); if (itemPrefab == null) { return false; } if (!int.TryParse(args[4], out var result2)) { return false; } int num = 1; int num2 = 0; if (args.Length > 5) { num = (int.TryParse(args[5], out var result3) ? result3 : num); } if (args.Length > 6) { num2 = (int.TryParse(args[6], out var result4) ? result4 : num2); } TimeMan.Reward reward = new TimeMan.Reward(((Object)itemPrefab).name, result2, num, num2); TimeMan.AddReward(result, reward); TimeMan.UpdateRewardFile(); TimekeeperPlugin.TimekeeperLogger.LogInfo((object)"Updated rewards"); return true; }, null, isSecret: false, adminOnly: true); } } } namespace Managers { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] public static class AssetManager { private static readonly Dictionary<string, AssetBundle> m_assetBundles = new Dictionary<string, AssetBundle>(); public static AssetBundle GetAssetBundle(string fileName) { if (m_assetBundles.TryGetValue(fileName, out var value)) { return value; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = executingAssembly.GetManifestResourceNames().Single([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (string str) => str.EndsWith(fileName)); using Stream stream = executingAssembly.GetManifestResourceStream(name); value = AssetBundle.LoadFromStream(stream); m_assetBundles[fileName] = value; return value; } } [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(1)] public static class FontManager { [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] public enum FontOptions { Norse, NorseBold, AveriaSerifLibre, AveriaSerifLibreBold, AveriaSerifLibreLight, LegacyRuntime } [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(0)] private class TextFont { private readonly Text m_text; public TextFont(Text text, [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(2)] Font font) { m_text = text; Update(font); m_allTexts.Add(this); } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public void Update(Font font) { m_text.font = font; } } [<67c466d5-4fad-4396-9408-d64f6873a1f4>Nullable(new byte[] { 1, 2 })] private static readonly Dictionary<FontOptions, Font> m_fonts = new Dictionary<FontOptions, Font>(); private static readonly List<TextFont> m_allTexts = new List<TextFont>(); private static string GetFontName(FontOptions option) { if (1 == 0) { } string result = option switch { FontOptions.Norse => "Norse", FontOptions.AveriaSerifLibre => "AveriaSerifLibre-Regular", FontOptions.AveriaSerifLibreBold => "AveriaSerifLibre-Bold", FontOptions.AveriaSerifLibreLight => "AveriaSerifLibre-Light", FontOptions.NorseBold => "Norsebold", FontOptions.LegacyRuntime => "LegacyRuntime", _ => "AveriaSerifLibre-Regular", }; if (1 == 0) { } return result; } [<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(2)] public static Font GetFont(FontOptions option) { if (m_fonts.TryGetValue(option, out var value)) { return value; } Font[] source = Resources.FindObjectsOfTypeAll<Font>(); Font val = ((IEnumerable<Font>)source).FirstOrDefault((Func<Font, bool>)([<82ba7967-cfcc-42a3-95f8-cb394c42ff49>NullableContext(0)] (Font x) => ((Object)x).name == GetFontName(option))); m_fonts[option] = val; return val; } public static void OnFontChange(object sender, EventArgs args) { Font font = GetFont(FontOptions.AveriaSerifLibre); foreach (TextFont allText in m_allTexts) { allText.Update(font); } } public static void SetFont(Text[] array) { foreach (Text text in array) { TextFont textFont = new TextFont(text, GetFont(FontOptions.AveriaSerifLibre)); } } } } namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] [CompilerGenerated] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [Microsoft.CodeAnalysis.Embedded] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [CompilerGenerated] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] [Microsoft.CodeAnalysis.Embedded] [CompilerGenerated] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ServerSync { [PublicAPI] internal abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] internal class SyncedConfigEntry<T> : OwnConfigEntryBase { public readonly ConfigEntry<T> SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry<T> sourceConfig) { SourceConfig = sourceConfig; base..ctor(); } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } internal abstract class CustomSyncedValueBase { public object? LocalBaseValue; public readonly string Identifier; 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; 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] internal sealed class CustomSyncedValue<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] internal class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List<ZNetPeer> peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List<string> CurrentList = new List<string>(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List<string>(adminList.GetList()); List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((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")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>(); public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] 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; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { private class BufferingSocket : ZPlayFabSocket, 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; ((ZPlayFabSocket)this)..ctor(); } 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); } } } [HarmonyPriority(800)] [HarmonyPrefix] private static void Prefix(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()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); 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) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary<Assembly, BufferingSocket>(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary<Assembly, BufferingSocket> __state, ZNet __instance, ZRpc rpc) { ZRpc rpc2 = rpc; ZNet __instance2 = __instance; Dictionary<Assembly, BufferingSocket> __state2 = __state; ZNetPeer peer; if (__instance2.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance2).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc2.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state2[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(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2] { adminList, rpc2.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false); yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List<ZNetPeer> { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section = null; public string key = null; public Type type = null; public object? value; } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [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")] private static class PreventConfigRereadChangingValues { [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; } } private class InvalidDeserializationTypeException : Exception { public string expected = null; public string received = null; public string field = ""; } public static bool Processin