Decompiled source of CustomCheckpoints v0.0.2

CustomCheckpoints.dll

Decompiled a day ago
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using ChainedPuzzles;
using CustomCheckpoints.Data;
using CustomCheckpoints.Extensions;
using CustomCheckpoints.Manager;
using CustomCheckpoints.Utility;
using GTFO.API;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("CustomCheckpoints")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.0.2")]
[assembly: AssemblyInformationalVersion("0.0.2+c5d2922301ab4ae57c5447a39af8c0d1fbcdee23")]
[assembly: AssemblyProduct("CustomCheckpoints")]
[assembly: AssemblyTitle("CustomCheckpoints")]
[assembly: AssemblyVersion("0.0.2.0")]
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.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;
		}
	}
}
namespace CustomCheckpoints
{
	[BepInPlugin("com.monkal.CustomCheckpoints", "CustomCheckpoints", "0.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class CustomCheckpoints : BasePlugin
	{
		public const string ModName = "CustomCheckpoints";

		private const string Author = "monkal";

		private const string Guid = "com.monkal.CustomCheckpoints";

		private const string Version = "0.0.2";

		private readonly CheckpointConfigManager _checkpointConfigManager = new CheckpointConfigManager();

		public override void Load()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			GameDataAPI.OnGameDataInitialized += _checkpointConfigManager.ValidateConfig;
			new Harmony("com.monkal.CustomCheckpoints").PatchAll();
			LevelAPI.OnBuildStart += Execute;
		}

		private void Execute()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				_checkpointConfigManager.ValidateConfig();
				int num = CustomCheckpointManager.ReplaceDoorsForLevel(RundownDataManager.GetDoorData(_checkpointConfigManager.GetConfig()));
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(19, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Added ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" checkpoints.");
				}
				Log.Logger.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log = ((BasePlugin)this).Log;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Error occurred during door replacement: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogError(val2);
			}
		}
	}
	[GeneratedCode("VersionInfoGenerator", "2.0.0+git50a4b1a-master")]
	[CompilerGenerated]
	internal static class VersionInfo
	{
		public const string RootNamespace = "CustomCheckpoints";

		public const string Version = "0.0.2";

		public const string VersionPrerelease = null;

		public const string VersionMetadata = "gitc5d2922-master";

		public const string SemVer = "0.0.2";

		public const string GitRevShort = "c5d2922";

		public const string GitRevLong = "c5d2922301ab4ae57c5447a39af8c0d1fbcdee23";

		public const string GitBranch = "master";

		public const string GitTag = null;

		public const bool GitIsDirty = false;
	}
}
namespace CustomCheckpoints.Utility
{
	public class JsonSerializer
	{
		private readonly JsonSerializerOptions _options = new JsonSerializerOptions
		{
			AllowTrailingCommas = true,
			IncludeFields = true,
			PropertyNameCaseInsensitive = true,
			ReadCommentHandling = JsonCommentHandling.Skip,
			WriteIndented = true
		};

		public JsonSerializer()
		{
			_options.Converters.Add(new JsonStringEnumConverter());
		}

		public T Read<T>(string path) where T : new()
		{
			string json = File.ReadAllText(path);
			T val = Deserialize<T>(json);
			if (val == null)
			{
				throw new JsonException("Deserialization returned null.");
			}
			return val;
		}

		public void Write(string path, string json)
		{
			File.WriteAllText(path, json);
		}

		public string Serialize(object value)
		{
			return System.Text.Json.JsonSerializer.Serialize(value, _options);
		}

		public T? Deserialize<T>(string json)
		{
			return System.Text.Json.JsonSerializer.Deserialize<T>(json, _options);
		}
	}
	public static class Log
	{
		public static readonly ManualLogSource Logger = Logger.CreateLogSource("CustomCheckpoints");

