Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Benchwarp v1.2.0
plugins/Benchwarp.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using Benchwarp.Benches; using Benchwarp.Components; using Benchwarp.Data; using Benchwarp.Deploy; using Benchwarp.Doors; using Benchwarp.Doors.Obstacles; using Benchwarp.Events; using Benchwarp.Hotkeys; using Benchwarp.Patches; using Benchwarp.Settings; using Benchwarp.Util; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GlobalEnums; using HarmonyLib; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PrepatcherPlugin; using Silksong.AssetHelper.ManagedAssets; using Silksong.DataManager; using Silksong.FsmUtil; using Silksong.ModMenu.Elements; using Silksong.ModMenu.Plugin; using TeamCherry.Localization; using TeamCherry.NestedFadeGroup; using TeamCherry.SharedUtils; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Benchwarp")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+f0c6c37a4a1b7e85197233c19d4b7598f49ebcbf")] [assembly: AssemblyProduct("Benchwarp")] [assembly: AssemblyTitle("Benchwarp")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/homothetyhk/Silksong.Benchwarp")] [assembly: NeutralResourcesLanguage("EN")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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; } } [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 System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class UnscopedRefAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class SkipLocalsInitAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class RequiresLocationAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ExtensionMarkerAttribute : Attribute { public string Name { get; } public ExtensionMarkerAttribute(string name) { Name = name; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CompilerLoweringPreserveAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] [Embedded] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] [Embedded] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Embedded] [AttributeUsage(AttributeTargets.All)] [ExcludeFromCodeCoverage] internal sealed class EmbeddedAttribute : Attribute { } } namespace Benchwarp { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("io.github.homothetyhk.benchwarp", "Benchwarp", "1.2.0")] public class BenchwarpPlugin : BaseUnityPlugin, IModMenuCustomElement, IModMenuInterface, ISaveDataMod<SaveSettingsData>, IRawSaveDataMod, IGlobalDataMod<SharedSettingsData>, IRawGlobalDataMod { private static BenchwarpPlugin? _instance; [CompilerGenerated] private TextButton <ModMenuEntryButton>k__BackingField; public const string Id = "io.github.homothetyhk.benchwarp"; public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger; public static BenchwarpPlugin Instance => _instance ?? throw new NullReferenceException("Benchwarp has not loaded yet!"); private bool StartCalled { get; set; } private string HarmonyID { get; } = Name + " (io.github.homothetyhk.benchwarp)"; internal TextButton ModMenuEntryButton { get { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown if (<ModMenuEntryButton>k__BackingField == null || !Object.op_Implicit((Object)(object)<ModMenuEntryButton>k__BackingField.MenuButton)) { SelectableElement val = default(SelectableElement); new ConfigEntryFactory().GenerateEntryButton(LocalizedText.op_Implicit("Benchwarp"), (BaseUnityPlugin)(object)this, ref val); <ModMenuEntryButton>k__BackingField = (TextButton)val; } return <ModMenuEntryButton>k__BackingField; } } public static ConfigSettings ConfigSettings { get; private set; } = null; public static SaveSettings SaveSettings { get; } = new SaveSettings(new SaveSettingsData()); public static SharedSettings SharedSettings { get; } = new SharedSettings(new SharedSettingsData()); SaveSettingsData? ISaveDataMod<SaveSettingsData>.SaveData { get { return SaveSettings.GetSerializationData(); } set { SaveSettings.Load(value ?? new SaveSettingsData()); } } SharedSettingsData? IGlobalDataMod<SharedSettingsData>.GlobalData { get { return SharedSettings.GetSerializationData(); } set { SharedSettings.Load(value ?? new SharedSettingsData()); } } public static string Name => "Benchwarp"; public static string Version => "1.2.0"; private BenchwarpPlugin() { _instance = this; ConfigSettings = DefineConfig(); } private void Awake() { try { ((Component)this).gameObject.AddComponent<RespawnChangeListener>(); LoadAssets(); LogHelper.Log("Plugin " + Name + " (io.github.homothetyhk.benchwarp) has loaded!"); } catch (Exception e) { LogHelper.LogError(GetErrorMsg(e, "Awake")); } } private void OnEnable() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!StartCalled) { return; } try { new Harmony(HarmonyID).PatchAll(((object)this).GetType().Assembly); ShakraPDHook.Hook(); DataManagerFix.Hook(); RedeployPatch.Hook(); StyxBenchFix.Hook(); GUIController.Setup(); } catch (Exception e) { LogHelper.LogError(GetErrorMsg(e, "OnEnable")); } } private void Start() { StartCalled = true; try { OnEnable(); GUIController.LateSetup(); } catch (Exception e) { LogHelper.LogError(GetErrorMsg(e, "Start")); } } private void OnDisable() { try { Harmony.UnpatchID(HarmonyID); ShakraPDHook.Unhook(); DataManagerFix.Unhook(); RedeployPatch.Unhook(); StyxBenchFix.Unhook(); GUIController.Unload(); } catch (Exception e) { LogHelper.LogError(GetErrorMsg(e, "OnDisable")); } } private string GetErrorMsg(Exception e, [CallerMemberName] string? caller = "") { return $"Error during {((object)this).GetType().Name}.{caller}:\n{e}"; } private void LoadAssets() { DeployAssets.Bench = ManagedAsset<GameObject>.FromSceneAsset("Bone_04", "RestBench"); } SelectableElement IModMenuCustomElement.BuildCustomElement() { return (SelectableElement)(object)ModMenuEntryButton; } private ConfigSettings DefineConfig() { //IL_0010: 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_002b: Expected O, but got Unknown //IL_002b: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0057: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_0083: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00af: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_00db: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_0108: Expected O, but got Unknown ConfigEntry<MenuMode> menuMode = ((BaseUnityPlugin)this).Config.Bind<MenuMode>(new ConfigDefinition("Menu", "MenuMode"), MenuMode.StandardBenchwarp, new ConfigDescription("See README.md for details on modes.", (AcceptableValueBase)null, Array.Empty<object>())); ConfigEntry<bool> showScene = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Menu", "ShowScene"), false, new ConfigDescription("Displays a panel in the bottom-left with the active scene name.", (AcceptableValueBase)null, Array.Empty<object>())); ConfigEntry<bool> alwaysToggleAll = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Menu", "AlwaysToggleAll"), false, new ConfigDescription("Auto-expand all dropdown panels.", (AcceptableValueBase)null, Array.Empty<object>())); ConfigEntry<bool> enableDeploy = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Menu", "EnableDeploy"), true, new ConfigDescription("Enables placing a bench at the current location through the menu.", (AcceptableValueBase)null, Array.Empty<object>())); ConfigEntry<bool> enableHotkeys = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Menu", "EnableHotkeys"), false, new ConfigDescription("See README.md for information on supported commands.", (AcceptableValueBase)null, Array.Empty<object>())); ConfigEntry<bool> recoveryMode = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Menu", "RecoveryMode"), false, new ConfigDescription("Use if you get stuck. While active, any file loaded will spawn into the starting area in Moss Grotto.", (AcceptableValueBase)null, Array.Empty<object>())); return new ConfigSettings(new ConfigSettingsData { MenuMode = menuMode, ShowScene = showScene, AlwaysToggleAll = alwaysToggleAll, EnableDeploy = enableDeploy, EnableHotkeys = enableHotkeys, RecoveryMode = recoveryMode }); } } public static class ChangeScene { private class DoorwarpSceneLoadInfo(IObstacleHandler handler, RoomData room, DoorData gate, IObstacleProvider provider) : SceneLoadInfo() { public override void NotifyFetchComplete() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown ((SceneLoadInfo)this).NotifyFetchComplete(); GameManager.instance.sceneLoad.ActivationComplete += new ActivationCompleteDelegate(ActivationComplete); } private void ActivationComplete() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) GameManager.instance.sceneLoad.ActivationComplete -= new ActivationCompleteDelegate(ActivationComplete); Scene activeScene = SceneManager.GetActiveScene(); handler.OnSceneChange(activeScene, room, gate, provider); } } public static void WarpToRespawn() { GameManager gm = GameManager.instance; if ((Object)(object)gm == (Object)null) { LogHelper.LogError("WarpToRespawn called while GameManager is null, aborting..."); return; } ModEvents.InvokeOnBenchwarp(); PlayerDataAccess.atBench = false; gm.SaveGame((Action<bool>)delegate(bool worked) { if (worked) { gm.LoadGameFromUI(gm.profileID); } }); ((MonoBehaviour)gm).StartCoroutine(gm.PauseGameToggle(false)); } public static void WarpToDoor(RoomData room, DoorData gate) { if ((Object)(object)GameManager.instance == (Object)null) { LogHelper.LogError("WarpToRespawn called while GameManager is null, aborting..."); return; } ModEvents.InvokeOnDoorwarp(room, gate); ((MonoBehaviour)BenchwarpPlugin.Instance).StartCoroutine(DoWarpToDoor(room, gate)); } private static IEnumerator DoWarpToDoor(RoomData room, DoorData gate) { if (GameManager.instance.IsGamePaused()) { yield return GameManager.instance.PauseGameToggleByMenu(); } PlayerDataAccess.atBench = false; if ((Object)(object)HeroController.SilentInstance != (Object)null) { if (HeroController.instance.cState.onConveyor || HeroController.instance.cState.onConveyorV || HeroController.instance.cState.inConveyorZone) { ConveyorMovementHero component = ((Component)HeroController.instance).GetComponent<ConveyorMovementHero>(); if (component != null) { component.StopConveyorMove(); } HeroController.instance.cState.inConveyorZone = false; HeroController.instance.cState.onConveyor = false; HeroController.instance.cState.onConveyorV = false; } HeroController.instance.cState.nearBench = false; } SceneLoad sceneLoad = GameManager.instance.sceneLoad; if (sceneLoad != null) { sceneLoad.Finish += new FinishDelegate(Warp); } else { Warp(); } void Warp() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) IObstacleHandler doorwarpObstacleHandler = ModEvents.DoorwarpObstacleHandler; IObstacleProvider doorwarpObstacleProvider = ModEvents.DoorwarpObstacleProvider; doorwarpObstacleHandler.BeforeTransition(room, gate, doorwarpObstacleProvider); GameManager.instance.BeginSceneTransition((SceneLoadInfo)(object)new DoorwarpSceneLoadInfo(doorwarpObstacleHandler, room, gate, doorwarpObstacleProvider) { SceneName = gate.Self.SceneName, EntryGateName = gate.Self.GateName, PreventCameraFadeOut = false, WaitForSceneTransitionCameraFade = true, Visualization = (SceneLoadVisualizations)0, AlwaysUnloadUnusedAssets = true, IsFirstLevelForPlayer = false }); } } } } namespace Benchwarp.Util { public static class JsonUtil { private class Vector2Converter : JsonConverter<Vector2> { public override Vector2 ReadJson(JsonReader reader, Type objectType, Vector2 existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Invalid comparison between Unknown and I4 float num = 0f; float num2 = 0f; while (reader.Read()) { if ((int)reader.TokenType == 4) { string text = (string)reader.Value; if (!(text == "x")) { if (text == "y") { num2 = (float)reader.ReadAsDouble().Value; } } else { num = (float)reader.ReadAsDouble().Value; } } else if ((int)reader.TokenType == 13) { break; } } return new Vector2(num, num2); } public override void WriteJson(JsonWriter writer, Vector2 value, JsonSerializer serializer) { //IL_0012: 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) writer.WriteStartObject(); writer.WritePropertyName("x"); writer.WriteValue(value.x); writer.WritePropertyName("y"); writer.WriteValue(value.y); writer.WriteEndObject(); } } private class Vector3Converter : JsonConverter<Vector3> { public override Vector3 ReadJson(JsonReader reader, Type objectType, Vector3 existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 float num = 0f; float num2 = 0f; float num3 = 0f; while (reader.Read()) { if ((int)reader.TokenType == 4) { switch ((string)reader.Value) { case "x": num = (float)reader.ReadAsDouble().Value; break; case "y": num2 = (float)reader.ReadAsDouble().Value; break; case "z": num3 = (float)reader.ReadAsDouble().Value; break; } } else if ((int)reader.TokenType == 13) { break; } } return new Vector3(num, num2, num3); } public override void WriteJson(JsonWriter writer, Vector3 value, JsonSerializer serializer) { //IL_0012: 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) //IL_0040: Unknown result type (might be due to invalid IL or missing references) writer.WriteStartObject(); writer.WritePropertyName("x"); writer.WriteValue(value.x); writer.WritePropertyName("y"); writer.WriteValue(value.y); writer.WritePropertyName("z"); writer.WriteValue(value.z); writer.WriteEndObject(); } } public static readonly JsonSerializer _js; public static T Deserialize<T>(string embeddedResourcePath) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown using StreamReader streamReader = new StreamReader(typeof(JsonUtil).Assembly.GetManifestResourceStream(embeddedResourcePath)); JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { return _js.Deserialize<T>((JsonReader)(object)val); } finally { ((IDisposable)val)?.Dispose(); } } public static T DeserializeString<T>(string json) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using StringReader stringReader = new StringReader(json); JsonTextReader val = new JsonTextReader((TextReader)stringReader); try { return _js.Deserialize<T>((JsonReader)(object)val); } finally { ((IDisposable)val)?.Dispose(); } } public static T DeserializeFile<T>(string filepath) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown using StreamReader streamReader = new StreamReader(File.OpenRead(filepath)); JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { return _js.Deserialize<T>((JsonReader)(object)val); } finally { ((IDisposable)val)?.Dispose(); } } public static void SerializeFile(object o, string filePath) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using StreamWriter streamWriter = File.CreateText(filePath); JsonTextWriter val = new JsonTextWriter((TextWriter)streamWriter); try { _js.Serialize((JsonWriter)(object)val, o); } finally { ((IDisposable)val)?.Dispose(); } } public static void SerializeFileNearDLL(object o, string fileName) { File.WriteAllText(Path.Combine(Path.GetDirectoryName(typeof(JsonUtil).Assembly.Location), fileName), Serialize(o)); } public static string Serialize(object o) { using StringWriter stringWriter = new StringWriter(); _js.Serialize((TextWriter)stringWriter, o); stringWriter.Flush(); return stringWriter.ToString(); } static JsonUtil() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown _js = new JsonSerializer { DefaultValueHandling = (DefaultValueHandling)1, Formatting = (Formatting)1, TypeNameHandling = (TypeNameHandling)4 }; ((Collection<JsonConverter>)(object)_js.Converters).Add((JsonConverter)new StringEnumConverter()); ((Collection<JsonConverter>)(object)_js.Converters).Add((JsonConverter)(object)new Vector2Converter()); ((Collection<JsonConverter>)(object)_js.Converters).Add((JsonConverter)(object)new Vector3Converter()); } } public class KeyedEvent<TKey, TDelegate> where TDelegate : Delegate { public interface IKeyedEventOwner { TDelegate? GetDelegate(TKey key); } private class KeyedEventOwner(KeyedEvent<TKey, TDelegate> e) : IKeyedEventOwner { public TDelegate? GetDelegate(TKey key) { if (!<e>P.lookup.TryGetValue(key, out TDelegate value)) { return null; } return value; } } private readonly Dictionary<TKey, TDelegate?> lookup = new Dictionary<TKey, TDelegate>(); private readonly IKeyedEventOwner _owner; public KeyedEvent(out IKeyedEventOwner owner) { owner = (_owner = new KeyedEventOwner(this)); } public void Add(TKey key, TDelegate? value) { if (lookup.TryGetValue(key, out TDelegate value2)) { lookup[key] = (TDelegate)Delegate.Combine(value2, value); } else { lookup.Add(key, value); } } public void Remove(TKey key, TDelegate? value) { if (lookup.TryGetValue(key, out TDelegate value2)) { lookup[key] = (TDelegate)Delegate.Remove(value2, value); } } } public static class KeyedEventOwnerExtensions { [SpecialName] public sealed class <G>$C6A9B8DD00F1E45F26342E72D02C8C27<$T0> { [SpecialName] public static class <M>$E0AA760A0F8D6A1A9BBB3F6C99B2F6C4 { } [ExtensionMarker("<M>$E0AA760A0F8D6A1A9BBB3F6C99B2F6C4")] public void Invoke($T0 key, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } [SpecialName] public sealed class <G>$526F89CC70AF37E7C53F29AE13CF9C13<$T0, $T1> { [SpecialName] public static class <M>$75DC55BFFF8E5AD2F3C72A4A5C4E024A { } [ExtensionMarker("<M>$75DC55BFFF8E5AD2F3C72A4A5C4E024A")] public void Invoke($T0 key, $T1 arg, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } [SpecialName] public sealed class <G>$AD3E2172C724280323F6120772B0167B<$T0, $T1, $T2> { [SpecialName] public static class <M>$CFD08ADC185F78A9B822255600266AF9 { } [ExtensionMarker("<M>$CFD08ADC185F78A9B822255600266AF9")] public void Invoke($T0 key, $T1 arg1, $T2 arg2, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } public static void Invoke<TKey>(this KeyedEvent<TKey, Action>.IKeyedEventOwner owner, TKey key, [CallerMemberName] string? caller = "") { try { owner.GetDelegate(key)?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error invoking delegate from {caller} for key {key}:\n{arg}"); } } public static void Invoke<TKey, TArg>(this KeyedEvent<TKey, Action<TArg>>.IKeyedEventOwner owner, TKey key, TArg arg, [CallerMemberName] string? caller = "") { try { owner.GetDelegate(key)?.Invoke(arg); } catch (Exception ex) { LogHelper.LogError($"Error invoking delegate from {caller} for key {key} with arg {arg}:\n{ex}"); } } public static void Invoke<TKey, TArg1, TArg2>(this KeyedEvent<TKey, Action<TArg1, TArg2>>.IKeyedEventOwner owner, TKey key, TArg1 arg1, TArg2 arg2, [CallerMemberName] string? caller = "") { try { owner.GetDelegate(key)?.Invoke(arg1, arg2); } catch (Exception ex) { LogHelper.LogError($"Error invoking delegate from {caller} for key {key} with args {arg1}, {arg2}:\n{ex}"); } } } internal static class Localization { private const string Sheet = "Mods.io.github.homothetyhk.benchwarp"; public static string GetLanguageString(this string key) { return Language.Get(key, "Mods.io.github.homothetyhk.benchwarp"); } } internal static class LogHelper { public static void Log(object? o) { BenchwarpPlugin.Instance.Logger.LogInfo(o); } public static void LogError(object? o) { BenchwarpPlugin.Instance.Logger.LogError(o); } public static void LogWarn(object? o) { BenchwarpPlugin.Instance.Logger.LogWarning(o); } } internal static class SceneExtensions { private static readonly List<GameObject> rootObjects = new List<GameObject>(500); public static GameObject? FindGameObject(this Scene s, string path, bool warnIfNotFound) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) ((Scene)(ref s)).GetRootGameObjects(rootObjects); int num = path.IndexOf('/'); GameObject val = null; if (num >= 0) { string text = path.Substring(0, num); foreach (GameObject rootObject in rootObjects) { if (!(((Object)rootObject).name != text)) { Transform obj = rootObject.transform.Find(path.Substring(num + 1)); val = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)val != (Object)null) { break; } } } } else { val = ((IEnumerable<GameObject>)rootObjects).FirstOrDefault((Func<GameObject, bool>)((GameObject g) => ((Object)g).name == path)); } if (!Object.op_Implicit((Object)(object)val) && warnIfNotFound) { LogHelper.LogWarn("Failed to find object " + path + " in scene " + ((Scene)(ref s)).name + ". Existing objects are " + s.Dump() + "."); } rootObjects.Clear(); return val; } private static string Dump(this Scene s) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return string.Join("\n", from p in s.Traverse() select p.path); } private static List<(string path, GameObject go)> Traverse(this Scene s) { ((Scene)(ref s)).GetRootGameObjects(rootObjects); List<(string, GameObject)> list = new List<(string, GameObject)>(); foreach (GameObject rootObject in rootObjects) { TraverseInternal(string.Empty, rootObject.transform, list); } return list; } private static void TraverseInternal(string path, Transform t, List<(string, GameObject)> results) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown path = path + "/" + ((Object)t).name; results.Add((path, ((Component)t).gameObject)); foreach (Transform item in t) { Transform t2 = item; TraverseInternal(path, t2, results); } } } public class SequentialEvent<TDelegate> where TDelegate : Delegate { public interface ISequentialEventOwner { event Action? OnSubscribersChanged; IReadOnlyList<TDelegate> GetSubscribers(); } private class SequentialEventOwner(SequentialEvent<TDelegate> e) : ISequentialEventOwner { event Action? ISequentialEventOwner.OnSubscribersChanged { add { <e>P.OnSubscribersChanged += value; } remove { <e>P.OnSubscribersChanged -= value; } } IReadOnlyList<TDelegate> ISequentialEventOwner.GetSubscribers() { return <e>P.modifiers; } } private readonly List<TDelegate> modifiers = new List<TDelegate>(); private event Action? OnSubscribersChanged; public SequentialEvent(out ISequentialEventOwner owner) { owner = new SequentialEventOwner(this); } public void Add(TDelegate value) { modifiers.Add(value); this.OnSubscribersChanged?.Invoke(); } public void Remove(TDelegate value) { modifiers.Remove(value); this.OnSubscribersChanged?.Invoke(); } } public static class SequentialEventOwnerExtensions { [SpecialName] public sealed class <G>$CB57ABAC9FA4DBD61648592FA42C6095<$T0> { [SpecialName] public static class <M>$4243BAC63842EF50C4174920157E6FF2 { } [ExtensionMarker("<M>$4243BAC63842EF50C4174920157E6FF2")] public $T0 InvokeToTransform($T0 seed, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } [SpecialName] public sealed class <G>$F4F1B1619584B33AEBBA06C2121E2406<$T0, $T1> { [SpecialName] public static class <M>$5EF27F45C57A844E76D1FCF3BDDAC56E { } [ExtensionMarker("<M>$5EF27F45C57A844E76D1FCF3BDDAC56E")] public $T0 InvokeToTransform($T1 arg, $T0 seed, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } [SpecialName] public sealed class <G>$881BC38AE16CB7B346ABE66097582785<$T0> { [SpecialName] public static class <M>$6F70E36BFD44005BEBACCCB3BC775833 { } [ExtensionMarker("<M>$6F70E36BFD44005BEBACCCB3BC775833")] public List<$T0> InvokeAndCollect([CallerMemberName] string? caller = "") { throw new NotSupportedException(); } [ExtensionMarker("<M>$6F70E36BFD44005BEBACCCB3BC775833")] public TResult InvokeAndAggregate<TResult>(TResult seed, Func<TResult, $T0, TResult> combiner, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } [SpecialName] public sealed class <G>$DFECCCE3C66174E09FBA0B45DD8E5E82<$T0, $T1> { [SpecialName] public static class <M>$3142026A3634B7EA2AB5FCFAB1CBE662 { } [ExtensionMarker("<M>$3142026A3634B7EA2AB5FCFAB1CBE662")] public List<$T0> InvokeAndCollect($T1 arg, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } [ExtensionMarker("<M>$3142026A3634B7EA2AB5FCFAB1CBE662")] public TResult InvokeAndAggregate<TResult>($T1 arg, TResult seed, Func<TResult, $T0, TResult> combiner, [CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } [SpecialName] public sealed class <G>$6E033FA2D58B6339F639C8FC929EA571<$T0> { [SpecialName] public static class <M>$DCF101354DBCC7F6F23431DACBC4D482 { } [ExtensionMarker("<M>$DCF101354DBCC7F6F23431DACBC4D482")] public List<$T0> InvokeAndCollectFlat([CallerMemberName] string? caller = "") { throw new NotSupportedException(); } } public static TValue InvokeToTransform<TValue>(this SequentialEvent<Func<TValue, TValue>>.ISequentialEventOwner owner, TValue seed, [CallerMemberName] string? caller = "") { foreach (Func<TValue, TValue> subscriber in owner.GetSubscribers()) { try { seed = subscriber(seed); } catch (Exception arg) { LogHelper.LogError($"Error invoking sequential transformer from {caller}:\n{arg}"); } } return seed; } public static TValue InvokeToTransform<TValue, TArg>(this SequentialEvent<Func<TArg, TValue, TValue>>.ISequentialEventOwner owner, TArg arg, TValue seed, [CallerMemberName] string? caller = "") { foreach (Func<TArg, TValue, TValue> subscriber in owner.GetSubscribers()) { try { seed = subscriber(arg, seed); } catch (Exception arg2) { LogHelper.LogError($"Error invoking sequential transformer from {caller}:\n{arg2}"); } } return seed; } public static List<TValue> InvokeAndCollect<TValue>(this SequentialEvent<Func<TValue>>.ISequentialEventOwner owner, [CallerMemberName] string? caller = "") { IReadOnlyList<Func<TValue>> subscribers = owner.GetSubscribers(); List<TValue> list = new List<TValue>(subscribers.Count); foreach (Func<TValue> item2 in subscribers) { try { TValue item = item2(); list.Add(item); } catch (Exception arg) { LogHelper.LogError($"Error invoking subscriber to {caller}:\n{arg}"); } } return list; } public static TResult InvokeAndAggregate<TValue, TResult>(this SequentialEvent<Func<TValue>>.ISequentialEventOwner owner, TResult seed, Func<TResult, TValue, TResult> combiner, [CallerMemberName] string? caller = "") { foreach (Func<TValue> subscriber in owner.GetSubscribers()) { try { TValue arg = subscriber(); seed = combiner(seed, arg); } catch (Exception arg2) { LogHelper.LogError($"Error invoking sequential aggreator from {caller}:\n{arg2}"); } } return seed; } public static List<TValue> InvokeAndCollect<TValue, TArg>(this SequentialEvent<Func<TArg, TValue>>.ISequentialEventOwner owner, TArg arg, [CallerMemberName] string? caller = "") { IReadOnlyList<Func<TArg, TValue>> subscribers = owner.GetSubscribers(); List<TValue> list = new List<TValue>(subscribers.Count); foreach (Func<TArg, TValue> item2 in subscribers) { try { TValue item = item2(arg); list.Add(item); } catch (Exception arg2) { LogHelper.LogError($"Error invoking subscriber to {caller}:\n{arg2}"); } } return list; } public static TResult InvokeAndAggregate<TValue, TArg, TResult>(this SequentialEvent<Func<TArg, TValue>>.ISequentialEventOwner owner, TArg arg, TResult seed, Func<TResult, TValue, TResult> combiner, [CallerMemberName] string? caller = "") { foreach (Func<TArg, TValue> subscriber in owner.GetSubscribers()) { try { TValue arg2 = subscriber(arg); seed = combiner(seed, arg2); } catch (Exception arg3) { LogHelper.LogError($"Error invoking sequential aggreator from {caller} with arg {arg}:\n{arg3}"); } } return seed; } public static List<TValue> InvokeAndCollectFlat<TValue>(this SequentialEvent<Func<IEnumerable<TValue>>>.ISequentialEventOwner owner, [CallerMemberName] string? caller = "") { IReadOnlyList<Func<IEnumerable<TValue>>> subscribers = owner.GetSubscribers(); List<TValue> list = new List<TValue>(subscribers.Count); foreach (Func<IEnumerable<TValue>> item in subscribers) { try { IEnumerable<TValue> collection = item(); list.AddRange(collection); } catch (Exception arg) { LogHelper.LogError($"Error invoking subscriber to {caller}:\n{arg}"); } } return list; } } internal static class SpriteManager { public static Texture2D LoadTexFromAssembly(string resourceName) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_007f: Expected O, but got Unknown using Stream stream = typeof(SpriteManager).Assembly.GetManifestResourceStream(resourceName); if (stream == null) { LogHelper.LogError("Failed to load " + resourceName + ". The embedded resources are " + string.Join(", ", typeof(SpriteManager).Assembly.GetManifestResourceNames())); throw new KeyNotFoundException(resourceName); } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)72, false); ImageConversion.LoadImage(val, array); return val; } } internal class StableComparer<T> : IComparer<KeyValuePair<int, T>> { private readonly IComparer<T> comparer; public StableComparer(IComparer<T> comparison) { comparer = comparison; } public static Comparison<KeyValuePair<int, T>> GetStableComparison(Comparison<T> comparison) { return CompareTo; int CompareTo(KeyValuePair<int, T> x, KeyValuePair<int, T> y) { int num = comparison(x.Value, y.Value); if (num == 0) { return x.Key - y.Key; } return num; } } public int Compare(KeyValuePair<int, T> x, KeyValuePair<int, T> y) { int num = comparer.Compare(x.Value, y.Value); if (num == 0) { return x.Key - y.Key; } return num; } } internal static class StableSortExtension { internal static void StableSort<T>(this IList<T> ts, Comparison<T> comparison) { KeyValuePair<int, T>[] array = new KeyValuePair<int, T>[ts.Count]; for (int i = 0; i < ts.Count; i++) { array[i] = new KeyValuePair<int, T>(i, ts[i]); } Array.Sort(array, StableComparer<T>.GetStableComparison(comparison)); for (int j = 0; j < ts.Count; j++) { ts[j] = array[j].Value; } } } } namespace Benchwarp.Settings { public class ConfigSettings { private readonly ConfigSettingsData data; public MenuMode MenuMode { get { return data.MenuMode.Value; } set { data.MenuMode.Value = value; } } public bool ShowScene { get { return data.ShowScene.Value; } set { data.ShowScene.Value = value; } } public bool AlwaysToggleAll { get { return data.AlwaysToggleAll.Value; } set { data.AlwaysToggleAll.Value = value; } } public bool EnableDeploy { get { return data.EnableDeploy.Value; } set { data.EnableDeploy.Value = value; } } public bool EnableHotkeys { get { return data.EnableHotkeys.Value; } set { data.EnableHotkeys.Value = value; } } public bool RecoveryMode { get { return data.RecoveryMode.Value; } set { data.RecoveryMode.Value = value; } } internal static event Action? OnMenuModeChanged; internal static event Action? OnShowSceneChanged; internal static event Action? OnAlwaysToggleAllChanged; internal static event Action? OnEnableDeployChanged; internal static event Action? OnEnableHotkeysChanged; internal static event Action? OnRecoveryModeChanged; public ConfigSettings(ConfigSettingsData data) { this.data = data; data.MenuMode.SettingChanged += delegate { Invoke(ConfigSettings.OnMenuModeChanged, ".ctor"); }; data.ShowScene.SettingChanged += delegate { Invoke(ConfigSettings.OnShowSceneChanged, ".ctor"); }; data.AlwaysToggleAll.SettingChanged += delegate { Invoke(ConfigSettings.OnAlwaysToggleAllChanged, ".ctor"); }; data.EnableHotkeys.SettingChanged += delegate { Invoke(ConfigSettings.OnEnableHotkeysChanged, ".ctor"); }; data.EnableDeploy.SettingChanged += delegate { Invoke(ConfigSettings.OnEnableDeployChanged, ".ctor"); }; data.RecoveryMode.SettingChanged += delegate { Invoke(ConfigSettings.OnRecoveryModeChanged, ".ctor"); }; } internal static void Invoke(Action? a, [CallerMemberName] string? caller = "") { try { a?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error in update event for {caller}:\n{arg}"); } } internal static void Invoke<T>(Action<T>? a, T arg, [CallerMemberName] string? caller = "") { try { a?.Invoke(arg); } catch (Exception arg2) { LogHelper.LogError($"Error in update event for {caller}:\n{arg2}"); } } } public class ConfigSettingsData { public required ConfigEntry<MenuMode> MenuMode { get; init; } public required ConfigEntry<bool> ShowScene { get; init; } public required ConfigEntry<bool> AlwaysToggleAll { get; init; } public required ConfigEntry<bool> EnableDeploy { get; init; } public required ConfigEntry<bool> EnableHotkeys { get; init; } public required ConfigEntry<bool> RecoveryMode { get; init; } } public enum MenuMode { [Description("StandardBenchwarp: warp to visited benches only.")] StandardBenchwarp, [Description("WarpOnly: warp to current respawn only.")] WarpOnly, [Description("UnlockAll: warp to any bench.")] UnlockAll, [Description("DoorWarp: warp to room transitions.")] DoorWarp } public class SaveSettings(SaveSettingsData data) { private SaveSettingsData data = data; private static readonly KeyedEvent<BenchKey, Action<bool>>.IKeyedEventOwner onSetVisitedLocalOwner; private static readonly KeyedEvent<BenchKey, Action<bool>>.IKeyedEventOwner onSetLockedLocalOwner; internal static KeyedEvent<BenchKey, Action<bool>> OnSetVisitedLocal { get; } = new KeyedEvent<BenchKey, Action<bool>>(out onSetVisitedLocalOwner); internal static KeyedEvent<BenchKey, Action<bool>> OnSetLockedLocal { get; } = new KeyedEvent<BenchKey, Action<bool>>(out onSetLockedLocalOwner); public DeployInfo? DeployInfo { get { return data.DeployInfo; } set { data.DeployInfo = value; Invoke(SaveSettings.OnDeployInfoChanged, "DeployInfo"); } } internal static event Action<BenchKey, bool>? OnSetVisitedGlobal; internal static event Action<BenchKey, bool>? OnSetLocked; internal static event Action? OnDeployInfoChanged; internal static event Action? OnNewSettingsLoaded; public bool IsVisited(BenchKey key) { return data.VisitedBenches.Contains(key); } public bool IsLocked(BenchKey key) { return data.LockedBenches.Contains(key); } public void SetVisited(BenchKey key, bool value) { if (IsLocked(key)) { return; } if (value) { if (data.VisitedBenches.Add(key)) { Invoke(SaveSettings.OnSetVisitedGlobal, key, value, "SetVisited"); onSetVisitedLocalOwner.Invoke(key, value, "SetVisited"); } } else if (data.VisitedBenches.Remove(key)) { Invoke(SaveSettings.OnSetVisitedGlobal, key, value, "SetVisited"); onSetVisitedLocalOwner.Invoke(key, value, "SetVisited"); } } public void SetLocked(BenchKey key, bool value) { if (value) { if (data.LockedBenches.Add(key)) { Invoke(SaveSettings.OnSetLocked, key, value, "SetLocked"); onSetLockedLocalOwner.Invoke(key, value, "SetLocked"); } } else if (data.LockedBenches.Remove(key)) { Invoke(SaveSettings.OnSetLocked, key, value, "SetLocked"); onSetLockedLocalOwner.Invoke(key, value, "SetLocked"); } } private static void Invoke(Action? a, [CallerMemberName] string? caller = "") { try { a?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error in update event for {caller}:\n{arg}"); } } private static void Invoke<T1, T2>(Action<T1, T2>? a, T1 arg1, T2 arg2, [CallerMemberName] string? caller = "") { try { a?.Invoke(arg1, arg2); } catch (Exception arg3) { LogHelper.LogError($"Error invoking global update event for {caller}:\n{arg3}"); } } internal SaveSettingsData GetSerializationData() { return data; } internal void Load(SaveSettingsData data) { this.data = data; try { SaveSettings.OnNewSettingsLoaded?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error invoking OnNewSettingsLoaded:\n{arg}"); } } } public class SaveSettingsData { public DeployInfo? DeployInfo; public HashSet<BenchKey> VisitedBenches = new HashSet<BenchKey>(); public HashSet<BenchKey> LockedBenches = new HashSet<BenchKey>(); } public class SharedSettings(SharedSettingsData data) { private SharedSettingsData data = data; public DeployStyles DeployStyle { get { return data.DeployStyle; } set { data.DeployStyle = value; Invoke(SharedSettings.OnDeployStyleChanged, "DeployStyle"); } } internal static event Action? OnDeployStyleChanged; internal static event Action? OnNewSettingsLoaded; internal string GetHotkey(string code) { if (!data.HotkeyOverrides.TryGetValue(code, out string value)) { return code; } return value; } internal SharedSettingsData GetSerializationData() { return data; } internal void Load(SharedSettingsData data) { this.data = data; try { SharedSettings.OnNewSettingsLoaded?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error invoking OnNewSettingsLoaded:\n{arg}"); } } internal static void Invoke(Action? a, [CallerMemberName] string? caller = "") { try { a?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error in update event for {caller}:\n{arg}"); } } } public class SharedSettingsData { public DeployStyles DeployStyle = DeployStyles.Bone; public Dictionary<string, string> HotkeyOverrides = new Dictionary<string, string>(); internal static SharedSettingsData CreateDefault() { return new SharedSettingsData { HotkeyOverrides = new Dictionary<string, string> { ["LB"] = "LB", ["SB"] = "SB", ["DW"] = "DW", ["NP"] = "NP", ["WD"] = "WD", ["DB"] = "DB" } }; } } } namespace Benchwarp.Patches { internal static class DataManagerFix { internal static void Hook() { SceneManager.activeSceneChanged += OnMenu; } internal static void Unhook() { SceneManager.activeSceneChanged -= OnMenu; } private static void OnMenu(Scene from, Scene to) { if (((Scene)(ref to)).name == "Menu_Title") { BenchwarpPlugin.SaveSettings.Load(new SaveSettingsData()); } } } [HarmonyPatch(typeof(SceneAdditiveLoadConditional), "OnWasLoaded")] internal static class FleaGamesStartBenchFix { [HarmonyPostfix] public static void OnWasLoaded(SceneAdditiveLoadConditional __instance) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) if (!(__instance.SceneNameToLoad == "Aqueduct_05_festival") || !PlayerDataAccess.FleaGamesCanStart || PlayerDataAccess.FleaGamesStarted) { return; } RespawnInfo respawnInfo = RespawnInfo.FromPlayerData(); if (!(respawnInfo.SceneName == "Aqueduct_05") || (!(respawnInfo.RespawnMarkerName == "RestBench") && !(respawnInfo.RespawnMarkerName == "RestBench Festival"))) { return; } Scene s = Enumerable.Range(0, SceneManager.sceneCount).Select((Func<int, Scene>)SceneManager.GetSceneAt).First((Scene val2) => ((Scene)(ref val2)).name == "Aqueduct_05_festival"); string[] array = new string[2] { "Caravan_States/Flea Festival/Festival_Feast/RestBench Festival", "Caravan_States/Flea Festival/Festival_Feast/Bench (1)" }; foreach (string path in array) { GameObject val = s.FindGameObject(path, warnIfNotFound: true); if (!((Object)(object)val == (Object)null)) { val.transform.SetParent((Transform)null, true); val.SetActive(true); } } if (respawnInfo.RespawnMarkerName != "RestBench Festival") { PlayerDataAccess.respawnMarkerName = "RestBench Festival"; } } } [HarmonyPatch(typeof(GameManager), "GetRespawnInfo")] internal static class OverrideKnownRespawnPatch { [HarmonyPrefix] private static bool OverrideGetRespawnInfo(ref string scene, ref string marker) { DeployInfo deployInfo = BenchwarpPlugin.SaveSettings.DeployInfo; if ((object)deployInfo != null && deployInfo.IsCurrentRespawn()) { scene = deployInfo.RespawnInfo.SceneName; marker = deployInfo.RespawnInfo.RespawnMarkerName; return false; } BenchData currentBenchRespawn = BenchList.CurrentBenchRespawn; if ((object)currentBenchRespawn != null) { RespawnInfo respawnInfo = currentBenchRespawn.RespawnInfo.GetRespawnInfo(); scene = respawnInfo.SceneName; marker = respawnInfo.RespawnMarkerName; return false; } RespawnInfo startDef = BenchListModifiers.GetStartDef(); if (startDef.IsCurrentRespawn()) { scene = startDef.SceneName; marker = startDef.RespawnMarkerName; return false; } return true; } [HarmonyPostfix] private static void RecordGetRespawnInfoFallthrough(GameManager __instance, ref string scene, ref string marker) { if (scene == "Tut_01" && __instance.playerData.respawnScene != "Tut_01") { BenchwarpPlugin.Instance.Logger.LogWarning((object)("Unrecognized respawn at " + __instance.playerData.respawnMarkerName + " in " + __instance.playerData.respawnScene + ", GameManager.GetRespawnInfo will fall through to Tut_01.")); } } } [HarmonyPatch(typeof(GameManager), "ContinueGame")] internal static class RecoveryModePatch { [HarmonyPrefix] private static void ModifyRespawn() { if (BenchwarpPlugin.ConfigSettings.RecoveryMode) { LogHelper.LogWarn("Recovery mode is enabled. Setting respawn location to Tut_01..."); new RespawnInfo("Tut_01", "Death Respawn Marker Init", 0, (MapZone)13).SetRespawn(); } } } internal static class RedeployPatch { internal static void Hook() { SceneManager.activeSceneChanged += OnActiveSceneChanged; } internal static void Unhook() { SceneManager.activeSceneChanged -= OnActiveSceneChanged; } private static void OnActiveSceneChanged(Scene from, Scene to) { DeployManager.Redeploy(); } } internal static class ShakraPDHook { internal static void Hook() { PlayerDataVariableEvents.OnSetBool += UpdateShakraBenches; } internal static void Unhook() { PlayerDataVariableEvents.OnSetBool -= UpdateShakraBenches; } private static bool UpdateShakraBenches(PlayerData pd, string fieldName, bool current) { if (!(fieldName == "MapperLeftGreymoor")) { if (fieldName == "MapperLeftPeak" && current) { BenchwarpPlugin.SaveSettings.SetVisited(BaseBenchList.ShakraMountFay, value: true); } } else if (current) { BenchwarpPlugin.SaveSettings.SetVisited(BaseBenchList.ShakraGreymoor, value: true); } return current; } } internal class StyxBenchFix { internal static void Hook() { SceneManager.activeSceneChanged += OnActiveSceneChanged; } internal static void Unhook() { SceneManager.activeSceneChanged -= OnActiveSceneChanged; } private static void OnActiveSceneChanged(Scene from, Scene to) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!(((Scene)(ref to)).name == "Dust_11") || (int)PlayerDataAccess.permadeathMode != 0 || !GameManager.instance.RespawningHero || !BaseBenchList.Styx.RespawnInfo.IsCurrentRespawn() || !(PlayerDataAccess.blackThreadWorld ? (!PlayerDataAccess.silkFarmAbyssCoresCleared) : (!PlayerDataAccess.silkFarmBattle1_complete))) { return; } GameObject val = to.FindGameObject("Steel Soul States/Regular/NPC Control/Grub Farmer NPC", warnIfNotFound: true); if (Object.op_Implicit((Object)(object)val)) { PlayMakerFSM val2 = FSMUtility.LocateMyFSM(val, "Control"); string[] array = new string[2] { "Battle Active", "Abyss Battle Active" }; foreach (string text in array) { FsmUtil.RemoveFirstActionOfType<SetPosition>(FsmUtil.MustGetState(val2, text)); } } } } } namespace Benchwarp.Hotkeys { public static class HotkeyActions { public const string LastBench = "LB"; public const string StartBench = "SB"; public const string DoorWarp = "DW"; public const string NextPage = "NP"; public const string WarpDeploy = "WD"; public const string DeployBench = "DB"; private static readonly Dictionary<string, Action> _hotkeys; public static ReadOnlyDictionary<string, Action> CurrentHotkeys { get; } public static ReadOnlyDictionary<string, Action> BaseHotkeys { get; } static HotkeyActions() { CurrentHotkeys = new ReadOnlyDictionary<string, Action>(_hotkeys = new Dictionary<string, Action>()); BaseHotkeys = new ReadOnlyDictionary<string, Action>(new Dictionary<string, Action> { ["LB"] = ChangeScene.WarpToRespawn, ["SB"] = (Action)Delegate.Combine(new Action(BenchListModifiers.MenuSetToStart), new Action(ChangeScene.WarpToRespawn)), ["WD"] = (Action)Delegate.Combine(new Action(DeployManager.MenuSetRespawnToDeploy), new Action(ChangeScene.WarpToRespawn)), ["DW"] = delegate { if (BenchwarpPlugin.ConfigSettings.MenuMode != MenuMode.DoorWarp) { BenchwarpPlugin.ConfigSettings.MenuMode = MenuMode.DoorWarp; } else { BenchwarpPlugin.ConfigSettings.MenuMode = MenuMode.StandardBenchwarp; } }, ["DB"] = delegate { DeployManager.DeployAtHero(); }, ["NP"] = delegate { GUIController.Instance.NextPage(); } }); RefreshHotkeys(); } public static void RefreshHotkeys() { _hotkeys.Clear(); foreach (var (code, a) in BaseHotkeys) { AddHotkey(_hotkeys, code, a); } foreach (var (text2, action2) in ModEvents.GetHotkeyRequests()) { if (action2 == null) { _hotkeys.Remove(text2); } else { AddHotkey(_hotkeys, text2, action2); } } } internal static void AddHotkey(Dictionary<string, Action> dict, string code, Action a) { code = BenchwarpPlugin.SharedSettings.GetHotkey(code); if (code.Length != 2 || !char.IsLetter(code[0]) || !char.IsLetter(code[1])) { LogHelper.LogError("Invalid hotkey " + code + ": hotkeys must consist of exactly two letters."); } else { dict[code] = a; } } public static bool TryDoHotkeyAction(int groupIndex, int benchIndex) { if (BenchList.BenchGroups.Count > groupIndex && BenchList.BenchGroups[groupIndex].Benches.Count > benchIndex) { BenchList.BenchGroups[groupIndex].Benches[benchIndex].MenuSetBench(); ChangeScene.WarpToRespawn(); return true; } return false; } public static bool TryDoHotkeyAction(string code) { if (CurrentHotkeys.TryGetValue(code, out Action value)) { try { value?.Invoke(); } catch (Exception arg) { LogHelper.LogError($"Error invoking hotkey bound to {code}:\n{arg}"); } return true; } return false; } } public readonly record struct HotkeyCode(HotkeyInput First, HotkeyInput Second) { public static HotkeyCode None { get; } = new HotkeyCode(HotkeyInput.None, HotkeyInput.None); public bool IsComplete { get { if (!First.IsNone) { return !Second.IsNone; } return false; } } public static HotkeyCode operator +(HotkeyCode code, HotkeyInput input) { return new HotkeyCode(code.Second, input); } public bool TryGetLetterNumCode(out int firstIndex, out int secondIndex) { if (First.IsLetter && Second.IsNum) { firstIndex = First.Num; secondIndex = Second.Num; return true; } firstIndex = 0; secondIndex = 0; return false; } public bool TryGetNumericCode(out int code) { if (First.IsNum && Second.IsNum) { code = First.Num * 10 + Second.Num; return true; } code = 0; return false; } public bool TryGetStringCode(out string code) { if (First.IsLetter && Second.IsLetter) { code = $"{First.Letter}{Second.Letter}"; return true; } code = string.Empty; return false; } } public readonly record struct HotkeyInput(HotkeyType Type, int Num) { public static HotkeyInput None { get; } = new HotkeyInput(HotkeyType.None, 0); public bool IsNone => Type == HotkeyType.None; public bool IsLetter => Type == HotkeyType.Letter; public bool IsNum => Type == HotkeyType.Number; public char Letter => (char)(65 + Num); } public enum HotkeyType { None, Letter, Number } } namespace Benchwarp.Events { public static class BenchListModifiers { private static readonly SequentialEvent<Func<RespawnInfo, RespawnInfo>>.ISequentialEventOwner onGetStartDefOwner; private static readonly SequentialEvent<Func<BenchData, bool>>.ISequentialEventOwner benchSuppressorsOwner; private static readonly SequentialEvent<Func<IEnumerable<BenchData>>>.ISequentialEventOwner benchInjectorsOwner; private static readonly SequentialEvent<Comparison<BenchData>>.ISequentialEventOwner benchComparisonsOwner; public static SequentialEvent<Func<RespawnInfo, RespawnInfo>> OnGetStartDef { get; } public static SequentialEvent<Func<BenchData, bool>> BenchSuppressors { get; } public static SequentialEvent<Func<IEnumerable<BenchData>>> BenchInjectors { get; } public static SequentialEvent<Comparison<BenchData>> BenchComparisons { get; } public static RespawnInfo GetStartDef() { return onGetStartDefOwner.InvokeToTransform(new RespawnInfo("Tut_01", "Death Respawn Marker Init", 0, (MapZone)13), "GetStartDef"); } public static bool AtStart() { return GetStartDef().IsCurrentRespawn(); } public static void MenuSetToStart() { if (BenchwarpPlugin.ConfigSettings.MenuMode != MenuMode.WarpOnly) { GetStartDef().SetRespawn(); } } internal static bool ShouldSuppressBench(BenchData bench) { return benchSuppressorsOwner.InvokeAndAggregate(bench, seed: false, (bool b1, bool b2) => b1 || b2, "ShouldSuppressBench"); } internal static IEnumerable<BenchData> GetInjectedBenches() { return benchInjectorsOwner.InvokeAndCollectFlat("GetInjectedBenches"); } internal static void SortBenchList(List<BenchData> benches) { foreach (Comparison<BenchData> subscriber in benchComparisonsOwner.GetSubscribers()) { benches.StableSort(subscriber); } } static BenchListModifiers() { OnGetStartDef = new SequentialEvent<Func<RespawnInfo, RespawnInfo>>(out onGetStartDefOwner); BenchSuppressors = new SequentialEvent<Func<BenchData, bool>>(out benchSuppressorsOwner); BenchInjectors = new SequentialEvent<Func<IEnumerable<BenchData>>>(out benchInjectorsOwner); BenchComparisons = new SequentialEvent<Comparison<BenchData>>(out benchComparisonsOwner); benchSuppressorsOwner.OnSubscribersChanged += BenchList.RefreshBenchList; benchInjectorsOwner.OnSubscribersChanged += BenchList.RefreshBenchList; } } public static class ModEvents { private static readonly SequentialEvent<Func<(string, Action?)>>.ISequentialEventOwner hotkeyRequestsOwner; public static IObstacleHandler DoorwarpObstacleHandler { get; set; } public static IObstacleProvider DoorwarpObstacleProvider { get; set; } public static SequentialEvent<Func<(string, Action?)>> HotkeyRequests { get; } public static event Action? OnBenchSelected; public static event Action? OnBenchwarp; public static event Action<RoomData, DoorData>? OnDoorwarp; internal static void InvokeOnBenchSelected() { try { ModEvents.OnBenchSelected?.Invoke(); } catch (Exception o) { LogHelper.LogError(o); } } internal static void InvokeOnBenchwarp() { try { ModEvents.OnBenchwarp?.Invoke(); } catch (Exception o) { LogHelper.LogError(o); } } internal static void InvokeOnDoorwarp(RoomData room, DoorData gate) { try { ModEvents.OnDoorwarp?.Invoke(room, gate); } catch (Exception o) { LogHelper.LogError(o); } } internal static IEnumerable<(string, Action?)> GetHotkeyRequests() { return hotkeyRequestsOwner.InvokeAndCollect("GetHotkeyRequests"); } static ModEvents() { DoorwarpObstacleHandler = new NoSaveObstacleHandler(); DoorwarpObstacleProvider = new BaseObstacleProvider(); HotkeyRequests = new SequentialEvent<Func<(string, Action)>>(out hotkeyRequestsOwner); hotkeyRequestsOwner.OnSubscribersChanged += HotkeyActions.RefreshHotkeys; } } public static class WorldEvents { public static event Action<RespawnInfo, BenchData?>? OnRespawnChanged; internal static void InvokeOnRespawnChanged(RespawnInfo info) { BenchList.UpdateRespawn(info); try { WorldEvents.OnRespawnChanged?.Invoke(info, BenchList.CurrentBenchRespawn); } catch (Exception o) { LogHelper.LogError(o); } } } } namespace Benchwarp.Doors { public class AreaRoomGroup { public required string MenuArea { get; init; } public required ReadOnlyCollection<RoomData> Rooms { get; init; } } public class DoorData { private static readonly ReadOnlyCollection<TransitionKey> emptyDynamicTargets = new ReadOnlyCollection<TransitionKey>(new List<TransitionKey>()); private static readonly ReadOnlyCollection<ObstacleInfo> emptyObstacles = new ReadOnlyCollection<ObstacleInfo>(new List<ObstacleInfo>()); public TransitionKey Self { get; } public TransitionKey? Target { get; } public TransitionKey? Source { get; } public ReadOnlyCollection<TransitionKey> DynamicTargets { get; init; } = emptyDynamicTargets; public ReadOnlyCollection<ObstacleInfo> Obstacles { get; init; } = emptyObstacles; public DoorData(TransitionKey self) { Self = self; Target = self; } public DoorData(TransitionKey self, TransitionKey sourcetarget) { Self = self; Target = sourcetarget; Source = sourcetarget; } public DoorData(TransitionKey self, TransitionKey? source, TransitionKey? target) { Self = self; Target = target; Source = source; } } public static class DoorList { public static ReadOnlyDictionary<string, RoomData> Rooms { get; } public static ReadOnlyDictionary<TransitionKey, DoorData> Doors { get; } public static ReadOnlyCollection<AreaRoomGroup> RoomGroups { get; } public static int RoomCount { get; } public static int DoorCount { get; } public static int MaxRoomsPerArea { get; } public static int MaxDoorsPerRoom { get; } static DoorList() { Rooms = new ReadOnlyDictionary<string, RoomData>((from p in typeof(BaseRoomList).GetProperties(BindingFlags.Static | BindingFlags.Public) where p.PropertyType == typeof(RoomData) select (RoomData)p.GetValue(null)).ToDictionary((RoomData d) => d.Name, (RoomData d) => d)); Doors = new ReadOnlyDictionary<TransitionKey, DoorData>(Rooms.Values.SelectMany((RoomData r) => r.Gates).ToDictionary((DoorData g) => g.Self)); List<AreaRoomGroup> list = new List<AreaRoomGroup>(); list.AddRange(from g in (from r in Rooms.Values group r by r.TitledArea).Select(delegate(IGrouping<string, RoomData> g) { AreaRoomGroup obj = new AreaRoomGroup { MenuArea = g.Key }; List<RoomData> list2 = new List<RoomData>(); list2.AddRange(g); obj.Rooms = new ReadOnlyCollection<RoomData>(list2); return obj; }) orderby g.MenuArea select g); RoomGroups = new ReadOnlyCollection<AreaRoomGroup>(list); RoomCount = ((IEnumerable<AreaRoomGroup>)RoomGroups).Sum((Func<AreaRoomGroup, int>)CountRooms); DoorCount = RoomGroups.Sum((AreaRoomGroup g) => ((IEnumerable<RoomData>)g.Rooms).Sum((Func<RoomData, int>)CountGates)); MaxRoomsPerArea = ((IEnumerable<AreaRoomGroup>)RoomGroups).Max((Func<AreaRoomGroup, int>)CountRooms); MaxDoorsPerRoom = RoomGroups.Max((AreaRoomGroup g) => ((IEnumerable<RoomData>)g.Rooms).Max((Func<RoomData, int>)CountGates)); static int CountGates(RoomData r) { return r.Gates.Count; } static int CountRooms(AreaRoomGroup g) { return g.Rooms.Count; } } } public class RoomData { public required string Name { get; init; } public required MapZone MapZone { get; init; } public required string MapArea { get; init; } public required string TitledArea { get; init; } public required ReadOnlyCollection<DoorData> Gates { get; init; } } public readonly record struct TransitionKey(string SceneName, string GateName) { public string Name { get; } = SceneName + "[" + GateName + "]"; private static readonly Regex r = new Regex("^(\\w+)\\[([\\w\\s]+)\\]$"); public static TransitionKey FromName(string name) { Match match = r.Match(name); if (match == null || !match.Success) { throw new ArgumentException("Illformated transition name" + name, "name"); } return new TransitionKey(match.Groups[1].Value, match.Groups[2].Value); } } } namespace Benchwarp.Doors.Obstacles { public class BaseObstacleProvider : IObstacleProvider { public IEnumerable<ObstacleInfo> GetGateObstacles(RoomData room, DoorData gate) { return gate.Obstacles; } } public record BehaviourObstacleInfo<T> : ObstacleInfo where T : Behaviour { public bool Enable { get; init; } public int Index { get; init; } public BehaviourObstacleInfo(string ObjPath, bool Enable, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null, int Index = 0) { this.Enable = Enable; this.Index = Index; base..ctor(ObjPath, Type, Severity, SaveInfo); } public Behaviour? FindBehaviour(Scene scene, bool warnIfNotFound = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindObj(scene, warnIfNotFound); if (!Object.op_Implicit((Object)(object)val)) { return null; } object obj = val.GetComponents<T>().ElementAtOrDefault(Index); if (!Object.op_Implicit((Object)obj) && warnIfNotFound) { LogHelper.LogWarn($"GameObject at {base.ObjPath} did not have {Index + 1} components of type {typeof(T).Name}."); } return (Behaviour?)obj; } public override void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Behaviour val = FindBehaviour(scene); if (val != null && Object.op_Implicit((Object)(object)val)) { val.enabled = Enable; } } [CompilerGenerated] public void Deconstruct(out string ObjPath, out bool Enable, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo, out int Index) { ObjPath = base.ObjPath; Enable = this.Enable; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; Index = this.Index; } } public record FsmEventObstacleInfo : FsmObstacleInfo { public string FsmEventName { get; init; } public FsmEventObstacleInfo(string ObjPath, string FsmName, string FsmEventName, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null) { this.FsmEventName = FsmEventName; base..ctor(ObjPath, FsmName, Type, Severity, SaveInfo); } public override void Open(PlayMakerFSM fsm) { fsm.SendEvent(FsmEventName); } [CompilerGenerated] public void Deconstruct(out string ObjPath, out string FsmName, out string FsmEventName, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo) { ObjPath = base.ObjPath; FsmName = base.FsmName; FsmEventName = this.FsmEventName; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; } } public abstract record FsmObstacleInfo : ObstacleInfo { public string FsmName { get; init; } protected FsmObstacleInfo(string ObjPath, string FsmName, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null) { this.FsmName = FsmName; base..ctor(ObjPath, Type, Severity, SaveInfo); } public abstract void Open(PlayMakerFSM fsm); public sealed override void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindObj(scene); if (!((Object)(object)val == (Object)null)) { PlayMakerFSM val2 = FSMUtility.LocateMyFSM(val, FsmName); if (!((Object)(object)val2 == (Object)null)) { Open(val2); } } } [CompilerGenerated] public void Deconstruct(out string ObjPath, out string FsmName, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo) { ObjPath = base.ObjPath; FsmName = this.FsmName; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; } } public record FsmTransitionObstacleInfo : FsmObstacleInfo { public string FsmStateName { get; init; } public string FsmEventName { get; init; } public string ToState { get; init; } public FsmTransitionObstacleInfo(string ObjPath, string FsmName, string FsmStateName, string FsmEventName, string ToState, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null) { this.FsmStateName = FsmStateName; this.FsmEventName = FsmEventName; this.ToState = ToState; base..ctor(ObjPath, FsmName, Type, Severity, SaveInfo); } public override void Open(PlayMakerFSM fsm) { FsmUtil.ChangeTransition(FsmUtil.MustGetState(fsm, FsmStateName), FsmEventName, ToState); } [CompilerGenerated] public void Deconstruct(out string ObjPath, out string FsmName, out string FsmStateName, out string FsmEventName, out string ToState, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo) { ObjPath = base.ObjPath; FsmName = base.FsmName; FsmStateName = this.FsmStateName; FsmEventName = this.FsmEventName; ToState = this.ToState; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; } } public record GameObjectActiveObstacleInfo : ObstacleInfo { public bool Active { get; init; } public GameObjectActiveObstacleInfo(string ObjPath, bool Active, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null) { this.Active = Active; base..ctor(ObjPath, Type, Severity, SaveInfo); } public override void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GameObject? obj = FindObj(scene); if (obj != null) { obj.SetActive(Active); } } [CompilerGenerated] public void Deconstruct(out string ObjPath, out bool Active, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo) { ObjPath = base.ObjPath; Active = this.Active; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; } } public interface IObstacleHandler { void BeforeTransition(RoomData room, DoorData gate, IObstacleProvider obstacleProvider); void OnSceneChange(Scene scene, RoomData room, DoorData gate, IObstacleProvider obstacleProvider); } public interface IObstacleProvider { IEnumerable<ObstacleInfo> GetGateObstacles(RoomData room, DoorData gate); } public class NoSaveObstacleHandler : ObstacleHandler { protected override bool HandleObstacleOnActiveSceneChange(Scene scene, RoomData room, DoorData gate, ObstacleInfo o, bool handledBeforeTransition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return HandleObstacle(scene, room, gate, o); } public static bool HandleObstacle(Scene scene, RoomData room, DoorData gate, ObstacleInfo o) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) o.Open(scene); return true; } } public abstract class ObstacleHandler : IObstacleHandler { protected readonly HashSet<ObstacleInfo> handledObstacles = new HashSet<ObstacleInfo>(); public void BeforeTransition(RoomData room, DoorData gate, IObstacleProvider obstacleProvider) { handledObstacles.Clear(); foreach (ObstacleInfo gateObstacle in obstacleProvider.GetGateObstacles(room, gate)) { try { if (HandleObstacleBeforeTransition(room, gate, gateObstacle)) { handledObstacles.Add(gateObstacle); } } catch (Exception arg) { LogHelper.LogError($"Error handling obstacle {gateObstacle} before transition for gate {gate.Self}:\n{arg}"); } } } public void OnSceneChange(Scene scene, RoomData room, DoorData gate, IObstacleProvider obstacleProvider) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) foreach (ObstacleInfo gateObstacle in obstacleProvider.GetGateObstacles(room, gate)) { try { if (HandleObstacleOnActiveSceneChange(scene, room, gate, gateObstacle, handledObstacles.Contains(gateObstacle))) { handledObstacles.Add(gateObstacle); } } catch (Exception arg) { LogHelper.LogError($"Error handling obstacle {gateObstacle} on scene change for gate {gate.Self}:\n{arg}"); } } IEnumerable<ObstacleInfo> enumerable = gate.Obstacles.Where((ObstacleInfo o) => !handledObstacles.Contains(o)); if (enumerable.Any()) { LogHelper.LogWarn("ObstacleHandler " + GetType().Name + " for gate " + gate.Self.Name + " did not handle the following obstacles: " + string.Join("; ", enumerable)); } handledObstacles.Clear(); } protected virtual bool HandleObstacleBeforeTransition(RoomData room, DoorData gate, ObstacleInfo o) { return false; } protected virtual bool HandleObstacleOnActiveSceneChange(Scene scene, RoomData room, DoorData gate, ObstacleInfo o, bool handledBeforeTransition) { return false; } } public record ObstacleInfo(string ObjPath, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null) { public string GetObjName() { return ObjPath.Split('/').Last(); } public GameObject? FindObj(Scene scene, bool warnIfNotFound = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return scene.FindGameObject(ObjPath, warnIfNotFound); } public void DestroyObj(Scene scene, bool warnIfNotFound = false) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Object.Destroy((Object)(object)FindObj(scene, warnIfNotFound)); } public virtual void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) DestroyObj(scene); } public bool TrySave(RoomData room, DoorData gate) { if ((object)SaveInfo != null) { SaveInfo.Save(room, gate, GetObjName()); return true; } return false; } } public abstract record ObstacleSaveInfo { public abstract void Save(RoomData room, DoorData gate, string objName); } [Flags] public enum ObstacleSeverity { ModifiesSaveData = 1, InterruptsEntry = 2, LimitsRoomAccess = 4, LimitsExitAccess = 8, LimitsVisibility = 0x10, AbnormalVisual = 0x20 } public enum ObstacleType { Mask, OneWayBreakableEntry, OneWayBreakableExit, TwoWayBreakable, OneWayMechanismEntry, OneWayMechanismExit, TwoWayMechanism, OpenAfterProgression, ClosedAfterProgression, Cutscene, Other } public class OverrideObstacleProvider : IObstacleProvider { public required IEnumerable<ObstacleInfo> Obstacles { get; init; } public IEnumerable<ObstacleInfo> GetGateObstacles(RoomData room, DoorData gate) { return gate.Obstacles; } } public class PermanentObstacleHandler : ObstacleHandler { protected override bool HandleObstacleBeforeTransition(RoomData room, DoorData gate, ObstacleInfo o) { return HandleObstacle(room, gate, o); } protected override bool HandleObstacleOnActiveSceneChange(Scene scene, RoomData room, DoorData gate, ObstacleInfo o, bool handledBeforeTransition) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (handledBeforeTransition) { return false; } return NoSaveObstacleHandler.HandleObstacle(scene, room, gate, o); } public static bool HandleObstacle(RoomData room, DoorData gate, ObstacleInfo o) { return o.TrySave(room, gate); } } public record PersistentBoolSaveInfo(string? SceneName = null, string? ID = null) : ObstacleSaveInfo() { public override void Save(RoomData room, DoorData gate, string objName) { SceneData.instance.PersistentBools.SetValue(new PersistentItemData<bool> { SceneName = (SceneName ?? room.Name), ID = (ID ?? objName), Value = true }); } } public record PlayerDataBoolSaveInfo(string PlayerDataBoolName) : ObstacleSaveInfo() { public override void Save(RoomData room, DoorData gate, string objName) { PlayerData.instance.SetBool(PlayerDataBoolName, true); } } public record PlayerDataIntSaveInfo(string PlayerDataIntName, int Value) : ObstacleSaveInfo() { public override void Save(RoomData room, DoorData gate, string objName) { PlayerData.instance.SetInt(PlayerDataIntName, Value); } } public record TestObjObstacleInfo : BehaviourObstacleInfo<TestGameObjectActivator> { public bool Activate { get; init; } public TestObjObstacleInfo(string ObjPath, bool Activate, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null, int Index = 0) { this.Activate = Activate; base..ctor(ObjPath, Activate, Type, Severity, SaveInfo, Index); } public override void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Behaviour? obj = FindBehaviour(scene); TestGameObjectActivator val = (TestGameObjectActivator)(object)((obj is TestGameObjectActivator) ? obj : null); if (val != null && Object.op_Implicit((Object)(object)val)) { ((Behaviour)val).enabled = false; GameObject activateGameObject = val.activateGameObject; if (activateGameObject != null) { activateGameObject.SetActive(Activate); } GameObject deactivateGameObject = val.deactivateGameObject; if (deactivateGameObject != null) { deactivateGameObject.SetActive(!Activate); } } } [CompilerGenerated] public override int GetHashCode() { return base.GetHashCode() * -1521134295 + EqualityComparer<bool>.Default.GetHashCode(Activate); } [CompilerGenerated] protected TestObjObstacleInfo(TestObjObstacleInfo original) : base((BehaviourObstacleInfo<TestGameObjectActivator>)original) { Activate = original.Activate; } [CompilerGenerated] public new void Deconstruct(out string ObjPath, out bool Activate, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo, out int Index) { ObjPath = base.ObjPath; Activate = this.Activate; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; Index = base.Index; } } public record TransitionObstacleInfo : BehaviourObstacleInfo<TransitionPoint> { public bool Enabled { get; init; } public TransitionObstacleInfo(string ObjPath, bool Enabled, ObstacleType Type, ObstacleSeverity Severity, ObstacleSaveInfo? SaveInfo = null) { this.Enabled = Enabled; base..ctor(ObjPath, Enabled, Type, Severity, SaveInfo, 0); } public override void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Behaviour? obj = FindBehaviour(scene); TransitionPoint val = (TransitionPoint)(object)((obj is TransitionPoint) ? obj : null); if (val != null && Object.op_Implicit((Object)(object)val)) { ((Behaviour)val).enabled = Enabled; val.isInactive = !Enabled; ((InteractableBase)val).IsDisabled = !Enabled; } } [CompilerGenerated] public override int GetHashCode() { return base.GetHashCode() * -1521134295 + EqualityComparer<bool>.Default.GetHashCode(Enabled); } [CompilerGenerated] protected TransitionObstacleInfo(TransitionObstacleInfo original) : base((BehaviourObstacleInfo<TransitionPoint>)original) { Enabled = original.Enabled; } [CompilerGenerated] public void Deconstruct(out string ObjPath, out bool Enabled, out ObstacleType Type, out ObstacleSeverity Severity, out ObstacleSaveInfo? SaveInfo) { ObjPath = base.ObjPath; Enabled = this.Enabled; Type = base.Type; Severity = base.Severity; SaveInfo = base.SaveInfo; } } public record UnmaskerInfo : BehaviourObstacleInfo<Unmasker> { public UnmaskerInfo(string ObjPath, ObstacleSaveInfo? SaveInfo = null) : base(ObjPath, Enable: true, ObstacleType.Mask, ObstacleSeverity.LimitsVisibility, SaveInfo, 0) { } public override void Open(Scene scene) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Behaviour? obj = FindBehaviour(scene); Unmasker val = (Unmasker)(object)((obj is Unmasker) ? obj : null); if (val != null && Object.op_Implicit((Object)(object)val)) { val.Uncover(); } } [CompilerGenerated] public override int GetHashCode() { return base.GetHashCode(); } [CompilerGenerated] protected UnmaskerInfo(UnmaskerInfo original) : base((BehaviourObstacleInfo<Unmasker>)original) { } [CompilerGenerated] public void Deconstruct(out string ObjPath, out ObstacleSaveInfo? SaveInfo) { ObjPath = base.ObjPath; SaveInfo = base.SaveInfo; } } } namespace Benchwarp.Deploy { internal static class DeployAssets { public const string DeployedRespawnMarkerName = "Benchwarp Deployed Respawn"; public static ManagedAsset<GameObject>? Bench { get; set; } public static GameObject CreateMarker() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown GameObject val = new GameObject("Benchwarp Deployed Respawn"); RespawnMarker obj = val.AddComponent<RespawnMarker>(); obj.customFadeDuration = new OverrideFloat(); obj.overrideMapZone = new OverrideMapZone(); val.AddComponent<DeployComponent>(); return val; } public static void PlaceMarkerRelativeToHero(GameObject go, Vector3 heroPos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) go.transform.position = heroPos; } public static GameObject CreateBench() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) ((ManagedAssetBase<GameObject>)(object)Bench).Load().WaitForCompletion(); GameObject obj = ManagedAssetExtensions.InstantiateAsset<GameObject>(Bench); ((Object)obj).name = "Benchwarp Deployed Respawn"; ModifyBench(obj); obj.AddComponent<DeployComponent>(); return obj; } public static void PlaceBenchRelativeToHero(GameObject go, Vector3 heroPos) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) heroPos.y -= 0.6677f; heroPos.z += 0.0087f; go.transform.position = heroPos; } private static void ModifyBench(GameObject bench) { PlayMakerFSM obj = FSMUtility.LocateMyFSM(bench, "Bench Control"); FsmUtil.ChangeTransition(FsmUtil.GetState(obj, "Craw Summons?"), "FINISHED", "Start Locked?").ThrowIfFalse(); FsmUtil.ReplaceAllActions(FsmUtil.GetState(obj, "Craw Summons?"), Array.Empty<FsmStateAction>()); FsmUtil.ChangeTransition(FsmUtil.GetState(obj, "Craw summons check"), "FINISHED", "Resting").ThrowIfFalse(); FsmUtil.ReplaceAllActions(FsmUtil.GetState(obj, "Craw summons check"), Array.Empty<FsmStateAction>()); FsmUtil.ReplaceAllActions(FsmUtil.GetState(obj, "Craw Summons Instant?"), Array.Empty<FsmStateAction>()); } private static void ThrowIfFalse(this bool b) { if (!b) { throw new InvalidOperationException(); } } } internal class DeployComponent : MonoBehaviour { private static DeployComponent? instance; private void Awake() { if (Object.op_Implicit((Object)(object)instance)) { Object.Destroy((Object)(object)((Component)instance).gameObject); } instance = this; } private void OnDestroy() { if ((Object)(object)instance == (Object)(object)this) { instance = null; } } public static void DestroyAll() { if (Object.op_Implicit((Object)(object)instance)) { Object.Destroy((Object)(object)((Component)instance).gameObject); } } } public record DeployInfo : IRespawnInfo { public required RespawnInfo RespawnInfo { get; init; } public required float HeroX { get; init; } public required float HeroY { get; init; } public required float HeroZ { get; init; } public required DeployStyles Style { get; init; } [JsonIgnore] public string SceneName => RespawnInfo.SceneName; [JsonIgnore] public Vector3 HeroPosition => new Vector3(HeroX, HeroY, HeroZ); RespawnInfo IRespawnInfo.GetRespawnInfo() { return RespawnInfo; } [CompilerGenerated] [SetsRequiredMembers] protected DeployInfo(DeployInfo original) { RespawnInfo = original.RespawnInfo; HeroX = original.HeroX; HeroY = original.HeroY; HeroZ = original.HeroZ; Style = original.Style; } public DeployInfo() { } } internal static class DeployManager { public static GameObject DeployAtHero() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) try { DeployStyles deployStyle = BenchwarpPlugin.SharedSettings.DeployStyle; Vector3 position = HeroController.instance.transform.position; object result = deployStyle switch { DeployStyles.Marker => DeployMarkerAtHero(position), DeployStyles.Bone => DeployBenchAtHero(position), _ => throw new NotImplementedException($"Unimplemented deploy style: {BenchwarpPlugin.SharedSettings.DeployStyle}"), }; BenchwarpPlugin.SaveSettings.DeployInfo = new DeployInfo { RespawnInfo = new RespawnInfo(GameManager.instance.GetSceneNameString(), "Benchwarp Deployed Respawn", deployStyle.ToRespawnType(), GameManager.instance.sm.mapZone), HeroX = position.x, HeroY = position.y, HeroZ = position.z, Style = deployStyle }; return (GameObject)result; } catch (Exception o) { LogHelper.LogError(o); throw; } } public static GameObject? Redeploy() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) DeployInfo deployInfo = BenchwarpPlugin.SaveSettings.DeployInfo; if ((object)deployInfo == null || GameManager.instance.GetSceneNameString() != deployInfo.SceneName) { return null; } try { Vector3 heroPosition = deployInfo.HeroPosition; return (GameObject?)(BenchwarpPlugin.SharedSettings.DeployStyle switch { DeployStyles.Marker => DeployMarkerAtHero(heroPosition), DeployStyles.Bone => DeployBenchAtHero(heroPosition), _ => throw new NotImplementedException($"Unimplemented deploy style: {BenchwarpPlugin.SharedSettings.DeployStyle}"), }); } catch (Exception o) { LogHelper.LogError(o); throw; } } public static GameObject DeployMarkerAtHero(Vector3 heroPos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) GameObject obj = DeployAssets.CreateMarker(); DeployAssets.PlaceMarkerRelativeToHero(obj, heroPos); return obj; } public static GameObject DeployBenchAtHero(Vector3 heroPos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) GameObject obj = DeployAssets.CreateBench(); DeployAssets.PlaceBenchRelativeToHero(obj, heroPos); return obj; } public static void Undeploy() { DeployComponent.DestroyAll(); DeployInfo? deployInfo = BenchwarpPlugin.SaveSettings.DeployInfo; if ((object)deployInfo != null && deployInfo.IsCurrentRespawn()) { BenchListModifiers.GetStartDef().SetRespawn(); } BenchwarpPlugin.SaveSettings.DeployInfo = null; } public static void MenuSetRespawnToDeploy() { if (BenchwarpPlugin.ConfigSettings.MenuMode != MenuMode.WarpOnly) { BenchwarpPlugin.SaveSettings.DeployInfo?.SetRespawn(); } } } public enum DeployStyles { Marker, Bone } public static class DeployStylesExtensions { [SpecialName] public sealed class <G>$D1CB0754BA300FE0865F6D28E6537FAA { [SpecialName] public static class <M>$0D16585C25657F0B27D8B3CE724D86E0 { } [ExtensionMarker("<M>$0D16585C25657F0B27D8B3CE724D86E0")] public int ToRespawnType() { throw new NotSupportedException(); } } public static int ToRespawnType(this DeployStyles style) { if (style == DeployStyles.Marker) { return 0; } return 1; } } } namespace Benchwarp.Data { public static class BaseBenchList { public static BenchData RuinedChapel { get; } = new BenchData("Ruined Chapel", "Mosslands", new RespawnInfo("Tut_03", "RestBench", 1, (MapZone)18)); public static BenchData BoneBottom { get; } = new BenchData("Bone Bottom", "Mosslands", new RespawnInfo("Bonetown", "RestBench", 1, (MapZone)12)); public static BenchData MossDruid { get; } = new BenchData("Moss Druid", "Mosslands", new RespawnInfo("Mosstown_02c", "RestBench", 1, (MapZone)19)); public static BenchData SnailShamans { get; } = new BenchData("Snail Shamans", "Mosslands", new RespawnInfo("Tut_04", "RestBench", 1, (MapZone)18)); public static BenchData TollMarrow { get; } = new BenchData("Toll", "The Marrow", new RespawnInfo("Bone_01c", "RestBench", 1, (MapZone)2)); public static BenchData MosshomeGate { get; } = new BenchData("Mosshome Gate", "The Marrow", new RespawnInfo("Bone_04", "RestBench", 1, (MapZone)19)); public static BenchData BellshrineMarrow { get; } = new BenchData("Bellshrine", "The Marrow", new RespawnInfo("Bellshrine", "RestBench", 1, (MapZone)2)); public static BenchData ShootingGallery { get; } = new BenchData("Shooting Gallery", "The Marrow", new PDConditionalRespawnInfo("act3_wokeUp", new RespawnInfo("Bone_12", "RestBench (1)", 1, (MapZone)2), new RespawnInfo("Bone_12", "RestBench", 1, (MapZone)2))); public static BenchData FleaCaravanMarrow { get; } = new BenchData("Flea Caravan", "The Marrow", new RespawnInfo("Bone_10", "RestBench", 1, (MapZone)2)); public static BenchData TrapMarch { get; } = new BenchData("Trap", "Hunter's March", new PDConditionalRespawnInfo("antBenchTrapDefused", new RespawnInfo("Ant_17", "RestBench", 1, (MapZone)11), new RespawnInfo("Ant_17", "RestBench", 0, (MapZone)11))); public static BenchData TollDocks { get; } = new BenchData("Toll", "Deep Docks", new RespawnInfo("Dock_01", "RestBench", 1, (MapZone)15)); public static BenchData Forge { get; } = new BenchData("Forge", "Deep Docks", new RespawnInfo("Room_Forge", "RestBench", 1, (MapZone)15)); public static BenchData BellshrineDocks { get; } = new BenchData("Bellshrine", "Deep Docks", new RespawnInfo("Bellshrine_05", "RestBench", 1, (MapZone)15)); public static BenchData Sauna { get; } = new BenchData("Sauna", "Deep Docks", new RespawnInfo("Dock_10", "RestBench", 1, (MapZone)15)); public static BenchData DivingBell { get; } = new BenchData("Diving Bell", "Deep Docks", new RespawnInfo("Room_Diving_Bell", "RestBench", 1, (MapZone)15)); public static BenchData AbyssExit { get; } = new BenchData("Abyss Exit", "Deep Docks", new RespawnInfo("Dock_06_Church", "RestBench (1)", 1, (MapZone)15)); public static BenchData BellwayFields { get; } = new BenchData("Bellway", "Far Fields", new RespawnInfo("Bellway_03", "RestBench", 1, (MapZone)16)); public static BenchData Seamstress { get; } = new BenchData("Seamstress", "Far Fields", new RespawnInfo("Bone_East_Umbrella", "RestBench", 1, (MapZone)16)); public static BenchData PilgrimsRest { get; } =