Decompiled source of MerchantSignposts v0.2.0

BepInEx/plugins/MerchantSignposts/MerchantSignposts.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace MerchantSignposts;

internal static class BuildGround
{
	private static readonly HashSet<int> CompilerPrefabs = new HashSet<int> { StringExtensionMethods.GetStableHashCode("_TerrainCompiler") };

	internal static float Height(Vector3 position)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: 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_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: 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_00ec: 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_0135: Unknown result type (might be due to invalid IL or missing references)
		ZoneSystem zones = ZoneSystem.instance;
		WorldGenerator world = WorldGenerator.instance;
		Vector2s zone = ZoneSystem.GetZone(position);
		Vector3 zonePos = ZoneSystem.GetZonePos(zone);
		float x0 = zonePos.x - zones.m_zoneSize * 0.5f;
		float z0 = zonePos.z - zones.m_zoneSize * 0.5f;
		List<ZDO> list = new List<ZDO>();
		ZdoSweep.CollectZone(zone, CompilerPrefabs, list);
		List<byte[]> list2 = new List<byte[]>(list.Count);
		foreach (ZDO item in list)
		{
			if (ZoneSystem.GetZone(item.GetPosition()) == zone)
			{
				list2.Add(item.GetByteArray(ZDOVars.s_TCData, (byte[])null));
			}
		}
		return TerrainEdits.Height(list2, position.x - x0, position.z - z0, zones.m_zoneSize, (float num, float num2) => SignpostPlan.TerrainHeight(world, zones, new Vector3(x0 + num, 0f, z0 + num2)), delegate
		{
			MerchantSignpostsPlugin.Log.LogWarning((object)$"[MerchantSignposts] invalid terrain edits in zone ({zone.x}, {zone.y}); using generated ground");
		}, SignpostPlan.TerrainHeight(world, zones, position));
	}

	internal static void CheckMirrors()
	{
		MethodInfo[] array = new MethodInfo[5]
		{
			AccessTools.Method(typeof(TerrainComp), "Save", (Type[])null, (Type[])null),
			AccessTools.Method(typeof(TerrainComp), "Load", (Type[])null, (Type[])null),
			AccessTools.Method(typeof(TerrainComp), "ApplyToHeightmap", (Type[])null, (Type[])null),
			AccessTools.Method(typeof(HeightmapBuilder), "Build", (Type[])null, (Type[])null),
			AccessTools.Method(typeof(Heightmap), "RebuildCollisionMesh", (Type[])null, (Type[])null)
		};
		for (int i = 0; i < array.Length; i++)
		{
			if (array[i] == null)
			{
				MerchantSignpostsPlugin.Log.LogWarning((object)"[MerchantSignposts] a mirrored terrain method is missing; review terrain height compatibility");
				break;
			}
		}
	}
}
internal static class Commitment
{
	internal static void Observe(List<ZDO> boards)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: 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_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: 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_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: 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)
		ZNet instance = ZNet.instance;
		if (!MerchantSignpostsPlugin.CommitmentEnabled.Value || !MerchantSignpostsPlugin.WorldPlacement.Value || (Object)(object)instance == (Object)null || !instance.IsServer() || ZDOMan.instance == null)
		{
			return;
		}
		List<(Vector3, string)> list = new List<(Vector3, string)>();
		foreach (ZNetPeer peer in instance.GetPeers())
		{
			if (peer.IsReady())
			{
				list.Add((peer.m_refPos, peer.m_playerName));
			}
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			list.Add((((Component)localPlayer).transform.position, localPlayer.GetPlayerName()));
		}
		if (list.Count == 0 || SignpostPlan.Get() == null)
		{
			return;
		}
		float value = MerchantSignpostsPlugin.CommitDistance.Value;
		if (float.IsNaN(value) || float.IsInfinity(value) || value < 0f)
		{
			return;
		}
		Vector3 val = default(Vector3);
		foreach (ZDO board in boards)
		{
			string text = board.GetString("MerchantSignposts.location", "");
			if (text.Length == 0 || board.GetBool("MerchantSignposts.manual", false) || !board.GetVec3("MerchantSignposts.origin", ref val) || board.GetBool("MerchantSignposts.retired", false) || board.GetBool("MerchantSignposts.seen", false))
			{
				continue;
			}
			foreach (var item in list)
			{
				Vector3 val2 = board.GetPosition() - item.Item1;
				if (!(val2.x * val2.x + val2.z * val2.z > value * value))
				{
					Mark(board, "MerchantSignposts.seen");
					Reconciler.RequestExtendingSweep();
					Commit(text, board.GetVec3("MerchantSignposts.target", Vector3.zero), item.Item2);
					break;
				}
			}
		}
	}

	internal static void Commit(string location, Vector3 target, string player)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: 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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: 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_0093: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: 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_012c: Unknown result type (might be due to invalid IL or missing references)
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)instance == (Object)null)
		{
			return;
		}
		List<Vector2s> list = new List<Vector2s>();
		bool flag = false;
		foreach (KeyValuePair<Vector2s, LocationInstance> locationInstance in instance.m_locationInstances)
		{
			LocationInstance value = locationInstance.Value;
			if (value.m_location != null && !(value.m_location.m_prefabName != location))
			{
				if (value.m_placed)
				{
					return;
				}
				if (Reconciler.Near(value.m_position, target))
				{
					flag = true;
				}
				else
				{
					list.Add(locationInstance.Key);
				}
			}
		}
		if (!flag || list.Count == 0)
		{
			return;
		}
		foreach (Vector2s item in list)
		{
			instance.m_locationInstances.Remove(item);
		}
		Prune(instance.m_locationIDCache.Values, location, target);
		Prune(instance.m_locationGroupCache.Values, location, target);
		Prune(instance.m_locationMaxGroupCache.Values, location, target);
		Merchants.Merchant merchant;
		string text = (Merchants.TryFind(location, out merchant) ? merchant.Label : location);
		MerchantSignpostsPlugin.Log.LogInfo((object)$"[MerchantSignposts] committed {text} at {DateTime.UtcNow:O} on {player}'s sighting, {list.Count} candidates discarded");
		Reconciler.RequestExtendingSweep();
	}

	private static void Prune(IEnumerable<List<LocationInstance>> caches, string location, Vector3 target)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		foreach (List<LocationInstance> cache in caches)
		{
			cache.RemoveAll((LocationInstance instance) => instance.m_location != null && instance.m_location.m_prefabName == location && !instance.m_placed && !Reconciler.Near(instance.m_position, target));
		}
	}

	internal static void Mark(ZDO zdo, string key)
	{
		if (!zdo.GetBool(key, false))
		{
			zdo.SetOwner(ZDOMan.GetSessionID());
			zdo.Set(key, true);
		}
	}
}
internal enum Restoration
{
	Never,
	NextServerStart,
	AfterDelay
}
internal sealed class DestroyedMarker
{
	internal string Identity;

	internal string LocationPrefab;

	internal Vector3 Target;

	internal Vector3 Origin;

	internal double Time;
}
internal static class DestroyedStore
{
	private const string RecordsKey = "MerchantSignposts.destroyedRecords.v1";

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

	private static readonly List<DestroyedMarker> Unidentified = new List<DestroyedMarker>();

	private static IReadOnlyDictionary<Vector2s, ZDO> Controllers = new Dictionary<Vector2s, ZDO>();

	private static readonly HashSet<Vector2s> Dirty = new HashSet<Vector2s>();

	private static readonly HashSet<Vector2s> KnownZones = new HashSet<Vector2s>();

	private static ZNet _session;

	private static bool _sessionStart = true;

	internal static int Count => ByIdentity.Count + Unidentified.Count;

	internal static bool IsMarked(string identity)
	{
		return ByIdentity.ContainsKey(identity);
	}

	internal static void BeginSession()
	{
		ByIdentity.Clear();
		Unidentified.Clear();
		Controllers = new Dictionary<Vector2s, ZDO>();
		Dirty.Clear();
		KnownZones.Clear();
		_sessionStart = true;
	}

	private static void Sync()
	{
		if (_session != ZNet.instance)
		{
			_session = ZNet.instance;
			BeginSession();
		}
	}

	internal static bool Record(ZDO piece, double now)
	{
		//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)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		Sync();
		DestroyedMarker destroyedMarker = new DestroyedMarker
		{
			Identity = piece.GetString("MerchantSignposts.identity", ""),
			LocationPrefab = piece.GetString("MerchantSignposts.location", ""),
			Target = piece.GetVec3("MerchantSignposts.target", Vector3.zero),
			Origin = piece.GetVec3("MerchantSignposts.origin", piece.GetPosition()),
			Time = now
		};
		if (!Add(destroyedMarker))
		{
			return false;
		}
		string arg = LogLabel(destroyedMarker);
		MerchantSignpostsPlugin.Log.LogInfo((object)$"[MerchantSignposts] destroyed signpost {arg} withheld; restoration={MerchantSignpostsPlugin.DestroyedSignRestoration.Value}");
		Write(ZoneSystem.GetZone(destroyedMarker.Origin));
		return true;
	}

