Decompiled source of TelAvivStage v0.4.1

plugins/TelAvivStage/TelAvivStage.dll

Decompiled 15 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.Security.Cryptography;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG;
using HG.Reflection;
using R2API;
using RoR2;
using RoR2.ConVar;
using RoR2.ContentManagement;
using RoR2.Navigation;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TelAvivStage")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Tel Aviv, an original Risk of Rain 2 stage.")]
[assembly: AssemblyFileVersion("0.4.0.0")]
[assembly: AssemblyInformationalVersion("0.4.0")]
[assembly: AssemblyProduct("TelAvivStage")]
[assembly: AssemblyTitle("TelAvivStage")]
[assembly: AssemblyVersion("0.4.0.0")]
namespace TelAvivStage;

internal sealed class TelAvivContent : IContentPackProvider
{
	private readonly string folder;

	private readonly ManualLogSource log;

	private readonly int stageOrder;

	private readonly float weight;

	private readonly bool preLoop;

	private readonly bool postLoop;

	private AssetBundle sceneBundle;

	private AssetBundle assetsBundle;

	private AsyncOperationHandle<GameObject> teleporterIndicatorHandle;

	private AsyncOperationHandle<GameObject> hiddenPickupHandle;

	internal NavigationData Navigation;

	internal DccsPool MonsterPool;

	internal DccsPool InteractablePool;

	internal SpawnCard TeleporterCard;

	internal InteractableSpawnCard LemurianEgg;

	internal SceneDef Definition;

	public string identifier => "com.gal66.telavivstage";

	internal string BundleFingerprint { get; }

	internal TelAvivContent(string folder, ManualLogSource log, int stageOrder, float weight, bool preLoop, bool postLoop)
	{
		TelAvivContent telAvivContent = this;
		this.folder = Path.Combine(folder, "AssetBundles");
		this.log = log;
		this.stageOrder = stageOrder;
		this.weight = weight;
		this.preLoop = preLoop;
		this.postLoop = postLoop;
		SHA256 hash = SHA256.Create();
		try
		{
			IEnumerable<string> values = new string[2] { "telavivscene", "telavivassets" }.Select(delegate(string name)
			{
				string text = Path.Combine(telAvivContent.folder, name);
				if (!File.Exists(text))
				{
					throw new FileNotFoundException("Tel Aviv requires both built asset bundles.", text);
				}
				using FileStream inputStream = File.OpenRead(text);
				return BitConverter.ToString(hash.ComputeHash(inputStream)).Replace("-", "");
			});
			BundleFingerprint = string.Join("", values);
		}
		finally
		{
			if (hash != null)
			{
				((IDisposable)hash).Dispose();
			}
		}
	}

