Decompiled source of EndingPortalsAfterStages v1.1.1

plugins/EndingPortalsAfterStages/EndingPortalsAfterStages.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG;
using Microsoft.CodeAnalysis;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
using RoR2.ExpansionManagement;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("EndingPortalsAfterStages")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("EndingPortalsAfterStages")]
[assembly: AssemblyTitle("EndingPortalsAfterStages")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace EndingPortalsAfterStages
{
	public enum GreenPortalStage
	{
		Stage3,
		Stage4,
		Stage5,
		Stage8,
		Stage9,
		Stage10
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.fafnir62.EndingPortalsAfterStages", "Ending Portals After Stages", "1.1.1")]
	public sealed class EndingPortalsAfterStagesPlugin : BaseUnityPlugin
	{
		private enum PortalKind
		{
			Celestial,
			Colossus,
			SolusWing
		}

		private sealed class PortalRoute
		{
			public readonly PortalKind Kind;

			public readonly string DisplayName;

			public readonly string SpawnCardAddress;

			public readonly string OpenMessageToken;

			public readonly string ExpansionAddress;

			public readonly ConfigEntry<bool> Enabled;

			public readonly ConfigEntry<int> Stage;

			public readonly ConfigEntry<GreenPortalStage> GreenStage;

			public bool AttemptedThisRun;

			public bool AssetLoadAttempted;

			public bool AssetsLoaded;

			public InteractableSpawnCard SpawnCard;

			public ExpansionDef RequiredExpansion;

			public int StageNumber
			{
				get
				{
					if (GreenStage == null)
					{
						return Stage.Value;
					}
					return GreenStage.Value switch
					{
						GreenPortalStage.Stage3 => 3, 
						GreenPortalStage.Stage4 => 4, 
						GreenPortalStage.Stage5 => 5, 
						GreenPortalStage.Stage8 => 8, 
						GreenPortalStage.Stage9 => 9, 
						GreenPortalStage.Stage10 => 10, 
						_ => 5, 
					};
				}
			}

			public PortalRoute(PortalKind kind, string displayName, string spawnCardAddress, string openMessageToken, string expansionAddress, ConfigEntry<bool> enabled, ConfigEntry<int> stage, ConfigEntry<GreenPortalStage> greenStage)
			{
				Kind = kind;
				DisplayName = displayName;
				SpawnCardAddress = spawnCardAddress;
				OpenMessageToken = openMessageToken;
				ExpansionAddress = expansionAddress;
				Enabled = enabled;
				Stage = stage;
				GreenStage = greenStage;
			}
		}

		public const string PluginGuid = "com.fafnir62.EndingPortalsAfterStages";

		public const string PluginName = "Ending Portals After Stages";

		public const string PluginVersion = "1.1.1";

		private const string RiskOfOptionsPluginGuid = "com.rune580.riskofoptions";

		private const string CelestialPortalAddress = "RoR2/Base/PortalMS/iscMSPortal.asset";

		private const string ColossusPortalAddress = "RoR2/DLC2/iscColossusPortal.asset";

		private const string SolusWingPortalAddress = "RoR2/DLC3/iscHardwareProgPortal_Haunt.asset";

		private const string Dlc2ExpansionAddress = "RoR2/DLC2/Common/DLC2.asset";

		private const string Dlc3ExpansionAddress = "RoR2/DLC3/DLC3.asset";

		private static readonly BindingFlags MemberFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly PropertyInfo PortalSpawnCardProperty = typeof(PortalSpawner).GetProperty("PortalSpawnCard", MemberFlags);

		private static readonly FieldInfo PortalSpawnCardField = typeof(PortalSpawner).GetField("portalSpawnCard", MemberFlags);

		private static readonly PropertyInfo PortalWillSpawnProperty = typeof(PortalSpawner).GetProperty("WillSpawn", MemberFlags);

		private static readonly PropertyInfo HiddenRealmPortalProperty = typeof(TeleporterInteraction).GetProperty("shouldAttemptToSpawnHiddenRealmsPortal", MemberFlags);

		private readonly List<PortalRoute> portalRoutes = new List<PortalRoute>();

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

		private ManualLogSource log;

		private bool digitalJourneyActive;

		private SceneDef digitalContinuationScene;

		private void Awake()
		{
			log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			RegisterRiskOfOptions();
			Run.onRunStartGlobal += OnRunStart;
			Run.onRunDestroyGlobal += OnRunDestroy;
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
			SceneExitController.onBeginExit += OnSceneExitBegin;
			Stage.onServerStageBegin += OnServerStageBegin;
			log.LogInfo((object)"Ending Portals After Stages 1.1.1 loaded.");
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance) && Object.op_Implicit((Object)(object)TeleporterInteraction.instance))
			{
				PreparePortalPreviews(TeleporterInteraction.instance, Run.instance);
			}
		}

		private void OnDestroy()
		{
			Run.onRunStartGlobal -= OnRunStart;
			Run.onRunDestroyGlobal -= OnRunDestroy;
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
			SceneExitController.onBeginExit -= OnSceneExitBegin;
			Stage.onServerStageBegin -= OnServerStageBegin;
		}

		private void BindConfig()
		{
			portalRoutes.Add(CreateRoute(PortalKind.Celestial, "1 - Twisted Scavenger (Celestial Portal)", "Celestial Portal", "RoR2/Base/PortalMS/iscMSPortal.asset", "PORTAL_MS_OPEN", null, enabledByDefault: true, 5));
			portalRoutes.Add(CreateRoute(PortalKind.Colossus, "2 - False Son (Green Portal)", "Green Portal", "RoR2/DLC2/iscColossusPortal.asset", "PORTAL_STORM_OPEN", "RoR2/DLC2/Common/DLC2.asset", enabledByDefault: true, 5));
			portalRoutes.Add(CreateRoute(PortalKind.SolusWing, "3 - Solus Wing (Digital Portal)", "Digital Portal", "RoR2/DLC3/iscHardwareProgPortal_Haunt.asset", "PORTAL_SOLUSSHOP_OPEN", "RoR2/DLC3/DLC3.asset", enabledByDefault: false, 5));
			RemoveOldSetting("1 - Twisted Scavenger (Celestial Portal)");
			RemoveOldSetting("2 - False Son (Green Portal)");
			RemoveOldSetting("3 - Solus Wing (Digital Portal)");
			((BaseUnityPlugin)this).Config.Save();
		}

		private void RemoveOldSetting(string section)
		{
			ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>(section, "Spawn Relation", string.Empty, string.Empty);
			((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val).Definition);
		}

		private PortalRoute CreateRoute(PortalKind kind, string section, string displayName, string spawnCardAddress, string openMessageToken, string expansionAddress, bool enabledByDefault, int defaultStage)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			ConfigEntry<bool> enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(section, "Enabled", enabledByDefault, "Adds one scheduled " + displayName + " per run. Vanilla portal appearances are never disabled or moved.");
			ConfigEntry<int> stage = null;
			ConfigEntry<GreenPortalStage> val = null;
			if (kind == PortalKind.Colossus)
			{
				val = ((BaseUnityPlugin)this).Config.Bind<GreenPortalStage>(section, "Stage Number", GreenPortalStage.Stage5, "The portal opens after this numbered stage. Stages 1, 2, 6, and 7 are excluded because the vanilla route sends them through the Path of the Colossus instead of directly to False Son.");
				if (!Enum.IsDefined(typeof(GreenPortalStage), val.Value))
				{
					val.Value = GreenPortalStage.Stage5;
				}
			}
			else
			{
				stage = ((BaseUnityPlugin)this).Config.Bind<int>(section, "Stage Number", defaultStage, new ConfigDescription("The portal opens after this numbered stage's teleporter finishes charging. Hidden realms do not count.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			}
			return new PortalRoute(kind, displayName, spawnCardAddress, openMessageToken, expansionAddress, enabled, stage, val);
		}

		private void RegisterRiskOfOptions()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				log.LogInfo((object)"Risk of Options is not installed; settings remain available in the BepInEx config file.");
				return;
			}
			try
			{
				ModSettingsManager.SetModDescription("Schedule one extra Celestial, Green, and Digital Portal on an exact numbered stage. The game's normal portal appearances remain unchanged.");
				foreach (PortalRoute portalRoute in portalRoutes)
				{
					ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(portalRoute.Enabled, new CheckBoxConfig
					{
						restartRequired = false
					}));
					if (portalRoute.GreenStage != null)
					{
						ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)portalRoute.GreenStage, new ChoiceConfig
						{
							restartRequired = false
						}));
						continue;
					}
					ModSettingsManager.AddOption((BaseOption)new IntSliderOption(portalRoute.Stage, new IntSliderConfig
					{
						min = 1,
						max = 10,
						restartRequired = false
					}));
				}
			}
			catch (Exception arg)
			{
				log.LogWarning((object)$"Could not register the Risk of Options menu: {arg}");
			}
		}

		private void OnRunStart(Run run)
		{
			ResetRunState();
		}

		private void OnRunDestroy(Run run)
		{
			ResetRunState();
		}

		private void ResetRunState()
		{
			foreach (PortalRoute portalRoute in portalRoutes)
			{
				portalRoute.AttemptedThisRun = false;
			}
			digitalPortalExitStages.Clear();
			digitalJourneyActive = false;
			digitalContinuationScene = null;
		}

		private void PreparePortalPreviews(TeleporterInteraction teleporter, Run run)
		{
			int completedStageNumber = run.stageClearCount + 1;
			foreach (PortalRoute portalRoute in portalRoutes)
			{
				if (ShouldAttemptRoute(portalRoute, completedStageNumber) && (portalRoute.Kind != PortalKind.SolusWing || !SolusRouteWasAlreadyUsed(run)) && TryLoadRouteAssets(portalRoute) && (!Object.op_Implicit((Object)(object)portalRoute.RequiredExpansion) || run.IsExpansionEnabled(portalRoute.RequiredExpansion)))
				{
					QueueVanillaPortal(portalRoute, teleporter);
				}
			}
		}

		private static void QueueVanillaPortal(PortalRoute route, TeleporterInteraction teleporter)
		{
			if (route.Kind == PortalKind.Celestial)
			{
				teleporter.shouldAttemptToSpawnMSPortal = true;
				return;
			}
			PortalSpawner[] portalSpawners = teleporter.portalSpawners;
			if (portalSpawners != null)
			{
				PortalSpawner[] array = portalSpawners;
				foreach (PortalSpawner val in array)
				{
					SpawnCard portalSpawnCard = GetPortalSpawnCard(val);
					if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)portalSpawnCard) && string.Equals(((Object)portalSpawnCard).name, ((Object)route.SpawnCard).name, StringComparison.OrdinalIgnoreCase))
					{
						if (PortalWillSpawnProperty != null)
						{
							PortalWillSpawnProperty.SetValue(val, true, null);
						}
						return;
					}
				}
			}
			if (route.Kind == PortalKind.SolusWing)
			{
				HiddenRealmPortalProperty?.SetValue(teleporter, true, null);
			}
		}

		private static SpawnCard GetPortalSpawnCard(PortalSpawner spawner)
		{
			if (!Object.op_Implicit((Object)(object)spawner))
			{
				return null;
			}
			if (PortalSpawnCardProperty != null)
			{
				object? value = PortalSpawnCardProperty.GetValue(spawner, null);
				return (SpawnCard)((value is SpawnCard) ? value : null);
			}
			object? obj = PortalSpawnCardField?.GetValue(spawner);
			return (SpawnCard)((obj is SpawnCard) ? obj : null);
		}

		private void OnTeleporterCharged(TeleporterInteraction teleporter)
		{
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)teleporter) || !Object.op_Implicit((Object)(object)Run.instance))
			{
				return;
			}
			Run instance = Run.instance;
			int num = instance.stageClearCount + 1;
			foreach (PortalRoute portalRoute in portalRoutes)
			{
				if (!ShouldAttemptRoute(portalRoute, num))
				{
					continue;
				}
				portalRoute.AttemptedThisRun = true;
				if (portalRoute.Kind == PortalKind.SolusWing && SolusRouteWasAlreadyUsed(instance))
				{
					log.LogInfo((object)("Skipped the scheduled " + portalRoute.DisplayName + ": the Solus route was already entered or completed this run."));
				}
				else
				{
					if (!TryLoadRouteAssets(portalRoute))
					{
						continue;
					}
					if (Object.op_Implicit((Object)(object)portalRoute.RequiredExpansion) && !instance.IsExpansionEnabled(portalRoute.RequiredExpansion))
					{
						log.LogInfo((object)("Skipped the scheduled " + portalRoute.DisplayName + ": its expansion is not enabled for this run."));
						continue;
					}
					List<SceneExitController> list = FindExistingPortalExits(portalRoute);
					if (list.Count > 0)
					{
						log.LogInfo((object)$"A {portalRoute.DisplayName} already exists on stage {num}; no duplicate was created.");
						if (portalRoute.Kind == PortalKind.SolusWing)
						{
							RegisterDigitalPortalExits(list, num);
						}
						continue;
					}
					GameObject val = SpawnPortal(portalRoute, teleporter, instance);
					if (!Object.op_Implicit((Object)(object)val))
					{
						log.LogWarning((object)$"Could not find a valid placement for the scheduled {portalRoute.DisplayName} on stage {num}.");
						continue;
					}
					if (!string.IsNullOrEmpty(portalRoute.OpenMessageToken))
					{
						Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
						{
							baseToken = portalRoute.OpenMessageToken
						});
					}
					if (portalRoute.Kind == PortalKind.SolusWing)
					{
						RegisterDigitalPortal(val, num);
					}
					log.LogInfo((object)$"Opened the scheduled {portalRoute.DisplayName} after numbered stage {num}.");
				}
			}
		}

		private static bool ShouldAttemptRoute(PortalRoute route, int completedStageNumber)
		{
			if (!route.Enabled.Value || route.AttemptedThisRun)
			{
				return false;
			}
			return completedStageNumber == route.StageNumber;
		}

		private bool TryLoadRouteAssets(PortalRoute route)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			if (route.AssetsLoaded)
			{
				return Object.op_Implicit((Object)(object)route.SpawnCard);
			}
			if (route.AssetLoadAttempted)
			{
				return false;
			}
			route.AssetLoadAttempted = true;
			try
			{
				route.SpawnCard = Addressables.LoadAssetAsync<InteractableSpawnCard>((object)route.SpawnCardAddress).WaitForCompletion();
				if (!string.IsNullOrEmpty(route.ExpansionAddress))
				{
					route.RequiredExpansion = Addressables.LoadAssetAsync<ExpansionDef>((object)route.ExpansionAddress).WaitForCompletion();
				}
				route.AssetsLoaded = Object.op_Implicit((Object)(object)route.SpawnCard) && (string.IsNullOrEmpty(route.ExpansionAddress) || Object.op_Implicit((Object)(object)route.RequiredExpansion));
				if (!route.AssetsLoaded)
				{
					log.LogError((object)("Failed to load the vanilla assets for " + route.DisplayName + "."));
				}
			}
			catch (Exception arg)
			{
				log.LogError((object)$"Failed to load the vanilla assets for {route.DisplayName}: {arg}");
			}
			return route.AssetsLoaded;
		}

		private static bool SolusRouteWasAlreadyUsed(Run run)
		{
			if (!run.GetEventFlag("HardwarePortalTaken") && !run.GetEventFlag("SolusWingBeaten"))
			{
				return run.GetEventFlag("SolusHeartBeaten");
			}
			return true;
		}

		private static GameObject SpawnPortal(PortalRoute route, TeleporterInteraction teleporter, Run run)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)DirectorCore.instance))
			{
				return null;
			}
			DirectorPlacementRule val = new DirectorPlacementRule
			{
				placementMode = (PlacementMode)1,
				minDistance = 10f,
				maxDistance = 40f,
				position = ((Component)teleporter).transform.position,
				spawnOnTarget = ((Component)teleporter).transform
			};
			DirectorSpawnRequest val2 = new DirectorSpawnRequest((SpawnCard)(object)route.SpawnCard, val, run.stageRng);
			return DirectorCore.instance.TrySpawnObject(val2);
		}

		private static List<SceneExitController> FindExistingPortalExits(PortalRoute route)
		{
			List<SceneExitController> list = new List<SceneExitController>();
			if (!Object.op_Implicit((Object)(object)route.SpawnCard) || !Object.op_Implicit((Object)(object)((SpawnCard)route.SpawnCard).prefab))
			{
				return list;
			}
			string name = ((Object)((SpawnCard)route.SpawnCard).prefab).name;
			SceneExitController[] array = Object.FindObjectsOfType<SceneExitController>();
			foreach (SceneExitController val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && HasNamedAncestor(((Component)val).transform, name))
				{
					list.Add(val);
				}
			}
			return list;
		}

		private static bool HasNamedAncestor(Transform transform, string prefabName)
		{
			Transform val = transform;
			while (Object.op_Implicit((Object)(object)val))
			{
				string name = ((Object)((Component)val).gameObject).name;
				if (name == prefabName || name == prefabName + "(Clone)")
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private void RegisterDigitalPortal(GameObject portal, int completedStageNumber)
		{
			SceneExitController[] componentsInChildren = portal.GetComponentsInChildren<SceneExitController>(true);
			RegisterDigitalPortalExits(componentsInChildren, completedStageNumber);
		}

		private void RegisterDigitalPortalExits(IEnumerable<SceneExitController> exits, int completedStageNumber)
		{
			foreach (SceneExitController exit in exits)
			{
				if (Object.op_Implicit((Object)(object)exit))
				{
					digitalPortalExitStages[((Object)exit).GetInstanceID()] = completedStageNumber;
				}
			}
		}

		private void OnSceneExitBegin(SceneExitController exitController)
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)exitController) && Object.op_Implicit((Object)(object)Run.instance) && digitalPortalExitStages.TryGetValue(((Object)exitController).GetInstanceID(), out var value))
			{
				digitalPortalExitStages.Clear();
				Run instance = Run.instance;
				SceneDef val = instance.nextStageScene;
				if (value % 5 == 0)
				{
					val = SelectLoopStartScene(instance, val);
				}
				if (!Object.op_Implicit((Object)(object)val))
				{
					log.LogWarning((object)"The Digital Portal was entered, but no normal continuation scene could be determined. Vanilla routing will be used.");
					return;
				}
				digitalContinuationScene = val;
				digitalJourneyActive = true;
				instance.nextStageScene = val;
				log.LogInfo((object)("Digital route will return to " + val.cachedName + " after the Collective offer is rejected."));
			}
		}

		private static SceneDef SelectLoopStartScene(Run run, SceneDef currentSelection)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (IsLoopStartScene(currentSelection) && run.CanPickStage(currentSelection))
			{
				return currentSelection;
			}
			WeightedSelection<SceneDef> val = new WeightedSelection<SceneDef>(16);
			Enumerator<SceneDef> enumerator = SceneCatalog.allStageSceneDefs.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					SceneDef current = enumerator.Current;
					if (IsLoopStartScene(current) && run.CanPickStage(current))
					{
						val.AddChoice(current, 1f);
					}
				}
			}
			finally
			{
				((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
			}
			if (val.Count == 0)
			{
				return null;
			}
			return val.Evaluate(run.nextStageRng.nextNormalizedFloat);
		}

		private static bool IsLoopStartScene(SceneDef sceneDef)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			if (!Object.op_Implicit((Object)(object)sceneDef) || sceneDef.stageOrder != 1 || sceneDef.isFinalStage || !sceneDef.validForRandomSelection)
			{
				return false;
			}
			if ((int)sceneDef.sceneType != 1)
			{
				return (int)sceneDef.sceneType == 5;
			}
			return true;
		}

		private void OnServerStageBegin(Stage stage)
		{
			if (NetworkServer.active && digitalJourneyActive && Object.op_Implicit((Object)(object)digitalContinuationScene) && Object.op_Implicit((Object)(object)Run.instance))
			{
				if (SameScene(Object.op_Implicit((Object)(object)stage) ? stage.sceneDef : null, digitalContinuationScene))
				{
					log.LogInfo((object)("Returned from the Digital route to " + digitalContinuationScene.cachedName + "."));
					digitalJourneyActive = false;
					digitalContinuationScene = null;
				}
				else
				{
					Run.instance.nextStageScene = digitalContinuationScene;
				}
			}
		}

		private static bool SameScene(SceneDef first, SceneDef second)
		{
			if ((Object)(object)first == (Object)(object)second)
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)first) && Object.op_Implicit((Object)(object)second))
			{
				return string.Equals(first.baseSceneName, second.baseSceneName, StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}
	}
}