Decompiled source of Debug Teleport Names v1.1.0

DebugTeleportNames.dll

Decompiled 18 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using NodeCanvas.Framework;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DebugTeleportNames")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DebugTeleportNames")]
[assembly: AssemblyTitle("DebugTeleportNames")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace DebugTeleportNames;

internal sealed class Destination
{
	public string Scene;

	public int Spawn;

	public string Label;

	public Kind Kind;

	public int BuildOrder;

	public override string ToString()
	{
		return $"{Label} -> {Scene} #{Spawn}";
	}
}
internal enum Kind
{
	Town,
	Region,
	Dungeon
}
internal static class Destinations
{
	private sealed class SubArea
	{
		public int Spawn;

		public string LocKey;

		public string Detail;
	}

	private static readonly Dictionary<string, SubArea[]> s_subAreas = new Dictionary<string, SubArea[]>
	{
		["ChersoneseDungeonsSmall"] = (from i in Enumerable.Range(1, 9)
			select Small(i)).ToArray(),
		["HallowedDungeonsSmall"] = new int[8] { 1, 2, 3, 4, 5, 6, 7, 9 }.Select((int i) => Small(i)).ToArray(),
		["AbrassarDungeonsSmall"] = (from i in Enumerable.Range(1, 8)
			select Small(i)).ToArray(),
		["EmercarDungeonsSmall"] = (from i in Enumerable.Range(1, 9)
			select Small(i)).ToArray(),
		["AntiqueFieldDungeonsSmall"] = (from i in Enumerable.Range(1, 8)
			select Small(i, "Scene_Harmattan_DungeonsSmall" + i)).ToArray(),
		["CalderaDungeonsSmall"] = new SubArea[10]
		{
			Small(0, "Scene_Caldera_SmallDungeon06"),
			Small(1, "Scene_Caldera_SmallDungeon01"),
			Small(2, "Scene_Caldera_SmallDungeon07"),
			Small(3, "Scene_Caldera_SmallDungeon05"),
			Small(4, "Scene_Caldera_SmallDungeon02"),
			Small(5, "Scene_Caldera_SmallDungeon04"),
			Small(6, "Scene_Caldera_SmallDungeon10"),
			Small(8, "Scene_Caldera_SmallDungeon08"),
			Small(10, "Scene_Caldera_SmallDungeon03"),
			Small(11, "Scene_Caldera_SmallDungeon11")
		},
		["ChersoneseDungeonsBosses"] = new SubArea[3]
		{
			Arena(0, "Troglodyte Queen"),
			Arena(1, "Elite Mantis Shrimp"),
			Arena(2, "Brand Squire")
		},
		["HallowedDungeonsBosses"] = new SubArea[3]
		{
			Arena(0, "Ash Giant Highmonk"),
			Arena(1, "Elite Ash Giants"),
			Arena(2, "Elite Alpha Tuanosaur")
		},
		["AbrassarDungeonsBosses"] = new SubArea[3]
		{
			Arena(0, "Calixa"),
			Arena(1, "Elite Beast Golem"),
			Arena(2, "Elite Crescent Sharks")
		},
		["EmercarDungeonsBosses"] = new SubArea[3]
		{
			Arena(0, "Light Mender and Plague Doctor"),
			Arena(1, "Elite Burning Man"),
			Arena(2, "Immaculate Dreamer")
		},
		["AntiqueFieldDungeonsBosses"] = new SubArea[3]
		{
			Arena(0, "Immaculate's Bird"),
			Arena(1, "Elite Sublime Shell"),
			Arena(2, "Elite Boozu")
		},
		["CalderaDungeonsBosses"] = new SubArea[4]
		{
			Arena(0, "Grandmother"),
			Arena(2, "Elite Crimson Avatar"),
			Arena(3, "Elite Gargoyles"),
			Arena(4, "Elite Torcrab")
		},
		["Caldera_Dungeon10"] = new SubArea[3]
		{
			Entrance(0),
			Entrance(1, "Top Entrance"),
			Entrance(2, "Bottom Entrance")
		}
	};

	private static SubArea Small(int spawn, string locKey = null)
	{
		return new SubArea
		{
			Spawn = spawn,
			LocKey = locKey
		};
	}

	private static SubArea Arena(int spawn, string boss)
	{
		return new SubArea
		{
			Spawn = spawn,
			Detail = boss
		};
	}

	private static SubArea Entrance(int spawn, string which = null)
	{
		return new SubArea
		{
			Spawn = spawn,
			Detail = which
		};
	}

	internal static List<Destination> Build(IList<string> scenes)
	{
		List<Destination> list = new List<Destination>();
		for (int i = 0; i < scenes.Count; i++)
		{
			string text = scenes[i];
			Area areaFromSceneName = AreaManager.Instance.GetAreaFromSceneName(text);
			string text2 = AreaName(text);
			Kind kind = KindOf(areaFromSceneName);
			if (s_subAreas.TryGetValue(text, out var value))
			{
				SubArea[] array = value;
				foreach (SubArea subArea in array)
				{
					list.Add(new Destination
					{
						Scene = text,
						Spawn = subArea.Spawn,
						Kind = kind,
						BuildOrder = i,
						Label = SubName(areaFromSceneName, text2, subArea)
					});
				}
			}
			else
			{
				list.Add(new Destination
				{
					Scene = text,
					Spawn = 0,
					Kind = kind,
					BuildOrder = i,
					Label = text2
				});
			}
		}
		Disambiguate(list);
		if (Plugin.ShowSceneName.Value)
		{
			foreach (Destination item in list.Where((Destination d) => d.Label != d.Scene))
			{
				item.Label += ((item.Spawn != 0 || s_subAreas.ContainsKey(item.Scene)) ? $" ({item.Scene} #{item.Spawn})" : (" (" + item.Scene + ")"));
			}
		}
		IOrderedEnumerable<Destination> source = list.OrderBy((Destination d) => d.Kind);
		source = (Plugin.SortByName.Value ? source.ThenBy<Destination, string>((Destination d) => d.Label, StringComparer.CurrentCultureIgnoreCase).ThenBy<Destination, string>((Destination d) => d.Scene, StringComparer.Ordinal) : source.ThenBy((Destination d) => d.BuildOrder));
		return source.ThenBy((Destination d) => d.Spawn).ToList();
	}

	private static Kind KindOf(Area area)
	{
		string text = area?.NameLocKey ?? "";
		if (text.EndsWith("_Town", StringComparison.Ordinal))
		{
			return Kind.Town;
		}
		if (text.EndsWith("_Open", StringComparison.Ordinal))
		{
			return Kind.Region;
		}
		return Kind.Dungeon;
	}

	private static string SubName(Area area, string areaName, SubArea sub)
	{
		if (sub.Detail != null)
		{
			return areaName + ": " + sub.Detail;
		}
		string text = null;
		if (sub.LocKey != null)
		{
			LocalizationManager.Instance.TryGetLoc(sub.LocKey, ref text);
		}
		else if (area != null)
		{
			text = AreaManager.Instance.GetAreaName((AreaEnum)area.ID, sub.Spawn);
		}
		if (!string.IsNullOrEmpty(text?.Trim()))
		{
			return text.Trim();
		}
		return $"{areaName} #{sub.Spawn}";
	}

	private static void Disambiguate(List<Destination> list)
	{
		foreach (IGrouping<string, Destination> group in (from d in list
			group d by d.Label into g
			where g.Count() > 1
			select g).ToList())
		{
			Dictionary<Destination, string> qualifiers = group.ToDictionary((Destination d) => d, (Destination d) => Qualifier(d.Scene, group.Key));
			foreach (IGrouping<string, Destination> item in from d in @group
				group d by qualifiers[d] into g
				where g.Count() > 1
				select g)
			{
				foreach (Destination item2 in item)
				{
					qualifiers[item2] = ((item2.Spawn == 0) ? item2.Scene : $"{item2.Scene} #{item2.Spawn}");
				}
			}
			foreach (Destination item3 in group)
			{
				if (qualifiers[item3] != null)
				{
					item3.Label = item3.Label + " (" + qualifiers[item3] + ")";
				}
			}
		}
	}

	private static string Qualifier(string scene, string name)
	{
		string text = AreaManager.Instance.GetAreaFromSceneName(scene)?.DefaultName?.Trim();
		if (string.IsNullOrEmpty(text) || string.Equals(text, name, StringComparison.OrdinalIgnoreCase))
		{
			return null;
		}
		if (!text.StartsWith(name + " ", StringComparison.OrdinalIgnoreCase))
		{
			return text;
		}
		return text.Substring(name.Length + 1);
	}

	internal static string AreaName(string scene)
	{
		string text = null;
		try
		{
			Area areaFromSceneName = AreaManager.Instance.GetAreaFromSceneName(scene);
			text = ((areaFromSceneName != null) ? areaFromSceneName.GetName() : null);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("No area name for " + scene + ": " + ex.Message));
		}
		if (!string.IsNullOrEmpty(text?.Trim()))
		{
			return text.Trim();
		}
		return scene;
	}
}
[HarmonyPatch]
internal static class ListColumns
{
	private const float Margin = 8f;

