using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Text; using BepInEx; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("DrakesTelemarker")] [assembly: AssemblyDescription("Per-world console warp bookmarks (10 slots).")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("DrakeMods")] [assembly: AssemblyProduct("DrakesTelemarker")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("5DF97E86-BF46-46C5-894F-6B2D80EA6645")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DrakesTelemarker { [BepInPlugin("com.drakemods.DrakesTelemarker", "DrakesTelemarker", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class DrakesTelemarkerPlugin : BaseUnityPlugin { private sealed class TelemarkCommand : ConsoleCommand { private readonly DrakesTelemarkerPlugin _plugin; public override string Name => "telemark"; public override string Help => "Not a cheat: prints usage. Subcommands list/set/recall/clear require cheat access — run with no args."; public override bool IsCheat => false; public TelemarkCommand(DrakesTelemarkerPlugin plugin) { _plugin = plugin; } public override List CommandOptionList() { return BuildTelemarkTabCompletions(); } public override void Run(string[] args) { RouteTelemark(_plugin, args); } } private sealed class SetMarkCommand : ConsoleCommand { private readonly DrakesTelemarkerPlugin _plugin; public override string Name => "set"; public override string Help => $"Shortcut for telemark set mark <1-{10}>"; public override bool IsCheat => false; public SetMarkCommand(DrakesTelemarkerPlugin plugin) { _plugin = plugin; } public override List CommandOptionList() { return BuildMarkAliasTabCompletions(); } public override void Run(string[] args) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (!CanUseTelemarkerCheats()) { Notify("Need cheat access (devcommands or server admin). Run telemark for help."); return; } if (!TryParseMarkSlotArgs(args, out int slot, out string usageError)) { Notify(usageError); return; } Player localPlayerOrNotify = GetLocalPlayerOrNotify(); if (localPlayerOrNotify != null) { Vector3 position = ((Component)localPlayerOrNotify).transform.position; _plugin.TrySetSlot(slot, position, out string _); Notify($"Saved mark {slot} at {FormatVec(position)}."); } } } private sealed class RecallMarkCommand : ConsoleCommand { private readonly DrakesTelemarkerPlugin _plugin; public override string Name => "recall"; public override string Help => $"Shortcut for telemark recall mark <1-{10}>"; public override bool IsCheat => false; public RecallMarkCommand(DrakesTelemarkerPlugin plugin) { _plugin = plugin; } public override List CommandOptionList() { return BuildMarkAliasTabCompletions(); } public override void Run(string[] args) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) if (!CanUseTelemarkerCheats()) { Notify("Need cheat access (devcommands or server admin). Run telemark for help."); return; } if (!TryParseMarkSlotArgs(args, out int slot, out string usageError)) { Notify(usageError); return; } Player localPlayerOrNotify = GetLocalPlayerOrNotify(); if (localPlayerOrNotify != null) { if (!_plugin.TryRecallSlot(slot, out Vector3 position, out string error)) { Notify(string.IsNullOrEmpty(error) ? $"Mark {slot} is empty." : error); return; } ((Component)localPlayerOrNotify).transform.position = position; Physics.SyncTransforms(); Notify($"Recalled mark {slot} -> {FormatVec(position)}."); } } } public const string ModName = "DrakesTelemarker"; public const string Version = "0.1.0"; public const string GUID = "com.drakemods.DrakesTelemarker"; internal const int SlotCount = 10; private void Awake() { TelemarkerClearDialog.RegisterForGuiRebuild(); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new TelemarkCommand(this)); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SetMarkCommand(this)); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RecallMarkCommand(this)); TelemarkerMinimap.Init(this); ((BaseUnityPlugin)this).Logger.LogInfo((object)"DrakesTelemarker v0.1.0 loaded — type 'telemark' in console for commands."); } internal static string GetMarksFilePath() { string text = Path.Combine(Paths.ConfigPath, "DrakesTelemarker"); Directory.CreateDirectory(text); return Path.Combine(text, "TelemarkerMarks.json"); } internal static string GetWorldKey() { if ((Object)(object)ZNet.instance != (Object)null) { string worldName = ZNet.instance.GetWorldName(); if (!string.IsNullOrEmpty(worldName)) { return worldName; } } return "noworld"; } internal static string SanitizeWorldKey(string worldName) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { worldName = worldName.Replace(oldChar, '_'); } return string.IsNullOrEmpty(worldName) ? "world" : worldName; } internal static Player? GetLocalPlayerOrNotify() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Notify("No local player (join a world first)."); } return localPlayer; } internal static void Notify(string message) { PrintToDeveloperConsole("[DrakesTelemarker] " + message); } private static void PrintToDeveloperConsole(string line) { try { object obj = TryGetValheimConsoleInstance(); if (obj == null) { Debug.Log((object)line); return; } MethodInfo method = obj.GetType().GetMethod("Print", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null); if (method == null) { Debug.Log((object)line); return; } method.Invoke(obj, new object[1] { line }); } catch { Debug.Log((object)line); } } private static object? TryGetValheimConsoleInstance() { try { Type type = typeof(Player).Assembly.GetType("Console"); if (type == null) { return null; } PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy); if (property != null) { return property.GetValue(null); } FieldInfo field = type.GetField("instance", BindingFlags.Static | BindingFlags.Public); if (field != null) { return field.GetValue(null); } return type.GetField("m_instance", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); } catch { return null; } } private static void PrintMultilineToDeveloperConsole(string text) { string[] array = text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.None); foreach (string text2 in array) { if (text2.Length > 0) { PrintToDeveloperConsole(text2); } } } internal bool TrySetSlot(int slot, Vector3 position, out string error) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) error = ""; string marksFilePath = GetMarksFilePath(); string worldKey = SanitizeWorldKey(GetWorldKey()); TelemarkerMarksDocument telemarkerMarksDocument = TelemarkerMarksDocument.Load(marksFilePath); telemarkerMarksDocument.UpsertSlot(worldKey, slot, position); TelemarkerMarksDocument.Save(marksFilePath, telemarkerMarksDocument); TelemarkerMinimap.RequestSync(); return true; } internal bool TryRecallSlot(int slot, out Vector3 position, out string error) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); error = ""; string marksFilePath = GetMarksFilePath(); string worldKey = SanitizeWorldKey(GetWorldKey()); TelemarkerMarksDocument telemarkerMarksDocument = TelemarkerMarksDocument.Load(marksFilePath); return telemarkerMarksDocument.TryGetSlot(worldKey, slot, out position, out error); } internal bool TryClearSlot(int slot, out string error) { error = ""; string marksFilePath = GetMarksFilePath(); string worldKey = SanitizeWorldKey(GetWorldKey()); TelemarkerMarksDocument telemarkerMarksDocument = TelemarkerMarksDocument.Load(marksFilePath); if (!telemarkerMarksDocument.ClearSlot(worldKey, slot)) { error = $"Mark {slot} was already empty."; return false; } TelemarkerMarksDocument.Save(marksFilePath, telemarkerMarksDocument); TelemarkerMinimap.RequestSync(); return true; } internal bool TryClearAllSlots(out int clearedCount, out string error) { clearedCount = 0; error = ""; string marksFilePath = GetMarksFilePath(); string worldKey = SanitizeWorldKey(GetWorldKey()); TelemarkerMarksDocument telemarkerMarksDocument = TelemarkerMarksDocument.Load(marksFilePath); clearedCount = telemarkerMarksDocument.ClearAllSlotsForWorld(worldKey); if (clearedCount == 0) { error = "No marks to clear."; return false; } TelemarkerMarksDocument.Save(marksFilePath, telemarkerMarksDocument); TelemarkerMinimap.RequestSync(); return true; } internal static bool CanUseTelemarkerCheats() { if (IsDevcommandsClientFlagOn()) { return true; } try { SynchronizationManager instance = SynchronizationManager.Instance; if (instance != null && instance.PlayerIsAdmin) { return true; } } catch { } return false; } internal static bool IsDevcommandsClientFlagOn() { return ReadTerminalCheatsEnabledWithFallback(); } private static bool ReadTerminalCheatsEnabledWithFallback() { try { MethodInfo[] methods = typeof(Terminal).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name != "IsCheatsEnabled" || methodInfo.ReturnType != typeof(bool) || methodInfo.GetParameters().Length != 0) { continue; } if (methodInfo.IsStatic) { if (methodInfo.Invoke(null, null) is bool result) { return result; } continue; } object obj = TryGetValheimConsoleInstance(); if (obj != null && methodInfo.Invoke(obj, null) is bool result2) { return result2; } } } catch { } return ReadTerminalCheatFlagViaReflection(); } private static bool ReadTerminalCheatFlagViaReflection() { try { object obj = TryGetValheimConsoleInstance(); FieldInfo field = typeof(Terminal).GetField("m_cheat", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && obj != null && field.GetValue(obj) is bool result) { return result; } field = typeof(Terminal).GetField("m_cheat", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.IsStatic) { object value = field.GetValue(null); if (value is bool) { bool result2 = (bool)value; if (true) { return result2; } } } } catch { } return false; } internal static string[] ArgsTail(string[] args, int start) { int num = args.Length - start; if (num <= 0) { return Array.Empty(); } string[] array = new string[num]; Array.Copy(args, start, array, 0, num); return array; } internal static string FormatVec(Vector3 p) { //IL_000b: 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_0021: Unknown result type (might be due to invalid IL or missing references) return string.Format(CultureInfo.InvariantCulture, "({0:F1}, {1:F1}, {2:F1})", p.x, p.y, p.z); } internal static List BuildTelemarkTabCompletions() { List list = new List { "help", "?", "list", "set", "recall", "clear", "mark", "all" }; for (int i = 1; i <= 10; i++) { list.Add(i.ToString(CultureInfo.InvariantCulture)); } return list; } internal static List BuildMarkAliasTabCompletions() { List list = new List { "mark" }; for (int i = 1; i <= 10; i++) { list.Add(i.ToString(CultureInfo.InvariantCulture)); } return list; } internal static bool TryParseMarkSlotArgs(string[] args, out int slot, out string usageError) { slot = 0; usageError = ""; if (args == null || args.Length < 2 || !args[0].Equals("mark", StringComparison.OrdinalIgnoreCase)) { usageError = $"Usage: telemark set mark <1-{10}> | telemark recall mark <1-{10}> (aliases: set mark …, recall mark …)"; return false; } int num = 1; if (num < args.Length && args[num].Equals("mark", StringComparison.OrdinalIgnoreCase)) { num++; } if (num >= args.Length || !int.TryParse(args[num], NumberStyles.Integer, CultureInfo.InvariantCulture, out slot) || slot < 1 || slot > 10) { usageError = $"Slot must be 1-{10}."; return false; } return true; } private static void PrintTelemarkUsage() { string text = "[DrakesTelemarker] Cheat vs help:\r\n • Running telemark alone (or telemark help) is NOT a cheat — it only prints this guide.\r\n • telemark list / set / recall / clear ARE cheats — need devcommands or server admin.\r\n • Same for aliases: set mark … and recall mark … (cheat access required).\r\n\r\nCommands:\r\n telemark\r\n Show this help (always allowed).\r\n telemark list\r\n List every slot that has a saved position for this world (cheat).\r\n" + $" telemark set mark <1-{10}>\r\n" + " Save your current position into a slot (cheat).\r\n" + $" telemark recall mark <1-{10}>\r\n" + " Warp to a saved slot (cheat).\r\n" + $" telemark clear <1-{10}>\r\n" + " Opens a confirmation dialog — click Yes to erase that slot, No to cancel.\r\n telemark clear all\r\n Same dialog for wiping every mark in this world.\r\nAliases:\r\n set mark Same as telemark set mark … (cheat).\r\n recall mark Same as telemark recall mark … (cheat).\r\n\r\nCheat access = devcommands OR server admin (adminlist; Server Devcommands works well here).\r\nJotunn syncs admin status for PlayerIsAdmin. Open console (F5): devcommands\r\n\r\nMinimap:\r\n" + $" Numbered pins labeled Mark 1–Mark {10}. Right-click (or Ctrl+left-click) a pin to recall when cheat access matches console (devcommands / Server Devcommands admin, same as telemark recall).\r\n"; PrintMultilineToDeveloperConsole(text); } private static void RunTelemarkList() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) string marksFilePath = GetMarksFilePath(); string text = SanitizeWorldKey(GetWorldKey()); TelemarkerMarksDocument telemarkerMarksDocument = TelemarkerMarksDocument.Load(marksFilePath); StringBuilder stringBuilder = new StringBuilder(); int num = 0; for (int i = 1; i <= 10; i++) { if (telemarkerMarksDocument.TryGetSlot(text, i, out Vector3 position, out string _)) { num++; stringBuilder.AppendLine($" slot {i}: {FormatVec(position)}"); } } if (num == 0) { Notify("No active marks for this world."); return; } PrintMultilineToDeveloperConsole(string.Format("[{0}] Active marks ({1}) for world \"{2}\":\n{3}", "DrakesTelemarker", num, text, stringBuilder.ToString().TrimEnd(Array.Empty()))); } private static void RouteTelemark(DrakesTelemarkerPlugin plugin, string[] args) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) if (args == null || args.Length == 0) { PrintTelemarkUsage(); return; } string text = args[0].ToLowerInvariant(); if ((text == "help" || text == "?") ? true : false) { PrintTelemarkUsage(); return; } if (!CanUseTelemarkerCheats()) { Notify("That needs cheat access (devcommands or server admin). telemark alone only prints help — run it for the full list."); return; } switch (text) { case "list": RunTelemarkList(); break; case "set": { if (!TryParseMarkSlotArgs(ArgsTail(args, 1), out int slot, out string usageError)) { Notify(usageError); break; } Player localPlayerOrNotify = GetLocalPlayerOrNotify(); if (localPlayerOrNotify != null) { Vector3 position = ((Component)localPlayerOrNotify).transform.position; plugin.TrySetSlot(slot, position, out string _); Notify($"Saved mark {slot} at {FormatVec(position)}."); } break; } case "recall": { if (!TryParseMarkSlotArgs(ArgsTail(args, 1), out int slot2, out string usageError2)) { Notify(usageError2); break; } Player localPlayerOrNotify2 = GetLocalPlayerOrNotify(); if (localPlayerOrNotify2 != null) { if (!plugin.TryRecallSlot(slot2, out Vector3 position2, out string error2)) { Notify(string.IsNullOrEmpty(error2) ? $"Mark {slot2} is empty." : error2); break; } ((Component)localPlayerOrNotify2).transform.position = position2; Physics.SyncTransforms(); Notify($"Recalled mark {slot2} -> {FormatVec(position2)}."); } break; } case "clear": { if (args.Length < 2) { Notify($"Usage: telemark clear <1-{10}> | telemark clear all"); break; } string text2 = args[1]; int result; if (text2.Equals("all", StringComparison.OrdinalIgnoreCase)) { if (args.Length > 2) { Notify("Usage: telemark clear all"); } else { TelemarkerClearDialog.RequestConfirmation(plugin, clearAll: true, 0); } } else if (!int.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) || result < 1 || result > 10) { Notify($"Usage: telemark clear <1-{10}> | telemark clear all"); } else if (args.Length > 2) { Notify($"Usage: telemark clear <1-{10}>"); } else { TelemarkerClearDialog.RequestConfirmation(plugin, clearAll: false, result); } break; } default: Notify("Unknown telemark subcommand '" + args[0] + "'. Check console log for full usage."); PrintTelemarkUsage(); break; } } } [DataContract] internal sealed class TelemarkerMarksDocument { [DataMember(Name = "schemaVersion")] public int SchemaVersion { get; set; } = 1; [DataMember(Name = "worlds")] public Dictionary Worlds { get; set; } = new Dictionary(); internal static TelemarkerMarksDocument Load(string path) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!File.Exists(path)) { return new TelemarkerMarksDocument(); } try { using FileStream fileStream = File.OpenRead(path); DataContractJsonSerializer val = new DataContractJsonSerializer(typeof(TelemarkerMarksDocument)); if (((XmlObjectSerializer)val).ReadObject((Stream)fileStream) is TelemarkerMarksDocument telemarkerMarksDocument) { TelemarkerMarksDocument telemarkerMarksDocument2 = telemarkerMarksDocument; if (telemarkerMarksDocument2.Worlds == null) { Dictionary dictionary2 = (telemarkerMarksDocument2.Worlds = new Dictionary()); } foreach (WorldMarkSlots value in telemarkerMarksDocument.Worlds.Values) { WorldMarkSlots worldMarkSlots = value; if (worldMarkSlots.Slots == null) { Dictionary dictionary4 = (worldMarkSlots.Slots = new Dictionary()); } } return telemarkerMarksDocument; } } catch (Exception ex) { Debug.LogWarning((object)("[DrakesTelemarker] Could not read " + path + ", starting fresh: " + ex.Message)); } return new TelemarkerMarksDocument(); } internal static void Save(string path, TelemarkerMarksDocument doc) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if (doc.Worlds == null) { Dictionary dictionary2 = (doc.Worlds = new Dictionary()); } string text = path + ".tmp"; using (FileStream fileStream = File.Create(text)) { DataContractJsonSerializer val = new DataContractJsonSerializer(typeof(TelemarkerMarksDocument)); ((XmlObjectSerializer)val).WriteObject((Stream)fileStream, (object)doc); } if (File.Exists(path)) { File.Delete(path); } File.Move(text, path); } internal void UpsertSlot(string worldKey, int slot1Based, Vector3 position) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) Worlds.TryGetValue(worldKey, out WorldMarkSlots value); if (value == null) { value = new WorldMarkSlots(); Worlds[worldKey] = value; } WorldMarkSlots worldMarkSlots = value; if (worldMarkSlots.Slots == null) { Dictionary dictionary2 = (worldMarkSlots.Slots = new Dictionary()); } string key = slot1Based.ToString(CultureInfo.InvariantCulture); value.Slots[key] = new MarkCoordinates { X = position.x, Y = position.y, Z = position.z }; } internal bool TryGetSlot(string worldKey, int slot1Based, out Vector3 position, out string error) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); error = ""; if (!Worlds.TryGetValue(worldKey, out WorldMarkSlots value) || value?.Slots == null) { error = $"Mark {slot1Based} is empty."; return false; } string key = slot1Based.ToString(CultureInfo.InvariantCulture); if (!value.Slots.TryGetValue(key, out MarkCoordinates value2)) { error = $"Mark {slot1Based} is empty."; return false; } position = new Vector3(value2.X, value2.Y, value2.Z); return true; } internal bool ClearSlot(string worldKey, int slot1Based) { if (!Worlds.TryGetValue(worldKey, out WorldMarkSlots value) || value.Slots == null) { return false; } string key = slot1Based.ToString(CultureInfo.InvariantCulture); return value.Slots.Remove(key); } internal int ClearAllSlotsForWorld(string worldKey) { if (!Worlds.TryGetValue(worldKey, out WorldMarkSlots value) || value.Slots == null || value.Slots.Count == 0) { return 0; } int count = value.Slots.Count; value.Slots.Clear(); Worlds.Remove(worldKey); return count; } } [DataContract] internal sealed class WorldMarkSlots { [DataMember(Name = "slots")] public Dictionary? Slots { get; set; } } [DataContract] internal sealed class MarkCoordinates { [DataMember(Name = "x")] public float X { get; set; } [DataMember(Name = "y")] public float Y { get; set; } [DataMember(Name = "z")] public float Z { get; set; } } internal static class TelemarkerClearDialog { [CompilerGenerated] private static class <>O { public static UnityAction <0>__Close; } [CompilerGenerated] private sealed class d__11 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DrakesTelemarkerPlugin plugin; public bool clearAll; public int slot1Based; private int 5__1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__1 = 0; break; case 1: <>1__state = -1; 5__1++; break; } if (5__1 < 240) { if (TryOpenNow(plugin, clearAll, slot1Based)) { return false; } <>2__current = null; <>1__state = 1; return true; } DrakesTelemarkerPlugin.Notify("Confirmation UI is not ready yet. Try again in a moment."); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const int TryOpenFrames = 240; private static GameObject? _root; private static Text? _questionText; private static Button? _buttonYes; private static Button? _buttonNo; private static bool _inputBlocked; private static bool _pendingAll; private static int _pendingSlot; private static string _lockedWorldKey = ""; internal static void RegisterForGuiRebuild() { GUIManager.OnCustomGUIAvailable += delegate { TearDownPanel(); }; } internal static void RequestConfirmation(DrakesTelemarkerPlugin plugin, bool clearAll, int slot1Based) { if (!TryOpenNow(plugin, clearAll, slot1Based)) { ((MonoBehaviour)plugin).StartCoroutine(CoRetryOpen(plugin, clearAll, slot1Based)); } } [IteratorStateMachine(typeof(d__11))] private static IEnumerator CoRetryOpen(DrakesTelemarkerPlugin plugin, bool clearAll, int slot1Based) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(0) { plugin = plugin, clearAll = clearAll, slot1Based = slot1Based }; } internal static bool TryOpenNow(DrakesTelemarkerPlugin plugin, bool clearAll, int slot1Based) { GUIManager instance = GUIManager.Instance; if (instance == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront)) { return false; } EnsurePanelBuilt(instance); if ((Object)(object)_root == (Object)null || (Object)(object)_questionText == (Object)null || (Object)(object)_buttonYes == (Object)null || (Object)(object)_buttonNo == (Object)null) { return false; } _pendingAll = clearAll; _pendingSlot = slot1Based; _lockedWorldKey = DrakesTelemarkerPlugin.SanitizeWorldKey(DrakesTelemarkerPlugin.GetWorldKey()); _questionText.text = (clearAll ? "Are you sure you want to clear ALL saved marks for this world?" : ("Are you sure you want to clear mark " + slot1Based.ToString(CultureInfo.InvariantCulture) + "?")); WireButtonsOnce(plugin); _root.SetActive(true); if (!_inputBlocked) { GUIManager.BlockInput(true); _inputBlocked = true; } return true; } private static void WireButtonsOnce(DrakesTelemarkerPlugin plugin) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown DrakesTelemarkerPlugin plugin2 = plugin; ((UnityEventBase)_buttonYes.onClick).RemoveAllListeners(); ((UnityEventBase)_buttonNo.onClick).RemoveAllListeners(); ((UnityEvent)_buttonYes.onClick).AddListener((UnityAction)delegate { OnYes(plugin2); }); ButtonClickedEvent onClick = _buttonNo.onClick; object obj = <>O.<0>__Close; if (obj == null) { UnityAction val = Close; <>O.<0>__Close = val; obj = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } private static void OnYes(DrakesTelemarkerPlugin plugin) { string b = DrakesTelemarkerPlugin.SanitizeWorldKey(DrakesTelemarkerPlugin.GetWorldKey()); if (!string.Equals(_lockedWorldKey, b, StringComparison.Ordinal)) { DrakesTelemarkerPlugin.Notify("World changed before confirmation — nothing was cleared. Run telemark clear … again."); Close(); return; } string error2; if (_pendingAll) { if (!plugin.TryClearAllSlots(out int clearedCount, out string error)) { DrakesTelemarkerPlugin.Notify(string.IsNullOrEmpty(error) ? "Nothing to clear." : error); } else { DrakesTelemarkerPlugin.Notify($"Cleared all {clearedCount} marks for this world."); } } else if (!plugin.TryClearSlot(_pendingSlot, out error2)) { DrakesTelemarkerPlugin.Notify(string.IsNullOrEmpty(error2) ? ("Mark " + _pendingSlot.ToString(CultureInfo.InvariantCulture) + " was already empty.") : error2); } else { DrakesTelemarkerPlugin.Notify("Cleared mark " + _pendingSlot.ToString(CultureInfo.InvariantCulture) + "."); } Close(); } private static void Close() { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } if (_inputBlocked) { GUIManager.BlockInput(false); _inputBlocked = false; } } private static void TearDownPanel() { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); _root = null; } _questionText = null; _buttonYes = null; _buttonNo = null; if (_inputBlocked) { try { GUIManager.BlockInput(false); } catch { } _inputBlocked = false; } } private static void EnsurePanelBuilt(GUIManager gui) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root != (Object)null)) { Transform transform = GUIManager.CustomGUIFront.transform; _root = gui.CreateWoodpanel(transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 380f, 200f, false); gui.CreateText("DrakesTelemarker", _root.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -36f), gui.AveriaSerifBold, 18, gui.ValheimOrange, true, Color.black, 340f, 28f, false); GameObject val = gui.CreateText("", _root.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 12f), gui.AveriaSerifBold, 15, Color.white, true, Color.black, 340f, 70f, false); _questionText = val.GetComponent(); _questionText.alignment = (TextAnchor)4; _questionText.horizontalOverflow = (HorizontalWrapMode)0; _buttonYes = gui.CreateButton("Yes", _root.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(-70f, 36f), 110f, 32f).GetComponent