Decompiled source of AutoPins v1.1.0

AutoPins.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace AutoPins;

public enum Cat
{
	Ore,
	Pickable,
	Dungeon,
	Portal,
	Cart,
	Ship
}
public class Entry
{
	public Cat cat;

	public string label;

	public Vector3 pos;

	public string key;

	public bool hidden;
}
public enum MapIcon
{
	Icon1Fire,
	Icon2House,
	Icon3Hammer,
	Icon4Dot,
	Icon5Portal
}
[BepInPlugin("com.burks.autopins", "Auto Pins", "1.1.0")]
public class AutoPinsPlugin : BaseUnityPlugin
{
	public const string GUID = "com.burks.autopins";

	public const string NAME = "Auto Pins";

	public const string VERSION = "1.1.0";

	public static ManualLogSource Log;

	public static ConfigEntry<bool> Enabled;

	public static ConfigEntry<bool> ShowNames;

	public static ConfigEntry<bool> SkipFarmland;

	public static ConfigEntry<float> PinRadius;

	public static ConfigEntry<float> ScanInterval;

	public static ConfigEntry<float> PickableGroup;

	public static ConfigEntry<float> OreGroup;

	public static ConfigEntry<int> MaxPins;

	public static ConfigEntry<bool>[] CatOn = new ConfigEntry<bool>[6];

	public static ConfigEntry<MapIcon>[] CatIcon = new ConfigEntry<MapIcon>[6];

	public static ConfigEntry<string> IgnorePickables;

	public static ConfigEntry<string> IgnoreOreDrops;

	private bool _headless;

	private void Awake()
	{
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0330: Invalid comparison between Unknown and I4
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch.");
		PinRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PinRadiusMeters", 60f, "Things closer to you than this get pinned (30-100).");
		ScanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ScanIntervalSeconds", 3f, "How often the area around you is checked.");
		ShowNames = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowNames", true, "Show a name under each pin on the big map.");
		MaxPins = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPins", 3000, "Upper limit on stored pins per character per world. Oldest are dropped first.");
		CatOn[0] = ((BaseUnityPlugin)this).Config.Bind<bool>("Categories", "OreDeposits", true, "Copper, tin, silver, scrap piles, obsidian and any other rock that gives more than plain stone.");
		CatOn[1] = ((BaseUnityPlugin)this).Config.Bind<bool>("Categories", "Pickables", true, "Berries, mushrooms, thistle and other things you pick by hand.");
		CatOn[2] = ((BaseUnityPlugin)this).Config.Bind<bool>("Categories", "DungeonEntrances", true, "Burial chambers, troll caves, crypts, frost caves, mines and other entrances.");
		CatOn[3] = ((BaseUnityPlugin)this).Config.Bind<bool>("Categories", "Portals", true, "Portals, labelled with their tag.");
		CatOn[4] = ((BaseUnityPlugin)this).Config.Bind<bool>("Categories", "Carts", true, "Carts, at the last place you saw them.");
		CatOn[5] = ((BaseUnityPlugin)this).Config.Bind<bool>("Categories", "Ships", true, "Rafts and ships, at the last place you saw them.");
		string text = " Uses the game's own icons, numbered as they appear beside the map.";
		CatIcon[0] = ((BaseUnityPlugin)this).Config.Bind<MapIcon>("Icons", "OreDeposits", MapIcon.Icon3Hammer, "Map icon for deposits." + text);
		CatIcon[1] = ((BaseUnityPlugin)this).Config.Bind<MapIcon>("Icons", "Pickables", MapIcon.Icon4Dot, "Map icon for pickables." + text);
		CatIcon[2] = ((BaseUnityPlugin)this).Config.Bind<MapIcon>("Icons", "DungeonEntrances", MapIcon.Icon2House, "Map icon for dungeon entrances." + text);
		CatIcon[3] = ((BaseUnityPlugin)this).Config.Bind<MapIcon>("Icons", "Portals", MapIcon.Icon5Portal, "Map icon for portals." + text);
		CatIcon[4] = ((BaseUnityPlugin)this).Config.Bind<MapIcon>("Icons", "Carts", MapIcon.Icon4Dot, "Map icon for carts." + text);
		CatIcon[5] = ((BaseUnityPlugin)this).Config.Bind<MapIcon>("Icons", "Ships", MapIcon.Icon4Dot, "Map icon for ships." + text);
		IgnorePickables = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "IgnorePickables", "Stone,Wood,Flint,BoneFragments", "Item prefab names that are never pinned as pickables.");
		IgnoreOreDrops = ((BaseUnityPlugin)this).Config.Bind<string>("Filters", "IgnoreOreDrops", "Stone,Grausten,BlackMarble", "A rock is only pinned as a deposit if it drops something that is not on this list.");
		SkipFarmland = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "SkipCropsOnFarmland", true, "Do not pin pickables growing on cultivated ground (your own crops).");
		PickableGroup = ((BaseUnityPlugin)this).Config.Bind<float>("Filters", "PickableGroupMeters", 12f, "One pin per kind of pickable within roughly this distance, to keep berry patches to a single pin.");
		OreGroup = ((BaseUnityPlugin)this).Config.Bind<float>("Filters", "OreGroupMeters", 8f, "One pin per kind of deposit within roughly this distance.");
		_headless = (int)SystemInfo.graphicsDeviceType == 4;
		if (_headless)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Headless server detected; Auto Pins is client-side only.");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Auto Pins 1.1.0 loaded.");
		}
	}

	private void Update()
	{
		if (!_headless)
		{
			Scanner.Tick();
		}
	}

	private void OnDestroy()
	{
		Store.SaveIfDirty(force: true);
	}

	private void OnApplicationQuit()
	{
		Store.SaveIfDirty(force: true);
	}

	public static bool On(Cat c)
	{
		if (CatOn[(int)c] != null)
		{
			return CatOn[(int)c].Value;
		}
		return false;
	}

	public static PinType IconFor(Cat c)
	{
		return (PinType)(CatIcon[(int)c].Value switch
		{
			MapIcon.Icon1Fire => 0, 
			MapIcon.Icon2House => 1, 
			MapIcon.Icon3Hammer => 2, 
			MapIcon.Icon5Portal => 6, 
			_ => 3, 
		});
	}
}
public static class Store
{
	public static readonly Dictionary<string, Entry> Entries = new Dictionary<string, Entry>();