	public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
	{
		AssetBundleCreateRequest sceneRequest = AssetBundle.LoadFromFileAsync(Path.Combine(folder, "telavivscene"));
		yield return sceneRequest;
		sceneBundle = sceneRequest.assetBundle;
		AssetBundleCreateRequest assetRequest = AssetBundle.LoadFromFileAsync(Path.Combine(folder, "telavivassets"));
		yield return assetRequest;
		assetsBundle = assetRequest.assetBundle;
		if (!Object.op_Implicit((Object)(object)sceneBundle) || !Object.op_Implicit((Object)(object)assetsBundle) || !sceneBundle.GetAllScenePaths().Any((string path) => Path.GetFileNameWithoutExtension(path) == "telaviv_city"))
		{
			throw new InvalidDataException("Tel Aviv scene bundle is missing telaviv_city.");
		}
		TextAsset val = assetsBundle.LoadAsset<TextAsset>("telaviv_navigation");
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidDataException("Tel Aviv navigation was not baked.");
		}
		Navigation = JsonUtility.FromJson<NavigationData>(val.text);
		if (Navigation == null || Navigation.ground == null || Navigation.ground.Length < 40 || Navigation.air == null || Navigation.air.Length < 10)
		{
			throw new InvalidDataException("Tel Aviv needs valid baked ground and air navigation graphs.");
		}
		args.ReportProgress(0.4f);
		MonsterPool = Addressables.LoadAssetAsync<DccsPool>((object)"RoR2/Base/goolake/dpGooLakeMonsters.asset").WaitForCompletion();
		InteractablePool = Addressables.LoadAssetAsync<DccsPool>((object)"RoR2/Base/goolake/dpGooLakeInteractables.asset").WaitForCompletion();
		TeleporterCard = Addressables.LoadAssetAsync<SpawnCard>((object)"RoR2/Base/Teleporters/iscTeleporter.asset").WaitForCompletion();
		LemurianEgg = Addressables.LoadAssetAsync<InteractableSpawnCard>((object)"RoR2/CU8/LemurianEgg/iscLemurianEgg.asset").WaitForCompletion();
		if (!Object.op_Implicit((Object)(object)MonsterPool) || !Object.op_Implicit((Object)(object)InteractablePool) || !Object.op_Implicit((Object)(object)TeleporterCard))
		{
			throw new InvalidOperationException("Required base-game director assets are unavailable.");
		}
		teleporterIndicatorHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/PositionIndicators/TeleporterChargingPositionIndicator");
		hiddenPickupHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/PickupModels/PickupMystery");
		yield return teleporterIndicatorHandle;
		yield return hiddenPickupHandle;
		if (!teleporterIndicatorHandle.IsValid() || !hiddenPickupHandle.IsValid() || (int)teleporterIndicatorHandle.Status != 1 || (int)hiddenPickupHandle.Status != 1 || !Object.op_Implicit((Object)(object)teleporterIndicatorHandle.Result) || !Object.op_Implicit((Object)(object)hiddenPickupHandle.Result))
		{
			throw new InvalidOperationException("Required teleporter/pickup presentation assets failed to preload.");
		}
		Definition = ScriptableObject.CreateInstance<SceneDef>();
		Definition.cachedName = "telaviv_city";
		Definition.baseSceneNameOverride = "telaviv_city";
		Definition.sceneType = (SceneType)1;
		Definition.stageOrder = stageOrder;
		Definition.isOfflineScene = false;
		Definition.nameToken = "TELAVIV_NAME";
		Definition.subtitleToken = "TELAVIV_SUBTITLE";
		Definition.portalSelectionMessageString = "TELAVIV_SEER";
		Definition.loreToken = "TELAVIV_LORE";
		Definition.shouldIncludeInLogbook = false;
		Definition.validForRandomSelection = true;
		Definition.allowItemsToSpawnObjects = true;
		Definition.environmentColor = new Color(0.57f, 0.71f, 0.74f);
		Definition.mainTrack = Addressables.LoadAssetAsync<MusicTrackDef>((object)"RoR2/Base/Common/MusicTrackDefs/muSong13.asset").WaitForCompletion();
		Definition.bossTrack = Addressables.LoadAssetAsync<MusicTrackDef>((object)"RoR2/Base/Common/MusicTrackDefs/muSong05.asset").WaitForCompletion();
		Definition.previewTexture = (Texture)(object)assetsBundle.LoadAsset<Texture2D>("telaviv_preview");
		if (Object.op_Implicit((Object)(object)Definition.previewTexture))
		{
			Definition.portalMaterial = StageRegistration.MakeBazaarSeerMaterial((Texture2D)Definition.previewTexture);
		}
		GameFields.Set(Definition, "shouldUpdateSceneCollectionAfterLooping", true);
		StageRegistration.RegisterSceneDefToNormalProgression(Definition, weight, preLoop, postLoop);
		args.ReportProgress(1f);
	}

	public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
	{
		args.output.sceneDefs.Add((SceneDef[])(object)new SceneDef[1] { Definition });
		args.ReportProgress(1f);
		yield break;
	}

	public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
	{
		log.LogInfo((object)string.Format("Tel Aviv registered as independent stage {0}; {1} ground nodes and {2} air nodes. Scene: {3}.", stageOrder, Navigation.ground.Length, Navigation.air.Length, "telaviv_city"));
		args.ReportProgress(1f);
		yield break;
	}
}
[Serializable]
internal sealed class NavigationData
{
	public int schemaVersion;

	public GraphNode[] ground;

	public GraphNode[] air;

	public Point[] spawnPoints;

	public Point[] teleporterPoints;

	public Point boundsMin;

	public Point boundsMax;
}
[Serializable]
internal sealed class Point
{
	public float x;

	public float y;

	public float z;

	public Vector3 Vector => new Vector3(x, y, z);
}
[Serializable]
internal sealed class GraphNode
{
	public float x;

	public float y;

	public float z;

	public int flags;

	public int forbiddenHulls;

	public GraphLink[] links;

	public int[] visible;

	public Vector3 Vector => new Vector3(x, y, z);
}
[Serializable]
internal sealed class GraphLink
{
	public int index;

	public int hullMask;