		public static void LogObject(object? obj, string prefix = "", int depth = 0)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			if (depth > 3 || obj == null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(8, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(prefix);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is NULL");
				}
				Logger.LogInfo(val);
				return;
			}
			Type type = obj.GetType();
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
			foreach (PropertyInfo propertyInfo in properties)
			{
				try
				{
					object value = propertyInfo.GetValue(obj);
					LogValue(propertyInfo.Name, value, propertyInfo.PropertyType, prefix, depth);
				}
				catch
				{
				}
			}
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				try
				{
					object value2 = fieldInfo.GetValue(obj);
					LogValue(fieldInfo.Name, value2, fieldInfo.FieldType, prefix, depth);
				}
				catch
				{
				}
			}
		}

		private static void LogValue(string name, object? value, Type type, string prefix, int depth)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			if (type == typeof(IntPtr) || type == typeof(UIntPtr))
			{
				return;
			}
			string? text = type.Namespace;
			if ((text != null && text.StartsWith("Il2CppInterop")) || type.Name.Contains("Il2CppMethodInfo"))
			{
				return;
			}
			string text2 = prefix + name;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (value == null)
			{
				val = new BepInExInfoLogInterpolatedStringHandler(7, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" = NULL");
				}
				Logger.LogInfo(val);
				return;
			}
			if (type.IsPrimitive || type == typeof(string) || type.IsEnum)
			{
				val = new BepInExInfoLogInterpolatedStringHandler(3, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" = ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<object>(value);
				}
				Logger.LogInfo(val);
				return;
			}
			string? text3 = type.Namespace;
			if (text3 != null && text3.StartsWith("UnityEngine"))
			{
				val = new BepInExInfoLogInterpolatedStringHandler(3, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" = ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<object>(value);
				}
				Logger.LogInfo(val);
				return;
			}
			val = new BepInExInfoLogInterpolatedStringHandler(4, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.Name);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("):");
			}
			Logger.LogInfo(val);
			LogObject(value, text2 + ".", depth + 1);
		}
	}
}
namespace CustomCheckpoints.Patches
{
	[HarmonyPatch(typeof(ChainedPuzzleManager), "CreatePuzzleInstance", new Type[]
	{
		typeof(ChainedPuzzleDataBlock),
		typeof(LG_Area),
		typeof(Vector3),
		typeof(Transform)
	})]
	public static class CreatePuzzleInstancePatch
	{
		public static void Prefix(ref ChainedPuzzleDataBlock data, LG_Area sourceArea)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			if (data == null)
			{
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(41, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("CreatePuzzleInstance: null datablock for ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((sourceArea != null) ? ((Object)sourceArea).name : null);
				}
				Log.Logger.LogWarning(val);
				data = GetCheckpointScanReplacement();
			}
		}

		private static ChainedPuzzleDataBlock GetCheckpointScanReplacement()
		{
			return ((IEnumerable<ChainedPuzzleDataBlock>)GameDataBlockBase<ChainedPuzzleDataBlock>.GetAllBlocks()).FirstOrDefault((Func<ChainedPuzzleDataBlock, bool>)((ChainedPuzzleDataBlock b) => ((GameDataBlockBase<ChainedPuzzleDataBlock>)(object)b).name.ToLower().Contains("checkpoint"))) ?? CreateCheckpointBlock();
		}

		private static ChainedPuzzleDataBlock CreateCheckpointBlock()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_00ec: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			Il2CppArrayBase<ChainedPuzzleDataBlock> allBlocks = GameDataBlockBase<ChainedPuzzleDataBlock>.GetAllBlocks();
			int count = allBlocks.Count;
			uint num = 0u;
			for (int i = 0; i < count; i++)
			{
				if (((GameDataBlockBase<ChainedPuzzleDataBlock>)(object)allBlocks[i]).persistentID > num)
				{
					num = ((GameDataBlockBase<ChainedPuzzleDataBlock>)(object)allBlocks[i]).persistentID;
				}
			}
			ChainedPuzzleComponent val = new ChainedPuzzleComponent
			{
				PuzzleType = 19u
			};
			List<ChainedPuzzleComponent> val2 = new List<ChainedPuzzleComponent>();
			val2.Add(val);
			ChainedPuzzleDataBlock val3 = new ChainedPuzzleDataBlock
			{
				PublicAlarmName = "Alarm",
				TriggerAlarmOnActivate = false,
				SurvivalWaveSettings = 1u,
				SurvivalWavePopulation = 1u,
				SurvivalWaveAreaDistance = 2,
				DisableSurvivalWaveOnComplete = true,
				UseRandomPositions = false,
				WantedDistanceFromStartPos = 0f,
				WantedDistanceBetweenPuzzleComponents = 1f,
				ChainedPuzzle = val2,
				OnlyShowHUDWhenPlayerIsClose = false,
				AlarmSoundStart = 3339129407u,
				AlarmSoundStop = 42633153u
			};
			((GameDataBlockBase<ChainedPuzzleDataBlock>)val3).name = "Checkpoint";
			((GameDataBlockBase<ChainedPuzzleDataBlock>)val3).internalEnabled = true;
			((GameDataBlockBase<ChainedPuzzleDataBlock>)val3).persistentID = num + 1;
			ChainedPuzzleDataBlock val4 = val3;
			GameDataBlockBase<ChainedPuzzleDataBlock>.AddBlock(val4, -1);
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("Injected checkpoint scan block with ID ");
				((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<uint>(((GameDataBlockBase<ChainedPuzzleDataBlock>)(object)val4).persistentID);
			}
			Log.Logger.LogInfo(val5);
			return val4;
		}
	}
}
namespace CustomCheckpoints.Manager
{
	public class CheckpointConfigManager
	{
		private readonly global::CustomCheckpoints.Utility.JsonSerializer _serializer = new global::CustomCheckpoints.Utility.JsonSerializer();