	public static readonly List<Entry> Order = new List<Entry>();

	public static bool Dirty;

	public static int Generation;

	private static string _loadedKey;

	private static float _lastSave;

	private static string CurrentKey()
	{
		try
		{
			if ((Object)(object)Game.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return null;
			}
			PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
			if (playerProfile == null)
			{
				return null;
			}
			string text = ZNet.instance.GetWorldName();
			if (string.IsNullOrEmpty(text))
			{
				text = "unknown";
			}
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				text = text.Replace(oldChar, '_');
			}
			return text + "_" + playerProfile.GetPlayerID().ToString(CultureInfo.InvariantCulture);
		}
		catch
		{
			return null;
		}
	}

	private static string FilePath(string key)
	{
		string text = Path.Combine(Paths.ConfigPath, "AutoPins");
		if (!Directory.Exists(text))
		{
			Directory.CreateDirectory(text);
		}
		return Path.Combine(text, key + ".txt");
	}

	public static bool EnsureLoaded()
	{
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		string text = CurrentKey();
		if (text == null)
		{
			return false;
		}
		if (text == _loadedKey)
		{
			return true;
		}
		SaveIfDirty(force: true);
		Entries.Clear();
		Order.Clear();
		_loadedKey = text;
		Generation++;
		Dirty = false;
		try
		{
			string path = FilePath(text);
			if (File.Exists(path))
			{
				string[] array = File.ReadAllLines(path);
				foreach (string text2 in array)
				{
					if (text2.Length != 0 && text2[0] != '#')
					{
						string[] array2 = text2.Split('\t');
						if (array2.Length >= 6 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 0 && result <= 5 && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.TryParse(array2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && !Entries.ContainsKey(array2[4]))
						{
							Add(new Entry
							{
								cat = (Cat)result,
								pos = new Vector3(result2, result3, result4),
								key = array2[4],
								label = array2[5],
								hidden = (array2.Length > 6 && array2[6] == "1")
							}, markDirty: false);
						}
					}
				}
			}
			AutoPinsPlugin.Log.LogInfo((object)("Loaded " + Entries.Count + " stored pin(s)."));
		}
		catch (Exception ex)
		{
			AutoPinsPlugin.Log.LogWarning((object)("Could not load stored pins: " + ex.Message));
		}
		return true;
	}

	public static void Add(Entry e, bool markDirty = true)
	{
		Entries[e.key] = e;
		Order.Add(e);
		if (markDirty)
		{
			Dirty = true;
		}
		int num = Mathf.Max(100, AutoPinsPlugin.MaxPins.Value);
		while (Order.Count > num)
		{
			Remove(Order[0]);
		}
	}

	public static void Remove(Entry e)
	{
		if (Entries.TryGetValue(e.key, out var value) && value == e)
		{
			Entries.Remove(e.key);
		}
		Order.Remove(e);
		Dirty = true;
	}

	public static void SaveIfDirty(bool force)
	{
		if (!Dirty || _loadedKey == null || (!force && Time.unscaledTime - _lastSave < 15f))
		{
			return;
		}
		_lastSave = Time.unscaledTime;
		try
		{
			List<string> list = new List<string>(Order.Count + 1) { "# category\tx\ty\tz\tkey\tlabel\tdeleted   (Auto Pins bookkeeping; the pins themselves are ordinary map pins)" };
			foreach (Entry item in Order)
			{
				list.Add(string.Format(CultureInfo.InvariantCulture, "{0}\t{1:R}\t{2:R}\t{3:R}\t{4}\t{5}\t{6}", (int)item.cat, item.pos.x, item.pos.y, item.pos.z, item.key, (item.label ?? "").Replace('\t', ' '), item.hidden ? "1" : "0"));
			}
			File.WriteAllLines(FilePath(_loadedKey), list.ToArray());
			Dirty = false;
		}
		catch (Exception ex)
		{
			AutoPinsPlugin.Log.LogWarning((object)("Could not save pins: " + ex.Message));
		}
	}
}
public static class Scanner
{
	private static float _next;