	private const float ColumnGap = 4f;

	private static readonly FieldRef<DT_CharacterCheats, Dropdown[]> s_dropdowns = AccessTools.FieldRefAccess<DT_CharacterCheats, Dropdown[]>("m_ddFamilies");

	internal static string LastLayout;

	private static readonly Vector3[] s_corners = (Vector3[])(object)new Vector3[4];

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Dropdown), "Show")]
	private static void AfterShow(Dropdown __instance)
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Expected O, but got Unknown
		try
		{
			DT_CharacterCheats componentInParent = ((Component)__instance).GetComponentInParent<DT_CharacterCheats>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return;
			}
			Dropdown[] obj = s_dropdowns.Invoke(componentInParent);
			if (obj != null && UnityEngineExtensions.Contains<Dropdown>(obj, __instance))
			{
				Transform obj2 = ((Component)__instance).transform.Find("Dropdown List");
				RectTransform val = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null);
				if (val != null)
				{
					Arrange(val, (RectTransform)((Component)__instance).transform);
				}
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Could not lay out the area list: " + ex));
		}
	}

	private static void Arrange(RectTransform list, RectTransform button)
	{
		//IL_0030: 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_003a: 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_00a6: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: 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_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0370: Unknown result type (might be due to invalid IL or missing references)
		//IL_037e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0383: Unknown result type (might be due to invalid IL or missing references)
		LayoutRebuilder.ForceRebuildLayoutImmediate(list);
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(8f, 8f, (float)Screen.width - 16f, (float)Screen.height - 16f);
		Rect val2 = WorldRect(list);
		if (((Rect)(ref val)).Contains(((Rect)(ref val2)).min) && ((Rect)(ref val)).Contains(((Rect)(ref val2)).max))
		{
			return;
		}
		VerticalLayoutGroup component = ((Component)list).GetComponent<VerticalLayoutGroup>();
		List<RectTransform> list2 = (from Transform t in (IEnumerable)list
			where ((Component)t).gameObject.activeSelf && (Object)(object)((Component)t).GetComponent<Toggle>() != (Object)null
			select t).Cast<RectTransform>().ToList();
		if (!((Object)(object)component == (Object)null) && list2.Count != 0)
		{
			float y = ((Transform)list).lossyScale.y;
			Rect val3 = WorldRect(button);
			float num = ((Rect)(ref val3)).yMax - ((Rect)(ref val)).yMin;
			float num2 = ((Rect)(ref val)).yMax - ((Rect)(ref val3)).yMin;
			bool flag = num >= num2;
			float num3 = Mathf.Max(num, num2) / y;
			RectOffset padding = ((LayoutGroup)component).padding;
			float spacing = ((HorizontalOrVerticalLayoutGroup)component).spacing;
			Rect rect = list.rect;
			float num4 = (((Rect)(ref rect)).height - (float)padding.vertical + spacing) / (float)list2.Count;
			rect = list.rect;
			float num5 = ((Rect)(ref rect)).width - (float)padding.horizontal;
			int num6 = Mathf.Max(1, Mathf.FloorToInt((num3 - (float)padding.vertical + spacing) / num4));
			int num7 = Mathf.CeilToInt((float)list2.Count / (float)num6);
			LastLayout = $"{list2.Count} items, pitch {num4:F1}, padding {padding.vertical}, spacing {spacing}, " + string.Format("room {0:F0} {1}, {2} rows max -> {3} columns", num3, flag ? "below" : "above", num6, num7);
			Plugin.Log.LogDebug((object)("Area list: " + LastLayout));
			if (num7 > 1)
			{
				Object.DestroyImmediate((Object)(object)component);
				GridLayoutGroup obj = ((Component)list).gameObject.AddComponent<GridLayoutGroup>();
				((LayoutGroup)obj).padding = padding;
				obj.cellSize = new Vector2(num5, num4 - spacing);
				obj.spacing = new Vector2(4f, spacing);
				obj.startCorner = (Corner)0;
				obj.startAxis = (Axis)1;
				((LayoutGroup)obj).childAlignment = (TextAnchor)0;
				obj.constraint = (Constraint)1;
				obj.constraintCount = num7;
				int num8 = Mathf.CeilToInt((float)list2.Count / (float)num7);
				list.SetSizeWithCurrentAnchors((Axis)1, (float)padding.vertical + (float)num8 * num4 - spacing);
				LayoutRebuilder.ForceRebuildLayoutImmediate(list);
			}
			val2 = WorldRect(list);
			float num9 = (flag ? (((Rect)(ref val3)).yMax - ((Rect)(ref val2)).yMax) : (((Rect)(ref val3)).yMin - ((Rect)(ref val2)).yMin));
			float num10 = 0f;
			if (((Rect)(ref val2)).xMax > ((Rect)(ref val)).xMax)
			{
				num10 = ((Rect)(ref val)).xMax - ((Rect)(ref val2)).xMax;
			}
			if (((Rect)(ref val2)).xMin + num10 < ((Rect)(ref val)).xMin)
			{
				num10 = ((Rect)(ref val)).xMin - ((Rect)(ref val2)).xMin;
			}
			if (((Rect)(ref val2)).yMin + num9 < ((Rect)(ref val)).yMin)
			{
				num9 = ((Rect)(ref val)).yMin - ((Rect)(ref val2)).yMin;
			}
			if (((Rect)(ref val2)).yMax + num9 > ((Rect)(ref val)).yMax)
			{
				num9 = ((Rect)(ref val)).yMax - ((Rect)(ref val2)).yMax;
			}
			((Transform)list).position = ((Transform)list).position + new Vector3(num10, num9, 0f);
		}
	}

	private static Rect WorldRect(RectTransform t)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		t.GetWorldCorners(s_corners);
		return Rect.MinMaxRect(s_corners[0].x, s_corners[0].y, s_corners[2].x, s_corners[2].y);
	}
}
[BepInPlugin("tchernobill.debugteleportnames", "DebugTeleportNames", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
	public const string GUID = "tchernobill.debugteleportnames";

	public const string NAME = "DebugTeleportNames";

	public const string VERSION = "1.1.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> SortByName;

	internal static ConfigEntry<bool> ShowSceneName;

	private void Awake()
	{
		//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)
		Log = ((BaseUnityPlugin)this).Logger;
		SortByName = ((BaseUnityPlugin)this).Config.Bind<bool>("Area switch", "Sort by name", true, "List each region's dungeons alphabetically, after its town and the region itself (off: build order).");
		ShowSceneName = ((BaseUnityPlugin)this).Config.Bind<bool>("Area switch", "Show scene name", false, "Also show the internal scene name (and spawn point) after the name, e.g. \"Ghost Pass (Chersonese_Dungeon3)\".");
		Harmony val = new Harmony("tchernobill.debugteleportnames");
		val.PatchAll(typeof(AreaSwitchPatches));
		val.PatchAll(typeof(ListColumns));
		TestHarness.StartIfRequested(((Component)this).gameObject);
	}
}
[HarmonyPatch]
internal static class AreaSwitchPatches
{
	private static readonly FieldRef<DT_CharacterCheats, List<string>[]> s_scenes = AccessTools.FieldRefAccess<DT_CharacterCheats, List<string>[]>("m_activeScenes");

	private static readonly FieldRef<DT_CharacterCheats, Dropdown[]> s_dropdowns = AccessTools.FieldRefAccess<DT_CharacterCheats, Dropdown[]>("m_ddFamilies");

	private static readonly FieldRef<DT_CharacterCheats, int> s_lastFamily = AccessTools.FieldRefAccess<DT_CharacterCheats, int>("m_lastSelectedAreaFamilyIndex");

	private static readonly FieldRef<DT_CharacterCheats, DeveloperToolManager> s_manager = AccessTools.FieldRefAccess<DT_CharacterCheats, DeveloperToolManager>("m_manager");

	private static readonly ConditionalWeakTable<DT_CharacterCheats, List<Destination>[]> s_lists = new ConditionalWeakTable<DT_CharacterCheats, List<Destination>[]>();

	[HarmonyPostfix]
	[HarmonyPatch(typeof(DT_CharacterCheats), "InitAreaSwitches")]
	private static void AfterInit(DT_CharacterCheats __instance)
	{
		Refresh(__instance);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(DT_CharacterCheats), "Show")]
	private static void AfterShow(DT_CharacterCheats __instance)
	{
		Refresh(__instance);
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(DT_CharacterCheats), "OnAreaSwitch")]
	private static bool BeforeAreaSwitch(DT_CharacterCheats __instance, int _index)
	{
		//IL_0024: 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_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		Destination destination = Get(__instance, s_lastFamily.Invoke(__instance), _index);
		if (destination == null)
		{
			return true;
		}
		DLCs areaDLC = AreaManager.Instance.GetAreaDLC(destination.Scene);
		if (!CharacterManager.Instance.GetAllPlayersOwnDLC(areaDLC))
		{
			((UIElement)__instance).CharacterUI.ShowInfoNotificationLoc("Notification_Interaction_DLCRequiredCOOP", new string[1] { StoreManager.Instance.GetDLCName(areaDLC) });
			return false;
		}
		NetworkLevelLoader.Instance.RequestSwitchArea(destination.Scene, destination.Spawn, 1.5f, false);
		DeveloperToolManager obj = s_manager.Invoke(__instance);
		if (obj != null)
		{
			obj.HideCurrentDisplayedTool();
		}
		return false;
	}

	internal static Destination Get(DT_CharacterCheats panel, int family, int option)
	{
		if (option < 1 || !s_lists.TryGetValue(panel, out var value) || family < 0 || family >= value.Length)
		{
			return null;
		}
		List<Destination> list = value[family];
		Dropdown[] obj = s_dropdowns.Invoke(panel);
		Dropdown val = ((obj != null) ? obj[family] : null);
		if (list == null || (Object)(object)val == (Object)null || val.options.Count != list.Count + 1 || option > list.Count)
		{
			return null;
		}
		return list[option - 1];
	}

	internal static List<Destination> Get(DT_CharacterCheats panel, int family)
	{
		if (!s_lists.TryGetValue(panel, out var value) || family < 0 || family >= value.Length)
		{
			return null;
		}
		return value[family];
	}

	internal static void Refresh(DT_CharacterCheats panel)
	{
		List<string>[] array = s_scenes.Invoke(panel);
		Dropdown[] array2 = s_dropdowns.Invoke(panel);
		if (array == null || array2 == null || (Object)(object)AreaManager.Instance == (Object)null)
		{
			return;
		}
		s_lists.TryGetValue(panel, out var value);
		List<Destination>[] array3 = new List<Destination>[array.Length];
		for (int i = 0; i < array.Length && i < array2.Length; i++)
		{
			Dropdown val = array2[i];
			if (array[i] == null || (Object)(object)val == (Object)null)
			{
				continue;
			}
			int num = ((((value != null) ? value[i] : null) != null) ? (value[i].Count + 1) : (-1));
			if (val.options.Count != array[i].Count + 1 && val.options.Count != num)
			{
				continue;
			}
			try
			{
				List<Destination> list = Destinations.Build(array[i]);
				val.options.RemoveRange(1, val.options.Count - 1);
				val.options.AddRange(((IEnumerable<Destination>)list).Select((Func<Destination, OptionData>)((Destination d) => new OptionData(d.Label))));
				val.SetValueWithoutNotify(0);
				array3[i] = list;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"Could not build the destinations of list {i}: {arg}");
			}
		}
		s_lists.Remove(panel);
		s_lists.Add(panel, array3);
	}
}
[HarmonyPatch]
public class TestHarness : MonoBehaviour
{
	private const int CheatPanelIndex = 1;