		private const string CheckpointsConfigFileName = "CustomCheckpoints.doors.json";

		private byte[]? _configHash;

		private List<RundownData>? _config;

		public List<RundownData>? GetConfig()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				if (_config != null && _configHash == GetConfigHash())
				{
					return _config;
				}
				string configFilepath = GetConfigFilepath();
				List<RundownData> list = _serializer.Read<List<RundownData>>(configFilepath);
				CacheConfig(list);
				return list;
			}
			catch (Exception ex) when (((ex is DirectoryNotFoundException || ex is FileNotFoundException) ? 1 : 0) != 0)
			{
				return null;
			}
			catch (JsonException ex2)
			{
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(54, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("CustomCheckpoints.doors.json");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" configuration is invalid. See exception for details: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex2.Message);
				}
				Log.Logger.LogWarning(val);
				return new List<RundownData>();
			}
			catch (Exception ex3)
			{
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Unexpected error occured: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex3.Message);
				}
				Log.Logger.LogError(val2);
				throw;
			}
		}

		public void ValidateConfig()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			List<RundownData> config = GetConfig();
			if (config == null)
			{
				Log.Logger.LogInfo((object)"No existing configuration detected, creating new checkpoint configuration...");
				CreateConfig(RundownDataManager.RetrieveData());
				return;
			}
			bool flag = default(bool);
			if (config.Count == 0)
			{
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(80, 0, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Config exists, but no door data was found, resetting checkpoint configuration...");
				}
				Log.Logger.LogWarning(val);
				ResetConfig();
			}
			if (HasReadonlyDataChanged(config))
			{
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(69, 0, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Readonly data has been changed, resetting checkpoint configuration...");
				}
				Log.Logger.LogWarning(val);
				ResetConfig();
			}
		}

		private static bool HasReadonlyDataChanged(List<RundownData> config)
		{
			List<RundownData> originalData = RundownDataManager.OriginalData;
			return !config.SequenceEqual(originalData);
		}

		private static string GetConfigFilepath()
		{
			return Path.Combine(Paths.ConfigPath, "CustomCheckpoints.doors.json");
		}

		private void CreateConfig(List<RundownData> rundowns)
		{
			string json = _serializer.Serialize(rundowns);
			string configFilepath = GetConfigFilepath();
			_serializer.Write(configFilepath, json);
			CacheConfig(rundowns);
		}

		private void ResetConfig()
		{
			CreateConfig(RundownDataManager.OriginalData);
		}

		private void CacheConfig(List<RundownData> config)
		{
			_configHash = GetConfigHash();
			_config = config;
		}

		private static byte[] GetConfigHash()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			try
			{
				string configFilepath = GetConfigFilepath();
				using MD5 mD = MD5.Create();
				using FileStream inputStream = File.OpenRead(configFilepath);
				return mD.ComputeHash(inputStream);
			}
			catch (Exception ex)
			{
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unexpected error occured: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				Log.Logger.LogError(val);
				throw;
			}
		}
	}
	public static class CustomCheckpointManager
	{
		public static int ReplaceDoorsForLevel(Dictionary<string, List<SecurityDoorData>> doorData)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			int num = 0;
			ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
			string key = activeExpedition.LevelLayoutData.GetHashCode().ToString();
			doorData.TryGetValue(key, out List<SecurityDoorData> value);
			if (value == null || value.Count == 0)
			{
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(50, 0, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No door data could be found for the current level.");
				}
				Log.Logger.LogWarning(val);
				return 0;
			}
			num += ReplaceDoors(activeExpedition.LevelLayoutData, value, Layer.Main);
			if (activeExpedition.SecondaryLayerEnabled)
			{
				num += ReplaceDoors(activeExpedition.SecondaryLayout, value, Layer.Secondary);
			}
			if (activeExpedition.ThirdLayerEnabled)
			{
				num += ReplaceDoors(activeExpedition.ThirdLayout, value, Layer.Third);
			}
			return num;
		}

		private static int ReplaceDoors(uint layoutId, List<SecurityDoorData> doors, Layer layer)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			int num = 0;
			LevelLayoutDataBlock block = GameDataBlockBase<LevelLayoutDataBlock>.GetBlock(layoutId);
			if (block == null)
			{
				return 0;
			}
			List<ExpeditionZoneData> zones = block.Zones;
			Il2CppArrayBase<ExpeditionZoneData> items = zones._items;
			int size = zones._size;
			bool flag = default(bool);
			for (int i = 0; i < size; i++)
			{
				ExpeditionZoneData val = items[i];
				string doorId = val.GetDoorId(layer);
				if (val.ChainedPuzzleToEnter == 0)
				{
					continue;
				}
				SecurityDoorData securityDoorData = doors.FirstOrDefault((SecurityDoorData d) => d.Id == doorId);
				if (securityDoorData == null)
				{
					continue;
				}
				if (securityDoorData.IsCheckpoint)
				{
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Adding a checkpoint to ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(securityDoorData.Name);
					}
					Log.Logger.LogInfo(val2);
					num++;
				}
				val.IsCheckpointDoor = securityDoorData.IsCheckpoint;
				items[i] = val;
			}
			return num;
		}
	}
	public static class RundownDataManager
	{
		public static readonly List<RundownData> OriginalData = RetrieveData();

		public static List<RundownData> RetrieveData()
		{
			List<RundownData> list = new List<RundownData>();
			Il2CppArrayBase<RundownDataBlock> allBlocks = GameDataBlockBase<RundownDataBlock>.GetAllBlocks();
			int count = allBlocks.Count;
			for (int i = 0; i < count; i++)
			{
				RundownDataBlock obj = allBlocks[i];
				List<ExpeditionData> list2 = new List<ExpeditionData>();
				uint persistentID = ((GameDataBlockBase<RundownDataBlock>)(object)obj).persistentID;
				string name = ((GameDataBlockBase<RundownDataBlock>)(object)obj).name;
				List<ExpeditionInTierData>[] tiers = obj.GetTiers();
				foreach (List<ExpeditionInTierData> val in tiers)
				{
					if (val == null)
					{
						continue;
					}
					Il2CppArrayBase<ExpeditionInTierData> items = val._items;
					int size = val._size;
					for (int k = 0; k < size; k++)
					{
						ExpeditionInTierData val2 = items[k];
						if (val2 != null && val2.Enabled)
						{
							List<SecurityDoorData> doors = new List<SecurityDoorData>();
							string expeditionId = val2.GetExpeditionId(k);
							AddAllDoorsFromLayoutId(val2.LevelLayoutData, Layer.Main, doors);
							if (val2.SecondaryLayerEnabled)
							{
								AddAllDoorsFromLayoutId(val2.SecondaryLayout, Layer.Secondary, doors);
							}
							if (val2.ThirdLayerEnabled)
							{
								AddAllDoorsFromLayoutId(val2.ThirdLayout, Layer.Third, doors);
							}
							ExpeditionData item = new ExpeditionData(expeditionId, val2.LevelLayoutData, doors);
							list2.Add(item);
						}
					}
				}
				RundownData item2 = new RundownData(persistentID, name, list2);
				list.Add(item2);
			}
			return list;
		}

		public static Dictionary<string, List<SecurityDoorData>> GetDoorData(List<RundownData> config)
		{
			return (from d in config.SelectMany((RundownData r) => r.Expeditions)
				where d.Doors.Count > 0
				select d).ToDictionary((ExpeditionData e) => e.LayoutId.GetHashCode().ToString(), (ExpeditionData e) => e.Doors);
		}

		private static void AddAllDoorsFromLayoutId(uint layoutId, Layer layer, List<SecurityDoorData> doors)
		{
			LevelLayoutDataBlock block = GameDataBlockBase<LevelLayoutDataBlock>.GetBlock(layoutId);
			if (block != null)
			{
				int zoneAliasStart = block.ZoneAliasStart;
				AddDoorsFromLayout(block, layer, doors, zoneAliasStart);
			}
		}

		private static void AddDoorsFromLayout(LevelLayoutDataBlock layout, Layer layer, List<SecurityDoorData> doors, int startAlias)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected I4, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			Il2CppArrayBase<ExpeditionZoneData> items = layout.Zones._items;
			int size = layout.Zones._size;
			for (int i = 0; i < size; i++)
			{
				ExpeditionZoneData val = items[i];
				if ((int)val.LocalIndex != 0)
				{
					string doorId = val.GetDoorId(layer);
					string text = $"Door to zone {startAlias + val.LocalIndex}";
					string value = ((val.ChainedPuzzleToEnter == 0) ? "no alarm" : (((GameDataBlockBase<ChainedPuzzleDataBlock>)(object)GameDataBlockBase<ChainedPuzzleDataBlock>.GetBlock(val.ChainedPuzzleToEnter))?.name ?? "unknown alarm"));
					string description = $"{val.SecurityGateToEnter} door to {text} ({layer}) — {value}";
					SecurityDoorData item = new SecurityDoorData(doorId, text, description, val.IsCheckpointDoor);
					doors.Add(item);
				}
			}
		}
	}
}
namespace CustomCheckpoints.Extensions
{
	public static class DataBlockExtensions
	{
		public static List<ExpeditionInTierData>?[] GetTiers(this RundownDataBlock? dataBlock)
		{
			return new List<ExpeditionInTierData>[5]
			{
				(dataBlock != null) ? dataBlock.TierA : null,
				(dataBlock != null) ? dataBlock.TierB : null,
				(dataBlock != null) ? dataBlock.TierC : null,
				(dataBlock != null) ? dataBlock.TierD : null,
				(dataBlock != null) ? dataBlock.TierE : null
			};
		}