	private static readonly HashSet<string> _live = new HashSet<string>();

	private static readonly bool[] _typeFailed = new bool[8];

	private static readonly Dictionary<string, string> _pickLabel = new Dictionary<string, string>();

	private static readonly Dictionary<string, string> _oreLabel = new Dictionary<string, string>();

	private static string _ignPickRaw;

	private static string _ignOreRaw;

	private static readonly HashSet<string> _ignPick = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private static readonly HashSet<string> _ignOre = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private static Vector3 _pp;

	private static float _r2;

	private static void Fill(HashSet<string> set, string raw)
	{
		set.Clear();
		if (string.IsNullOrEmpty(raw))
		{
			return;
		}
		string[] array = raw.Split(',');
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length > 0)
			{
				set.Add(text);
			}
		}
	}

	private static void RefreshFilters()
	{
		if (_ignPickRaw != AutoPinsPlugin.IgnorePickables.Value)
		{
			_ignPickRaw = AutoPinsPlugin.IgnorePickables.Value;
			Fill(_ignPick, _ignPickRaw);
			_pickLabel.Clear();
		}
		if (_ignOreRaw != AutoPinsPlugin.IgnoreOreDrops.Value)
		{
			_ignOreRaw = AutoPinsPlugin.IgnoreOreDrops.Value;
			Fill(_ignOre, _ignOreRaw);
			_oreLabel.Clear();
		}
	}

	private static string Loc(string token)
	{
		if (string.IsNullOrEmpty(token))
		{
			return "";
		}
		try
		{
			return (Localization.instance != null) ? Localization.instance.Localize(token).Trim() : token;
		}
		catch
		{
			return token;
		}
	}

	private static string ItemName(GameObject itemPrefab)
	{
		if (itemPrefab == null)
		{
			return "";
		}
		ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
		if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null)
		{
			string text = Loc(component.m_itemData.m_shared.m_name);
			if (text.Length > 0 && text[0] != '$' && text[0] != '[')
			{
				return text;
			}
		}
		return ((Object)itemPrefab).name;
	}

	private static bool Usable(string s)
	{
		if (!string.IsNullOrEmpty(s) && s[0] != '$')
		{
			return s[0] != '[';
		}
		return false;
	}

	private static GameObject ValuableDrop(DropTable table)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_002b: 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_0050: Unknown result type (might be due to invalid IL or missing references)
		if (table == null || table.m_drops == null)
		{
			return null;
		}
		foreach (DropData drop in table.m_drops)
		{
			if (drop.m_item != null && !((Object)(object)drop.m_item == (Object)null) && !_ignOre.Contains(((Object)drop.m_item).name))
			{
				return drop.m_item;
			}
		}
		return null;
	}

	private static bool InRange(Vector3 pos)
	{
		//IL_0000: 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)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (pos.y > 2500f)
		{
			return false;
		}
		float num = pos.x - _pp.x;
		float num2 = pos.z - _pp.z;
		return num * num + num2 * num2 <= _r2;
	}

	private static uint Hash(string s)
	{
		uint num = 2166136261u;
		for (int i = 0; i < s.Length; i++)
		{
			num ^= s[i];
			num *= 16777619;
		}
		return num;
	}

	private static void Report(Cat cat, string label, Vector3 pos, float cell)
	{
		//IL_0049: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		if (cell < 1f)
		{
			cell = 1f;
		}
		string[] array = new string[7];
		int num = (int)cat;
		array[0] = num.ToString();
		array[1] = ":";
		array[2] = Hash(label).ToString(CultureInfo.InvariantCulture);
		array[3] = ":";
		array[4] = Mathf.FloorToInt(pos.x / cell).ToString(CultureInfo.InvariantCulture);
		array[5] = ":";
		array[6] = Mathf.FloorToInt(pos.z / cell).ToString(CultureInfo.InvariantCulture);
		string text = string.Concat(array);
		_live.Add(text);
		if (!Store.Entries.ContainsKey(text) && AutoPinsPlugin.On(cat))
		{
			Store.Add(new Entry
			{
				cat = cat,
				label = label,
				pos = pos,
				key = text
			});
		}
	}

	private static void ReportMover(Cat cat, string label, Vector3 pos, ZNetView view)
	{
		//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_005e: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: 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)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)view == (Object)null || !view.IsValid())
		{
			return;
		}
		int num = (int)cat;
		string text = num + ":id:" + ((object)Unsafe.As<ZDOID, ZDOID>(ref view.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString();
		_live.Add(text);
		if (Store.Entries.TryGetValue(text, out var value))
		{
			Vector3 val = value.pos - pos;
			if (((Vector3)(ref val)).sqrMagnitude > 1f)
			{
				value.pos = pos;
				Store.Dirty = true;
			}
			if (value.label != label)
			{
				value.label = label;
				Store.Dirty = true;
			}
		}
		else if (AutoPinsPlugin.On(cat))
		{
			Store.Add(new Entry
			{
				cat = cat,
				label = label,
				pos = pos,
				key = text
			});
		}
	}

	private static void Guard(int slot, string what, Action scan)
	{
		if (_typeFailed[slot])
		{
			return;
		}
		try
		{
			scan();
		}
		catch (Exception ex)
		{
			_typeFailed[slot] = true;
			AutoPinsPlugin.Log.LogWarning((object)("Stopped pinning " + what + " after an error: " + ex));
		}
	}

	public static void Tick()
	{
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: 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)
		if (Time.unscaledTime < _next)
		{
			return;
		}
		_next = Time.unscaledTime + Mathf.Clamp(AutoPinsPlugin.ScanInterval.Value, 1f, 30f);
		if (!AutoPinsPlugin.Enabled.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || (Object)(object)Minimap.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || !Store.EnsureLoaded())
		{
			return;
		}
		Commands.Register();
		RefreshFilters();
		float num = Mathf.Clamp(AutoPinsPlugin.PinRadius.Value, 30f, 100f);
		_pp = ((Component)localPlayer).transform.position;
		_r2 = num * num;
		_live.Clear();
		if (_pp.y <= 2500f)
		{
			float pg = Mathf.Clamp(AutoPinsPlugin.PickableGroup.Value, 1f, 16f);
			float og = Mathf.Clamp(AutoPinsPlugin.OreGroup.Value, 1f, 16f);
			Guard(0, "pickables", delegate
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: 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_00c5: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
				Pickable[] array = Object.FindObjectsByType<Pickable>((FindObjectsSortMode)0);
				foreach (Pickable val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position) && val.m_itemPrefab != null && !((Object)(object)val.m_itemPrefab == (Object)null))
					{
						string name = ((Object)val.m_itemPrefab).name;
						if (!_pickLabel.TryGetValue(name, out var value))
						{
							value = (_ignPick.Contains(name) ? null : ItemName(val.m_itemPrefab));
							_pickLabel[name] = value;
						}
						if (value != null && !val.GetPicked())
						{
							if (AutoPinsPlugin.SkipFarmland.Value)
							{
								Heightmap val2 = Heightmap.FindHeightmap(position);
								if ((Object)(object)val2 != (Object)null && val2.IsCultivated(position))
								{
									continue;
								}
							}
							Report(Cat.Pickable, value, position, pg);
						}
					}
				}
			});
			Guard(1, "large deposits", delegate
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: 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_009d: Unknown result type (might be due to invalid IL or missing references)
				MineRock5[] array = Object.FindObjectsByType<MineRock5>((FindObjectsSortMode)0);
				foreach (MineRock5 val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						string prefabName = Utils.GetPrefabName(((Component)val).gameObject);
						if (!_oreLabel.TryGetValue(prefabName, out var value))
						{
							GameObject val2 = ValuableDrop(val.m_dropItems);
							value = (((Object)(object)val2 == (Object)null) ? null : (Usable(Loc(val.m_name)) ? Loc(val.m_name) : ItemName(val2)));
							_oreLabel[prefabName] = value;
						}
						if (value != null)
						{
							Report(Cat.Ore, value, position, og);
						}
					}
				}
			});
			Guard(2, "deposits", delegate
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: 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_009d: Unknown result type (might be due to invalid IL or missing references)
				MineRock[] array = Object.FindObjectsByType<MineRock>((FindObjectsSortMode)0);
				foreach (MineRock val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						string prefabName = Utils.GetPrefabName(((Component)val).gameObject);
						if (!_oreLabel.TryGetValue(prefabName, out var value))
						{
							GameObject val2 = ValuableDrop(val.m_dropItems);
							value = (((Object)(object)val2 == (Object)null) ? null : (Usable(Loc(val.m_name)) ? Loc(val.m_name) : ItemName(val2)));
							_oreLabel[prefabName] = value;
						}
						if (value != null)
						{
							Report(Cat.Ore, value, position, og);
						}
					}
				}
			});
			Guard(3, "small deposits", delegate
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: 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_0052: 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_005f: 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_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Invalid comparison between Unknown and I4
				//IL_0109: 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_006e: Invalid comparison between Unknown and I4
				//IL_0076: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Invalid comparison between Unknown and I4
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				Destructible[] array = Object.FindObjectsByType<Destructible>((FindObjectsSortMode)0);
				foreach (Destructible val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						string prefabName = Utils.GetPrefabName(((Component)val).gameObject);
						if (!_oreLabel.TryGetValue(prefabName, out var value))
						{
							value = null;
							DamageModifier pickaxe = val.m_damages.m_pickaxe;
							DamageModifier chop = val.m_damages.m_chop;
							bool num6 = (int)pickaxe != 3 && (int)pickaxe != 4;
							bool flag = (int)chop == 3 || (int)chop == 4;
							if (num6 && flag)
							{
								DropOnDestroyed component = ((Component)val).GetComponent<DropOnDestroyed>();
								GameObject val2 = (((Object)(object)component != (Object)null) ? ValuableDrop(component.m_dropWhenDestroyed) : null);
								if ((Object)(object)val2 != (Object)null)
								{
									HoverText component2 = ((Component)val).GetComponent<HoverText>();
									string text = (((Object)(object)component2 != (Object)null) ? Loc(component2.m_text) : "");
									value = (Usable(text) ? text : ItemName(val2));
								}
							}
							_oreLabel[prefabName] = value;
						}
						if (value != null)
						{
							Report(Cat.Ore, value, position, og);
						}
					}
				}
			});
			Guard(4, "dungeon entrances", delegate
			{
				//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)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				Teleport[] array = Object.FindObjectsByType<Teleport>((FindObjectsSortMode)0);
				foreach (Teleport val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						string text = Loc(val.m_hoverText);
						if (!Usable(text))
						{
							text = "Entrance";
						}
						Report(Cat.Dungeon, text, position, 6f);
					}
				}
			});
			Guard(5, "portals", delegate
			{
				//IL_0061: 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_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_001d: 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_0121: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				TeleportWorld[] array = Object.FindObjectsByType<TeleportWorld>((FindObjectsSortMode)0);
				foreach (TeleportWorld val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						string text = "";
						try
						{
							text = val.GetText();
						}
						catch
						{
							text = "";
						}
						string text2 = 3 + ":at:" + Mathf.FloorToInt(position.x / 2f) + ":" + Mathf.FloorToInt(position.z / 2f);
						string text3 = (string.IsNullOrEmpty(text) ? "Portal" : ("Portal: " + text));
						_live.Add(text2);
						if (Store.Entries.TryGetValue(text2, out var value))
						{
							if (value.label != text3)
							{
								value.label = text3;
								Store.Dirty = true;
							}
						}
						else if (AutoPinsPlugin.On(Cat.Portal))
						{
							Store.Add(new Entry
							{
								cat = Cat.Portal,
								label = text3,
								pos = position,
								key = text2
							});
						}
					}
				}
			});
			Guard(6, "carts", delegate
			{
				//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)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				Vagon[] array = Object.FindObjectsByType<Vagon>((FindObjectsSortMode)0);
				foreach (Vagon val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						string text = Loc(val.m_name);
						ReportMover(Cat.Cart, Usable(text) ? text : "Cart", position, ((Component)val).GetComponent<ZNetView>());
					}
				}
			});
			Guard(7, "ships", delegate
			{
				//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)
				//IL_001b: 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)
				Ship[] array = Object.FindObjectsByType<Ship>((FindObjectsSortMode)0);
				foreach (Ship val in array)
				{
					Vector3 position = ((Component)val).transform.position;
					if (InRange(position))
					{
						Piece component = ((Component)val).GetComponent<Piece>();
						string text = (((Object)(object)component != (Object)null) ? Loc(component.m_name) : "");
						ReportMover(Cat.Ship, Usable(text) ? text : "Ship", position, ((Component)val).GetComponent<ZNetView>());
					}
				}
			});
			float num2 = Mathf.Max(8f, Mathf.Min(30f, num - 20f));
			float num3 = num2 * num2;
			List<Entry> list = null;
			foreach (Entry item in Store.Order)
			{
				float num4 = item.pos.x - _pp.x;
				float num5 = item.pos.z - _pp.z;
				if (!(num4 * num4 + num5 * num5 > num3) && !_typeFailed[SlotOf(item.cat)] && (item.cat != Cat.Ore || (!_typeFailed[1] && !_typeFailed[2] && !_typeFailed[3])) && !item.hidden && !_live.Contains(item.key) && ZNetScene.instance.IsAreaReady(item.pos))
				{
					if (list == null)
					{
						list = new List<Entry>();
					}
					list.Add(item);
				}
			}
			if (list != null)
			{
				foreach (Entry item2 in list)
				{
					Store.Remove(item2);
				}
			}
		}
		MapSync.Sync();
		Store.SaveIfDirty(force: false);
	}

	private static int SlotOf(Cat c)
	{
		return c switch
		{
			Cat.Pickable => 0, 
			Cat.Ore => 1, 
			Cat.Dungeon => 4, 
			Cat.Portal => 5, 
			Cat.Cart => 6, 
			_ => 7, 
		};
	}
}
public static class MapSync
{
	private static Minimap _mm;

