Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PortalSkidmarks v0.4.0
PortalSkidmarks.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Adam Robichaud")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 Adam Robichaud")] [assembly: AssemblyDescription("Draws portal connections on the Valheim map.")] [assembly: AssemblyFileVersion("0.4.0.0")] [assembly: AssemblyInformationalVersion("0.4.0+a6a38e1a59525528c76e63c9d5e4802b788831c3")] [assembly: AssemblyProduct("PortalSkidmarks")] [assembly: AssemblyTitle("PortalSkidmarks")] [assembly: AssemblyVersion("0.4.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PortalSkidmarks { internal static class MapTooltip { private const float OffsetX = 18f; private const float OffsetY = 18f; private static RectTransform _root; private static TextMeshProUGUI _text; private static string _shown; internal static void Reset() { _root = null; _text = null; _shown = null; } internal static void Show(Minimap map, string label, Vector2 screenPoint) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(label)) { Hide(); return; } RectTransform val = (RectTransform)(((Object)(object)map.m_largeRoot != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null || ((Object)(object)_root == (Object)null && !Create(map, val))) { return; } if (!((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(true); } ((Transform)_root).SetAsLastSibling(); if (_shown != label) { _shown = label; ((TMP_Text)_text).text = label; LayoutRebuilder.ForceRebuildLayoutImmediate(_root); } Vector2 val2 = default(Vector2); if (RectTransformUtility.ScreenPointToLocalPointInRectangle(val, screenPoint, (Camera)null, ref val2)) { Rect rect = _root.rect; Vector2 size = ((Rect)(ref rect)).size; Rect rect2 = val.rect; float num = val2.x + 18f; float num2 = val2.y - 18f; if (num + size.x > ((Rect)(ref rect2)).xMax) { num = val2.x - 18f - size.x; } if (num2 - size.y < ((Rect)(ref rect2)).yMin) { num2 = val2.y + 18f + size.y; } ((Transform)_root).localPosition = new Vector3(num, num2, 0f); } } internal static void Hide() { if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(false); } } private static bool Create(Minimap map, RectTransform parent) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("PortalSkidmarks_Tooltip", new Type[5] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(HorizontalLayoutGroup), typeof(ContentSizeFitter) }); _root = val.GetComponent<RectTransform>(); ((Transform)_root).SetParent((Transform)(object)parent, false); RectTransform root = _root; RectTransform root2 = _root; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.5f); root2.anchorMax = val2; root.anchorMin = val2; _root.pivot = new Vector2(0f, 1f); ((Transform)_root).localScale = Vector3.one; Image component = val.GetComponent<Image>(); ((Graphic)component).color = new Color(0f, 0f, 0f, 0.8f); ((Graphic)component).raycastTarget = false; HorizontalLayoutGroup component2 = val.GetComponent<HorizontalLayoutGroup>(); ((LayoutGroup)component2).padding = new RectOffset(10, 10, 5, 5); ((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false; ContentSizeFitter component3 = val.GetComponent<ContentSizeFitter>(); component3.horizontalFit = (FitMode)2; component3.verticalFit = (FitMode)2; GameObject val3 = new GameObject("Text", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI) }); ((Transform)val3.GetComponent<RectTransform>()).SetParent((Transform)(object)_root, false); _text = val3.GetComponent<TextMeshProUGUI>(); TMP_Text val4 = map.m_biomeNameLarge; if ((Object)(object)val4 == (Object)null || (Object)(object)val4.font == (Object)null) { val4 = Object.FindFirstObjectByType<TMP_Text>(); } if ((Object)(object)val4 != (Object)null && (Object)(object)val4.font != (Object)null) { ((TMP_Text)_text).font = val4.font; ((TMP_Text)_text).fontSharedMaterial = val4.fontSharedMaterial; } ((TMP_Text)_text).fontSize = 20f; ((Graphic)_text).color = Color.white; ((TMP_Text)_text).alignment = (TextAlignmentOptions)513; ((TMP_Text)_text).richText = false; ((Graphic)_text).raycastTarget = false; _shown = null; val.SetActive(false); return true; } } public static class OverlayToggle { [HarmonyPatch(typeof(Terminal), "InitTerminal")] private static class Terminal_InitTerminal_Patch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void <Postfix>b__0_0(ConsoleEventArgs args) { bool flag; switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "") { case "1": case "show": case "true": case "on": flag = true; break; case "0": case "hide": case "off": case "false": flag = false; break; case "": flag = !Visible; break; default: { Terminal context = args.Context; if (context != null) { context.AddString("Usage: portals [on|off]"); } return; } } Set(flag, announce: false); Terminal context2 = args.Context; if (context2 != null) { context2.AddString(flag ? "Portal overlay: on" : "Portal overlay: off"); } } } private static void Postfix() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { bool flag; switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "") { case "1": case "show": case "true": case "on": flag = true; break; case "0": case "hide": case "off": case "false": flag = false; break; case "": flag = !Visible; break; default: { Terminal context = args.Context; if (context != null) { context.AddString("Usage: portals [on|off]"); } return; } } Set(flag, announce: false); Terminal context2 = args.Context; if (context2 != null) { context2.AddString(flag ? "Portal overlay: on" : "Portal overlay: off"); } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("portals", "[on|off] Show or hide the PortalSkidmarks portal overlay on the map", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } private const string ToggleName = "PortalSkidmarks_Toggle"; private static Toggle _mapToggle; private static RectTransform _mapRow; private static RectTransform _publicRow; private static RectTransform _sharedRow; private static readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4]; public static bool Visible => Plugin.ShowOverlay.Value; public static void Set(bool visible, bool announce) { if (Plugin.ShowOverlay.Value != visible) { Plugin.ShowOverlay.Value = visible; } if (announce && (Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)1, visible ? "Portal overlay: on" : "Portal overlay: off", 0, (Sprite)null, false); } } internal static void Tick(Minimap map) { HandleHotkey(); SyncMapToggle(map); } internal static void OnMinimapDestroyed() { _mapToggle = null; _mapRow = null; _publicRow = null; _sharedRow = null; } private static void HandleHotkey() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) KeyboardShortcut value = Plugin.ToggleKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false)) { return; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!ZInput.GetKey(modifier, false)) { return; } } if (!IsTyping()) { Set(!Visible, announce: true); } } private static bool IsTyping() { if (Minimap.InTextInput()) { return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if (Menu.IsVisible()) { return true; } return false; } private static void SyncMapToggle(Minimap map) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 if (!((Object)(object)map == (Object)null) && !((Object)(object)map.m_publicPosition == (Object)null) && (!((Object)(object)_mapToggle == (Object)null) || (Plugin.ShowMapToggle.Value && CreateMapRow(map)))) { bool value = Plugin.ShowMapToggle.Value; if (((Component)_mapRow).gameObject.activeSelf != value) { ((Component)_mapRow).gameObject.SetActive(value); } if (_mapToggle.isOn != Visible) { _mapToggle.SetIsOnWithoutNotify(Visible); } if (value && (int)map.m_mode == 2) { PositionMapRow(); } } } private static bool CreateMapRow(Minimap map) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown try { Transform stopAt = (((Object)(object)map.m_largeRoot != (Object)null) ? map.m_largeRoot.transform : null); _publicRow = RowOf((RectTransform)((Component)map.m_publicPosition).transform, stopAt); _sharedRow = null; if ((Object)(object)map.m_sharedMapHint != (Object)null) { Transform transform = map.m_sharedMapHint.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val != null) { RectTransform val2 = RowOf(val, stopAt); if ((Object)(object)val2 != (Object)(object)_publicRow && !((Transform)val2).IsChildOf((Transform)(object)_publicRow) && !((Transform)_publicRow).IsChildOf((Transform)(object)val2)) { _sharedRow = val2; } } } GameObject val3 = Object.Instantiate<GameObject>(((Component)_publicRow).gameObject, ((Transform)_publicRow).parent); ((Object)val3).name = "PortalSkidmarks_Toggle"; UIGamePad[] componentsInChildren = val3.GetComponentsInChildren<UIGamePad>(true); foreach (UIGamePad val4 in componentsInChildren) { if ((Object)(object)val4.m_hint != (Object)null) { Object.DestroyImmediate((Object)(object)val4.m_hint); } Object.DestroyImmediate((Object)(object)val4); } MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val5 in componentsInChildren2) { if ((Object)(object)val5 != (Object)null && ((object)val5).GetType().Name.Contains("Locali")) { Object.DestroyImmediate((Object)(object)val5); } } Toggle componentInChildren = val3.GetComponentInChildren<Toggle>(true); if ((Object)(object)componentInChildren == (Object)null) { throw new InvalidOperationException("copied row has no Toggle"); } componentInChildren.onValueChanged = new ToggleEvent(); componentInChildren.group = null; componentInChildren.SetIsOnWithoutNotify(Visible); ((UnityEvent<bool>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v) { Set(v, announce: false); }); SetLabel(val3, "Portals"); _mapRow = (RectTransform)val3.transform; _mapToggle = componentInChildren; if ((Object)(object)((Component)((Transform)_mapRow).parent).GetComponent<LayoutGroup>() != (Object)null) { int num = ((Transform)_publicRow).GetSiblingIndex(); if ((Object)(object)_sharedRow != (Object)null && (Object)(object)((Transform)_sharedRow).parent == (Object)(object)((Transform)_publicRow).parent) { num = Mathf.Min(num, ((Transform)_sharedRow).GetSiblingIndex()); } ((Transform)_mapRow).SetSiblingIndex(num); } val3.SetActive(Plugin.ShowMapToggle.Value); Plugin.Log.LogInfo((object)("Added 'Portals' row to the large map (copied '" + PathOf((Transform)(object)_publicRow) + "', cartography row '" + PathOf((Transform)(object)_sharedRow) + "')")); return true; } catch (Exception arg) { Plugin.Log.LogWarning((object)$"Could not add the map checkbox, use the hotkey or 'portals' command instead: {arg}"); _mapToggle = null; _mapRow = null; Plugin.ShowMapToggle.Value = false; return false; } } private static RectTransform RowOf(RectTransform start, Transform stopAt) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) Rect rect = start.rect; float height = ((Rect)(ref rect)).height; float num = Mathf.Max(height * 1.75f, height + 20f); RectTransform result = start; Transform parent = ((Transform)start).parent; while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)stopAt) { RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val == (Object)null) { break; } rect = val.rect; if (((Rect)(ref rect)).height > num) { break; } result = val; parent = parent.parent; } return result; } private static void PositionMapRow() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_mapRow == (Object)null) && !((Object)(object)_publicRow == (Object)null) && (!((Object)(object)((Transform)_mapRow).parent != (Object)null) || !((Object)(object)((Component)((Transform)_mapRow).parent).GetComponent<LayoutGroup>() != (Object)null))) { Rect pub = WorldRect(_publicRow); float num = ((Rect)(ref pub)).yMax; if ((Object)(object)_sharedRow != (Object)null && IsShown(_sharedRow)) { float num2 = num; Rect val = WorldRect(_sharedRow); num = Mathf.Max(num2, ((Rect)(ref val)).yMax); } Vector2 value = Plugin.MapToggleOffset.Value; Vector3 lossyScale = ((Transform)_mapRow).lossyScale; Rect val2 = WorldRect(_mapRow); float num3 = num + RowGap(pub) + value.y * lossyScale.y - ((Rect)(ref val2)).yMin; float num4 = ((Rect)(ref pub)).center.x + value.x * lossyScale.x - ((Rect)(ref val2)).center.x; if (Mathf.Abs(num4) > 0.01f || Mathf.Abs(num3) > 0.01f) { RectTransform mapRow = _mapRow; ((Transform)mapRow).position = ((Transform)mapRow).position + new Vector3(num4, num3, 0f); } } } private static float RowGap(Rect pub) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_sharedRow != (Object)null) { Rect val = WorldRect(_sharedRow); float num = ((((Rect)(ref val)).yMin >= ((Rect)(ref pub)).yMax) ? (((Rect)(ref val)).yMin - ((Rect)(ref pub)).yMax) : (((Rect)(ref pub)).yMin - ((Rect)(ref val)).yMax)); if (num >= 0f && num < ((Rect)(ref pub)).height) { return num; } } return ((Rect)(ref pub)).height * 0.2f; } private static bool IsShown(RectTransform row) { Transform val = (Transform)(object)row; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)((Transform)_publicRow).parent) { if (!((Component)val).gameObject.activeSelf) { return false; } val = val.parent; } return true; } private static Rect WorldRect(RectTransform rt) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) rt.GetWorldCorners(_corners); return Rect.MinMaxRect(_corners[0].x, _corners[0].y, _corners[2].x, _corners[2].y); } private static string PathOf(Transform t) { if ((Object)(object)t == (Object)null) { return "none"; } string text = ((Object)t).name; Transform parent = t.parent; while ((Object)(object)parent != (Object)null && (Object)(object)parent.parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private static void SetLabel(GameObject go, string text) { TMP_Text componentInChildren = go.GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.text = text; return; } Text componentInChildren2 = go.GetComponentInChildren<Text>(true); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.text = text; } } } [BepInPlugin("com.puhpuhburr.portalskidmarks", "PortalSkidmarks", "0.4.0")] public class Plugin : BaseUnityPlugin { public enum ColorMode { PerTag, Single } public const string GUID = "com.puhpuhburr.portalskidmarks"; public const string NAME = "PortalSkidmarks"; public const string VERSION = "0.4.0"; internal static ManualLogSource Log; internal static Plugin Instance; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> BroadcastInterval; internal static ConfigEntry<float> LineThickness; internal static ConfigEntry<float> IdleOpacity; internal static ConfigEntry<float> HoverOpacity; internal static ConfigEntry<bool> ShowTooltip; internal static ConfigEntry<ColorMode> LineColorMode; internal static ConfigEntry<Color> SingleLineColor; internal static ConfigEntry<bool> ShowPortalPins; internal static ConfigEntry<bool> ShowUnconnectedPins; internal static ConfigEntry<bool> MarkUnconnected; internal static ConfigEntry<bool> ShowOnMinimap; internal static ConfigEntry<bool> ShowOverlay; internal static ConfigEntry<KeyboardShortcut> ToggleKey; internal static ConfigEntry<bool> ShowMapToggle; internal static ConfigEntry<Vector2> MapToggleOffset; private Harmony _harmony; private void Awake() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Master switch. When off, nothing is drawn and the server sends nothing."); BroadcastInterval = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "BroadcastInterval", 5f, new ConfigDescription("Server only. Seconds between checks for portal changes to broadcast to clients.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); LineThickness = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "LineThickness", 3f, new ConfigDescription("Thickness of connection lines on the large map, in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 12f), Array.Empty<object>())); IdleOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "IdleOpacity", 0.2f, new ConfigDescription("Opacity of portal markers and connection lines when the mouse is not over them.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); HoverOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Display", "HoverOpacity", 1f, new ConfigDescription("Opacity of a portal pair (both markers and their line) while the mouse is over any part of it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>())); ShowTooltip = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowTooltip", true, "Show the portal name next to the mouse while hovering a portal marker or connection line on the large map."); LineColorMode = ((BaseUnityPlugin)this).Config.Bind<ColorMode>("2 - Display", "LineColorMode", ColorMode.PerTag, "PerTag gives every portal tag its own colour so linked pairs are easy to tell apart. Single uses SingleLineColor for everything."); SingleLineColor = ((BaseUnityPlugin)this).Config.Bind<Color>("2 - Display", "SingleLineColor", new Color(0.35f, 0.85f, 1f), "Line colour used when LineColorMode is Single."); ShowPortalPins = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowPortalPins", true, "Add a portal pin (with its tag as the name) for every known portal."); ShowUnconnectedPins = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowUnconnectedPins", true, "Also add pins for portals that currently have no partner."); MarkUnconnected = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "MarkUnconnected", true, "Append ' (no link)' to the pin name of unconnected portals."); ShowOnMinimap = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Display", "ShowOnMinimap", false, "Also draw connection lines on the small corner minimap."); ShowOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Toggle", "ShowOverlay", true, "Whether the portal overlay is shown. The hotkey, the map checkbox and the 'portals' console command all flip this, and the last state is remembered between sessions."); ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Toggle", "ToggleKey", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Hotkey that toggles the overlay. Works anywhere in game except while typing in chat, the console or a text box. Set to None to disable."); ShowMapToggle = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Toggle", "ShowMapToggle", true, "Add a 'Portals' row to the large map, above the 'Cartography Table' row if shown, otherwise above 'Visible to other players'."); MapToggleOffset = ((BaseUnityPlugin)this).Config.Bind<Vector2>("3 - Toggle", "MapToggleOffset", Vector2.zero, "Extra offset in UI pixels for the map 'Portals' row, if it overlaps something in your UI layout."); _harmony = new Harmony("com.puhpuhburr.portalskidmarks"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"PortalSkidmarks 0.4.0 loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public struct PortalInfo { public ZDOID Id; public Vector3 Position; public string Tag; public ZDOID Target; public bool IsConnected => !((ZDOID)(ref Target)).IsNone(); } public sealed class PortalSnapshot { public const int FormatVersion = 1; public readonly List<PortalInfo> Portals = new List<PortalInfo>(); public int Fingerprint { get; private set; } public static PortalSnapshot FromWorld() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) PortalSnapshot portalSnapshot = new PortalSnapshot(); if (ZDOMan.instance == null) { return portalSnapshot; } foreach (ZDO portal in ZDOMan.instance.GetPortalList()) { if (portal != null) { portalSnapshot.Portals.Add(new PortalInfo { Id = portal.m_uid, Position = portal.GetPosition(), Tag = (portal.GetString(ZDOVars.s_tag, "") ?? string.Empty), Target = portal.GetConnectionZDOID((ConnectionType)1) }); } } portalSnapshot.SortAndFingerprint(); return portalSnapshot; } public void Write(ZPackage pkg) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) pkg.Write(1); pkg.Write(Portals.Count); foreach (PortalInfo portal in Portals) { pkg.Write(portal.Id); pkg.Write(portal.Position); pkg.Write(portal.Tag ?? string.Empty); pkg.Write(portal.Target); } } public static PortalSnapshot Read(ZPackage pkg) { //IL_005d: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) PortalSnapshot portalSnapshot = new PortalSnapshot(); int num = pkg.ReadInt(); if (num != 1) { Plugin.Log.LogWarning((object)$"Received portal snapshot with format {num}, expected {1}. Ignoring."); return null; } int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 200000) { return null; } for (int i = 0; i < num2; i++) { portalSnapshot.Portals.Add(new PortalInfo { Id = pkg.ReadZDOID(), Position = pkg.ReadVector3(), Tag = pkg.ReadString(), Target = pkg.ReadZDOID() }); } portalSnapshot.SortAndFingerprint(); return portalSnapshot; } private unsafe void SortAndFingerprint() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) Portals.Sort(delegate(PortalInfo a, PortalInfo b) { int num4 = ((ZDOID)(ref a.Id)).UserID.CompareTo(((ZDOID)(ref b.Id)).UserID); return (num4 == 0) ? ((ZDOID)(ref a.Id)).ID.CompareTo(((ZDOID)(ref b.Id)).ID) : num4; }); int num = 17; foreach (PortalInfo portal in Portals) { int num2 = num * 31; ZDOID id = portal.Id; num = num2 + ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).GetHashCode(); int num3 = num * 31; id = portal.Target; num = num3 + ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).GetHashCode(); num = num * 31 + (portal.Tag?.GetHashCode() ?? 0); num = num * 31 + Mathf.RoundToInt(portal.Position.x); num = num * 31 + Mathf.RoundToInt(portal.Position.z); } Fingerprint = num; } } public static class PortalMapRenderer { private struct DrawnLine { public Image Img; public Vector2 A; public Vector2 B; public long Key; public ZDOID IdA; public ZDOID IdB; public string Label; public string Tag; } private struct PortalPin { public PinData Pin; public ZDOID Id; } [HarmonyPatch(typeof(Minimap), "Update")] private static class Minimap_Update_Patch { private static void Postfix(Minimap __instance) { try { OnMinimapUpdate(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"PortalSkidmarks render error: {arg}"); } } } [HarmonyPatch(typeof(Minimap), "OnDestroy")] private static class Minimap_OnDestroy_Patch { private static void Prefix() { _lineRootLarge = null; _lineRootSmall = null; _poolLarge.Clear(); _poolSmall.Clear(); _linesLarge.Clear(); _linesSmall.Clear(); _pins.Clear(); _renderedPinRevision = -1; _fallback = null; ClearHover(); MapTooltip.Reset(); OverlayToggle.OnMinimapDestroyed(); } } private const string LineRootName = "PortalSkidmarks_Lines"; private static int _renderedPinRevision = -1; private static float _lastFallbackScan; private static PortalSnapshot _fallback; private static RectTransform _lineRootLarge; private static RectTransform _lineRootSmall; private static readonly List<Image> _poolLarge = new List<Image>(); private static readonly List<Image> _poolSmall = new List<Image>(); private static readonly List<DrawnLine> _linesLarge = new List<DrawnLine>(); private static readonly List<DrawnLine> _linesSmall = new List<DrawnLine>(); private static readonly List<PortalPin> _pins = new List<PortalPin>(); private static readonly HashSet<long> _drawnPairs = new HashSet<long>(); private static readonly Dictionary<ZDOID, PortalInfo> _byId = new Dictionary<ZDOID, PortalInfo>(); private static readonly HashSet<ZDOID> _hoverIds = new HashSet<ZDOID>(); private static long _hoverKey; private static bool _hoverHasLine; private static void OnMinimapUpdate(Minimap map) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Invalid comparison between Unknown and I4 //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)map == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null)) { OverlayToggle.Tick(map); bool flag = Plugin.Enabled.Value && OverlayToggle.Visible; PortalSnapshot portalSnapshot = (flag ? GetSnapshot() : null); SyncPins(map, portalSnapshot, flag); bool flag2 = flag && portalSnapshot != null && (int)map.m_mode == 2; bool draw = flag && portalSnapshot != null && (int)map.m_mode == 1 && Plugin.ShowOnMinimap.Value; if (portalSnapshot != null) { IndexPortals(portalSnapshot); } LayoutLines(map, portalSnapshot, map.m_mapImageLarge, map.m_pinRootLarge, ref _lineRootLarge, _poolLarge, _linesLarge, flag2); LayoutLines(map, portalSnapshot, map.m_mapImageSmall, map.m_pinRootSmall, ref _lineRootSmall, _poolSmall, _linesSmall, draw); ClearHover(); string text = null; Vector2 screen = Vector2.zero; if (flag2 && TryGetPointer(map, out screen)) { text = FindHover(map, portalSnapshot, screen); } ColorLines(_linesLarge); ColorLines(_linesSmall); ColorPins(); if (flag2 && Plugin.ShowTooltip.Value && text != null) { MapTooltip.Show(map, text, screen); } else { MapTooltip.Hide(); } } } private static PortalSnapshot GetSnapshot() { if (PortalSync.Current != null) { return PortalSync.Current; } if (Time.time - _lastFallbackScan > 2f) { _lastFallbackScan = Time.time; PortalSnapshot portalSnapshot = PortalSync.LocalFallback(); if (_fallback == null || portalSnapshot.Fingerprint != _fallback.Fingerprint) { _fallback = portalSnapshot; _renderedPinRevision = -1; } } return _fallback; } private static void IndexPortals(PortalSnapshot snap) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) _byId.Clear(); foreach (PortalInfo portal in snap.Portals) { _byId[portal.Id] = portal; } } private static string DisplayName(PortalInfo p) { string text = (string.IsNullOrEmpty(p.Tag) ? "(no tag)" : p.Tag); if (!p.IsConnected && Plugin.MarkUnconnected.Value) { text += " (no link)"; } return text; } private static bool ShowsPin(PortalInfo p) { if (Plugin.ShowPortalPins.Value) { if (!p.IsConnected) { return Plugin.ShowUnconnectedPins.Value; } return true; } return false; } private static void SyncPins(Minimap map, PortalSnapshot snap, bool enabled) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) bool flag = enabled && snap != null && Plugin.ShowPortalPins.Value; int num = ((!flag) ? (-2) : ((PortalSync.Current != null) ? PortalSync.Revision : snap.Fingerprint)); if (num == _renderedPinRevision && (!flag || PinsStillPresent(map))) { return; } _renderedPinRevision = num; foreach (PortalPin pin in _pins) { map.RemovePin(pin.Pin); } _pins.Clear(); if (!flag) { return; } foreach (PortalInfo portal in snap.Portals) { if (ShowsPin(portal)) { PinData val = map.AddPin(portal.Position, (PinType)6, DisplayName(portal), false, false, 0L, default(PlatformUserID)); if (val != null) { _pins.Add(new PortalPin { Pin = val, Id = portal.Id }); } } } } private static bool PinsStillPresent(Minimap map) { if (_pins.Count == 0) { return true; } return Traverse.Create((object)map).Field<List<PinData>>("m_pins").Value?.Contains(_pins[0].Pin) ?? true; } private static void ColorPins() { //IL_0034: 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) //IL_0069: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) float value = Plugin.IdleOpacity.Value; float value2 = Plugin.HoverOpacity.Value; foreach (PortalPin pin2 in _pins) { float num = (_hoverIds.Contains(pin2.Id) ? value2 : value); PinData pin = pin2.Pin; if ((Object)(object)pin.m_iconElement != (Object)null) { Color color = ((Graphic)pin.m_iconElement).color; if (!Mathf.Approximately(color.a, num)) { color.a = num; ((Graphic)pin.m_iconElement).color = color; } } if (pin.m_NamePinData != null && (Object)(object)pin.m_NamePinData.PinNameText != (Object)null) { Color color2 = ((Graphic)pin.m_NamePinData.PinNameText).color; if (!Mathf.Approximately(color2.a, num)) { color2.a = num; ((Graphic)pin.m_NamePinData.PinNameText).color = color2; } } } } private static void LayoutLines(Minimap map, PortalSnapshot snap, RawImage mapImage, RectTransform pinRoot, ref RectTransform lineRoot, List<Image> pool, List<DrawnLine> drawn, bool draw) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) drawn.Clear(); if ((Object)(object)mapImage == (Object)null || (Object)(object)pinRoot == (Object)null) { return; } if ((Object)(object)lineRoot == (Object)null) { lineRoot = CreateLineRoot(pinRoot); pool.Clear(); } if (!draw) { if (((Component)lineRoot).gameObject.activeSelf) { ((Component)lineRoot).gameObject.SetActive(false); } return; } if (!((Component)lineRoot).gameObject.activeSelf) { ((Component)lineRoot).gameObject.SetActive(true); } Rect uvRect = mapImage.uvRect; Rect rect = ((Graphic)mapImage).rectTransform.rect; float value = Plugin.LineThickness.Value; _drawnPairs.Clear(); int num = 0; foreach (PortalInfo portal in snap.Portals) { if (!portal.IsConnected || !_byId.TryGetValue(portal.Target, out var value2)) { continue; } long num2 = PairKey(portal.Id, value2.Id); if (_drawnPairs.Add(num2)) { Vector2 p = WorldToGui(map, portal.Position, uvRect, rect); Vector2 p2 = WorldToGui(map, value2.Position, uvRect, rect); if (ClipToRect(ref p, ref p2, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height)) { Image line = GetLine(lineRoot, pool, num++); Vector2 val = p2 - p; RectTransform rectTransform = ((Graphic)line).rectTransform; rectTransform.anchoredPosition = p; rectTransform.sizeDelta = new Vector2(((Vector2)(ref val)).magnitude, value); ((Transform)rectTransform).localRotation = Quaternion.Euler(0f, 0f, Mathf.Atan2(val.y, val.x) * 57.29578f); drawn.Add(new DrawnLine { Img = line, A = p, B = p2, Key = num2, IdA = portal.Id, IdB = value2.Id, Label = DisplayName(portal), Tag = portal.Tag }); } } } for (int i = num; i < pool.Count; i++) { if ((Object)(object)pool[i] != (Object)null && ((Component)pool[i]).gameObject.activeSelf) { ((Component)pool[i]).gameObject.SetActive(false); } } } private static void ColorLines(List<DrawnLine> drawn) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: 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) float value = Plugin.IdleOpacity.Value; float value2 = Plugin.HoverOpacity.Value; foreach (DrawnLine item in drawn) { bool flag = _hoverHasLine && item.Key == _hoverKey; Color color = LineColor(item.Tag); color.a = (flag ? value2 : value); ((Graphic)item.Img).color = color; if (flag) { ((Transform)((Graphic)item.Img).rectTransform).SetAsLastSibling(); } } } private static RectTransform CreateLineRoot(RectTransform pinRoot) { //IL_0018: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) RectTransform component = new GameObject("PortalSkidmarks_Lines", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)pinRoot, false); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.pivot = Vector2.zero; component.anchoredPosition = Vector2.zero; component.sizeDelta = Vector2.zero; ((Transform)component).localScale = Vector3.one; ((Transform)component).SetAsFirstSibling(); return component; } private static Image GetLine(RectTransform root, List<Image> pool, int index) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) while (pool.Count <= index) { GameObject val = new GameObject("line", new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)root, false); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.zero; component.pivot = new Vector2(0f, 0.5f); ((Transform)component).localScale = Vector3.one; Image component2 = val.GetComponent<Image>(); ((Graphic)component2).raycastTarget = false; component2.sprite = null; pool.Add(component2); } Image val2 = pool[index]; if (!((Component)val2).gameObject.activeSelf) { ((Component)val2).gameObject.SetActive(true); } return val2; } private static void ClearHover() { _hoverIds.Clear(); _hoverKey = 0L; _hoverHasLine = false; } private static bool TryGetPointer(Minimap map, out Vector2 screen) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)map.m_gamepadCrosshair != (Object)null && ((Component)map.m_gamepadCrosshair).gameObject.activeInHierarchy) { screen = RectTransformUtility.WorldToScreenPoint((Camera)null, ((Transform)map.m_gamepadCrosshair).position); } else { screen = Vector2.op_Implicit(ZInput.pointerPosition); } RectTransform rectTransform = ((Graphic)map.m_mapImageLarge).rectTransform; Vector2 val = default(Vector2); if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screen, (Camera)null, ref val)) { return false; } Rect rect = rectTransform.rect; return ((Rect)(ref rect)).Contains(val); } private static string FindHover(Minimap map, PortalSnapshot snap, Vector2 screen) { //IL_0014: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_010e: 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_01d1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_lineRootLarge == (Object)null) { return null; } Vector2 val = default(Vector2); if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_lineRootLarge, screen, (Camera)null, ref val)) { return null; } Rect uvRect = map.m_mapImageLarge.uvRect; Rect rect = ((Graphic)map.m_mapImageLarge).rectTransform.rect; float num = map.m_pinSizeLarge * 0.5f; float num2 = num * num; bool flag = false; PortalInfo p = default(PortalInfo); foreach (PortalInfo portal in snap.Portals) { if (ShowsPin(portal)) { Vector2 val2 = WorldToGui(map, portal.Position, uvRect, rect) - val; float sqrMagnitude = ((Vector2)(ref val2)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; p = portal; flag = true; } } } if (flag) { _hoverIds.Add(p.Id); if (p.IsConnected && _byId.ContainsKey(p.Target)) { _hoverIds.Add(p.Target); _hoverKey = PairKey(p.Id, p.Target); _hoverHasLine = true; } return DisplayName(p); } float num3 = Mathf.Max(Plugin.LineThickness.Value * 0.5f + 4f, 6f); float num4 = num3 * num3; int num5 = -1; for (int i = 0; i < _linesLarge.Count; i++) { float num6 = SqrDistanceToSegment(val, _linesLarge[i].A, _linesLarge[i].B); if (num6 < num4) { num4 = num6; num5 = i; } } if (num5 < 0) { return null; } DrawnLine drawnLine = _linesLarge[num5]; _hoverIds.Add(drawnLine.IdA); _hoverIds.Add(drawnLine.IdB); _hoverKey = drawnLine.Key; _hoverHasLine = true; return drawnLine.Label; } private static float SqrDistanceToSegment(Vector2 p, Vector2 a, Vector2 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) Vector2 val = b - a; float sqrMagnitude = ((Vector2)(ref val)).sqrMagnitude; Vector2 val2; if (sqrMagnitude < 1E-06f) { val2 = p - a; return ((Vector2)(ref val2)).sqrMagnitude; } float num = Mathf.Clamp01(Vector2.Dot(p - a, val) / sqrMagnitude); val2 = p - (a + val * num); return ((Vector2)(ref val2)).sqrMagnitude; } private static Vector2 WorldToGui(Minimap map, Vector3 world, Rect uv, Rect rect) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) float num = (float)map.m_textureSize / 2f; float num2 = (world.x / map.m_pixelSize + num) / (float)map.m_textureSize; float num3 = (world.z / map.m_pixelSize + num) / (float)map.m_textureSize; return new Vector2((num2 - ((Rect)(ref uv)).xMin) / ((Rect)(ref uv)).width * ((Rect)(ref rect)).width, (num3 - ((Rect)(ref uv)).yMin) / ((Rect)(ref uv)).height * ((Rect)(ref rect)).height); } private static bool ClipToRect(ref Vector2 p0, ref Vector2 p1, float w, float h) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) float t = 0f; float t2 = 1f; float num = p1.x - p0.x; float num2 = p1.y - p0.y; if (!ClipEdge(0f - num, p0.x, ref t, ref t2)) { return false; } if (!ClipEdge(num, w - p0.x, ref t, ref t2)) { return false; } if (!ClipEdge(0f - num2, p0.y, ref t, ref t2)) { return false; } if (!ClipEdge(num2, h - p0.y, ref t, ref t2)) { return false; } Vector2 val = p0 + new Vector2(num, num2) * t; Vector2 val2 = p0 + new Vector2(num, num2) * t2; p0 = val; p1 = val2; return true; } private static bool ClipEdge(float p, float q, ref float t0, ref float t1) { if (Mathf.Approximately(p, 0f)) { return q >= 0f; } float num = q / p; if (p < 0f) { if (num > t1) { return false; } if (num > t0) { t0 = num; } } else { if (num < t0) { return false; } if (num < t1) { t1 = num; } } return true; } private unsafe static long PairKey(ZDOID a, ZDOID b) { int num = ((object)(*(ZDOID*)(&a))/*cast due to .constrained prefix*/).GetHashCode(); int num2 = ((object)(*(ZDOID*)(&b))/*cast due to .constrained prefix*/).GetHashCode(); if (num > num2) { int num3 = num; num = num2; num2 = num3; } return ((long)num << 32) ^ (uint)num2; } private static Color LineColor(string tag) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (Plugin.LineColorMode.Value == Plugin.ColorMode.Single) { return Plugin.SingleLineColor.Value; } return Color.HSVToRGB((float)((double)((!string.IsNullOrEmpty(tag)) ? ((uint)StringExtensionMethods.GetStableHashCode(tag)) : 0u) * 0.6180339887498949 % 1.0), 0.75f, 1f); } } public static class PortalSync { [HarmonyPatch(typeof(Game), "Start")] private static class Game_Start_Patch { private static void Postfix() { Register(); } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] private static class ZNet_OnDestroy_Patch { private static void Postfix() { Reset(); } } [HarmonyPatch(typeof(Game), "ConnectPortals")] private static class Game_ConnectPortals_Patch { private static void Postfix() { ServerTick(); } } private const string RpcPortals = "PortalSkidmarks_Portals"; private const string RpcRequest = "PortalSkidmarks_RequestPortals"; private static int _lastBroadcastFingerprint; private static float _lastBroadcastTime; private static bool _registered; private static readonly HashSet<long> _peersUpToDate = new HashSet<long>(); public static PortalSnapshot Current { get; private set; } public static int Revision { get; private set; } public static bool ServerHasMod { get; private set; } internal static void Reset() { Current = null; Revision++; ServerHasMod = false; _lastBroadcastFingerprint = 0; _lastBroadcastTime = 0f; _registered = false; _peersUpToDate.Clear(); } private static void Register() { if (!_registered && ZRoutedRpc.instance != null) { _registered = true; _peersUpToDate.Clear(); ZRoutedRpc.instance.Register<ZPackage>("PortalSkidmarks_Portals", (Action<long, ZPackage>)RPC_Portals); ZRoutedRpc.instance.Register("PortalSkidmarks_RequestPortals", (Action<long>)RPC_RequestPortals); if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { ZRoutedRpc.instance.InvokeRoutedRPC("PortalSkidmarks_RequestPortals", Array.Empty<object>()); Plugin.Log.LogInfo((object)"Requested portal list from server"); } } } private static void ServerTick() { if (!Plugin.Enabled.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZRoutedRpc.instance == null || (_lastBroadcastFingerprint != 0 && Time.time - _lastBroadcastTime < Plugin.BroadcastInterval.Value)) { return; } PortalSnapshot portalSnapshot = PortalSnapshot.FromWorld(); bool flag = portalSnapshot.Fingerprint != _lastBroadcastFingerprint; bool flag2 = false; foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.IsReady() && !_peersUpToDate.Contains(peer.m_uid)) { flag2 = true; break; } } if (!flag && !flag2) { return; } Broadcast(portalSnapshot, 0L); _lastBroadcastFingerprint = portalSnapshot.Fingerprint; _lastBroadcastTime = Time.time; _peersUpToDate.Clear(); foreach (ZNetPeer peer2 in ZNet.instance.GetPeers()) { if (peer2.IsReady()) { _peersUpToDate.Add(peer2.m_uid); } } if (flag) { Plugin.Log.LogInfo((object)$"Broadcast {portalSnapshot.Portals.Count} portals to clients"); } } private static void Broadcast(PortalSnapshot snap, long target) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); snap.Write(val); ZRoutedRpc.instance.InvokeRoutedRPC(target, "PortalSkidmarks_Portals", new object[1] { val }); } private static void RPC_RequestPortals(long sender) { if (Plugin.Enabled.Value && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { PortalSnapshot portalSnapshot = PortalSnapshot.FromWorld(); Broadcast(portalSnapshot, sender); _peersUpToDate.Add(sender); Plugin.Log.LogInfo((object)$"Sent {portalSnapshot.Portals.Count} portals to peer {sender} on request"); } } private static void RPC_Portals(long sender, ZPackage pkg) { if (pkg == null || (Object)(object)ZNet.instance == (Object)null) { return; } long num = (ZNet.instance.IsServer() ? Traverse.Create((object)ZRoutedRpc.instance).Field<long>("m_id").Value : (ZNet.instance.GetServerPeer()?.m_uid ?? 0)); if (sender != num) { Plugin.Log.LogWarning((object)$"Ignoring portal snapshot from non-server peer {sender}"); return; } PortalSnapshot portalSnapshot = PortalSnapshot.Read(pkg); if (portalSnapshot != null) { ServerHasMod = true; if (Current == null || Current.Fingerprint != portalSnapshot.Fingerprint) { Current = portalSnapshot; Revision++; Plugin.Log.LogInfo((object)$"Portal list updated: {portalSnapshot.Portals.Count} portals"); } } } public static PortalSnapshot LocalFallback() { return PortalSnapshot.FromWorld(); } } }