	internal static string LogLabel(DestroyedMarker marker)
	{
		Merchants.Merchant merchant;
		string text = (Merchants.TryFind(marker.LocationPrefab, out merchant) ? merchant.Label : marker.LocationPrefab);
		string[] array = (marker.Identity ?? "").Split(new char[1] { '/' });
		if (array.Length != 3)
		{
			return text;
		}
		string[] array2 = array[0].Split(new char[1] { ':' });
		if (array2.Length != 3 || array2[0] != marker.LocationPrefab || !int.TryParse(array2[1], NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array2[2], NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out result) || !int.TryParse(array[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result2) || result2 <= 0 || !int.TryParse(array[2], NumberStyles.None, CultureInfo.InvariantCulture, out var result3) || result3 <= 0)
		{
			return text;
		}
		return text + " spoke " + result2.ToString(CultureInfo.InvariantCulture) + " point " + result3.ToString(CultureInfo.InvariantCulture);
	}

	private static bool Add(DestroyedMarker marker)
	{
		if (marker.Identity.Length > 0)
		{
			if (ByIdentity.ContainsKey(marker.Identity))
			{
				return false;
			}
			ByIdentity[marker.Identity] = marker;
			return true;
		}
		if (Unidentified.Exists((DestroyedMarker other) => other.LocationPrefab == marker.LocationPrefab && Reconciler.Near(other.Target, marker.Target) && Reconciler.Near(other.Origin, marker.Origin)))
		{
			return false;
		}
		Unidentified.Add(marker);
		return true;
	}

	internal static void Prepare(IReadOnlyDictionary<Vector2s, ZDO> controllers, SignpostPlan terrain, out int restored, out int pruned)
	{
		Sync();
		restored = 0;
		pruned = 0;
		Controllers = controllers;
		Restoration value = MerchantSignpostsPlugin.DestroyedSignRestoration.Value;
		if (_sessionStart)
		{
			_sessionStart = false;
			Load();
			if (value == Restoration.NextServerStart)
			{
				restored += RemoveAll((DestroyedMarker marker) => true);
			}
		}
		if (value == Restoration.AfterDelay)
		{
			double now = ZNet.instance.GetTimeSeconds();
			double delay = (double)MerchantSignpostsPlugin.DestroyedSignRestorationDelayHours.Value * 3600.0;
			restored += RemoveAll((DestroyedMarker marker) => now >= marker.Time + delay);
		}
		pruned += RemoveAll((DestroyedMarker marker) => !Reconciler.CampExists(terrain, marker.LocationPrefab, marker.Target));
		Flush();
	}

	internal static bool IsWithheld(SignpostPlan.Planned point, Vector3 anchor)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		string text = SignpostPlan.Identity(point);
		if (ByIdentity.ContainsKey(text))
		{
			return true;
		}
		DestroyedMarker destroyedMarker = Unidentified.Find((DestroyedMarker candidate) => Matches(candidate, point, anchor));
		if (destroyedMarker == null)
		{
			return false;
		}
		Unidentified.Remove(destroyedMarker);
		destroyedMarker.Identity = text;
		ByIdentity[text] = destroyedMarker;
		Dirty.Add(ZoneSystem.GetZone(destroyedMarker.Origin));
		return true;
	}

	private static bool Matches(DestroyedMarker marker, SignpostPlan.Planned point, Vector3 anchor)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: 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_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		if (marker.LocationPrefab == point.LocationPrefab && Reconciler.Near(marker.Target, point.Target))
		{
			if (!Reconciler.Near(marker.Origin, point.Position))
			{
				return Reconciler.Near(marker.Origin, anchor);
			}
			return true;
		}
		return false;
	}

	private static int RemoveAll(Predicate<DestroyedMarker> match)
	{
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		List<DestroyedMarker> list = new List<DestroyedMarker>();
		foreach (DestroyedMarker value in ByIdentity.Values)
		{
			if (match(value))
			{
				list.Add(value);
			}
		}
		foreach (DestroyedMarker item in Unidentified)
		{
			if (match(item))
			{
				list.Add(item);
			}
		}
		foreach (DestroyedMarker item2 in list)
		{
			if (item2.Identity.Length > 0)
			{
				ByIdentity.Remove(item2.Identity);
			}
			else
			{
				Unidentified.Remove(item2);
			}
			Dirty.Add(ZoneSystem.GetZone(item2.Origin));
		}
		return list.Count;
	}

	private static void Load()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//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_00f7: Unknown result type (might be due to invalid IL or missing references)
		List<DestroyedMarker> list = new List<DestroyedMarker>();
		foreach (DestroyedMarker value in ByIdentity.Values)
		{
			if (Dirty.Contains(ZoneSystem.GetZone(value.Origin)))
			{
				list.Add(value);
			}
		}
		foreach (DestroyedMarker item in Unidentified)
		{
			if (Dirty.Contains(ZoneSystem.GetZone(item.Origin)))
			{
				list.Add(item);
			}
		}
		ByIdentity.Clear();
		Unidentified.Clear();
		foreach (KeyValuePair<Vector2s, ZDO> controller in Controllers)
		{
			string text = controller.Value.GetString("MerchantSignposts.destroyedRecords.v1", "");
			if (text.Length > 0)
			{
				KnownZones.Add(controller.Key);
			}
			string[] array = text.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (TryParse(array[i], out var marker))
				{
					Add(marker);
				}
			}
		}
		foreach (DestroyedMarker item2 in list)
		{
			Add(item2);
		}
	}

	internal static void Flush()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		foreach (Vector2s item in new List<Vector2s>(Dirty))
		{
			Write(item);
		}
	}

	internal static void RecheckBeforeSave()
	{
		//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_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		Sync();
		if ((Object)(object)ZoneSystem.instance == (Object)null || ZDOMan.instance == null)
		{
			return;
		}
		Controllers = PieceIndex.ZoneControllers(ZoneSystem.instance);
		HashSet<Vector2s> hashSet = new HashSet<Vector2s>(KnownZones);
		hashSet.UnionWith(Dirty);
		foreach (DestroyedMarker value in ByIdentity.Values)
		{
			hashSet.Add(ZoneSystem.GetZone(value.Origin));
		}
		foreach (DestroyedMarker item in Unidentified)
		{
			hashSet.Add(ZoneSystem.GetZone(item.Origin));
		}
		int num = 0;
		foreach (Vector2s item2 in hashSet)
		{
			if (Write(item2))
			{
				num++;
			}
		}
		MerchantSignpostsPlugin.Log.LogInfo((object)$"[MerchantSignposts] destroyed save recheck: zones checked={hashSet.Count}, zones rewritten={num}");
	}

	private static bool Write(Vector2s zone)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: 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_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: 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_0104: Unknown result type (might be due to invalid IL or missing references)
		KnownZones.Add(zone);
		if (!Controllers.TryGetValue(zone, out var value) || ZDOMan.instance.GetZDO(value.m_uid) != value)
		{
			Dirty.Add(zone);
			return false;
		}
		List<string> list = new List<string>();
		foreach (DestroyedMarker value2 in ByIdentity.Values)
		{
			if (ZoneSystem.GetZone(value2.Origin) == zone)
			{
				list.Add(Serialize(value2));
			}
		}
		foreach (DestroyedMarker item in Unidentified)
		{
			if (ZoneSystem.GetZone(item.Origin) == zone)
			{
				list.Add(Serialize(item));
			}
		}
		list.Sort(StringComparer.Ordinal);
		string text = string.Join("\n", list);
		Dirty.Remove(zone);
		if (value.GetString("MerchantSignposts.destroyedRecords.v1", "") == text)
		{
			return false;
		}
		value.SetOwner(ZDOMan.GetSessionID());
		value.Set("MerchantSignposts.destroyedRecords.v1", text);
		return true;
	}

	private static string Serialize(DestroyedMarker marker)
	{
		//IL_002a: 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)
		return string.Join("|", Encode(marker.Identity), Encode(marker.LocationPrefab), Point(marker.Target), Point(marker.Origin), marker.Time.ToString("R", CultureInfo.InvariantCulture));
	}

	private static bool TryParse(string line, out DestroyedMarker marker)
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		marker = null;
		string[] array = line.Split(new char[1] { '|' });
		if (array.Length != 5 || !TryPoint(array[2], out var point) || !TryPoint(array[3], out var point2) || !double.TryParse(array[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
		{
			return false;
		}
		try
		{
			marker = new DestroyedMarker
			{
				Identity = Decode(array[0]),
				LocationPrefab = Decode(array[1]),
				Target = point,
				Origin = point2,
				Time = result
			};
			return marker.LocationPrefab.Length != 0;
		}
		catch (FormatException)
		{
			return false;
		}
	}

	private static string Point(Vector3 value)
	{
		return string.Join(",", value.x.ToString("R", CultureInfo.InvariantCulture), value.y.ToString("R", CultureInfo.InvariantCulture), value.z.ToString("R", CultureInfo.InvariantCulture));
	}

	private static bool TryPoint(string value, out Vector3 point)
	{
		//IL_0001: 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)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		point = default(Vector3);
		string[] array = value.Split(new char[1] { ',' });
		if (array.Length != 3 || !float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
		{
			return false;
		}
		point = new Vector3(result, result2, result3);
		return true;
	}

	private static string Encode(string value)
	{
		return Convert.ToBase64String(Encoding.UTF8.GetBytes(value ?? ""));
	}

	private static string Decode(string value)
	{
		return Encoding.UTF8.GetString(Convert.FromBase64String(value));
	}
}
[HarmonyPatch]
internal static class DestructionAttribution
{
	private static readonly HashSet<ZDOID> Own = new HashSet<ZDOID>();

	private static ZNet _session;

	internal static void Destroy(ZDO zdo)
	{
		Expect(zdo);
		zdo.SetOwner(ZDOMan.GetSessionID());
		ZDOMan.instance.DestroyZDO(zdo);
	}

	internal static void Expect(GameObject go)
	{
		ZNetView val = (((Object)(object)go != (Object)null) ? go.GetComponent<ZNetView>() : null);
		ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null);
		if (val2 != null)
		{
			Expect(val2);
		}
	}

	private static void Expect(ZDO zdo)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		Sync();
		Own.Add(zdo.m_uid);
	}

	private static void Sync()
	{
		if (_session != ZNet.instance)
		{
			_session = ZNet.instance;
			Own.Clear();
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(ZDOMan), "RPC_DestroyZDO")]
	private static void BeforeDestroyZDO(long sender, ZPackage pkg)
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		ZNet instance = ZNet.instance;
		if ((Object)(object)instance == (Object)null || !instance.IsServer() || ZDOMan.instance == null)
		{
			return;
		}
		Sync();
		int pos = pkg.GetPos();
		bool flag = false;
		try
		{
			int num = pkg.ReadInt();
			for (int i = 0; i < num; i++)
			{
				ZDOID val = pkg.ReadZDOID();
				if (sender != ZDOMan.GetSessionID() || !Own.Contains(val))
				{
					ZDO zDO = ZDOMan.instance.GetZDO(val);
					if (zDO != null && Reconciler.PlannedPiece(zDO) && !zDO.GetBool("MerchantSignposts.retired", false))
					{
						flag |= DestroyedStore.Record(zDO, instance.GetTimeSeconds());
					}
				}
			}
		}
		catch (Exception ex)
		{
			MerchantSignpostsPlugin.Log.LogWarning((object)("[MerchantSignposts] could not attribute a destruction: " + ex.Message));
		}
		finally
		{
			pkg.SetPos(pos);
		}
		if (flag)
		{
			Reconciler.RequestSweep();
		}
	}
}
internal sealed class GameDependencies
{
	internal bool IsOff { get; private set; } = true;

