using System.Text; using PluginLoader.Data; using PluginLoader.Patch; using PluginLoader.Stats; using PluginLoader.Stats.Model; using Sandbox; using Sandbox.Game.Gui; using Sandbox.Game.Multiplayer; using Sandbox.Game.Screens.Helpers; using Sandbox.Game.World; using Sandbox.Graphics.GUI; using VRage; using VRage.Audio; using VRage.Game; using VRage.Input; using VRage.Utils; using VRageMath; using static Sandbox.Graphics.GUI.MyGuiScreenMessageBox; using Parallel = ParallelTasks.Parallel; namespace PluginLoader.GUI; public class MyGuiScreenPluginConfig : MyGuiScreenBase { private const float BarWidth = 0.85f; private const float Spacing = 0.0175f; private static bool allItemsVisible = true; private static bool _hideLocalPlugins = true; public readonly Dictionary AfterRebootEnableFlags = new(); private readonly Dictionary pluginCheckboxes = new(); private readonly PluginDetailsPanel pluginDetails; private MyGuiControlButton buttonMore; private MyGuiControlContextMenu contextMenu; private bool forceRestart; private MyGuiControlContextMenu pluginContextMenu; private MyGuiControlLabel pluginCountLabel; public PluginStats PluginStats; private MyGuiControlTable pluginTable; private string[] tableFilter; /// /// The plugins screen, the constructor itself sets up the menu properties. /// private MyGuiScreenPluginConfig() : base(new Vector2(0.5f, 0.5f), MyGuiConstants.SCREEN_BACKGROUND_COLOR, new Vector2(1f, 0.97f), false, null, MySandboxGame.Config.UIBkOpacity, MySandboxGame.Config.UIOpacity) { EnabledBackgroundFade = true; m_closeOnEsc = true; m_drawEvenWithoutFocus = true; CanHideOthers = true; CanBeHidden = true; CloseButtonEnabled = true; foreach (var plugin in Main.Instance.List) AfterRebootEnableFlags[plugin.Id] = plugin.Enabled; pluginDetails = new(this); } private static PluginConfig Config => Main.Instance.Config; private PluginData SelectedPlugin { get => pluginDetails.Plugin; set => pluginDetails.Plugin = value; } private bool RequiresRestart => forceRestart || Main.Instance.List.Any( plugin => plugin.Enabled != AfterRebootEnableFlags[plugin.Id]); public static void OpenMenu() { if (Main.Instance.List.HasError) MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(buttonType: MyMessageBoxButtonsType.OK, messageText: new( "An error occurred while downloading the plugin list.\nPlease send your game log to the developers of Plugin Loader."), messageCaption: MyTexts.Get( MyCommonTexts.MessageBoxCaptionError), callback: x => MyGuiSandbox.AddScreen( new MyGuiScreenPluginConfig()))); else MyGuiSandbox.AddScreen(new MyGuiScreenPluginConfig()); } public override string GetFriendlyName() { return "MyGuiScreenPluginConfig"; } public override void LoadContent() { base.LoadContent(); RecreateControls(true); PlayerConsent.OnConsentChanged += OnConsentChanged; } public override void HandleUnhandledInput(bool receivedFocusInThisUpdate) { var input = MyInput.Static; if (input.IsNewKeyPressed(MyKeys.F5) && input.IsAnyAltKeyPressed() && input.IsAnyCtrlKeyPressed()) Patch_IngameRestart.ShowRestartMenu(); } public override void UnloadContent() { PlayerConsent.OnConsentChanged -= OnConsentChanged; pluginDetails.OnPluginToggled -= EnablePlugin; base.UnloadContent(); } private void OnConsentChanged() { DownloadStats(); } private void DownloadStats() { LogFile.Log.Debug("Downloading user statistics", false); Parallel.Start(() => { PluginStats = StatsClient.DownloadStats(); }, OnDownloadedStats); } private void OnDownloadedStats() { pluginDetails?.LoadPluginData(); } /// /// Initializes the controls of the menu on the left side of the menu. /// public override void RecreateControls(bool constructor) { base.RecreateControls(constructor); var title = AddCaption("Plugins List"); // Sets the origin relative to the center of the caption on the X axis and to the bottom the caption on the y axis. var origin = title.Position += new Vector2(0f, title.Size.Y / 2); origin.Y += Spacing; // Adds a bar right below the caption. var titleBar = new MyGuiControlSeparatorList(); titleBar.AddHorizontal(new(origin.X - BarWidth / 2, origin.Y), BarWidth); Controls.Add(titleBar); origin.Y += Spacing; // Change the position of this to move the entire middle section of the menu, the menu bars, menu title, and bottom buttons won't move // Adds a search bar right below the bar on the left side of the menu. var searchBox = new MyGuiControlSearchBox(new Vector2(origin.X - BarWidth / 2, origin.Y), originAlign: MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP); // Changing the search box X size will change the plugin list length. searchBox.Size = new(0.4f, searchBox.Size.Y); searchBox.OnTextChanged += SearchBox_TextChanged; Controls.Add(searchBox); #region Visibility Button // Adds a button to show only enabled plugins. Located right of the search bar. var buttonVisibility = new MyGuiControlButton( new Vector2(origin.X - BarWidth / 2 + searchBox.Size.X, origin.Y) + new Vector2(0.003f, 0.002f), MyGuiControlButtonStyleEnum.Rectangular, new Vector2(searchBox.Size.Y * 2.52929769833f), onButtonClick: OnVisibilityClick, originAlign: MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, toolTip: "Show only enabled plugins.", buttonScale: 0.5f); if (allItemsVisible || Config.Count == 0) { allItemsVisible = true; buttonVisibility.Icon = IconHide; } else { buttonVisibility.Icon = IconShow; } Controls.Add(buttonVisibility); #endregion origin.Y += searchBox.Size.Y + Spacing; #region Plugin List // Adds the plugin list on the right of the menu below the search bar. pluginTable = new() { Position = new(origin.X - BarWidth / 2, origin.Y), Size = new(searchBox.Size.X + buttonVisibility.Size.X + 0.001f, 0.6f), // The y value can be bigger than the visible rows count as the visibleRowsCount controls the height. OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, ColumnsCount = 3, VisibleRowsCount = 20 }; pluginTable.SetCustomColumnWidths(new[] { 0.22f, 0.6f, 0.22f }); pluginTable.SetColumnName(0, new("Source")); pluginTable.SetColumnComparison(0, CellTextOrDataComparison); pluginTable.SetColumnName(1, new("Name")); pluginTable.SetColumnComparison(1, CellTextComparison); pluginTable.SetColumnName(2, new("Enable")); pluginTable.SetColumnComparison(2, CellTextComparison); // Default sorting pluginTable.SortByColumn(2, MyGuiControlTable.SortStateEnum.Ascending); // Selecting list items load their details in OnItemSelected pluginTable.ItemSelected += OnItemSelected; Controls.Add(pluginTable); // Double clicking list items toggles the enable flag pluginTable.ItemDoubleClicked += OnItemDoubleClicked; #endregion origin.Y += Spacing + pluginTable.Size.Y; // Adds the bar at the bottom between just above the buttons. var bottomBar = new MyGuiControlSeparatorList(); bottomBar.AddHorizontal(new(origin.X - BarWidth / 2, origin.Y), BarWidth); Controls.Add(bottomBar); origin.Y += Spacing; // Adds buttons at bottom of menu var buttonRestart = new MyGuiControlButton(origin, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP, "Restart the game and apply changes.", new("Apply"), 0.8f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, MyGuiControlHighlightType.WHEN_ACTIVE, OnRestartButtonClick); var buttonClose = new MyGuiControlButton(origin, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP, "Closes the dialog without saving changes to plugin selection", new("Cancel"), 0.8f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, MyGuiControlHighlightType.WHEN_ACTIVE, OnCancelButtonClick); buttonMore = new(origin, MyGuiControlButtonStyleEnum.Tiny, null, null, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_TOP, "Advanced", new("..."), 0.8f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, MyGuiControlHighlightType.WHEN_ACTIVE, OnMoreButtonClick); // FIXME: Use MyLayoutHorizontal instead AlignRow(origin, 0.05f, buttonRestart, buttonClose); Controls.Add(buttonRestart); Controls.Add(buttonClose); buttonMore.Position = buttonClose.Position + new Vector2(buttonClose.Size.X / 2 + 0.05f, 0); Controls.Add(buttonMore); // Adds a place to show the total amount of plugins and to show the total amount of visible plugins. pluginCountLabel = new(new Vector2(origin.X - BarWidth / 2, buttonRestart.Position.Y), originAlign: MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP); Controls.Add(pluginCountLabel); // Right side panel showing the details of the selected plugin var rightSideOrigin = buttonVisibility.Position + new Vector2(Spacing * 1.778f + buttonVisibility.Size.X / 2, -(buttonVisibility.Size.Y / 2)); pluginDetails.CreateControls(rightSideOrigin); Controls.Add(pluginDetails); pluginDetails.OnPluginToggled += EnablePlugin; // Context menu for the more (...) button contextMenu = new(); contextMenu.Deactivate(); contextMenu.CreateNewContextMenu(); contextMenu.AddItem(new("Add development folder"), "Open and compile a folder for development", userData: nameof(OnLoadFolder)); contextMenu.AddItem(new("Save profile"), "Saved the current plugin selection", userData: nameof(OnSaveProfile)); contextMenu.AddItem(new("Load profile"), "Loads a saved plugin selection", userData: nameof(OnLoadProfile)); contextMenu.AddItem(new("------------")); contextMenu.AddItem( new(PlayerConsent.ConsentGiven ? "Revoke consent" : "Give consent"), PlayerConsent.ConsentGiven ? "Revoke consent to data handling, clear my votes" : "Give consent to data handling, allow me to vote", userData: nameof(OnConsent)); contextMenu.Enabled = true; contextMenu.ItemClicked += OnContextMenuItemClicked; contextMenu.OnDeactivated += OnContextMenuDeactivated; // contextMenu.SetMaxSize(new Vector2(0.2f, 0.7f)); Controls.Add(contextMenu); // Context menu for the plugin list pluginContextMenu = new(); pluginContextMenu.Deactivate(); pluginContextMenu.CreateNewContextMenu(); pluginContextMenu.ItemClicked += OnPluginContextMenuItemClicked; pluginContextMenu.OnDeactivated += OnContextMenuDeactivated; Controls.Add(pluginContextMenu); // Refreshes the table to show plugins on plugin list RefreshTable(); DownloadStats(); } public void RequireRestart() { forceRestart = true; } private void OnLoadFolder() { LocalFolderPlugin.CreateNew(plugin => { Config.PluginFolders[plugin.Id] = plugin.FolderSettings; CreatePlugin(plugin); }); } public void CreatePlugin(PluginData data) { Main.Instance.List.Add(data); AfterRebootEnableFlags[data.Id] = true; Config.SetEnabled(data.Id, true); forceRestart = true; RefreshTable(tableFilter); } public void RemovePlugin(PluginData data) { Main.Instance.List.Remove(data.Id); AfterRebootEnableFlags.Remove(data.Id); Config.SetEnabled(data.Id, false); forceRestart = true; RefreshTable(tableFilter); } public void RefreshSidePanel() { pluginDetails?.LoadPluginData(); } /// /// Event that triggers when the visibility button is clicked. This method shows all plugins or only enabled plugins. /// /// The button to assign this event to. private void OnVisibilityClick(MyGuiControlButton btn) { if (allItemsVisible && _hideLocalPlugins) { allItemsVisible = false; btn.Icon = IconShow; } else if (_hideLocalPlugins) { allItemsVisible = true; _hideLocalPlugins = false; } else { _hideLocalPlugins = true; btn.Icon = IconHide; } RefreshTable(tableFilter); } private static int CellTextOrDataComparison(MyGuiControlTable.Cell x, MyGuiControlTable.Cell y) { var result = TextComparison(x.Text, y.Text); if (result != 0) return result; return TextComparison((StringBuilder)x.UserData, (StringBuilder)y.UserData); } private static int CellTextComparison(MyGuiControlTable.Cell x, MyGuiControlTable.Cell y) { return TextComparison(x.Text, y.Text); } private static int TextComparison(StringBuilder x, StringBuilder y) { if (x == null) { if (y == null) return 0; return 1; } if (y == null) return -1; return x.CompareTo(y); } /// /// Clears the table and adds the list of plugins and their information. /// /// Text filter private void RefreshTable(string[] filter = null) { pluginTable.Clear(); pluginTable.Controls.Clear(); pluginCheckboxes.Clear(); var list = Main.Instance.List; var noFilter = filter == null || filter.Length == 0; foreach (var plugin in list) { var enabled = AfterRebootEnableFlags[plugin.Id]; if (plugin.IsLocal && _hideLocalPlugins) continue; if (noFilter && (plugin.Hidden || !allItemsVisible) && !enabled) continue; if (!noFilter && !FilterName(plugin.FriendlyName, filter)) continue; var row = new MyGuiControlTable.Row(plugin); pluginTable.Add(row); var name = new StringBuilder(plugin.FriendlyName); row.AddCell(new(plugin.Source, name)); var tip = plugin.FriendlyName; if (!string.IsNullOrWhiteSpace(plugin.Tooltip)) tip += "\n" + plugin.Tooltip; row.AddCell(new(plugin.FriendlyName, toolTip: tip)); var text = new StringBuilder(FormatCheckboxSortKey(plugin, enabled)); var enabledCell = new MyGuiControlTable.Cell(text, name); var enabledCheckbox = new MyGuiControlCheckbox(isChecked: enabled) { UserData = plugin, Visible = true }; enabledCheckbox.IsCheckedChanged += OnPluginCheckboxChanged; enabledCell.Control = enabledCheckbox; pluginTable.Controls.Add(enabledCheckbox); pluginCheckboxes[plugin.Id] = enabledCheckbox; row.AddCell(enabledCell); } pluginCountLabel.Text = pluginTable.RowsCount + "/" + list.Count + " visible"; pluginTable.Sort(false); pluginTable.SelectedRowIndex = null; tableFilter = filter; pluginTable.SelectedRowIndex = 0; var args = new MyGuiControlTable.EventArgs { RowIndex = 0 }; OnItemSelected(pluginTable, args); } private static string FormatCheckboxSortKey(PluginData plugin, bool enabled) { // Uses a prefix of + and - to list plugins to enable to the top return enabled ? $"+{plugin.FriendlyName}|{plugin.Source}" : $"-{plugin.FriendlyName}|{plugin.Source}"; } /// /// Event that triggers when the text in the searchbox is changed. /// /// The text that was entered into the searchbox. private void SearchBox_TextChanged(string txt) { var args = txt.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); RefreshTable(args); } private static bool FilterName(string name, IEnumerable filter) { return filter.All(s => name.Contains(s, StringComparison.OrdinalIgnoreCase)); } /// /// Sets text on right side of screen. /// /// Table to get the plugin data. /// Event arguments. private void OnItemSelected(MyGuiControlTable table, MyGuiControlTable.EventArgs args) { if (!TryGetPluginByRowIndex(args.RowIndex, out var plugin)) return; if (args.MouseButton == MyMouseButtonsEnum.Right && plugin.OpenContextMenu(pluginContextMenu)) { pluginContextMenu.ItemList_UseSimpleItemListMouseOverCheck = true; pluginContextMenu.Activate(); } contextMenu.Deactivate(); SelectedPlugin = plugin; } private void OnItemDoubleClicked(MyGuiControlTable table, MyGuiControlTable.EventArgs args) { if (!TryGetPluginByRowIndex(args.RowIndex, out var data)) return; EnablePlugin(data, !AfterRebootEnableFlags[data.Id]); } private bool TryGetPluginByRowIndex(int rowIndex, out PluginData plugin) { if (rowIndex < 0 || rowIndex >= pluginTable.RowsCount) { plugin = null; return false; } var row = pluginTable.GetRow(rowIndex); plugin = row.UserData as PluginData; return plugin != null; } private void AlignRow(Vector2 origin, float spacing, params MyGuiControlBase[] elements) { if (elements.Length == 0) return; float totalWidth = 0; for (var i = 0; i < elements.Length; i++) { var btn = elements[i]; totalWidth += btn.Size.X; if (i < elements.Length - 1) totalWidth += spacing; } var originX = origin.X - totalWidth / 2; foreach (var btn in elements) { var halfWidth = btn.Size.X / 2; originX += halfWidth; btn.Position = new(originX, origin.Y); originX += spacing + halfWidth; } } private void OnPluginCheckboxChanged(MyGuiControlCheckbox checkbox) { var plugin = (PluginData)checkbox.UserData; EnablePlugin(plugin, checkbox.IsChecked); if (ReferenceEquals(plugin, SelectedPlugin)) pluginDetails.LoadPluginData(); } public void EnablePlugin(PluginData plugin, bool enable) { if (enable == AfterRebootEnableFlags[plugin.Id]) return; AfterRebootEnableFlags[plugin.Id] = enable; SetPluginCheckbox(plugin, enable); if (enable) { DisableOtherPluginsInSameGroup(plugin); EnableDependencies(plugin); } } private void SetPluginCheckbox(PluginData plugin, bool enable) { if (!pluginCheckboxes.TryGetValue(plugin.Id, out var checkbox)) return; // The checkbox might not exist if the target plugin is a dependency not currently in the table checkbox.IsChecked = enable; var row = pluginTable.Find(x => ReferenceEquals(x.UserData as PluginData, plugin)); row?.GetCell(2).Text.Clear().Append(FormatCheckboxSortKey(plugin, enable)); } private void DisableOtherPluginsInSameGroup(PluginData plugin) { foreach (var other in plugin.Group) if (!ReferenceEquals(other, plugin)) EnablePlugin(other, false); } private void EnableDependencies(PluginData plugin) { if (plugin is not ModPlugin mod || mod.Dependencies == null) return; foreach (PluginData other in mod.Dependencies) if (!ReferenceEquals(other, plugin)) EnablePlugin(other, true); } private void OnCancelButtonClick(MyGuiControlButton btn) { CloseScreen(); } private void OnMoreButtonClick(MyGuiControlButton _) { contextMenu.ItemList_UseSimpleItemListMouseOverCheck = true; contextMenu.Enabled = false; contextMenu.Activate(false); contextMenu.OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP; contextMenu.Position = buttonMore.Position + buttonMore.Size * new Vector2(-1.3f, -1.9f); FocusContextMenuList(); } private void FocusContextMenuList() { var guiControlsOwner = (IMyGuiControlsOwner)contextMenu; while (guiControlsOwner.Owner != null) { guiControlsOwner = guiControlsOwner.Owner; if (guiControlsOwner is not MyGuiScreenBase myGuiScreenBase) continue; myGuiScreenBase.FocusedControl = contextMenu.GetInnerList(); break; } } private void OnContextMenuDeactivated() { contextMenu.Enabled = true; } private void OnContextMenuItemClicked(MyGuiControlContextMenu _, MyGuiControlContextMenu.EventArgs args) { contextMenu.Deactivate(); switch ((string)args.UserData) { case nameof(OnLoadFolder): OnLoadFolder(); break; case nameof(OnSaveProfile): OnSaveProfile(); break; case nameof(OnLoadProfile): OnLoadProfile(); break; case nameof(OnConsent): OnConsent(); break; } } private void OnPluginContextMenuItemClicked(MyGuiControlContextMenu menu, MyGuiControlContextMenu.EventArgs args) { SelectedPlugin?.ContextMenuClicked(this, args); } private void OnSaveProfile() { var timestamp = DateTime.Now.ToString("O").Substring(0, 19).Replace('T', ' '); MyGuiSandbox.AddScreen(new NameDialog(OnProfileNameProvided, "Save profile", timestamp)); } private void OnProfileNameProvided(string name) { var afterRebootEnablePluginIds = AfterRebootEnableFlags .Where(p => p.Value) .Select(p => p.Key); var profile = new Profile(name, afterRebootEnablePluginIds.ToArray()); Config.ProfileMap[profile.Key] = profile; Config.Save(); } private void OnLoadProfile() { MyGuiSandbox.AddScreen(new ProfilesDialog("Load profile", OnProfileLoaded)); } private void OnProfileLoaded(Profile profile) { var pluginsEnabledInProfile = profile.Plugins.ToHashSet(); foreach (var plugin in Main.Instance.List) EnablePlugin(plugin, pluginsEnabledInProfile.Contains(plugin.Id)); pluginTable.SortByColumn(2, MyGuiControlTable.SortStateEnum.Ascending); } private void OnConsent() { PlayerConsent.ShowDialog(); } private void OnRestartButtonClick(MyGuiControlButton btn) { if (!RequiresRestart) { CloseScreen(); return; } MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox(MyMessageBoxStyleEnum.Info, MyMessageBoxButtonsType.YES_NO_CANCEL, new( "A restart is required to apply changes. Would you like to restart the game now?"), new("Apply Changes?"), callback: AskRestartResult)); } private void Save() { if (!RequiresRestart) return; foreach (var plugin in Main.Instance.List) Config.SetEnabled(plugin.Id, AfterRebootEnableFlags[plugin.Id]); Config.Save(); } #region Icons // Source: MyTerminalControlPanel private static readonly MyGuiHighlightTexture IconHide = new() { Normal = "Textures\\GUI\\Controls\\button_hide.dds", Highlight = "Textures\\GUI\\Controls\\button_hide.dds", Focus = "Textures\\GUI\\Controls\\button_hide_focus.dds", SizePx = new(40f, 40f) }; // Source: MyTerminalControlPanel private static readonly MyGuiHighlightTexture IconShow = new() { Normal = "Textures\\GUI\\Controls\\button_unhide.dds", Highlight = "Textures\\GUI\\Controls\\button_unhide.dds", Focus = "Textures\\GUI\\Controls\\button_unhide_focus.dds", SizePx = new(40f, 40f) }; #endregion #region Restart private void AskRestartResult(ResultEnum result) { if (result == ResultEnum.YES) { Save(); if (MyGuiScreenGamePlay.Static != null) { ShowSaveMenu(delegate { LoaderTools.UnloadAndRestart(); }); return; } LoaderTools.UnloadAndRestart(); } else if (result == ResultEnum.NO) { Save(); CloseScreen(); } } /// /// From WesternGamer/InGameWorldLoading /// /// Action after code is executed. private static void ShowSaveMenu(Action afterMenu) { // Sync.IsServer is backwards if (!Sync.IsServer) { afterMenu(); return; } var message = ""; var isCampaign = false; var buttonsType = MyMessageBoxButtonsType.YES_NO_CANCEL; // Sync.IsServer is backwards if (Sync.IsServer && !MySession.Static.Settings.EnableSaving) { message += "Are you sure that you want to restart the game? All progress from the last checkpoint will be lost."; isCampaign = true; buttonsType = MyMessageBoxButtonsType.YES_NO; } else { message += "Save changes before restarting game?"; } var saveMenu = MyGuiSandbox.CreateMessageBox(buttonType: buttonsType, messageText: new(message), messageCaption: MyTexts.Get( MyCommonTexts.MessageBoxCaptionPleaseConfirm), callback: ShowSaveMenuCallback, cancelButtonText: MyStringId.GetOrCompute("Don't Restart")); saveMenu.InstantClose = false; MyGuiSandbox.AddScreen(saveMenu); void ShowSaveMenuCallback(ResultEnum callbackReturn) { if (isCampaign) { if (callbackReturn == ResultEnum.YES) afterMenu(); return; } switch (callbackReturn) { case ResultEnum.YES: MyAsyncSaving.Start(delegate { MySandboxGame.Static.OnScreenshotTaken += UnloadAndExitAfterScreenshotWasTaken; }); break; case ResultEnum.NO: MyAudio.Static.Mute = true; MyAudio.Static.StopMusic(); afterMenu(); break; } } void UnloadAndExitAfterScreenshotWasTaken(object sender, EventArgs e) { MySandboxGame.Static.OnScreenshotTaken -= UnloadAndExitAfterScreenshotWasTaken; afterMenu(); } } #endregion }