		public static string GetDoorId(this ExpeditionZoneData zone, Layer layerName)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			return $"{Enum.GetName(typeof(Layer), layerName)}_{zone.LocalIndex}";
		}

		public static string GetExpeditionId(this ExpeditionInTierData exp, int index)
		{
			return exp.GetShortName(index) + " " + StripRichText(exp.Descriptive.PublicName);
		}

		private static string StripRichText(string input)
		{
			if (string.IsNullOrEmpty(input))
			{
				return input;
			}
			return Regex.Replace(input, "<.*?>", string.Empty);
		}
	}
}
namespace CustomCheckpoints.Data
{
	public class ExpeditionData : IEquatable<ExpeditionData>
	{
		public string Id { get; init; }

		public uint LayoutId { get; init; }

		public List<SecurityDoorData> Doors { get; init; }

		public ExpeditionData(string id, uint layoutId, List<SecurityDoorData> doors)
		{
			Id = id;
			LayoutId = layoutId;
			Doors = doors;
		}

		public bool Equals(ExpeditionData? other)
		{
			if (other == null)
			{
				return false;
			}
			if (Id == other.Id && LayoutId == other.LayoutId)
			{
				return Doors.SequenceEqual(other.Doors);
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			return Equals(obj as ExpeditionData);
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(Id, LayoutId);
		}
	}
	public enum Layer
	{
		Main,
		Secondary,
		Third
	}
	public class RundownData : IEquatable<RundownData>
	{
		public uint Id { get; init; }