	internal bool Start(Harmony harmony, Action<string> logOff, IEnumerable<(Type Type, string Name)> extraNames = null, Action afterPatch = null)
	{
		IsOff = true;
		string text;
		try
		{
			List<string> list = new List<string>();
			Type[] array = Check(list);
			if (extraNames != null)
			{
				foreach (var extraName in extraNames)
				{
					Resolve(extraName.Type, extraName.Name, null, list);
				}
			}
			if (list.Count == 0)
			{
				Type[] array2 = array;
				foreach (Type type in array2)
				{
					harmony.CreateClassProcessor(type, true).Patch();
				}
				afterPatch?.Invoke();
				IsOff = false;
				return true;
			}
			text = "this game build lacks " + string.Join(", ", list.Distinct());
		}
		catch (Exception ex)
		{
			text = "startup failed: " + ex.Message;
			try
			{
				Unpatch(harmony);
			}
			catch (Exception ex2)
			{
				text = text + "; rollback failed: " + ex2.Message;
			}
		}
		logOff("[MerchantSignposts] off: " + text.Replace('\r', ' ').Replace('\n', ' '));
		return false;
	}

	internal static void Unpatch(Harmony harmony)
	{
		MethodBase[] array = harmony.GetPatchedMethods().ToArray();
		foreach (MethodBase methodBase in array)
		{
			harmony.Unpatch(methodBase, (HarmonyPatchType)0, harmony.Id);
		}
	}

	private static Type[] Check(List<string> misses)
	{
		//IL_01d4: 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_01dd: Unknown result type (might be due to invalid IL or missing references)
		Type[] array = (from t in typeof(MerchantSignpostsPlugin).Assembly.GetTypes()
			where t.IsDefined(typeof(HarmonyPatch), inherit: true) || AccessTools.GetDeclaredMethods(t).Any((MethodInfo m) => m.IsDefined(typeof(HarmonyPatch), inherit: true))
			select t).OrderBy<Type, string>((Type t) => t.FullName, StringComparer.Ordinal).ToArray();
		Type[] array2 = array;
		foreach (Type type in array2)
		{
			HarmonyMethod mergedFromType = HarmonyMethodExtensions.GetMergedFromType(type);
			foreach (MethodInfo patch in AccessTools.GetDeclaredMethods(type))
			{
				object[] attributes = patch.GetCustomAttributes(inherit: true);
				if (!new string[6] { "Prefix", "Postfix", "Transpiler", "Finalizer", "ReversePatch", "ILManipulator" }.Any((string k) => patch.Name == k || attributes.Any((object a) => a.GetType().FullName == "HarmonyLib.Harmony" + k)))
				{
					if (patch.IsDefined(typeof(HarmonyPatch), inherit: true))
					{
						misses.Add(type.Name + "." + patch.Name + " (no patch kind)");
					}
					continue;
				}
				List<HarmonyMethod> fromMethod = HarmonyMethodExtensions.GetFromMethod((MethodBase)patch);
				if (fromMethod.Count((HarmonyMethod a) => a.methodName != null) > 1)
				{
					misses.Add(type.Name + "." + patch.Name + " (multiple targets unsupported)");
					continue;
				}
				HarmonyMethod val = HarmonyMethodExtensions.Merge(mergedFromType, HarmonyMethod.Merge(fromMethod));
				if ((val.methodType.HasValue && val.methodType != (MethodType?)0) || val.declaringType == null || val.methodName == null)
				{
					misses.Add(type.Name + "." + patch.Name + " (unsupported target)");
					continue;
				}
				MethodInfo methodInfo = Resolve(val.declaringType, val.methodName, val.argumentTypes, misses);
				if (methodInfo != null)
				{
					CheckBindings(methodInfo, patch, misses);
				}
			}
		}
		try
		{
			GameFields.Sectors = AccessTools.FieldRefAccess<ZDOMan, List<ZDO>[]>("m_objectsBySector");
		}
		catch (Exception)
		{
			misses.Add("ZDOMan.m_objectsBySector");
		}
		try
		{
			GameFields.Portals = AccessTools.FieldRefAccess<ZDOMan, Dictionary<SectorIndex, List<ZDO>>>("m_portalObjects");
		}
		catch (Exception)
		{
			misses.Add("ZDOMan.m_portalObjects");
		}
		try
		{
			GameFields.GeneratedZones = AccessTools.FieldRefAccess<ZoneSystem, HashSet<Vector2s>>("m_generatedZones");
		}
		catch (Exception)
		{
			misses.Add("ZoneSystem.m_generatedZones");
		}
		return array;
	}

	private static MethodInfo Resolve(Type type, string name, Type[] arguments, List<string> misses)
	{
		try
		{
			MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, arguments, (Type[])null);
			if (methodInfo == null)
			{
				misses.Add(type.Name + "." + name);
			}
			return methodInfo;
		}
		catch (AmbiguousMatchException)
		{
			misses.Add(type.Name + "." + name + " (ambiguous)");
			return null;
		}
	}

	internal static void CheckBindings(MethodInfo original, MethodInfo patch, List<string> misses)
	{
		ParameterInfo[] parameters = original.GetParameters();
		ParameterInfo[] parameters2 = patch.GetParameters();
		foreach (ParameterInfo parameterInfo in parameters2)
		{
			string name = parameterInfo.Name;
			if (name == "__state" || name.StartsWith("___", StringComparison.Ordinal))
			{
				continue;
			}
			Type type = null;
			int result;
			if (name == "__instance")
			{
				type = (original.IsStatic ? null : original.DeclaringType);
			}
			else if (name == "__result")
			{
				type = ((original.ReturnType == typeof(void)) ? null : original.ReturnType);
			}
			else if (name.StartsWith("__", StringComparison.Ordinal) && int.TryParse(name.Substring(2), out result))
			{
				if (result >= 0 && result < parameters.Length)
				{
					type = parameters[result].ParameterType;
				}
			}
			else
			{
				type = parameters.FirstOrDefault((ParameterInfo p) => p.Name == name)?.ParameterType;
			}
			Type type2 = parameterInfo.ParameterType;
			bool isByRef = type2.IsByRef;
			if (type2.IsByRef)
			{
				type2 = type2.GetElementType();
			}
			if (type != null && type.IsByRef)
			{
				type = type.GetElementType();
			}
			if (type == null || (isByRef ? (type2 != type) : (!type2.IsAssignableFrom(type))))
			{
				misses.Add(original.DeclaringType.Name + "." + original.Name + ":" + name + " (missing or incompatible parameter for " + patch.DeclaringType.Name + "." + patch.Name + ")");
			}
		}
	}
}
internal static class GameFields
{
	internal static FieldRef<ZDOMan, List<ZDO>[]> Sectors;

	internal static FieldRef<ZDOMan, Dictionary<SectorIndex, List<ZDO>>> Portals;

	internal static FieldRef<ZoneSystem, HashSet<Vector2s>> GeneratedZones;
}
internal static class InvariantNumbers
{
	internal static string Format(float value)
	{
		return value.ToString("R", CultureInfo.InvariantCulture);
	}

	internal static string InstanceIdentity(string prefab, int x, int z)
	{
		return prefab + ":" + x.ToString(CultureInfo.InvariantCulture) + ":" + z.ToString(CultureInfo.InvariantCulture);
	}

	internal static bool IsSubcommand(string word, string command)
	{
		return string.Equals(word, command, StringComparison.OrdinalIgnoreCase);
	}

	internal static bool TryCoordinates(string[] words, out float x, out float z)
	{
		x = (z = 0f);
		if (words.Length == 0)
		{
			return true;
		}
		if (words.Length == 2 && float.TryParse(words[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x) && float.TryParse(words[1], NumberStyles.Float, CultureInfo.InvariantCulture, out z) && !float.IsNaN(x) && !float.IsInfinity(x) && !float.IsNaN(z))
		{
			return !float.IsInfinity(z);
		}
		return false;
	}
}
internal static class Merchants
{
	internal struct Merchant
	{
		public string LocationPrefab;

		public string Label;
	}

	private static MerchantSettings _settings = NewSettings();

	private static List<Merchant> _merchants;

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

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

	private static MerchantSettings NewSettings()
	{
		return new MerchantSettings(delegate(string message)
		{
			MerchantSignpostsPlugin.Log.LogWarning((object)message);
		});
	}

	internal static void WarnOnce(string message)
	{
		if (ParserWarnings.Add(message))
		{
			MerchantSignpostsPlugin.Log.LogWarning((object)message);
		}
	}

	internal static void Reset()
	{
		_settings = NewSettings();
		_merchants = null;
		PlacementTables.Clear();
		ParserWarnings.Clear();
	}

	private static IEnumerable<string> Names()
	{
		if (_merchants == null)
		{
			yield break;
		}
		foreach (Merchant merchant in _merchants)
		{
			yield return merchant.LocationPrefab;
		}
	}

	internal static void Refresh()
	{
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance == (Object)null || !instance.LocationsGenerated)
		{
			return;
		}
		if (_merchants == null)
		{
			List<string> list = new List<string>();
			foreach (ZoneLocation location in instance.m_locations)
			{
				list.Add(location.m_prefabName);
			}
			_merchants = new List<Merchant>();
			foreach (KeyValuePair<string, string> item in _settings.Pairs(MerchantSignpostsPlugin.MerchantTable.Value, "Merchants.Table", list))
			{
				_merchants.Add(new Merchant
				{
					LocationPrefab = item.Key,
					Label = item.Value
				});
			}
			PlacementTables["trail"] = MerchantSignpostsPlugin.Trails.Value;
			PlacementTables["water margin"] = MerchantSignpostsPlugin.WaterMargins.Value;
			PlacementTables["same-merchant keep-out"] = MerchantSignpostsPlugin.SameMerchantKeepOuts.Value;
			PlacementTables["biome"] = MerchantSignpostsPlugin.Biomes.Value;
			foreach (KeyValuePair<string, string> placementTable in PlacementTables)
			{
				ParsePairs(placementTable.Value, placementTable.Key);
			}
		}
		ParsePairs(MerchantSignpostsPlugin.TextColors.Value, "TextColors");
		List<KeyValuePair<string, string>> overrides = ParsePairs(MerchantSignpostsPlugin.PolePrefabs.Value, "PolePrefabs");
		_settings.ValidatePosts(MerchantSignpostsPlugin.PolePrefab.Value, overrides, Names(), ((Object)(object)ZNetScene.instance == (Object)null) ? null : ((Func<string, bool>)((string name) => (Object)(object)ZNetScene.instance.GetPrefab(name) != (Object)null)));
	}