	private static int _generation = -1;

	private static readonly Dictionary<Entry, PinData> _pinOf = new Dictionary<Entry, PinData>();

	private static FieldRef<Minimap, List<PinData>> _pins;

	private static bool _failed;

	private const float CellSize = 8f;

	private static string NameFor(Entry e)
	{
		if (!AutoPinsPlugin.ShowNames.Value)
		{
			return "";
		}
		return e.label ?? "";
	}

	private static bool Mover(Cat c)
	{
		if (c != Cat.Cart)
		{
			return c == Cat.Ship;
		}
		return true;
	}

	public static int Clear(Func<Entry, bool> which)
	{
		int num = 0;
		Minimap instance = Minimap.instance;
		foreach (Entry item in new List<Entry>(Store.Order))
		{
			if (!which(item))
			{
				continue;
			}
			if ((Object)(object)instance != (Object)null && (Object)(object)instance == (Object)(object)_mm && _pinOf.TryGetValue(item, out var value))
			{
				try
				{
					instance.RemovePin(value);
				}
				catch
				{
				}
				_pinOf.Remove(item);
			}
			Store.Remove(item);
			num++;
		}
		Store.SaveIfDirty(force: true);
		return num;
	}

	public static void Sync()
	{
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_030e: Unknown result type (might be due to invalid IL or missing references)
		//IL_031a: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: 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)
		//IL_048a: Unknown result type (might be due to invalid IL or missing references)
		//IL_048f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0605: Unknown result type (might be due to invalid IL or missing references)
		//IL_060a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0619: Unknown result type (might be due to invalid IL or missing references)
		//IL_061f: Unknown result type (might be due to invalid IL or missing references)
		//IL_053b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0540: Unknown result type (might be due to invalid IL or missing references)
		if (_failed)
		{
			return;
		}
		try
		{
			Minimap instance = Minimap.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if (_pins == null)
			{
				_pins = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");
			}
			if ((Object)(object)instance != (Object)(object)_mm || _generation != Store.Generation)
			{
				_pinOf.Clear();
				_mm = instance;
				_generation = Store.Generation;
			}
			List<PinData> list = _pins.Invoke(instance);
			HashSet<PinData> hashSet = new HashSet<PinData>(list);
			List<Entry> list2 = null;
			foreach (KeyValuePair<Entry, PinData> item in _pinOf)
			{
				if (!hashSet.Contains(item.Value))
				{
					if (list2 == null)
					{
						list2 = new List<Entry>();
					}
					list2.Add(item.Key);
				}
			}
			if (list2 != null)
			{
				bool flag = list2.Count > 5 && list2.Count * 2 > _pinOf.Count;
				foreach (Entry item2 in list2)
				{
					_pinOf.Remove(item2);
					if (!flag && Store.Entries.TryGetValue(item2.key, out var value) && value == item2)
					{
						if (Mover(item2.cat))
						{
							Store.Remove(item2);
							continue;
						}
						item2.hidden = true;
						Store.Dirty = true;
					}
				}
			}
			List<Entry> list3 = null;
			List<Entry> list4 = null;
			foreach (KeyValuePair<Entry, PinData> item3 in _pinOf)
			{
				Entry key = item3.Key;
				PinData value2 = item3.Value;
				Entry value3;
				bool flag2 = Store.Entries.TryGetValue(key.key, out value3) && value3 == key && !key.hidden && AutoPinsPlugin.On(key.cat);
				bool flag3 = value2.m_type == AutoPinsPlugin.IconFor(key.cat) && value2.m_name == NameFor(key);
				if (flag2 && flag3)
				{
					if (value2.m_pos != key.pos)
					{
						value2.m_pos = key.pos;
					}
					continue;
				}
				if (flag2 && !flag3)
				{
					if (list4 == null)
					{
						list4 = new List<Entry>();
					}
					list4.Add(key);
					continue;
				}
				instance.RemovePin(value2);
				if (list3 == null)
				{
					list3 = new List<Entry>();
				}
				list3.Add(key);
			}
			if (list3 != null)
			{
				foreach (Entry item4 in list3)
				{
					_pinOf.Remove(item4);
				}
			}
			if (list4 != null)
			{
				foreach (Entry item5 in list4)
				{
					PinData val = _pinOf[item5];
					bool flag4 = val.m_checked;
					instance.RemovePin(val);
					_pinOf[item5] = instance.AddPin(item5.pos, AutoPinsPlugin.IconFor(item5.cat), NameFor(item5), true, flag4, 0L, default(PlatformUserID));
				}
			}
			List<Entry> list5 = null;
			foreach (Entry item6 in Store.Order)
			{
				if (!item6.hidden && AutoPinsPlugin.On(item6.cat) && !_pinOf.ContainsKey(item6))
				{
					if (list5 == null)
					{
						list5 = new List<Entry>();
					}
					list5.Add(item6);
				}
			}
			if (list5 == null)
			{
				return;
			}
			HashSet<PinData> hashSet2 = new HashSet<PinData>(_pinOf.Values);
			Dictionary<long, List<PinData>> dictionary = new Dictionary<long, List<PinData>>();
			foreach (PinData item7 in list)
			{
				if (item7.m_save && !hashSet2.Contains(item7))
				{
					long key2 = Cell(item7.m_pos.x, item7.m_pos.z);
					if (!dictionary.TryGetValue(key2, out var value4))
					{
						value4 = (dictionary[key2] = new List<PinData>());
					}
					value4.Add(item7);
				}
			}
			foreach (Entry item8 in list5)
			{
				PinType val2 = AutoPinsPlugin.IconFor(item8.cat);
				float num = (Mover(item8.cat) ? 25f : 1f);
				PinData val3 = null;
				float num2 = num * num;
				int num3 = Mathf.CeilToInt(num / 8f);
				int num4 = Mathf.FloorToInt(item8.pos.x / 8f);
				int num5 = Mathf.FloorToInt(item8.pos.z / 8f);
				for (int i = num4 - num3; i <= num4 + num3; i++)
				{
					for (int j = num5 - num3; j <= num5 + num3; j++)
					{
						if (!dictionary.TryGetValue(((long)i << 32) ^ (uint)j, out var value5))
						{
							continue;
						}
						foreach (PinData item9 in value5)
						{
							if (item9.m_type == val2 && !hashSet2.Contains(item9) && (!Mover(item8.cat) || !(item9.m_name != NameFor(item8))))
							{
								float num6 = item9.m_pos.x - item8.pos.x;
								float num7 = item9.m_pos.z - item8.pos.z;
								float num8 = num6 * num6 + num7 * num7;
								if (num8 <= num2)
								{
									num2 = num8;
									val3 = item9;
								}
							}
						}
					}
				}
				if (val3 == null)
				{
					val3 = instance.AddPin(item8.pos, val2, NameFor(item8), true, false, 0L, default(PlatformUserID));
				}
				hashSet2.Add(val3);
				_pinOf[item8] = val3;
			}
		}
		catch (Exception ex)
		{
			_failed = true;
			AutoPinsPlugin.Log.LogWarning((object)("Could not put pins on the map: " + ex));
		}
	}

