Decompiled source of ParchmentMap v0.3.0

ParchmentMap.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ParchmentMap")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0+330d2e5a67ae95d2e175d8f2ffb0f52d432a864f")]
[assembly: AssemblyProduct("ParchmentMap")]
[assembly: AssemblyTitle("ParchmentMap")]
[assembly: AssemblyVersion("0.3.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 ParchmentMap
{
	internal sealed class PinRecord
	{
		public string Name = "";

		public Vector3 Pos;

		public int Type;

		public bool Checked;

		public PinRecord Clone()
		{
			//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)
			return new PinRecord
			{
				Name = Name,
				Pos = Pos,
				Type = Type,
				Checked = Checked
			};
		}
	}
	internal static class MapBits
	{
		public static byte[] Pack(BitArray bits)
		{
			byte[] array = new byte[(bits.Length + 7) / 8];
			bits.CopyTo(array, 0);
			return array;
		}

		public static BitArray Unpack(byte[] bytes, int bitCount)
		{
			BitArray bitArray = new BitArray(bytes);
			if (bitArray.Length != bitCount)
			{
				bitArray.Length = bitCount;
			}
			return bitArray;
		}

		public static int Count(BitArray bits)
		{
			int[] array = new int[(bits.Length + 31) / 32];
			bits.CopyTo(array, 0);
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				uint num2 = (uint)array[i];
				num2 -= (num2 >> 1) & 0x55555555;
				num2 = (num2 & 0x33333333) + ((num2 >> 2) & 0x33333333);
				num += (int)(((num2 + (num2 >> 4)) & 0xF0F0F0F) * 16843009 >> 24);
			}
			return num;
		}

		public static bool Any(BitArray bits)
		{
			int[] array = new int[(bits.Length + 31) / 32];
			bits.CopyTo(array, 0);
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] != 0)
				{
					return true;
				}
			}
			return false;
		}

		public static bool Centroid(BitArray bits, int size, out float x, out float y)
		{
			byte[] array = Pack(bits);
			double num = 0.0;
			double num2 = 0.0;
			long num3 = 0L;
			for (int i = 0; i < array.Length; i++)
			{
				int num4 = array[i];
				if (num4 == 0)
				{
					continue;
				}
				for (int j = 0; j < 8; j++)
				{
					if ((num4 & (1 << j)) != 0)
					{
						int num5 = i * 8 + j;
						num += (double)(num5 % size);
						num2 += (double)(num5 / size);
						num3++;
					}
				}
			}
			x = ((num3 > 0) ? ((float)(num / (double)num3)) : 0f);
			y = ((num3 > 0) ? ((float)(num2 / (double)num3)) : 0f);
			return num3 > 0;
		}

		public static BitArray Added(BitArray before, BitArray after)
		{
			return new BitArray(after).And(new BitArray(before).Not());
		}

		public static byte[] Compress(byte[] raw)
		{
			using MemoryStream memoryStream = new MemoryStream();
			using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionLevel.Optimal))
			{
				gZipStream.Write(raw, 0, raw.Length);
			}
			return memoryStream.ToArray();
		}

		public static byte[] Decompress(byte[] packed, int offset)
		{
			using MemoryStream stream = new MemoryStream(packed, offset, packed.Length - offset);
			using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress);
			using MemoryStream memoryStream = new MemoryStream();
			gZipStream.CopyTo(memoryStream);
			return memoryStream.ToArray();
		}
	}
	internal static class PinMerge
	{
		public const float SameRadius = 1f;

		public const int MaxTombstones = 256;

		public static bool Near(Vector3 a, Vector3 b, float radius)
		{
			//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 = a.x - b.x;
			float num2 = a.z - b.z;
			return num * num + num2 * num2 < radius * radius;
		}

		public static int IndexNear(List<PinRecord> pins, Vector3 pos)
		{
			//IL_000b: 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)
			for (int i = 0; i < pins.Count; i++)
			{
				if (Near(pins[i].Pos, pos, 1f))
				{
					return i;
				}
			}
			return -1;
		}

		public static bool IsBuried(List<Vector3> tombstones, Vector3 pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < tombstones.Count; i++)
			{
				if (Near(tombstones[i], pos, 1f))
				{
					return true;
				}
			}
			return false;
		}

		public static void Bury(List<Vector3> tombstones, Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!IsBuried(tombstones, pos))
			{
				tombstones.Add(pos);
				if (tombstones.Count > 256)
				{
					tombstones.RemoveRange(0, tombstones.Count - 256);
				}
			}
		}

		public static void Unbury(List<Vector3> tombstones, Vector3 pos)
		{
			//IL_0007: 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)
			tombstones.RemoveAll((Vector3 t) => Near(t, pos, 1f));
		}

		public static List<PinRecord> FromTable(List<PinRecord> mapPins, List<Vector3> tombstones, List<PinRecord> tablePins)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			List<PinRecord> list = new List<PinRecord>();
			foreach (PinRecord tablePin in tablePins)
			{
				if (!IsBuried(tombstones, tablePin.Pos) && IndexNear(mapPins, tablePin.Pos) < 0 && IndexNear(list, tablePin.Pos) < 0)
				{
					list.Add(tablePin.Clone());
				}
			}
			return list;
		}

		public static void IntoTable(List<PinRecord> tablePins, List<PinRecord> mapPins, List<Vector3> tombstones)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			tablePins.RemoveAll((PinRecord p) => IsBuried(tombstones, p.Pos));
			foreach (PinRecord mapPin in mapPins)
			{
				int num = IndexNear(tablePins, mapPin.Pos);
				if (num >= 0)
				{
					tablePins[num] = mapPin.Clone();
				}
				else
				{
					tablePins.Add(mapPin.Clone());
				}
			}
		}
	}
	internal sealed class ZoneRevs
	{
		private const int Offset = 512;

		private const int Bits = 10;

		private readonly Dictionary<int, int> revs = new Dictionary<int, int>();

		public int Count => revs.Count;

		public static bool InRange(int zoneX, int zoneY)
		{
			if (zoneX > -512 && zoneX < 512 && zoneY > -512)
			{
				return zoneY < 512;
			}
			return false;
		}

		public static int Key(int zoneX, int zoneY)
		{
			return (zoneY + 512 << 10) | (zoneX + 512);
		}

		public static void Split(int key, out int zoneX, out int zoneY)
		{
			zoneX = (key & 0x3FF) - 512;
			zoneY = (key >> 10) - 512;
		}

		public int Get(int zoneX, int zoneY)
		{
			if (!InRange(zoneX, zoneY) || !revs.TryGetValue(Key(zoneX, zoneY), out var value))
			{
				return 0;
			}
			return value;
		}

		public bool Raise(int zoneX, int zoneY, int rev)
		{
			if (InRange(zoneX, zoneY))
			{
				return RaiseKey(Key(zoneX, zoneY), rev);
			}
			return false;
		}

		public bool RaiseAll(ZoneRevs other)
		{
			bool flag = false;
			foreach (KeyValuePair<int, int> rev in other.revs)
			{
				flag |= RaiseKey(rev.Key, rev.Value);
			}
			return flag;
		}

		public int GetKey(int key)
		{
			if (!revs.TryGetValue(key, out var value))
			{
				return 0;
			}
			return value;
		}

		public bool RaiseKey(int key, int rev)
		{
			if (rev <= 0 || (revs.TryGetValue(key, out var value) && value >= rev))
			{
				return false;
			}
			revs[key] = rev;
			return true;
		}

		public void Clear()
		{
			revs.Clear();
		}

		public int CountAlsoIn(ZoneRevs other)
		{
			int num = 0;
			foreach (int key in revs.Keys)
			{
				num += (other.revs.ContainsKey(key) ? 1 : 0);
			}
			return num;
		}

		public ZoneRevs Clone()
		{
			ZoneRevs zoneRevs = new ZoneRevs();
			foreach (KeyValuePair<int, int> rev in revs)
			{
				zoneRevs.revs[rev.Key] = rev.Value;
			}
			return zoneRevs;
		}

		public void Write(BinaryWriter w)
		{
			List<int> list = new List<int>(revs.Keys);
			list.Sort();
			MapIO.WriteVar(w, list.Count);
			int num = 0;
			foreach (int item in list)
			{
				MapIO.WriteVar(w, item - num);
				MapIO.WriteVar(w, revs[item]);
				num = item;
			}
		}

		public static ZoneRevs Read(BinaryReader r)
		{
			ZoneRevs zoneRevs = new ZoneRevs();
			int num = MapIO.ReadVar(r);
			if (num > 1048576)
			{
				throw new InvalidDataException("zone snapshot list of " + num);
			}
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				num2 += MapIO.ReadVar(r);
				int num3 = MapIO.ReadVar(r);
				if (num2 >= 1048576)
				{
					throw new InvalidDataException("zone snapshot list runs out of the world");
				}
				if (num3 > 0)
				{
					zoneRevs.revs[num2] = num3;
				}
			}
			return zoneRevs;
		}
	}
	internal static class ZoneGrid
	{
		public const float ZoneSize = 64f;

		public const float Overhang = 64f;

		public static int ZoneOf(float w)
		{
			return (int)Math.Floor(((double)w + 32.0) / 64.0);
		}

		public static List<int> Touching(float x, float z, float radius)
		{
			List<int> list = new List<int>();
			for (int i = ZoneOf(z - radius); i <= ZoneOf(z + radius); i++)
			{
				for (int j = ZoneOf(x - radius); j <= ZoneOf(x + radius); j++)
				{
					float num = Math.Max((float)j * 64f - 32f, Math.Min(x, (float)j * 64f + 32f));
					float num2 = Math.Max((float)i * 64f - 32f, Math.Min(z, (float)i * 64f + 32f));
					if ((num - x) * (num - x) + (num2 - z) * (num2 - z) <= radius * radius && ZoneRevs.InRange(j, i))
					{
						list.Add(ZoneRevs.Key(j, i));
					}
				}
			}
			return list;
		}

		public static List<int> WithoutRev(BitArray cells, int textureSize, float pixelSize, ZoneRevs revs)
		{
			HashSet<int> hashSet = new HashSet<int>();
			byte[] array = MapBits.Pack(cells);
			float num = textureSize / 2;
			int num2 = -1;
			for (int i = 0; i < array.Length; i++)
			{
				int num3 = array[i];
				if (num3 == 0)
				{
					continue;
				}
				for (int j = 0; j < 8; j++)
				{
					if ((num3 & (1 << j)) != 0)
					{
						int num4 = i * 8 + j;
						int zoneX = ZoneOf(((float)(num4 % textureSize) - num) * pixelSize);
						int zoneY = ZoneOf(((float)(num4 / textureSize) - num) * pixelSize);
						int num5 = ZoneRevs.Key(zoneX, zoneY);
						if (num5 != num2 && ZoneRevs.InRange(zoneX, zoneY))
						{
							num2 = num5;
							hashSet.Add(num5);
						}
					}
				}
			}
			HashSet<int> hashSet2 = new HashSet<int>();
			foreach (int item in hashSet)
			{
				ZoneRevs.Split(item, out var zoneX2, out var zoneY2);
				for (int k = -1; k <= 1; k++)
				{
					for (int l = -1; l <= 1; l++)
					{
						if (ZoneRevs.InRange(zoneX2 + l, zoneY2 + k) && revs.Get(zoneX2 + l, zoneY2 + k) == 0)
						{
							hashSet2.Add(ZoneRevs.Key(zoneX2 + l, zoneY2 + k));
						}
					}
				}
			}
			List<int> list = new List<int>(hashSet2);
			list.Sort();
			return list;
		}
	}
	internal sealed class MapData
	{
		public const string CustomDataKey = "q8pm_map";

		public const string StatsKey = "q8pm_stats";

		private const byte FormatVersion = 2;

		public long WorldUid;

		public int TextureSize;

		public BitArray Explored;

		public BitArray Pending;

		public List<PinRecord> Pins = new List<PinRecord>();

		public List<Vector3> Tombstones = new List<Vector3>();

		public bool HasView;

		public float ViewX;

		public float ViewZ;

		public ZoneRevs DrawnRevs = new ZoneRevs();

		public ZoneRevs PendingRevs = new ZoneRevs();

		public bool SurveyChecked;

		public static MapData CreateNew(long worldUid, int textureSize)
		{
			return new MapData
			{
				WorldUid = worldUid,
				TextureSize = textureSize,
				Explored = new BitArray(textureSize * textureSize),
				Pending = new BitArray(textureSize * textureSize)
			};
		}

		public string ToBlob()
		{
			//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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(WorldUid);
			binaryWriter.Write(TextureSize);
			MapIO.WriteBits(binaryWriter, Explored);
			bool flag = MapBits.Any(Pending);
			binaryWriter.Write(flag);
			if (flag)
			{
				MapIO.WriteBits(binaryWriter, Pending);
			}
			MapIO.WritePins(binaryWriter, Pins);
			binaryWriter.Write(Tombstones.Count);
			foreach (Vector3 tombstone in Tombstones)
			{
				binaryWriter.Write(tombstone.x);
				binaryWriter.Write(tombstone.z);
			}
			binaryWriter.Write(HasView);
			binaryWriter.Write(ViewX);
			binaryWriter.Write(ViewZ);
			DrawnRevs.Write(binaryWriter);
			PendingRevs.Write(binaryWriter);
			binaryWriter.Flush();
			return Convert.ToBase64String(MapIO.Wrap(2, memoryStream.ToArray()));
		}

		public static MapData FromBlob(string blob, out string error)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			try
			{
				byte version;
				using BinaryReader binaryReader = new BinaryReader(new MemoryStream(MapIO.Unwrap(Convert.FromBase64String(blob), 2, out version)));
				MapData mapData = new MapData();
				mapData.WorldUid = binaryReader.ReadInt64();
				mapData.TextureSize = binaryReader.ReadInt32();
				int num = mapData.TextureSize * mapData.TextureSize;
				mapData.Explored = MapIO.ReadBits(binaryReader, num);
				mapData.Pending = (binaryReader.ReadBoolean() ? MapIO.ReadBits(binaryReader, num) : new BitArray(num));
				mapData.Pins = MapIO.ReadPins(binaryReader);
				int num2 = binaryReader.ReadInt32();
				for (int i = 0; i < num2; i++)
				{
					float num3 = binaryReader.ReadSingle();
					float num4 = binaryReader.ReadSingle();
					mapData.Tombstones.Add(new Vector3(num3, 0f, num4));
				}
				mapData.HasView = binaryReader.ReadBoolean();
				mapData.ViewX = binaryReader.ReadSingle();
				mapData.ViewZ = binaryReader.ReadSingle();
				if (version >= 2)
				{
					mapData.DrawnRevs = ZoneRevs.Read(binaryReader);
					mapData.PendingRevs = ZoneRevs.Read(binaryReader);
				}
				return mapData;
			}
			catch (Exception ex)
			{
				error = ex.GetType().Name + ": " + ex.Message;
				return null;
			}
		}
	}
	internal sealed class TableData
	{
		public const string ZdoKey = "q8pm_table";

		private const byte FormatVersion = 2;

		public int TextureSize;

		public BitArray Explored;

		public List<PinRecord> Pins = new List<PinRecord>();

		public ZoneRevs Revs = new ZoneRevs();

		public static TableData CreateNew(int textureSize)
		{
			return new TableData
			{
				TextureSize = textureSize,
				Explored = new BitArray(textureSize * textureSize)
			};
		}

		public byte[] ToBytes()
		{
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(TextureSize);
			MapIO.WriteBits(binaryWriter, Explored);
			MapIO.WritePins(binaryWriter, Pins);
			Revs.Write(binaryWriter);
			binaryWriter.Flush();
			return MapIO.Wrap(2, memoryStream.ToArray());
		}

		public static TableData FromBytes(byte[] bytes, out string error)
		{
			error = null;
			try
			{
				byte version;
				using BinaryReader binaryReader = new BinaryReader(new MemoryStream(MapIO.Unwrap(bytes, 2, out version)));
				TableData tableData = new TableData();
				tableData.TextureSize = binaryReader.ReadInt32();
				tableData.Explored = MapIO.ReadBits(binaryReader, tableData.TextureSize * tableData.TextureSize);
				tableData.Pins = MapIO.ReadPins(binaryReader);
				if (version >= 2)
				{
					tableData.Revs = ZoneRevs.Read(binaryReader);
				}
				return tableData;
			}
			catch (Exception ex)
			{
				error = ex.GetType().Name + ": " + ex.Message;
				return null;
			}
		}
	}
	internal static class MapIO
	{
		public static byte[] Wrap(byte version, byte[] raw)
		{
			byte[] array = MapBits.Compress(raw);
			byte[] array2 = new byte[array.Length + 1];
			array2[0] = version;
			Buffer.BlockCopy(array, 0, array2, 1, array.Length);
			return array2;
		}

		public static byte[] Unwrap(byte[] bytes, byte newestVersion, out byte version)
		{
			if (bytes == null || bytes.Length < 2)
			{
				throw new InvalidDataException("empty data");
			}
			version = bytes[0];
			if (version < 1 || version > newestVersion)
			{
				throw new InvalidDataException("unknown format version " + version);
			}
			return MapBits.Decompress(bytes, 1);
		}

		public static void WriteVar(BinaryWriter w, int value)
		{
			uint num;
			for (num = (uint)value; num >= 128; num >>= 7)
			{
				w.Write((byte)(num | 0x80));
			}
			w.Write((byte)num);
		}

		public static int ReadVar(BinaryReader r)
		{
			int num = 0;
			for (int i = 0; i <= 28; i += 7)
			{
				byte b = r.ReadByte();
				num |= (b & 0x7F) << i;
				if ((b & 0x80) == 0)
				{
					if (num < 0)
					{
						throw new InvalidDataException("negative number");
					}
					return num;
				}
			}
			throw new InvalidDataException("number too long");
		}

		public static void WriteBits(BinaryWriter w, BitArray bits)
		{
			byte[] array = MapBits.Pack(bits);
			w.Write(array.Length);
			w.Write(array);
		}

		public static BitArray ReadBits(BinaryReader r, int bitCount)
		{
			int num = r.ReadInt32();
			if (num != (bitCount + 7) / 8)
			{
				throw new InvalidDataException("bitmap size " + num + " does not match map size");
			}
			return MapBits.Unpack(r.ReadBytes(num), bitCount);
		}

		public static void WritePins(BinaryWriter w, List<PinRecord> pins)
		{
			w.Write(pins.Count);
			foreach (PinRecord pin in pins)
			{
				w.Write(pin.Name ?? "");
				w.Write(pin.Pos.x);
				w.Write(pin.Pos.y);
				w.Write(pin.Pos.z);
				w.Write(pin.Type);
				w.Write(pin.Checked);
			}
		}

		public static List<PinRecord> ReadPins(BinaryReader r)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			int num = r.ReadInt32();
			List<PinRecord> list = new List<PinRecord>(num);
			for (int i = 0; i < num; i++)
			{
				PinRecord pinRecord = new PinRecord();
				pinRecord.Name = r.ReadString();
				float num2 = r.ReadSingle();
				float num3 = r.ReadSingle();
				float num4 = r.ReadSingle();
				pinRecord.Pos = new Vector3(num2, num3, num4);
				pinRecord.Type = r.ReadInt32();
				pinRecord.Checked = r.ReadBoolean();
				list.Add(pinRecord);
			}
			return list;
		}
	}
	internal static class MapItem
	{
		public const string PrefabName = "Q8_ParchmentMap";

		public const string NameToken = "$item_q8pm_parchment";

		public const string DescriptionToken = "$item_q8pm_parchment_desc";

		private const string BasePrefabName = "DeerHide";

		private const string HandModelName = "model";

		private const float SheetWidth = 0.44f;

		private const float SheetHeight = 0.33f;

		private static readonly FieldRef<VisEquipment, GameObject> RightItemInstanceRef = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_rightItemInstance");

		private static Transform handModel;

		internal static bool IsParchment(ItemData item)
		{
			if (item != null && item.m_shared != null)
			{
				return item.m_shared.m_name == "$item_q8pm_parchment";
			}
			return false;
		}

		internal static void Register()
		{
			//IL_00b6: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: 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_0074: Invalid comparison between Unknown and I4
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("Q8_ParchmentMap", "DeerHide");
			if ((Object)(object)val == (Object)null)
			{
				ParchmentMapPlugin.Log.LogError((object)"Base prefab DeerHide not found, the parchment map is not added.");
				return;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				ParchmentMapPlugin.Log.LogError((object)"Base prefab DeerHide has no ItemDrop, the parchment map is not added.");
				return;
			}
			bool flag = (int)SystemInfo.graphicsDeviceType == 4;
			if (!flag)
			{
				try
				{
					BuildVisuals(val);
				}
				catch (Exception ex)
				{
					ParchmentMapPlugin.Log.LogWarning((object)("Could not build the parchment model: " + ex.Message));
				}
			}
			component.m_autoDestroy = false;
			SharedData shared = component.m_itemData.m_shared;
			shared.m_itemType = (ItemType)19;
			shared.m_animationState = (AnimationState)5;
			shared.m_attachOverride = (ItemType)0;
			shared.m_maxStackSize = 1;
			shared.m_autoStack = false;
			shared.m_maxQuality = 1;
			shared.m_weight = 0.3f;
			shared.m_value = 0;
			shared.m_teleportable = true;
			shared.m_questItem = false;
			shared.m_equipDuration = 0.5f;
			shared.m_useDurability = false;
			shared.m_canBeReparied = false;
			shared.m_buildPieces = null;
			shared.m_equipStatusEffect = null;
			shared.m_attackStatusEffect = null;
			shared.m_consumeStatusEffect = null;
			shared.m_setStatusEffect = null;
			shared.m_setName = "";
			shared.m_setSize = 0;
			shared.m_food = 0f;
			shared.m_foodStamina = 0f;
			shared.m_foodEitr = 0f;
			shared.m_variants = 0;
			shared.m_attack = (Attack)(((object)shared.m_attack) ?? ((object)new Attack()));
			shared.m_secondaryAttack = (Attack)(((object)shared.m_secondaryAttack) ?? ((object)new Attack()));
			shared.m_attack.m_attackAnimation = "";
			shared.m_secondaryAttack.m_attackAnimation = "";
			ItemConfig val2 = new ItemConfig
			{
				Name = "$item_q8pm_parchment",
				Description = "$item_q8pm_parchment_desc"
			};
			if (!flag)
			{
				val2.CraftingStation = CraftingStations.Workbench;
				val2.MinStationLevel = 1;
				val2.Amount = 1;
				val2.Icons = (Sprite[])(object)new Sprite[1] { LoadIcon() };
				val2.Requirements = ParseRecipe(ParchmentMapPlugin.Recipe.Value).ToArray();
			}
			if (!ItemManager.Instance.AddItem(new CustomItem(val, false, val2)))
			{
				ParchmentMapPlugin.Log.LogError((object)"Jotunn rejected the parchment map item.");
			}
		}

		internal static List<RequirementConfig> ParseRecipe(string text)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			List<RequirementConfig> list = new List<RequirementConfig>();
			string[] array = (text ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text2 in array)
			{
				string[] array2 = text2.Split(new char[1] { ':' });
				if (array2.Length != 2 || array2[0].Trim().Length == 0 || !int.TryParse(array2[1].Trim(), out var result) || result < 1)
				{
					ParchmentMapPlugin.Log.LogWarning((object)("Recipe entry '" + text2 + "' is ignored, expected Item:amount."));
				}
				else
				{
					list.Add(new RequirementConfig(array2[0].Trim(), result, 0, true));
				}
			}
			if (list.Count == 0)
			{
				list.Add(new RequirementConfig("DeerHide", 2, 0, true));
			}
			return list;
		}

		internal static void ApplyRecipeToObjectDB()
		{
			//IL_00c3: 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)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			Recipe val = ObjectDB.instance.m_recipes.Find((Recipe r) => (Object)(object)r != (Object)null && (Object)(object)r.m_item != (Object)null && ((Object)((Component)r.m_item).gameObject).name == "Q8_ParchmentMap");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			List<Requirement> list = new List<Requirement>();
			foreach (RequirementConfig item in ParseRecipe(ParchmentMapPlugin.Recipe.Value))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Item);
				ItemDrop val2 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val2 == (Object)null)
				{
					ParchmentMapPlugin.Log.LogWarning((object)("Recipe item '" + item.Item + "' does not exist and is ignored."));
					continue;
				}
				list.Add(new Requirement
				{
					m_resItem = val2,
					m_amount = item.Amount,
					m_amountPerLevel = 0,
					m_recover = true
				});
			}
			if (list.Count > 0)
			{
				val.m_resources = list.ToArray();
			}
		}

		private static void BuildVisuals(GameObject prefab)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer componentInChildren = prefab.GetComponentInChildren<MeshRenderer>(true);
			Material val = (((Object)(object)componentInChildren != (Object)null && (Object)(object)((Renderer)componentInChildren).sharedMaterial != (Object)null) ? new Material(((Renderer)componentInChildren).sharedMaterial) : new Material(Shader.Find("Standard")));
			((Object)val).name = "q8pm_parchment";
			val.mainTexture = (Texture)(object)LoadTexture("parchment.png", repeat: false);
			val.color = Color.white;
			if (val.HasProperty("_Cull"))
			{
				val.SetFloat("_Cull", 0f);
			}
			string[] array = new string[3] { "_BumpMap", "_MetallicGlossMap", "_EmissionMap" };
			foreach (string text in array)
			{
				if (val.HasProperty(text))
				{
					val.SetTexture(text, (Texture)null);
				}
			}
			array = new string[2] { "_Metallic", "_Glossiness" };
			foreach (string text2 in array)
			{
				if (val.HasProperty(text2))
				{
					val.SetFloat(text2, 0f);
				}
			}
			for (int num = prefab.transform.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)prefab.transform.GetChild(num)).gameObject);
			}
			LODGroup component = prefab.GetComponent<LODGroup>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			Mesh mesh = BuildSheetMesh();
			GameObject obj = CreateSheet("ground", prefab.transform, mesh, val);
			obj.transform.localPosition = new Vector3(0f, 0.02f, 0f);
			obj.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
			GameObject val2 = new GameObject("attach");
			val2.layer = prefab.layer;
			val2.transform.SetParent(prefab.transform, false);
			handModel = CreateSheet("model", val2.transform, mesh, val).transform;
			val2.SetActive(false);
			ApplyHandPose();
			if ((Object)(object)prefab.GetComponentInChildren<Collider>(true) == (Object)null)
			{
				BoxCollider obj2 = prefab.AddComponent<BoxCollider>();
				obj2.size = new Vector3(0.44f, 0.04f, 0.33f);
				obj2.center = new Vector3(0f, 0.02f, 0f);
			}
		}

		private static GameObject CreateSheet(string name, Transform parent, Mesh mesh, Material material)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			GameObject val = new GameObject(name)
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = material;
			return val;
		}

		private static Mesh BuildSheetMesh()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: 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_014f: 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_015d: 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_016c: Expected O, but got Unknown
			int num = 9;
			Vector3[] array = (Vector3[])(object)new Vector3[num * 2];
			Vector3[] array2 = (Vector3[])(object)new Vector3[num * 2];
			Vector2[] array3 = (Vector2[])(object)new Vector2[num * 2];
			for (int i = 0; i < num; i++)
			{
				float num2 = (float)i / 8f;
				float num3 = (num2 - 0.5f) * 0.44f;
				float num4 = -0.018f * Mathf.Sin(num2 * (float)Math.PI);
				for (int j = 0; j < 2; j++)
				{
					int num5 = i * 2 + j;
					array[num5] = new Vector3(num3, ((float)j - 0.5f) * 0.33f, num4);
					array2[num5] = Vector3.back;
					array3[num5] = new Vector2(num2, (float)j);
				}
			}
			int[] array4 = new int[48];
			int num6 = 0;
			for (int k = 0; k < 8; k++)
			{
				int num7 = k * 2;
				int num8 = num7 + 1;
				int num9 = num7 + 2;
				int num10 = num7 + 3;
				array4[num6++] = num7;
				array4[num6++] = num8;
				array4[num6++] = num9;
				array4[num6++] = num9;
				array4[num6++] = num8;
				array4[num6++] = num10;
			}
			Mesh val = new Mesh
			{
				name = "q8pm_sheet",
				vertices = array,
				normals = array2,
				uv = array3,
				triangles = array4
			};
			val.RecalculateBounds();
			return val;
		}

		internal static void ApplyHandPose()
		{
			if ((Object)(object)handModel != (Object)null)
			{
				SetPose(handModel);
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && IsParchment(((Humanoid)localPlayer).RightItem))
			{
				VisEquipment component = ((Component)localPlayer).GetComponent<VisEquipment>();
				GameObject val = (((Object)(object)component != (Object)null) ? RightItemInstanceRef.Invoke(component) : null);
				Transform val2 = (((Object)(object)val != (Object)null) ? val.transform.Find("model") : null);
				if ((Object)(object)val2 != (Object)null)
				{
					SetPose(val2);
				}
			}
		}

		private static void SetPose(Transform model)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0026: 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)
			model.localPosition = ParchmentMapPlugin.HandPosition.Value;
			model.localRotation = Quaternion.Euler(ParchmentMapPlugin.HandRotation.Value);
			model.localScale = Vector3.one * Mathf.Clamp(ParchmentMapPlugin.HandScale.Value, 0.1f, 5f);
		}

		private static Sprite LoadIcon()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTexture("icon.png", repeat: false);
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
		}

		private static Texture2D LoadTexture(string resourceName, bool repeat)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
				if (stream == null)
				{
					throw new FileNotFoundException("embedded resource is missing");
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule");
				MethodInfo methodInfo = ((type != null) ? type.GetMethod("LoadImage", new Type[2]
				{
					typeof(Texture2D),
					typeof(byte[])
				}) : null);
				if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2] { val, array }))
				{
					throw new InvalidDataException("the image could not be decoded");
				}
			}
			catch (Exception ex)
			{
				ParchmentMapPlugin.Log.LogWarning((object)("Could not load " + resourceName + ": " + ex.Message));
				Color val2 = default(Color);
				((Color)(ref val2))..ctor(0.85f, 0.75f, 0.55f, 1f);
				val.SetPixels((Color[])(object)new Color[4] { val2, val2, val2, val2 });
				val.Apply();
			}
			((Object)val).name = "q8pm_" + resourceName;
			((Texture)val).wrapMode = (TextureWrapMode)(!repeat);
			return val;
		}
	}
	internal static class MapSession
	{
		private static readonly FieldRef<Minimap, BitArray> ExploredRef = AccessTools.FieldRefAccess<Minimap, BitArray>("m_explored");

		private static readonly FieldRef<Minimap, BitArray> ExploredOthersRef = AccessTools.FieldRefAccess<Minimap, BitArray>("m_exploredOthers");

		private static readonly FieldRef<Minimap, Texture2D> FogTextureRef = AccessTools.FieldRefAccess<Minimap, Texture2D>("m_fogTexture");

		private static readonly FieldRef<Minimap, bool> HasGeneratedRef = AccessTools.FieldRefAccess<Minimap, bool>("m_hasGenerated");

		private static readonly FieldRef<Minimap, List<PinData>> PinsRef = AccessTools.FieldRefAccess<Minimap, List<PinData>>("m_pins");

		private static readonly FieldRef<Minimap, Vector3> MapOffsetRef = AccessTools.FieldRefAccess<Minimap, Vector3>("m_mapOffset");

		private static readonly FieldRef<Minimap, bool> PinUpdateRequiredRef = AccessTools.FieldRefAccess<Minimap, bool>("m_pinUpdateRequired");

		private static readonly MethodInfo LoadMapDataMethod = AccessTools.Method(typeof(Minimap), "LoadMapData", (Type[])null, (Type[])null);

		private static readonly Func<Minimap, Vector3, bool> IsExploredMethod = AccessTools.MethodDelegate<Func<Minimap, Vector3, bool>>(AccessTools.Method(typeof(Minimap), "IsExplored", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Color32 FogHidden = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);

		private static readonly Color32 FogSeen = new Color32((byte)0, byte.MaxValue, byte.MaxValue, byte.MaxValue);

		private const double WorldRadius = 10500.0;

		internal static bool InTouchZoom;

		private static MapData data;

		private static bool dirty;

		private static bool noMapByRule;

		private static bool wasManaging;

		private static bool fogLoaded;

		private static ItemData cachedItem;

		private static string cachedBlob;

		private static ItemData rejectedItem;

		private static Color32[] fogBuffer;

		private static bool faulted;

		private const float SurveyAgainAfter = 120f;

		private const int CheckBatch = 96;

		private const float CheckTimeout = 20f;

		private const float AskAgainAfter = 300f;

		private static readonly Dictionary<int, float> surveyedAt = new Dictionary<int, float>();

		private static List<int> checkQueue;

		private static bool checkInFlight;

		private static float checkSentAt;

		private static float surveysOffUntil;

		internal static ItemData Held { get; private set; }

		internal static bool IsActive => Held != null;

		internal static bool Loading { get; private set; }

		internal static bool PictureMode
		{
			get
			{
				if (IsActive)
				{
					return !ParchmentMapPlugin.LiveMarkers.Value;
				}
				return false;
			}
		}

		internal static Vector3 Anchor { get; private set; }

		internal static void ResetSession()
		{
			faulted = false;
			Held = null;
			data = null;
			dirty = false;
			wasManaging = false;
			fogLoaded = false;
			cachedItem = null;
			cachedBlob = null;
			rejectedItem = null;
			fogBuffer = null;
			Loading = false;
			surveyedAt.Clear();
			checkQueue = null;
			checkInFlight = false;
			surveysOffUntil = 0f;
		}

		internal static void Tick(Minimap minimap)
		{
			if (faulted)
			{
				return;
			}
			try
			{
				TickCore(minimap);
			}
			catch (Exception ex)
			{
				faulted = true;
				Held = null;
				ParchmentMapPlugin.Log.LogError((object)("Parchment map is switched off until you re-enter the world: " + ex));
			}
		}

		private static void TickCore(Minimap minimap)
		{
			if (!HasGeneratedRef.Invoke(minimap))
			{
				return;
			}
			if (ParchmentMapPlugin.ReplaceVanillaMap.Value)
			{
				ApplyReplaceRule();
			}
			else if (noMapByRule)
			{
				Game.UpdateNoMap();
			}
			bool noMap = Game.m_noMap;
			if (noMap != wasManaging)
			{
				wasManaging = noMap;
				if (noMap)
				{
					BeginManaging(minimap);
				}
				else
				{
					EndManaging(minimap);
				}
			}
			if (noMap)
			{
				Player localPlayer = Player.m_localPlayer;
				ItemData val = (((Object)(object)localPlayer != (Object)null && !((Character)localPlayer).IsDead()) ? ((Humanoid)localPlayer).RightItem : null);
				if (Held != null && val != Held)
				{
					Deactivate();
				}
				if (val != rejectedItem)
				{
					rejectedItem = null;
				}
				if (Held == null && val != null && rejectedItem == null && MapItem.IsParchment(val))
				{
					Activate(minimap, localPlayer, val);
				}
				if (Held != null)
				{
					PumpSurveyCheck();
				}
			}
		}

		internal static void OnNoMapUpdated()
		{
			noMapByRule = false;
			ApplyReplaceRule();
		}

		private static void ApplyReplaceRule()
		{
			if (!Game.m_noMap && ParchmentMapPlugin.ReplaceVanillaMap.Value)
			{
				Game.m_noMap = true;
				noMapByRule = true;
				Minimap instance = Minimap.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.SetMapMode((MapMode)0);
				}
			}
		}

		private static void BeginManaging(Minimap minimap)
		{
			minimap.Reset();
			RemoveSavedPins(minimap);
			fogLoaded = false;
			cachedItem = null;
			cachedBlob = null;
			ParchmentMapPlugin.Log.LogInfo((object)(noMapByRule ? "This world has the map enabled: the parchment map replaces it (rule ReplaceVanillaMap)" : "This world has no map: the only map is the parchment map"));
		}

		private static void EndManaging(Minimap minimap)
		{
			Deactivate();
			fogLoaded = false;
			cachedItem = null;
			cachedBlob = null;
			fogBuffer = null;
			if ((Object)(object)Game.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			try
			{
				minimap.Reset();
				LoadMapDataMethod.Invoke(minimap, null);
			}
			catch (Exception ex)
			{
				ParchmentMapPlugin.Log.LogWarning((object)("Could not restore the character's own map: " + ex.Message));
			}
		}

		private static void Activate(Minimap minimap, Player player, ItemData item)
		{
			//IL_0168: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			int textureSize = minimap.m_textureSize;
			long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0);
			item.m_customData.TryGetValue("q8pm_map", out var value);
			if (!fogLoaded || data == null || item != cachedItem || !(value == cachedBlob))
			{
				MapData mapData;
				if (string.IsNullOrEmpty(value))
				{
					mapData = MapData.CreateNew(num, textureSize);
				}
				else
				{
					mapData = MapData.FromBlob(value, out var error);
					if (mapData == null || mapData.TextureSize != textureSize)
					{
						ParchmentMapPlugin.Log.LogWarning((object)("Map data of this parchment cannot be read: " + (error ?? ("map size " + mapData.TextureSize + " instead of " + textureSize))));
						Reject(player, item, "$q8pm_msg_unreadable");
						return;
					}
					if (mapData.WorldUid != num)
					{
						Reject(player, item, "$q8pm_msg_otherworld");
						return;
					}
				}
				data = mapData;
				SetExplored(minimap, data.Explored);
				cachedItem = item;
				cachedBlob = value;
				fogLoaded = true;
				dirty = false;
				ParchmentMapPlugin.Log.LogInfo((object)("Parchment map in hand: " + Describe()));
			}
			Held = item;
			Anchor = (Vector3)(data.HasView ? new Vector3(data.ViewX, 0f, data.ViewZ) : CentreOf(minimap, data.Explored));
			MapOffsetRef.Invoke(minimap) = Vector3.zero;
			ReplacePins(minimap, data.Pins);
			if (!ParchmentMapPlugin.RevealAtTableOnly.Value && (MapBits.Any(data.Pending) || data.PendingRevs.Count > 0) && CommitPending(minimap))
			{
				UploadFog(minimap);
			}
			surveyedAt.Clear();
			StartSurveyCheck(minimap);
			SurveyAround(((Component)player).transform.position, minimap.m_exploreRadius * ParchmentMapPlugin.ExploreRadiusMultiplier.Value);
		}

		private static void Reject(Player player, ItemData item, string message)
		{
			rejectedItem = item;
			((Character)player).Message((MessageType)2, message, 0, (Sprite)null, false);
		}

		internal static void Deactivate()
		{
			//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)
			if (Held != null)
			{
				Flush();
				Held = null;
				checkQueue = null;
				checkInFlight = false;
				Minimap instance = Minimap.instance;
				if ((Object)(object)instance != (Object)null)
				{
					RemoveSavedPins(instance);
					MapOffsetRef.Invoke(instance) = Vector3.zero;
					instance.SetMapMode((MapMode)0);
				}
			}
		}

		internal static void MarkDirty()
		{
			dirty = true;
		}

		internal static void Flush()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			if (Held != null && data != null && !((Object)(object)instance == (Object)null))
			{
				FoldView(instance);
				List<PinRecord> list = CapturePins(instance);
				if (dirty || !SamePins(list, data.Pins))
				{
					data.Explored = new BitArray(ExploredRef.Invoke(instance));
					data.Pins = list;
					data.HasView = true;
					data.ViewX = Anchor.x;
					data.ViewZ = Anchor.z;
					string text = data.ToBlob();
					Held.m_customData["q8pm_map"] = text;
					Held.m_customData["q8pm_stats"] = BuildStats(instance);
					cachedItem = Held;
					cachedBlob = text;
					dirty = false;
					ParchmentMapPlugin.Log.LogInfo((object)("Map saved into the parchment: " + Describe() + ", " + text.Length / 1024 + " KB"));
				}
			}
		}

		internal static void FoldView(Minimap minimap)
		{
			//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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (PictureMode)
			{
				Vector3 val = MapOffsetRef.Invoke(minimap);
				if (val.x != 0f || val.z != 0f)
				{
					Anchor = new Vector3(Anchor.x + val.x, 0f, Anchor.z + val.z);
					MapOffsetRef.Invoke(minimap) = Vector3.zero;
					dirty = true;
				}
			}
		}

		internal static void LookAt(Minimap minimap, Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			Anchor = new Vector3(point.x, 0f, point.z);
			MapOffsetRef.Invoke(minimap) = Vector3.zero;
			dirty = true;
		}

		internal static void RebaseTouchOffset(Minimap minimap, Player player)
		{
			//IL_000b: 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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_004a: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = MapOffsetRef.Invoke(minimap);
			Vector3 val2 = Anchor - ((Component)player).transform.position;
			MapOffsetRef.Invoke(minimap) = new Vector3(val.x - val2.x, 0f, val.z - val2.z);
		}

		internal static bool IsDrawn(Minimap minimap, Vector3 pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return IsExploredMethod(minimap, pos);
		}

		private static Vector3 CentreOf(Minimap minimap, BitArray cells)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!MapBits.Centroid(cells, minimap.m_textureSize, out var x, out var y))
			{
				return Vector3.zero;
			}
			float num = minimap.m_textureSize / 2;
			return new Vector3((x - num) * minimap.m_pixelSize, 0f, (y - num) * minimap.m_pixelSize);
		}

		private static bool SamePins(List<PinRecord> a, List<PinRecord> b)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (a.Count != b.Count)
			{
				return false;
			}
			for (int i = 0; i < a.Count; i++)
			{
				if (a[i].Name != b[i].Name || a[i].Pos != b[i].Pos || a[i].Type != b[i].Type || a[i].Checked != b[i].Checked)
				{
					return false;
				}
			}
			return true;
		}

		private static string Describe()
		{
			return MapBits.Count(data.Explored) + " cells drawn, " + MapBits.Count(data.Pending) + " noted, " + data.Pins.Count + " marks, " + data.DrawnRevs.Count + " zone snapshots drawn, " + data.PendingRevs.Count + " noted";
		}

		internal static int RevisionOf(int zoneX, int zoneY)
		{
			if (Held == null || data == null)
			{
				return -1;
			}
			return data.DrawnRevs.Get(zoneX, zoneY);
		}

		internal static void SurveyAround(Vector3 position, float radius)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (Held == null || data == null || Time.time < surveysOffUntil || !SatelliteLink.CanSurvey)
			{
				return;
			}
			float time = Time.time;
			List<int> list = null;
			foreach (int item in ZoneGrid.Touching(position.x, position.z, radius + 64f))
			{
				if (!surveyedAt.TryGetValue(item, out var value) || time - value > 120f)
				{
					(list ?? (list = new List<int>())).Add(item);
				}
			}
			if (list == null || !RequestSurvey(list, walked: true))
			{
				return;
			}
			foreach (int item2 in list)
			{
				surveyedAt[item2] = time;
			}
		}

		private static bool RequestSurvey(List<int> keys, bool walked)
		{
			int[] array = new int[keys.Count];
			int[] array2 = new int[keys.Count];
			for (int i = 0; i < keys.Count; i++)
			{
				ZoneRevs.Split(keys[i], out array[i], out array2[i]);
			}
			ItemData item = Held;
			bool toNotes = walked && ParchmentMapPlugin.RevealAtTableOnly.Value;
			return SatelliteLink.Survey(array, array2, delegate(int[] zoneXs, int[] zoneYs, int[] revs)
			{
				OnSurveyed(item, zoneXs, zoneYs, revs, toNotes, !walked);
			});
		}

		private static void OnSurveyed(ItemData item, int[] zoneXs, int[] zoneYs, int[] revs, bool toNotes, bool isCheck)
		{
			if (isCheck)
			{
				checkInFlight = false;
				if (zoneXs.Length == 0)
				{
					surveysOffUntil = Time.time + 300f;
					checkQueue = null;
				}
			}
			if (Held == null || Held != item || data == null)
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < zoneXs.Length; i++)
			{
				if (!toNotes)
				{
					flag |= data.DrawnRevs.Raise(zoneXs[i], zoneYs[i], revs[i]);
				}
				else if (revs[i] > data.DrawnRevs.Get(zoneXs[i], zoneYs[i]))
				{
					dirty |= data.PendingRevs.Raise(zoneXs[i], zoneYs[i], revs[i]);
				}
			}
			if (flag)
			{
				dirty = true;
				SatelliteLink.NotifyExploredChanged();
			}
		}

		private static void StartSurveyCheck(Minimap minimap)
		{
			checkQueue = null;
			checkInFlight = false;
			if (data != null && !data.SurveyChecked && !(Time.time < surveysOffUntil) && SatelliteLink.CanSurvey)
			{
				List<int> list = ZoneGrid.WithoutRev(ExploredRef.Invoke(minimap), minimap.m_textureSize, minimap.m_pixelSize, data.DrawnRevs);
				if (list.Count == 0)
				{
					data.SurveyChecked = true;
					return;
				}
				checkQueue = list;
				ParchmentMapPlugin.Log.LogInfo((object)(list.Count + " zones of this map have no snapshot yet: they are being recorded as they are now"));
			}
		}

		private static void PumpSurveyCheck()
		{
			if (checkQueue == null)
			{
				return;
			}
			if (checkInFlight)
			{
				if (Time.time - checkSentAt > 20f)
				{
					checkInFlight = false;
					checkQueue = null;
					surveysOffUntil = Time.time + 300f;
				}
				return;
			}
			if (checkQueue.Count == 0)
			{
				checkQueue = null;
				data.SurveyChecked = true;
				return;
			}
			int num = Math.Min(96, checkQueue.Count);
			List<int> range = checkQueue.GetRange(checkQueue.Count - num, num);
			checkQueue.RemoveRange(checkQueue.Count - num, num);
			checkInFlight = true;
			checkSentAt = Time.time;
			if (!RequestSurvey(range, walked: false))
			{
				checkInFlight = false;
				checkQueue = null;
			}
		}

		internal static void AddPending(Minimap minimap, int x, int y)
		{
			int num = y * minimap.m_textureSize + x;
			if (num >= 0 && num < data.Pending.Length && !ExploredRef.Invoke(minimap)[num] && !data.Pending[num])
			{
				data.Pending[num] = true;
				dirty = true;
			}
		}

		internal static void ForgetPin(Vector3 pos)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (data != null)
			{
				PinMerge.Bury(data.Tombstones, pos);
				dirty = true;
			}
		}

		internal static void RememberPin(Vector3 pos)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (data != null)
			{
				PinMerge.Unbury(data.Tombstones, pos);
				dirty = true;
			}
		}

		internal static bool UseTable(MapTable table, Humanoid user, bool write)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (!IsActive || data == null)
			{
				((Character)user).Message((MessageType)2, "$q8pm_msg_needmap", 0, (Sprite)null, false);
				return false;
			}
			if (write && !PrivateArea.CheckAccess(((Component)table).transform.position, 0f, true, false))
			{
				return true;
			}
			ZNetView component = ((Component)table).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return false;
			}
			ZDO zDO = component.GetZDO();
			int stableHashCode = StringExtensionMethods.GetStableHashCode("q8pm_table");
			int textureSize = instance.m_textureSize;
			BitArray before = new BitArray(ExploredRef.Invoke(instance));
			bool flag = CommitPending(instance);
			TableData tableData = null;
			byte[] byteArray = zDO.GetByteArray(stableHashCode, (byte[])null);
			if (byteArray != null)
			{
				tableData = TableData.FromBytes(byteArray, out var error);
				if (tableData == null || tableData.TextureSize != textureSize)
				{
					ParchmentMapPlugin.Log.LogWarning((object)("Records of this cartography table cannot be read: " + (error ?? ("map size " + tableData.TextureSize + " instead of " + textureSize))));
					((Character)user).Message((MessageType)2, "$q8pm_msg_tableunreadable", 0, (Sprite)null, false);
					if (flag)
					{
						UploadFog(instance);
						Flush();
					}
					return false;
				}
			}
			if (tableData != null)
			{
				BitArray obj = ExploredRef.Invoke(instance);
				int num = MapBits.Count(obj);
				obj.Or(tableData.Explored);
				if (MapBits.Count(obj) != num)
				{
					flag = true;
					data.SurveyChecked = false;
				}
				if (data.DrawnRevs.RaiseAll(tableData.Revs))
				{
					flag = true;
				}
				List<PinRecord> list = PinMerge.FromTable(CapturePins(instance), data.Tombstones, tableData.Pins);
				if (list.Count > 0)
				{
					flag = true;
					Loading = true;
					try
					{
						foreach (PinRecord item in list)
						{
							AddPin(instance, item);
						}
					}
					finally
					{
						Loading = false;
					}
				}
			}
			if (flag)
			{
				UploadFog(instance);
				dirty = true;
				BitArray bitArray = MapBits.Added(before, ExploredRef.Invoke(instance));
				if (PictureMode && MapBits.Any(bitArray))
				{
					LookAt(instance, CentreOf(instance, bitArray));
				}
			}
			if (write)
			{
				if (tableData == null)
				{
					tableData = TableData.CreateNew(textureSize);
				}
				tableData.Explored.Or(ExploredRef.Invoke(instance));
				tableData.Revs.RaiseAll(data.DrawnRevs);
				PinMerge.IntoTable(tableData.Pins, CapturePins(instance), data.Tombstones);
				component.ClaimOwnership();
				zDO.Set(stableHashCode, tableData.ToBytes());
				table.m_writeEffects.Create(((Component)table).transform.position, ((Component)table).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
			}
			Flush();
			StartSurveyCheck(instance);
			ParchmentMapPlugin.Log.LogInfo((object)("Cartography table " + (write ? "write" : "read") + ": " + Describe() + ((tableData != null) ? (", table has " + MapBits.Count(tableData.Explored) + " cells and " + tableData.Pins.Count + " marks") : ", table is empty")));
			string text = (write ? "$q8pm_msg_written" : ((!flag) ? ((tableData == null) ? "$q8pm_msg_tableempty" : "$q8pm_msg_uptodate") : "$q8pm_msg_updated"));
			((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false);
			return true;
		}

		private static bool CommitPending(Minimap minimap)
		{
			if (data == null)
			{
				return false;
			}
			bool flag = false;
			if (MapBits.Any(data.Pending))
			{
				ExploredRef.Invoke(minimap).Or(data.Pending);
				data.Pending.SetAll(value: false);
				data.SurveyChecked = false;
				flag = true;
			}
			if (data.PendingRevs.Count > 0)
			{
				flag |= data.DrawnRevs.RaiseAll(data.PendingRevs);
				data.PendingRevs.Clear();
				dirty = true;
			}
			if (flag)
			{
				dirty = true;
			}
			return flag;
		}

		private static void SetExplored(Minimap minimap, BitArray explored)
		{
			ExploredRef.Invoke(minimap) = new BitArray(explored);
			ExploredOthersRef.Invoke(minimap).SetAll(value: false);
			if ((Object)(object)minimap.m_sharedMapHint != (Object)null)
			{
				minimap.m_sharedMapHint.gameObject.SetActive(false);
			}
			UploadFog(minimap);
		}

		private static void UploadFog(Minimap minimap)
		{
			//IL_006d: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			BitArray obj = ExploredRef.Invoke(minimap);
			Texture2D val = FogTextureRef.Invoke(minimap);
			int length = obj.Length;
			if (fogBuffer == null || fogBuffer.Length != length)
			{
				fogBuffer = (Color32[])(object)new Color32[length];
			}
			byte[] array = MapBits.Pack(obj);
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				if (num >= length)
				{
					break;
				}
				int num2 = array[i];
				int num3 = 0;
				while (num3 < 8 && num < length)
				{
					fogBuffer[num] = (((num2 & (1 << num3)) != 0) ? FogSeen : FogHidden);
					num3++;
					num++;
				}
			}
			val.SetPixels32(fogBuffer);
			val.Apply();
			PinUpdateRequiredRef.Invoke(minimap) = true;
			SatelliteLink.NotifyExploredChanged();
		}

		internal static bool IsHiddenPin(Minimap minimap, PinData pin)
		{
			//IL_000b: 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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0015: 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: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (pin.m_save)
			{
				return false;
			}
			PinType type = pin.m_type;
			if ((int)type == 7 || type - 10 <= 3)
			{
				return true;
			}
			return !IsDrawn(minimap, pin.m_pos);
		}

		internal static List<PinData> Pins(Minimap minimap)
		{
			return PinsRef.Invoke(minimap);
		}

		private static List<PinRecord> CapturePins(Minimap minimap)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected I4, but got Unknown
			List<PinRecord> list = new List<PinRecord>();
			foreach (PinData item in PinsRef.Invoke(minimap))
			{
				if (item.m_save)
				{
					list.Add(new PinRecord
					{
						Name = (item.m_name ?? ""),
						Pos = item.m_pos,
						Type = (int)item.m_type,
						Checked = item.m_checked
					});
				}
			}
			return list;
		}

		private static void ReplacePins(Minimap minimap, List<PinRecord> pins)
		{
			Loading = true;
			try
			{
				RemoveSavedPinsCore(minimap);
				foreach (PinRecord pin in pins)
				{
					AddPin(minimap, pin);
				}
			}
			finally
			{
				Loading = false;
			}
		}

		private static void RemoveSavedPins(Minimap minimap)
		{
			Loading = true;
			try
			{
				RemoveSavedPinsCore(minimap);
			}
			finally
			{
				Loading = false;
			}
		}

		private static void RemoveSavedPinsCore(Minimap minimap)
		{
			List<PinData> list = PinsRef.Invoke(minimap);
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num].m_save)
				{
					minimap.RemovePin(list[num]);
				}
			}
		}

		private static void AddPin(Minimap minimap, PinRecord pin)
		{
			//IL_0002: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			minimap.AddPin(pin.Pos, (PinType)pin.Type, pin.Name, true, pin.Checked, 0L, default(PlatformUserID));
		}

		private static string BuildStats(Minimap minimap)
		{
			double num = Math.PI * Math.Pow(10500.0 / (double)minimap.m_pixelSize, 2.0);
			double num2 = (double)MapBits.Count(data.Explored) * 100.0 / num;
			double num3 = (double)MapBits.Count(data.Pending) * 100.0 / num;
			return string.Format(CultureInfo.InvariantCulture, "{0:0.0};{1:0.0};{2};{3}", num2, num3, data.Pins.Count, data.PendingRevs.CountAlsoIn(data.DrawnRevs));
		}

		internal static bool TryReadStats(ItemData item, out string explored, out string pending, out string pins, out string changes)
		{
			explored = (pending = (pins = (changes = null)));
			if (item == null || !item.m_customData.TryGetValue("q8pm_stats", out var value))
			{
				return false;
			}
			string[] array = value.Split(new char[1] { ';' });
			if (array.Length < 3)
			{
				return false;
			}
			explored = array[0];
			pending = array[1];
			pins = array[2];
			changes = ((array.Length > 3) ? array[3] : "0");
			return true;
		}
	}
	[HarmonyPatch(typeof(Game), "UpdateNoMap")]
	internal static class Game_UpdateNoMap_Patch
	{
		private static void Postfix()
		{
			MapSession.OnNoMapUpdated();
		}
	}
	[HarmonyPatch(typeof(PersistentEventSystemDirectionHelper), "UpdatePersistentEventSystemParticleHelper")]
	internal static class PersistentEventSystemDirectionHelper_Update_Patch
	{
		private static PersistentEventSystemDirectionHelper unlocked;

		private static void Prefix(PersistentEventSystemDirectionHelper __instance)
		{
			if (__instance.m_onlyOnNoMap && ParchmentMapPlugin.ReplaceVanillaMap.Value)
			{
				__instance.m_onlyOnNoMap = false;
				unlocked = __instance;
			}
		}

		private static void Finalizer()
		{
			if (unlocked != null)
			{
				unlocked.m_onlyOnNoMap = true;
				unlocked = null;
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "Awake")]
	internal static class Minimap_Awake_Patch
	{
		private static void Postfix()
		{
			MapSession.ResetSession();
		}
	}
	[HarmonyPatch(typeof(Minimap), "Update")]
	internal static class Minimap_Update_Patch
	{
		private static void Postfix(Minimap __instance)
		{
			MapSession.Tick(__instance);
		}
	}
	[HarmonyPatch(typeof(Minimap), "SetMapMode")]
	internal static class Minimap_SetMapMode_Patch
	{
		private static bool noMapBefore;

		private static void Prefix(Minimap __instance, MapMode mode)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			noMapBefore = Game.m_noMap;
			if (noMapBefore && MapSession.IsActive)
			{
				Game.m_noMap = false;
				if ((int)__instance.m_mode == 2 && (int)mode != 2)
				{
					MapSession.FoldView(__instance);
				}
			}
		}

		private static void Finalizer(Minimap __instance)
		{
			Game.m_noMap = noMapBefore;
			if (noMapBefore && MapSession.IsActive && __instance.m_smallRoot.activeSelf && (!ParchmentMapPlugin.ShowMinimap.Value || MapSession.PictureMode))
			{
				__instance.m_smallRoot.SetActive(false);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
	internal static class Minimap_UpdateExplore_Patch
	{
		private static bool Prefix()
		{
			if (Game.m_noMap)
			{
				return MapSession.IsActive;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	internal static class Minimap_ExploreArea_Patch
	{
		private static void Prefix(Vector3 p, ref float radius)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (Game.m_noMap && MapSession.IsActive)
			{
				radius *= ParchmentMapPlugin.ExploreRadiusMultiplier.Value;
				MapSession.SurveyAround(p, radius);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(int),
		typeof(int)
	})]
	internal static class Minimap_ExploreCell_Patch
	{
		private static bool Prefix(Minimap __instance, int x, int y, ref bool __result)
		{
			if (!Game.m_noMap || !MapSession.IsActive || MapSession.Loading || !ParchmentMapPlugin.RevealAtTableOnly.Value)
			{
				return true;
			}
			MapSession.AddPending(__instance, x, y);
			__result = false;
			return false;
		}

		private static void Postfix(bool __result)
		{
			if (__result && MapSession.IsActive)
			{
				MapSession.MarkDirty();
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "SaveMapData")]
	internal static class Minimap_SaveMapData_Patch
	{
		private static bool Prefix()
		{
			return !Game.m_noMap;
		}
	}
	[HarmonyPatch(typeof(Minimap), "AddPin")]
	internal static class Minimap_AddPin_Patch
	{
		private static void Postfix(Vector3 pos, bool save)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (save && MapSession.IsActive && !MapSession.Loading)
			{
				MapSession.RememberPin(pos);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })]
	internal static class Minimap_RemovePin_Patch
	{
		private static void Prefix(PinData pin)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (pin != null && pin.m_save && MapSession.IsActive && !MapSession.Loading)
			{
				MapSession.ForgetPin(pin.m_pos);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
	internal static class Minimap_OnMapLeftClick_Patch
	{
		private static void Postfix()
		{
			if (MapSession.IsActive)
			{
				MapSession.MarkDirty();
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnPinTextEntered")]
	internal static class Minimap_OnPinTextEntered_Patch
	{
		private static void Postfix()
		{
			if (MapSession.IsActive)
			{
				MapSession.MarkDirty();
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
	internal static class Humanoid_UnequipItem_Patch
	{
		private static void Prefix(Humanoid __instance, ItemData item)
		{
			if (item != null && item == MapSession.Held && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				MapSession.Deactivate();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Save")]
	internal static class Player_Save_Patch
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				MapSession.Flush();
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	internal static class Humanoid_StartAttack_Patch
	{
		private static bool Prefix(Humanoid __instance, ref bool __result)
		{
			if (!ParchmentMapPlugin.BlockAttacks.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !MapItem.IsParchment(__instance.RightItem))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData),
		typeof(bool)
	})]
	internal static class MapTable_OnRead_Patch
	{
		private static bool Prefix(MapTable __instance, Humanoid user, ItemData item, ref bool __result)
		{
			if (!Game.m_noMap || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			__result = item == null && MapSession.UseTable(__instance, user, write: false);
			return false;
		}
	}
	[HarmonyPatch(typeof(MapTable), "OnWrite")]
	internal static class MapTable_OnWrite_Patch
	{
		private static bool Prefix(MapTable __instance, Humanoid user, ItemData item, ref bool __result)
		{
			if (!Game.m_noMap || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			__result = item == null && MapSession.UseTable(__instance, user, write: true);
			return false;
		}
	}
	[HarmonyPatch(typeof(MapTable), "GetReadHoverText")]
	internal static class MapTable_GetReadHoverText_Patch
	{
		private static void Postfix(MapTable __instance, ref string __result)
		{
			TableHover.Replace(__instance, "$q8pm_hover_read", ref __result);
		}
	}
	[HarmonyPatch(typeof(MapTable), "GetWriteHoverText")]
	internal static class MapTable_GetWriteHoverText_Patch
	{
		private static void Postfix(MapTable __instance, ref string __result)
		{
			TableHover.Replace(__instance, "$q8pm_hover_write", ref __result);
		}
	}
	internal static class TableHover
	{
		internal static void Replace(MapTable table, string action, ref string result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Game.m_noMap && PrivateArea.CheckAccess(((Component)table).transform.position, 0f, false, false))
			{
				string text = (MapSession.IsActive ? (table.m_name + "\n[<color=yellow><b>$KEY_Use</b></color>] " + action) : (table.m_name + "\n<color=#AAAAAA>$q8pm_hover_needmap</color>"));
				result = Localization.instance.Localize(text);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "ShowPinNameInput")]
	internal static class Minimap_ShowPinNameInput_Patch
	{
		private static bool Prefix(Minimap __instance, Vector3 pos)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!Game.m_noMap || !MapSession.IsActive || !ParchmentMapPlugin.PinsOnlyOnExplored.Value || MapSession.IsDrawn(__instance, pos))
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "$q8pm_msg_pin_unexplored", 0, (Sprite)null, false);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Minimap), "DiscoverLocation")]
	internal static class Minimap_DiscoverLocation_Patch
	{
		private static bool Prefix(Minimap __instance, Vector3 pos, ref bool __result)
		{
			//IL_0028: 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_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)
			if (!Game.m_noMap)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!MapSession.IsActive)
			{
				__result = false;
				return false;
			}
			if (!ParchmentMapPlugin.PinsOnlyOnExplored.Value || MapSession.IsDrawn(__instance, pos))
			{
				return true;
			}
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, "$q8pm_msg_pin_unexplored", 0, (Sprite)null, false);
				((Character)localPlayer).SetLookDir(pos - ((Component)localPlayer).transform.position, 3.5f);
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Minimap), "CenterMap")]
	internal static class Minimap_CenterMap_Patch
	{
		private static void Prefix(ref Vector3 centerPoint)
		{
			//IL_001e: 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_002e: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (MapSession.PictureMode && !MapSession.InTouchZoom && !((Object)(object)localPlayer == (Object)null))
			{
				Vector3 val = MapSession.Anchor - ((Component)localPlayer).transform.position;
				centerPoint = new Vector3(centerPoint.x + val.x, centerPoint.y, centerPoint.z + val.z);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "TouchZoom")]
	internal static class Minimap_TouchZoom_Patch
	{
		private static void Prefix()
		{
			MapSession.InTouchZoom = true;
		}

		private static void Finalizer(Minimap __instance, Player player)
		{
			MapSession.InTouchZoom = false;
			if (MapSession.PictureMode && (Object)(object)player != (Object)null)
			{
				MapSession.RebaseTouchOffset(__instance, player);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "ShowPointOnMap")]
	internal static class Minimap_ShowPointOnMap_Patch
	{
		private static void Postfix(Minimap __instance, Vector3 point)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (MapSession.PictureMode)
			{
				MapSession.LookAt(__instance, point);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdatePlayerMarker")]
	internal static class Minimap_UpdatePlayerMarker_Patch
	{
		private static bool smallMarkerHidden;

		private static void Postfix(Minimap __instance)
		{
			if (!MapSession.PictureMode)
			{
				if (smallMarkerHidden)
				{
					smallMarkerHidden = false;
					((Component)__instance.m_smallMarker).gameObject.SetActive(true);
				}
			}
			else
			{
				smallMarkerHidden = true;
				((Component)__instance.m_smallMarker).gameObject.SetActive(false);
				((Component)__instance.m_largeMarker).gameObject.SetActive(false);
				((Component)__instance.m_smallShipMarker).gameObject.SetActive(false);
				((Component)__instance.m_largeShipMarker).gameObject.SetActive(false);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdatePins")]
	internal static class Minimap_UpdatePins_Patch
	{
		private static readonly Vector3 Nowhere = new Vector3(1000000f, 0f, 1000000f);

		private static readonly List<KeyValuePair<PinData, Vector3>> moved = new List<KeyValuePair<PinData, Vector3>>();

		private static void Prefix(Minimap __instance)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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)
			moved.Clear();
			if (!MapSession.PictureMode)
			{
				return;
			}
			foreach (PinData item in MapSession.Pins(__instance))
			{
				if (MapSession.IsHiddenPin(__instance, item))
				{
					moved.Add(new KeyValuePair<PinData, Vector3>(item, item.m_pos));
					item.m_pos = Nowhere;
				}
			}
		}

		private static void Finalizer()
		{
			//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)
			foreach (KeyValuePair<PinData, Vector3> item in moved)
			{
				item.Key.m_pos = item.Value;
			}
			moved.Clear();
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ItemData_GetTooltip_Patch
	{
		private static void Postfix(ItemData item, bool crafting, ref string __result)
		{
			if (crafting || !MapItem.IsParchment(item))
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(__result);
			if (MapSession.TryReadStats(item, out var explored, out var pending, out var pins, out var changes))
			{
				stringBuilder.Append("\n\n$q8pm_tip_explored: <color=orange>").Append(explored).Append("%</color>");
				if (pending != "0.0")
				{
					stringBuilder.Append("\n$q8pm_tip_pending: <color=orange>").Append(pending).Append("%</color>");
				}
				if (changes != "0")
				{
					stringBuilder.Append("\n$q8pm_tip_changes: <color=orange>").Append(changes).Append("</color>");
				}
				stringBuilder.Append("\n$q8pm_tip_pins: <color=orange>").Append(pins).Append("</color>");
			}
			else
			{
				stringBuilder.Append("\n\n<color=orange>$q8pm_tip_blank</color>");
			}
			__result = stringBuilder.ToString();
		}
	}
	[BepInPlugin("qua8ion.valheim.parchmentmap", "ParchmentMap", "0.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ParchmentMapPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "qua8ion.valheim.parchmentmap";

		public const string PluginName = "ParchmentMap";

		public const string PluginVersion = "0.3.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ReplaceVanillaMap;

		internal static ConfigEntry<bool> RevealAtTableOnly;

		internal static ConfigEntry<float> ExploreRadiusMultiplier;

		internal static ConfigEntry<bool> ShowMinimap;

		internal static ConfigEntry<bool> BlockAttacks;

		internal static ConfigEntry<bool> PinsOnlyOnExplored;

		internal static ConfigEntry<bool> LiveMarkers;

		internal static ConfigEntry<int> DetailLevel;

		internal static ConfigEntry<string> Recipe;

		internal static ConfigEntry<Vector3> HandPosition;

		internal static ConfigEntry<Vector3> HandRotation;

		internal static ConfigEntry<float> HandScale;

		private FileSystemWatcher configWatcher;

		private volatile bool configChanged;

		private void Awake()
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ReplaceVanillaMap = Rule("Rules", "ReplaceVanillaMap", value: true, "The parchment map replaces the game's own map in every world. A world that has the map enabled is then played like a no-map world: without a parchment in hand there is no map and no minimap, and nothing gets charted. If false, the mod works only in worlds without a map (the 'nomap' world modifier) and does nothing elsewhere.");
			RevealAtTableOnly = Rule("Rules", "RevealAtTableOnly", value: true, "What you walk through with the map in hand is only noted down. It appears on the map when you use a cartography table. If false, the map is revealed right away while you walk.");
			ExploreRadiusMultiplier = Rule("Rules", "ExploreRadiusMultiplier", 1f, "Multiplier for the radius that gets recorded around you while the map is in hand.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 4f));
			ShowMinimap = Rule("Rules", "ShowMinimap", value: false, "Also show the small corner map while the parchment map is in hand. If false, only the big map (M) is available.");
			BlockAttacks = Rule("Rules", "BlockAttacks", value: true, "No punching while the map is in hand: put it away to fight.");
			PinsOnlyOnExplored = Rule("Rules", "PinsOnlyOnExplored", value: true, "Marks can be placed only where the map is already drawn. The same goes for boss and other location marks from runestones: no mark appears if that place is not on the map in your hand.");
			LiveMarkers = Rule("Rules", "LiveMarkers", value: false, "If false the map is just a picture: it shows neither you nor other players, pings, shouts or raids, game-made marks (bed, traders) appear only on drawn land, and the view stays where you left it instead of following you. If true the map behaves like the vanilla one.");
			DetailLevel = Rule("Rules", "DetailLevel", 3, "Works together with the SatelliteMap mod (optional): how detailed the picture of the drawn part of the map is when you zoom in. 0: the plain game map only. 1: a sketch (relief, water, paths, fields, buildings, ruins, boss altars). 2: a good map (also the forest and large rocks). 3: the best map (everything down to bushes). Planned: the level will come from the grade of the parchment instead of this setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3));
			Recipe = Rule("Rules", "Recipe", "DeerHide:2,Coal:1,Feathers:1", "Workbench recipe as Item:amount pairs separated by commas (prefab names).");
			HandPosition = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Visual", "HandPosition", new Vector3(-0.02f, -0.15f, 0.17f), "Position of the sheet in the right hand, metres: X away from you, Y to your right, Z up out of the fist. Applied on the fly when this file is saved.");
			HandRotation = ((BaseUnityPlugin)this).Config.Bind<Vector3>("Visual", "HandRotation", new Vector3(-180f, -90f, -90f), "Rotation of the sheet in the right hand, degrees. The default turns the drawn side towards you.");
			HandScale = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "HandScale", 1f, "Size of the sheet in hand.");
			HandPosition.SettingChanged += delegate
			{
				MapItem.ApplyHandPose();
			};
			HandRotation.SettingChanged += delegate
			{
				MapItem.ApplyHandPose();
			};
			HandScale.SettingChanged += delegate
			{
				MapItem.ApplyHandPose();
			};
			Recipe.SettingChanged += delegate
			{
				MapItem.ApplyRecipeToObjectDB();
			};
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				MapItem.ApplyRecipeToObjectDB();
			};
			AddLocalization();
			SatelliteLink.Register();
			PrefabManager.OnVanillaPrefabsAvailable += MapItem.Register;
			new Harmony("qua8ion.valheim.parchmentmap").PatchAll(Assembly.GetExecutingAssembly());
			WatchConfigFile();
		}

		private ConfigEntry<T> Rule<T>(string section, string key, T value, string description, AcceptableValueBase range = null)
		{
			//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_0022: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}

		private void WatchConfigFile()
		{
			try
			{
				configWatcher = new FileSystemWatcher(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath));
				configWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
				configWatcher.Changed += delegate
				{
					configChanged = true;
				};
				configWatcher.Created += delegate
				{
					configChanged = true;
				};
				configWatcher.EnableRaisingEvents = true;
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Config file will not be reloaded on the fly: " + ex.Message));
			}
		}

		private void Update()
		{
			if (!configChanged)
			{
				return;
			}
			configChanged = false;
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not reload the config file: " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			if (configWatcher != null)
			{
				configWatcher.Dispose();
			}
		}

		private static void AddLocalization()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "item_q8pm_parchment", "Parchment map" },
				{ "item_q8pm_parchment_desc", "A sheet of hide and a piece of coal. Hold it in your hand to chart the land as you walk and to look at the map. What you have seen goes onto the map at a cartography table." },
				{ "q8pm_tip_explored", "Charted" },
				{ "q8pm_tip_pending", "Not yet drawn" },
				{ "q8pm_tip_changes", "Places charted anew, not yet drawn" },
				{ "q8pm_tip_pins", "Marks" },
				{ "q8pm_tip_blank", "Blank" },
				{ "q8pm_hover_read", "Draw your notes on the map and copy the table's records" },
				{ "q8pm_hover_write", "Add your map to the table's records" },
				{ "q8pm_hover_needmap", "Hold a parchment map in your hand" },
				{ "q8pm_msg_needmap", "Hold a parchment map in your hand" },
				{ "q8pm_msg_updated", "The map has been updated" },
				{ "q8pm_msg_uptodate", "Nothing new for this map" },
				{ "q8pm_msg_tableempty", "The table has no records yet" },
				{ "q8pm_msg_written", "The map has been recorded on the table" },
				{ "q8pm_msg_otherworld", "This map shows some other world" },
				{ "q8pm_msg_unreadable", "The drawings on this map cannot be read" },
				{ "q8pm_msg_tableunreadable", "The table's records cannot be read" },
				{ "q8pm_msg_pin_unexplored", "This place is not on the map yet" }
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "item_q8pm_parchment", "Карта на пергаменте" },
				{ "item_q8pm_parchment_desc", "Кусок шкуры и уголёк. Держите карту в руке, чтобы отмечать пройденное и смотреть на неё. Увиденное наносится на карту у стола картографа." },
				{ "q8pm_tip_explored", "Нанесено" },
				{ "q8pm_tip_pending", "Ещё не нанесено" },
				{ "q8pm_tip_changes", "Мест обойдено заново, ещё не нанесено" },
				{ "q8pm_tip_pins", "Меток" },
				{ "q8pm_tip_blank", "Чистая" },
				{ "q8pm_hover_read", "Нанести заметки на карту и переписать записи стола" },
				{ "q8pm_hover_write", "Добавить свою карту в записи стола" },
				{ "q8pm_hover_needmap", "Возьмите карту в руку" },
				{ "q8pm_msg_needmap", "Возьмите карту в руку" },
				{ "q8pm_msg_updated", "Карта обновлена" },
				{ "q8pm_msg_uptodate", "Для этой карты нет ничего нового" },
				{ "q8pm_msg_tableempty", "На столе пока нет записей" },
				{ "q8pm_msg_written", "Карта записана на стол" },
				{ "q8pm_msg_otherworld", "На этой карте какой-то другой мир" },
				{ "q8pm_msg_unreadable", "Рисунки на этой карте не разобрать" },
				{ "q8pm_msg_tableunreadable", "Записи стола не разобрать" },
				{ "q8pm_msg_pin_unexplored", "Этого места на карте ещё нет" }
			});
		}
	}
	internal static class SatelliteLink
	{
		private const string ApiType = "SatelliteMap.SatelliteMapApi";

		private static Action notifyExploredChanged;

		private static Func<int[], int[], Action<int[], int[], int[]>, bool> survey;

		internal static bool CanSurvey => survey != null;

		internal static void Register()
		{
			try
			{
				Type type = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				for (int i = 0; i < assemblies.Length; i++)
				{
					type = assemblies[i].GetType("SatelliteMap.SatelliteMapApi", throwOnError: false);
					if (type != null)
					{
						break;
					}
				}
				if (type == null)
				{
					return;
				}
				MethodInfo method = type.GetMethod("AddDetailLimit", BindingFlags.Static | BindingFlags.Public);
				MethodInfo method2 = type.GetMethod("NotifyExploredChanged", BindingFlags.Static | BindingFlags.Public);
				if (method == null || method2 == null)
				{
					ParchmentMapPlugin.Log.LogWarning((object)"SatelliteMap is installed, but its interface is not the expected one");
					return;
				}
				method.Invoke(null, new object[1]
				{
					new Func<int>(DetailLimit)
				});
				notifyExploredChanged = (Action)Delegate.CreateDelegate(typeof(Action), method2);
				MethodInfo method3 = type.GetMethod("SetZoneRevisionProvider", BindingFlags.Static | BindingFlags.Public);
				MethodInfo method4 = type.GetMethod("Survey", BindingFlags.Static | BindingFlags.Public);
				if (method3 != null && method4 != null)
				{
					method3.Invoke(null, new object[1]
					{
						new Func<int, int, int>(MapSession.RevisionOf)
					});
					survey = (Func<int[], int[], Action<int[], int[], int[]>, bool>)Delegate.CreateDelegate(typeof(Func<int[], int[], Action<int[], int[], int[]>, bool>), method4);
					ParchmentMapPlugin.Log.LogInfo((object)"SatelliteMap found: the parchment map gets the detailed picture, drawn as the land was when you charted it");
				}
				else
				{
					ParchmentMapPlugin.Log.LogWarning((object)"SatelliteMap found, but it is older than 0.2.0: the detailed picture will show the world as it is now, not as it was when you charted it");
				}
			}
			catch (Exception ex)
			{
				ParchmentMapPlugin.Log.LogWarning((object)("Could not link to SatelliteMap: " + ex.Message));
			}
		}

		internal static int DetailLevelOf(ItemData parchment)
		{
			return Mathf.Clamp(ParchmentMapPlugin.DetailLevel.Value, 0, 3);
		}

		private static int DetailLimit()
		{
			if (!MapSession.IsActive)
			{
				return -1;
			}
			return DetailLevelOf(MapSession.Held);
		}

		internal static void NotifyExploredChanged()
		{
			if (notifyExploredChanged != null)
			{
				notifyExploredChanged();
			}
		}

		internal static bool Survey(int[] zoneXs, int[] zoneYs, Action<int[], int[], int[]> done)
		{
			if (survey == null)
			{
				return false;
			}
			try
			{
				return survey(zoneXs, zoneYs, done);
			}
			catch (Exception ex)
			{
				ParchmentMapPlugin.Log.LogWarning((object)("Could not ask SatelliteMap for zone snapshots: " + ex.Message));
				return false;
			}
		}
	}
}