	private string outputDir;

	private bool survey;

	private static int s_loadsStarted;

	private int offScreenLists;

	private static readonly string[] SurveyScenes = new string[18]
	{
		"ChersoneseNewTerrain", "HallowedMarshNewTerrain", "Abrassar", "Emercar", "AntiqueField", "Caldera", "ChersoneseDungeonsSmall", "HallowedDungeonsSmall", "AbrassarDungeonsSmall", "EmercarDungeonsSmall",
		"AntiqueFieldDungeonsSmall", "CalderaDungeonsSmall", "ChersoneseDungeonsBosses", "HallowedDungeonsBosses", "AbrassarDungeonsBosses", "EmercarDungeonsBosses", "AntiqueFieldDungeonsBosses", "CalderaDungeonsBosses"
	};

	private static string ActiveScene
	{
		get
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name;
		}
	}

	public static void StartIfRequested(GameObject host)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		string[] commandLineArgs = Environment.GetCommandLineArgs();
		if (UnityEngineExtensions.Contains<string>(commandLineArgs, "--dtn-test") || UnityEngineExtensions.Contains<string>(commandLineArgs, "--dtn-survey") || UnityEngineExtensions.Contains<string>(commandLineArgs, "--dtn-probe"))
		{
			new Harmony("tchernobill.debugteleportnames.test").PatchAll(typeof(TestHarness));
			host.AddComponent<TestHarness>().survey = UnityEngineExtensions.Contains<string>(commandLineArgs, "--dtn-survey") || UnityEngineExtensions.Contains<string>(commandLineArgs, "--dtn-probe");
		}
	}

	private void Start()
	{
		outputDir = Path.Combine(Paths.BepInExRootPath, "DebugTeleportNamesTest");
		Directory.CreateDirectory(outputDir);
		((MonoBehaviour)this).StartCoroutine(Run());
	}

	private static void Log(string message)
	{
		Plugin.Log.LogMessage((object)("dtn-test: " + message));
	}

	private static string Fail(string reason)
	{
		Plugin.Log.LogError((object)("dtn-test: FAILED " + reason));
		return reason;
	}

	private static IEnumerator WaitRealtime(float seconds)
	{
		float end = Time.realtimeSinceStartup + seconds;
		while (Time.realtimeSinceStartup < end)
		{
			yield return null;
		}
	}

	private static bool InGameplay(string scene)
	{
		if ((Object)(object)NetworkLevelLoader.Instance != (Object)null && NetworkLevelLoader.Instance.IsOverallLoadingDone)
		{
			return ActiveScene == scene;
		}
		return false;
	}

	private IEnumerator Run()
	{
		Character character = null;
		float deadline = Time.realtimeSinceStartup + 900f;
		while ((Object)(object)character == (Object)null)
		{
			if (Time.realtimeSinceStartup > deadline)
			{
				Fail("not in Berg after 900 s");
				yield break;
			}
			yield return null;
			if (InGameplay(survey ? ActiveScene : "Berg"))
			{
				try
				{
					CharacterManager instance = CharacterManager.Instance;
					character = ((instance != null) ? instance.GetFirstLocalCharacter() : null);
				}
				catch (NullReferenceException)
				{
				}
			}
		}
		yield return WaitRealtime(5f);
		if (survey)
		{
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			int num = Array.IndexOf(commandLineArgs, "--dtn-probe");
			if (num >= 0 && num + 2 < commandLineArgs.Length)
			{
				yield return Probe(commandLineArgs[num + 1], commandLineArgs[num + 2]);
			}
			else
			{
				yield return Survey();
			}
			yield break;
		}
		Log($"local character {character.Name} in {ActiveScene}, batchmode {Application.isBatchMode}, screen {Screen.width}x{Screen.height}");
		DumpAreas();
		DeveloperToolManager tools = ((Component)character.CharacterUI).GetComponentInChildren<DeveloperToolManager>(true);
		if ((Object)(object)tools == (Object)null)
		{
			Fail("no DeveloperToolManager under the CharacterUI");
			yield break;
		}
		Log("toggle keys: " + string.Join(", ", Traverse.Create((object)tools).Field("TOGGLE_KEYS").GetValue<KeyCode[]>()));
		Global.CheatsEnabled = true;
		MenuManager.Instance.MasterCanvas.alpha = 1f;
		MenuManager.Instance.MasterCanvas.interactable = true;
		string[] commandLineArgs2 = Environment.GetCommandLineArgs();
		int num2 = Array.IndexOf(commandLineArgs2, "--dtn-test-resolution");
		if (num2 >= 0 && num2 + 1 < commandLineArgs2.Length)
		{
			string[] array = commandLineArgs2[num2 + 1].Split(new char[1] { 'x' });
			Screen.SetResolution(int.Parse(array[0]), int.Parse(array[1]), false);
			yield return WaitRealtime(3f);
			Log($"screen now {Screen.width}x{Screen.height}");
		}
		tools.ShowDeveloperTool(1);
		yield return WaitRealtime(2f);
		DT_CharacterCheats panel = ((Component)tools).GetComponentInChildren<DT_CharacterCheats>(true);
		DumpChain(((Object)(object)panel != (Object)null) ? ((Component)panel).transform : ((Component)tools).transform);
		List<string>[] scenes = Traverse.Create((object)panel).Field("m_activeScenes").GetValue<List<string>[]>();
		Dropdown[] dropdowns = Traverse.Create((object)panel).Field("m_ddFamilies").GetValue<Dropdown[]>();
		if ((Object)(object)panel == (Object)null || scenes == null || dropdowns == null)
		{
			Fail("no area switch lists in the Character Cheats panel");
			yield break;
		}
		string text = CheckLists(panel, scenes, dropdowns);
		if (text != null)
		{
			Fail(text);
			yield break;
		}
		int berg = Array.FindIndex(AreaManager.AreaFamilies, (AreaFamily f) => f.FamilyName == "Berg");
		if (berg < 0 || (Object)(object)dropdowns[berg] == (Object)null)
		{
			Fail("no Berg list");
			yield break;
		}
		Dropdown dropdown = dropdowns[berg];
		yield return Capture("panel");
		panel.OnSceneFamilyClicked(berg);
		dropdown.Show();
		yield return WaitRealtime(1.5f);
		yield return Capture("berg_list");
		dropdown.Hide();
		yield return WaitRealtime(0.5f);
		yield return CheckListLayouts(panel, dropdowns);
		if (offScreenLists > 0)
		{
			Fail($"{offScreenLists} lists not fully on screen");
			yield break;
		}
		bool flag = UnityEngineExtensions.Contains<string>(Environment.GetCommandLineArgs(), "--dtn-test-all");
		List<(int family, string label)> probes = new List<(int, string)>();
		for (int num3 = 0; num3 < scenes.Length; num3++)
		{
			foreach (Destination item3 in AreaSwitchPatches.Get(panel, num3) ?? new List<Destination>())
			{
				if (flag ? ((byte)item3.Spawn != 0) : (item3.Label.EndsWith("Immaculate Dreamer") || item3.Label.EndsWith("Elite Boozu") || (item3.Scene == "EmercarDungeonsSmall" && item3.Spawn == 9) || (item3.Scene == "CalderaDungeonsSmall" && item3.Spawn == 11) || item3.Scene == "Chersonese_Dungeon3" || item3.Label.EndsWith("Grandmother") || item3.Scene == "Caldera_Dungeon10"))
				{
					probes.Add((num3, item3.Label));
				}
			}
		}
		Log($"teleport: {probes.Count} destinations to try");
		int failures = 0;
		foreach (var item4 in probes)
		{
			int item = item4.family;
			string item2 = item4.label;
			string result = null;
			yield return Teleport(item, item2, delegate(string r)
			{
				result = r;
			});
			if (result != null)
			{
				failures++;
				Log("teleport FAILED: " + result);
			}
		}
		if (failures > 0)
		{
			Fail($"{failures} of {probes.Count} teleports failed");
		}
		else
		{
			Log("done");
		}
	}

	private IEnumerator Teleport(int family, string label, Action<string> fail)
	{
		Character character = CharacterManager.Instance.GetFirstLocalCharacter();
		DeveloperToolManager tools = ((Component)character.CharacterUI).GetComponentInChildren<DeveloperToolManager>(true);
		tools.ShowDeveloperTool(1);
		yield return WaitRealtime(1f);
		DT_CharacterCheats componentInChildren = ((Component)tools).GetComponentInChildren<DT_CharacterCheats>(true);
		Dropdown dropdown = Traverse.Create((object)componentInChildren).Field("m_ddFamilies").GetValue<Dropdown[]>()[family];
		int num = dropdown.options.FindIndex((OptionData o) => o.text == label);
		Destination d = AreaSwitchPatches.Get(componentInChildren, family, num);
		if (d == null)
		{
			fail($"\"{label}\" not in list {family}");
			yield break;
		}
		int loads = s_loadsStarted;
		componentInChildren.OnSceneFamilyClicked(family);
		((Component)dropdown).transform.Find("Dropdown List");
		if (d.Label.EndsWith("Grandmother"))
		{
			dropdown.Show();
			yield return WaitRealtime(1f);
			Transform obj = ((Component)dropdown).transform.Find("Dropdown List");
			Toggle val = ((obj != null) ? ((IEnumerable<Toggle>)((Component)obj).GetComponentsInChildren<Toggle>()).FirstOrDefault((Func<Toggle, bool>)delegate(Toggle t)
			{
				Text componentInChildren2 = ((Component)t).GetComponentInChildren<Text>();
				return ((componentInChildren2 != null) ? componentInChildren2.text : null) == label;
			}) : null);
			if ((Object)(object)val == (Object)null)
			{
				fail("\"" + label + "\": no list entry to click");
				yield break;
			}
			Log($"teleport: clicking \"{label}\" at {((Component)val).transform.position:F0}");
			ExecuteEvents.Execute<IPointerClickHandler>(((Component)val).gameObject, (BaseEventData)new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
		}
		else
		{
			dropdown.value = num;
		}
		yield return null;
		if (s_loadsStarted == loads)
		{
			fail("\"" + label + "\": no area switch requested");
			yield break;
		}
		float deadline = Time.realtimeSinceStartup + 60f;
		while (NetworkLevelLoader.Instance.IsOverallLoadingDone && Time.realtimeSinceStartup < deadline)
		{
			yield return null;
		}
		deadline = Time.realtimeSinceStartup + 300f;
		while (!InGameplay(d.Scene) || (Object)(object)SpawnPointManager.Instance == (Object)null)
		{
			if (Time.realtimeSinceStartup > deadline)
			{
				fail("\"" + label + "\": in " + ActiveScene + " after 300 s, expected " + d.Scene);
				yield break;
			}
			yield return null;
		}
		yield return WaitRealtime(2f);
		character = CharacterManager.Instance.GetFirstLocalCharacter();
		Transform[] spawns = SpawnPointManager.Instance.SpawnPoints;
		float num2 = ((d.Spawn < spawns.Length && (Object)(object)spawns[d.Spawn] != (Object)null) ? Vector3.Distance(spawns[d.Spawn].position, ((Component)character).transform.position) : float.NaN);
		int num3 = (from i in Enumerable.Range(0, spawns.Length)
			where (Object)(object)spawns[i] != (Object)null
			orderby Vector3.Distance(spawns[i].position, ((Component)character).transform.position)
			select i).FirstOrDefault();
		Log($"teleport: \"{label}\" -> {ActiveScene} #{d.Spawn}, {num2:F1} m from it (nearest spawn {num3}), alive {!character.IsDead}");
		if (!(num2 < 30f))
		{
			fail($"\"{label}\": landed {num2:F0} m from spawn {d.Spawn} of {d.Scene}");
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(NetworkLevelLoader), "RequestSwitchArea", new Type[]
	{
		typeof(float),
		typeof(string),
		typeof(int),
		typeof(float),
		typeof(bool)
	})]
	private static void CountLoads()
	{
		s_loadsStarted++;
	}

	private static void DumpChain(Transform t)
	{
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		while ((Object)(object)t != (Object)null)
		{
			CanvasGroup component = ((Component)t).GetComponent<CanvasGroup>();
			Canvas component2 = ((Component)t).GetComponent<Canvas>();
			Log($"  {((Object)t).name}: active {((Component)t).gameObject.activeSelf}" + (((Object)(object)component != (Object)null) ? $", group alpha {component.alpha}" : "") + (((Object)(object)component2 != (Object)null) ? $", canvas {component2.renderMode} enabled {((Behaviour)component2).enabled} order {component2.sortingOrder}" : "") + $", layer {((Component)t).gameObject.layer}");
			t = t.parent;
		}
	}

	private static void DumpAreas()
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("SceneName\tDefaultName\tNameLocKey\tGetName\tDLC\tInBuild");
		HashSet<string> hashSet = new HashSet<string>(AreaManager.ActiveScenes ?? new string[0]);
		Area[] areas = AreaManager.Instance.Areas;
		foreach (Area val in areas)
		{
			stringBuilder.AppendLine($"{val.SceneName}\t{val.DefaultName}\t{val.NameLocKey}\t{val.GetName()}\t{val.DLCId}\t{hashSet.Contains(val.SceneName)}");
		}
		File.WriteAllText(Path.Combine(Path.Combine(Paths.BepInExRootPath, "DebugTeleportNamesTest"), "areas.tsv"), stringBuilder.ToString());
		Log($"{AreaManager.Instance.Areas.Length} areas dumped, language {LocalizationManager.Instance.CurrentLanguage}");
	}

	private static string CheckLists(DT_CharacterCheats panel, List<string>[] scenes, Dropdown[] dropdowns)
	{
		int num = 0;
		for (int i = 0; i < scenes.Length; i++)
		{
			if (scenes[i] == null)
			{
				continue;
			}
			Dropdown val = dropdowns[i];
			string text = ((i < AreaManager.AreaFamilies.Length) ? AreaManager.AreaFamilies[i].FamilyName : "Others");
			List<Destination> list = AreaSwitchPatches.Get(panel, i);
			if (list == null)
			{
				return "list " + text + ": not built";
			}
			Log($"list {text}: {list.Count} destinations for {scenes[i].Count} scenes");
			if (val.options.Count != list.Count + 1 || val.options[0].text != "")
			{
				return $"list {text}: {val.options.Count} options for {list.Count} destinations";
			}
			if (val.options.Select((OptionData o) => o.text).Distinct().Count() != val.options.Count)
			{
				return "list " + text + ": two destinations with the same label";
			}
			string text2 = scenes[i].FirstOrDefault((string s) => list.All((Destination d) => d.Scene != s));
			if (text2 != null)
			{
				return "list " + text + ": scene " + text2 + " lost";
			}
			if ((from d in list
				group d by (Scene: d.Scene, Spawn: d.Spawn)).Any((IGrouping<(string Scene, int Spawn), Destination> g) => g.Count() > 1))
			{
				return "list " + text + ": one spawn point listed twice";
			}
			for (int num2 = 0; num2 < list.Count; num2++)
			{
				Destination destination = list[num2];
				Destination destination2 = ((num2 > 0) ? list[num2 - 1] : null);
				Log($"  {num2 + 1,2} {destination.Kind,-7} {destination.Label}  <- {destination.Scene} #{destination.Spawn}");
				if (val.options[num2 + 1].text != destination.Label)
				{
					return $"list {text}: option {num2 + 1} \"{val.options[num2 + 1].text}\" is not \"{destination.Label}\"";
				}
				if (destination2 != null && destination2.Kind > destination.Kind)
				{
					return $"list {text}: {destination2.Kind} \"{destination2.Label}\" before {destination.Kind} \"{destination.Label}\"";
				}
				if (Plugin.SortByName.Value && destination2 != null && destination2.Kind == destination.Kind && string.Compare(destination2.Label, destination.Label, StringComparison.CurrentCultureIgnoreCase) > 0)
				{
					return "list " + text + ": \"" + destination2.Label + "\" listed before \"" + destination.Label + "\"";
				}
			}
			if (list.Any((Destination d) => d.Kind == Kind.Town) && list[0].Kind != Kind.Town)
			{
				return "list " + text + ": the town is not first";
			}
			num += scenes[i].Count;
		}
		if (num != AreaManager.ActiveScenes.Count((string s) => AreaManager.Instance.GetAreaFromSceneName(s) != null && s != "Tutorial_Standalone" && StoreManager.Instance.IsDlcInstalled(AreaManager.Instance.GetAreaFromSceneName(s).DLCId)))
		{
			return $"{num} scenes listed, not every area of the build";
		}
		return null;
	}

	private IEnumerator Capture(string label)
	{
		string file = Path.Combine(outputDir, label + ".png");
		if (!Application.isBatchMode)
		{
			yield return (object)new WaitForEndOfFrame();
			Texture2D val = ScreenCapture.CaptureScreenshotAsTexture();
			File.WriteAllBytes(file, ImageConversion.EncodeToPNG(val));
			Object.Destroy((Object)(object)val);
			Log("captured " + file);
		}
		else
		{
			Log("batchmode: no screen to capture for " + label);
		}
	}

	private IEnumerator CheckListLayouts(DT_CharacterCheats panel, Dropdown[] dropdowns)
	{
		offScreenLists = 0;
		for (int f = 0; f < dropdowns.Length; f++)
		{
			Dropdown dropdown = dropdowns[f];
			if ((Object)(object)dropdown == (Object)null)
			{
				continue;
			}
			string family = ((f < AreaManager.AreaFamilies.Length) ? AreaManager.AreaFamilies[f].FamilyName : "Others");
			panel.OnSceneFamilyClicked(f);
			ListColumns.LastLayout = "single column";
			dropdown.Show();
			yield return WaitRealtime(1f);
			Transform obj = ((Component)dropdown).transform.Find("Dropdown List");
			RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				Log("layout " + family + ": no list opened");
				offScreenLists++;
				continue;
			}
			if (family == "Sirocco")
			{
				File.WriteAllText(Path.Combine(outputDir, "list_hierarchy.txt"), Describe((Transform)(object)val, 0, new StringBuilder()).ToString());
			}
			Toggle[] array = (from t in ((Component)val).GetComponentsInChildren<Toggle>(true)
				where ((Component)t).gameObject.activeInHierarchy
				select t).ToArray();
			int num = 0;
			Vector3[] array2 = (Vector3[])(object)new Vector3[4];
			Toggle[] array3 = array;
			for (int num2 = 0; num2 < array3.Length; num2++)
			{
				((RectTransform)((Component)array3[num2]).transform).GetWorldCorners(array2);
				if (array2.Any((Vector3 c) => c.x < -0.5f || c.y < -0.5f || c.x > (float)Screen.width + 0.5f || c.y > (float)Screen.height + 0.5f))
				{
					num++;
				}
			}
			val.GetWorldCorners(array2);
			Log($"layout {family}: {array.Length} items, {num} off screen, list {array2[0]:F0}-{array2[2]:F0}, {ListColumns.LastLayout}");
			if (num > 0)
			{
				offScreenLists++;
			}
			yield return Capture("list_" + family);
			dropdown.Hide();
			yield return WaitRealtime(0.5f);
		}
	}

	private static StringBuilder Describe(Transform t, int depth, StringBuilder sb)
	{
		//IL_0054: 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_0070: 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_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Expected O, but got Unknown
		RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null);
		sb.Append(' ', depth * 2).Append(((Object)t).name).Append(((Component)t).gameObject.activeSelf ? "" : " (inactive)");
		if ((Object)(object)val != (Object)null)
		{
			object[] obj = new object[6] { val.anchorMin, val.anchorMax, val.pivot, val.anchoredPosition, val.sizeDelta, null };
			Rect rect = val.rect;
			obj[5] = ((Rect)(ref rect)).size;
			sb.Append(string.Format("  anchors {0:F2}-{1:F2} pivot {2:F2} pos {3:F1} size {4:F1} rect {5:F1}", obj));
		}
		sb.Append("  [").Append(string.Join(", ", from c in ((Component)t).GetComponents<Component>()
			where !(c is Transform)
			select ((object)c).GetType().Name)).AppendLine("]");
		int num = 0;
		foreach (Transform item in t)
		{
			Transform val2 = item;
			if ((Object)(object)((Component)val2).GetComponent<Toggle>() == (Object)null || num++ < 1)
			{
				Describe(val2, depth + 1, sb);
			}
		}
		return sb;
	}

	private IEnumerator Probe(string scene, string pattern)
	{
		Log("probe: loading " + scene);
		NetworkLevelLoader.Instance.RequestSwitchArea(scene, 0, 1.5f, false);
		yield return WaitRealtime(3f);
		float deadline = Time.realtimeSinceStartup + 300f;
		while (!InGameplay(scene))
		{
			if (Time.realtimeSinceStartup > deadline)
			{
				Fail("probe: " + scene + " did not load");
				yield break;
			}
			yield return null;
		}
		yield return WaitRealtime(4f);
		string path = Path.Combine(outputDir, "probe_" + scene + ".txt");
		try
		{
			File.WriteAllText(path, DescribeProbe(scene, pattern));
		}
		catch (Exception ex)
		{
			File.WriteAllText(path, ex.ToString());
		}
		Log("probe: done");
	}

	private static string DescribeProbe(string scene, string patternList)
	{
		//IL_0735: Unknown result type (might be due to invalid IL or missing references)
		//IL_073a: Unknown result type (might be due to invalid IL or missing references)
		//IL_09c8: Unknown result type (might be due to invalid IL or missing references)
		string[] array = patternList.Split(new char[1] { '|' });
		string pattern = array[0];
		StringBuilder stringBuilder = new StringBuilder();
		List<GameObject> source = Resources.FindObjectsOfTypeAll<GameObject>().Where(delegate(GameObject g)
		{
			//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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			Scene scene3 = g.scene;
			if (!(((Scene)(ref scene3)).name == scene))
			{
				scene3 = g.scene;
				return ((Scene)(ref scene3)).name == "DontDestroyOnLoad";
			}
			return true;
		}).ToList();
		HashSet<GameObject> hashSet = new HashSet<GameObject>(source.Where(delegate(GameObject g)
		{
			//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)
			Scene scene3 = g.scene;
			return ((Scene)(ref scene3)).name == scene && ((Object)g).name.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) >= 0;
		}));
		stringBuilder.AppendLine($"== objects named *{pattern}* ({hashSet.Count})");
		foreach (GameObject item in hashSet.OrderBy((GameObject g) => HierarchyPath(g.transform)))
		{
			stringBuilder.AppendLine($"  {HierarchyPath(item.transform)}  self {item.activeSelf} hierarchy {item.activeInHierarchy}  " + "[" + string.Join(", ", from c in item.GetComponents<Component>()
				where (Object)(object)c != (Object)null && !(c is Transform)
				select ((object)c).GetType().Name) + "]");
		}
		foreach (GameObjectToggleOnQuestEvent item2 in hashSet.SelectMany((GameObject g) => g.GetComponents<GameObjectToggleOnQuestEvent>()))
		{
			string text = JsonUtility.ToJson((object)item2);
			foreach (Match item3 in Regex.Matches(text, "\"m_eventUID\":\"([^\"]+)\""))
			{
				text += $"  [{item3.Groups[1].Value} = {QuestEventDictionary.GetQuestEvent(item3.Groups[1].Value)?.EventName}, stack {QuestEventManager.Instance.GetEventCurrentStack(item3.Groups[1].Value)}]";
			}
			stringBuilder.AppendLine("  toggle on " + HierarchyPath(((Component)item2).transform) + ": " + text + "  ObjectToToggle " + (((Object)(object)item2.ObjectToToggle != (Object)null) ? HierarchyPath(item2.ObjectToToggle.transform) : "null"));
		}
		stringBuilder.AppendLine("== components referencing them");
		foreach (MonoBehaviour item4 in from c in source.Where(delegate(GameObject g)
			{
				//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)
				Scene scene3 = g.scene;
				return ((Scene)(ref scene3)).name == scene;
			}).SelectMany((GameObject g) => g.GetComponents<MonoBehaviour>())
			where (Object)(object)c != (Object)null
			select c)
		{
			foreach (FieldInfo item5 in AccessTools.GetDeclaredFields(((object)item4).GetType()).Concat(BaseFields(((object)item4).GetType())).Distinct())
			{
				object value;
				try
				{
					value = item5.GetValue(item4);
				}
				catch
				{
					continue;
				}
				List<string> list;
				try
				{
					list = (from g in References(value).Where(hashSet.Contains)
						select ((Object)g).name).ToList();
				}
				catch
				{
					continue;
				}
				if (list.Count > 0)
				{
					stringBuilder.AppendLine(string.Format("  {0} {1}.{2} -> {3}  (enabled {4})", HierarchyPath(((Component)item4).transform), ((object)item4).GetType().Name, item5.Name, string.Join(", ", list), ((Behaviour)item4).enabled));
				}
			}
		}
		stringBuilder.AppendLine("== components whose serialized data mentions a pattern");
		foreach (MonoBehaviour item6 in from c in source.Where(delegate(GameObject g)
			{
				//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)
				Scene scene3 = g.scene;
				return ((Scene)(ref scene3)).name == scene;
			}).SelectMany((GameObject g) => g.GetComponents<MonoBehaviour>())
			where (Object)(object)c != (Object)null
			select c)
		{
			if (!(item6 is GraphOwner))
			{
				string data;
				try
				{
					data = JsonUtility.ToJson((object)item6);
				}
				catch
				{
					continue;
				}
				if (array.Any((string p) => data.IndexOf(p, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					stringBuilder.AppendLine(string.Format("  {0} {1} (active {2}): {3}", HierarchyPath(((Component)item6).transform), ((object)item6).GetType().Name, ((Behaviour)item6).isActiveAndEnabled, (data.Length > 1500) ? (data.Substring(0, 1500) + "...") : data));
				}
			}
		}
		stringBuilder.AppendLine("== graphs mentioning it");
		HashSet<string> hashSet2 = new HashSet<string>();
		foreach (GraphOwner item7 in from o in source.SelectMany((GameObject g) => g.GetComponents<GraphOwner>())
			where (Object)(object)o != (Object)null
			select o)
		{
			Graph graph = item7.graph;
			string value2 = Traverse.Create((object)item7).Field("boundGraphSerialization").GetValue<string>();
			string json = ((!string.IsNullOrEmpty(value2)) ? value2 : (((Object)(object)graph != (Object)null) ? Traverse.Create((object)graph).Field("_serializedGraph").GetValue<string>() : null));
			if (json == null || !array.Any((string p) => json.IndexOf(p, StringComparison.OrdinalIgnoreCase) >= 0))
			{
				continue;
			}
			string[] obj4 = new string[8]
			{
				"  ",
				HierarchyPath(((Component)item7).transform),
				" (",
				null,
				null,
				null,
				null,
				null
			};
			Scene scene2 = ((Component)item7).gameObject.scene;
			obj4[3] = ((Scene)(ref scene2)).name;
			obj4[4] = ") ";
			obj4[5] = ((object)item7).GetType().Name;
			obj4[6] = " ";
			obj4[7] = $"graph {((graph != null) ? graph.name : null)}, active {((Behaviour)item7).isActiveAndEnabled}:\n{json}\n";
			stringBuilder.AppendLine(string.Concat(obj4));
			foreach (Match item8 in Regex.Matches(json, "m_eventUID\":\"([^\"]+)\""))
			{
				hashSet2.Add(item8.Groups[1].Value);
			}
		}
		stringBuilder.AppendLine("== quest events used by those graphs");
		foreach (string item9 in hashSet2)
		{
			QuestEventSignature questEvent = QuestEventDictionary.GetQuestEvent(item9);
			stringBuilder.AppendLine("  " + item9 + ": " + ((questEvent == null) ? "?" : $"{questEvent.ParentSection?.Name}/{questEvent.EventName} \"{questEvent.Description}\" timed {questEvent.IsTimedEvent} stackable {questEvent.IsStackable} savable {questEvent.Savable}") + $"  stack now {QuestEventManager.Instance.GetEventCurrentStack(item9)}");
		}
		stringBuilder.AppendLine("== interactions");
		foreach (InteractionBase item10 in from i in source.SelectMany((GameObject g) => g.GetComponents<InteractionBase>())
			where (Object)(object)i != (Object)null
			select i)
		{
			stringBuilder.AppendLine($"  {HierarchyPath(((Component)item10).transform)} {((object)item10).GetType().Name}  active {((Component)item10).gameObject.activeInHierarchy} at {((Component)item10).transform.position:F0}");
		}
		return stringBuilder.ToString();
	}

	private static IEnumerable<FieldInfo> BaseFields(Type type)
	{
		type = type.BaseType;
		while (type != null && type != typeof(MonoBehaviour))
		{
			foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(type))
			{
				yield return declaredField;
			}
			type = type.BaseType;
		}
	}

	private static IEnumerable<GameObject> References(object value)
	{
		GameObject val = (GameObject)((value is GameObject) ? value : null);
		if (val == null)
		{
			Component val2 = (Component)((value is Component) ? value : null);
			if (val2 == null)
			{
				if (value is string)
				{
					yield break;
				}
			}
			else if ((Object)(object)val2 != (Object)null)
			{
				yield return val2.gameObject;
				yield break;
			}
			if (!(value is IEnumerable enumerable))
			{
				yield break;
			}
			foreach (object item in enumerable)
			{
				GameObject val3 = (GameObject)((item is GameObject) ? item : null);
				if (val3 != null && (Object)(object)val3 != (Object)null)
				{
					yield return val3;
					continue;
				}
				Component val4 = (Component)((item is Component) ? item : null);
				if (val4 != null && (Object)(object)val4 != (Object)null)
				{
					yield return val4.gameObject;
				}
			}
		}
		else if ((Object)(object)val != (Object)null)
		{
			yield return val;
		}
	}

	private IEnumerator Survey()
	{
		string file = Path.Combine(outputDir, "survey.txt");
		File.WriteAllText(file, "");
		string[] commandLineArgs = Environment.GetCommandLineArgs();
		int num = Array.IndexOf(commandLineArgs, "--dtn-survey-scenes");
		string[] array = ((num >= 0 && num + 1 < commandLineArgs.Length) ? commandLineArgs[num + 1].Split(new char[1] { ',' }) : SurveyScenes);
		if (num >= 0 && commandLineArgs[num + 1] == "all")
		{
			array = AreaManager.ActiveScenes.Where((string s) => AreaManager.Instance.GetAreaFromSceneName(s) != null && s != "Tutorial_Standalone").ToArray();
		}
		File.AppendAllText(file, DescribeNameTables());
		string[] array2 = array;
		foreach (string scene in array2)
		{
			Log("survey: loading " + scene);
			NetworkLevelLoader.Instance.RequestSwitchArea(scene, 0, 1.5f, false);
			float deadline = Time.realtimeSinceStartup + 300f;
			yield return WaitRealtime(3f);
			while (!InGameplay(scene))
			{
				if (Time.realtimeSinceStartup > deadline)
				{
					Fail("survey: " + scene + " did not load");
					yield break;
				}
				yield return null;
			}
			yield return WaitRealtime(4f);
			try
			{
				File.AppendAllText(file, DescribeScene(scene));
			}
			catch (Exception arg)
			{
				File.AppendAllText(file, $"== {scene}: {arg}\n");
			}
		}
		Log("survey: done");
	}

	private static string DescribeScene(string scene)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0325: Unknown result type (might be due to invalid IL or missing references)
		//IL_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0418: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder();
		Area areaFromSceneName = AreaManager.Instance.GetAreaFromSceneName(scene);
		AreaEnum val = (AreaEnum)areaFromSceneName.ID;
		stringBuilder.AppendLine($"== {scene} ({val}, \"{areaFromSceneName.GetName()}\")");
		Transform[] array = (Transform[])(((Object)(object)SpawnPointManager.Instance != (Object)null) ? ((Array)SpawnPointManager.Instance.SpawnPoints) : ((Array)new Transform[0]));
		stringBuilder.AppendLine($"spawn points: {array.Length}");
		for (int i = 0; i < array.Length; i++)
		{
			Transform val2 = array[i];
			object arg = i;
			string arg2 = (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "null");
			object arg3;
			if (!((Object)(object)val2 != (Object)null))
			{
				arg3 = "-";
			}
			else
			{
				Vector3 position = val2.position;
				arg3 = ((Vector3)(ref position)).ToString("F0");
			}
			stringBuilder.AppendLine($"  spawn {arg}: {arg2} at {arg3}" + "  GetAreaName \"" + AreaManager.Instance.GetAreaName(val, i) + "\"");
		}
		stringBuilder.AppendLine("doors:");
		foreach (InteractionSwitchArea item in Resources.FindObjectsOfTypeAll<InteractionSwitchArea>().Where(delegate(InteractionSwitchArea d)
		{
			//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)
			Scene scene2 = ((Component)d).gameObject.scene;
			return ((Scene)(ref scene2)).name == scene;
		}))
		{
			string value = Traverse.Create((object)item).Field("m_overrideAreaLocKey").GetValue<string>();
			Area area = AreaManager.Instance.GetArea(item.Area);
			stringBuilder.AppendLine($"  {((Component)item).transform.position:F0} -> {item.Area} ({area?.SceneName}) spawn {item.SpawnPoint}" + "  name \"" + AreaManager.Instance.GetAreaName(item.Area, item.SpawnPoint) + "\"" + (string.IsNullOrEmpty(value) ? "" : ("  override " + value + " \"" + LocalizationManager.Instance.GetLoc(value) + "\"")) + $"  active {((Component)item).gameObject.activeInHierarchy}  path {HierarchyPath(((Component)item).transform)}");
		}
		stringBuilder.AppendLine("characters (nearest spawn):");
		foreach (Character item2 in CharacterManager.Instance.Characters.Values.Where((Character c) => (Object)(object)c != (Object)null && !c.IsLocalPlayer))
		{
			int num = -1;
			float num2 = float.MaxValue;
			for (int num3 = 0; num3 < array.Length; num3++)
			{
				if (!((Object)(object)array[num3] == (Object)null))
				{
					float num4 = Vector3.Distance(array[num3].position, ((Component)item2).transform.position);
					if (num4 < num2)
					{
						num2 = num4;
						num = num3;
					}
				}
			}
			string value2 = Traverse.Create((object)item2).Field("m_nameLocKey").GetValue<string>();
			object[] obj = new object[8] { num, num2, item2.Name, value2, item2.UID, null, null, null };
			CharacterStats stats = item2.Stats;
			obj[5] = ((stats != null) ? new float?(stats.MaxHealth) : ((float?)null));
			obj[6] = item2.IsAI;
			obj[7] = item2.Faction;
			stringBuilder.AppendLine(string.Format("  spawn {0} ({1:F0} m): \"{2}\" key {3} uid {4} hp {5:F0} ai {6} faction {7}", obj) + $" active {((Component)item2).gameObject.activeInHierarchy} at {((Component)item2).transform.position:F0}  {((Object)((Component)item2).gameObject).name}");
		}
		stringBuilder.AppendLine();
		return stringBuilder.ToString();
	}

	private static string DescribeNameTables()
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		StringBuilder stringBuilder = new StringBuilder("== name tables\n");
		SmallDungeonName[] smallDungeonNames = AreaManager.Instance.SmallDungeonNames;
		foreach (SmallDungeonName val in smallDungeonNames)
		{
			stringBuilder.AppendLine($"  {val.SmallDungeon}: " + string.Join(" | ", val.SpawnIndexLocKey.Select((string key, int num2) => $"[{num2}] {key} \"{LocalizationManager.Instance.GetLoc(key)}\"")));
		}
		string[] array = new string[3] { "Scene_Harmattan_DungeonsSmall", "Scene_Caldera_SmallDungeon", "Scene_Caldera_SmallDungeon0" };
		string text2 = default(string);
		foreach (string text in array)
		{
			for (int num = 0; num <= 14; num++)
			{
				if (LocalizationManager.Instance.TryGetLoc(text + num, ref text2))
				{
					stringBuilder.AppendLine("  " + text + num + " \"" + text2 + "\"");
				}
			}
		}
		return stringBuilder.AppendLine().ToString();
	}

	private static string HierarchyPath(Transform t)
	{
		string text = ((Object)t).name;
		t = t.parent;
		while ((Object)(object)t != (Object)null)
		{
			text = ((Object)t).name + "/" + text;
			t = t.parent;
		}
		return text;
	}
}