	internal static List<Merchant> Parse(string table)
	{
		Refresh();
		if (_merchants != null)
		{
			return new List<Merchant>(_merchants);
		}
		return new List<Merchant>();
	}

	internal static List<KeyValuePair<string, string>> ParsePairs(string table, string what)
	{
		if (PlacementTables.TryGetValue(what, out var value))
		{
			table = value;
		}
		return _settings.Pairs(table, what switch
		{
			"biome" => "Biomes", 
			"same-merchant keep-out" => "SameMerchantKeepOuts", 
			"water margin" => "WaterMargins", 
			"trail" => "Trails", 
			_ => what, 
		}, (_merchants == null) ? null : Names(), what == "TextColors" || what == "PolePrefabs", what == "TextColors");
	}

	private static string Lookup(string table, string what, string locationPrefab)
	{
		Refresh();
		foreach (KeyValuePair<string, string> item in ParsePairs(table, what))
		{
			if (string.Equals(item.Key, locationPrefab, StringComparison.OrdinalIgnoreCase))
			{
				return item.Value;
			}
		}
		return null;
	}

	internal static string PoleFor(string locationPrefab)
	{
		return Lookup(MerchantSignpostsPlugin.PolePrefabs.Value, "PolePrefabs", locationPrefab) ?? MerchantSignpostsPlugin.PolePrefab.Value;
	}

	internal static HashSet<string> PolePrefabs()
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal) { MerchantSignpostsPlugin.PolePrefab.Value };
		foreach (KeyValuePair<string, string> item in ParsePairs(MerchantSignpostsPlugin.PolePrefabs.Value, "PolePrefabs"))
		{
			hashSet.Add(item.Value);
		}
		return hashSet;
	}

	internal static string SignText(string locationPrefab, string label)
	{
		return ColoredText(locationPrefab, label, MerchantSignpostsPlugin.TextTemplate.Value);
	}

	internal static string RetiredText(string locationPrefab, string label)
	{
		return ColoredText(locationPrefab, label, MerchantSignpostsPlugin.RetiredTextTemplate.Value);
	}

	private static string ColoredText(string locationPrefab, string label, string template)
	{
		string text = template.Replace("{merchant}", label);
		string text2 = Lookup(MerchantSignpostsPlugin.TextColors.Value, "TextColors", locationPrefab);
		if (!string.IsNullOrEmpty(text2))
		{
			return "<color=" + text2 + ">" + text + "</color>";
		}
		return text;
	}

	internal static bool TryLabel(string locationPrefab, out string label)
	{
		label = null;
		foreach (Merchant item in Parse(MerchantSignpostsPlugin.MerchantTable.Value))
		{
			if (item.LocationPrefab == locationPrefab)
			{
				label = item.Label;
			}
		}
		return label != null;
	}

	internal static string ExpectedText(ZDO board)
	{
		string text = board.GetString("MerchantSignposts.location", "");
		string label;
		bool flag = TryLabel(text, out label);
		if (board.GetBool("MerchantSignposts.retired", false))
		{
			return RetiredText(text, label ?? text);
		}
		if (!flag)
		{
			return null;
		}
		return SignText(text, label);
	}

	internal static bool TryFind(string nameOrLabel, out Merchant merchant)
	{
		foreach (Merchant item in Parse(MerchantSignpostsPlugin.MerchantTable.Value))
		{
			if (string.Equals(item.LocationPrefab, nameOrLabel, StringComparison.OrdinalIgnoreCase) || string.Equals(item.Label, nameOrLabel, StringComparison.OrdinalIgnoreCase))
			{
				merchant = item;
				return true;
			}
		}
		merchant = default(Merchant);
		return false;
	}

	internal static bool TryNearestInstance(string locationPrefab, Vector3 from, out Vector3 position, out bool placed, out int remaining)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: 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_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		position = Vector3.zero;
		placed = false;
		remaining = 0;
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		float num = float.MaxValue;
		bool result = false;
		foreach (KeyValuePair<Vector2s, LocationInstance> locationInstance in instance.m_locationInstances)
		{
			LocationInstance value = locationInstance.Value;
			if (value.m_location != null && !(value.m_location.m_prefabName != locationPrefab))
			{
				remaining++;
				float num2 = Vector3.Distance(from, value.m_position);
				if (num2 < num)
				{
					num = num2;
					position = value.m_position;
					placed = value.m_placed;
					result = true;
				}
			}
		}
		return result;
	}
}
internal sealed class MerchantSettings
{
	private readonly Action<string> _warning;

	private readonly HashSet<string> _warned = new HashSet<string>(StringComparer.Ordinal);

	private readonly Dictionary<string, List<KeyValuePair<string, string>>> _cache = new Dictionary<string, List<KeyValuePair<string, string>>>(StringComparer.Ordinal);

	private string _lastPosts;

	internal MerchantSettings(Action<string> warning)
	{
		_warning = warning;
	}

	internal void Reset()
	{
		_warned.Clear();
		_cache.Clear();
		_lastPosts = null;
	}

	internal List<KeyValuePair<string, string>> Pairs(string raw, string table, IEnumerable<string> known, bool firstWins = false, bool colors = false)
	{
		Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
		if (known != null)
		{
			foreach (string item in known)
			{
				if (!dictionary.ContainsKey(item))
				{
					dictionary.Add(item, item);
				}
			}
		}
		List<string> list = new List<string>(dictionary.Values);
		list.Sort(StringComparer.Ordinal);
		string key = table + "\0" + raw + "\0" + firstWins + "\0" + colors + "\0" + ((known == null) ? "*" : string.Join("\0", list));
		if (_cache.TryGetValue(key, out var value))
		{
			return new List<KeyValuePair<string, string>>(value);
		}
		List<KeyValuePair<string, string>> list2 = new List<KeyValuePair<string, string>>();
		Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
		string[] array = (raw ?? "").Split(new char[1] { ',' });
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length == 0)
			{
				continue;
			}
			int num = text.IndexOf('=');
			string text2 = ((num < 0) ? "" : text.Substring(0, num).Trim());
			string text3 = ((num < 0) ? "" : text.Substring(num + 1).Trim());
			if (text2.Length == 0 || text3.Length == 0)
			{
				Warn(raw, table, "ignoring malformed " + table + " entry '" + text + "'");
				continue;
			}
			if (known != null)
			{
				if (!dictionary.TryGetValue(text2, out var value2))
				{
					Warn(raw, table, "ignoring " + table + " name '" + text2 + "': no matching " + ((table == "Merchants.Table") ? "game location" : "merchant"));
					continue;
				}
				text2 = value2;
			}
			int value3;
			bool flag = dictionary2.TryGetValue(text2, out value3);
			if (flag)
			{
				Warn(raw, table, "duplicate " + table + " name '" + text2 + "': " + (firstWins ? "first entry wins" : "last entry wins"));
				if (firstWins)
				{
					continue;
				}
			}
			if (colors && !ValidColor(text3))
			{
				Warn(raw, table, "ignoring invalid " + table + " colour '" + text3 + "' for '" + text2 + "'; using vanilla colour");
				if (firstWins && !flag)
				{
					dictionary2.Add(text2, -1);
				}
			}
			else
			{
				KeyValuePair<string, string> keyValuePair = new KeyValuePair<string, string>(text2, text3);
				if (flag && value3 >= 0)
				{
					list2[value3] = keyValuePair;
					continue;
				}
				dictionary2[text2] = list2.Count;
				list2.Add(keyValuePair);
			}
		}
		_cache.Add(key, list2);
		return new List<KeyValuePair<string, string>>(list2);
	}

	private void Warn(string raw, string table, string message)
	{
		if (_warned.Add(table + "\0" + raw + "\0" + message))
		{
			_warning("[MerchantSignposts] " + message);
		}
	}

	internal void ValidatePosts(string defaultPost, List<KeyValuePair<string, string>> overrides, IEnumerable<string> merchants, Func<string, bool> exists)
	{
		if (exists == null)
		{
			return;
		}
		Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.Ordinal);
		dictionary[defaultPost] = new List<string>();
		Dictionary<string, string> dictionary2 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
		string text = defaultPost;
		foreach (KeyValuePair<string, string> @override in overrides)
		{
			dictionary2[@override.Key] = @override.Value;
			text = text + "\0" + @override.Key + "=" + @override.Value;
			if (!dictionary.ContainsKey(@override.Value))
			{
				dictionary[@override.Value] = new List<string>();
			}
		}
		foreach (string merchant in merchants)
		{
			string value;
			string key = (dictionary2.TryGetValue(merchant, out value) ? value : defaultPost);
			dictionary[key].Add(merchant);
			text = text + "\0merchant=" + merchant;
		}
		if (_lastPosts == text)
		{
			return;
		}
		_lastPosts = text;
		foreach (KeyValuePair<string, List<string>> item in dictionary)
		{
			if (!exists(item.Key))
			{
				Warn(text, "PolePrefab/PolePrefabs", "unknown post prefab '" + item.Key + "' in PolePrefab/PolePrefabs; affected merchants: " + ((item.Value.Count == 0) ? "none" : string.Join(", ", item.Value)) + ". Existing signposts stay standing; no new signposts will be built for these merchants until corrected.");
			}
		}
	}

	internal static bool ValidColor(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return false;
		}
		if (value[0] == '#')
		{
			int num = value.Length - 1;
			if (num != 3 && num != 4 && num != 6 && num != 8)
			{
				return false;
			}
			for (int i = 1; i < value.Length; i++)
			{
				char c = value[i];
				if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F'))
				{
					return false;
				}
			}
			return true;
		}
		switch (value.ToLowerInvariant())
		{
		case "blue":
		case "grey":
		case "black":
		case "green":
		case "white":
		case "orange":
		case "purple":
		case "yellow":
		case "red":
		case "lightblue":
			return true;
		default:
			return false;
		}
	}
}
internal sealed class ObstacleIndex
{
	private sealed class Disc
	{
		private readonly float _x;

