Decompiled source of IShowSeed v1.9.0

IShowSeed.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using IShowSeed;
using IShowSeed.HandleProviders;
using IShowSeed.Prediction;
using IShowSeed.Random;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("IShowSeed")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Seeded runs and seed search with custom leaderboards")]
[assembly: AssemblyFileVersion("1.9.0.0")]
[assembly: AssemblyInformationalVersion("1.9.0+53c499c40b99b4b16543678ac727ccc27466efa8")]
[assembly: AssemblyProduct("IShowSeed")]
[assembly: AssemblyTitle("IShowSeed")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.9.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
internal static class MasterServer
{
	public record LeaderboardEntry(string steamid, int rank, int score, int time, int seed, bool hardmode, bool iron, bool finished);

	internal static HttpClient HttpClient;

	internal static bool Initialized;

	public static async Task InitializeHttpClient()
	{
		HttpClient = new HttpClient();
		HttpClient.Timeout = TimeSpan.FromSeconds(Plugin.TimeoutSeconds.Value);
		string[] uris = new string[3]
		{
			Plugin.LeaderboardUri.Value,
			"http://128.199.54.23:80",
			"http://158.160.65.211:5252"
		};
		string[] array = uris;
		foreach (string uri in array)
		{
			try
			{
				Plugin.Beep.LogInfo((object)("Checking seeded runs leaderboard uri: " + uri));
				HttpClient.BaseAddress = new Uri(uri);
				(await HttpClient.GetAsync("/health")).EnsureSuccessStatusCode();
				Initialized = true;
			}
			catch (Exception)
			{
				Plugin.Beep.LogInfo((object)("Uri `" + uri + "` failed"));
				continue;
			}
			break;
		}
		if (Initialized)
		{
			Plugin.Beep.LogInfo((object)$"Connected to {HttpClient.BaseAddress}");
			Plugin.LeaderboardUri.Value = HttpClient.BaseAddress.ToString();
		}
	}

	public static async Task<List<LeaderboardEntry>> FetchLeaderboards(string gamemode, ScoreType scoreType, int limit = 10, string steamid = "")
	{
		//IL_0019: 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)
		if (!Initialized)
		{
			return new List<LeaderboardEntry>();
		}
		string endpoint = string.Format($"getstats?gamemode={gamemode}&limit={limit}&sortby={scoreType}&steamid={steamid}");
		Plugin.Beep.LogWarning((object)("Fetching Leaderboards: " + endpoint));
		using HttpResponseMessage response = await HttpClient.GetAsync(endpoint);
		if (!response.IsSuccessStatusCode)
		{
			Plugin.Beep.LogError((object)response);
			response.EnsureSuccessStatusCode();
		}
		return JsonConvert.DeserializeObject<List<LeaderboardEntry>>(await response.Content.ReadAsStringAsync());
	}

	public static async void UploadScore(string gamemode, int seed, float score, float time, bool iron, bool hardmode, bool finished)
	{
		if (!Initialized)
		{
			return;
		}
		Plugin.Beep.LogWarning((object)$"Uploading run info: gamemode={gamemode}, seed={seed}, score={score}, time={time}, iron={iron}, hardmode={hardmode}, finished={finished}");
		using StringContent jsonContent = new StringContent(JsonConvert.SerializeObject((object)new Dictionary<string, object>
		{
			{ "gamemode", gamemode },
			{
				"steamid",
				SteamClient.SteamId.Value.ToString()
			},
			{ "seed", seed },
			{
				"time",
				Mathf.FloorToInt(Mathf.Clamp(time, 0f, 2.1474836E+09f))
			},
			{
				"score",
				Mathf.FloorToInt(Mathf.Clamp(score, 0f, 2.1474836E+09f))
			},
			{ "iron", iron },
			{ "hardmode", hardmode },
			{ "finished", finished }
		}, (Formatting)0), Encoding.UTF8, "application/json");
		using HttpResponseMessage response = await HttpClient.PostAsync("uploadscore", jsonContent);
		if (!response.IsSuccessStatusCode)
		{
			Plugin.Beep.LogError((object)response);
			response.EnsureSuccessStatusCode();
		}
	}
}
namespace System.Runtime.CompilerServices
{
	internal static class IsExternalInit
	{
	}
}
namespace IShowSeed
{
	public static class Helpers
	{
		public static readonly FieldRef<CL_AssetManager, List<WKDatabaseHolder>> databasesRef = (FieldRef<CL_AssetManager, List<WKDatabaseHolder>>)(object)AccessTools.FieldRefAccess<List<WKDatabaseHolder>>(typeof(CL_AssetManager), "databases");

		internal static List<string> BaseGamemodes = new List<string>(8) { "Campaign", "Endless Superstructure", "Endless Substructure", "Endless Underworks", "Endless Silos", "Endless Pipeworks", "Endless Habitation", "Endless Abyss" };

		public static string LevelOfStr(Transform tr)
		{
			if ((Object)(object)tr == (Object)null)
			{
				return "could_not_get_level_of_" + ((Object)((Component)tr).gameObject).name;
			}
			return ((Component)tr).GetComponentInParent<M_Level>(true).levelName;
		}

		public static M_Level LevelOf(Transform tr)
		{
			if ((Object)(object)tr == (Object)null)
			{
				return null;
			}
			return ((Component)tr).GetComponentInParent<M_Level>(true);
		}

		public static List<Perk> GetAllPerks()
		{
			List<Perk> list = new List<Perk>();
			foreach (WKDatabaseHolder item in databasesRef.Invoke(CL_AssetManager.instance))
			{
				list.AddRange(item.database.perkAssets);
			}
			foreach (Perk item2 in list)
			{
				item2.id = item2.id.ToLower();
			}
			return list;
		}

		internal static void PatchAllWithAttribute<T>(Harmony harmony) where T : Attribute
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			IEnumerable<Type> enumerable = from t in executingAssembly.GetTypes()
				where t.GetCustomAttribute<T>() != null
				select t;
			foreach (Type item in enumerable)
			{
				harmony.PatchAll(item);
			}
		}

		internal static List<string> GetAllGamemodes(bool withOptions)
		{
			List<string> list = new List<string>();
			foreach (string baseGamemode in BaseGamemodes)
			{
				list.Add(baseGamemode);
				if (withOptions)
				{
					list.Add(baseGamemode + "-Hardmode");
					list.Add(baseGamemode + "-Iron");
					list.Add(baseGamemode + "-Hardmode-Iron");
				}
			}
			return list;
		}

		internal static string GetAllGamemodesStr(bool withOptions, string delimiter)
		{
			return string.Join(delimiter, GetAllGamemodes(withOptions));
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class OnlyForSeededRunsPatchAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class PermanentPatchAttribute : Attribute
	{
	}
	public static class Things
	{
		private static readonly Items _items = new Items();

		private static readonly Sprites _sprites = new Sprites();

		public static Handle<Item_Object> Items()
		{
			return _items.Handle();
		}

		public static Handle<Sprite> Sprites()
		{
			return _sprites.Handle();
		}
	}
	public abstract class HandleProvider<T>
	{
		public abstract Func<T, string> Name { get; }

		public virtual Func<T, T> Finalizer { get; } = (T obj) => obj;


		public abstract Handle<T> Handle();
	}
	public class Handle<T>
	{
		private readonly IEnumerable<T> _data;

		private readonly Func<T, string> _nameGetter;

		private readonly Func<T, T> _finalizer;

		public Handle(IEnumerable<T> d, Func<T, string> nameGetter, Func<T, T> finalizer)
		{
			_data = d;
			_nameGetter = (T x) => nameGetter(x)?.ToLower() ?? null;
			_finalizer = finalizer;
			base..ctor();
		}

		public Handle<T> Filter(string filter)
		{
			return new Handle<T>(_data.Where((T x) => _nameGetter(x).Contains(filter.ToLower())), _nameGetter, _finalizer);
		}

		public T Any()
		{
			T val = _data.FirstOrDefault();
			return (val != null) ? _finalizer(val) : default(T);
		}

		public string AnyName()
		{
			return _nameGetter(Any());
		}

		public string[] Names()
		{
			return _data.Select((T x) => _nameGetter(x)).ToArray();
		}

		public string Join(string delimiter = "\n- ")
		{
			return string.Join(delimiter, Names());
		}

		public List<T> ToList()
		{
			return _data.ToList();
		}

		public IEnumerable<T> Data()
		{
			return _data;
		}

		public int Count()
		{
			return _data.Count();
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(Leaderboard_Panel), "UpdateScore")]
	public static class SpawnSettings_UpdateScore_Patcher
	{
		public static bool FilterBySeed = false;

		private static readonly FieldRef<Leaderboard_Panel, List<Leaderboard_Score>> scoreObjectsRef = (FieldRef<Leaderboard_Panel, List<Leaderboard_Score>>)(object)AccessTools.FieldRefAccess<List<Leaderboard_Score>>(typeof(Leaderboard_Panel), "scoreObjects");

		public static bool Prefix(Leaderboard_Panel __instance)
		{
			if (Plugin.IsRandomRun() || !MasterServer.Initialized)
			{
				return true;
			}
			try
			{
				OverrideLeaderboardsAsync(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Beep.LogError((object)"An error occurred when trying to connect to leaderboards server! Make sure you have the latest version of the mod and default URI setting in mod's config");
				Plugin.Beep.LogError((object)ex);
			}
			return false;
		}

		public static async Task OverrideLeaderboardsAsync(Leaderboard_Panel __instance)
		{
			List<Leaderboard_Score> scoreObjects = scoreObjectsRef.Invoke(__instance);
			string leaderboardsName = CL_GameManager.GetGamemodeName(true, false);
			for (int j = 0; j < scoreObjects.Count; j++)
			{
				((Component)scoreObjects[j]).gameObject.SetActive(false);
			}
			List<MasterServer.LeaderboardEntry> lbScores = null;
			if ((int)__instance.defaultType == 0)
			{
				lbScores = await MasterServer.FetchLeaderboards(leaderboardsName, __instance.scoreType, __instance.scoresToPull);
			}
			else if ((int)__instance.defaultType == 1 || (int)__instance.defaultType == 2)
			{
				lbScores = await MasterServer.FetchLeaderboards(leaderboardsName, __instance.scoreType, __instance.scoresToPull, SteamClient.SteamId.Value.ToString());
				List<MasterServer.LeaderboardEntry> list = lbScores;
				List<MasterServer.LeaderboardEntry> list2 = list;
				if (list2 == null)
				{
					List<MasterServer.LeaderboardEntry> list3;
					lbScores = (list3 = await MasterServer.FetchLeaderboards(leaderboardsName, __instance.scoreType, __instance.scoresToPull));
					list2 = list3;
				}
				_ = list2;
			}
			for (int i = 0; i < scoreObjects.Count; i++)
			{
				if (i >= lbScores.Count)
				{
					((Component)scoreObjects[i]).gameObject.SetActive(false);
					continue;
				}
				SteamId steamId = new SteamId
				{
					Value = Convert.ToUInt64(lbScores[i].steamid)
				};
				Friend steamUser = new Friend(steamId);
				((Behaviour)scoreObjects[i].hmIcon).enabled = lbScores[i].hardmode;
				((Behaviour)scoreObjects[i].ikIcon).enabled = lbScores[i].iron;
				((Component)scoreObjects[i]).gameObject.SetActive(true);
				scoreObjects[i].positionText.text = $"<mspace=''>{lbScores[i].rank}</mspace>";
				scoreObjects[i].nameText.text = ((Friend)(ref steamUser)).Name ?? "";
				if ((int)__instance.scoreType == 0)
				{
					scoreObjects[i].scoreText.text = $"{lbScores[i].score}\n<color=grey>seed: {lbScores[i].seed}</color>";
				}
				else
				{
					if ((int)__instance.scoreType != 1)
					{
						Plugin.Beep.LogWarning((object)$"Unsupported scoreType {__instance.scoreType}");
						break;
					}
					TimeSpan timeSpan = TimeSpan.FromSeconds(lbScores[i].time);
					scoreObjects[i].scoreText.text = $"{timeSpan:hh\\:mm\\:ss} <color=grey>seed: {lbScores[i].seed}</color>";
				}
				Texture2D texture = SteamManager.ConvertSteamIcon((await ((Friend)(ref steamUser)).GetMediumAvatarAsync()).Value);
				scoreObjects[i].profile.texture = (Texture)(object)texture;
				if (SteamClient.SteamId.Value == steamId.Value)
				{
					((Graphic)scoreObjects[i].positionText).color = __instance.isMeColor;
					((Graphic)scoreObjects[i].nameText).color = __instance.isMeColor;
					((Graphic)scoreObjects[i].scoreText).color = __instance.isMeColor;
				}
				else
				{
					((Graphic)scoreObjects[i].positionText).color = Color.white;
					((Graphic)scoreObjects[i].nameText).color = Color.white;
					((Graphic)scoreObjects[i].scoreText).color = Color.white;
				}
			}
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(M_Gamemode), "Finish")]
	public static class M_Gamemode_Finish_Patcher
	{
		public static bool Prefix(M_Gamemode __instance, float time, bool hasFinished)
		{
			if (Plugin.IsRandomRun())
			{
				return true;
			}
			__instance.gamemodeModule.OnFinish(hasFinished);
			bool flag = (!__instance.allowCheatedScores && CommandConsole.hasCheated) || (!__instance.allowCheatedScores && !CL_GameManager.AreAchievementsAllowed());
			try
			{
				MasterServer.UploadScore(__instance.GetGamemodeName(true), Plugin.SeedForRandom, flag ? 0f : __instance.GetPlayerScore(hasFinished), time, __instance.IsIronKnuckle(), __instance.allowHardmode && CL_GameManager.IsHardmode(), hasFinished);
			}
			catch (Exception ex)
			{
				Plugin.Beep.LogError((object)"An error occurred when trying to connect to leaderboards server! Make sure you have the latest version of the mod and default URI setting in mod's config");
				Plugin.Beep.LogError((object)ex);
			}
			return false;
		}
	}
	[BepInPlugin("shishyando.WK.IShowSeed", "IShowSeed", "1.9.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static Plugin Instance;

		internal static ManualLogSource Beep;

		internal static Harmony TogglableHarmony = new Harmony("shishyando.WK.IShowSeed.togglable");

		internal static Harmony PermanentHarmony = new Harmony("shishyando.WK.IShowSeed.permanent");

		internal static int SeedForRandom = 0;

		private static bool OnStartupDone = false;

		internal static ConfigEntry<int> ConfigPresetSeed;

		internal static ConfigEntry<bool> PersistBetweenGameRestarts;

		internal static ConfigEntry<string> LeaderboardUri;

		internal static ConfigEntry<int> TimeoutSeconds;

		internal static ConfigEntry<string> EnabledGamemodesStr;

		internal static List<string> EnabledGamemodes;

		internal static ConfigEntry<string> DesiredRouteDescription;

		internal static ConfigEntry<int> SeedSearchIterations;

		internal static ConfigEntry<int> SeedSearchResultsNeeded;

		internal static ConfigEntry<bool> EnableRandomSeedReplayability;

		private void Awake()
		{
			Instance = this;
			Beep = ((BaseUnityPlugin)this).Logger;
			ConfigPresetSeed = ((BaseUnityPlugin)this).Config.Bind<int>("General", "PresetSeed", 0, "Preset seed, `0` to keep the default behaviour");
			PersistBetweenGameRestarts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PersistBetweenGameRestarts", true, "If true, the seed will stay the same even after game restart");
			EnableRandomSeedReplayability = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableRandomSeedReplayability", false, "If true, random-seeded runs can be replayed in a seeded run by entering the seed you had");
			EnabledGamemodesStr = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Gamemodes", Helpers.GetAllGamemodesStr(withOptions: true, "|") ?? "", "Gamemodes which should be affected by IShowSeed, separated by `|`. Available values (can append \"-Hardmode\", \"-Iron\" or \"-Hardmode-Iron\"):\n" + Helpers.GetAllGamemodesStr(withOptions: false, "\n"));
			EnabledGamemodes = EnabledGamemodesStr.Value.Split('|').ToList();
			LeaderboardUri = ((BaseUnityPlugin)this).Config.Bind<string>("Leaderboards", "Uri", "http://128.199.54.23:80", "If you encounter any network problems, make sure you have the latest version of the mod and reset this to default");
			TimeoutSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Leaderboards", "TimeoutSeconds", 10, "If this is not enough, either the server is down or you have network issues");
			DesiredRouteDescription = ((BaseUnityPlugin)this).Config.Bind<string>("SeedSearch", "DesiredRouteDescription", "shortcut_burner: perk_u_t2_conditionedpolyphagia, perk_metabolicstasis, perk_metabolicstasis", "Format: `{route name}: {unstable_perk1}, {perk2}, {perk3}`, available route names: `default`, `shortcut_sink`, `shortcut_burner`");
			SeedSearchIterations = ((BaseUnityPlugin)this).Config.Bind<int>("SeedSearch", "SearchIterations", 0, "How many seed search iterations to run");
			SeedSearchResultsNeeded = ((BaseUnityPlugin)this).Config.Bind<int>("SeedSearch", "SearchResultsCap", 25, "How many seeds with desired route should be found, do not make search range too big or your game will load forever");
			SceneManager.sceneLoaded += OnGameStartup;
			Beep.LogInfo((object)"shishyando.WK.IShowSeed is loaded");
		}

		public void OnGameStartup(Scene scene, LoadSceneMode loadSceneMode)
		{
			if (!(((Scene)(ref scene)).name != "Main-Menu") && !OnStartupDone)
			{
				OnStartupDone = true;
				MasterServer.InitializeHttpClient();
				ClearSeedOnRestartIfNeeded();
				Vanga.DoSeedSearch();
				Helpers.PatchAllWithAttribute<PermanentPatchAttribute>(PermanentHarmony);
			}
		}

		public void ClearSeedOnRestartIfNeeded()
		{
			if (!PersistBetweenGameRestarts.Value)
			{
				ConfigPresetSeed.Value = 0;
				Beep.LogInfo((object)"PersistBetweenGameRestarts is false, clearing the preset seed");
			}
		}

		public static bool IsSeededRun()
		{
			return ConfigPresetSeed.Value != 0;
		}

		public static bool IsRandomRun()
		{
			return ConfigPresetSeed.Value == 0;
		}

		public static bool ShouldEnableRod()
		{
			return (IsSeededRun() || EnableRandomSeedReplayability.Value) && EnabledGamemodes.Contains(CL_GameManager.GetGamemodeName(true, false));
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(string) })]
	public static class SceneManager_LoadScene_Patcher
	{
		public static void Prefix(string sceneName)
		{
			if (sceneName == "Main-Menu")
			{
				Plugin.TogglableHarmony.UnpatchSelf();
				Rod.SwitchToMode(Rod.ERandomMode.Disabled);
			}
			if (!(sceneName == "Game-Main"))
			{
				return;
			}
			if (Plugin.ShouldEnableRod())
			{
				if (Rod.GetMode() == Rod.ERandomMode.Enabled)
				{
					Plugin.Beep.LogInfo((object)"Only resetting random on restart, no double patching");
					Rod.Reset();
				}
				else
				{
					Plugin.Beep.LogInfo((object)"Applying patches for random for the first time");
					Rod.SwitchToMode(Rod.ERandomMode.Enabled);
					Helpers.PatchAllWithAttribute<OnlyForSeededRunsPatchAttribute>(Plugin.TogglableHarmony);
				}
			}
			else
			{
				Plugin.Beep.LogInfo((object)("Gamemode `" + CL_GameManager.GetGamemodeName(true, false) + "` is not enabled in IShowSeed's configs, not doing anything"));
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "shishyando.WK.IShowSeed";

		public const string PLUGIN_NAME = "IShowSeed";

		public const string PLUGIN_VERSION = "1.9.0";
	}
}
namespace IShowSeed.UI
{
	[PermanentPatch]
	[HarmonyPatch(typeof(UT_SeededEnable), "OnEnable")]
	public static class UT_SeededEnable_OnEnable_Patcher
	{
		public static bool Prefix(UT_SeededEnable __instance)
		{
			TextMeshProUGUI component = ((Component)__instance).gameObject.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).text = $"SEED: {Plugin.SeedForRandom}";
			if (Plugin.IsSeededRun())
			{
				((TMP_Text)component).text = "PRESET " + ((TMP_Text)component).text;
			}
			return false;
		}
	}
}
namespace IShowSeed.Random
{
	public static class Rod
	{
		public enum ERandomMode
		{
			Disabled,
			Enabled,
			Prediction
		}

		public struct Context
		{
			public State PrevRandomState;

			public int BaseSeed;

			public bool Valid;

			public uint CallNumber;
		}

		public static ERandomMode Mode = ERandomMode.Disabled;

		private static readonly object _lock = new object();

		private static readonly Dictionary<int, State> _stateBySiteSeed = new Dictionary<int, State>();

		private static readonly Dictionary<int, uint> _cntBySiteSeed = new Dictionary<int, uint>();

		internal static void Enter(ref Context ctx, string customCallSite)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (Mode != 0)
			{
				ctx = default(Context);
				ctx.BaseSeed = DeriveSeed(customCallSite ?? ComputeSiteKey());
				Monitor.Enter(_lock);
				ctx.PrevRandomState = Random.state;
				if (!_stateBySiteSeed.ContainsKey(ctx.BaseSeed))
				{
					Random.InitState(ctx.BaseSeed);
					_stateBySiteSeed[ctx.BaseSeed] = Random.state;
					_cntBySiteSeed[ctx.BaseSeed] = 1u;
					ctx.CallNumber = 1u;
				}
				else
				{
					Random.state = _stateBySiteSeed[ctx.BaseSeed];
					ctx.CallNumber = ++_cntBySiteSeed[ctx.BaseSeed];
				}
				ctx.Valid = true;
			}
		}

		internal static void Exit(in Context ctx)
		{
			//IL_0010: 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_0021: 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)
			if (ctx.Valid)
			{
				State state = Random.state;
				_stateBySiteSeed[ctx.BaseSeed] = state;
				Random.state = ctx.PrevRandomState;
				Monitor.Exit(_lock);
			}
		}

		private static string ComputeSiteKey()
		{
			return GetStackTraceStr(2);
		}

		private static int DeriveSeed(string siteKey)
		{
			return Animator.StringToHash(siteKey) ^ Plugin.SeedForRandom;
		}

		internal static ERandomMode GetMode()
		{
			return Mode;
		}

		internal static void SwitchToMode(ERandomMode mode)
		{
			if (Mode != ERandomMode.Prediction && mode != ERandomMode.Prediction)
			{
				Plugin.Beep.LogInfo((object)$"RandomGod switching to {mode}");
			}
			Monitor.Enter(_lock);
			Mode = mode;
			_stateBySiteSeed.Clear();
			Monitor.Exit(_lock);
		}

		internal static void Reset()
		{
			Plugin.Beep.LogWarning((object)"RandomGod reset");
			Monitor.Enter(_lock);
			_stateBySiteSeed.Clear();
			Monitor.Exit(_lock);
		}

		private static string GetStackTraceStr(int frames)
		{
			StackTrace stackTrace = new StackTrace(frames);
			return string.Join(" ==> ", stackTrace.GetFrames().Select(delegate(StackFrame f)
			{
				MethodBase method = f.GetMethod();
				Type declaringType = method.DeclaringType;
				return (declaringType == null) ? "" : (declaringType.FullName + "." + method.Name);
			}));
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(App_PerkPage), "GenerateCards", new Type[] { typeof(bool) })]
	public static class App_PerkPage_GenerateCards_Patcher
	{
		private static readonly FieldRef<App_PerkPage, OS_Manager> osRef = (FieldRef<App_PerkPage, OS_Manager>)(object)AccessTools.FieldRefAccess<OS_Manager>(typeof(App_PerkPage), "os");

		private static readonly FieldRef<OS_Computer_Interface, int> seedRef = (FieldRef<OS_Computer_Interface, int>)(object)AccessTools.FieldRefAccess<int>(typeof(OS_Computer_Interface), "seed");

		public static void Prefix(ref Rod.Context __state, App_PerkPage __instance, bool refresh)
		{
			Rod.Enter(ref __state, GenerateCustomCallSite(__instance, refresh));
			seedRef.Invoke(osRef.Invoke(__instance).worldInterface) = -1;
		}

		public static void Postfix(ref Rod.Context __state, App_PerkPage __instance)
		{
			seedRef.Invoke(osRef.Invoke(__instance).worldInterface) = (int)(__state.BaseSeed + __state.CallNumber);
			Rod.Exit(in __state);
		}

		private static string GenerateCustomCallSite(App_PerkPage i, bool refresh)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)osRef.Invoke(i).worldInterface).transform;
			return $"perkpage_{i.perkPageType}_{Helpers.LevelOfStr(transform)}_{i.minCards}_{i.maxCards}_{refresh}";
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(CL_EventManager), "GetPossibleEvents")]
	public static class CL_EventManager_GetPossibleEvents_Patcher
	{
		public static void Postfix(ref List<SessionEvent> __result)
		{
			if (Plugin.IsSeededRun())
			{
				__result?.RemoveAll((SessionEvent x) => (int)x.startCheck == 3);
			}
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(ENV_ArtifactDevice), "Start")]
	public static class ENV_ArtifactDevice_Start_Patcher
	{
		public static void Prefix(ref Rod.Context __state)
		{
			Rod.Enter(ref __state, "artifact_device");
		}

		public static void Finalizer(ref Rod.Context __state)
		{
			Rod.Exit(in __state);
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(ENV_VendingMachine), "GenerateOptions")]
	public static class ENV_VendingMachine_GenerateOptions_Patcher
	{
		private static readonly FieldRef<ENV_VendingMachine, int> localSeedRef = AccessTools.FieldRefAccess<ENV_VendingMachine, int>("localSeed");

		public static void Prefix(ref Rod.Context __state, ENV_VendingMachine __instance)
		{
			Rod.Enter(ref __state, GenerateCustomCallSite(__instance));
			localSeedRef.Invoke(__instance) = (int)(__state.BaseSeed + __state.CallNumber);
		}

		public static void Finalizer(ref Rod.Context __state)
		{
			Rod.Exit(in __state);
		}

		private static string GenerateCustomCallSite(ENV_VendingMachine instance)
		{
			return "vendo_" + Helpers.LevelOfStr(((Component)instance).transform) + "_" + ((Object)((Component)instance).gameObject).name;
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(ENV_VendingMachine), "Buy", new Type[]
	{
		typeof(int),
		typeof(bool),
		typeof(bool)
	})]
	public static class ENV_VendingMachine_Buy_Patcher
	{
		private static readonly FieldRef<ENV_VendingMachine, bool> deadRef = AccessTools.FieldRefAccess<ENV_VendingMachine, bool>("dead");

		public static void Prefix(ref Rod.Context __state, ENV_VendingMachine __instance, ref int i, bool force, bool free)
		{
			if (force && free && deadRef.Invoke(__instance))
			{
				Rod.Enter(ref __state, GenerateCustomCallSite(__instance));
				i = Random.Range(0, __instance.buttons.Length);
			}
		}

		public static void Finalizer(ref Rod.Context __state)
		{
			Rod.Exit(in __state);
		}

		private static string GenerateCustomCallSite(ENV_VendingMachine instance)
		{
			return "vendo_" + Helpers.LevelOfStr(((Component)instance).transform) + "_" + ((Object)((Component)instance).gameObject).name + "_dead";
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(ENV_VendingMachine), "SetSeed")]
	public static class ENV_VendingMachine_SetSeed_Patcher
	{
		public static bool Prefix()
		{
			return false;
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(M_Level), "Awake")]
	public static class M_Level_Awake_Patcher
	{
		public static void Prefix(M_Level __instance)
		{
			if (Plugin.IsSeededRun())
			{
				__instance.canFlip = false;
			}
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(OS_Computer_Interface), "SetSeed")]
	public static class OS_Computer_Interface_SetSeed_Patcher
	{
		public static bool Prefix()
		{
			return false;
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(SpawnSettings), "RandomCheck")]
	public static class SpawnSettings_RandomCheck_Patcher
	{
		public static bool Prefix(ref Rod.Context __state, ref bool __result, SpawnSettings __instance)
		{
			float effectiveSpawnChance = __instance.GetEffectiveSpawnChance();
			if (effectiveSpawnChance == 0f)
			{
				__result = false;
				return false;
			}
			if (effectiveSpawnChance == 1f)
			{
				__result = true;
				return false;
			}
			Rod.Enter(ref __state, null);
			return true;
		}

		public static void Finalizer(ref Rod.Context __state)
		{
			Rod.Exit(in __state);
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(UT_SPT_Spawner), "Spawn")]
	public static class UT_SPT_Spawner_Spawn_Patcher
	{
		public static void Prefix(ref Rod.Context __state, UT_SPT_Spawner __instance)
		{
			Rod.Enter(ref __state, GenerateCustomCallSite(__instance));
		}

		public static void Finalizer(ref Rod.Context __state)
		{
			Rod.Exit(in __state);
		}

		private static string GenerateCustomCallSite(UT_SPT_Spawner i)
		{
			return "UT_SPT_" + ((Object)((Component)i).gameObject).name;
		}
	}
	[OnlyForSeededRunsPatch]
	[HarmonyPatch(typeof(WorldLoader), "Awake")]
	public static class WorldLoader_Awake_Patcher
	{
		public static void Prefix()
		{
			WorldLoader.SetPresetSeed(Plugin.ConfigPresetSeed.Value.ToString());
			Plugin.Beep.LogInfo((object)$"custom preset seed: {Plugin.ConfigPresetSeed.Value}");
			Plugin.SeedForRandom = Plugin.ConfigPresetSeed.Value;
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(WorldLoader), "Initialize")]
	public static class WorldLoader_Initialize_Patcher
	{
		public static void Postfix()
		{
			if (Plugin.IsRandomRun())
			{
				Plugin.SeedForRandom = WorldLoader.instance.seed;
			}
		}
	}
}
namespace IShowSeed.Random.UI
{
	[PermanentPatch]
	[HarmonyPatch(typeof(CL_UIManager), "Update")]
	public static class CL_UIManager_Update_Patcher
	{
		public static void Postfix()
		{
			DebugMenu.UpdateDebugText("starting-seed", $"<color=blue>Starting seed: {Plugin.SeedForRandom}</color>");
		}
	}
	[PermanentPatch]
	[HarmonyPatch(typeof(MenuManager), "Start")]
	public static class MenuManager_Start_Patcher
	{
		public static void Postfix(MenuManager __instance)
		{
			PatchSeedWindow(__instance);
			AddSeedWindowButton(__instance);
		}

