Decompiled source of LiveSeedMap v1.5.3

plugins/LiveSeedMap.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LiveSeedMap")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.3.0")]
[assembly: AssemblyInformationalVersion("1.5.3+a973e3a1dffdbcab6bfd2b2ac1932f1d87dbe731")]
[assembly: AssemblyProduct("LiveSeedMap")]
[assembly: AssemblyTitle("LiveSeedMap")]
[assembly: AssemblyVersion("1.5.3.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 LiveSeedMap
{
	public struct PieceRow
	{
		public int Prefab;

		public int Creator;

		public float X;

		public float Y;

		public float Z;

		public float QX;

		public float QY;

		public float QZ;

		public float QW;

		public bool Same(PieceRow other)
		{
			if (other.Prefab == Prefab && other.Creator == Creator && other.X == X && other.Y == Y && other.Z == Z && other.QX == QX && other.QY == QY && other.QZ == QZ)
			{
				return other.QW == QW;
			}
			return false;
		}
	}
	public readonly struct PieceKey : IEquatable<PieceKey>
	{
		public readonly int Prefab;

		public readonly int X;

		public readonly int Y;

		public readonly int Z;

		public PieceKey(int prefab, float x, float y, float z)
		{
			Prefab = prefab;
			X = (int)Math.Round(x * 100f);
			Y = (int)Math.Round(y * 100f);
			Z = (int)Math.Round(z * 100f);
		}

		public bool Equals(PieceKey other)
		{
			if (Prefab == other.Prefab && X == other.X && Y == other.Y)
			{
				return Z == other.Z;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is PieceKey other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((((Prefab * 397) ^ X) * 397) ^ Y) * 397) ^ Z;
		}
	}
	public sealed class FrozenBuildings
	{
		public string World;

		public int Version;

		public string[] Prefabs;

		public long[] Creators;

		public PieceRow[] Rows;
	}
	public sealed class BuildingBook
	{
		public const float MissingSeconds = 10f;

		private readonly List<string> prefabs = new List<string>();

		private readonly Dictionary<string, int> prefabIndex = new Dictionary<string, int>(StringComparer.Ordinal);

		private readonly List<long> creators = new List<long>();

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

		private readonly Dictionary<PieceKey, PieceRow> pieces = new Dictionary<PieceKey, PieceRow>();

		private readonly Dictionary<PieceKey, float> missing = new Dictionary<PieceKey, float>();

		private bool changed;

		public string World { get; }

		public int Count => pieces.Count;

		public int Version { get; private set; }

		public BuildingBook(string world)
		{
			World = world;
			Version = Environment.TickCount;
		}

		public int PrefabIndex(string prefab)
		{
			if (prefabIndex.TryGetValue(prefab, out var value))
			{
				return value;
			}
			prefabs.Add(prefab);
			return prefabIndex[prefab] = prefabs.Count - 1;
		}

		private int CreatorIndex(long creator)
		{
			if (creatorIndex.TryGetValue(creator, out var value))
			{
				return value;
			}
			creators.Add(creator);
			return creatorIndex[creator] = creators.Count - 1;
		}

		public PieceKey Observe(string prefab, float x, float y, float z, float qx, float qy, float qz, float qw, long creator)
		{
			PieceRow pieceRow = new PieceRow
			{
				Prefab = PrefabIndex(prefab),
				Creator = CreatorIndex(creator),
				X = x,
				Y = y,
				Z = z,
				QX = qx,
				QY = qy,
				QZ = qz,
				QW = qw
			};
			PieceKey pieceKey = new PieceKey(pieceRow.Prefab, x, y, z);
			missing.Remove(pieceKey);
			if (pieces.TryGetValue(pieceKey, out var value) && value.Same(pieceRow))
			{
				return pieceKey;
			}
			pieces[pieceKey] = pieceRow;
			Changed();
			return pieceKey;
		}

		public bool Remove(string prefab, float x, float y, float z)
		{
			if (!prefabIndex.TryGetValue(prefab, out var value))
			{
				return false;
			}
			PieceKey key = new PieceKey(value, x, y, z);
			missing.Remove(key);
			if (!pieces.Remove(key))
			{
				return false;
			}
			Changed();
			return true;
		}

		public bool Sweep(HashSet<PieceKey> present, Func<float, float, bool> loaded, float elapsed, bool complete)
		{
			List<PieceKey> list = new List<PieceKey>();
			foreach (KeyValuePair<PieceKey, PieceRow> piece in pieces)
			{
				if (present.Contains(piece.Key))
				{
					continue;
				}
				if (complete)
				{
					list.Add(piece.Key);
					continue;
				}
				if (!loaded(piece.Value.X, piece.Value.Z))
				{
					missing.Remove(piece.Key);
					continue;
				}
				missing.TryGetValue(piece.Key, out var value);
				value += elapsed;
				if (value >= 10f)
				{
					list.Add(piece.Key);
				}
				else
				{
					missing[piece.Key] = value;
				}
			}
			foreach (PieceKey item in list)
			{
				pieces.Remove(item);
				missing.Remove(item);
			}
			if (list.Count > 0)
			{
				Changed();
			}
			return list.Count > 0;
		}

		public bool TakeChanged()
		{
			bool result = changed;
			changed = false;
			return result;
		}

		private void Changed()
		{
			changed = true;
			Version++;
		}

		public FrozenBuildings Freeze()
		{
			return new FrozenBuildings
			{
				World = World,
				Version = Version,
				Prefabs = prefabs.ToArray(),
				Creators = creators.ToArray(),
				Rows = pieces.Values.ToArray()
			};
		}

		public static void WritePieces(JsonWriter w, PieceRow[] rows)
		{
			w.WriteStartArray();
			for (int i = 0; i < rows.Length; i++)
			{
				PieceRow pieceRow = rows[i];
				w.WriteStartArray();
				w.WriteValue(pieceRow.Prefab);
				w.WriteValue(pieceRow.Creator);
				w.WriteValue(Math.Round(pieceRow.X, 2));
				w.WriteValue(Math.Round(pieceRow.Y, 2));
				w.WriteValue(Math.Round(pieceRow.Z, 2));
				w.WriteValue(Math.Round(pieceRow.QX, 4));
				w.WriteValue(Math.Round(pieceRow.QY, 4));
				w.WriteValue(Math.Round(pieceRow.QZ, 4));
				w.WriteValue(Math.Round(pieceRow.QW, 4));
				w.WriteEndArray();
			}
			w.WriteEndArray();
		}

		public static string ToFile(FrozenBuildings frozen)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				((JsonWriter)val).WritePropertyName("world");
				((JsonWriter)val).WriteValue(frozen.World);
				((JsonWriter)val).WritePropertyName("prefabs");
				((JsonWriter)val).WriteStartArray();
				string[] array = frozen.Prefabs;
				foreach (string text in array)
				{
					((JsonWriter)val).WriteValue(text);
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WritePropertyName("creators");
				((JsonWriter)val).WriteStartArray();
				long[] array2 = frozen.Creators;
				foreach (long num in array2)
				{
					((JsonWriter)val).WriteValue(num.ToString(CultureInfo.InvariantCulture));
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WritePropertyName("pieces");
				WritePieces((JsonWriter)(object)val, frozen.Rows);
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		public static BuildingBook Load(string text, string world)
		{
			BuildingBook buildingBook = new BuildingBook(world);
			if (string.IsNullOrEmpty(text))
			{
				return buildingBook;
			}
			try
			{
				JObject val = JObject.Parse(text);
				if ((string)val["world"] != world)
				{
					goto IL_006f;
				}
				JToken obj = val["prefabs"];
				JArray val2 = (JArray)(object)((obj is JArray) ? obj : null);
				if (val2 == null)
				{
					goto IL_006f;
				}
				JToken obj2 = val["creators"];
				JArray val3 = (JArray)(object)((obj2 is JArray) ? obj2 : null);
				if (val3 == null)
				{
					goto IL_006f;
				}
				JToken obj3 = val["pieces"];
				JArray val4 = (JArray)(object)((obj3 is JArray) ? obj3 : null);
				if (val4 == null)
				{
					goto IL_006f;
				}
				string[] array = ((IEnumerable<JToken>)val2).Select((JToken n) => (string)n).ToArray();
				long result;
				long[] array2 = ((IEnumerable<JToken>)val3).Select((JToken i) => (!long.TryParse((string)i, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) ? 0 : result).ToArray();
				foreach (JArray item in ((IEnumerable)val4).OfType<JArray>())
				{
					if (((JContainer)item).Count >= 9)
					{
						int num = (int)item[0];
						int num2 = (int)item[1];
						if (num >= 0 && num < array.Length && !string.IsNullOrEmpty(array[num]) && num2 >= 0 && num2 < array2.Length)
						{
							buildingBook.Observe(array[num], (float)item[2], (float)item[3], (float)item[4], (float)item[5], (float)item[6], (float)item[7], (float)item[8], array2[num2]);
						}
					}
				}
				goto end_IL_0012;
				IL_006f:
				return buildingBook;
				end_IL_0012:;
			}
			catch (Exception ex) when (ex is JsonException || ex is FormatException || ex is InvalidCastException || ex is OverflowException)
			{
				return new BuildingBook(world);
			}
			buildingBook.changed = false;
			return buildingBook;
		}
	}
	public static class Buildings
	{
		private const float ScanEvery = 3f;

		private const float SaveEvery = 30f;

		private static readonly FieldInfo ObjectsField = AccessTools.Field(typeof(ZDOMan), "m_objectsByID");

		private static BuildingBook book;

		private static long worldUid;

		private static ZDOMan hooked;

		private static ZNetScene piecesOf;

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

		private static readonly HashSet<int> crops = new HashSet<int>();

		private static readonly Dictionary<string, string> types = new Dictionary<string, string>(StringComparer.Ordinal);

		private static readonly HashSet<PieceKey> present = new HashSet<PieceKey>();

		private static float nextScan;

		private static float nextSave;

		private static bool unsaved;

		private static volatile FrozenBuildings frozen;

		private static volatile string[] frozenTypes;

		private static volatile string self;

		private static string cachedJson;

		private static int cachedVersion;

		private static readonly object cacheGate = new object();

		private static ManualLogSource log;

		public static int? Version => book?.Version;

		public static void Tick(float now, ManualLogSource logger)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			log = logger;
			World val = ((!Object.op_Implicit((Object)(object)ZNet.instance)) ? ((World)null) : ((World)Capture.WorldField.GetValue(null)));
			ZDOMan instance = ZDOMan.instance;
			if (val == null || instance == null || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				Leave();
				return;
			}
			if (book == null || val.m_uid != worldUid)
			{
				Join(val.m_uid);
			}
			if (hooked != instance)
			{
				if (hooked != null)
				{
					ZDOMan obj = hooked;
					obj.m_onZDODestroyed = (Action<ZDO>)Delegate.Remove(obj.m_onZDODestroyed, new Action<ZDO>(Destroyed));
				}
				instance.m_onZDODestroyed = (Action<ZDO>)Delegate.Combine(instance.m_onZDODestroyed, new Action<ZDO>(Destroyed));
				hooked = instance;
			}
			if (now >= nextScan)
			{
				nextScan = now + 3f;
				Scan(instance);
			}
			if (book.TakeChanged())
			{
				Publish();
				unsaved = true;
			}
			if (unsaved && now >= nextSave)
			{
				Save();
				nextSave = now + 30f;
			}
		}

		public static void Flush()
		{
			Save(wait: true);
		}

		private static void Join(long uid)
		{
			Leave();
			worldUid = uid;
			string world = uid.ToString(CultureInfo.InvariantCulture);
			string text = null;
			try
			{
				if (File.Exists(FileOf(world)))
				{
					text = File.ReadAllText(FileOf(world));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = log;
				if (obj != null)
				{
					obj.LogWarning((object)("Could not read the saved buildings: " + ex.Message));
				}
			}
			book = BuildingBook.Load(text, world);
			Publish();
			nextScan = 0f;
		}

		private static void Leave()
		{
			if (book != null)
			{
				Save();
				if (hooked != null)
				{
					ZDOMan obj = hooked;
					obj.m_onZDODestroyed = (Action<ZDO>)Delegate.Remove(obj.m_onZDODestroyed, new Action<ZDO>(Destroyed));
				}
				hooked = null;
				book = null;
				frozen = null;
				frozenTypes = null;
			}
		}

		private static string FileOf(string world)
		{
			return Path.Combine(Path.Combine(Paths.ConfigPath, "LiveSeedMap"), "buildings-" + world + ".json");
		}

		private static void Publish()
		{
			FrozenBuildings frozenBuildings = book.Freeze();
			string[] array = new string[frozenBuildings.Prefabs.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = TypeOf(frozenBuildings.Prefabs[i]);
			}
			Player localPlayer = Player.m_localPlayer;
			self = (Object.op_Implicit((Object)(object)localPlayer) ? localPlayer.GetPlayerID().ToString(CultureInfo.InvariantCulture) : null);
			frozenTypes = array;
			frozen = frozenBuildings;
		}

		private static void Save(bool wait = false)
		{
			if (book == null || !unsaved)
			{
				return;
			}
			unsaved = false;
			FrozenBuildings copy = book.Freeze();
			if (wait)
			{
				Write();
				return;
			}
			ThreadPool.QueueUserWorkItem(delegate
			{
				lock (cacheGate)
				{
					Write();
				}
			});
			void Write()
			{
				try
				{
					string text = FileOf(copy.World);
					Directory.CreateDirectory(Path.GetDirectoryName(text));
					string text2 = text + ".tmp";
					File.WriteAllText(text2, BuildingBook.ToFile(copy));
					if (File.Exists(text))
					{
						File.Delete(text);
					}
					File.Move(text2, text);
				}
				catch (Exception ex)
				{
					ManualLogSource obj = log;
					if (obj != null)
					{
						obj.LogWarning((object)("Could not save the buildings: " + ex.Message));
					}
				}
			}
		}

		private static Dictionary<int, string> PieceNames()
		{
			if ((Object)(object)piecesOf == (Object)(object)ZNetScene.instance)
			{
				return pieceNames;
			}
			pieceNames.Clear();
			crops.Clear();
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<Piece>()))
				{
					continue;
				}
				pieceNames[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = ((Object)prefab).name;
				Plant component = prefab.GetComponent<Plant>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				GameObject[] grownPrefabs = component.m_grownPrefabs;
				foreach (GameObject val in grownPrefabs)
				{
					if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent<Pickable>()))
					{
						int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name);
						pieceNames[stableHashCode] = ((Object)val).name;
						crops.Add(stableHashCode);
					}
				}
			}
			piecesOf = ZNetScene.instance;
			return pieceNames;
		}

		private static void Scan(ZDOMan zdos)
		{
			//IL_0117: 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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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)
			//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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			if (!(ObjectsField?.GetValue(zdos) is Dictionary<ZDOID, ZDO> dictionary))
			{
				return;
			}
			Dictionary<int, string> dictionary2 = PieceNames();
			present.Clear();
			foreach (ZDO value2 in dictionary.Values)
			{
				if (value2 != null && dictionary2.TryGetValue(value2.GetPrefab(), out var value))
				{
					long num = value2.GetLong(ZDOVars.s_creator, 0L);
					if (num != 0L || crops.Contains(value2.GetPrefab()))
					{
						Vector3 position = value2.GetPosition();
						Quaternion rotation = value2.GetRotation();
						present.Add(book.Observe(value, position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w, num));
					}
				}
			}
			Player player = Player.m_localPlayer;
			float reach = Capture.Reach(ZNet.instance.GetSyncedSimulationDistance(), ZoneSystem.instance.m_zoneSize) * 0.9f;
			Vector3 here = (Object.op_Implicit((Object)(object)player) ? ((Component)player).transform.position : Vector3.zero);
			book.Sweep(present, (float x, float z) => Object.op_Implicit((Object)(object)player) && (x - here.x) * (x - here.x) + (z - here.z) * (z - here.z) <= reach * reach, 3f, ZNet.instance.IsServer());
		}

		private static void Destroyed(ZDO zdo)
		{
			//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_002d: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (book != null && zdo != null && PieceNames().TryGetValue(zdo.GetPrefab(), out var value))
				{
					Vector3 position = zdo.GetPosition();
					book.Remove(value, position.x, position.y, position.z);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource obj = log;
				if (obj != null)
				{
					obj.LogError((object)ex);
				}
			}
		}

		public static string Json()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			FrozenBuildings frozenBuildings = frozen;
			string[] array = frozenTypes;
			if (frozenBuildings == null || array == null)
			{
				return null;
			}
			lock (cacheGate)
			{
				if (cachedJson != null && cachedVersion == frozenBuildings.Version)
				{
					return cachedJson;
				}
				StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
				JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
				try
				{
					((JsonWriter)val).WriteStartObject();
					((JsonWriter)val).WritePropertyName("v");
					((JsonWriter)val).WriteValue(1);
					((JsonWriter)val).WritePropertyName("world");
					((JsonWriter)val).WriteValue(frozenBuildings.World);
					((JsonWriter)val).WritePropertyName("version");
					((JsonWriter)val).WriteValue(frozenBuildings.Version);
					((JsonWriter)val).WritePropertyName("self");
					if (self == null)
					{
						((JsonWriter)val).WriteNull();
					}
					else
					{
						((JsonWriter)val).WriteValue(self);
					}
					((JsonWriter)val).WritePropertyName("creators");
					((JsonWriter)val).WriteStartArray();
					long[] creators = frozenBuildings.Creators;
					foreach (long num in creators)
					{
						((JsonWriter)val).WriteValue(num.ToString(CultureInfo.InvariantCulture));
					}
					((JsonWriter)val).WriteEndArray();
					((JsonWriter)val).WritePropertyName("prefabs");
					((JsonWriter)val).WriteStartArray();
					for (int j = 0; j < frozenBuildings.Prefabs.Length; j++)
					{
						if (j < array.Length && array[j] != null)
						{
							((JsonWriter)val).WriteRawValue(array[j]);
							continue;
						}
						((JsonWriter)val).WriteStartObject();
						((JsonWriter)val).WritePropertyName("id");
						((JsonWriter)val).WriteValue(frozenBuildings.Prefabs[j]);
						((JsonWriter)val).WriteEndObject();
					}
					((JsonWriter)val).WriteEndArray();
					((JsonWriter)val).WritePropertyName("pieces");
					BuildingBook.WritePieces((JsonWriter)(object)val, frozenBuildings.Rows);
					((JsonWriter)val).WriteEndObject();
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
				cachedJson = stringWriter.ToString();
				cachedVersion = frozenBuildings.Version;
				return cachedJson;
			}
		}

		private static string TypeOf(string name)
		{
			if (types.TryGetValue(name, out var value))
			{
				return value;
			}
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(name) : null);
			string text = null;
			if (Object.op_Implicit((Object)(object)val))
			{
				try
				{
					text = Describe(name, val);
				}
				catch (Exception ex)
				{
					ManualLogSource obj = log;
					if (obj != null)
					{
						obj.LogWarning((object)("Could not read the shape of " + name + ": " + ex.Message));
					}
				}
			}
			if (text != null || !Object.op_Implicit((Object)(object)val))
			{
				types[name] = text;
			}
			return text;
		}

		private static string Describe(string name, GameObject prefab)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			Piece component = prefab.GetComponent<Piece>();
			WearNTear component2 = prefab.GetComponent<WearNTear>();
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				((JsonWriter)val).WritePropertyName("id");
				((JsonWriter)val).WriteValue(name);
				((JsonWriter)val).WritePropertyName("name");
				((JsonWriter)val).WriteValue((Object.op_Implicit((Object)(object)component) && Localization.instance != null) ? Localization.instance.Localize(component.m_name) : name);
				string text = GroupOf(name, prefab, component);
				((JsonWriter)val).WritePropertyName("group");
				((JsonWriter)val).WriteValue(text);
				((JsonWriter)val).WritePropertyName("material");
				if (Object.op_Implicit((Object)(object)component2))
				{
					((JsonWriter)val).WriteValue(((object)Unsafe.As<MaterialType, MaterialType>(ref component2.m_materialType)/*cast due to .constrained prefix*/).ToString());
				}
				else
				{
					((JsonWriter)val).WriteNull();
				}
				if (BaseArea(prefab, out var area))
				{
					((JsonWriter)val).WritePropertyName("base");
					((JsonWriter)val).WriteStartArray();
					((JsonWriter)val).WriteValue(Math.Round(area.x, 2));
					((JsonWriter)val).WriteValue(Math.Round(area.y, 2));
					((JsonWriter)val).WriteValue(Math.Round(area.z, 2));
					((JsonWriter)val).WriteEndArray();
				}
				((JsonWriter)val).WritePropertyName("boxes");
				((JsonWriter)val).WriteStartArray();
				Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
				int num = 0;
				float num2 = SeenExtent(prefab, worldToLocalMatrix);
				Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
				foreach (Collider val2 in componentsInChildren)
				{
					if (!Object.op_Implicit((Object)(object)val2) || (val2.isTrigger && text != "plant") || !BoundsOf(val2, out var bounds))
					{
						continue;
					}
					Matrix4x4 m = worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix;
					if (!(num2 > 0f) || !(GroundExtent(bounds, m) > num2 + 2f))
					{
						num++;
						((JsonWriter)val).WriteStartArray();
						for (int j = 0; j < 8; j++)
						{
							Vector3 val3 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
							Vector3 val4 = ((Matrix4x4)(ref m)).MultiplyPoint3x4(val3);
							((JsonWriter)val).WriteValue(Math.Round(val4.x, 3));
							((JsonWriter)val).WriteValue(Math.Round(val4.y, 3));
							((JsonWriter)val).WriteValue(Math.Round(val4.z, 3));
						}
						MeshCollider val5 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null);
						if (val5 != null && SlopeOf(val5.sharedMesh, m, out var rise))
						{
							((JsonWriter)val).WriteValue(Math.Round(rise.x, 3));
							((JsonWriter)val).WriteValue(Math.Round(rise.y, 3));
						}
						((JsonWriter)val).WriteEndArray();
					}
				}
				if (num == 0 && text == "plant")
				{
					((JsonWriter)val).WriteStartArray();
					for (int k = 0; k < 8; k++)
					{
						((JsonWriter)val).WriteValue(((k & 1) == 0) ? (-0.25) : 0.25);
						((JsonWriter)val).WriteValue(((k & 2) == 0) ? 0.0 : 0.5);
						((JsonWriter)val).WriteValue(((k & 4) == 0) ? (-0.25) : 0.25);
					}
					((JsonWriter)val).WriteEndArray();
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		private static bool SlopeOf(Mesh mesh, Matrix4x4 m, out Vector2 rise)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: 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_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			rise = default(Vector2);
			if (!Object.op_Implicit((Object)(object)mesh) || !mesh.isReadable)
			{
				return false;
			}
			Vector3[] vertices = mesh.vertices;
			if (vertices.Length < 4)
			{
				return false;
			}
			Vector3[] array = (Vector3[])(object)new Vector3[vertices.Length];
			float num = float.MaxValue;
			float num2 = float.MaxValue;
			float num3 = float.MinValue;
			float num4 = float.MinValue;
			for (int i = 0; i < vertices.Length; i++)
			{
				Vector3 val = (array[i] = ((Matrix4x4)(ref m)).MultiplyPoint3x4(vertices[i]));
				num = Mathf.Min(num, val.x);
				num3 = Mathf.Max(num3, val.x);
				num2 = Mathf.Min(num2, val.z);
				num4 = Mathf.Max(num4, val.z);
			}
			float[] array2 = new float[64];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = float.NaN;
			}
			float num5 = Mathf.Max(0.001f, num3 - num) / 8f;
			float num6 = Mathf.Max(0.001f, num4 - num2) / 8f;
			Vector3[] array3 = array;
			foreach (Vector3 val2 in array3)
			{
				int num7 = Mathf.Min(7, (int)((val2.x - num) / num5)) + 8 * Mathf.Min(7, (int)((val2.z - num2) / num6));
				if (float.IsNaN(array2[num7]) || val2.y > array2[num7])
				{
					array2[num7] = val2.y;
				}
			}
			double num8 = 0.0;
			double num9 = 0.0;
			double num10 = 0.0;
			double num11 = 0.0;
			double num12 = 0.0;
			double num13 = 0.0;
			double num14 = 0.0;
			double num15 = 0.0;
			double num16 = 0.0;
			for (int l = 0; l < array2.Length; l++)
			{
				if (!float.IsNaN(array2[l]))
				{
					double num17 = (double)num + ((double)(l % 8) + 0.5) * (double)num5;
					double num18 = (double)num2 + ((double)(l / 8) + 0.5) * (double)num6;
					double num19 = array2[l];
					num8 += 1.0;
					num9 += num17;
					num10 += num18;
					num11 += num19;
					num12 += num17 * num17;
					num13 += num18 * num18;
					num14 += num17 * num18;
					num15 += num17 * num19;
					num16 += num18 * num19;
				}
			}
			if (num8 < 4.0)
			{
				return false;
			}
			double num20 = num12 - num9 * num9 / num8;
			double num21 = num13 - num10 * num10 / num8;
			double num22 = num14 - num9 * num10 / num8;
			double num23 = num15 - num9 * num11 / num8;
			double num24 = num16 - num10 * num11 / num8;
			double num25 = num20 * num21 - num22 * num22;
			if (Math.Abs(num25) < 1E-09)
			{
				return false;
			}
			double num26 = (num23 * num21 - num24 * num22) / num25;
			double num27 = (num24 * num20 - num23 * num22) / num25;
			if (num26 * num26 + num27 * num27 < 0.04)
			{
				return false;
			}
			rise = new Vector2((float)num26, (float)num27);
			return true;
		}

		private static bool BaseArea(GameObject prefab, out Vector3 area)
		{
			//IL_0001: 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_0012: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: 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)
			area = default(Vector3);
			Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
			EffectArea[] componentsInChildren = prefab.GetComponentsInChildren<EffectArea>(true);
			foreach (EffectArea val in componentsInChildren)
			{
				if (!Object.op_Implicit((Object)(object)val) || (val.m_type & 4) == 0)
				{
					continue;
				}
				Collider[] components = ((Component)val).GetComponents<Collider>();
				foreach (Collider val2 in components)
				{
					if (Object.op_Implicit((Object)(object)val2) && BoundsOf(val2, out var bounds))
					{
						Vector3 lossyScale = ((Component)val).transform.lossyScale;
						SphereCollider val3 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null);
						float num = ((val3 != null) ? (val3.radius * Mathf.Max(new float[3]
						{
							Mathf.Abs(lossyScale.x),
							Mathf.Abs(lossyScale.y),
							Mathf.Abs(lossyScale.z)
						})) : Mathf.Max(((Bounds)(ref bounds)).extents.x * Mathf.Abs(lossyScale.x), ((Bounds)(ref bounds)).extents.z * Mathf.Abs(lossyScale.z)));
						if (!(num <= area.z))
						{
							Vector3 val4 = ((Matrix4x4)(ref worldToLocalMatrix)).MultiplyPoint3x4(((Component)val).transform.TransformPoint(((Bounds)(ref bounds)).center));
							area = new Vector3(val4.x, val4.z, num);
						}
					}
				}
				if (!(area.z <= 0f))
				{
					continue;
				}
				ManualLogSource obj = log;
				if (obj != null)
				{
					obj.LogWarning((object)(((Object)prefab).name + ": its PlayerBase area has no collider the map can read (" + string.Join(", ", from c in ((Component)val).GetComponents<Component>()
						select (!Object.op_Implicit((Object)(object)c)) ? "null" : ((object)c).GetType().Name) + ")"));
				}
			}
			return area.z > 0f;
		}

		private static float SeenExtent(GameObject prefab, Matrix4x4 toRoot)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (val is MeshRenderer || val is SkinnedMeshRenderer)
				{
					Bounds bounds = val.bounds;
					num = Mathf.Max(num, GroundExtent(new Bounds(((Bounds)(ref bounds)).center, ((Bounds)(ref bounds)).size), toRoot));
				}
			}
			return num;
		}

		private static float GroundExtent(Bounds bounds, Matrix4x4 m)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			float num2 = float.MinValue;
			float num3 = float.MaxValue;
			float num4 = float.MinValue;
			for (int i = 0; i < 8; i++)
			{
				Vector3 val = ((Matrix4x4)(ref m)).MultiplyPoint3x4(((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((i & 1) != 0) ? 1 : (-1)), (float)(((i & 2) != 0) ? 1 : (-1)), (float)(((i & 4) != 0) ? 1 : (-1)))));
				num = Mathf.Min(num, val.x);
				num2 = Mathf.Max(num2, val.x);
				num3 = Mathf.Min(num3, val.z);
				num4 = Mathf.Max(num4, val.z);
			}
			return Mathf.Max(num2 - num, num4 - num3);
		}

		private static bool BoundsOf(Collider collider, out Bounds bounds)
		{
			//IL_0038: 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_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)
			//IL_00ff: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			BoxCollider val = (BoxCollider)(object)((collider is BoxCollider) ? collider : null);
			if (val == null)
			{
				MeshCollider val2 = (MeshCollider)(object)((collider is MeshCollider) ? collider : null);
				if (val2 == null)
				{
					SphereCollider val3 = (SphereCollider)(object)((collider is SphereCollider) ? collider : null);
					if (val3 != null)
					{
						bounds = new Bounds(val3.center, Vector3.one * val3.radius * 2f);
						return true;
					}
					CapsuleCollider val4 = (CapsuleCollider)(object)((collider is CapsuleCollider) ? collider : null);
					if (val4 != null)
					{
						Vector3 val5 = Vector3.one * val4.radius * 2f;
						((Vector3)(ref val5))[Mathf.Clamp(val4.direction, 0, 2)] = Mathf.Max(val4.height, val4.radius * 2f);
						bounds = new Bounds(val4.center, val5);
						return true;
					}
				}
				else if (Object.op_Implicit((Object)(object)val2.sharedMesh))
				{
					bounds = val2.sharedMesh.bounds;
					return true;
				}
				bounds = default(Bounds);
				return false;
			}
			bounds = new Bounds(val.center, val.size);
			return true;
		}

		private static string GroupOf(string name, GameObject prefab, Piece piece)
		{
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Invalid comparison between Unknown and I4
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Invalid comparison between Unknown and I4
			string text = name.ToLowerInvariant();
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<TeleportWorld>()))
			{
				return "portal";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Ship>()))
			{
				return "ship";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<PrivateArea>()))
			{
				return "ward";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<CraftingStation>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<StationExtension>()))
			{
				return "station";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Smelter>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<Fermenter>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<CookingStation>()) || Object.op_Implicit((Object)(object)prefab.GetComponent<Beehive>()))
			{
				return "production";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Bed>()))
			{
				return "bed";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Container>()))
			{
				return "chest";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Plant>()) || (!Object.op_Implicit((Object)(object)piece) && Object.op_Implicit((Object)(object)prefab.GetComponent<Pickable>())))
			{
				return "plant";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Door>()))
			{
				return "door";
			}
			if (Object.op_Implicit((Object)(object)prefab.GetComponent<Fireplace>()))
			{
				if (!text.Contains("torch") && !text.Contains("sconce") && !text.Contains("brazier") && !text.Contains("lantern") && !text.Contains("candle"))
				{
					return "fire";
				}
				return "light";
			}
			if (text.Contains("roof"))
			{
				return "roof";
			}
			if (text.Contains("stake") || text.Contains("sharp") || text.Contains("palisade") || text.Contains("spike"))
			{
				return "defense";
			}
			if (Object.op_Implicit((Object)(object)piece))
			{
				PieceCategory category = piece.m_category;
				if (piece.m_comfort > 0 || (int)category == 4 || ((int)category == 0 && !Object.op_Implicit((Object)(object)prefab.GetComponent<WearNTear>())))
				{
					return "furniture";
				}
				if ((int)category == 1)
				{
					return "production";
				}
			}
			if (!Object.op_Implicit((Object)(object)prefab.GetComponent<WearNTear>()))
			{
				return "furniture";
			}
			return "structure";
		}
	}
	public sealed class WorldInfo
	{
		public string Name;

		public string Seed;

		public int Hash;

		public int Generation;

		public long Uid;
	}
	public sealed class SelfInfo
	{
		public string Name;

		public float X;

		public float Y;

		public float Z;

		public float Heading;

		public bool Dead;
	}
	public sealed class PlayerSpot
	{
		public string Name;

		public float X;

		public float Z;
	}
	public sealed class Creature
	{
		public string Prefab;

		public string Name;

		public int Level;

		public float Health;

		public float MaxHealth;

		public float X;

		public float Z;

		public bool Tamed;

		public bool Boss;

		public bool Hostile;
	}
	public sealed class Pin
	{
		public int Type;

		public string Name;

		public float X;

		public float Z;

		public bool Checked;

		public bool Shared;
	}
	public sealed class Icon
	{
		public string Prefab;

		public float X;

		public float Z;
	}
	public sealed class ShipInfo
	{
		public string Prefab;

		public string Name;

		public string Sail;

		public float X;

		public float Z;

		public float Heading;

		public float Speed;
	}
	public sealed class WindInfo
	{
		public float Angle;

		public float Intensity;
	}
	public sealed class Snapshot
	{
		public WorldInfo World;

		public SelfInfo Self;

		public float Reach;

		public PlayerSpot[] Players = new PlayerSpot[0];

		public Creature[] Creatures = new Creature[0];

		public Pin[] Pins = new Pin[0];

		public Icon[] Icons = new Icon[0];

		public bool PinWrites;

		public string FocusKey;

		public ShipInfo Ship;

		public WindInfo Wind;

		public int? ExploredVersion;

		public int? PortalsVersion;

		public int? BuildingsVersion;

		public bool Tracking;

		public TrackInfo Track;
	}
	public static class Capture
	{
		internal static readonly FieldInfo WorldField = AccessTools.Field(typeof(ZNet), "m_world");

		internal static readonly FieldInfo PinsField = AccessTools.Field(typeof(Minimap), "m_pins");

		public static Snapshot Take()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			Snapshot snapshot = new Snapshot();
			World val = ((!Object.op_Implicit((Object)(object)ZNet.instance)) ? ((World)null) : ((World)WorldField.GetValue(null)));
			if (val == null || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return snapshot;
			}
			snapshot.World = new WorldInfo
			{
				Name = val.m_name,
				Seed = val.m_seedName,
				Hash = val.m_seed,
				Uid = val.m_uid,
				Generation = val.m_worldGenVersion
			};
			snapshot.Reach = Reach(ZNet.instance.GetSyncedSimulationDistance(), ZoneSystem.instance.m_zoneSize);
			Player player = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)player))
			{
				Vector3 position = ((Component)player).transform.position;
				SelfInfo obj = new SelfInfo
				{
					Name = player.GetPlayerName(),
					X = position.x,
					Y = position.y,
					Z = position.z
				};
				Quaternion rotation = ((Component)player).transform.rotation;
				obj.Heading = ((Quaternion)(ref rotation)).eulerAngles.y;
				obj.Dead = ((Character)player).IsDead();
				snapshot.Self = obj;
				snapshot.Ship = ShipOf(player);
			}
			snapshot.Wind = Wind();
			snapshot.ExploredVersion = Explored.Version(Time.unscaledTime);
			snapshot.PortalsVersion = Portals.Version;
			snapshot.BuildingsVersion = Buildings.Version;
			snapshot.Track = Track.Current;
			List<PlayerInfo> list = new List<PlayerInfo>();
			ZNet.instance.GetOtherPublicPlayers(list);
			snapshot.Players = list.Select((PlayerInfo info) => new PlayerSpot
			{
				Name = CensorShittyWords.FilterUGC(info.m_name, (UGCType)2, ((ZDOID)(ref info.m_characterID)).UserID),
				X = info.m_position.x,
				Z = info.m_position.z
			}).ToArray();
			snapshot.Creatures = (from character in Character.GetAllCharacters()
				where Object.op_Implicit((Object)(object)character) && !character.IsPlayer() && !character.IsDead()
				select character).Select(delegate(Character character)
			{
				//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)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				Vector3 position2 = ((Component)character).transform.position;
				return new Creature
				{
					Prefab = Utils.GetPrefabName(((Component)character).gameObject),
					Name = character.m_name,
					Level = character.GetLevel(),
					Health = character.GetHealth(),
					MaxHealth = character.GetMaxHealth(),
					X = position2.x,
					Z = position2.z,
					Tamed = character.IsTamed(),
					Boss = character.IsBoss(),
					Hostile = (Object.op_Implicit((Object)(object)player) && BaseAI.IsEnemy(character, (Character)(object)player) && character.GetBaseAI() is MonsterAI)
				};
			}).ToArray();
			if (Object.op_Implicit((Object)(object)Minimap.instance))
			{
				snapshot.Pins = (from pin in (List<PinData>)PinsField.GetValue(Minimap.instance)
					where pin.m_save
					select new Pin
					{
						Type = (int)pin.m_type,
						Name = pin.m_name,
						X = pin.m_pos.x,
						Z = pin.m_pos.z,
						Checked = pin.m_checked,
						Shared = (pin.m_ownerID != 0)
					}).ToArray();
			}
			Dictionary<Vector3, string> dictionary = new Dictionary<Vector3, string>();
			ZoneSystem.instance.GetLocationIcons(dictionary);
			snapshot.Icons = dictionary.Select((KeyValuePair<Vector3, string> icon) => new Icon
			{
				Prefab = icon.Value,
				X = icon.Key.x,
				Z = icon.Key.z
			}).ToArray();
			return snapshot;
		}

		private static ShipInfo ShipOf(Player player)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			Ship val = player.GetControlledShip();
			if (!Object.op_Implicit((Object)(object)val))
			{
				val = Ship.GetLocalShip();
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			Transform transform = ((Component)val).transform;
			Piece component = ((Component)val).GetComponent<Piece>();
			ShipInfo obj = new ShipInfo
			{
				Prefab = Utils.GetPrefabName(((Component)val).gameObject),
				Name = (Object.op_Implicit((Object)(object)component) ? component.m_name : ""),
				X = transform.position.x,
				Z = transform.position.z
			};
			Quaternion rotation = transform.rotation;
			obj.Heading = ((Quaternion)(ref rotation)).eulerAngles.y;
			obj.Speed = val.GetSpeed();
			obj.Sail = ((object)val.GetSpeedSetting()/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
			return obj;
		}

		private static WindInfo Wind()
		{
			//IL_0011: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			EnvMan instance = EnvMan.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return null;
			}
			Vector3 windDir = instance.GetWindDir();
			float num = Mathf.Atan2(windDir.x, windDir.z) * 57.29578f;
			return new WindInfo
			{
				Angle = ((num < 0f) ? (num + 360f) : num),
				Intensity = Mathf.Clamp01(instance.GetWindIntensity())
			};
		}

		public static float Reach(SimulationDistance distance, float zone)
		{
			if (!((SimulationDistance)(ref distance)).IsClassic)
			{
				return Mathf.Max(0f, ((float)((SimulationDistance)(ref distance)).NearSimulationDistance + 0.5f) * zone - zone * Mathf.Sqrt(2f));
			}
			return (float)((SimulationDistance)(ref distance)).NearSimulationDistance * zone;
		}
	}
	public static class Explored
	{
		private static readonly FieldInfo ExploredField = AccessTools.Field(typeof(Minimap), "m_explored");

		private static readonly FieldInfo OthersField = AccessTools.Field(typeof(Minimap), "m_exploredOthers");

		private const float HashEvery = 2f;

		private static int[] words;

		private static Minimap owner;

		private static float next;

		private static int? version;

		public static int? Version(float now, bool force = false)
		{
			Minimap instance = Minimap.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				owner = null;
				version = null;
				return null;
			}
			if (!force && (Object)(object)owner == (Object)(object)instance && version.HasValue && now < next)
			{
				return version;
			}
			owner = instance;
			next = now + 2f;
			BitArray bitArray = ExploredField?.GetValue(instance) as BitArray;
			BitArray bitArray2 = OthersField?.GetValue(instance) as BitArray;
			version = ((bitArray == null || bitArray2 == null) ? ((int?)null) : new int?(Hash(bitArray) * 31 + Hash(bitArray2)));
			return version;
		}

		public static ExploredPlanes Read(float now)
		{
			Minimap instance = Minimap.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return null;
			}
			BitArray bitArray = ExploredField?.GetValue(instance) as BitArray;
			BitArray bitArray2 = OthersField?.GetValue(instance) as BitArray;
			if (bitArray == null || bitArray2 == null)
			{
				return null;
			}
			return new ExploredPlanes
			{
				Size = instance.m_textureSize,
				Explored = Pack(bitArray),
				Others = Pack(bitArray2),
				Version = Version(now, force: true).GetValueOrDefault()
			};
		}

		private static byte[] Pack(BitArray bits)
		{
			byte[] array = new byte[(bits.Length + 7) / 8];
			bits.CopyTo(array, 0);
			return array;
		}

		private static int Hash(BitArray bits)
		{
			int num = (bits.Length + 31) / 32;
			if (words == null || words.Length != num)
			{
				words = new int[num];
			}
			bits.CopyTo(words, 0);
			int num2 = -2128831035;
			int[] array = words;
			foreach (int num3 in array)
			{
				num2 = (num2 ^ num3) * 16777619;
			}
			return num2;
		}
	}
	public sealed class FocusTarget
	{
		public string Kind;

		public string Prefab;
	}
	public static class Focus
	{
		private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

		private static readonly FieldInfo AvailableRecipesField = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

		private static readonly FieldInfo ContainerGridField = AccessTools.Field(typeof(InventoryGui), "m_containerGrid");

		public static bool Typing()
		{
			if ((!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.InTextInput())
			{
				return Menu.IsVisible();
			}
			return true;
		}

		public static FocusTarget Find()
		{
			//IL_002b: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return null;
			}
			InventoryGui instance = InventoryGui.instance;
			if (Object.op_Implicit((Object)(object)instance) && InventoryGui.IsVisible())
			{
				Vector3 pointerPosition = ZInput.pointerPosition;
				Vector2i val = default(Vector2i);
				((Vector2i)(ref val))..ctor((int)pointerPosition.x, (int)pointerPosition.y);
				bool flag = ZInput.IsExclusiveGamepadActive();
				InventoryGrid[] array = (InventoryGrid[])(object)new InventoryGrid[2]
				{
					instance.m_playerGrid,
					(InventoryGrid)(instance.IsContainerOpen() ? /*isinst with value type is only supported in some contexts*/: null)
				};
				foreach (InventoryGrid val2 in array)
				{
					if (Object.op_Implicit((Object)(object)val2))
					{
						string text = ItemPrefab((!flag) ? val2.GetItem(val) : ((Object.op_Implicit((Object)(object)val2.m_uiGroup) && val2.m_uiGroup.IsActive) ? val2.GetGamepadSelectedItem() : null));
						if (text != null)
						{
							return new FocusTarget
							{
								Kind = "item",
								Prefab = text
							};
						}
					}
				}
				Recipe val3 = (flag ? null : HoveredRecipe(instance, pointerPosition)) ?? RecipeOf(SelectedRecipeField?.GetValue(instance));
				if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.m_item))
				{
					return new FocusTarget
					{
						Kind = "item",
						Prefab = ((Object)((Component)val3.m_item).gameObject).name
					};
				}
				return null;
			}
			Character hoverCreature = localPlayer.GetHoverCreature();
			if (Object.op_Implicit((Object)(object)hoverCreature) && !hoverCreature.IsPlayer())
			{
				return new FocusTarget
				{
					Kind = "creature",
					Prefab = Utils.GetPrefabName(((Component)hoverCreature).gameObject)
				};
			}
			GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
			ItemDrop val4 = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<ItemDrop>() : null);
			if (Object.op_Implicit((Object)(object)val4))
			{
				return new FocusTarget
				{
					Kind = "item",
					Prefab = Utils.GetPrefabName(((Component)val4).gameObject)
				};
			}
			return null;
		}

		private static Recipe HoveredRecipe(InventoryGui gui, Vector3 pointer)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (!(AvailableRecipesField?.GetValue(gui) is IList list))
			{
				return null;
			}
			foreach (object item in list)
			{
				object obj = Property(item, "InterfaceElement");
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if (Object.op_Implicit((Object)(object)val) && val.activeInHierarchy)
				{
					Transform transform = val.transform;
					RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if (Object.op_Implicit((Object)(object)val2) && RectTransformUtility.RectangleContainsScreenPoint(val2, Vector2.op_Implicit(pointer)))
					{
						return RecipeOf(item);
					}
				}
			}
			return null;
		}

		private static Recipe RecipeOf(object pair)
		{
			if (pair != null)
			{
				object obj = Property(pair, "Recipe");
				return (Recipe)((obj is Recipe) ? obj : null);
			}
			return null;
		}

		private static object Property(object row, string name)
		{
			return row?.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(row);
		}

		private static string ItemPrefab(ItemData item)
		{
			if (item == null)
			{
				return null;
			}
			if (Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return ((Object)item.m_dropPrefab).name;
			}
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ((IEnumerable<GameObject>)ObjectDB.instance.m_items).FirstOrDefault((Func<GameObject, bool>)delegate(GameObject go)
			{
				if (Object.op_Implicit((Object)(object)go))
				{
					ItemDrop component = go.GetComponent<ItemDrop>();
					if (component != null)
					{
						return component.m_itemData.m_shared.m_name == item.m_shared.m_name;
					}
				}
				return false;
			}) : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return ((Object)val).name;
		}
	}
	public static class Json
	{
		public const int Protocol = 1;

		public static string Write(Snapshot s, float range)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				((JsonWriter)val).WritePropertyName("v");
				((JsonWriter)val).WriteValue(1);
				Field((JsonWriter)(object)val, "mod", "1.5.3");
				((JsonWriter)val).WritePropertyName("world");
				if (s.World == null)
				{
					((JsonWriter)val).WriteNull();
				}
				else
				{
					((JsonWriter)val).WriteStartObject();
					Field((JsonWriter)(object)val, "name", s.World.Name);
					Field((JsonWriter)(object)val, "seed", s.World.Seed);
					((JsonWriter)val).WritePropertyName("hash");
					((JsonWriter)val).WriteValue(s.World.Hash);
					Field((JsonWriter)(object)val, "uid", s.World.Uid.ToString(CultureInfo.InvariantCulture));
					((JsonWriter)val).WritePropertyName("gen");
					((JsonWriter)val).WriteValue(s.World.Generation);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WritePropertyName("reach");
				((JsonWriter)val).WriteValue(Round(s.Reach));
				((JsonWriter)val).WritePropertyName("self");
				if (s.Self == null)
				{
					((JsonWriter)val).WriteNull();
				}
				else
				{
					((JsonWriter)val).WriteStartObject();
					Field((JsonWriter)(object)val, "name", s.Self.Name);
					Number((JsonWriter)(object)val, "x", s.Self.X);
					Number((JsonWriter)(object)val, "y", s.Self.Y);
					Number((JsonWriter)(object)val, "z", s.Self.Z);
					Number((JsonWriter)(object)val, "heading", s.Self.Heading);
					((JsonWriter)val).WritePropertyName("dead");
					((JsonWriter)val).WriteValue(s.Self.Dead);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WritePropertyName("players");
				((JsonWriter)val).WriteStartArray();
				PlayerSpot[] players = s.Players;
				foreach (PlayerSpot playerSpot in players)
				{
					((JsonWriter)val).WriteStartObject();
					Field((JsonWriter)(object)val, "name", playerSpot.Name);
					Number((JsonWriter)(object)val, "x", playerSpot.X);
					Number((JsonWriter)(object)val, "z", playerSpot.Z);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WritePropertyName("creatures");
				((JsonWriter)val).WriteStartArray();
				Creature[] creatures = s.Creatures;
				foreach (Creature creature in creatures)
				{
					if (s.Self != null && Within(creature.X - s.Self.X, creature.Z - s.Self.Z, range))
					{
						((JsonWriter)val).WriteStartObject();
						Field((JsonWriter)(object)val, "prefab", creature.Prefab);
						Field((JsonWriter)(object)val, "name", creature.Name);
						((JsonWriter)val).WritePropertyName("level");
						((JsonWriter)val).WriteValue(creature.Level);
						Number((JsonWriter)(object)val, "hp", creature.Health);
						Number((JsonWriter)(object)val, "max", creature.MaxHealth);
						Number((JsonWriter)(object)val, "x", creature.X);
						Number((JsonWriter)(object)val, "z", creature.Z);
						((JsonWriter)val).WritePropertyName("tamed");
						((JsonWriter)val).WriteValue(creature.Tamed);
						((JsonWriter)val).WritePropertyName("boss");
						((JsonWriter)val).WriteValue(creature.Boss);
						((JsonWriter)val).WritePropertyName("hostile");
						((JsonWriter)val).WriteValue(creature.Hostile);
						((JsonWriter)val).WriteEndObject();
					}
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WritePropertyName("pins");
				((JsonWriter)val).WriteStartArray();
				Pin[] pins = s.Pins;
				foreach (Pin pin in pins)
				{
					((JsonWriter)val).WriteStartObject();
					((JsonWriter)val).WritePropertyName("type");
					((JsonWriter)val).WriteValue(pin.Type);
					Field((JsonWriter)(object)val, "name", pin.Name);
					Number((JsonWriter)(object)val, "x", pin.X);
					Number((JsonWriter)(object)val, "z", pin.Z);
					((JsonWriter)val).WritePropertyName("checked");
					((JsonWriter)val).WriteValue(pin.Checked);
					((JsonWriter)val).WritePropertyName("shared");
					((JsonWriter)val).WriteValue(pin.Shared);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WritePropertyName("pinWrites");
				((JsonWriter)val).WriteValue(s.PinWrites);
				((JsonWriter)val).WritePropertyName("focusKey");
				if (s.FocusKey == null)
				{
					((JsonWriter)val).WriteNull();
				}
				else
				{
					((JsonWriter)val).WriteValue(s.FocusKey);
				}
				((JsonWriter)val).WritePropertyName("ship");
				if (s.Ship == null)
				{
					((JsonWriter)val).WriteNull();
				}
				else
				{
					((JsonWriter)val).WriteStartObject();
					Field((JsonWriter)(object)val, "prefab", s.Ship.Prefab);
					Field((JsonWriter)(object)val, "name", s.Ship.Name);
					Number((JsonWriter)(object)val, "x", s.Ship.X);
					Number((JsonWriter)(object)val, "z", s.Ship.Z);
					Number((JsonWriter)(object)val, "heading", s.Ship.Heading);
					Number((JsonWriter)(object)val, "speed", s.Ship.Speed);
					Field((JsonWriter)(object)val, "sail", s.Ship.Sail);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WritePropertyName("wind");
				if (s.Wind == null)
				{
					((JsonWriter)val).WriteNull();
				}
				else
				{
					((JsonWriter)val).WriteStartObject();
					Number((JsonWriter)(object)val, "angle", s.Wind.Angle);
					((JsonWriter)val).WritePropertyName("intensity");
					((JsonWriter)val).WriteValue(Math.Round(s.Wind.Intensity, 2));
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WritePropertyName("exploredVersion");
				if (s.ExploredVersion.HasValue)
				{
					((JsonWriter)val).WriteValue(s.ExploredVersion.Value);
				}
				else
				{
					((JsonWriter)val).WriteNull();
				}
				((JsonWriter)val).WritePropertyName("portalsVersion");
				if (s.PortalsVersion.HasValue)
				{
					((JsonWriter)val).WriteValue(s.PortalsVersion.Value);
				}
				else
				{
					((JsonWriter)val).WriteNull();
				}
				((JsonWriter)val).WritePropertyName("buildingsVersion");
				if (s.BuildingsVersion.HasValue)
				{
					((JsonWriter)val).WriteValue(s.BuildingsVersion.Value);
				}
				else
				{
					((JsonWriter)val).WriteNull();
				}
				((JsonWriter)val).WritePropertyName("tracking");
				((JsonWriter)val).WriteValue(s.Tracking);
				((JsonWriter)val).WritePropertyName("track");
				if (s.Track == null)
				{
					((JsonWriter)val).WriteNull();
				}
				else
				{
					((JsonWriter)val).WriteStartObject();
					Number((JsonWriter)(object)val, "x", s.Track.X);
					Number((JsonWriter)(object)val, "z", s.Track.Z);
					Field((JsonWriter)(object)val, "label", s.Track.Label);
					Number((JsonWriter)(object)val, "clearWithin", s.Track.ClearWithin);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WritePropertyName("icons");
				((JsonWriter)val).WriteStartArray();
				Icon[] icons = s.Icons;
				foreach (Icon icon in icons)
				{
					((JsonWriter)val).WriteStartObject();
					Field((JsonWriter)(object)val, "prefab", icon.Prefab);
					Number((JsonWriter)(object)val, "x", icon.X);
					Number((JsonWriter)(object)val, "z", icon.Z);
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		public static string Focus(FocusTarget target)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				((JsonWriter)val).WritePropertyName("v");
				((JsonWriter)val).WriteValue(1);
				Field((JsonWriter)(object)val, "type", "focus");
				Field((JsonWriter)(object)val, "kind", target.Kind);
				Field((JsonWriter)(object)val, "prefab", target.Prefab);
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		public static string Explored(ExploredPlanes planes)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				((JsonWriter)val).WritePropertyName("v");
				((JsonWriter)val).WriteValue(1);
				((JsonWriter)val).WritePropertyName("size");
				((JsonWriter)val).WriteValue(planes.Size);
				((JsonWriter)val).WritePropertyName("version");
				((JsonWriter)val).WriteValue(planes.Version);
				Field((JsonWriter)(object)val, "explored", Convert.ToBase64String(planes.Explored));
				Field((JsonWriter)(object)val, "others", Convert.ToBase64String(planes.Others));
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		public static string Error(string code, string message)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				Field((JsonWriter)(object)val, "error", code);
				Field((JsonWriter)(object)val, "message", message);
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		public unsafe static string KeyLabel(KeyboardShortcut shortcut)
		{
			//IL_0002: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0)
			{
				return null;
			}
			List<string> list = new List<string>();
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if ((int)modifier != 0 && modifier != ((KeyboardShortcut)(ref shortcut)).MainKey)
				{
					list.Add(((object)(*(KeyCode*)(&modifier))/*cast due to .constrained prefix*/).ToString());
				}
			}
			list.Add(((object)((KeyboardShortcut)(ref shortcut)).MainKey/*cast due to .constrained prefix*/).ToString());
			return string.Join(" + ", list);
		}

		private static bool Within(float dx, float dz, float range)
		{
			return dx * dx + dz * dz <= range * range;
		}

		private static double Round(float value)
		{
			return Math.Round(value, 1);
		}

		private static void Field(JsonWriter w, string name, string value)
		{
			w.WritePropertyName(name);
			w.WriteValue(value);
		}

		private static void Number(JsonWriter w, string name, float value)
		{
			w.WritePropertyName(name);
			w.WriteValue(Round(value));
		}
	}
	public sealed class LiveServer
	{
		private sealed class Request
		{
			public string Method;

			public string Path;

			public float Range = float.PositiveInfinity;

			public readonly Dictionary<string, string> Headers = new Dictionary<string, string>();

			public int Length = -1;

			public byte[] Body = new byte[0];

			public bool ReadBody(Stream stream)
			{
				if (!Headers.TryGetValue("content-length", out var value))
				{
					return true;
				}
				if (!int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out Length) || Length > 65536)
				{
					return false;
				}
				byte[] array = new byte[Length];
				int num;
				for (int i = 0; i < Length; i += num)
				{
					num = stream.Read(array, i, Length - i);
					if (num == 0)
					{
						return false;
					}
				}
				Body = ((Length <= 4096) ? array : null);
				return true;
			}

			public static Request Read(Stream stream)
			{
				List<byte> list = new List<byte>();
				byte[] array = new byte[1];
				while (!EndsWithBlankLine(list))
				{
					if (list.Count >= 16384 || stream.Read(array, 0, 1) == 0)
					{
						return null;
					}
					list.Add(array[0]);
				}
				string[] array2 = Encoding.ASCII.GetString(list.ToArray()).Split(new string[1] { "\r\n" }, StringSplitOptions.None);
				string[] array3 = array2[0].Split(' ');
				if (array3.Length < 2)
				{
					return null;
				}
				string[] array4 = array3[1].Split(new char[1] { '?' }, 2);
				Request request = new Request
				{
					Method = array3[0],
					Path = array4[0]
				};
				if (array4.Length == 2)
				{
					string[] array5 = array4[1].Split('&');
					for (int i = 0; i < array5.Length; i++)
					{
						string[] array6 = array5[i].Split(new char[1] { '=' }, 2);
						if (array6.Length == 2 && array6[0] == "range" && float.TryParse(Uri.UnescapeDataString(array6[1]), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result >= 0f)
						{
							request.Range = result;
						}
					}
				}
				foreach (string item in array2.Skip(1))
				{
					int num = item.IndexOf(':');
					if (num > 0)
					{
						request.Headers[item.Substring(0, num).Trim().ToLowerInvariant()] = item.Substring(num + 1).Trim();
					}
				}
				return request;
			}

			private static bool EndsWithBlankLine(List<byte> b)
			{
				if (b.Count >= 4 && b[b.Count - 4] == 13 && b[b.Count - 3] == 10 && b[b.Count - 2] == 13)
				{
					return b[b.Count - 1] == 10;
				}
				return false;
			}
		}

		private const int MaxHeaderBytes = 16384;

		private const int MaxBodyBytes = 4096;

		private const int MaxDiscardBytes = 65536;

		private const int WriteTimeoutMs = 5000;

		private readonly int port;

		private readonly HashSet<string> origins;

		private readonly ManualLogSource log;

		private readonly object gate = new object();

		private TcpListener listener;

		private volatile bool running;

		private Snapshot latest = new Snapshot();

		private long revision;

		private string focus;

		private long focusRevision;

		private int clients;

		private readonly ConcurrentQueue<PinCommand> commands = new ConcurrentQueue<PinCommand>();

		private readonly ConcurrentQueue<ExploredRequest> exploredRequests = new ConcurrentQueue<ExploredRequest>();

		private readonly ConcurrentQueue<NearbyRequest> nearbyRequests = new ConcurrentQueue<NearbyRequest>();

		private readonly ConcurrentQueue<TrackCommand> trackCommands = new ConcurrentQueue<TrackCommand>();

		public Func<bool> PinWritesAllowed = () => false;

		public Func<string> PortalsJson = () => (string)null;

		public Func<string> BuildingsJson = () => (string)null;

		public Func<bool> TrackingAllowed = () => false;

		public bool HasClients => Volatile.Read(in clients) > 0;

		public LiveServer(int port, IEnumerable<string> origins, ManualLogSource log)
		{
			this.port = port;
			this.origins = new HashSet<string>(from o in origins
				select o.Trim().TrimEnd('/') into o
				where o.Length > 0
				select o, StringComparer.OrdinalIgnoreCase);
			this.log = log;
		}

		public void Start()
		{
			listener = new TcpListener(IPAddress.Loopback, port);
			listener.Start();
			running = true;
			Thread thread = new Thread(Accept);
			thread.IsBackground = true;
			thread.Name = "LiveSeedMap accept";
			thread.Start();
			log.LogInfo((object)$"Listening on http://127.0.0.1:{port}");
		}

		public void Stop()
		{
			running = false;
			listener?.Stop();
			lock (gate)
			{
				Monitor.PulseAll(gate);
			}
		}

		public void Publish(Snapshot snapshot)
		{
			lock (gate)
			{
				latest = snapshot;
				revision++;
				Monitor.PulseAll(gate);
			}
		}

		public void PublishFocus(FocusTarget target)
		{
			string text = Json.Focus(target);
			lock (gate)
			{
				focus = text;
				focusRevision++;
				Monitor.PulseAll(gate);
			}
		}

		public bool TryTakeCommand(out PinCommand command)
		{
			return commands.TryDequeue(out command);
		}

		public bool TryTakeExplored(out ExploredRequest request)
		{
			return exploredRequests.TryDequeue(out request);
		}

		public bool TryTakeNearby(out NearbyRequest request)
		{
			return nearbyRequests.TryDequeue(out request);
		}

		public bool TryTakeTrack(out TrackCommand command)
		{
			return trackCommands.TryDequeue(out command);
		}

		private void Accept()
		{
			while (running)
			{
				TcpClient client;
				try
				{
					client = listener.AcceptTcpClient();
				}
				catch (SocketException)
				{
					if (running)
					{
						continue;
					}
					break;
				}
				catch (ObjectDisposedException)
				{
					break;
				}
				Thread thread = new Thread((ThreadStart)delegate
				{
					Serve(client);
				});
				thread.IsBackground = true;
				thread.Name = "LiveSeedMap client";
				thread.Start();
			}
		}

		private void Serve(TcpClient client)
		{
			using (client)
			{
				try
				{
					client.NoDelay = true;
					NetworkStream stream = client.GetStream();
					Request request = Request.Read(stream);
					if (request != null && request.ReadBody(stream))
					{
						Respond(stream, request);
					}
				}
				catch (IOException)
				{
				}
				catch (SocketException)
				{
				}
				catch (ObjectDisposedException)
				{
				}
			}
		}

		private void Respond(Stream stream, Request request)
		{
			request.Headers.TryGetValue("origin", out var value);
			request.Headers.TryGetValue("host", out var value2);
			if ((!(value2 == $"127.0.0.1:{port}") && !(value2 == $"localhost:{port}")) || (value != null && !origins.Contains(value)))
			{
				Write(stream, "403 Forbidden", null, "text/plain", "Forbidden");
				return;
			}
			if (request.Method == "OPTIONS")
			{
				Write(stream, "204 No Content", value, null, null, "Access-Control-Allow-Methods: GET, POST, DELETE\r\nAccess-Control-Allow-Headers: Content-Type\r\nAccess-Control-Allow-Private-Network: true\r\nAccess-Control-Max-Age: 600\r\n");
				return;
			}
			if ((request.Path == "/v1/pins" && (request.Method == "POST" || request.Method == "DELETE")) || (request.Path == "/v1/pins/checked" && request.Method == "POST"))
			{
				PinWrite(stream, request, value);
				return;
			}
			if (request.Path == "/v1/track" && (request.Method == "POST" || request.Method == "DELETE"))
			{
				TrackWrite(stream, request, value);
				return;
			}
			float range = request.Range;
			if (request.Method == "GET" && request.Path == "/v1/state")
			{
				Interlocked.Increment(ref clients);
				try
				{
					long seen;
					lock (gate)
					{
						seen = revision;
					}
					Snapshot snapshot = Next(ref seen);
					if (snapshot != null)
					{
						Write(stream, "200 OK", value, "application/json", Json.Write(snapshot, range));
					}
					return;
				}
				finally
				{
					Interlocked.Decrement(ref clients);
				}
			}
			if (request.Method == "GET" && request.Path == "/v1/stream")
			{
				Stream(stream, value, range);
			}
			else if (request.Method == "GET" && request.Path == "/v1/explored")
			{
				ExploredRead(stream, value);
			}
			else if (request.Method == "GET" && request.Path == "/v1/nearby")
			{
				NearbyRead(stream, value, range);
			}
			else if (request.Method == "GET" && request.Path == "/v1/buildings")
			{
				string text = BuildingsJson();
				if (text == null)
				{
					Write(stream, "409 Conflict", value, "application/json", Json.Error("no-world", "No world is loaded."));
				}
				else
				{
					Write(stream, "200 OK", value, "application/json", text);
				}
			}
			else if (request.Method == "GET" && request.Path == "/v1/portals")
			{
				string text2 = PortalsJson();
				if (text2 == null)
				{
					Write(stream, "409 Conflict", value, "application/json", Json.Error("no-world", "No world is loaded."));
				}
				else
				{
					Write(stream, "200 OK", value, "application/json", text2);
				}
			}
			else
			{
				Write(stream, "404 Not Found", value, "text/plain", "Not found");
			}
		}

		private void Stream(Stream stream, string origin, float range)
		{
			string s = "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nCache-Control: no-store\r\nConnection: keep-alive\r\n" + Cors(origin) + "\r\n";
			byte[] bytes = Encoding.ASCII.GetBytes(s);
			stream.Write(bytes, 0, bytes.Length);
			stream.Flush();
			Interlocked.Increment(ref clients);
			try
			{
				long num;
				long num2;
				lock (gate)
				{
					num = revision;
					num2 = focusRevision;
				}
				while (true)
				{
					Snapshot s2 = null;
					string text;
					lock (gate)
					{
						while (running && revision == num && focusRevision == num2)
						{
							Monitor.Wait(gate);
						}
						if (!running)
						{
							break;
						}
						if (focusRevision != num2)
						{
							num2 = focusRevision;
							text = "event: focus\ndata: " + focus + "\n\n";
						}
						else
						{
							num = revision;
							s2 = latest;
							text = null;
						}
					}
					byte[] bytes2 = Encoding.UTF8.GetBytes(text ?? ("data: " + Json.Write(s2, range) + "\n\n"));
					stream.Write(bytes2, 0, bytes2.Length);
					stream.Flush();
				}
			}
			finally
			{
				Interlocked.Decrement(ref clients);
			}
		}

		private void PinWrite(Stream stream, Request request, string origin)
		{
			if (!PinWritesAllowed())
			{
				Write(stream, "403 Forbidden", origin, "application/json", Json.Error("pin-writes-off", "Pin writes are off in this game. Set AllowPinWrites = true in BepInEx/config/wiki.thevalheim.liveseedmap.cfg to let the seed map change your pins."));
				return;
			}
			request.Headers.TryGetValue("content-type", out var value);
			if (value == null || !value.Split(';')[0].Trim().Equals("application/json", StringComparison.OrdinalIgnoreCase))
			{
				Write(stream, "415 Unsupported Media Type", origin, "application/json", Json.Error("unsupported-media", "Send the pin as application/json."));
				return;
			}
			if (request.Length < 0)
			{
				Write(stream, "411 Length Required", origin, "application/json", Json.Error("length-required", "Content-Length is required."));
				return;
			}
			if (request.Body == null)
			{
				Write(stream, "413 Payload Too Large", origin, "application/json", Json.Error("too-large", "A pin is at most " + 4096 + " bytes."));
				return;
			}
			string body = Encoding.UTF8.GetString(request.Body);
			PinCommand.Kind kind = ((request.Method == "DELETE") ? PinCommand.Kind.Remove : ((request.Path == "/v1/pins/checked") ? PinCommand.Kind.Check : PinCommand.Kind.Add));
			string problem;
			PinArgs pinArgs = PinArgs.Parse(body, out problem);
			if (pinArgs == null || (kind == PinCommand.Kind.Check && !pinArgs.Checked.HasValue))
			{
				Write(stream, "400 Bad Request", origin, "application/json", problem ?? Json.Error("bad-request", "\"checked\" must be true or false."));
				return;
			}
			PinCommand pinCommand = new PinCommand
			{
				Action = kind,
				Body = body
			};
			commands.Enqueue(pinCommand);
			if (!pinCommand.Done.Wait(5000))
			{
				pinCommand.Abandoned = true;
				Write(stream, "503 Service Unavailable", origin, "application/json", Json.Error("busy", "The game did not answer in time; try again."));
			}
			else
			{
				string status = ((pinCommand.Status == 200) ? "200 OK" : ((pinCommand.Status == 400) ? "400 Bad Request" : ((pinCommand.Status == 409) ? "409 Conflict" : "500 Internal Server Error")));
				Write(stream, status, origin, "application/json", pinCommand.Response);
			}
		}

		private void TrackWrite(Stream stream, Request request, string origin)
		{
			if (!TrackingAllowed())
			{
				Write(stream, "403 Forbidden", origin, "application/json", Json.Error("tracking-off", "Tracking is off in this game. Set AllowTracking = true in BepInEx/config/wiki.thevalheim.liveseedmap.cfg to let the seed map show a target in the game."));
				return;
			}
			TrackCommand trackCommand = new TrackCommand();
			if (request.Method == "POST")
			{
				request.Headers.TryGetValue("content-type", out var value);
				if (value == null || !value.Split(';')[0].Trim().Equals("application/json", StringComparison.OrdinalIgnoreCase))
				{
					Write(stream, "415 Unsupported Media Type", origin, "application/json", Json.Error("unsupported-media", "Send the target as application/json."));
					return;
				}
				if (request.Length < 0)
				{
					Write(stream, "411 Length Required", origin, "application/json", Json.Error("length-required", "Content-Length is required."));
					return;
				}
				if (request.Body == null)
				{
					Write(stream, "413 Payload Too Large", origin, "application/json", Json.Error("too-large", "A target is at most " + 4096 + " bytes."));
					return;
				}
				trackCommand.Target = TrackArgs.Parse(Encoding.UTF8.GetString(request.Body), out var problem);
				if (trackCommand.Target == null)
				{
					Write(stream, "400 Bad Request", origin, "application/json", problem);
					return;
				}
			}
			trackCommands.Enqueue(trackCommand);
			if (!trackCommand.Done.Wait(5000))
			{
				trackCommand.Abandoned = true;
				Write(stream, "503 Service Unavailable", origin, "application/json", Json.Error("busy", "The game did not answer in time; try again."));
			}
			else
			{
				string status = ((trackCommand.Status == 200) ? "200 OK" : ((trackCommand.Status == 409) ? "409 Conflict" : "500 Internal Server Error"));
				Write(stream, status, origin, "application/json", trackCommand.Response);
			}
		}

		private void ExploredRead(Stream stream, string origin)
		{
			ExploredRequest exploredRequest = new ExploredRequest();
			exploredRequests.Enqueue(exploredRequest);
			if (!exploredRequest.Done.Wait(5000))
			{
				exploredRequest.Abandoned = true;
				Write(stream, "503 Service Unavailable", origin, "application/json", Json.Error("busy", "The game did not answer in time; try again."));
			}
			else if (exploredRequest.Planes == null)
			{
				Write(stream, "409 Conflict", origin, "application/json", Json.Error("no-world", "No world is loaded."));
			}
			else
			{
				Write(stream, "200 OK", origin, "application/json", Json.Explored(exploredRequest.Planes));
			}
		}

		private void NearbyRead(Stream stream, string origin, float range)
		{
			NearbyRequest nearbyRequest = new NearbyRequest
			{
				Range = range
			};
			nearbyRequests.Enqueue(nearbyRequest);
			if (!nearbyRequest.Done.Wait(5000))
			{
				nearbyRequest.Abandoned = true;
				Write(stream, "503 Service Unavailable", origin, "application/json", Json.Error("busy", "The game did not answer in time; try again."));
			}
			else if (nearbyRequest.Json == null)
			{
				Write(stream, "409 Conflict", origin, "application/json", Json.Error("no-player", "No character is in a world."));
			}
			else
			{
				Write(stream, "200 OK", origin, "application/json", nearbyRequest.Json);
			}
		}

		private Snapshot Next(ref long seen)
		{
			lock (gate)
			{
				while (running && revision == seen)
				{
					Monitor.Wait(gate);
				}
				if (!running)
				{
					return null;
				}
				seen = revision;
				return latest;
			}
		}

		private static string Cors(string origin)
		{
			if (origin != null)
			{
				return "Access-Control-Allow-Origin: " + origin + "\r\nVary: Origin\r\n";
			}
			return "";
		}

		private static void Write(Stream stream, string status, string origin, string type, string body, string extra = "")
		{
			byte[] array = ((body == null) ? new byte[0] : Encoding.UTF8.GetBytes(body));
			string s = "HTTP/1.1 " + status + "\r\n" + Cors(origin) + extra + ((type == null) ? "" : ("Content-Type: " + type + "; charset=utf-8\r\nCache-Control: no-store\r\n")) + $"Content-Length: {array.Length}\r\nConnection: close\r\n\r\n";
			byte[] bytes = Encoding.ASCII.GetBytes(s);
			stream.Write(bytes, 0, bytes.Length);
			stream.Write(array, 0, array.Length);
			stream.Flush();
		}
	}
	public sealed class ExploredPlanes
	{
		public int Size;

		public int Version;

		public byte[] Explored;

		public byte[] Others;
	}
	public sealed class ExploredRequest
	{
		public ExploredPlanes Planes;

		public volatile bool Abandoned;

		public readonly ManualResetEventSlim Done = new ManualResetEventSlim(initialState: false);
	}
	public sealed class NearbyRequest
	{
		public float Range;

		public string Json;

		public volatile bool Abandoned;

		public readonly ManualResetEventSlim Done = new ManualResetEventSlim(initialState: false);
	}
	public static class Nearby
	{
		private static readonly FieldInfo InstancesField = AccessTools.Field(typeof(ZNetScene), "m_instances");

		public const float MaxRange = 400f;

		public static string Read(float range)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			ZNetScene instance = ZNetScene.instance;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)instance) || !(InstancesField?.GetValue(instance) is Dictionary<ZDO, ZNetView> dictionary))
			{
				return null;
			}
			float num = ((Object.op_Implicit((Object)(object)ZNet.instance) && Object.op_Implicit((Object)(object)ZoneSystem.instance)) ? Capture.Reach(ZNet.instance.GetSyncedSimulationDistance(), ZoneSystem.instance.m_zoneSize) : 400f);
			float num2 = Mathf.Min(float.IsInfinity(range) ? num : range, 400f);
			Vector3 position = ((Component)localPlayer).transform.position;
			List<(string, string, Vector3)> list = new List<(string, string, Vector3)>();
			foreach (KeyValuePair<ZDO, ZNetView> item in dictionary)
			{
				ZNetView value = item.Value;
				if (!Object.op_Implicit((Object)(object)value) || item.Key == null)
				{
					continue;
				}
				Vector3 position2 = item.Key.GetPosition();
				float num3 = position2.x - position.x;
				float num4 = position2.z - position.z;
				if (!(num3 * num3 + num4 * num4 > num2 * num2))
				{
					string text = KindOf(((Component)value).gameObject);
					GameObject prefab = instance.GetPrefab(item.Key.GetPrefab());
					if (text != null)
					{
						list.Add((Object.op_Implicit((Object)(object)prefab) ? ((Object)prefab).name : Utils.GetPrefabName(((Component)value).gameObject), text, position2));
					}
				}
			}
			StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
			JsonTextWriter val = new JsonTextWriter((TextWriter)stringWriter);
			try
			{
				((JsonWriter)val).WriteStartObject();
				((JsonWriter)val).WritePropertyName("v");
				((JsonWriter)val).WriteValue(1);
				((JsonWriter)val).WritePropertyName("x");
				((JsonWriter)val).WriteValue(Math.Round(position.x, 1));
				((JsonWriter)val).WritePropertyName("z");
				((JsonWriter)val).WriteValue(Math.Round(position.z, 1));
				((JsonWriter)val).WritePropertyName("radius");
				((JsonWriter)val).WriteValue(Math.Round(num2, 1));
				((JsonWriter)val).WritePropertyName("objects");
				((JsonWriter)val).WriteStartArray();
				foreach (var item2 in list.OrderBy<(string, string, Vector3), string>(((string Prefab, string Kind, Vector3 At) r) => r.Prefab, StringComparer.Ordinal))
				{
					((JsonWriter)val).WriteStartObject();
					((JsonWriter)val).WritePropertyName("prefab");
					((JsonWriter)val).WriteValue(item2.Item1);
					((JsonWriter)val).WritePropertyName("kind");
					((JsonWriter)val).WriteValue(item2.Item2);
					((JsonWriter)val).WritePropertyName("x");
					((JsonWriter)val).WriteValue(Math.Round(item2.Item3.x, 2));
					((JsonWriter)val).WritePropertyName("y");
					((JsonWriter)val).WriteValue(Math.Round(item2.Item3.y, 2));
					((JsonWriter)val).WritePropertyName("z");
					((JsonWriter)val).WriteValue(Math.Round(item2.Item3.z, 2));
					((JsonWriter)val).WriteEndObject();
				}
				((JsonWriter)val).WriteEndArray();
				((JsonWriter)val).WriteEndObject();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
			return stringWriter.ToString();
		}

		private static string KindOf(GameObject go)
		{
			if (Object.op_Implicit((Object)(object)go.GetComponent<Pickable>()) || Object.op_Implicit((Object)(object)go.GetComponent<PickableItem>()))
			{
				return "pickable";
			}
			if (Object.op_Implicit((Object)(object)go.GetComponent<TreeBase>()))
			{
				return "tree";
			}
			if (Object.op_Implicit((Object)(object)go.GetComponent<MineRock>()) || Object.op_Implicit((Object)(object)go.GetComponent<MineRock5>()))
			{
				return "rock";
			}
			if (Object.op_Implicit((Object)(object)go.GetComponent<Destructible>()))
			{
				return "destructible";
			}
			return null;
		}
	}
	public sealed class PinCommand
	{
		public enum Kind
		{
			Add,
			Remove,
			Check
		}

		public Kind Action;

		public string Body;

		public int Status = 500;

		public string Response = "";

		public volatile bool Abandoned;

		public readonly ManualResetEventSlim Done = new ManualResetEventSlim(initialState: false);
	}
	public sealed class PinArgs
	{
		public static readonly int[] Placeable = new int[5] { 0, 1, 2, 3, 6 };

		public const int MaxName = 64;

		public const float MaxCoordinate = 10500f;

		public int Type;

		public string Name;

		public float X;

		public float Z;

		public bool? Checked;

		public static PinArgs Parse(string body, out string problem)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Invalid comparison between Unknown and I4
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Invalid comparison between Unknown and I4
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Invalid comparison between Unknown and I4
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Invalid comparison between Unknown and I4
			problem = null;
			JObject val;
			try
			{
				val = JObject.Parse(body ?? "");
			}
			catch (Exception)
			{
				problem = Json.Error("bad-request", "The body is not a JSON object.");
				return null;
			}
			if (val["type"] == null || (int)val["type"].Type != 6)
			{
				problem = Json.Error("bad-request", "\"type\" must be a whole number.");
				return null;
			}
			long num = Extensions.Value<long>((IEnumerable<JToken>)val["type"]);
			if (num < 0 || num > 64 || Array.IndexOf(Placeable, (int)num) < 0)
			{
				problem = Json.Error("pin-type", "Only fire, house, hammer, dot and portal pins (types 0, 1, 2, 3, 6) can be written.");
				return null;
			}
			string text = "";
			JToken val2 = val["name"];
			if (val2 != null && (int)val2.Type != 10)
			{
				if ((int)val2.Type != 8)
				{
					problem = Json.Error("bad-request", "\"name\" must be a string.");
					return null;
				}
				text = new string((from c in Extensions.Value<string>((IEnumerable<JToken>)val2)
					where !char.IsControl(c)
					select c).ToArray());
				if (text.Length > 64)
				{
					problem = Json.Error("bad-request", $"\"name\" is longer than {64} characters.");
					return null;
				}
			}
			if (!Coordinate(val["x"], out var value) || !Coordinate(val["z"], out var value2))
			{
				problem = Json.Error("bad-request", $"\"x\" and \"z\" must be numbers within {10500f} m of the world centre.");
				return null;
			}
			bool? flag = null;
			JToken val3 = val["checked"];
			if (val3 != null && (int)val3.Type != 10)
			{
				if ((int)val3.Type != 9)
				{
					problem = Json.Error("bad-request", "\"checked\" must be true or false.");
					return null;
				}
				flag = Extensions.Value<bool>((IEnumerable<JToken>)val3);
			}
			return new PinArgs
			{
				Type = (int)num,
				Name = text,
				X = value,
				Z = value2,
				Checked = flag
			};
		}

		private static bool Coordinate(JToken token, out float value)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			value = 0f;
			if (token == null || ((int)token.Type != 6 && (int)token.Type != 7))
			{
				return false;
			}
			double num = Extensions.Value<double>((IEnumerable<JToken>)token);
			if (double.IsNaN(num) || double.IsInfinity(num) || Math.Abs(num) > 10500.0)
			{
				return false;
			}
			value = (float)num;
			return true;
		}
	}
	public static class PinWrites
	{
		public const float MatchRadius = 1f;

		private static readonly FieldInfo UpdateField = AccessTools.Field(typeof(Minimap), "m_pinUpdateRequired");

		public static void Execute(PinCommand command)
		{
			try
			{
				Run(command);
			}
			catch (Exception ex)
			{
				command.Status = 500;
				command.Response = Json.Error("failed", ex.Message);
			}
		}

		private static void Run(PinCommand command)
		{
			//IL_00cb: 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_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Minimap.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				command.Status = 409;
				command.Response = Json.Error("no-world", "Load a world first; the game has no map open.");
				return;
			}
			string problem;
			PinArgs args = PinArgs.Parse(command.Body, out problem);
			if (args == null)
			{
				command.Status = 400;
				command.Response = problem;
				return;
			}
			if (command.Action == PinCommand.Kind.Check && !args.Checked.HasValue)
			{
				command.Status = 400;
				command.Response = Json.Error("bad-request", "\"checked\" must be true or false.");
				return;
			}
			Minimap instance = Minimap.instance;
			Vector3 at = new Vector3(args.X, 0f, args.Z);
			List<PinData> list = ((List<PinData>)Capture.PinsField.GetValue(instance)).Where((PinData pin) => pin.m_save && pin.m_ownerID == 0L && (int)pin.m_type == args.Type && pin.m_name == args.Name && Utils.DistanceXZ(pin.m_pos, at) <= 1f).ToList();
			command.Status = 200;
			switch (command.Action)
			{
			case PinCommand.