		private readonly float _z;

		private readonly float _radius;

		internal Disc(float x, float z, float radius)
		{
			_x = x;
			_z = z;
			_radius = radius;
		}

		internal bool Covers(Bounds sign)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(_x, ((Bounds)(ref sign)).min.x, ((Bounds)(ref sign)).max.x) - _x;
			float num2 = Mathf.Clamp(_z, ((Bounds)(ref sign)).min.z, ((Bounds)(ref sign)).max.z) - _z;
			return num * num + num2 * num2 < _radius * _radius;
		}

		internal IEnumerable<(int, int)> Cells()
		{
			for (int x = Cell(_x - _radius); x <= Cell(_x + _radius); x++)
			{
				for (int z = Cell(_z - _radius); z <= Cell(_z + _radius); z++)
				{
					yield return (x, z);
				}
			}
		}
	}

	internal const float BaseReach = 5f;

	private readonly Dictionary<(int, int), List<Bounds>> _cells = new Dictionary<(int, int), List<Bounds>>();

	private const float CellSize = 64f;

	private readonly HashSet<string> _unnetworked = new HashSet<string>(StringComparer.Ordinal);

	private readonly List<(int Hash, Bounds Local)> _measured = new List<(int, Bounds)>();

	private readonly HashSet<int> _hashes = new HashSet<int>();

	private readonly Dictionary<ZDOID, List<Bounds>> _byObject = new Dictionary<ZDOID, List<Bounds>>();

	private readonly HashSet<Vector2s> _indexed = new HashSet<Vector2s>();

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

	private readonly Dictionary<(int, int), List<Disc>> _stationCells = new Dictionary<(int, int), List<Disc>>();

	private readonly Dictionary<ZDOID, Disc> _discs = new Dictionary<ZDOID, Disc>();

	private float _maximumReach;

	private int _count;

	internal int Count => _count;

	internal int StationCount => _discs.Count;

	internal int UnnetworkedCount => _unnetworked.Count;

	internal IEnumerable<string> UnnetworkedNames => _unnetworked;

	internal string Maintenance { get; private set; } = "full";

	internal int Removed { get; private set; }

	internal int ExtendedZones { get; private set; }

	internal static ObstacleIndex Refresh(ObstacleIndex live, bool rebuild, ZoneSystem zones, HashSet<Vector2s> generated)
	{
		if (rebuild || live == null)
		{
			ObstacleIndex obstacleIndex = Build(zones);
			obstacleIndex.MarkIndexed(generated);
			return obstacleIndex;
		}
		live.Extend(generated);
		return live;
	}

	internal static ObstacleIndex Build(ZoneSystem zones)
	{
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0256: Unknown result type (might be due to invalid IL or missing references)
		ObstacleIndex obstacleIndex = new ObstacleIndex();
		if ((Object)(object)zones == (Object)null || ZDOMan.instance == null)
		{
			return obstacleIndex;
		}
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		List<(int, Bounds)> measured = obstacleIndex._measured;
		foreach (ZoneVegetation item in zones.m_vegetation)
		{
			GameObject prefab = item.m_prefab;
			if (item.m_enable && !((Object)(object)prefab == (Object)null) && hashSet.Add(((Object)prefab).name) && SignpostBuilder.TryMeasure(prefab, out var local))
			{
				if ((Object)(object)prefab.GetComponent<ZNetView>() == (Object)null)
				{
					obstacleIndex._unnetworked.Add(((Object)prefab).name);
					continue;
				}
				float num = Mathf.Sqrt(Mathf.Max(((Bounds)(ref local)).min.x * ((Bounds)(ref local)).min.x, ((Bounds)(ref local)).max.x * ((Bounds)(ref local)).max.x) + Mathf.Max(((Bounds)(ref local)).min.z * ((Bounds)(ref local)).min.z, ((Bounds)(ref local)).max.z * ((Bounds)(ref local)).max.z));
				obstacleIndex._maximumReach = Mathf.Max(obstacleIndex._maximumReach, num * Mathf.Max(Mathf.Abs(item.m_scaleMin), Mathf.Abs(item.m_scaleMax)));
				measured.Add((StringExtensionMethods.GetStableHashCode(((Object)prefab).name), local));
			}
		}
		obstacleIndex.MeasureStations();
		foreach (var item2 in measured)
		{
			obstacleIndex._hashes.Add(item2.Item1);
		}
		foreach (int key in obstacleIndex._stations.Keys)
		{
			obstacleIndex._hashes.Add(key);
		}
		Dictionary<int, List<ZDO>> dictionary = ZdoSweep.CollectMany(obstacleIndex._hashes);
		foreach (var item3 in measured)
		{
			foreach (ZDO item4 in dictionary[item3.Item1])
			{
				obstacleIndex.Add(item4, item3.Item2);
			}
		}
		foreach (int key2 in obstacleIndex._stations.Keys)
		{
			foreach (ZDO item5 in dictionary[key2])
			{
				obstacleIndex.AddStation(item5);
			}
		}
		return obstacleIndex;
	}

	private void MeasureStations()
	{
		ZNetScene instance = ZNetScene.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		foreach (GameObject prefab in instance.m_prefabs)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				continue;
			}
			CraftingStation component = prefab.GetComponent<CraftingStation>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)prefab.GetComponent<ZNetView>() == (Object)null))
			{
				float num = component.m_rangeBuild + 5f;
				if (!(num <= 0f))
				{
					int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name);
					_stations[stableHashCode] = (_stations.TryGetValue(stableHashCode, out var value) ? Mathf.Max(value, num) : num);
				}
			}
		}
	}

	internal void MarkIndexed(IEnumerable<Vector2s> zones)
	{
		Maintenance = "full";
		ExtendedZones = 0;
		if (zones != null)
		{
			_indexed.UnionWith(zones);
		}
	}

	internal void Extend(HashSet<Vector2s> generated)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: 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_0088: 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)
		Maintenance = "extend";
		ExtendedZones = 0;
		if (generated == null || ZDOMan.instance == null)
		{
			return;
		}
		List<ZDO> list = new List<ZDO>();
		foreach (Vector2s item in generated)
		{
			if (!_indexed.Add(item))
			{
				continue;
			}
			ExtendedZones++;
			ZdoSweep.CollectZone(item, _hashes, list);
			foreach (ZDO item2 in list)
			{
				AddStation(item2);
				if (_byObject.ContainsKey(item2.m_uid))
				{
					continue;
				}
				foreach (var item3 in _measured)
				{
					if (item3.Hash == item2.GetPrefab())
					{
						Add(item2, item3.Local);
					}
				}
			}
		}
	}

	internal void Remove(ZDOID id)
	{
		//IL_0006: 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_0016: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: 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_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		if (_discs.TryGetValue(id, out var value))
		{
			_discs.Remove(id);
			Removed++;
			foreach (var item in value.Cells())
			{
				if (_stationCells.TryGetValue(item, out var value2))
				{
					value2.Remove(value);
					if (value2.Count == 0)
					{
						_stationCells.Remove(item);
					}
				}
			}
		}
		if (!_byObject.TryGetValue(id, out var value3))
		{
			return;
		}
		_byObject.Remove(id);
		Removed++;
		foreach (Bounds item2 in value3)
		{
			Bounds current2 = item2;
			_count--;
			for (int i = Cell(((Bounds)(ref current2)).min.x); i <= Cell(((Bounds)(ref current2)).max.x); i++)
			{
				for (int j = Cell(((Bounds)(ref current2)).min.z); j <= Cell(((Bounds)(ref current2)).max.z); j++)
				{
					if (_cells.TryGetValue((i, j), out var value4))
					{
						value4.Remove(current2);
						if (value4.Count == 0)
						{
							_cells.Remove((i, j));
						}
					}
				}
			}
		}
	}

	private void Add(ZDO zdo, Bounds local)
	{
		//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_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: 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)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		Vector3 vec = zdo.GetVec3(ZDOVars.s_scaleHash, Vector3.zero);
		if (vec == Vector3.zero)
		{
			float num = zdo.GetFloat(ZDOVars.s_scaleScalarHash, 1f);
			((Vector3)(ref vec))..ctor(num, num, num);
		}
		Bounds val = Transform(local, zdo.GetPosition(), zdo.GetRotation(), vec);
		if (!_byObject.TryGetValue(zdo.m_uid, out var value))
		{
			_byObject.Add(zdo.m_uid, value = new List<Bounds>());
		}
		value.Add(val);
		Add(val);
	}

	internal void AddStation(ZDO zdo)
	{
		//IL_001c: 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_002f: 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_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		if (!_stations.TryGetValue(zdo.GetPrefab(), out var value) || _discs.ContainsKey(zdo.m_uid))
		{
			return;
		}
		Vector3 position = zdo.GetPosition();
		Disc disc = new Disc(position.x, position.z, value);
		_discs.Add(zdo.m_uid, disc);
		foreach (var item in disc.Cells())
		{
			if (!_stationCells.TryGetValue(item, out var value2))
			{
				_stationCells.Add(item, value2 = new List<Disc>());
			}
			value2.Add(disc);
		}
	}

	internal bool TryClear(Bounds sign, HashSet<Vector2s> generated, bool keepOutOfBases, out bool clear)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: 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_004b: 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_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		clear = false;
		if (generated == null)
		{
			return false;
		}
		foreach (Vector2s item in RequiredZones(sign))
		{
			if (!generated.Contains(item))
			{
				return false;
			}
		}
		for (int i = Cell(((Bounds)(ref sign)).min.x); i <= Cell(((Bounds)(ref sign)).max.x); i++)
		{
			for (int j = Cell(((Bounds)(ref sign)).min.z); j <= Cell(((Bounds)(ref sign)).max.z); j++)
			{
				if (!_cells.TryGetValue((i, j), out var value))
				{
					continue;
				}
				foreach (Bounds item2 in value)
				{
					Bounds current2 = item2;
					if (((Bounds)(ref current2)).Intersects(sign))
					{
						return true;
					}
				}
			}
		}
		if (keepOutOfBases)
		{
			for (int k = Cell(((Bounds)(ref sign)).min.x); k <= Cell(((Bounds)(ref sign)).max.x); k++)
			{
				for (int l = Cell(((Bounds)(ref sign)).min.z); l <= Cell(((Bounds)(ref sign)).max.z); l++)
				{
					if (!_stationCells.TryGetValue((k, l), out var value2))
					{
						continue;
					}
					foreach (Disc item3 in value2)
					{
						if (item3.Covers(sign))
						{
							return true;
						}
					}
				}
			}
		}
		clear = true;
		return true;
	}

	private static int Cell(float position)
	{
		return Mathf.FloorToInt(position / 64f);
	}

	private void Add(Bounds obstacle)
	{
		//IL_0010: 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_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		_count++;
		for (int i = Cell(((Bounds)(ref obstacle)).min.x); i <= Cell(((Bounds)(ref obstacle)).max.x); i++)
		{
			for (int j = Cell(((Bounds)(ref obstacle)).min.z); j <= Cell(((Bounds)(ref obstacle)).max.z); j++)
			{
				if (!_cells.TryGetValue((i, j), out var value))
				{
					_cells.Add((i, j), value = new List<Bounds>());
				}
				value.Add(obstacle);
			}
		}
	}

	internal List<Vector2s> RequiredZones(Bounds sign)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: 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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: 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_0062: 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_0071: Unknown result type (might be due to invalid IL or missing references)
		List<Vector2s> list = new List<Vector2s>();
		Vector3 val = ((Bounds)(ref sign)).min - new Vector3(_maximumReach, 0f, _maximumReach);
		Vector3 val2 = ((Bounds)(ref sign)).max + new Vector3(_maximumReach, 0f, _maximumReach);
		Vector2s zone = ZoneSystem.GetZone(val);
		Vector2s zone2 = ZoneSystem.GetZone(val2);
		for (short num = zone.x; num <= zone2.x; num++)
		{
			for (short num2 = zone.y; num2 <= zone2.y; num2++)
			{
				list.Add(new Vector2s(num, num2));
			}
		}
		return list;
	}

	internal static Bounds Transform(Bounds local, Vector3 position, Quaternion rotation, Vector3 scale)
	{
		//IL_0004: 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_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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)
		//IL_0066: 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_0075: 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_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: 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)
		bool flag = true;
		Bounds result = default(Bounds);
		Vector3 val = default(Vector3);
		for (int i = 0; i < 8; i++)
		{
			((Vector3)(ref val))..ctor(((i & 1) == 0) ? ((Bounds)(ref local)).min.x : ((Bounds)(ref local)).max.x, ((i & 2) == 0) ? ((Bounds)(ref local)).min.y : ((Bounds)(ref local)).max.y, ((i & 4) == 0) ? ((Bounds)(ref local)).min.z : ((Bounds)(ref local)).max.z);
			val = Vector3.Scale(val, scale);
			Vector3 val2 = position + rotation * val;
			if (flag)
			{
				((Bounds)(ref result))..ctor(val2, Vector3.zero);
				flag = false;
			}
			else
			{
				((Bounds)(ref result)).Encapsulate(val2);
			}
		}
		return result;
	}
}
internal static class PieceIndex
{
	private static ZNet _session;

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