		private static void AddSeedWindowButton(MenuManager __instance)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			Transform val = ((Component)__instance.menu).transform.Find("Main Menu Buttons/Logbook");
			Transform val2 = Object.Instantiate<Transform>(val, ((Component)val).transform.parent);
			((Object)val2).name = "Seeded runs";
			TextMeshProUGUI component = ((Component)val2.GetChild(0)).GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).text = "seeded runs";
			((Graphic)component).color = Color.grey;
			((TMP_Text)component).fontSize = ((TMP_Text)component).fontSize / 2f;
			Button component2 = ((Component)val2).GetComponent<Button>();
			component2.onClick = new ButtonClickedEvent();
			((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
			{
				__instance.seedWindow.SetActive(!__instance.seedWindow.activeSelf);
			});
		}

		private static void PatchSeedWindow(MenuManager __instance)
		{
			GameObject seedWindow = __instance.seedWindow;
			TextMeshProUGUI component = ((Component)seedWindow.transform.Find("Overview Titles/Title Text")).gameObject.GetComponent<TextMeshProUGUI>();
			TextMeshProUGUI buttonText = ((Component)seedWindow.transform.Find("Tab Selection Hor/Exit/Text (TMP)")).gameObject.GetComponent<TextMeshProUGUI>();
			Button component2 = ((Component)seedWindow.transform.Find("Tab Selection Hor/Exit")).gameObject.GetComponent<Button>();
			TMP_InputField seedPrompt = ((Component)seedWindow.transform.Find("Seed Input")).gameObject.GetComponent<TMP_InputField>();
			TextMeshProUGUI component3 = ((Component)seedWindow.transform.Find("Seed Input/Text Area/Placeholder")).gameObject.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)buttonText == (Object)null || (Object)(object)seedPrompt == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component == (Object)null || (Object)(object)component3 == (Object)null)
			{
				Plugin.Beep.LogWarning((object)$"button: {component2}\nbuttonText: {buttonText}\nseedPrompt: {seedPrompt}\ntitle: {component}\nplaceholder {component3}");
			}
			else
			{
				PatchTitle(component);
				PatchPrompt(seedPrompt, component3);
				PatchButton(component2);
			}
			void PatchButton(Button button)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: Expected O, but got Unknown
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Expected O, but got Unknown
				((Graphic)buttonText).color = Color.grey;
				((TMP_Text)buttonText).text = "Save to Config";
				button.onClick = new ButtonClickedEvent();
				((UnityEvent)button.onClick).AddListener((UnityAction)delegate
				{
					//IL_0093: Unknown result type (might be due to invalid IL or missing references)
					if (int.TryParse(seedPrompt.text, out var result) || seedPrompt.text == "")
					{
						Plugin.ConfigPresetSeed.Value = result;
						((BaseUnityPlugin)Plugin.Instance).Config.Save();
						Plugin.Beep.LogInfo((object)$"Set new seed to {result}");
						seedWindow.SetActive(false);
					}
					else
					{
						((TMP_Text)buttonText).text = "Invalid seed";
						((Graphic)buttonText).color = Color.red;
					}
				});
			}
			void PatchPrompt(TMP_InputField prompt, TextMeshProUGUI placeholder)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Expected O, but got Unknown
				prompt.onValueChanged = new OnChangeEvent();
				((UnityEvent<string>)(object)prompt.onValueChanged).AddListener((UnityAction<string>)delegate
				{
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					((Graphic)buttonText).color = Color.white;
					((TMP_Text)buttonText).text = "Save to Config";
				});
				prompt.text = Plugin.ConfigPresetSeed.Value.ToString();
				if (prompt.text == "0")
				{
					prompt.text = "";
				}
				((TMP_Text)placeholder).text = "KEEP RANDOM";
			}
			static void PatchTitle(TextMeshProUGUI title)
			{
				((TMP_Text)title).text = "ENTER SEED";
			}
		}
	}
}
namespace IShowSeed.Prediction
{
	public struct PredictedPerks
	{
		public List<string> PerkIds;

