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(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(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(string path) where T : new() { string json = File.ReadAllText(path); T val = Deserialize(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(string json) { return System.Text.Json.JsonSerializer.Deserialize(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(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(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(text2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" = "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(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(text2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" = "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(value); } Logger.LogInfo(val); return; } val = new BepInExInfoLogInterpolatedStringHandler(4, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(text2); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(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((sourceArea != null) ? ((Object)sourceArea).name : null); } Log.Logger.LogWarning(val); data = GetCheckpointScanReplacement(); } } private static ChainedPuzzleDataBlock GetCheckpointScanReplacement() { return ((IEnumerable)GameDataBlockBase.GetAllBlocks()).FirstOrDefault((Func)((ChainedPuzzleDataBlock b) => ((GameDataBlockBase)(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 allBlocks = GameDataBlockBase.GetAllBlocks(); int count = allBlocks.Count; uint num = 0u; for (int i = 0; i < count; i++) { if (((GameDataBlockBase)(object)allBlocks[i]).persistentID > num) { num = ((GameDataBlockBase)(object)allBlocks[i]).persistentID; } } ChainedPuzzleComponent val = new ChainedPuzzleComponent { PuzzleType = 19u }; List val2 = new List(); 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)val3).name = "Checkpoint"; ((GameDataBlockBase)val3).internalEnabled = true; ((GameDataBlockBase)val3).persistentID = num + 1; ChainedPuzzleDataBlock val4 = val3; GameDataBlockBase.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(((GameDataBlockBase)(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? _config; public List? 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 list = _serializer.Read>(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("CustomCheckpoints.doors.json"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" configuration is invalid. See exception for details: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted(ex2.Message); } Log.Logger.LogWarning(val); return new List(); } catch (Exception ex3) { BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Unexpected error occured: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted(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 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 config) { List originalData = RundownDataManager.OriginalData; return !config.SequenceEqual(originalData); } private static string GetConfigFilepath() { return Path.Combine(Paths.ConfigPath, "CustomCheckpoints.doors.json"); } private void CreateConfig(List 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 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(ex.Message); } Log.Logger.LogError(val); throw; } } } public static class CustomCheckpointManager { public static int ReplaceDoorsForLevel(Dictionary> 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 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 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.GetBlock(layoutId); if (block == null) { return 0; } List zones = block.Zones; Il2CppArrayBase 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(securityDoorData.Name); } Log.Logger.LogInfo(val2); num++; } val.IsCheckpointDoor = securityDoorData.IsCheckpoint; items[i] = val; } return num; } } public static class RundownDataManager { public static readonly List OriginalData = RetrieveData(); public static List RetrieveData() { List list = new List(); Il2CppArrayBase allBlocks = GameDataBlockBase.GetAllBlocks(); int count = allBlocks.Count; for (int i = 0; i < count; i++) { RundownDataBlock obj = allBlocks[i]; List list2 = new List(); uint persistentID = ((GameDataBlockBase)(object)obj).persistentID; string name = ((GameDataBlockBase)(object)obj).name; List[] tiers = obj.GetTiers(); foreach (List val in tiers) { if (val == null) { continue; } Il2CppArrayBase items = val._items; int size = val._size; for (int k = 0; k < size; k++) { ExpeditionInTierData val2 = items[k]; if (val2 != null && val2.Enabled) { List doors = new List(); 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> GetDoorData(List 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 doors) { LevelLayoutDataBlock block = GameDataBlockBase.GetBlock(layoutId); if (block != null) { int zoneAliasStart = block.ZoneAliasStart; AddDoorsFromLayout(block, layer, doors, zoneAliasStart); } } private static void AddDoorsFromLayout(LevelLayoutDataBlock layout, Layer layer, List 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 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)(object)GameDataBlockBase.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?[] GetTiers(this RundownDataBlock? dataBlock) { return new List[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 { public string Id { get; init; } public uint LayoutId { get; init; } public List Doors { get; init; } public ExpeditionData(string id, uint layoutId, List 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 { public uint Id { get; init; } public string Name { get; init; } public List Expeditions { get; init; } public RundownData(uint id, string name, List 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 { 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); } } }