	private static readonly HashSet<ZDOID> Pieces = new HashSet<ZDOID>();

	private static readonly Dictionary<Vector2s, ZDO> Controllers = new Dictionary<Vector2s, ZDO>();

	private static readonly Dictionary<ZDOID, Vector2s> ControllerZones = new Dictionary<ZDOID, Vector2s>();

	private static int _controllerHash;

	internal static int Walks { get; private set; }

	internal static int ZoneReads { get; private set; }

	internal static int Count => Pieces.Count;

	internal static int ControllerCount => Controllers.Count;

	private static void Sync()
	{
		if (_session != ZNet.instance)
		{
			_session = ZNet.instance;
			Walked.Clear();
			Pieces.Clear();
			Controllers.Clear();
			ControllerZones.Clear();
			_controllerHash = 0;
			Walks = 0;
			ZoneReads = 0;
		}
	}

	internal static void Add(ZDO zdo)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		Sync();
		Pieces.Add(zdo.m_uid);
	}

	internal static void Remove(ZDOID id)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: 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_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_004a: Unknown result type (might be due to invalid IL or missing references)
		Pieces.Remove(id);
		if (ControllerZones.TryGetValue(id, out var value))
		{
			ControllerZones.Remove(id);
			if (Controllers.TryGetValue(value, out var value2) && value2.m_uid == id)
			{
				Controllers.Remove(value);
			}
		}
	}

	internal static List<ZDO> Find(IEnumerable<string> prefabs)
	{
		//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_006c: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		Sync();
		HashSet<int> hashSet = new HashSet<int>();
		foreach (string prefab in prefabs)
		{
			hashSet.Add(StringExtensionMethods.GetStableHashCode(prefab));
		}
		Walk(hashSet);
		List<ZDO> list = new List<ZDO>();
		List<ZDOID> list2 = new List<ZDOID>();
		foreach (ZDOID piece in Pieces)
		{
			ZDO zDO = ZDOMan.instance.GetZDO(piece);
			if (zDO == null)
			{
				list2.Add(piece);
			}
			else if (zDO.IsValid() && hashSet.Contains(zDO.GetPrefab()))
			{
				list.Add(zDO);
			}
		}
		foreach (ZDOID item in list2)
		{
			Pieces.Remove(item);
		}
		list.Sort(delegate(ZDO a, ZDO b)
		{
			int num = ((ZDOID)(ref a.m_uid)).UserID.CompareTo(((ZDOID)(ref b.m_uid)).UserID);
			return (num == 0) ? ((ZDOID)(ref a.m_uid)).ID.CompareTo(((ZDOID)(ref b.m_uid)).ID) : num;
		});
		return list;
	}

	internal static IReadOnlyDictionary<Vector2s, ZDO> ZoneControllers(ZoneSystem zones)
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: 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)
		Sync();
		Walk(new HashSet<int>());
		ZoneReads = 0;
		if (_controllerHash == 0)
		{
			return Controllers;
		}
		HashSet<Vector2s> obj = Reconciler.GeneratedZones.Invoke(zones);
		List<ZDO> list = new List<ZDO>();
		HashSet<int> prefabs = new HashSet<int> { _controllerHash };
		foreach (Vector2s item in obj)
		{
			if (Controllers.ContainsKey(item))
			{
				continue;
			}
			ZoneReads++;
			ZdoSweep.CollectZone(item, prefabs, list);
			foreach (ZDO item2 in list)
			{
				AddController(item2);
			}
		}
		return Controllers;
	}

	private static void Walk(HashSet<int> needed)
	{
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		HashSet<int> hashSet = new HashSet<int>();
		foreach (int item in needed)
		{
			if (!Walked.Contains(item))
			{
				hashSet.Add(item);
			}
		}
		ZoneSystem instance = ZoneSystem.instance;
		bool flag = _controllerHash == 0 && (Object)(object)instance != (Object)null && (Object)(object)instance.m_zoneCtrlPrefab != (Object)null;
		if (flag)
		{
			_controllerHash = StringExtensionMethods.GetStableHashCode(((Object)instance.m_zoneCtrlPrefab).name);
		}
		if (hashSet.Count == 0 && !flag)
		{
			return;
		}
		HashSet<int> hashSet2 = new HashSet<int>(hashSet);
		if (flag)
		{
			hashSet2.Add(_controllerHash);
		}
		Walks++;
		foreach (KeyValuePair<int, List<ZDO>> item2 in ZdoSweep.CollectMany(hashSet2))
		{
			foreach (ZDO item3 in item2.Value)
			{
				if (flag && item2.Key == _controllerHash)
				{
					AddController(item3);
				}
				if (hashSet.Contains(item2.Key) && item3.GetString("MerchantSignposts.location", "").Length > 0)
				{
					Pieces.Add(item3.m_uid);
				}
			}
		}
		Walked.UnionWith(hashSet);
	}

	private static void AddController(ZDO zdo)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: 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_0021: Unknown result type (might be due to invalid IL or missing references)
		Vector2s zone = ZoneSystem.GetZone(zdo.GetPosition());
		if (Controllers.TryGetValue(zone, out var value))
		{
			ControllerZones.Remove(value.m_uid);
		}
		Controllers[zone] = zdo;
		ControllerZones[zdo.m_uid] = zone;
	}
}
internal static class PlacementSearch
{
	internal enum Probe
	{
		Rejected,
		Obstructed,
		Unknown,
		Clear
	}

	internal enum Outcome
	{
		Placed,
		Pending,
		Omitted
	}

	internal struct Result
	{
		internal Outcome Outcome;

		internal Vector3 Position;
	}

	internal static Result Select(Vector3 anchor, float radius, Func<Vector3, Probe> evaluate)
	{
		//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_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: 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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: 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)
		foreach (Vector3 item in Offsets(radius, includeOrigin: true))
		{
			Vector3 val = anchor + item;
			switch (evaluate(val))
			{
			case Probe.Clear:
				return new Result
				{
					Outcome = Outcome.Placed,
					Position = val
				};
			case Probe.Unknown:
				return new Result
				{
					Outcome = Outcome.Pending,
					Position = val
				};
			}
		}
		return new Result
		{
			Outcome = Outcome.Omitted,
			Position = anchor
		};
	}

	internal static List<Vector3> Offsets(float radius, bool includeOrigin)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		List<Vector3> list = new List<Vector3>();
		if (!FiniteNonNegative(radius) || radius > 50f)
		{
			return list;
		}
		if (includeOrigin)
		{
			list.Add(Vector3.zero);
		}
		for (int i = -50; i <= 50; i += 10)
		{
			for (int j = -50; j <= 50; j += 10)
			{
				if ((i != 0 || j != 0) && (float)(i * i + j * j) <= radius * radius)
				{
					list.Add(new Vector3((float)i, 0f, (float)j));
				}
			}
		}
		list.Sort(delegate(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_000e: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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)
			if (a == Vector3.zero)
			{
				if (!(b == Vector3.zero))
				{
					return -1;
				}
				return 0;
			}
			if (b == Vector3.zero)
			{
				return 1;
			}
			int num = (a.x * a.x + a.z * a.z).CompareTo(b.x * b.x + b.z * b.z);
			if (num != 0)
			{
				return num;
			}
			int num2 = a.x.CompareTo(b.x);
			return (num2 == 0) ? a.z.CompareTo(b.z) : num2;
		});
		return list;
	}

	private static bool FiniteNonNegative(float value)
	{
		if (!float.IsNaN(value) && !float.IsInfinity(value))
		{
			return value >= 0f;
		}
		return false;
	}
}
internal enum ResolvedOutcome
{
	Placed,
	Pending,
	Omitted,
	RetainedObstructed
}
internal sealed class PlacementDecision
{
	internal string Identity;

	internal string LocationPrefab;

	internal string Fingerprint;

	internal Vector3 Target;

	internal Vector3 Anchor;

	internal Vector3 Position;

	internal ResolvedOutcome Outcome;

	internal bool Found;

	internal bool Retired;
}
internal sealed class PlacementStore
{
	private const string RecordsKey = "MerchantSignposts.placementRecords.v1";

	private IReadOnlyDictionary<Vector2s, ZDO> _controllers = new Dictionary<Vector2s, ZDO>();

	private readonly Dictionary<string, PlacementDecision> _records = new Dictionary<string, PlacementDecision>(StringComparer.Ordinal);

	private static ZNet _session;

	private static Dictionary<Vector2s, string> _values;

	internal IReadOnlyDictionary<Vector2s, ZDO> Controllers => _controllers;

	internal IEnumerable<PlacementDecision> Records => _records.Values;

