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 SceneSwitcher v1.0.0
SceneSwitcher.dll
Decompiled 12 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using SceneSwitcher.Core; using SceneSwitcher.Ui; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SceneSwitcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SceneSwitcher")] [assembly: AssemblyTitle("SceneSwitcher")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace SceneSwitcher { internal static class CrashReporter { public const string ErrorCode = "CRM001 - Crimson's hamster stopped running"; public static void Report(Exception exception, string context) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)string.Format("{0} [{1}]\n{2}", "CRM001 - Crimson's hamster stopped running", context, exception)); } try { Feedback.Fail("CRM001 - Crimson's hamster stopped running"); } catch { } } public static bool Guard(string context, Action action) { try { action(); return true; } catch (Exception exception) { Report(exception, context); return false; } } } internal static class Feedback { public static void Ok(string message) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Show(message, (MenuClickEffectType)1, Color.green); } public static void Info(string message, float time = 3f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Show(message, (MenuClickEffectType)1, Color.white, time); } public static void Fail(string message) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Show(message, (MenuClickEffectType)2, Color.red); } private static void Show(string message, MenuClickEffectType effect, Color flash, float time = 3f) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)("/scene: " + message)); if (Object.op_Implicit((Object)(object)MenuManager.instance)) { MenuManager.instance.MenuEffectClick(effect, (MenuPage)null, 1f, 1f, true, true); } if (Object.op_Implicit((Object)(object)MissionUI.instance)) { SemiFunc.UIFocusText(message, Color.white, flash, time); } } } [BepInPlugin("abzu.SceneSwitcher", "SceneSwitcher", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "abzu.SceneSwitcher"; public const string PluginName = "SceneSwitcher"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; if (CrashReporter.Guard("startup", delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown _harmony = new Harmony("abzu.SceneSwitcher"); _harmony.PatchAll(typeof(Plugin).Assembly); Settings.Bind(((BaseUnityPlugin)this).Config); SceneWindow.Create(Settings.WindowToggleKey); })) { Log.LogInfo((object)"SceneSwitcher v1.0.0 loaded."); Log.LogInfo((object)"Todo inició correctamente, chupala Crimson"); } } } internal static class SceneLauncher { public static void ReturnToLobbyMenu() { if (CheckCanSwitch()) { Feedback.Ok("Returning to the lobby menu..."); SceneSwitchService.ReturnToLobbyMenu(); } } public static void Launch(Level level, int? levelNumber, string targetName = null) { if (CheckCanSwitch()) { if (!Object.op_Implicit((Object)(object)level)) { Feedback.Fail("Level not available."); return; } string text = targetName ?? LevelNameResolver.DisplayName(((Object)level).name); string text2 = (levelNumber.HasValue ? $" (level {levelNumber.Value})" : string.Empty); Feedback.Ok("Launching " + text + text2 + "..."); SceneSwitchService.LaunchLevel(level, levelNumber); } } public static void LaunchRandom(Level level, int? levelNumber, string kind) { if (!Object.op_Implicit((Object)(object)level)) { Feedback.Fail("No " + kind + " available."); } else { Launch(level, levelNumber); } } private static bool CheckCanSwitch() { if (SceneSwitchService.CanSwitch(out var reason)) { return true; } Feedback.Fail(reason); return false; } } internal static class SceneSwitchService { private static readonly MethodInfo ResetLevelProgressMethod = AccessTools.Method(typeof(DebugCommandHandler), "ResetLevelProgress", (Type[])null, (Type[])null); public static IEnumerable<Level> Maps => RunManager.instance.levels.Where((Level l) => Object.op_Implicit((Object)(object)l)); public static IEnumerable<Level> Arenas => RunManager.instance.levelArena.Where((Level l) => Object.op_Implicit((Object)(object)l)); public static IEnumerable<Level> Shops => RunManager.instance.levelShop.Where((Level l) => Object.op_Implicit((Object)(object)l)); public static Level Truck => RunManager.instance.levelLobby; public static bool CanSwitch(out string reason) { RunManager instance = RunManager.instance; if (!Object.op_Implicit((Object)(object)instance)) { reason = "Game is not ready."; return false; } if (!SemiFunc.IsMasterClientOrSingleplayer()) { reason = "Only the host can change scenes."; return false; } if (SemiFunc.IsSplashScreen() || SemiFunc.IsMainMenu() || SemiFunc.RunIsTutorial()) { reason = "Not available in this scene."; return false; } if (instance.restarting) { reason = "A scene change is already in progress."; return false; } reason = null; return true; } public static void ReturnToLobbyMenu() { RunManager instance = RunManager.instance; if (Settings.Progress.Value == ProgressMode.RevertToLastSave) { ResetLevelProgress(); } if (!SemiFunc.RunIsLobbyMenu()) { instance.loadLevel = instance.saveLevel; } if (SemiFunc.RunIsArena()) { instance.levelCurrent = instance.levelLobby; } instance.ChangeLevel(false, false, (ChangeLevelType)3); } public static void LaunchLevel(Level level, int? levelNumber) { RunManager instance = RunManager.instance; if (Settings.Progress.Value != ProgressMode.KeepCurrent && (!SemiFunc.IsLevelShop(level) || !SemiFunc.RunIsLevel())) { ResetLevelProgress(); } if (levelNumber.HasValue) { instance.levelsCompleted = levelNumber.Value - 1; SemiFunc.StatSetRunLevel(instance.levelsCompleted); } instance.debugLevel = level; try { instance.ChangeLevel(false, false, (ChangeLevelType)0); } finally { instance.debugLevel = null; } } public static Level PickRandomMap() { return PickRandom(Maps); } public static Level PickRandomShop() { return PickRandom(Shops); } private static Level PickRandom(IEnumerable<Level> levels) { List<Level> list = levels.ToList(); List<Level> list2 = list.Where((Level l) => (Object)(object)l != (Object)(object)RunManager.instance.levelCurrent).ToList(); List<Level> list3 = ((list2.Count > 0) ? list2 : list); if (list3.Count <= 0) { return null; } return list3[Random.Range(0, list3.Count)]; } private static void ResetLevelProgress() { if (Object.op_Implicit((Object)(object)DebugCommandHandler.instance) && ResetLevelProgressMethod != null) { ResetLevelProgressMethod.Invoke(DebugCommandHandler.instance, null); } else { Plugin.Log.LogWarning((object)"DebugCommandHandler.ResetLevelProgress not available; progress not reset."); } } } internal enum ProgressMode { RevertToLastSave, KeepCurrent } internal static class Settings { public static ConfigEntry<Key> WindowToggleKey { get; private set; } public static ConfigEntry<ProgressMode> Progress { get; private set; } public static void Bind(ConfigFile config) { WindowToggleKey = config.Bind<Key>("Window", "ToggleKey", (Key)70, "Key that opens/closes the Scene Switcher window (host only). Set to None to disable the window."); Progress = config.Bind<ProgressMode>("Saves", "ProgressOnSceneChange", ProgressMode.RevertToLastSave, "What happens to the run's progress in saved (private) lobbies when you switch scene. RevertToLastSave: go back to the last save first. KeepCurrent: keep money, upgrades and level as they are now. Going from a map to a shop always keeps progress. Arenas are the Game Over screen: entering one deletes the save file, as in vanilla."); } } } namespace SceneSwitcher.Ui { internal sealed class SceneWindow : MonoBehaviour { private const int MaxLevel = 50; private const float ReferenceHeight = 1080f; private const float BlockTime = 0.1f; private static readonly List<InputKey> NoControls = new List<InputKey>(); private ConfigEntry<Key> _toggleKey; private bool _visible; private Rect _windowRect = new Rect(40f, 40f, 340f, 640f); private Vector2 _scroll; private int _level; private int? SelectedLevel { get { if (_level != 0) { return _level; } return null; } } public static void Create(ConfigEntry<Key> toggleKey) { //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_0010: Expected O, but got Unknown //IL_0010: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SceneSwitcher.SceneWindow"); Object.DontDestroyOnLoad((Object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<SceneWindow>()._toggleKey = toggleKey; } private void Update() { if (!CrashReporter.Guard("window", UpdateWindow)) { Shutdown(); } } private void Shutdown() { Close(); ((Behaviour)this).enabled = false; } private void UpdateWindow() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) Keyboard current = Keyboard.current; if (current == null) { return; } Key value = _toggleKey.Value; if ((int)value != 0 && ((ButtonControl)current[value]).wasPressedThisFrame && SemiFunc.NoTextInputsActive()) { Toggle(); } if (_visible) { if (((ButtonControl)current.escapeKey).wasPressedThisFrame || !SceneSwitchService.CanSwitch(out var _)) { Close(); } else { BlockGame(); } } } private void Toggle() { if (_visible) { Close(); return; } if (!SceneSwitchService.CanSwitch(out var reason)) { Feedback.Fail(reason); return; } _visible = true; BlockGame(); } private void Close() { _visible = false; Cursor.visible = false; } private static void BlockGame() { if (Object.op_Implicit((Object)(object)CursorManager.instance)) { CursorManager.instance.Unlock(0.1f); } Cursor.visible = true; if (Object.op_Implicit((Object)(object)MenuCursor.instance)) { MenuCursor.instance.OverrideHide(0.1f); } if (Object.op_Implicit((Object)(object)InputManager.instance)) { InputManager.instance.DisableMovement(0.1f); InputManager.instance.DisableAiming(0.1f); InputManager.instance.DisableControlsExcept(0.1f, NoControls); } } private void OnGUI() { //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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (_visible) { float num = (float)Screen.height / 1080f; GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f)); _windowRect = GUILayout.Window(((Object)this).GetInstanceID(), _windowRect, new WindowFunction(DrawWindow), "Scene Switcher (host)", Array.Empty<GUILayoutOption>()); } } private void DrawWindow(int windowId) { try { DrawWindowContents(); } catch (Exception ex) when (!(ex is ExitGUIException)) { CrashReporter.Report(ex, "window GUI"); Shutdown(); } } private void DrawWindowContents() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) GUILayout.Label((_level == 0) ? "Level: keep current" : $"Level: {_level}", Array.Empty<GUILayoutOption>()); _level = Mathf.RoundToInt(GUILayout.HorizontalSlider((float)_level, 0f, 50f, Array.Empty<GUILayoutOption>())); GUILayout.Space(6f); _scroll = GUILayout.BeginScrollView(_scroll, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Lobby menu", Array.Empty<GUILayoutOption>())) { Run(SceneLauncher.ReturnToLobbyMenu); } if (GUILayout.Button("Truck", Array.Empty<GUILayoutOption>())) { Run(delegate { SceneLauncher.Launch(SceneSwitchService.Truck, SelectedLevel, "the truck"); }); } Section("Shops"); if (GUILayout.Button("Random shop", Array.Empty<GUILayoutOption>())) { Run(delegate { SceneLauncher.LaunchRandom(SceneSwitchService.PickRandomShop(), SelectedLevel, "shops"); }); } foreach (Level shop in SceneSwitchService.Shops) { if (GUILayout.Button(LevelNameResolver.DisplayName(((Object)shop).name), Array.Empty<GUILayoutOption>())) { Run(delegate { SceneLauncher.Launch(shop, SelectedLevel); }); } } Section("Maps"); if (GUILayout.Button("Random map", Array.Empty<GUILayoutOption>())) { Run(delegate { SceneLauncher.LaunchRandom(SceneSwitchService.PickRandomMap(), SelectedLevel, "maps"); }); } foreach (Level map in SceneSwitchService.Maps) { if (GUILayout.Button(LevelNameResolver.DisplayName(((Object)map).name), Array.Empty<GUILayoutOption>())) { Run(delegate { SceneLauncher.Launch(map, SelectedLevel); }); } } Section("Arenas"); foreach (Level arena in SceneSwitchService.Arenas) { if (GUILayout.Button(LevelNameResolver.DisplayName(((Object)arena).name), Array.Empty<GUILayoutOption>())) { Run(delegate { SceneLauncher.Launch(arena, null); }); } } GUILayout.EndScrollView(); if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>())) { Close(); } GUI.DragWindow(); } private static void Section(string title) { GUILayout.Space(8f); GUILayout.Label(title, Array.Empty<GUILayoutOption>()); } private void Run(Action action) { Close(); CrashReporter.Guard("window button", action); } } } namespace SceneSwitcher.Patches { [HarmonyPatch(typeof(LevelGenerator), "GenerateDoneApply")] internal static class LevelCatalogLogger { private static bool _logged; [HarmonyPostfix] private static void Postfix() { if (!_logged && !((Object)(object)RunManager.instance == (Object)null)) { _logged = true; CrashReporter.Guard("level catalog", LogCatalog); } } private static void LogCatalog() { RunManager instance = RunManager.instance; ManualLogSource log = Plugin.Log; Level levelCurrent = instance.levelCurrent; log.LogInfo((object)$"Current level: {((levelCurrent != null) ? ((Object)levelCurrent).name : null)} | levelsCompleted: {instance.levelsCompleted}"); ManualLogSource log2 = Plugin.Log; Level levelLobby = instance.levelLobby; string obj = ((levelLobby != null) ? ((Object)levelLobby).name : null); Level levelLobbyMenu = instance.levelLobbyMenu; log2.LogInfo((object)("Lobby: " + obj + " | Lobby menu: " + ((levelLobbyMenu != null) ? ((Object)levelLobbyMenu).name : null))); Plugin.Log.LogInfo((object)("Arenas: " + string.Join(", ", from l in instance.levelArena where Object.op_Implicit((Object)(object)l) select ((Object)l).name))); Plugin.Log.LogInfo((object)("Shops: " + string.Join(", ", from l in instance.levelShop where Object.op_Implicit((Object)(object)l) select ((Object)l).name))); Plugin.Log.LogInfo((object)("Run levels: " + string.Join(", ", from l in instance.levels where Object.op_Implicit((Object)(object)l) select ((Object)l).name))); } } } namespace SceneSwitcher.Core { public enum ResolveStatus { Found, NotFound, Ambiguous } public sealed class ResolveResult { public ResolveStatus Status { get; } public string Match { get; } public IReadOnlyList<string> Candidates { get; } private ResolveResult(ResolveStatus status, string match, IReadOnlyList<string> candidates) { Status = status; Match = match; Candidates = candidates; } public static ResolveResult Found(string match) { return new ResolveResult(ResolveStatus.Found, match, Array.Empty<string>()); } public static ResolveResult NotFound() { return new ResolveResult(ResolveStatus.NotFound, null, Array.Empty<string>()); } public static ResolveResult Ambiguous(IReadOnlyList<string> candidates) { return new ResolveResult(ResolveStatus.Ambiguous, null, candidates); } } public static class LevelNameResolver { public const string LevelPrefix = "Level - "; public static string DisplayName(string levelName) { if (string.IsNullOrEmpty(levelName)) { return string.Empty; } if (!levelName.StartsWith("Level - ", StringComparison.OrdinalIgnoreCase)) { return levelName; } return levelName.Substring("Level - ".Length); } public static string Normalize(string name) { string[] value = DisplayName(name?.Trim()).Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); return string.Join(" ", value).ToLowerInvariant(); } public static ResolveResult Resolve(string query, IEnumerable<string> levelNames) { string normalizedQuery = Normalize(query); if (normalizedQuery.Length == 0) { return ResolveResult.NotFound(); } List<string> source = levelNames.Where((string n) => !string.IsNullOrEmpty(n)).Distinct().ToList(); List<string> list = source.Where((string n) => Normalize(n) == normalizedQuery).ToList(); if (list.Count > 0) { if (list.Count != 1) { return ResolveResult.Ambiguous(list); } return ResolveResult.Found(list[0]); } List<string> list2 = source.Where((string n) => Normalize(n).StartsWith(normalizedQuery, StringComparison.Ordinal)).ToList(); if (list2.Count > 0) { if (list2.Count != 1) { return ResolveResult.Ambiguous(list2); } return ResolveResult.Found(list2[0]); } List<string> list3 = source.Where((string n) => Normalize(n).Contains(normalizedQuery)).ToList(); if (list3.Count > 0) { if (list3.Count != 1) { return ResolveResult.Ambiguous(list3); } return ResolveResult.Found(list3[0]); } return ResolveResult.NotFound(); } } public enum SceneAction { Help, List, LobbyMenu, Truck, Arena, Map, RandomMap, Shop, RandomShop, Crimson } public sealed class SceneRequest { public SceneAction Action { get; set; } public string Query { get; set; } public string RawQuery { get; set; } public int? LevelNumber { get; set; } public string Error { get; set; } } public static class SceneCommandParser { public const string Usage = "/scene lobby | truck [level] | shop [zone|random] [level] | map <name|random> [level] | arena <fight|race> | list"; private const string ShopPrefix = "Shop "; private static readonly Dictionary<string, string> ArenaAliases = new Dictionary<string, string> { { "fight", "Arena Fight" }, { "disposal", "Arena Fight" }, { "race", "Arena Race" }, { "cars", "Arena Race" }, { "race cars", "Arena Race" }, { "racecars", "Arena Race" } }; public static SceneRequest Parse(string[] args) { if (args == null || args.Length == 0) { return new SceneRequest { Action = SceneAction.Help }; } string text = args[0].ToLowerInvariant(); string[] rest = args.Skip(1).ToArray(); switch (text) { case "help": return new SceneRequest { Action = SceneAction.Help }; case "crimson": return new SceneRequest { Action = SceneAction.Crimson }; case "list": return new SceneRequest { Action = SceneAction.List }; case "lobby": case "menu": return new SceneRequest { Action = SceneAction.LobbyMenu }; case "truck": return ParseTruck(rest); case "arena": return ParseArena(rest); case "map": return ParseMap(rest); case "shop": return ParseShop(rest); default: return new SceneRequest { Action = SceneAction.Help, Error = "Unknown option '" + args[0] + "'." }; } } private static SceneRequest ParseArena(string[] rest) { if (rest.Length == 0) { return new SceneRequest { Action = SceneAction.Arena, Error = "Missing arena: fight or race." }; } string text = string.Join(" ", rest); if (ArenaAliases.TryGetValue(text.ToLowerInvariant(), out var value)) { text = value; } return new SceneRequest { Action = SceneAction.Arena, Query = text, RawQuery = text }; } private static SceneRequest ParseTruck(string[] rest) { SceneRequest sceneRequest = new SceneRequest { Action = SceneAction.Truck }; if (rest.Length > 1 || (rest.Length == 1 && !int.TryParse(rest[0], out var _))) { sceneRequest.Error = "Usage: /scene truck [level]."; return sceneRequest; } if (rest.Length == 1) { SetLevelNumber(sceneRequest, int.Parse(rest[0])); } return sceneRequest; } private static SceneRequest ParseMap(string[] rest) { if (rest.Length == 0) { return new SceneRequest { Action = SceneAction.Map, Error = "Missing map name." }; } return ParseNamedTarget(rest, SceneAction.Map, SceneAction.RandomMap); } private static SceneRequest ParseShop(string[] rest) { if (rest.Length == 0) { return new SceneRequest { Action = SceneAction.RandomShop }; } if (rest.Length == 1 && int.TryParse(rest[0], out var result)) { SceneRequest obj = new SceneRequest { Action = SceneAction.RandomShop }; SetLevelNumber(obj, result); return obj; } SceneRequest sceneRequest = ParseNamedTarget(rest, SceneAction.Shop, SceneAction.RandomShop); if (sceneRequest.Error == null && sceneRequest.Action == SceneAction.Shop) { sceneRequest.Query = WithShopPrefix(sceneRequest.Query); sceneRequest.RawQuery = WithShopPrefix(sceneRequest.RawQuery); } return sceneRequest; } private static SceneRequest ParseNamedTarget(string[] rest, SceneAction action, SceneAction randomAction) { SceneRequest sceneRequest = new SceneRequest { Action = action, RawQuery = string.Join(" ", rest) }; string[] value = rest; if (rest.Length > 1 && int.TryParse(rest[^1], out var result)) { if (!SetLevelNumber(sceneRequest, result)) { return sceneRequest; } value = rest.Take(rest.Length - 1).ToArray(); } sceneRequest.Query = string.Join(" ", value); if (sceneRequest.Query.Equals("random", StringComparison.OrdinalIgnoreCase)) { sceneRequest.Action = randomAction; } return sceneRequest; } private static bool SetLevelNumber(SceneRequest request, int number) { if (number < 1) { request.Error = "Level number must be 1 or higher."; return false; } request.LevelNumber = number; return true; } private static string WithShopPrefix(string query) { string text = LevelNameResolver.DisplayName(query.Trim()); if (!text.StartsWith("Shop ", StringComparison.OrdinalIgnoreCase)) { return "Shop " + text; } return text; } public static ResolveResult ResolveTarget(SceneRequest request, IEnumerable<string> levelNames, out int? levelNumber) { List<string> list = levelNames.ToList(); levelNumber = request.LevelNumber; if (request.LevelNumber.HasValue) { string fullQuery = LevelNameResolver.Normalize(request.RawQuery); List<string> list2 = list.Where((string n) => LevelNameResolver.Normalize(n) == fullQuery).ToList(); if (list2.Count == 1) { levelNumber = null; return ResolveResult.Found(list2[0]); } } ResolveResult resolveResult = LevelNameResolver.Resolve(request.Query, list); if (resolveResult.Status == ResolveStatus.NotFound && request.LevelNumber.HasValue) { ResolveResult resolveResult2 = LevelNameResolver.Resolve(request.RawQuery, list); if (resolveResult2.Status != ResolveStatus.NotFound) { levelNumber = null; return resolveResult2; } } return resolveResult; } } } namespace SceneSwitcher.Commands { [HarmonyPatch(typeof(DebugCommandHandler), "Start")] internal static class SceneChatCommand { private const string CommandName = "scene"; private const string CrimsonLine = "guatona culia fea"; [HarmonyPostfix] private static void Postfix(DebugCommandHandler __instance) { if (!((Object)(object)__instance != (Object)(object)DebugCommandHandler.instance)) { CrashReporter.Guard("command registration", delegate { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown __instance.Register(new ChatCommand("scene", "Host only. Switch scene: /scene lobby | truck [level] | shop [zone|random] [level] | map <name|random> [level] | arena <fight|race> | list", (Action<bool, string[]>)Execute, (Func<bool, string, string[], List<string>>)Suggest, (Func<bool>)null, false)); Plugin.Log.LogInfo((object)"Registered chat command /scene."); }); } } private static void Execute(bool isDebugConsole, string[] args) { CrashReporter.Guard("/scene " + string.Join(" ", args), delegate { ExecuteRequest(args); }); } private static void ExecuteRequest(string[] args) { SceneRequest sceneRequest = SceneCommandParser.Parse(args); if (sceneRequest.Error != null) { Feedback.Fail(sceneRequest.Error + " Usage: /scene lobby | truck [level] | shop [zone|random] [level] | map <name|random> [level] | arena <fight|race> | list"); return; } switch (sceneRequest.Action) { case SceneAction.Help: Feedback.Info("/scene lobby | truck [level] | shop [zone|random] [level] | map <name|random> [level] | arena <fight|race> | list"); return; case SceneAction.List: ListLevels(); return; case SceneAction.Crimson: if (Object.op_Implicit((Object)(object)PlayerAvatar.instance)) { PlayerAvatar.instance.ChatMessageSend("guatona culia fea", (string)null); } return; } if (!SceneSwitchService.CanSwitch(out var reason)) { Feedback.Fail(reason); return; } switch (sceneRequest.Action) { case SceneAction.LobbyMenu: SceneLauncher.ReturnToLobbyMenu(); break; case SceneAction.Truck: SceneLauncher.Launch(SceneSwitchService.Truck, sceneRequest.LevelNumber, "the truck"); break; case SceneAction.Arena: LaunchResolved(sceneRequest, SceneSwitchService.Arenas.ToList(), "arena"); break; case SceneAction.Map: LaunchResolved(sceneRequest, SceneSwitchService.Maps.ToList(), "map"); break; case SceneAction.RandomMap: SceneLauncher.LaunchRandom(SceneSwitchService.PickRandomMap(), sceneRequest.LevelNumber, "maps"); break; case SceneAction.Shop: LaunchResolved(sceneRequest, SceneSwitchService.Shops.ToList(), "shop"); break; case SceneAction.RandomShop: SceneLauncher.LaunchRandom(SceneSwitchService.PickRandomShop(), sceneRequest.LevelNumber, "shops"); break; } } private static void LaunchResolved(SceneRequest request, List<Level> candidates, string kind) { int? levelNumber; ResolveResult result = SceneCommandParser.ResolveTarget(request, candidates.Select((Level l) => ((Object)l).name), out levelNumber); switch (result.Status) { case ResolveStatus.NotFound: Feedback.Fail("No " + kind + " matches '" + request.Query + "'. Try /scene list."); break; case ResolveStatus.Ambiguous: Feedback.Fail("'" + request.Query + "' matches: " + string.Join(", ", result.Candidates.Select(LevelNameResolver.DisplayName))); break; default: SceneLauncher.Launch(candidates.First((Level l) => ((Object)l).name == result.Match), levelNumber); break; } } private static void ListLevels() { if (!Object.op_Implicit((Object)(object)RunManager.instance)) { Feedback.Fail("Game is not ready."); return; } string text = string.Join(", ", SceneSwitchService.Maps.Select((Level l) => LevelNameResolver.DisplayName(((Object)l).name))); string text2 = string.Join(", ", SceneSwitchService.Arenas.Select((Level l) => LevelNameResolver.DisplayName(((Object)l).name))); string text3 = string.Join(", ", SceneSwitchService.Shops.Select((Level l) => ShopZone(((Object)l).name))); Feedback.Info("Maps: " + text + "\nShops: " + text3 + "\nArenas: " + text2, 8f); } internal static string ShopZone(string levelName) { string text = LevelNameResolver.Normalize(levelName); if (!text.StartsWith("shop ")) { return text; } return text.Substring("shop ".Length); } private static List<string> Suggest(bool isDebugConsole, string partial, string[] args) { IEnumerable<string> source = ((args.Length <= 1) ? new string[7] { "lobby", "truck", "shop", "map", "arena", "list", "help" } : ((args[0].ToLowerInvariant() == "shop" && Object.op_Implicit((Object)(object)RunManager.instance)) ? SceneSwitchService.Shops.Select((Level l) => ShopZone(((Object)l).name)).Prepend("random") : ((args[0].ToLowerInvariant() == "arena") ? new string[2] { "fight", "race" } : ((!(args[0].ToLowerInvariant() == "map") || !Object.op_Implicit((Object)(object)RunManager.instance)) ? Enumerable.Empty<string>() : SceneSwitchService.Maps.Select((Level l) => LevelNameResolver.Normalize(((Object)l).name)).Prepend("random"))))); return source.Where((string o) => o.StartsWith(partial.ToLowerInvariant())).ToList(); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }