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 SoloMapPins v0.2.1
plugins\SoloMapPins.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [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("SoloMapPins")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SoloMapPins")] [assembly: AssemblyTitle("SoloMapPins")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 SoloMapPins { [BepInPlugin("SoloMapPins", "Solo Map Pins", "0.2.1")] public sealed class SoloMapPinsPlugin : BaseUnityPlugin { private struct PendingLocation { public Vector3 Point; public string Name; } private static class DiscoverLocationPatch { public static bool Prefix(object?[] __args) { //IL_0020: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!_blockFarSharedDiscoveries.Value || !TryGetWorldPoint(__args, out var point)) { if (TryGetWorldPoint(__args, out point)) { UnlockLocation(point, null); } return true; } if (IsLocalPlayerNear(point, _fallbackDiscoveryRange.Value)) { UnlockLocation(point, null); return true; } DebugLog($"Blocked shared location discovery at {point}; local player is not nearby."); return false; } } private static class LocationIconsPatch { public static void Postfix() { PendingLocations.Clear(); _nextPendingLocationCheck = 0f; ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance != (Object)null) { Dictionary<Vector3, string> dictionary = new Dictionary<Vector3, string>(); instance.GetLocationIcons(dictionary); } if ((Object)(object)Minimap.instance != (Object)null) { Traverse.Create((object)Minimap.instance).Field("m_updateLocationsTimer").SetValue((object)0f); } } } private static class GetLocationIconsPatch { public static void Postfix(Dictionary<Vector3, string> __0) { FilterLocationIcons(__0); } } public const string PluginGuid = "SoloMapPins"; public const string PluginName = "Solo Map Pins"; public const string PluginVersion = "0.2.1"; private static ConfigEntry<bool> _blockFarSharedDiscoveries = null; private static ConfigEntry<bool> _filterGlobalLocationIcons = null; private static ConfigEntry<float> _fallbackDiscoveryRange = null; private static ConfigEntry<float> _locationIconRevealRange = null; private static ConfigEntry<string> _alwaysKeepLocationNames = null; private static ConfigEntry<float> _duplicatePinRadius = null; private static ConfigEntry<bool> _debugLogging = null; private static SoloMapPinsPlugin _instance = null; private const string UnlockedLocationsKey = "SoloMapPins.UnlockedLocationIcons"; private const float PendingLocationCheckInterval = 1f; private static readonly Dictionary<string, PendingLocation> PendingLocations = new Dictionary<string, PendingLocation>(); private static float _nextPendingLocationCheck; private Harmony _harmony; private void Awake() { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown _instance = this; _blockFarSharedDiscoveries = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BlockFarSharedDiscoveries", false, "Prevents direct location discovery pins from being accepted when the local player is not near the location. Disabled by default because mods like MWL Waystones intentionally reveal distant personal pins."); _filterGlobalLocationIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FilterGlobalLocationIcons", true, "Filters synced unique location icons before they are added unless the local player is close enough to that location."); _fallbackDiscoveryRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FallbackDiscoveryRange", 100f, "Distance used when guarding direct location discovery responses."); _locationIconRevealRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LocationIconRevealRange", 250f, "Unique location icons within this many meters of the local player are allowed to stay on the map."); _alwaysKeepLocationNames = ((BaseUnityPlugin)this).Config.Bind<string>("General", "AlwaysKeepLocationNames", "StartTemple,BossStone", "Comma-separated location name fragments that are never removed from the synced location icon list."); _duplicatePinRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DuplicatePinRadius", 25f, "Existing location pins within this many meters are treated as the same discovery."); _debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Logs blocked or locally-added location pins."); _harmony = new Harmony("SoloMapPins"); PatchIfPresent(typeof(Minimap), "DiscoverLocation", typeof(DiscoverLocationPatch)); PatchIfPresent(typeof(Game), "RPC_DiscoverLocationResponse", typeof(DiscoverLocationPatch)); PatchIfPresent(typeof(ZoneSystem), "RPC_LocationIcons", typeof(LocationIconsPatch), postfix: true); PatchIfPresent(typeof(ZoneSystem), "GetLocationIcons", typeof(GetLocationIconsPatch), postfix: true); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Solo Map Pins 0.2.1 loaded."); } private void Update() { ReevaluatePendingLocations(); } private void OnDestroy() { PendingLocations.Clear(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void PatchIfPresent(Type targetType, string methodName, Type patchType, bool postfix = false) { //IL_0060: 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) MethodInfo methodInfo = AccessTools.Method(targetType, methodName, (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not find " + targetType.Name + "." + methodName + "; this Valheim version may have renamed it.")); } else { HarmonyMethod val = (postfix ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(patchType, "Prefix", (Type[])null, (Type[])null))); HarmonyMethod val2 = ((!postfix) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(patchType, "Postfix", (Type[])null, (Type[])null))); _harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void DebugLog(string message) { if (_debugLogging.Value) { ((BaseUnityPlugin)_instance).Logger.LogInfo((object)message); } } private static bool IsLocalPlayerNear(Vector3 point, float range) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; range = Mathf.Max(0f, range); if ((Object)(object)localPlayer != (Object)null) { return HorizontalDistanceSquared(((Component)localPlayer).transform.position, point) <= range * range; } return false; } private static bool ShouldKeepLocationIcon(Vector3 point) { //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) Player localPlayer = Player.m_localPlayer; float num = Mathf.Max(0f, _locationIconRevealRange.Value); if ((Object)(object)localPlayer != (Object)null) { return HorizontalDistanceSquared(((Component)localPlayer).transform.position, point) <= num * num; } return false; } private static float HorizontalDistanceSquared(Vector3 first, Vector3 second) { //IL_0000: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = first.x - second.x; float num2 = first.z - second.z; return num * num + num2 * num2; } private static string GetLegacyLocationKey(Vector3 point) { //IL_0005: 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) return $"{Mathf.RoundToInt(point.x)}:{Mathf.RoundToInt(point.z)}"; } private static string GetLocationKey(Vector3 point, string? locationName) { //IL_0053: 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) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(locationName)) { return GetLegacyLocationKey(point); } string s = locationName.Trim().ToLowerInvariant(); string arg = Convert.ToBase64String(Encoding.UTF8.GetBytes(s)).TrimEnd(new char[1] { '=' }).Replace('+', '-') .Replace('/', '_'); return $"v2:{Mathf.RoundToInt(point.x)}:{Mathf.RoundToInt(point.z)}:{arg}"; } private static Dictionary<string, string> GetUnlockedLocations() { Dictionary<string, string> dictionary = new Dictionary<string, string>(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return dictionary; } Dictionary<string, string> value = Traverse.Create((object)localPlayer).Field("m_customData").GetValue<Dictionary<string, string>>(); if (value == null || !value.TryGetValue("SoloMapPins.UnlockedLocationIcons", out var value2) || string.IsNullOrWhiteSpace(value2)) { return dictionary; } string[] array = value2.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '=' }, 2); if (array2.Length == 2 && !dictionary.ContainsKey(array2[0])) { dictionary.Add(array2[0], array2[1]); } } return dictionary; } private static void SaveUnlockedLocations(Dictionary<string, string> unlocked) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Dictionary<string, string> value = Traverse.Create((object)localPlayer).Field("m_customData").GetValue<Dictionary<string, string>>(); if (value != null) { value["SoloMapPins.UnlockedLocationIcons"] = string.Join("|", unlocked.Select<KeyValuePair<string, string>, string>((KeyValuePair<string, string> kvp) => kvp.Key + "=" + kvp.Value).ToArray()); } } private static bool IsLocationUnlocked(Dictionary<string, string> unlocked, Vector3 point, string? locationName) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!unlocked.ContainsKey(GetLegacyLocationKey(point))) { return unlocked.ContainsKey(GetLocationKey(point, locationName)); } return true; } private static bool AddUnlockedLocation(Dictionary<string, string> unlocked, Vector3 point, string? locationName) { //IL_0000: 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) string locationKey = GetLocationKey(point, locationName); if (unlocked.ContainsKey(locationKey)) { return false; } unlocked[locationKey] = locationName ?? string.Empty; DebugLog($"Unlocked personal location icon '{locationName ?? locationKey}' at {point}."); return true; } private static void UnlockLocation(Vector3 point, string? locationName) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, string> unlockedLocations = GetUnlockedLocations(); if (AddUnlockedLocation(unlockedLocations, point, locationName)) { SaveUnlockedLocations(unlockedLocations); } } private static bool ShouldAlwaysKeepLocationName(object? locationName) { if (!(locationName is string text) || string.IsNullOrWhiteSpace(text)) { return false; } string[] array = _alwaysKeepLocationNames.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { if (text.IndexOf(text2.Trim(), StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static void FilterLocationIcons(Dictionary<Vector3, string> icons) { //IL_0045: 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_008d: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) if (!_filterGlobalLocationIcons.Value || (Object)(object)Player.m_localPlayer == (Object)null) { PendingLocations.Clear(); return; } Dictionary<string, string> unlockedLocations = GetUnlockedLocations(); bool flag = false; KeyValuePair<Vector3, string>[] array = icons.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<Vector3, string> keyValuePair = array[i]; string locationKey = GetLocationKey(keyValuePair.Key, keyValuePair.Value); if (ShouldAlwaysKeepLocationName(keyValuePair.Value) || IsLocationUnlocked(unlockedLocations, keyValuePair.Key, keyValuePair.Value)) { PendingLocations.Remove(locationKey); continue; } if (ShouldKeepLocationIcon(keyValuePair.Key)) { flag |= AddUnlockedLocation(unlockedLocations, keyValuePair.Key, keyValuePair.Value); PendingLocations.Remove(locationKey); continue; } icons.Remove(keyValuePair.Key); PendingLocations[locationKey] = new PendingLocation { Point = keyValuePair.Key, Name = keyValuePair.Value }; } if (flag) { SaveUnlockedLocations(unlockedLocations); } } private static void ReevaluatePendingLocations() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (!_filterGlobalLocationIcons.Value || PendingLocations.Count == 0 || (Object)(object)Player.m_localPlayer == (Object)null || Time.unscaledTime < _nextPendingLocationCheck) { return; } _nextPendingLocationCheck = Time.unscaledTime + 1f; Dictionary<string, string> unlockedLocations = GetUnlockedLocations(); bool flag = false; bool flag2 = false; KeyValuePair<string, PendingLocation>[] array = PendingLocations.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<string, PendingLocation> keyValuePair = array[i]; PendingLocation value = keyValuePair.Value; if (ShouldAlwaysKeepLocationName(value.Name) || ShouldKeepLocationIcon(value.Point)) { if (!ShouldAlwaysKeepLocationName(value.Name)) { flag |= AddUnlockedLocation(unlockedLocations, value.Point, value.Name); } PendingLocations.Remove(keyValuePair.Key); flag2 = true; } } if (flag) { SaveUnlockedLocations(unlockedLocations); } if (flag2 && (Object)(object)Minimap.instance != (Object)null) { Traverse.Create((object)Minimap.instance).Field("m_updateLocationsTimer").SetValue((object)0f); DebugLog("Revealed pending synced location icons after the local player entered range."); } } private static bool TryGetWorldPoint(object?[] args, out Vector3 point) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_001b: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < args.Length; i++) { if (args[i] is Vector3 val) { point = val; return true; } } point = default(Vector3); return false; } } }