Decompiled source of TimeMachine v1.1.6

TimeMachine.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BTD_Mod_Helper;
using BTD_Mod_Helper.Api;
using BTD_Mod_Helper.Api.Components;
using BTD_Mod_Helper.Api.Helpers;
using BTD_Mod_Helper.Api.ModOptions;
using BTD_Mod_Helper.Extensions;
using HarmonyLib;
using Il2CppAssets.Scripts.Data.Legends;
using Il2CppAssets.Scripts.Models;
using Il2CppAssets.Scripts.Models.Artifacts;
using Il2CppAssets.Scripts.Models.Profile;
using Il2CppAssets.Scripts.Models.ServerEvents;
using Il2CppAssets.Scripts.Simulation;
using Il2CppAssets.Scripts.Simulation.Artifacts;
using Il2CppAssets.Scripts.Simulation.Input;
using Il2CppAssets.Scripts.Simulation.SimulationBehaviors;
using Il2CppAssets.Scripts.Simulation.Towers;
using Il2CppAssets.Scripts.Unity;
using Il2CppAssets.Scripts.Unity.Menu;
using Il2CppAssets.Scripts.Unity.UI_New.GameOver;
using Il2CppAssets.Scripts.Unity.UI_New.InGame;
using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu;
using Il2CppAssets.Scripts.Unity.UI_New.Pause;
using Il2CppAssets.Scripts.Unity.UI_New.Popups;
using Il2CppAssets.Scripts.Utils;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNewtonsoft.Json;
using Il2CppNinjaKiwi.GUTS.Models.ContentBrowser;
using Il2CppNinjaKiwi.LiNK.Client;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using TimeMachine;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(TimeMachineMod), "Time Machine", "1.1.6", "doombubbles", null)]
[assembly: MelonGame("Ninja Kiwi", "BloonsTD6")]
[assembly: MelonGame("Ninja Kiwi", "BloonsTD6-Epic")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TimeMachine")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+74ad0a82f8a00b3d55a14bbf6b7a9fde21af8313")]
[assembly: AssemblyProduct("TimeMachine")]
[assembly: AssemblyTitle("TimeMachine")]
[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.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]
	[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 TimeMachine
{
	public static class ModHelperData
	{
		public const string WorksOnVersion = "54.2";

		public const string Version = "1.1.6";

		public const string Name = "Time Machine";

		public const string Description = "Stores backups as you play, allowing you to travel back in time to any previous round you passed (even if you just lost!)";

		public const string RepoOwner = "doombubbles";

		public const string PrevRepoName = "time-machine";

		public const string RepoName = "TimeMachine";
	}
	[HarmonyPatch(typeof(InGame), "RoundEnd")]
	internal static class InGame_RoundEnd
	{
		[HarmonyPostfix]
		private static void Postfix(int completedRound, int highestCompletedRound)
		{
			if (InGame.instance.GameId == 0)
			{
				ModHelper.Warning<TimeMachineMod>((object)"This save is too old to create Time Machine backups for!");
			}
			else
			{
				TimeMachineMod.SaveRound(completedRound, highestCompletedRound);
			}
		}
	}
	[HarmonyPatch(typeof(PauseScreen), "Open")]
	internal static class PauseScreen_Open
	{
		[HarmonyPostfix]
		private static void Postfix(PauseScreen __instance)
		{
			if (!InGameData.CurrentGame.IsSandbox && !(InGameData.CurrentGame.selectedMode == "MapEditor"))
			{
				GameObject gameObject = ((Component)__instance.sidePanel.transform.parent).gameObject;
				TimeMachineMod.CreateTimelineUI(gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(DefeatScreen), "Open")]
	internal static class DefeatScreen_Open
	{
		[HarmonyPostfix]
		private static void Postfix(DefeatScreen __instance)
		{
			TimeMachineMod.CreateTimelineUI(__instance.regularObject, -50);
		}
	}
	[HarmonyPatch(typeof(BossDefeatScreen), "Open")]
	internal static class BossDefeatScreen_Open
	{
		[HarmonyPostfix]
		private static void Postfix(BossDefeatScreen __instance)
		{
			TimeMachineMod.CreateTimelineUI(((Component)((GameMenu)__instance).commonPanel).gameObject, -50);
		}
	}
	[HarmonyPatch(typeof(RogueDefeatScreen), "Open")]
	internal static class RogueDefeatScreen_Open
	{
		[HarmonyPostfix]
		private static void Postfix(RogueDefeatScreen __instance)
		{
			TimeMachineMod.CreateTimelineUI(((Component)((GameMenu)__instance).commonPanel).gameObject, -50);
		}
	}
	[HarmonyPatch(typeof(RogueInstaInventory), "GetSaveMetaData")]
	internal static class RogueInstaInventory_GetSaveMetaData
	{
		[HarmonyPostfix]
		internal static void Postfix(RogueInstaInventory __instance, Dictionary<string, string> metaData)
		{
			Enumerator<RogueInstaMonkey> enumerator = __instance.instas.GetEnumerator();
			while (enumerator.MoveNext())
			{
				RogueInstaMonkey current = enumerator.Current;
				metaData["RogueCooldown_" + current.uniqueId] = current.currentCooldown.ToString();
			}
		}
	}
	[HarmonyPatch(typeof(RogueInstaInventory), "SetSaveMetaData")]
	internal static class RogueInstaInventory_SetSaveMetaData
	{
		[HarmonyPostfix]
		internal static void Postfix(RogueInstaInventory __instance, Dictionary<string, string> metaData)
		{
			Enumerator<RogueInstaMonkey> enumerator = __instance.instas.GetEnumerator();
			string s = default(string);
			while (enumerator.MoveNext())
			{
				RogueInstaMonkey current = enumerator.Current;
				if (metaData.TryGetValue("RogueCooldown_" + current.uniqueId, ref s) && int.TryParse(s, out var result))
				{
					current.currentCooldown = result;
				}
			}
		}
	}
	[HarmonyPatch(typeof(FrontierDefeatScreen), "Open")]
	internal static class FrontierDefeatScreen_Open
	{
		[HarmonyPostfix]
		private static void Postfix(FrontierDefeatScreen __instance)
		{
			TimeMachineMod.CreateTimelineUI(((Component)((GameMenu)__instance).commonPanel).gameObject, -50);
		}
	}
	[HarmonyPatch(typeof(StaminaTraitArtifact), "Initialise")]
	internal static class StaminaTraitArtifact_Initialise
	{
		[HarmonyPrefix]
		internal static void Prefix(StaminaTraitArtifact __instance, Model modelToUse)
		{
			StaminaTraitArtifactModel staminaTraitArtifactModel = default(StaminaTraitArtifactModel);
			if (Il2CppSystemObjectExt.Is<StaminaTraitArtifactModel>((Il2CppObjectBase)(object)modelToUse, ref staminaTraitArtifactModel))
			{
				__instance.staminaTraitArtifactModel = staminaTraitArtifactModel;
			}
		}
	}
	[HarmonyPatch(typeof(Simulation), "GetSaveMetaData")]
	internal static class Simulation_GetSaveMetaData
	{
		[HarmonyPostfix]
		internal static void Postfix(Simulation __instance, Dictionary<string, string> metaData)
		{
			FrontierInstaInventory frontierInstaInventory = __instance.frontierInstaInventory;
			if (((frontierInstaInventory != null) ? frontierInstaInventory.instas : null) != null)
			{
				Enumerator<FrontierInstaMonkey> enumerator = __instance.frontierInstaInventory.instas.GetEnumerator();
				while (enumerator.MoveNext())
				{
					FrontierInstaMonkey current = enumerator.Current;
					metaData["FrontierStamina_" + current.frontierId] = current.stamina.ToString();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Simulation), "SetSaveMetaData")]
	internal static class Simulation_SetSaveMetaData
	{
		[HarmonyPostfix]
		internal static void Postfix(Simulation __instance, Dictionary<string, string> metaData)
		{
			FrontierInstaInventory frontierInstaInventory = __instance.frontierInstaInventory;
			if (((frontierInstaInventory != null) ? frontierInstaInventory.instas : null) == null)
			{
				return;
			}
			Enumerator<FrontierInstaMonkey> enumerator = __instance.frontierInstaInventory.instas.GetEnumerator();
			string s = default(string);
			while (enumerator.MoveNext())
			{
				FrontierInstaMonkey current = enumerator.Current;
				if (metaData.TryGetValue("FrontierStamina_" + current.frontierId, ref s) && float.TryParse(s, out var result))
				{
					current.stamina = result;
				}
			}
		}
	}
	[HarmonyPatch(typeof(FrontierTraitsPanel), "UpdateStamina")]
	internal static class FrontierTraitsPanel_UpdateStamina
	{
		[HarmonyPrefix]
		internal static bool Prefix(FrontierTraitsPanel __instance)
		{
			return __instance.insta != null;
		}
	}
	[HarmonyPatch(typeof(TowerManager), "CreateTower")]
	internal static class TowerManager_CreateTower
	{
		[HarmonyPrefix]
		internal static void Prefix(TowerSaveDataModel? loadingSaveData, ref int frontierId)
		{
			if (loadingSaveData != null && loadingSaveData.frontierId > -1)
			{
				frontierId = loadingSaveData.frontierId;
			}
		}
	}
	public class TimeMachineMod : BloonsTD6Mod
	{
		public static readonly ModSettingHotkey StepBackwardHotkey = new ModSettingHotkey((KeyCode)276, (HotkeyModifier)2)
		{
			description = "Hotkey to load the previous saved round of this match"
		};

		public static readonly ModSettingHotkey StepForwardHotkey = new ModSettingHotkey((KeyCode)275, (HotkeyModifier)2)
		{
			description = "Hotkey to load the subsequent saved round of this match"
		};

		public static readonly ModSettingButton OpenSavesFolder = new ModSettingButton((Action)delegate
		{
			Process.Start(new ProcessStartInfo
			{
				FileName = SavesFolder,
				UseShellExecute = true,
				Verb = "open"
			});
		})
		{
			buttonText = "Open"
		};

		public static readonly ModSettingButton DeleteData;

		private static ModHelperOption? deleteOption;

		public const string SavesFolderName = "TimeMachineSaves";

		internal static readonly JsonSerializerSettings Settings;

		public static string OldSavesFolder => Path.Combine(FileIOHelper.sandboxRoot, "TimeMachineSaves");

		public static string SavesFolder => Path.Combine(((PlayerServiceComponent)Game.instance.playerService).configuration.playerDataRootPath, "TimeMachineSaves", ((Player<ProfileModel>)(object)Game.Player).Data.ownerID ?? "");

		public static string CurrentTimeMachineID => InGame.instance.GameId.ToString();

		public static void CalcSize(ModHelperOption? option = null)
		{
			if ((Object)(object)option != (Object)null)
			{
				deleteOption = option;
			}
			DirectoryInfo folder = new DirectoryInfo(SavesFolder);
			if (!folder.Exists || (Object)(object)deleteOption == (Object)null)
			{
				return;
			}
			Task.Run(() => folder.EnumerateFiles("*", SearchOption.AllDirectories).Sum((FileInfo info) => info.Length)).ContinueWith(delegate(Task<long> task)
			{
				TaskScheduler.ScheduleTask((Action)delegate
				{
					if ((Object)(object)deleteOption != (Object)null)
					{
						((Component)deleteOption.TopRow).GetComponentInChildren<ModHelperText>().SetText($"Storing {(double)task.Result / 1000000.0:N1} mb of data");
					}
				}, (Func<bool>)null);
			});
		}

		public static void ClearData()
		{
			try
			{
				Directory.Delete(SavesFolder, recursive: true);
				Directory.CreateDirectory(SavesFolder);
			}
			catch (Exception ex)
			{
				ModHelper.Warning<TimeMachineMod>((object)ex);
			}
			CalcSize();
		}

		public override void OnMainMenu()
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(SavesFolder);
			if (!directoryInfo.Exists && Directory.Exists(OldSavesFolder))
			{
				directoryInfo.Parent.Create();
				Directory.Move(OldSavesFolder, SavesFolder);
			}
			if (!directoryInfo.Exists || (Game.Player.OnlineData == null && !string.IsNullOrEmpty(((Player<ProfileModel>)(object)Game.Player).Data.ownerID)))
			{
				return;
			}
			IEnumerable<MapSaveDataModel> first = IEnumerableExt.OfIl2CppType<MapSaveDataModel>((IEnumerable)Il2CppSystemDictionaryExt.GetValues<string, MapSaveDataModel>(((Player<ProfileModel>)(object)Game.Player).Data.AllSavedMaps).ToArray());
			OnlineProfileModel onlineData = Game.Player.OnlineData;
			object obj;
			if (onlineData == null)
			{
				obj = null;
			}
			else
			{
				Dictionary<ContentType, ContentTypeSaveData> contentBrowserData = onlineData.contentBrowserData;
				obj = ((contentBrowserData != null) ? IEnumerableExt.OfIl2CppType<MapSaveDataModel>((IEnumerable)Il2CppSystemDictionaryExt.Values<ContentType, ContentTypeSaveData>(contentBrowserData).SelectMany(delegate(ContentTypeSaveData data)
				{
					List<BaseSaveDataModel> saveData = data.saveData;
					return ((saveData != null) ? Il2CppGenericsExt.ToList<BaseSaveDataModel>(saveData) : null) ?? new List<BaseSaveDataModel>();
				})) : null);
			}
			IEnumerable<MapSaveDataModel> enumerable = (IEnumerable<MapSaveDataModel>)obj;
			IEnumerable<string> usedGameIds = from mapSave in first.Concat(enumerable ?? Array.Empty<MapSaveDataModel>())
				select JsonConvert.SerializeObject((Object)(object)mapSave.gameId);
			foreach (DirectoryInfo item in from directoryInfo2 in directoryInfo.GetDirectories().ToList()
				where !usedGameIds.Contains(directoryInfo2.Name)
				select directoryInfo2)
			{
				ModHelper.Msg<TimeMachineMod>((object)("Deleting Time Machine saves for game " + item.Name + " since it was removed from profile"));
				try
				{
					item.Delete(recursive: true);
				}
				catch (Exception ex)
				{
					ModHelper.Warning<TimeMachineMod>((object)ex);
				}
			}
		}

		public override void OnUpdate()
		{
			if ((!StepBackwardHotkey.JustPressed() && !StepForwardHotkey.JustPressed()) || (Object)(object)InGame.instance == (Object)null || InGame.Bridge == null)
			{
				return;
			}
			List<int> rounds = GetRounds();
			if (rounds.Any())
			{
				int currentRound = InGame.Bridge.GetCurrentRound();
				if (InGame.Bridge.AreRoundsActive() && StepBackwardHotkey.JustPressed() && !InGame.instance.IsApopalypse && InGame.Bridge.GetBossBloon() == null)
				{
					currentRound++;
				}
				int[] array = rounds.Where((int r) => r < currentRound).ToArray();
				int[] array2 = rounds.Where((int r) => r > currentRound).ToArray();
				if (StepBackwardHotkey.JustPressed() && ArrayExt.Any<int>(array))
				{
					LoadRound(array.Last());
				}
				if (StepForwardHotkey.JustPressed() && ArrayExt.Any<int>(array2))
				{
					LoadRound(array2.First());
				}
			}
		}

		internal static MapSaveDataModel? GetSaveModel(int highestCompletedRound)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			bool flag = false;
			Simulation simulation = InGame.Bridge.Simulation;
			if ((int)simulation.model.subGameType == 16)
			{
				FrontierBossManager frontierBossManager = simulation.frontierBossManager;
				if (frontierBossManager != null && frontierBossManager.IsBossGame)
				{
					if ((int)simulation.frontierBossManager.frontierGameManagerModel.boss == 6)
					{
						return null;
					}
					flag = true;
					simulation.model.subGameType = (SubGameType)4;
				}
			}
			MapSaveDataModel result = InGame.instance.CreateCurrentMapSave(highestCompletedRound, InGame.instance.MapDataSaveId);
			if (flag)
			{
				simulation.model.subGameType = (SubGameType)16;
			}
			return result;
		}

		public static void SaveRound(int completedRound, int highestCompletedRound)
		{
			string text = FilePathFor(CurrentTimeMachineID, completedRound + 1);
			MapSaveDataModel saveModel = GetSaveModel(highestCompletedRound);
			if (saveModel == null)
			{
				return;
			}
			string s = JsonConvert.SerializeObject((Object)(object)saveModel, Settings);
			byte[] bytes = Encoding.UTF8.GetBytes(s);
			using MemoryStream memoryStream = new MemoryStream(bytes);
			using (ZLibStream zLibStream = new ZLibStream(memoryStream, CompressionMode.Compress))
			{
				zLibStream.Write(bytes, 0, bytes.Length);
			}
			Directory.CreateDirectory(new FileInfo(text).DirectoryName);
			File.WriteAllBytes(text, memoryStream.ToArray());
		}

		public static void LoadRound(int round)
		{
			if ((Object)(object)InGame.instance == (Object)null)
			{
				return;
			}
			string text = FilePathFor(CurrentTimeMachineID, round);
			string text2;
			if (File.Exists(text))
			{
				byte[] buffer = File.ReadAllBytes(text);
				using MemoryStream stream = new MemoryStream(buffer);
				using MemoryStream memoryStream = new MemoryStream();
				using (ZLibStream zLibStream = new ZLibStream(stream, CompressionMode.Decompress))
				{
					zLibStream.CopyTo(memoryStream);
				}
				text2 = Encoding.UTF8.GetString(memoryStream.ToArray());
			}
			else
			{
				if (!File.Exists(text + ".json"))
				{
					ModHelper.Warning<TimeMachineMod>((object)("No Time Machine data for " + text));
					return;
				}
				text2 = File.ReadAllText(text + ".json");
			}
			MapSaveDataModel saveModel = JsonConvert.DeserializeObject<MapSaveDataModel>(text2, Settings);
			LoadSave(saveModel);
		}

		public static void LoadSave(MapSaveDataModel saveModel)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Invalid comparison between Unknown and I4
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Invalid comparison between Unknown and I4
			ReadonlyInGameData currentGame = InGameData.CurrentGame;
			ChallengeType? obj;
			if (currentGame == null)
			{
				obj = null;
			}
			else
			{
				DailyChallengeModel dcModel = currentGame.dcModel;
				obj = ((dcModel != null) ? new ChallengeType?(dcModel.chalType) : ((ChallengeType?)null));
			}
			ChallengeType? val = obj;
			bool flag;
			if (val.HasValue)
			{
				ChallengeType valueOrDefault = val.GetValueOrDefault();
				if ((int)valueOrDefault == 3 || (int)valueOrDefault == 12)
				{
					flag = true;
					goto IL_005a;
				}
			}
			flag = false;
			goto IL_005a;
			IL_005a:
			if (flag && saveModel.gameVersion != ((Object)Game.Version).ToString())
			{
				PopupScreenExt.SafelyQueue(PopupScreen.instance, (Action<PopupScreen>)delegate(PopupScreen screen)
				{
					screen.ShowOkPopup("Can't load save from an older BTD6 version for a Custom Map", (ReturnCallback)null);
				});
				return;
			}
			InGame.Bridge.ExecuteContinueFromCheckpoint(InGame.Bridge.MyPlayerNumber, new KonFuze(0.0), ref saveModel, true, false);
			ArtifactManager artifactManager = InGame.Bridge.Simulation.artifactManager;
			GameType gameType = InGame.instance.GameType;
			GameType val2 = gameType;
			if ((int)val2 != 13)
			{
				if ((int)val2 == 14)
				{
					ShopMenuExt.instance.RebuildFrontierTowers();
					foreach (ArtifactLoot item in (Il2CppArrayBase<ArtifactLoot>)(object)InGameData.CurrentGame.frontierIngameData.equippedArtifacts)
					{
						artifactManager.Activate(item.artifactName, item.frontierIds);
					}
				}
			}
			else
			{
				ShopMenuExt.instance.RebuildRogueTowers();
				foreach (ArtifactLoot item2 in (Il2CppArrayBase<ArtifactLoot>)(object)InGameData.CurrentGame.rogueData.equippedArtifacts)
				{
					if (!artifactManager.IsArtifactActive(item2.artifactName))
					{
						artifactManager.Activate(item2.artifactName, (List<int>)null);
					}
				}
			}
			((Player<ProfileModel>)(object)Game.Player).Data.SetSavedMap(saveModel.savedMapsId, saveModel);
		}

		public static string FilePathFor(string gameId, int round)
		{
			return Path.Combine(SavesFolder, gameId, round.ToString());
		}

		public static List<int> GetRounds()
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(SavesFolder, CurrentTimeMachineID));
			if (!directoryInfo.Exists)
			{
				return new List<int>();
			}
			int result;
			return (from fileInfo in directoryInfo.GetFiles()
				select int.TryParse(Path.GetFileNameWithoutExtension(fileInfo.Name), out result) ? result : 0 into i
				where i != 0
				orderby i
				select i).ToList();
		}

		public static void CreateTimelineUI(GameObject mainPanel, int yOffset = 0)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(SavesFolder, CurrentTimeMachineID));
			if (!directoryInfo.Exists)
			{
				return;
			}
			List<int> rounds = GetRounds();
			if (!rounds.Any())
			{
				return;
			}
			ModHelperScrollPanel val = GameObjectExt.AddModHelperScrollPanel(mainPanel, new Info("TimeMachineScroll", 0f, (float)(-1150 + yOffset), 2500f, 150f), (Axis?)(Axis)0, "Ui[MainBgPanelHematite]", 100f, 0);
			GameObjectExt.AddModHelperComponent<ModHelperImage>(mainPanel, ModHelperImage.Create(new Info("TimeIcon", -1400f, (float)(-1150 + yOffset), 175f), "Ui[StopWatch]"));
			GameObjectExt.AddModHelperComponent<ModHelperImage>(mainPanel, ModHelperImage.Create(new Info("TimeIcon2", 1400f, (float)(-1150 + yOffset), 200f), "PowerIcons[DartTimeIcon]"));
			int currentRound = InGame.instance.bridge.GetCurrentRound();
			foreach (int round in rounds)
			{
				string message = $"Travel back {((round > currentRound) ? "(to the future!)" : "to")} when you finished round {round}?\nRound {round + 1} will be about to start.";
				string text = ((round == currentRound) ? "Ui[YellowBtn]" : "Ui[BrightBlueBtn]");
				ModHelperButton val2 = ((ModHelperComponent)val.ScrollContent).AddButton(new Info($"Btn{round}", 140f), text, Action.op_Implicit((Action)delegate
				{
					AudioClipExtensions.Play(MenuManager.instance.buttonClick3Sound, "ClickSounds", 1f);
					PopupScreenExt.SafelyQueue(PopupScreen.instance, (Action<PopupScreen>)delegate(PopupScreen screen)
					{
						screen.ShowPopup((Placement)2, "Time Machine", message, ReturnCallback.op_Implicit((Action)delegate
						{
							LoadRound(round);
						}), "Yes", (ReturnCallback)null, "No", (TransitionAnim)1, (BackGround)0, false, false);
					});
				}));
				Info val3 = new Info("Text", (InfoPreset)0);
				((Info)(ref val3)).set_Width(50f);
				((ModHelperComponent)val2).AddText(val3, round.ToString(), 100f);
			}
			float value = (float)InGame.instance.bridge.GetCurrentRound() / (float)rounds.Max();
			val.ScrollRect.horizontalNormalizedPosition = Math.Clamp(value, 0f, 1f);
		}

		static TimeMachineMod()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			ModSettingButton val = new ModSettingButton((Action)delegate
			{
				PopupScreen.instance.ShowPopup((Placement)2, "Delete Data", "Are you sure you want to delete all Time Machine Backups?", ReturnCallback.op_Implicit((Action)ClearData), "Delete", (ReturnCallback)null, "Cancel", (TransitionAnim)1, (BackGround)1, false, false);
			});
			((ModSetting)val).displayName = "Calculating...";
			val.buttonText = "Delete Data";
			val.buttonSprite = "Ui[RedBtnLong]";
			((ModSetting)val).modifyOption = CalcSize;
			DeleteData = val;
			Settings = new JsonSerializerSettings
			{
				TypeNameHandling = (TypeNameHandling)1
			};
		}
	}
}