	private static long Cell(float x, float z)
	{
		return ((long)Mathf.FloorToInt(x / 8f) << 32) ^ (uint)Mathf.FloorToInt(z / 8f);
	}
}
public static class Commands
{
	private static bool _done;

	public static void Register()
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Expected O, but got Unknown
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		if (_done)
		{
			return;
		}
		_done = true;
		try
		{
			new ConsoleCommand("autopins", "clear [ore|pickables|dungeons|portals|carts|ships] - remove the pins Auto Pins made (all of them, or one kind)", new ConsoleEvent(Run), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
		catch (Exception ex)
		{
			AutoPinsPlugin.Log.LogWarning((object)("Could not add the 'autopins' console command: " + ex.Message));
		}
	}

	private static void Run(ConsoleEventArgs args)
	{
		if (((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : "") != "clear")
		{
			args.Context.AddString("Usage: autopins clear [ore|pickables|dungeons|portals|carts|ships]");
			return;
		}
		string text = ((args.Args.Length > 2) ? args.Args[2].ToLowerInvariant() : "");
		int cat = -1;
		if (text.StartsWith("ore") || text.StartsWith("dep"))
		{
			cat = 0;
		}
		else if (text.StartsWith("pick"))
		{
			cat = 1;
		}
		else if (text.StartsWith("dun") || text.StartsWith("cave"))
		{
			cat = 2;
		}
		else if (text.StartsWith("port"))
		{
			cat = 3;
		}
		else if (text.StartsWith("cart"))
		{
			cat = 4;
		}
		else if (text.StartsWith("ship") || text.StartsWith("boat"))
		{
			cat = 5;
		}
		else if (text.Length > 0)
		{
			args.Context.AddString("Unknown kind '" + text + "'.");
			return;
		}
		int num = MapSync.Clear((Entry e) => cat < 0 || e.cat == (Cat)cat);
		args.Context.AddString("Auto Pins: removed " + num + " pin(s). Anything still nearby is pinned again on the next scan unless its category is switched off.");
	}
}