		public string Name { get; init; }

		public List<ExpeditionData> Expeditions { get; init; }

		public RundownData(uint id, string name, List<ExpeditionData> expeditions)
		{
			Id = id;
			Name = name;
			Expeditions = expeditions;
		}

		public bool Equals(RundownData? other)
		{
			if (other == null)
			{
				return false;
			}
			if (Id == other.Id && Name == other.Name)
			{
				return Expeditions.SequenceEqual(other.Expeditions);
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			return Equals(obj as RundownData);
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(Id, Name);
		}
	}
	public class SecurityDoorData : IEquatable<SecurityDoorData>
	{
		public string Id { get; init; }

		public string Name { get; init; }

		public string Description { get; init; }

		public bool IsCheckpoint { get; set; }

		public SecurityDoorData(string id, string name, string description, bool isCheckpoint)
		{
			Id = id;
			Name = name;
			Description = description;
			IsCheckpoint = isCheckpoint;
		}

		public bool Equals(SecurityDoorData? other)
		{
			if (other == null)
			{
				return false;
			}
			if (Id == other.Id && Name == other.Name)
			{
				return Description == other.Description;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			return Equals(obj as SecurityDoorData);
		}

		public override int GetHashCode()
		{
			return HashCode.Combine(Id, Name, Description);
		}
	}
}