	public float distance;
}
[BepInPlugin("com.gal66.telavivstage", "Tel Aviv", "0.4.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class TelAvivPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.gal66.telavivstage";

	public const string PluginName = "Tel Aviv";

	public const string PluginVersion = "0.4.0";

	public const string SceneName = "telaviv_city";

	private TelAvivContent content;

	private void Awake()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Expected O, but got Unknown
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Expected O, but got Unknown
		ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("Rotation", "StageOrder", 2, new ConfigDescription("Normal loop slot, 1 to 4. Restart required. Slot 5 is reserved for the primordial teleporter.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
		ConfigEntry<float> val2 = ((BaseUnityPlugin)this).Config.Bind<float>("Rotation", "SelectionWeight", 1f, new ConfigDescription("Relative chance against other maps in the same slot. Restart required.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 10f), Array.Empty<object>()));
		ConfigEntry<bool> val3 = ((BaseUnityPlugin)this).Config.Bind<bool>("Rotation", "BeforeFirstLoop", true, "Allow Tel Aviv before the first loop. Restart required.");
		ConfigEntry<bool> val4 = ((BaseUnityPlugin)this).Config.Bind<bool>("Rotation", "AfterFirstLoop", true, "Allow Tel Aviv after looping. Restart required.");
		string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		content = new TelAvivContent(directoryName, ((BaseUnityPlugin)this).Logger, val.Value, val2.Value, val3.Value, val4.Value);
		NetworkModCompatibilityHelper.networkModList = NetworkModCompatibilityHelper.networkModList.Append("com.gal66.telavivstage;0.4.0;" + content.BundleFingerprint + ";" + val.Value + ";" + val3.Value + ";" + val4.Value).ToArray();
		ContentManager.collectContentPackProviders += new CollectContentPackProvidersDelegate(AddProvider);
		SceneManager.sceneLoaded += OnSceneLoaded;
		LanguageAPI.Add("TELAVIV_NAME", "Tel Aviv");
		LanguageAPI.Add("TELAVIV_SUBTITLE", "The White City, Adrift");
		LanguageAPI.Add("TELAVIV_SEER", "You dream of salt, concrete, and sleepless streets.");
		LanguageAPI.Add("TELAVIV_LORE", "A city remembered in fragments: three towers above a market, pale balconies turned toward the sea, and painted alleys that never learned to sleep. The distance between neighborhoods has collapsed. The streets still know the way.");
		if (Environment.GetCommandLineArgs().Contains("-telaviv-smoke"))
		{
			TelAvivSmokeTest telAvivSmokeTest = ((Component)this).gameObject.AddComponent<TelAvivSmokeTest>();
			telAvivSmokeTest.Log = ((BaseUnityPlugin)this).Logger;
			telAvivSmokeTest.OutputDirectory = directoryName;
		}
	}

	private void AddProvider(AddContentPackProviderDelegate addProvider)
	{
		addProvider.Invoke((IContentPackProvider)(object)content);
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		if (((Scene)(ref scene)).name != "telaviv_city")
		{
			return;
		}
		try
		{
			TelAvivScene.Setup(scene, content, ((BaseUnityPlugin)this).Logger);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Tel Aviv scene setup failed: " + ex));
		}
	}

	private void OnDestroy()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		ContentManager.collectContentPackProviders -= new CollectContentPackProvidersDelegate(AddProvider);
		SceneManager.sceneLoaded -= OnSceneLoaded;
	}
}
internal static class GameFields
{
	internal static void Set(object target, string field, object value)
	{
		FieldInfo? field2 = target.GetType().GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field2 == null)
		{
			throw new MissingFieldException(target.GetType().FullName, field);
		}
		field2.SetValue(target, value);
	}
}
internal static class TelAvivScene
{
	internal static void Setup(Scene scene, TelAvivContent content, ManualLogSource log)
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Expected O, but got Unknown
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0308: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0346: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_035d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0362: Unknown result type (might be due to invalid IL or missing references)
		//IL_038d: Unknown result type (might be due to invalid IL or missing references)
		//IL_038f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0391: Unknown result type (might be due to invalid IL or missing references)
		//IL_039b: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		if (((Scene)(ref scene)).GetRootGameObjects().Any((GameObject go) => ((Object)go).name == "TelAviv.Runtime"))
		{
			return;
		}
		if (content.Navigation == null)
		{
			throw new InvalidOperationException("Content pack has not loaded.");
		}
		GameObject val = new GameObject("TelAviv.Runtime");
		SceneManager.MoveGameObjectToScene(val, scene);
		val.SetActive(false);
		NodeGraph val2 = BuildGraph(content.Navigation.ground, "TelAvivGround", val.transform);
		NodeGraph val3 = BuildGraph(content.Navigation.air, "TelAvivAir", val.transform);
		GameObject obj = Child(val, "SceneInfo");
		SceneInfo val4 = obj.AddComponent<SceneInfo>();
		GameFields.Set(val4, "groundNodesAsset", val2);
		GameFields.Set(val4, "airNodesAsset", val3);
		ClassicStageInfo val5 = obj.AddComponent<ClassicStageInfo>();
		GameFields.Set(val5, "monsterDccsPool", content.MonsterPool);
		GameFields.Set(val5, "interactableDccsPool", content.InteractablePool);
		val5.sceneDirectorInteractibleCredits = 360;
		val5.sceneDirectorMonsterCredits = 25;
		val5.bonusInteractibleCreditObjects = Array.Empty<BonusInteractibleCreditObject>();
		val5.possibleMonsterFamilies = Array.Empty<MonsterFamily>();
		GameObject val6 = Child(val, "Director");
		val6.AddComponent<DirectorCore>();
		SceneDirector val7 = val6.AddComponent<SceneDirector>();
		((Behaviour)val7).enabled = false;
		val7.teleporterSpawnCard = content.TeleporterCard;
		val7.lumerianEgg = new DirectorCard
		{
			spawnCard = (SpawnCard)(object)content.LemurianEgg,
			selectionWeight = 1
		};
		val7.expRewardCoefficient = 0.2f;
		val7.eliteBias = 1f;
		val7.spawnDistanceMultiplier = 1f;
		ConfigureCombatDirector(val6.AddComponent<CombatDirector>(), 2.3f, 4.3f);
		ConfigureCombatDirector(val6.AddComponent<CombatDirector>(), 22f, 30f);
		Child(val, "GameManager").AddComponent<GlobalEventManager>();
		Vector3 entryOrigin = content.Navigation.spawnPoints[0].Vector;
		IOrderedEnumerable<GraphNode> orderedEnumerable = content.Navigation.ground.Where((GraphNode node) => (node.flags & 1) != 0 && (node.flags & 4) == 0 && (node.forbiddenHulls & 2) == 0 && content.Navigation.teleporterPoints.All((Point point) => Vector3.Distance(node.Vector, point.Vector) >= 45f)).OrderBy(delegate(GraphNode node)
		{
			//IL_0001: 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)
			//IL_000c: 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)
			Vector3 val8 = node.Vector - entryOrigin;
			return ((Vector3)(ref val8)).sqrMagnitude;
		});
		List<GraphNode> list = new List<GraphNode>();
		foreach (GraphNode candidate in orderedEnumerable)
		{
			if (!list.Any((GraphNode node) => Vector3.Distance(node.Vector, candidate.Vector) < 6f))
			{
				list.Add(candidate);
				if (list.Count >= RoR2Application.maxPlayers)
				{
					break;
				}
			}
		}
		if (list.Count < RoR2Application.maxPlayers)
		{
			throw new InvalidOperationException("Tel Aviv has insufficient clear entry nodes away from teleporter plazas.");
		}
		foreach (GraphNode item in list)
		{
			GameObject obj2 = Child(val, "PlayerSpawn");
			obj2.transform.position = item.Vector + Vector3.up * 0.15f;
			obj2.AddComponent<SpawnPoint>();
		}
		Vector3 vector = content.Navigation.boundsMin.Vector;
		Vector3 vector2 = content.Navigation.boundsMax.Vector;
		GameObject obj3 = Child(val, "MapBounds");
		obj3.layer = LayerIndex.defaultLayer.intVal;
		BoxCollider obj4 = obj3.AddComponent<BoxCollider>();
		((Collider)obj4).isTrigger = true;
		obj4.center = (vector + vector2) * 0.5f;
		obj4.size = vector2 - vector;
		MapZone obj5 = obj3.AddComponent<MapZone>();
		obj5.triggerType = (TriggerType)0;
		obj5.zoneType = (ZoneType)0;
		TelAvivSceneMonitor telAvivSceneMonitor = val.AddComponent<TelAvivSceneMonitor>();
		telAvivSceneMonitor.Log = log;
		((Behaviour)telAvivSceneMonitor).enabled = false;
		TelAvivDirectorActivation telAvivDirectorActivation = val.AddComponent<TelAvivDirectorActivation>();
		telAvivDirectorActivation.Log = log;
		telAvivDirectorActivation.Director = val7;
		telAvivDirectorActivation.CombatDirectors = val6.GetComponents<CombatDirector>();
		telAvivDirectorActivation.Monitor = telAvivSceneMonitor;
		val.SetActive(true);
		typeof(ClassicStageInfo).GetMethod("RebuildCards", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(val5, new object[2]);
		Object.Destroy((Object)(object)val2);
		Object.Destroy((Object)(object)val3);
		log.LogInfo((object)$"TELAVIV_BOOTSTRAP scene={((Scene)(ref scene)).name} server={NetworkServer.active} ground={val4.groundNodes.GetNodeCount()} air={val4.airNodes.GetNodeCount()} director=ready");
	}

	private static void ConfigureCombatDirector(CombatDirector director, float minReroll, float maxReroll)
	{
		//IL_003a: 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_0059: 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_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: 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_00cd: Expected O, but got Unknown
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Expected O, but got Unknown
		((Behaviour)director).enabled = false;
		director.customName = ((minReroll < 10f) ? "Tel Aviv fast waves" : "Tel Aviv slow waves");
		director.minRerollSpawnInterval = minReroll;
		director.maxRerollSpawnInterval = maxReroll;
		director.moneyWaveIntervals = (RangeFloat[])(object)new RangeFloat[2]
		{
			new RangeFloat
			{
				min = 0.5f,
				max = 0.5f
			},
			new RangeFloat
			{
				min = 3f,
				max = 4f
			}
		};
		director.creditMultiplier = 0.75f;
		director.expRewardCoefficient = 0.2f;
		director.goldRewardCoefficient = 1f;
		director.spawnDistanceMultiplier = 1f;
		director.maxSpawnDistance = 120f;
		director.onSpawnedServer = new OnSpawnedServer();
		director.onSpawnedWithDirectorServer = new OnSpawnedWithDirectorServer();
	}

	private static GameObject Child(GameObject parent, string name)
	{
		//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_0019: Expected O, but got Unknown
		GameObject val = new GameObject(name);
		val.transform.SetParent(parent.transform, false);
		return val;
	}

	private static NodeGraph BuildGraph(GraphNode[] data, string name, Transform parent)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: 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_0094: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Expected O, but got Unknown
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0186: Unknown result type (might be due to invalid IL or missing references)
		NodeGraph val = ScriptableObject.CreateInstance<NodeGraph>();
		((Object)val).name = name;
		GameObject val2 = new GameObject(name + ".Source");
		val2.transform.SetParent(parent, false);
		List<MapNode> list = new List<MapNode>(data.Length);
		List<SerializableBitArray> list2 = new List<SerializableBitArray>(data.Length);
		for (int i = 0; i < data.Length; i++)
		{
			GameObject val3 = new GameObject("Node" + i);
			val3.transform.SetParent(val2.transform, false);
			val3.transform.position = data[i].Vector;
			MapNode val4 = val3.AddComponent<MapNode>();
			val4.flags = (NodeFlags)(byte)data[i].flags;
			val4.forbiddenHulls = (HullMask)data[i].forbiddenHulls;
			list.Add(val4);
			SerializableBitArray val5 = new SerializableBitArray(data.Length);
			int[] visible = data[i].visible;
			foreach (int num in visible)
			{
				val5[num] = true;
			}
			list2.Add(val5);
		}
		for (int k = 0; k < data.Length; k++)
		{
			GraphLink[] links = data[k].links;
			foreach (GraphLink graphLink in links)
			{
				list[k].links.Add(new Link
				{
					nodeB = list[graphLink.index],
					distanceScore = graphLink.distance,
					hullMask = graphLink.hullMask,
					jumpHullMask = 0,
					minJumpHeight = 0f,
					gateName = ""
				});
			}
		}
		val.SetNodes(list.AsReadOnly(), list2.AsReadOnly());
		Object.Destroy((Object)(object)val2);
		return val;
	}
}
internal sealed class TelAvivDirectorActivation : MonoBehaviour
{
	internal ManualLogSource Log;

	internal SceneDirector Director;

	internal CombatDirector[] CombatDirectors;

	internal TelAvivSceneMonitor Monitor;

	private IEnumerator Start()
	{
		float deadline = Time.realtimeSinceStartup + 60f;
		while ((!Object.op_Implicit((Object)(object)Stage.instance) || !Object.op_Implicit((Object)(object)Stage.instance.sceneDef) || Stage.instance.sceneDef.cachedName != "telaviv_city" || Stage.instance.entryDifficultyCoefficient <= 0f) && Time.realtimeSinceStartup < deadline)
		{
			yield return null;
		}
		if (!Object.op_Implicit((Object)(object)Stage.instance) || !Object.op_Implicit((Object)(object)Stage.instance.sceneDef) || Stage.instance.sceneDef.cachedName != "telaviv_city" || Stage.instance.entryDifficultyCoefficient <= 0f)
		{
			Log.LogError((object)"TELAVIV_VALIDATION_FAILED: vanilla network Stage initialization timed out; population was not started.");
			yield break;
		}
		CombatDirector[] combatDirectors = CombatDirectors;
		for (int i = 0; i < combatDirectors.Length; i++)
		{
			((Behaviour)combatDirectors[i]).enabled = true;
		}
		((Behaviour)Director).enabled = true;
		((Behaviour)Monitor).enabled = true;
		Log.LogInfo((object)$"TELAVIV_STAGE_READY difficulty={Stage.instance.entryDifficultyCoefficient} entryPoints={SpawnPoint.readOnlyInstancesList.Count}; scene population enabled");
	}
}
internal sealed class TelAvivSceneMonitor : MonoBehaviour
{
	internal ManualLogSource Log;

	private float remaining = 3f;

	private void Update()
	{
		//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)
		remaining -= Time.unscaledDeltaTime;
		if (remaining > 0f)
		{
			return;
		}
		((Behaviour)this).enabled = false;
		if (NetworkServer.active)
		{
			TeleporterInteraction instance = TeleporterInteraction.instance;
			Log.LogInfo((object)string.Format("TELAVIV_POPULATED teleporter={0} combatDirectors={1} interactables={2} monsters={3}", Object.op_Implicit((Object)(object)instance) ? ((object)((Component)instance).transform.position/*cast due to .constrained prefix*/).ToString() : "MISSING", CombatDirector.instancesList.Count, Object.FindObjectsOfType<PurchaseInteraction>().Length, TeamComponent.GetTeamMembers((TeamIndex)2).Count));
			if (!Object.op_Implicit((Object)(object)instance))
			{
				Log.LogError((object)"TELAVIV_VALIDATION_FAILED: no teleporter was spawned.");
			}
		}
	}
}
internal sealed class TelAvivSmokeTest : MonoBehaviour
{
	private sealed class SurveyCamera : MonoBehaviour, ICameraStateProvider
	{
		internal Vector3 Position;

		internal Vector3 Target;

		public void GetCameraState(CameraRigController rig, ref CameraState state)
		{
			//IL_0002: 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)
			//IL_000e: 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_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_0023: Unknown result type (might be due to invalid IL or missing references)
			state.position = Position;
			state.rotation = Quaternion.LookRotation(Target - Position);
			state.fov = 68f;
		}

		public bool IsUserLookAllowed(CameraRigController rig)
		{
			return false;
		}

		public bool IsUserControlAllowed(CameraRigController rig)
		{
			return false;
		}

		public bool IsHudAllowed(CameraRigController rig)
		{
			return true;
		}
	}

	internal ManualLogSource Log;

	internal string OutputDirectory;

	private bool initialSceneSelected;

	private bool overrideCleared;

	private bool roofProbesPassed;

	private void OnRunStarted(Run run)
	{
		Run.onRunStartGlobal -= OnRunStarted;
		initialSceneSelected = Object.op_Implicit((Object)(object)run.nextStageScene) && run.nextStageScene.cachedName == "telaviv_city";
		object? obj = typeof(Run).GetField("cvRunSceneOverride", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null);
		StringConVar val = (StringConVar)((obj is StringConVar) ? obj : null);
		if (val != null)
		{
			((BaseConVar)val).SetString(string.Empty);
			overrideCleared = ((BaseConVar)val).GetString() == string.Empty;
		}
		Console.instance.SubmitCmd((NetworkUser)null, "run_prevent_gameover 1", false);
		Log.LogInfo((object)$"TELAVIV_SMOKE_INITIAL_SELECTION selected={initialSceneSelected} overrideCleared={overrideCleared}");
	}

	private void OnDestroy()
	{
		Run.onRunStartGlobal -= OnRunStarted;
	}

	private IEnumerator Start()
	{
		float deadline = Time.realtimeSinceStartup + 180f;
		while ((!RoR2Application.loadFinished || !Object.op_Implicit((Object)(object)Console.instance)) && Time.realtimeSinceStartup < deadline)
		{
			yield return null;
		}
		if (!RoR2Application.loadFinished)
		{
			Log.LogError((object)"TELAVIV_SMOKE_FAILED: application startup timeout");
			yield break;
		}
		yield return (object)new WaitForSecondsRealtime(3f);
		Log.LogInfo((object)"TELAVIV_SMOKE: starting a non-listening local test session");
		Console.instance.SubmitCmd((NetworkUser)null, "gamemode ClassicRun; host 0", false);
		deadline = Time.realtimeSinceStartup + 60f;
		while ((!NetworkServer.active || !Object.op_Implicit((Object)(object)PreGameController.instance)) && Time.realtimeSinceStartup < deadline)
		{
			yield return null;
		}
		if (!Object.op_Implicit((Object)(object)PreGameController.instance))
		{
			Log.LogError((object)"TELAVIV_SMOKE_FAILED: local pregame timeout");
			yield break;
		}
		GameFields.Set(CheatsConVar.instance, "_boolValue", true);
		((BaseConVar)CheatsConVar.instance).SetString("1");
		Run.onRunStartGlobal += OnRunStarted;
		Console.instance.SubmitCmd((NetworkUser)null, "run_scene_override telaviv_city; pregame_start_run", false);
		deadline = Time.realtimeSinceStartup + 90f;
		Scene scene;
		while (true)
		{
			if (Object.op_Implicit((Object)(object)SceneInfo.instance))
			{
				scene = ((Component)SceneInfo.instance).gameObject.scene;
				if (!(((Scene)(ref scene)).name != "telaviv_city"))
				{
					break;
				}
			}
			if (!(Time.realtimeSinceStartup < deadline))
			{
				break;
			}
			yield return null;
		}
		if (Object.op_Implicit((Object)(object)SceneInfo.instance))
		{
			scene = ((Component)SceneInfo.instance).gameObject.scene;
			if (!(((Scene)(ref scene)).name != "telaviv_city"))
			{
				if (Object.op_Implicit((Object)(object)Run.instance))
				{
					Console.instance.SubmitCmd((NetworkUser)null, "run_prevent_gameover 1", false);
				}
				yield return (object)new WaitForSecondsRealtime(8f);
				SceneDef def = SceneInfo.instance.sceneDef;
				NodeGraph groundNodes = SceneInfo.instance.groundNodes;
				int groundCount = ((groundNodes != null) ? groundNodes.GetNodeCount() : 0);
				NodeGraph airNodes = SceneInfo.instance.airNodes;
				int airCount = ((airNodes != null) ? airNodes.GetNodeCount() : 0);
				SceneDef next = Run.instance?.nextStageScene;
				bool stageReady = Object.op_Implicit((Object)(object)Stage.instance) && (Object)(object)Stage.instance.sceneDef == (Object)(object)def && Stage.instance.entryDifficultyCoefficient > 0f;
				bool flag = false;
				if (Object.op_Implicit((Object)(object)def) && Object.op_Implicit((Object)(object)def.destinationsGroup) && Object.op_Implicit((Object)(object)next))
				{
					Enumerator<SceneEntry> enumerator = def.destinationsGroup.sceneEntries.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							SceneEntry current = enumerator.Current;
							if ((Object)(object)current.sceneDef == (Object)(object)next || (Object)(object)current.fallbackSceneDef == (Object)(object)next)
							{
								flag = true;
							}
						}
					}
					finally
					{
						((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
				}
				bool validNextStage = Object.op_Implicit((Object)(object)def) && Object.op_Implicit((Object)(object)next) && (Object)(object)next != (Object)(object)def && (int)next.sceneType == 1 && next.stageOrder == def.stageOrder + 1 && flag;
				LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
				CharacterBody body = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null);
				if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.currentVehicle))
				{
					body.currentVehicle.EjectPassenger();
					yield return (object)new WaitForSecondsRealtime(1f);
				}
				Log.LogInfo((object)(Object.op_Implicit((Object)(object)body) ? ("TELAVIV_SMOKE_PLAYER body=" + ((Object)body).name) : "TELAVIV_SMOKE_NO_LOCAL_PLAYER: screenshot records the current camera; this is not a player gameplay capture."));
				string screenshotPath = Path.Combine(OutputDirectory, "smoke-telaviv.png");
				bool screenshotRequested = false;
				try
				{
					if (File.Exists(screenshotPath))
					{
						File.Delete(screenshotPath);
					}
					ScreenCapture.CaptureScreenshot(screenshotPath);
					screenshotRequested = true;
				}
				catch (Exception ex)
				{
					Log.LogError((object)("TELAVIV_SMOKE_SCREENSHOT_FAILED: " + ex.Message));
				}
				if (screenshotRequested)
				{
					yield return (object)new WaitForEndOfFrame();
					yield return null;
					deadline = Time.realtimeSinceStartup + 10f;
					while (!ScreenshotExists(screenshotPath) && Time.realtimeSinceStartup < deadline)
					{
						yield return null;
					}
				}
				bool screenshotWritten = screenshotRequested && ScreenshotExists(screenshotPath);
				Log.LogInfo((object)$"TELAVIV_SMOKE_SCREENSHOT written={screenshotWritten} localPlayer={Object.op_Implicit((Object)(object)body)} path={screenshotPath}");
				if (Object.op_Implicit((Object)(object)body))
				{
					yield return RoofProbes(body);
				}
				object[] obj = new object[12]
				{
					groundCount,
					airCount,
					stageReady,
					Object.op_Implicit((Object)(object)TeleporterInteraction.instance),
					Object.op_Implicit((Object)(object)def) && def.hasAnyDestinations,
					null,
					null,
					null,
					null,
					null,
					null,
					null
				};
				obj[5] = ((next != null) ? next.cachedName : null);
				obj[6] = next?.stageOrder;
				obj[7] = validNextStage;
				obj[8] = overrideCleared;
				obj[9] = (Object)(object)DirectorCore.instance != (Object)null;
				obj[10] = screenshotWritten;
				obj[11] = Object.op_Implicit((Object)(object)body);
				string text = string.Format("ground={0} air={1} stageReady={2} teleporter={3} progression={4} next={5} nextOrder={6} validNext={7} overrideCleared={8} director={9} screenshot={10} localPlayer={11}; teleporter charging and stage exit were not exercised", obj);
				text += $"; roofStandingProbes={roofProbesPassed}";
				if (initialSceneSelected && overrideCleared && stageReady && groundCount > 0 && airCount > 0 && Object.op_Implicit((Object)(object)TeleporterInteraction.instance) && validNextStage && Object.op_Implicit((Object)(object)DirectorCore.instance) && screenshotWritten && roofProbesPassed)
				{
					Log.LogInfo((object)("TELAVIV_SMOKE_COMPLETE: " + text));
				}
				else
				{
					Log.LogError((object)("TELAVIV_SMOKE_FAILED: " + text));
				}
				yield break;
			}
		}
		Log.LogError((object)"TELAVIV_SMOKE_FAILED: stage load timeout");
	}

	private IEnumerator RoofProbes(CharacterBody body)
	{
		Vector3[] positions = (Vector3[])(object)new Vector3[11]
		{
			new Vector3(100f, 20f, -27f),
			new Vector3(-142f, 16.46f, 32f),
			new Vector3(158f, 32f, 155f),
			new Vector3(53f, 0f, -59f),
			new Vector3(-64.5f, 0.41f, 55f),
			new Vector3(-99f, 0f, -160f),
			new Vector3(102f, 0f, -123f),
			new Vector3(-118f, 0f, -48f),
			new Vector3(96f, 4f, 56f),
			new Vector3(-60f, 5.8f, 165f),
			new Vector3(-52.5f, 0f, -174f)
		};
		string[] names = new string[11]
		{
			"market-roof", "white-city-roof", "azrieli-lookout", "jasmino", "hakosem", "levinsky", "abulafia", "abuhassan", "miznon", "anita",
			"puaa"
		};
		Vector3[] views = (Vector3[])(object)new Vector3[11]
		{
			new Vector3(85f, 26f, -42f),
			new Vector3(-161f, 23f, 12f),
			new Vector3(165f, 38f, 163f),
			new Vector3(62f, 6f, -48f),
			new Vector3(-69f, 4.5f, 43f),
			new Vector3(-94f, 3.8f, -165f),
			new Vector3(102f, 5.8f, -133f),
			new Vector3(-118f, 4f, -59f),
			new Vector3(96f, 8.5f, 43f),
			new Vector3(-62f, 8.6f, 156f),
			new Vector3(-48f, 4f, -186f)
		};
		Vector3[] targets = (Vector3[])(object)new Vector3[11]
		{
			new Vector3(132f, 20f, 65f),
			new Vector3(-110f, 16f, 30f),
			new Vector3(80f, 12f, 45f),
			new Vector3(52.5f, 3.4f, -73f),
			new Vector3(-64.5f, 3.2f, 64f),
			new Vector3(-99f, 2.5f, -151f),
			new Vector3(102f, 4.5f, -112f),
			new Vector3(-118f, 2.4f, -40f),
			new Vector3(96f, 6.8f, 62f),
			new Vector3(-60f, 8.6f, 173f),
			new Vector3(-52.5f, 2.8f, -167f)
		};
		CameraRigController rig = null;
		foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
		{
			if (Object.op_Implicit((Object)(object)readOnlyInstances) && readOnlyInstances.localUserViewer != null)
			{
				rig = readOnlyInstances;
				break;
			}
		}
		SurveyCamera survey = new GameObject("Tel Aviv diagnostic camera").AddComponent<SurveyCamera>();
		bool previousGod = body.healthComponent.godMode;
		Vector3 start = body.footPosition;
		body.healthComponent.godMode = true;
		roofProbesPassed = true;
		for (int i = 0; i < positions.Length; i++)
		{
			TeleportHelper.TeleportBody(body, positions[i] + Vector3.up * 2f, true);
			survey.Position = views[i];
			survey.Target = targets[i];
			if (Object.op_Implicit((Object)(object)rig))
			{
				rig.SetOverrideCam((ICameraStateProvider)(object)survey, 0f);
			}
			yield return (object)new WaitForSecondsRealtime(2f);
			Vector3 footPosition = body.footPosition;
			bool flag = Mathf.Abs(footPosition.y - positions[i].y) < 0.8f && Vector3.Distance(new Vector3(footPosition.x, positions[i].y, footPosition.z), positions[i]) < 2f;
			roofProbesPassed &= flag;
			Log.LogInfo((object)$"TELAVIV_ROOF_PROBE {names[i]} supported={flag} feet={footPosition} expected={positions[i]}");
			string path = Path.Combine(OutputDirectory, "smoke-view-" + names[i] + ".png");
			if (File.Exists(path))
			{
				File.Delete(path);
			}
			ScreenCapture.CaptureScreenshot(path);
			yield return (object)new WaitForEndOfFrame();
			yield return null;
			float deadline = Time.realtimeSinceStartup + 5f;
			while (!ScreenshotExists(path) && Time.realtimeSinceStartup < deadline)
			{
				yield return null;
			}
			roofProbesPassed &= ScreenshotExists(path);
		}
		if (Object.op_Implicit((Object)(object)rig))
		{
			rig.SetOverrideCam((ICameraStateProvider)null, 0f);
		}
		Object.Destroy((Object)(object)((Component)survey).gameObject);
		TeleportHelper.TeleportBody(body, start + Vector3.up * 2f, true);
		body.healthComponent.godMode = previousGod;
	}

	private static bool ScreenshotExists(string path)
	{
		try
		{
			return File.Exists(path) && new FileInfo(path).Length > 0;
		}
		catch (IOException)
		{
			return false;
		}
	}
}