		public List<string> RefreshedPerkIds;
	}
	public struct PerkMachinePred
	{
		public PerkPageType PerkPageType;

		public string LevelName;

		public PredictedPerks PredictedPerks;

		public PerkMachinePred(PerkPageType type, string levelName, int minCards, int maxCards)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: 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_0007: 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)
			PerkPageType = type;
			LevelName = levelName;
			PredictedPerks = PerkPredictor.Generate(type, levelName, minCards, maxCards);
		}
	}
	public static class PerkPredictor
	{
		private static readonly List<string> _machines = new List<string>(6) { "perkpage_unstable_M1_Silos_SafeArea_01_2_2", "perkpage_regular_Campaign_Interlude_Silo_To_Pipeworks_01_3_3", "perkpage_regular_Campaign_Interlude_Sink_To_Pipeworks_01_2_2", "perkpage_unstable_Campaign_Interlude_Sink_To_Pipeworks_01_2_2", "perkpage_regular_M3_Habitation_Shaft_Intro_3_3", "perkpage_regular_Campaign_Interlude_Chute_To_Habitation_2_2" };

		public static PredictedPerks Generate(PerkPageType perkPageType, string levelName, int minCards, int maxCards)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			Rod.SwitchToMode(Rod.ERandomMode.Prediction);
			bool flag = false;
			PredictedPerks predictedPerks = default(PredictedPerks);
			predictedPerks.PerkIds = new List<string>();
			predictedPerks.RefreshedPerkIds = new List<string>();
			PredictedPerks result = predictedPerks;
			int num = 0;
			while (num <= 1)
			{
				Rod.Context ctx = default(Rod.Context);
				Rod.Enter(ref ctx, $"perkpage_{perkPageType}_{levelName}_{minCards}_{maxCards}_{flag}");
				List<string> source = (((int)perkPageType != 0) ? GenerateInternal(perkPageType, minCards, maxCards, flag, result.PerkIds, new List<string>(1) { "unstable" }) : GenerateInternal(perkPageType, minCards, maxCards, flag, result.PerkIds, new List<string>(1) { "standard" }));
				if (!flag)
				{
					result.PerkIds = source.ToList();
				}
				else
				{
					result.RefreshedPerkIds = source.ToList();
				}
				Rod.Exit(in ctx);
				num++;
				flag = true;
			}
			Rod.SwitchToMode(Rod.ERandomMode.Disabled);
			return result;
		}

		private static List<string> GenerateInternal(PerkPageType perkPageType, int minCards, int maxCards, bool refresh, List<string> generatedPerks, List<string> requiredPerkTags)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Invalid comparison between Unknown and I4
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Invalid comparison between Unknown and I4
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Invalid comparison between Unknown and I4
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Invalid comparison between Unknown and I4
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			if (generatedPerks.Count > 0)
			{
				for (int num = generatedPerks.Count - 1; num >= 0; num--)
				{
					if (refresh)
					{
						list2.Add(generatedPerks[num]);
					}
				}
			}
			int num2 = Random.Range(minCards, maxCards + 1);
			List<Perk> list3 = Helpers.GetAllPerks().ToList();
			for (int num3 = list3.Count - 1; num3 >= 0; num3--)
			{
				if ((int)perkPageType == 0)
				{
					if ((int)list3[num3].spawnPool != 0)
					{
						list3.RemoveAt(num3);
						continue;
					}
				}
				else if ((int)perkPageType == 1 && (int)list3[num3].spawnPool != 1)
				{
					list3.RemoveAt(num3);
					continue;
				}
				bool flag = true;
				bool flag2 = false;
				foreach (string requiredPerkTag in requiredPerkTags)
				{
					if (list3[num3].tags.Contains(requiredPerkTag))
					{
						flag2 = true;
						break;
					}
				}
				if (!flag2)
				{
					list3.RemoveAt(num3);
				}
				if (refresh && list3.Count > maxCards && list2 != null && list2.Contains(list3[num3].id))
				{
					list3.RemoveAt(num3);
				}
			}
			for (int i = 0; i < num2; i++)
			{
				bool flag3 = false;
				Perk val = null;
				int num4 = 0;
				while (!flag3 && num4 < 100)
				{
					num4++;
					val = list3[Random.Range(0, list3.Count)];
					if ((int)perkPageType == 1)
					{
						flag3 = true;
					}
					else if ((i < num2 - 1 && val.cost == 0) || (i == num2 - 1 && val.cost > 0))
					{
						flag3 = true;
					}
				}
				list3.Remove(val);
				list.Add(val.id);
			}
			return list;
		}
	}
	public enum RouteType
	{
		DEFAULT,
		SHORTCUT_SINK,
		SHORTCUT_BURNER
	}
	public static class Vanga
	{
		public struct RouteInfo
		{
			public string RouteName;

			public List<PerkMachinePred> PerkMachines;

			public Dictionary<string, IEnumerable<string>> VendoItems;
		}

		public static void DoSeedSearch()
		{
			if (string.IsNullOrWhiteSpace(Plugin.DesiredRouteDescription.Value))
			{
				return;
			}
			string[] array = Plugin.DesiredRouteDescription.Value.Split(':');
			if (array.Length == 0)
			{
				Plugin.Beep.LogWarning((object)("Invalid DesiredRouteDescription format: '" + Plugin.DesiredRouteDescription.Value + "'. Expected format: '{route}: {perk1}, {perk2}, {perk3}'"));
				return;
			}
			string text = array[0].Trim().ToLower();
			string[] array2 = ((array.Length >= 2) ? (from p in array[1].Split(',')
				select p.Trim().ToLower()).ToArray() : Array.Empty<string>());
			if (!Enum.TryParse<RouteType>(text.ToUpper(), out var result))
			{
				Plugin.Beep.LogWarning((object)("Invalid desired route name: '" + text + "'. Valid routes are: " + string.Join(", ", Enum.GetNames(typeof(RouteType)))));
				return;
			}
			if (array2.Length != 3)
			{
				Plugin.Beep.LogWarning((object)string.Format("Invalid desired perk count: {0}. Expected exactly {1} perks but got: {2}", array2.Length, 3, string.Join(", ", array2)));
				return;
			}
			Plugin.Beep.LogInfo((object)("Searching desired route: " + text + ", perks: " + string.Join(", ", array2)));
			Random.InitState(Plugin.SeedSearchIterations.Value);
			int num = 0;
			for (int i = 0; i <= Plugin.SeedSearchIterations.Value; i++)
			{
				int num2 = Random.Range(0, 10000000);
				RouteInfo routeInfo = GenerateRouteInfo(num2, result);
				if (!routeInfo.PerkMachines[0].PredictedPerks.PerkIds.Contains(array2[0]) || !routeInfo.PerkMachines[1].PredictedPerks.PerkIds.Contains(array2[1]) || !routeInfo.PerkMachines[2].PredictedPerks.PerkIds.Contains(array2[2]))
				{
					continue;
				}
				Plugin.Beep.LogInfo((object)string.Format("Found suitable seed: {0}, injectors: >= {1}", num2, routeInfo.VendoItems.Values.Sum((IEnumerable<string> items) => items.Count((string x) => x == "injector"))));
				Plugin.Beep.LogInfo((object)JsonConvert.SerializeObject((object)routeInfo.VendoItems, (Formatting)1));
				if (++num >= Plugin.SeedSearchResultsNeeded.Value)
				{
					break;
				}
			}
		}

		public static RouteInfo GenerateRouteInfo(int seed, RouteType routeType)
		{
			Plugin.SeedForRandom = seed;
			if (1 == 0)
			{
			}
			RouteInfo result;
			switch (routeType)
			{
			case RouteType.DEFAULT:
			{
				RouteInfo routeInfo = default(RouteInfo);
				routeInfo.RouteName = routeType.ToString();
				routeInfo.PerkMachines = new List<PerkMachinePred>(3)
				{
					new PerkMachinePred((PerkPageType)1, "M1_Silos_SafeArea_01", 2, 2),
					new PerkMachinePred((PerkPageType)0, "Campaign_Interlude_Silo_To_Pipeworks_01", 3, 3),
					new PerkMachinePred((PerkPageType)0, "M3_Habitation_Shaft_Intro", 3, 3)
				};
				routeInfo.VendoItems = VendoPredictor.Generate(RouteType.DEFAULT);
				result = routeInfo;
				break;
			}
			case RouteType.SHORTCUT_SINK:
			{
				RouteInfo routeInfo = default(RouteInfo);
				routeInfo.RouteName = routeType.ToString();
				routeInfo.PerkMachines = new List<PerkMachinePred>(3)
				{
					new PerkMachinePred((PerkPageType)1, "Campaign_Interlude_Sink_To_Pipeworks_01", 2, 2),
					new PerkMachinePred((PerkPageType)0, "Campaign_Interlude_Sink_To_Pipeworks_01", 2, 2),
					new PerkMachinePred((PerkPageType)0, "M3_Habitation_Shaft_Intro", 3, 3)
				};
				routeInfo.VendoItems = VendoPredictor.Generate(RouteType.SHORTCUT_SINK);
				result = routeInfo;
				break;
			}
			case RouteType.SHORTCUT_BURNER:
			{
				RouteInfo routeInfo = default(RouteInfo);
				routeInfo.RouteName = routeType.ToString();
				routeInfo.PerkMachines = new List<PerkMachinePred>(3)
				{
					new PerkMachinePred((PerkPageType)1, "M1_Silos_SafeArea_01", 2, 2),
					new PerkMachinePred((PerkPageType)0, "Campaign_Interlude_Silo_To_Pipeworks_01", 3, 3),
					new PerkMachinePred((PerkPageType)0, "Campaign_Interlude_Chute_To_Habitation", 2, 2)
				};
				routeInfo.VendoItems = VendoPredictor.Generate(RouteType.SHORTCUT_BURNER);
				result = routeInfo;
				break;
			}
			default:
				result = default(RouteInfo);
				break;
			}
			if (1 == 0)
			{
			}
			return result;
		}
	}
	public class VendoPredictor
	{
		private enum VendoTier
		{
			T1,
			T2
		}

		private struct VendoPurchase
		{
			public string Name;

			public float Chance;
		}

		private static readonly List<VendoPurchase> PurchaseListT1 = new List<VendoPurchase>(13)
		{
			new VendoPurchase
			{
				Name = "piton",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "rebar",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "rebar rope",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "rubble",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "beans",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "injector",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "pills",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "rebar explosive",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "sluggrub",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "auto piton",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "foodbar",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "flaregun",
				Chance = 0.5f
			},
			new VendoPurchase
			{
				Name = "blinkeye",
				Chance = 0.8f
			}
		};

		private static readonly List<VendoPurchase> PurchaseListT2 = new List<VendoPurchase>(7)
		{
			new VendoPurchase
			{
				Name = "injector",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "pills",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "rebar explosive",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "sluggrub",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "auto piton",
				Chance = 1f
			},
			new VendoPurchase
			{
				Name = "foodbar",
				Chance = 0.8f
			},
			new VendoPurchase
			{
				Name = "blinkeye",
				Chance = 0.8f
			}
		};

		public static Dictionary<string, IEnumerable<string>> Generate(RouteType routeType)
		{
			return routeType switch
			{
				RouteType.DEFAULT => new Dictionary<string, IEnumerable<string>>
				{
					{
						"vendo_M1_Silos_SafeArea_01_Prop_VendingMachine.01",
						GenerateInternal("vendo_M1_Silos_SafeArea_01_Prop_VendingMachine.01", 3, VendoTier.T1)
					},
					{
						"vendo_M1_Silos_SafeArea_01_Prop_VendingMachine",
						GenerateInternal("vendo_M1_Silos_SafeArea_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine",
						GenerateInternal("vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine.01",
						GenerateInternal("vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine.01", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Pipeworks_To_Habitation_01_Prop_VendingMachine",
						GenerateInternal("vendo_Campaign_Interlude_Pipeworks_To_Habitation_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine.01",
						GenerateInternal("vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine.01", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Pier_Entrance_01_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Pier_Entrance_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Lab_Lobby_Prop_VendingMachine_T2",
						GenerateInternal("vendo_M3_Habitation_Lab_Lobby_Prop_VendingMachine_T2", 3, VendoTier.T2)
					},
					{
						"vendo_M3_Habitation_Lab_Ending_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Lab_Ending_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Habitation_To_Abyss_01_Prop_VendingMachine_Big",
						GenerateInternal("vendo_Campaign_Interlude_Habitation_To_Abyss_01_Prop_VendingMachine_Big", 8, VendoTier.T1)
					}
				}, 
				RouteType.SHORTCUT_SINK => new Dictionary<string, IEnumerable<string>>
				{
					{
						"vendo_Campaign_Interlude_Sink_To_Pipeworks_01_Prop_VendingMachine",
						GenerateInternal("vendo_Campaign_Interlude_Sink_To_Pipeworks_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Pipeworks_To_Habitation_01_Prop_VendingMachine",
						GenerateInternal("vendo_Campaign_Interlude_Pipeworks_To_Habitation_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine.01",
						GenerateInternal("vendo_M3_Habitation_Shaft_Intro_Prop_VendingMachine.01", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Pier_Entrance_01_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Pier_Entrance_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Lab_Lobby_Prop_VendingMachine_T2",
						GenerateInternal("vendo_M3_Habitation_Lab_Lobby_Prop_VendingMachine_T2", 3, VendoTier.T2)
					},
					{
						"vendo_M3_Habitation_Lab_Ending_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Lab_Ending_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Habitation_To_Abyss_01_Prop_VendingMachine_Big",
						GenerateInternal("vendo_Campaign_Interlude_Habitation_To_Abyss_01_Prop_VendingMachine_Big", 8, VendoTier.T1)
					}
				}, 
				RouteType.SHORTCUT_BURNER => new Dictionary<string, IEnumerable<string>>
				{
					{
						"vendo_M1_Silos_SafeArea_01_Prop_VendingMachine.01",
						GenerateInternal("vendo_M1_Silos_SafeArea_01_Prop_VendingMachine.01", 3, VendoTier.T1)
					},
					{
						"vendo_M1_Silos_SafeArea_01_Prop_VendingMachine",
						GenerateInternal("vendo_M1_Silos_SafeArea_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine",
						GenerateInternal("vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine.01",
						GenerateInternal("vendo_Campaign_Interlude_Silo_To_Pipeworks_01_Prop_VendingMachine.01", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Chute_To_Habitation_Prop_VendingMachine",
						GenerateInternal("vendo_Campaign_Interlude_Chute_To_Habitation_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Pier_Entrance_01_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Pier_Entrance_01_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_M3_Habitation_Lab_Lobby_Prop_VendingMachine_T2",
						GenerateInternal("vendo_M3_Habitation_Lab_Lobby_Prop_VendingMachine_T2", 3, VendoTier.T2)
					},
					{
						"vendo_M3_Habitation_Lab_Ending_Prop_VendingMachine",
						GenerateInternal("vendo_M3_Habitation_Lab_Ending_Prop_VendingMachine", 3, VendoTier.T1)
					},
					{
						"vendo_Campaign_Interlude_Habitation_To_Abyss_01_Prop_VendingMachine_Big",
						GenerateInternal("vendo_Campaign_Interlude_Habitation_To_Abyss_01_Prop_VendingMachine_Big", 8, VendoTier.T1)
					}
				}, 
				_ => new Dictionary<string, IEnumerable<string>>(), 
			};
		}

		private static List<string> GenerateInternal(string callSite, int itemsToGenerate, VendoTier vendoTier)
		{
			Rod.SwitchToMode(Rod.ERandomMode.Prediction);
			List<string> list = new List<string>();
			Rod.Context ctx = default(Rod.Context);
			Rod.Enter(ref ctx, callSite);
			List<VendoPurchase> list2 = ((vendoTier != 0) ? PurchaseListT2 : PurchaseListT1);
			while (list.Count < itemsToGenerate)
			{
				VendoPurchase vendoPurchase = list2[Random.Range(0, list2.Count)];
				if (Random.value < vendoPurchase.Chance)
				{
					list.Add(vendoPurchase.Name);
				}
			}
			Rod.Exit(in ctx);
			Rod.SwitchToMode(Rod.ERandomMode.Disabled);
			return list;
		}
	}
}
namespace IShowSeed.HandleProviders
{
	public class Items : HandleProvider<Item_Object>
	{
		private List<Item_Object> _items = new List<Item_Object>();

		public override Func<Item_Object, string> Name { get; } = (Item_Object x) => ((x == null) ? null : ((Object)x).name?.ToLower()) ?? null;


		public void InitializeFromAssetDatabase()
		{
			List<GameObject> itemPrefabs = CL_AssetManager.GetFullCombinedAssetDatabase().itemPrefabs;
			foreach (GameObject item in itemPrefabs)
			{
				Item_Object component = item.GetComponent<Item_Object>();
				if ((Object)(object)component != (Object)null)
				{
					_items.Add(component);
				}
			}
		}

		public override Handle<Item_Object> Handle()
		{
			if (_items.Count == 0)
			{
				InitializeFromAssetDatabase();
			}
			return new Handle<Item_Object>(_items, Name, Finalizer);
		}
	}
	public class Sprites : HandleProvider<Sprite>
	{
		private List<Sprite> _sprites = new List<Sprite>();

		public override Func<Sprite, string> Name { get; } = (Sprite x) => ((x == null) ? null : ((Object)x).name?.ToLower()) ?? null;


		public void InitializeFromAssetDatabase()
		{
			_sprites = CL_AssetManager.GetFullCombinedAssetDatabase().spriteAssets;
		}

		public override Handle<Sprite> Handle()
		{
			if (_sprites.Count == 0)
			{
				InitializeFromAssetDatabase();
			}
			return new Handle<Sprite>(_sprites, Name, Finalizer);
		}
	}
}