	internal static PlacementStore Load(ZoneSystem zones)
	{
		//IL_00c2: 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)
		PlacementStore placementStore = new PlacementStore();
		if ((Object)(object)zones == (Object)null || (Object)(object)zones.m_zoneCtrlPrefab == (Object)null || ZDOMan.instance == null)
		{
			return placementStore;
		}
		placementStore._controllers = PieceIndex.ZoneControllers(zones);
		Sync();
		if (_values == null)
		{
			_values = new Dictionary<Vector2s, string>();
			foreach (KeyValuePair<Vector2s, ZDO> controller in placementStore._controllers)
			{
				string text = controller.Value.GetString("MerchantSignposts.placementRecords.v1", "");
				if (text.Length > 0)
				{
					_values[controller.Key] = text;
				}
			}
		}
		foreach (KeyValuePair<Vector2s, string> value in _values)
		{
			Write(placementStore._controllers, value.Key, value.Value);
			string[] array = value.Value.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				if (TryParse(array[i], out var record))
				{
					placementStore._records[record.Identity] = record;
				}
			}
		}
		return placementStore;
	}

	internal bool HasController(Vector3 anchor)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		return _controllers.ContainsKey(ZoneSystem.GetZone(anchor));
	}

	internal bool TryGet(string identity, out PlacementDecision decision)
	{
		return _records.TryGetValue(identity, out decision);
	}

	internal void Put(PlacementDecision decision)
	{
		_records[decision.Identity] = decision;
	}

	internal void PruneExcept(HashSet<string> identities)
	{
		List<string> list = new List<string>();
		foreach (string key in _records.Keys)
		{
			if (!identities.Contains(key))
			{
				list.Add(key);
			}
		}
		foreach (string item in list)
		{
			_records.Remove(item);
		}
	}

	internal void Flush()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: 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_00a4: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<Vector2s, List<string>> dictionary = new Dictionary<Vector2s, List<string>>();
		foreach (PlacementDecision value5 in _records.Values)
		{
			Vector2s zone = ZoneSystem.GetZone(value5.Anchor);
			if (!dictionary.TryGetValue(zone, out var value))
			{
				value = (dictionary[zone] = new List<string>());
			}
			value.Add(Serialize(value5));
		}
		HashSet<Vector2s> hashSet = new HashSet<Vector2s>(dictionary.Keys);
		if (_values != null)
		{
			hashSet.UnionWith(_values.Keys);
		}
		foreach (Vector2s item in hashSet)
		{
			if (_controllers.TryGetValue(item, out var _))
			{
				List<string> value3;
				List<string> list2 = (dictionary.TryGetValue(item, out value3) ? value3 : new List<string>());
				list2.Sort(StringComparer.Ordinal);
				string value4 = string.Join("\n", list2);
				_values[item] = value4;
				Write(_controllers, item, value4);
			}
		}
	}

	private static void Sync()
	{
		if (_session != ZNet.instance)
		{
			_session = ZNet.instance;
			_values = null;
		}
	}

	internal static void RecheckBeforeSave()
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		Sync();
		if (_values == null || (Object)(object)ZoneSystem.instance == (Object)null || ZDOMan.instance == null)
		{
			return;
		}
		IReadOnlyDictionary<Vector2s, ZDO> controllers = PieceIndex.ZoneControllers(ZoneSystem.instance);
		int num = 0;
		foreach (KeyValuePair<Vector2s, string> value in _values)
		{
			if (Write(controllers, value.Key, value.Value))
			{
				num++;
			}
		}
		MerchantSignpostsPlugin.Log.LogInfo((object)$"[MerchantSignposts] placement save recheck: zones checked={_values.Count}, zones rewritten={num}");
	}

	private static bool Write(IReadOnlyDictionary<Vector2s, ZDO> controllers, Vector2s zone, string value)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		if (!controllers.TryGetValue(zone, out var value2) || ZDOMan.instance.GetZDO(value2.m_uid) != value2 || value2.GetString("MerchantSignposts.placementRecords.v1", "") == value)
		{
			return false;
		}
		value2.SetOwner(ZDOMan.GetSessionID());
		value2.Set("MerchantSignposts.placementRecords.v1", value);
		return true;
	}

	private static string Serialize(PlacementDecision record)
	{
		//IL_007d: 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_0099: Unknown result type (might be due to invalid IL or missing references)
		string[] obj = new string[9]
		{
			Encode(record.Identity),
			Encode(record.LocationPrefab),
			Encode(record.Fingerprint),
			null,
			null,
			null,
			null,
			null,
			null
		};
		int outcome = (int)record.Outcome;
		obj[3] = outcome.ToString(CultureInfo.InvariantCulture);
		obj[4] = (record.Found ? "1" : "0");
		obj[5] = (record.Retired ? "1" : "0");
		obj[6] = Point(record.Target);
		obj[7] = Point(record.Anchor);
		obj[8] = Point(record.Position);
		return string.Join("|", obj);
	}

	private static bool TryParse(string line, out PlacementDecision record)
	{
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
		record = null;
		string[] array = line.Split(new char[1] { '|' });
		if (array.Length != 9 || !int.TryParse(array[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !TryPoint(array[6], out var point) || !TryPoint(array[7], out var point2) || !TryPoint(array[8], out var point3) || result < 0 || result > 3)
		{
			return false;
		}
		try
		{
			record = new PlacementDecision
			{
				Identity = Decode(array[0]),
				LocationPrefab = Decode(array[1]),
				Fingerprint = Decode(array[2]),
				Outcome = (ResolvedOutcome)result,
				Found = (array[4] == "1"),
				Retired = (array[5] == "1"),
				Target = point,
				Anchor = point2,
				Position = point3
			};
			return record.Identity.Length != 0;
		}
		catch (FormatException)
		{
			return false;
		}
	}

	private static string Point(Vector3 value)
	{
		return string.Join(",", value.x.ToString("R", CultureInfo.InvariantCulture), value.y.ToString("R", CultureInfo.InvariantCulture), value.z.ToString("R", CultureInfo.InvariantCulture));
	}

	private static bool TryPoint(string value, out Vector3 point)
	{
		//IL_0001: 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)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		point = default(Vector3);
		string[] array = value.Split(new char[1] { ',' });
		if (array.Length != 3 || !float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
		{
			return false;
		}
		point = new Vector3(result, result2, result3);
		return true;
	}

	private static string Encode(string value)
	{
		return Convert.ToBase64String(Encoding.UTF8.GetBytes(value ?? ""));
	}

	private static string Decode(string value)
	{
		return Encoding.UTF8.GetString(Convert.FromBase64String(value));
	}
}
internal static class PlanExport
{
	internal const string DirectoryVariable = "MERCHANT_SIGNPOSTS_EXPORT_DIR";

	internal const string QuitVariable = "MERCHANT_SIGNPOSTS_EXPORT_QUIT";

	private const float CellSize = 8f;

	private static readonly HashSet<string> DisposableSeeds = new HashSet<string>(StringComparer.Ordinal) { "FhZHKQBUUB", "UIFZxRKyGb", "0pzVMReYkJ", "5Egn5b4FJt" };

	private static readonly string[] BiomeLegend = new string[10] { "None", "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands", "DeepNorth", "Ocean" };

	private static string _directory;

	private static bool _quit;

	private static bool _finished;

	internal static void Initialize()
	{
		_directory = Environment.GetEnvironmentVariable("MERCHANT_SIGNPOSTS_EXPORT_DIR");
		string environmentVariable = Environment.GetEnvironmentVariable("MERCHANT_SIGNPOSTS_EXPORT_QUIT");
		_quit = string.IsNullOrEmpty(environmentVariable) || environmentVariable == "1" || environmentVariable.Equals("true", StringComparison.OrdinalIgnoreCase);
		_finished = false;
	}

	internal static void Update()
	{
		if (_directory == null || _finished || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || WorldGenerator.instance == null)
		{
			return;
		}
		if (!ZNet.instance.IsServer())
		{
			_finished = true;
			MerchantSignpostsPlugin.Log.LogWarning((object)"Signpost export ignored: not a server");
		}
		else if (ZoneSystem.instance.LocationsGenerated)
		{
			_finished = true;
			bool flag = Export();
			if (_quit)
			{
				Application.Quit((!flag) ? 1 : 0);
			}
		}
	}

	private static bool Export()
	{
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_031e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0455: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0216: 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_0231: Unknown result type (might be due to invalid IL or missing references)
		//IL_0233: Unknown result type (might be due to invalid IL or missing references)
		//IL_0277: Unknown result type (might be due to invalid IL or missing references)
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		string text = null;
		try
		{
			World world = ZNet.instance.GetWorld();
			if (world == null || !DisposableSeeds.Contains(world.m_seedName) || string.Equals(world.m_name, "Brews", StringComparison.OrdinalIgnoreCase) || world.m_seed != WorldGenerator.instance.GetSeed())
			{
				MerchantSignpostsPlugin.Log.LogWarning((object)"Signpost export refused: not an admitted disposable test world");
				return false;
			}
			if (string.IsNullOrWhiteSpace(_directory) || string.IsNullOrEmpty(world.m_name) || world.m_name != Path.GetFileName(world.m_name) || world.m_name == "." || world.m_name == "..")
			{
				throw new InvalidOperationException("Invalid export path");
			}
			Stopwatch stopwatch = Stopwatch.StartNew();
			SignpostPlan signpostPlan = SignpostPlan.Get();
			if (signpostPlan == null)
			{
				throw new InvalidOperationException("Plan unavailable");
			}
			ZoneSystem instance = ZoneSystem.instance;
			List<object> list = new List<object>();
			List<SignpostPlan.Instance> list2 = new List<SignpostPlan.Instance>(signpostPlan.Instances);
			list2.Sort((SignpostPlan.Instance a, SignpostPlan.Instance b) => StringComparer.Ordinal.Compare(a.Id, b.Id));
			foreach (SignpostPlan.Instance item in list2)
			{
				float num = item.Trail.Outer + MerchantSignpostsPlugin.SidewaysJitter.Value + item.Trail.Step * 0.25f;
				List<object> list3 = new List<object>();
				foreach (KeyValuePair<Vector2s, LocationInstance> locationInstance in instance.m_locationInstances)
				{
					LocationInstance value = locationInstance.Value;
					if (value.m_location != null && !(InvariantNumbers.InstanceIdentity(value.m_location.m_prefabName, locationInstance.Key.x, locationInstance.Key.y) == item.Id))
					{
						float num2 = ((value.m_location.m_prefabName == item.Prefab) ? item.SameMerchantKeepOut : (Math.Max(value.m_location.m_exteriorRadius, value.m_location.m_interiorRadius) + MerchantSignpostsPlugin.LocationMargin.Value));
						double num3 = (double)value.m_position.x - (double)item.Position.x;
						double num4 = (double)value.m_position.z - (double)item.Position.z;
						if (!(num3 * num3 + num4 * num4 > (double)(num + num2) * (double)(num + num2)))
						{
							list3.Add(Object("prefab", value.m_location.m_prefabName, "position", Point(value.m_position), "radius", num2));
						}
					}
				}
				list.Add(Object("id", item.Id, "prefab", item.Prefab, "label", item.Label, "position", Point(item.Position), "exteriorRadius", item.ExteriorRadius, "interiorRadius", item.InteriorRadius, "allowedBiomes", ((object)Unsafe.As<Biome, Biome>(ref item.Biomes)/*cast due to .constrained prefix*/).ToString(), "trail", Object("spokes", item.Trail.Spokes, "outer", item.Trail.Outer, "inner", item.Trail.Inner, "step", item.Trail.Step), "waterMargin", item.WaterMargin, "sameMerchantKeepOut", item.SameMerchantKeepOut, "radius", num, "raster", Raster(item.Position, num), "clearances", list3));
			}
			List<object> list4 = new List<object>();
			foreach (SignpostPlan.Planned item2 in signpostPlan.All)
			{
				Dictionary<string, object> dictionary = Candidate(item2);
				dictionary.Add("pointingTarget", Point(item2.PointingTarget));
				list4.Add(dictionary);
			}
			List<object> list5 = new List<object>();
			foreach (SignpostPlan.Rejected rejection in signpostPlan.Rejections)
			{
				Dictionary<string, object> dictionary2 = Candidate(rejection.Candidate);
				dictionary2.Add("reason", rejection.Reason);
				dictionary2["submerged"] = rejection.Submerged;
				list5.Add(dictionary2);
			}
			Dictionary<string, object> value2 = Object("schemaVersion", 1, "world", Object("name", world.m_name, "seed", world.m_seed, "seedName", world.m_seedName, "waterLevel", instance.m_waterLevel), "pluginVersion", "0.2.0", "settings", Settings(), "instances", list, "planned", list4, "rejected", list5);
			long elapsedMilliseconds = stopwatch.ElapsedMilliseconds;
			Directory.CreateDirectory(_directory);
			string text2 = Path.Combine(_directory, world.m_name + ".signposts.json");
			text = text2 + ".tmp";
			using (StreamWriter writer = new StreamWriter(text, append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)))
			{
				Write(writer, value2);
			}
			if (File.Exists(text2))
			{
				File.Replace(text, text2, null);
			}
			else
			{
				File.Move(text, text2);
			}
			MerchantSignpostsPlugin.Log.LogInfo((object)($"Signpost export complete: schema=1 instances={list.Count} " + $"planned={list4.Count} rejected={list5.Count} captureMs={elapsedMilliseconds} totalMs={stopwatch.ElapsedMilliseconds}"));
			return true;
		}
		catch (Exception ex)
		{
			if (text != null)
			{
				try
				{
					File.Delete(text);
				}
				catch (Exception)
				{
				}
			}
			MerchantSignpostsPlugin.Log.LogError((object)("Signpost export failed: " + ex.GetType().Name));
			return false;
		}
	}

	private static Dictionary<string, object> Candidate(SignpostPlan.Planned point)
	{
		//IL_004f: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<string, object> dictionary = Object("instanceId", point.InstanceId, "spoke", point.Spoke, "index", point.Index, "position", Point(point.Position), "target", Point(point.Target), "height", point.Height, "biome", point.Biome, "submerged", false);
		if (point.OriginalRejection != null)
		{
			dictionary.Add("originalPosition", Point(point.OriginalPosition));
			dictionary.Add("originalRejection", point.OriginalRejection);
		}
		return dictionary;
	}

	private static Dictionary<string, object> Settings()
	{
		return Object("WorldPlacement", MerchantSignpostsPlugin.WorldPlacement.Value, "Spokes", MerchantSignpostsPlugin.Spokes.Value, "OuterRadius", MerchantSignpostsPlugin.OuterRadius.Value, "InnerRadius", MerchantSignpostsPlugin.InnerRadius.Value, "Step", MerchantSignpostsPlugin.Step.Value, "SidewaysJitter", MerchantSignpostsPlugin.SidewaysJitter.Value, "LocationMargin", MerchantSignpostsPlugin.LocationMargin.Value, "SearchRadius", MerchantSignpostsPlugin.SearchRadius.Value, "MinimumSignDistance", MerchantSignpostsPlugin.MinimumSignDistance.Value, "SameMerchantKeepOut", MerchantSignpostsPlugin.SameMerchantKeepOut.Value, "SameMerchantKeepOuts", MerchantSignpostsPlugin.SameMerchantKeepOuts.Value, "WaterMargin", MerchantSignpostsPlugin.WaterMargin.Value, "WaterMargins", MerchantSignpostsPlugin.WaterMargins.Value, "Biomes", MerchantSignpostsPlugin.Biomes.Value, "Trails", MerchantSignpostsPlugin.Trails.Value, "MerchantTable", MerchantSignpostsPlugin.MerchantTable.Value);
	}

	private static Dictionary<string, object> Raster(Vector3 position, float radius)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: 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_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		if (float.IsNaN(radius) || float.IsInfinity(radius) || radius <= 0f || radius > 16000f)
		{
			throw new InvalidOperationException("Invalid raster extent");
		}
		double num = Math.Floor((position.x - radius) / 8f) * 8.0;
		double num2 = Math.Floor((position.z - radius) / 8f) * 8.0;
		int num3 = (int)Math.Ceiling(Math.Max((double)(position.x + radius) - num, (double)(position.z + radius) - num2) / 8.0);
		if ((long)num3 * (long)num3 > 4000000)
		{
			throw new InvalidOperationException("Raster too large");
		}
		int[] array = new int[num3 * num3];
		int[] array2 = new int[array.Length];
		Vector3 val = default(Vector3);
		for (int i = 0; i < num3; i++)
		{
			for (int j = 0; j < num3; j++)
			{
				((Vector3)(ref val))..ctor((float)(num + ((double)j + 0.5) * 8.0), 0f, (float)(num2 + ((double)i + 0.5) * 8.0));
				int num4 = i * num3 + j;
				array[num4] = checked((int)Math.Round((double)SignpostPlan.TerrainHeight(WorldGenerator.instance, ZoneSystem.instance, val) * 10.0, MidpointRounding.AwayFromZero));
				array2[num4] = Math.Max(0, Array.IndexOf<string>(BiomeLegend, ((object)WorldGenerator.instance.GetBiome(val.x, val.z, 0.02f, false)/*cast due to .constrained prefix*/).ToString()));
			}
		}
		return Object("origin", new double[2] { num, num2 }, "cellSize", 8f, "size", num3, "layout", "row-major from the south-west corner; values are cell centres", "heightDecimetres", array, "biome", array2, "biomeLegend", BiomeLegend);
	}

	private static double[] Point(Vector3 point)
	{
		//IL_0008: 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_0024: Unknown result type (might be due to invalid IL or missing references)
		return new double[3]
		{
			Round(point.x),
			Round(point.y),
			Round(point.z)
		};
	}

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

	private static Dictionary<string, object> Object(params object[] pairs)
	{
		Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
		for (int i = 0; i < pairs.Length; i += 2)
		{
			dictionary.Add((string)pairs[i], pairs[i + 1]);
		}
		return dictionary;
	}

	private static void Write(TextWriter writer, object value)
	{
		if (value is string text)
		{
			writer.Write('"');
			string text2 = text;
			foreach (char c in text2)
			{
				switch (c)
				{
				case '"':
					writer.Write("\\\"");
					continue;
				case '\\':
					writer.Write("\\\\");
					continue;
				case '\n':
					writer.Write("\\n");
					continue;
				case '\r':
					writer.Write("\\r");
					co