using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.BoringCompass.Core; using JG224.BoringCompass.UI; using JG224.ModCore.API; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; 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("BoringCompass")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("BoringCompass")] [assembly: AssemblyTitle("BoringCompass")] [assembly: AssemblyVersion("0.5.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 JG224.BoringCompass { internal sealed class BoringCompassConfig { private readonly ConfigFile _file; private readonly List _entries = new List(); internal ConfigEntry Enabled { get; } internal ConfigEntry AutoWidth { get; } internal ConfigEntry ShowWhenHudHidden { get; } internal ConfigEntry ShowDeathMarker { get; } internal ConfigEntry ShowMapMarkers { get; } internal ConfigEntry MarkerDistance { get; } internal ConfigEntry HeadingSource { get; } internal ConfigEntry Scale { get; } internal ConfigEntry OffsetX { get; } internal ConfigEntry OffsetY { get; } internal ConfigEntry Color { get; } internal ConfigEntry Opacity { get; } private BoringCompassConfig(ConfigFile file) { _file = file; Enabled = Bind("Enabled", value: true, "Show the scrolling compass at the top centre of the screen."); AutoWidth = Bind("AutoWidth", value: true, "Fit the compass and its offsets inside the current screen; Scale remains the maximum size."); ShowWhenHudHidden = Bind("ShowWhenHudHidden", value: false, "Keep the compass visible when the HUD is hidden."); ShowDeathMarker = Bind("ShowDeathMarker", value: true, "Show your latest death map pin at any distance. Checked or removed death pins stay hidden."); ShowMapMarkers = Bind("ShowMapMarkers", value: false, "Show nearby unchecked saved map pins, including pins available through map sharing. Excludes other death pins and live player/event pins."); MarkerDistance = BindRange("MarkerDistance", 100f, 1f, 10000f, "Maximum horizontal distance in metres for non-death map markers. Does not limit your latest death marker."); HeadingSource = Bind("HeadingSource", CompassHeadingSource.Camera, "Camera, PlayerFacing, or Movement. Movement falls back to player facing while stationary."); Scale = BindRange("Scale", 1.3f, 0.5f, 2f, "Compass display scale."); OffsetX = BindRange("OffsetX", 0f, -1000f, 1000f, "Horizontal compass offset in screen pixels."); OffsetY = BindRange("OffsetY", 8f, -500f, 500f, "Distance down from the top edge in screen pixels."); Color = Bind("Color", "#F2E6C9", "Compass HTML color, for example #F2E6C9."); Opacity = BindRange("Opacity", 0.95f, 0f, 1f, "Compass opacity."); } internal static BoringCompassConfig Load(BaseUnityPlugin plugin, string configDirectory, ManualLogSource log) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } string text = LegacyCompassConfigRules.FindImportSource(Directory.GetFiles(configDirectory, "*.cfg", SearchOption.TopDirectoryOnly)); string text2 = Path.Combine(configDirectory, "jg224.BoringCompass.cfg"); BoringCompassConfig boringCompassConfig = new BoringCompassConfig(PluginConfigFiles.Attach(plugin, new ConfigFile(text2, true, plugin.Info.Metadata))); if (text != null) { boringCompassConfig.ImportLegacyGeneralTweaks(text, log); } return boringCompassConfig; } internal IEnumerable RegisterMetadata(ICoreServices services, ModuleId owner) { //IL_0016: 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) foreach (ConfigEntryBase entry in _entries) { yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, entry.Definition.Section, entry.Definition.Key, (ConfigScope)1, (Func)(() => Convert.ToString(entry.BoxedValue, CultureInfo.InvariantCulture)), 1)); } } internal static Color ParseColor(string value, float opacity) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); if (!ColorUtility.TryParseHtmlString(value ?? string.Empty, ref result)) { ((Color)(ref result))..ctor(0.95f, 0.9f, 0.79f); } result.a = Mathf.Clamp01(opacity); return result; } private void ImportLegacyGeneralTweaks(string path, ManualLogSource log) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown try { ConfigFile val = new ConfigFile(path, false); Enabled.Value = val.Bind("Compass", "Enabled", Enabled.Value, (ConfigDescription)null).Value; HeadingSource.Value = val.Bind("Compass", "HeadingSource", HeadingSource.Value, (ConfigDescription)null).Value; Scale.Value = val.Bind("Compass", "Scale", Scale.Value, (ConfigDescription)null).Value; OffsetX.Value = val.Bind("Compass", "OffsetX", OffsetX.Value, (ConfigDescription)null).Value; OffsetY.Value = val.Bind("Compass", "OffsetY", OffsetY.Value, (ConfigDescription)null).Value; Color.Value = val.Bind("Compass", "Color", Color.Value, (ConfigDescription)null).Value; Opacity.Value = val.Bind("Compass", "Opacity", Opacity.Value, (ConfigDescription)null).Value; _file.Save(); if (log != null) { log.LogInfo((object)("Imported compass settings from " + Path.GetFileName(path) + " into jg224.BoringCompass.cfg.")); } } catch (Exception ex) { if (log != null) { log.LogWarning((object)("Could not import GeneralTweaks compass settings; using BoringCompass defaults. " + ex.Message)); } } } private ConfigEntry Bind(string key, T value, string description) { ConfigEntry val = _file.Bind("Compass", key, value, description); _entries.Add((ConfigEntryBase)(object)val); return val; } private ConfigEntry BindRange(string key, float value, float min, float max, string description) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown ConfigEntry val = _file.Bind("Compass", key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(min, max), Array.Empty())); _entries.Add((ConfigEntryBase)(object)val); return val; } } [BepInPlugin("jg224.BoringCompass", "BoringCompass", "0.5.0")] [BepInProcess("valheim.exe")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.BoringCompass"; public const string PluginName = "BoringCompass"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const string GeneralTweaksGuid = "JG224.GeneralTweaks"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("boringcompass"); private readonly List _registrations = new List(); private Harmony _harmony; private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static BoringCompassConfig Settings { get; private set; } internal static ICoreServices Core { get; private set; } private void Awake() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Settings = BoringCompassConfig.Load((BaseUnityPlugin)(object)this, Paths.ConfigPath, ((BaseUnityPlugin)this).Logger); try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before BoringCompass."); } Core = ModCoreApi.Services; RegisterWithCore(); if (TryGetLegacyCompassOwner(out var version)) { string text = "GeneralTweaks " + version?.ToString() + " still contains the compass; BoringCompass is paused to prevent duplicate overlays."; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)3, text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(text + " Update GeneralTweaks to 1.0.0 or newer.")); } else { _harmony = new Harmony("jg224.BoringCompass"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Client-local late-camera compass overlay ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("BoringCompass 0.5.0 loaded; protocol " + 1 + ".")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("BoringCompass failed to initialize safely: " + ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void OnDestroy() { Shutdown(); } private void RegisterWithCore() { //IL_0029: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("Invalid plugin version."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.BoringCompass", "BoringCompass", val, 1, (ModuleSide)1, (ModuleRequirement)1, 0uL, 1, 1))); foreach (IDisposable item in Settings.RegisterMetadata(Core, ModuleId)) { _registrations.Add(item); } _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)8, "jg224.boringcompass.", 1, Array.Empty())); _registrations.Add(Core.Ui.Reserve(new UiReservation(ModuleId, (UiSurface)6, "top-center.compass", 20, false))); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)9, (Action)delegate { CompassOverlay.Destroy(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action)delegate { CompassOverlay.Destroy(); }, 0)); } private static bool TryGetLegacyCompassOwner(out Version version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("JG224.GeneralTweaks", out var value)) { return false; } version = value.Metadata.Version; if (version != null) { return version.CompareTo(new Version(1, 0, 0)) < 0; } return false; } private void Shutdown() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; CompassOverlay.Destroy(); for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; Log = null; } } } namespace JG224.BoringCompass.UI { internal sealed class CompassMarkers { private static readonly FieldRef> Pins = AccessTools.FieldRefAccess>("m_pins"); private readonly Transform _parent; private readonly List _candidates = new List(); private readonly List _images = new List(); private Minimap _map; private PinData _latestDeath; private float _refreshAt; private bool _showDeath; private bool _showOthers; private float _range; internal CompassMarkers(Transform parent) { _parent = parent; } internal void Update(Player player, float heading, Color color, BoringCompassConfig config) { //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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_0111: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; float num = CompassMarkerRules.DistanceLimit(config.MarkerDistance.Value); Vector3 position = ((Component)player).transform.position; if ((Object)(object)instance != (Object)(object)_map || Time.unscaledTime >= _refreshAt || config.ShowDeathMarker.Value != _showDeath || config.ShowMapMarkers.Value != _showOthers || num != _range) { _map = instance; _showDeath = config.ShowDeathMarker.Value; _showOthers = config.ShowMapMarkers.Value; _range = num; Refresh(position); _refreshAt = Time.unscaledTime + 0.25f; } int num2 = 0; if (Object.op_Implicit((Object)(object)instance)) { foreach (PinData candidate in _candidates) { Vector3 val = candidate.m_pos - position; if (ShouldShow(candidate, val) && Object.op_Implicit((Object)(object)candidate.m_icon)) { float relativeDegrees = CompassMarkerRules.RelativeBearing(val.x, val.z, heading); float num3 = CompassLayoutRules.EdgeOpacity(relativeDegrees); if (!(num3 <= 0f)) { Image image = GetImage(num2++); image.sprite = candidate.m_icon; ((Graphic)image).color = new Color(1f, 1f, 1f, color.a * num3); ((Graphic)image).rectTransform.anchoredPosition = new Vector2(CompassLayoutRules.HorizontalOffset(relativeDegrees), -68f); ((Component)image).gameObject.SetActive(true); } } } } for (int i = num2; i < _images.Count; i++) { ((Component)_images[i]).gameObject.SetActive(false); } } private void Refresh(Vector3 position) { //IL_0073: 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_0109: 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_010f: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 //IL_00ab: 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) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) _candidates.Clear(); _latestDeath = null; if (!Object.op_Implicit((Object)(object)_map) || (!_showDeath && !_showOthers)) { return; } PlayerProfile val = (Object.op_Implicit((Object)(object)Game.instance) ? Game.instance.GetPlayerProfile() : null); List list = Pins.Invoke(_map); if (_showDeath && val != null && val.HaveDeathPoint()) { Vector3 deathPoint = val.GetDeathPoint(); foreach (PinData item in list) { Vector3 val2 = item.m_pos - deathPoint; if (CompassMarkerRules.MatchesLatestDeath((int)item.m_type == 4, item.m_ownerID, val2.x, val2.y, val2.z)) { _latestDeath = item; } } } foreach (PinData item2 in list) { if (item2 != _latestDeath && ShouldShow(item2, item2.m_pos - position)) { _candidates.Add(item2); } } if (_latestDeath != null && ShouldShow(_latestDeath, _latestDeath.m_pos - position)) { _candidates.Add(_latestDeath); } } private bool ShouldShow(PinData pin, Vector3 delta) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0032: 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) if (!pin.m_shouldDelete) { return CompassMarkerRules.ShouldShow((int)pin.m_type == 4, pin == _latestDeath, pin.m_save, pin.m_checked, _showDeath, _showOthers, delta.x, delta.z, _range); } return false; } private Image GetImage(int index) { //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_0083: 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_009a: 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) if (index < _images.Count) { return _images[index]; } GameObject val = new GameObject("MapMarker" + index, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_parent, false); Image val2 = val.AddComponent(); ((Graphic)val2).raycastTarget = false; val2.preserveAspect = true; RectTransform rectTransform = ((Graphic)val2).rectTransform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 1f); rectTransform.anchorMax = val3; rectTransform.anchorMin = val3; rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.sizeDelta = new Vector2(24f, 24f); _images.Add(val2); return val2; } } internal static class CompassOverlay { private const int TickCount = 25; private const float TickDegrees = 5f; private const float CompassOutlineWidth = 3f / 14f; private const float CompassFaceDilate = 0.2f; private const float PointerOutlineWidth = 5f / 52f; private const float PointerFaceDilate = 0.05f; private static readonly List CompassTicks = new List(); private static readonly List FontMaterials = new List(); private static GameObject _root; private static RectTransform _compass; private static Image _compassRail; private static TextMeshProUGUI _pointer; private static TMP_FontAsset _compassFont; private static CompassMarkers _markers; private static int _renderedCompassCentre = int.MinValue; private static float _lastHeading = float.NaN; private static float _retryAt; private static bool _reportedFailure; internal static void TickAfterCamera() { //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) if (Application.isBatchMode || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance)) { if (Object.op_Implicit((Object)(object)_root)) { _root.SetActive(false); } } else { if (Time.realtimeSinceStartup < _retryAt) { return; } try { EnsureCreated(); if (!Object.op_Implicit((Object)(object)_root)) { return; } _root.SetActive(true); UpdateCompass(Player.m_localPlayer); if (_reportedFailure) { _reportedFailure = false; ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"Compass overlay recovered after its HUD initialization failure."); } ICoreServices core = Plugin.Core; if (core != null) { core.Modules.SetState(Plugin.ModuleId, (ModuleRuntimeState)2, "Client-local late-camera compass overlay ready."); } } } catch (Exception ex) { ReleaseObjects(); _retryAt = Time.realtimeSinceStartup + 5f; if (!_reportedFailure) { _reportedFailure = true; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("Compass overlay failed; retrying in five seconds: " + ex)); } ICoreServices core2 = Plugin.Core; if (core2 != null) { core2.Modules.SetState(Plugin.ModuleId, (ModuleRuntimeState)3, "Compass overlay initialization/update failed; waiting to retry."); } } } } } internal static void Destroy() { ReleaseObjects(); _retryAt = 0f; } private static void ReleaseObjects() { if (Object.op_Implicit((Object)(object)_root)) { _root.SetActive(false); Object.Destroy((Object)(object)_root); } foreach (Material fontMaterial in FontMaterials) { if (Object.op_Implicit((Object)(object)fontMaterial)) { Object.Destroy((Object)(object)fontMaterial); } } FontMaterials.Clear(); _root = null; _compass = null; _compassRail = null; _pointer = null; _compassFont = null; _markers = null; _renderedCompassCentre = int.MinValue; _lastHeading = float.NaN; CompassTicks.Clear(); } private static void EnsureCreated() { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_root)) { return; } ReleaseObjects(); if (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)Hud.instance.m_healthText)) { _compassFont = Hud.instance.m_healthText.font; } if (!Object.op_Implicit((Object)(object)_compassFont) && Object.op_Implicit((Object)(object)MessageHud.instance) && Object.op_Implicit((Object)(object)MessageHud.instance.m_messageText)) { _compassFont = MessageHud.instance.m_messageText.font; } if (!Object.op_Implicit((Object)(object)_compassFont)) { _compassFont = TMP_Settings.defaultFontAsset; } if (!Object.op_Implicit((Object)(object)_compassFont) || !Object.op_Implicit((Object)(object)((TMP_Asset)_compassFont).material) || !Object.op_Implicit((Object)(object)_compassFont.atlasTexture)) { return; } _root = new GameObject("JG224.BoringCompass.Overlay"); _root.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_root); Canvas obj = _root.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 200; obj.pixelPerfect = false; _root.AddComponent().uiScaleMode = (ScaleMode)0; ((Behaviour)_root.AddComponent()).enabled = false; GameObject val = new GameObject("Compass", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(_root.transform, false); _compass = val.GetComponent(); _compass.anchorMin = new Vector2(0.5f, 1f); _compass.anchorMax = new Vector2(0.5f, 1f); _compass.pivot = new Vector2(0.5f, 1f); _compass.sizeDelta = new Vector2(900f, 96f); val.AddComponent(); _compassRail = CreateRule("TopRail", (Transform)(object)_compass, new Vector2(896f, 2f), new Vector2(0f, -5f)); Vector2 val3 = default(Vector2); for (int i = 0; i < 25; i++) { TextMeshProUGUI val2 = CreateCompassText("Tick" + i, (Transform)(object)_compass); RectTransform rectTransform = ((TMP_Text)val2).rectTransform; ((Vector2)(ref val3))..ctor(0.5f, 1f); rectTransform.anchorMax = val3; rectTransform.anchorMin = val3; rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.sizeDelta = new Vector2(58f, 58f); CompassTicks.Add(val2); } _pointer = CreateCompassPointer((Transform)(object)_compass); _markers = new CompassMarkers((Transform)(object)_compass); _root.SetActive(true); foreach (TextMeshProUGUI compassTick in CompassTicks) { ApplyMaterialStyle(compassTick, 3f / 14f, 0.2f); } ApplyMaterialStyle(_pointer, 5f / 52f, 0.05f); } private static TextMeshProUGUI CreateCompassText(string name, Transform parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); TextMeshProUGUI val2 = val.AddComponent(); if (Object.op_Implicit((Object)(object)_compassFont)) { ((TMP_Text)val2).font = _compassFont; } ((TMP_Text)val2).fontSize = 14f; ((TMP_Text)val2).fontStyle = (FontStyles)1; ((TMP_Text)val2).fontWeight = (FontWeight)900; ((TMP_Text)val2).alignment = (TextAlignmentOptions)258; ((TMP_Text)val2).richText = true; ((TMP_Text)val2).enableAutoSizing = false; ((TMP_Text)val2).overflowMode = (TextOverflowModes)0; ((Graphic)val2).raycastTarget = false; return val2; } private static void ApplyMaterialStyle(TextMeshProUGUI text, float outlineWidth, float faceDilate) { //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) if (!((Behaviour)text).isActiveAndEnabled || !Object.op_Implicit((Object)(object)((TMP_Text)text).fontSharedMaterial)) { throw new InvalidOperationException("Compass text has no active font material."); } Material fontMaterial = ((TMP_Text)text).fontMaterial; if (!Object.op_Implicit((Object)(object)fontMaterial)) { throw new InvalidOperationException("Compass font material could not be initialized."); } FontMaterials.Add(fontMaterial); ((TMP_Text)text).outlineColor = Color32.op_Implicit(Color.black); ((TMP_Text)text).outlineWidth = outlineWidth; if (fontMaterial.HasProperty(ShaderUtilities.ID_FaceDilate)) { fontMaterial.SetFloat(ShaderUtilities.ID_FaceDilate, faceDilate); } ((TMP_Text)text).UpdateMeshPadding(); } private static TextMeshProUGUI CreateCompassPointer(Transform parent) { //IL_0045: 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_005c: 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) //IL_0085: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI obj = CreateCompassText("Pointer", parent); ((TMP_Text)obj).text = "▼"; ((TMP_Text)obj).fontWeight = (FontWeight)700; ((TMP_Text)obj).alignment = (TextAlignmentOptions)258; RectTransform rectTransform = ((TMP_Text)obj).rectTransform; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 1f); rectTransform.anchorMax = val; rectTransform.anchorMin = val; rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.anchoredPosition = new Vector2(0f, -1f); rectTransform.sizeDelta = new Vector2(22f, 17f); return obj; } private static Image CreateRule(string name, Transform parent, Vector2 size, Vector2 position) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); Image obj = val.AddComponent(); ((Graphic)obj).raycastTarget = false; RectTransform rectTransform = ((Graphic)obj).rectTransform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 1f); rectTransform.anchorMax = val2; rectTransform.anchorMin = val2; rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.anchoredPosition = position; rectTransform.sizeDelta = size; return obj; } private static void UpdateCompass(Player player) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_015e: 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_0167: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) BoringCompassConfig settings = Plugin.Settings; bool flag = settings != null && settings.Enabled.Value && (settings.ShowWhenHudHidden.Value || (Object.op_Implicit((Object)(object)Hud.instance) && !Hud.IsUserHidden() && Object.op_Implicit((Object)(object)Hud.instance.m_rootObject) && Hud.instance.m_rootObject.activeInHierarchy)); ((Component)_compass).gameObject.SetActive(flag); if (!flag) { return; } float num = CompassFitRules.Scale(settings.Scale.Value, Screen.width, Screen.height, settings.AutoWidth.Value); ((Transform)_compass).localScale = Vector3.one * num; float num2 = (settings.AutoWidth.Value ? CompassFitRules.OffsetX(settings.OffsetX.Value, Screen.width, num) : settings.OffsetX.Value); float num3 = (settings.AutoWidth.Value ? Mathf.Clamp(settings.OffsetY.Value, 0f, Mathf.Max(0f, (float)Screen.height - 96f * num)) : settings.OffsetY.Value); _compass.anchoredPosition = new Vector2(num2, 0f - num3); Color val = BoringCompassConfig.ParseColor(settings.Color.Value, settings.Opacity.Value); ((Graphic)_pointer).color = val; Color color = val; color.a *= 0.75f; ((Graphic)_compassRail).color = color; float num4 = Heading(player, settings.HeadingSource.Value); int num5 = Mathf.RoundToInt(num4 / 5f) * 5; bool flag2 = CompassLayoutRules.ShouldRefreshText(_renderedCompassCentre, num5); int num6 = 12; for (int i = 0; i < 25; i++) { int num7 = num5 + (i - num6) * 5; float num8 = HeadingRules.Normalize(num7); float relativeDegrees = Mathf.DeltaAngle(num4, num8); TextMeshProUGUI val2 = CompassTicks[i]; CompassTickKind compassTickKind = HeadingRules.TickKindFor(num7); if (flag2) { string bearingText = HeadingRules.BearingText(num7); string text = CompassLayoutRules.TickMarkFor(compassTickKind); string text2 = CompassLayoutRules.BearingNumberFor(compassTickKind, bearingText); switch (compassTickKind) { case CompassTickKind.Cardinal: ((TMP_Text)val2).text = "" + text + "\n" + HeadingRules.LabelFor(num8) + ""; break; case CompassTickKind.Ordinal: ((TMP_Text)val2).text = "" + text + "\n" + HeadingRules.LabelFor(num8) + ""; break; default: ((TMP_Text)val2).text = "" + text + "\n" + text2 + ""; break; } } Color color2 = val; color2.a *= CompassLayoutRules.EdgeOpacity(relativeDegrees); ((Graphic)val2).color = color2; ((TMP_Text)val2).rectTransform.anchoredPosition = new Vector2(CompassLayoutRules.HorizontalOffset(relativeDegrees), CompassLayoutRules.VerticalOffset(compassTickKind)); } if (flag2) { _renderedCompassCentre = num5; } _markers.Update(player, num4, val, settings); } private static float Heading(Player player, CompassHeadingSource source) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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_0070: 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) //IL_007c: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) Vector3 val; switch (source) { case CompassHeadingSource.PlayerFacing: val = ((Component)player).transform.forward; break; case CompassHeadingSource.Movement: val = ((Character)player).GetMoveDir(); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = ((Component)player).transform.forward; } break; default: val = (Object.op_Implicit((Object)(object)GameCamera.instance) ? ((Component)GameCamera.instance).transform.forward : ((Component)player).transform.forward); break; } Vector3 forward = ((Component)player).transform.forward; _lastHeading = CompassFitRules.Heading(val.x, val.z, forward.x, forward.z, _lastHeading); return _lastHeading; } } } namespace JG224.BoringCompass.Patches { [HarmonyPatch(typeof(GameCamera), "LateUpdate")] internal static class CompassCameraLateUpdatePatch { private static void Postfix() { CompassOverlay.TickAfterCamera(); } } } namespace JG224.BoringCompass.Core { internal static class CompassFitRules { internal static float Heading(float x, float z, float facingX, float facingZ, float previous) { if (Finite(x) && Finite(z) && x * x + z * z >= 0.0001f) { return HeadingRules.Normalize((float)(Math.Atan2(x, z) * 180.0 / Math.PI)); } if (Finite(previous)) { return HeadingRules.Normalize(previous); } if (Finite(facingX) && Finite(facingZ) && facingX * facingX + facingZ * facingZ >= 0.0001f) { return HeadingRules.Normalize((float)(Math.Atan2(facingX, facingZ) * 180.0 / Math.PI)); } return 0f; } internal static float Scale(float requested, int width, int height, bool autoWidth) { requested = (Finite(requested) ? Math.Max(0.5f, Math.Min(2f, requested)) : 1f); if (!autoWidth) { return requested; } return Math.Min(requested, Math.Max(0.01f, Math.Min((float)Math.Max(1, width - 16) / 900f, (float)Math.Max(1, height) / 96f))); } internal static float OffsetX(float requested, int width, float scale) { float num = Math.Max(0f, ((float)width - 900f * scale) / 2f); if (!Finite(requested)) { return 0f; } return Math.Max(0f - num, Math.Min(num, requested)); } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public enum CompassHeadingSource { Camera, PlayerFacing, Movement } internal enum CompassTickKind { Minor, Ordinal, Cardinal } internal static class HeadingRules { private static readonly string[] Labels = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }; internal static float Normalize(float degrees) { degrees %= 360f; if (!(degrees < 0f)) { return degrees; } return degrees + 360f; } internal static string LabelFor(float degrees) { int num = (int)Math.Floor((Normalize(degrees) + 22.5f) / 45f) % Labels.Length; return Labels[num]; } internal static bool IsNamedBearing(int degrees) { return (degrees % 45 + 45) % 45 == 0; } internal static bool IsCardinalBearing(int degrees) { return (degrees % 90 + 90) % 90 == 0; } internal static CompassTickKind TickKindFor(int degrees) { if (IsCardinalBearing(degrees)) { return CompassTickKind.Cardinal; } if (!IsNamedBearing(degrees)) { return CompassTickKind.Minor; } return CompassTickKind.Ordinal; } internal static string BearingText(int degrees) { return ((degrees % 360 + 360) % 360).ToString("000", CultureInfo.InvariantCulture); } } internal static class CompassLayoutRules { internal const float ViewportHeight = 96f; internal const float TickTextHeight = 58f; private const float PixelsPerDegree = 10.625f; private const float OpaqueHalfDegrees = 34f; private const float VisibleHalfDegrees = 42f; internal static string TickMarkFor(CompassTickKind kind) { return "|"; } internal static string BearingNumberFor(CompassTickKind kind, string bearingText) { if (kind != CompassTickKind.Minor) { return string.Empty; } return bearingText; } internal static float HorizontalOffset(float relativeDegrees) { return relativeDegrees * 10.625f; } internal static float VerticalOffset(CompassTickKind kind) { return -6f; } internal static bool ShouldRefreshText(int renderedCentre, int currentCentre) { return renderedCentre != currentCentre; } internal static float EdgeOpacity(float relativeDegrees) { if (float.IsNaN(relativeDegrees) || float.IsInfinity(relativeDegrees)) { return 0f; } float num = Math.Abs(relativeDegrees); if (num <= 34f) { return 1f; } if (num >= 42f) { return 0f; } return (42f - num) / 8f; } } internal static class CompassMarkerRules { internal const float DefaultDistance = 100f; internal static bool MatchesLatestDeath(bool isDeath, long ownerId, float deltaX, float deltaY, float deltaZ) { if (isDeath && ownerId == 0L && deltaX == 0f && deltaY == 0f) { return deltaZ == 0f; } return false; } internal static float DistanceLimit(float configured) { if (!Finite(configured)) { return 100f; } return Math.Max(1f, Math.Min(10000f, configured)); } internal static bool ShouldShow(bool isDeath, bool isLatestDeath, bool saved, bool isChecked, bool showDeath, bool showOthers, float deltaX, float deltaZ, float range) { if (isChecked || !Finite(deltaX) || !Finite(deltaZ)) { return false; } if (isDeath) { return showDeath && isLatestDeath; } double num = DistanceLimit(range); if (showOthers && saved) { return (double)deltaX * (double)deltaX + (double)deltaZ * (double)deltaZ <= num * num; } return false; } internal static float RelativeBearing(float deltaX, float deltaZ, float heading) { if (deltaX == 0f && deltaZ == 0f) { return 0f; } return HeadingRules.Normalize((float)(Math.Atan2(deltaX, deltaZ) * 180.0 / Math.PI) - heading + 180f) - 180f; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } internal static class LegacyCompassConfigRules { internal const string CurrentFileName = "jg224.BoringCompass.cfg"; internal const string GeneralTweaksFileName = "jg224.GeneralTweaks.cfg"; internal const string LegacyGeneralTweaksFileName = "JG224.GeneralTweaks.cfg"; internal static string FindImportSource(IEnumerable candidatePaths) { string[] paths = ((candidatePaths == null) ? Array.Empty() : candidatePaths.ToArray()); if (FindExact(paths, "jg224.BoringCompass.cfg") != null) { return null; } return FindExact(paths, "jg224.GeneralTweaks.cfg") ?? FindExact(paths, "JG224.GeneralTweaks.cfg"); } private static string FindExact(IEnumerable paths, string fileName) { return paths.FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } }