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.0
plugins\SoloMapPins.dll
Decompiled 17 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; 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.0")] public sealed class SoloMapPinsPlugin : BaseUnityPlugin { private struct DictionarySnapshotEntry { public object? Key; public object? Value; } 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_0042: 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)) { return true; } DebugLog($"Blocked shared location discovery at {point}; local player is not nearby."); return false; } } private static class LocationIconsPatch { public static void Postfix() { PruneDistantLocationPins(); } } private static class LocationPinsUpdatePatch { public static void Postfix() { PruneDistantLocationPins(); } } public const string PluginGuid = "SoloMapPins"; public const string PluginName = "Solo Map Pins"; public const string PluginVersion = "0.2.0"; private static ConfigEntry<bool> _blockFarSharedDiscoveries; private static ConfigEntry<bool> _filterGlobalLocationIcons; private static ConfigEntry<float> _fallbackDiscoveryRange; private static ConfigEntry<float> _locationIconRevealRange; private static ConfigEntry<string> _alwaysKeepLocationNames; private static ConfigEntry<float> _duplicatePinRadius; private static ConfigEntry<bool> _debugLogging; private static SoloMapPinsPlugin _instance; private const string UnlockedLocationsKey = "SoloMapPins.UnlockedLocationIcons"; 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, "Removes synced unique location icons 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(Minimap), "UpdateLocationPins", typeof(LocationPinsUpdatePatch), postfix: true); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Solo Map Pins 0.2.0 loaded."); } private void OnDestroy() { 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_0015: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return Vector3.Distance(((Component)localPlayer).transform.position, point) <= range; } return false; } private static bool ShouldKeepLocationIcon(Vector3 point) { //IL_0015: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return Vector3.Distance(((Component)localPlayer).transform.position, point) <= _locationIconRevealRange.Value; } return false; } private static string GetLocationKey(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 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(Vector3 point) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return GetUnlockedLocations().ContainsKey(GetLocationKey(point)); } private static void UnlockLocation(Vector3 point, string? locationName) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, string> unlockedLocations = GetUnlockedLocations(); string locationKey = GetLocationKey(point); if (!unlockedLocations.ContainsKey(locationKey)) { unlockedLocations[locationKey] = locationName ?? string.Empty; SaveUnlockedLocations(unlockedLocations); DebugLog($"Unlocked personal location icon '{locationName ?? locationKey}' at {point}."); } } 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 List<DictionarySnapshotEntry> GetDictionarySnapshot(object dictionary) { List<DictionarySnapshotEntry> list = new List<DictionarySnapshotEntry>(); if (!(dictionary is IEnumerable enumerable)) { return list; } foreach (object item in enumerable) { if (item is DictionaryEntry dictionaryEntry) { list.Add(new DictionarySnapshotEntry { Key = dictionaryEntry.Key, Value = dictionaryEntry.Value }); continue; } Type type = item.GetType(); PropertyInfo property = type.GetProperty("Key"); PropertyInfo property2 = type.GetProperty("Value"); if (!(property == null) && !(property2 == null)) { list.Add(new DictionarySnapshotEntry { Key = property.GetValue(item), Value = property2.GetValue(item) }); } } return list; } private static bool TryGetLocationIconName(Vector3 point, out string? locationName) { //IL_0058: 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) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) locationName = null; ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return false; } object value = Traverse.Create((object)instance).Field("m_locationIcons").GetValue(); if (value == null) { return false; } foreach (DictionarySnapshotEntry item in GetDictionarySnapshot(value)) { if (item.Key is Vector3 val && val == point) { locationName = item.Value as string; return true; } } return false; } private static bool ShouldKeepLocationIcon(Vector3 point, string? locationName) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!ShouldAlwaysKeepLocationName(locationName) && !IsLocationUnlocked(point)) { return ShouldKeepLocationIcon(point); } return true; } private static bool IsSavedPin(object pin) { object value = Traverse.Create(pin).Field("m_save").GetValue(); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static void PruneDistantLocationPins() { //IL_0080: 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) //IL_0087: 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) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) if (!_filterGlobalLocationIcons.Value || (Object)(object)Player.m_localPlayer == (Object)null) { return; } Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || !(Traverse.Create((object)instance).Field("m_locationPins").GetValue() is IDictionary dictionary)) { return; } List<object> list = new List<object>(); foreach (DictionarySnapshotEntry item in GetDictionarySnapshot(dictionary)) { if (!(item.Key is Vector3 point) || !TryGetLocationIconName(point, out string locationName)) { continue; } object value = item.Value; if (value != null && IsSavedPin(value)) { continue; } if (ShouldAlwaysKeepLocationName(locationName) || ShouldKeepLocationIcon(point)) { UnlockLocation(point, locationName); } else if (!IsLocationUnlocked(point)) { if (value != null) { AccessTools.Method(typeof(Minimap), "RemovePin", new Type[1] { value.GetType() }, (Type[])null)?.Invoke(instance, new object[1] { value }); } list.Add(item.Key); } } foreach (object item2 in list) { dictionary.Remove(item2); } if (list.Count > 0) { DebugLog($"Pruned {list.Count} distant synced location pins."); } } 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; } } }