using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; using Barotrauma.CharacterEditor; using Barotrauma.LuaCs; using Barotrauma.LuaCs.Data; using Barotrauma.Networking; using Microsoft.Xna.Framework; // ReSharper disable ObjectCreationAsStatement namespace Barotrauma { partial class LuaCsSetup { private bool _isClientPromptActive; private bool _isCsEnabledForSession = false; public void CheckRunConditionalHostingCsEnabled(Action onReadyToRun) { var res = ReadyToRunNoPrompt(); if (res.ShouldRun) { onReadyToRun?.Invoke(); return; } DisplayCsModsPromptClient(res.Item2, (selectedYes) => { if (selectedYes) { onReadyToRun?.Invoke(); } }); } private (bool ShouldRun, ImmutableArray PromptPackages) ReadyToRunNoPrompt() { if (this.IsCsEnabled) { return (true, ImmutableArray.Empty); } if (!ShouldPromptForCs) { return (true, ImmutableArray.Empty); } ImmutableArray contentPackages = PackageManagementService.GetLoadedAssemblyPackages() .Where(p => p.Name != PackageId) .ToImmutableArray(); return (contentPackages.IsEmpty, contentPackages); } partial void CheckReadyToRun(Action onReadyToRun) { var res = ReadyToRunNoPrompt(); if (res.ShouldRun) { onReadyToRun?.Invoke(); return; } if (GameMain.Client?.ClientPeer is P2POwnerPeer) { SetCsPolicyAndContinue(true); return; } DisplayCsModsPromptClient(res.PromptPackages, (selectedYes) => { SetCsPolicyAndContinue(selectedYes); return; }); void SetCsPolicyAndContinue(bool csSessionExecutionPolicy) { var prevRunState = this.CurrentRunState; if (CurrentRunState >= RunState.Running) { SetRunState(RunState.LoadedNoExec); } this._isCsEnabledForSession = csSessionExecutionPolicy; CoroutineManager.Invoke(() => { if (CurrentRunState != prevRunState) { SetRunState(prevRunState); } onReadyToRun?.Invoke(); }, 0f); } } void DisplayCsModsPromptClient(ImmutableArray contentPackages, Action onSelection) { if (_isClientPromptActive) { return; } _isClientPromptActive = true; GUIMessageBox messageBox = new GUIMessageBox( TextManager.Get("warning"), relativeSize: new Vector2(0.3f, 0.55f), minSize: new Point(400, 500), text: string.Empty, buttons: []); GUILayoutGroup msgBoxLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.75f), messageBox.Content.RectTransform), isHorizontal: false, childAnchor: Anchor.TopCenter) { RelativeSpacing = 0.01f, Stretch = true }; new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), msgBoxLayout.RectTransform), "The following mods contain CSharp code", font: GUIStyle.SubHeadingFont, wrap: true, textAlignment: Alignment.Center); GUIListBox packageListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), msgBoxLayout.RectTransform)) { CurrentSelectMode = GUIListBox.SelectMode.None }; foreach (ContentPackage package in contentPackages) { GUIFrame packageFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.15f), packageListBox.Content.RectTransform), style: "ListBoxElement"); new GUITextBlock(new RectTransform(new Vector2(1f, 1f), packageFrame.RectTransform), package.Name); } new GUITextBlock(new RectTransform(new Vector2(1.0f, 0f), msgBoxLayout.RectTransform), "CSharp mods are not sandboxed, meaning that they have unrestrictive access to your computer, please make sure you trust these mods before you continue. If you are not hosting a server, selecting cancel will only run Lua-mods.", wrap: true) { Wrap = true }; GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.25f), messageBox.Content.RectTransform, Anchor.BottomCenter), isHorizontal: false, childAnchor: Anchor.TopCenter); new GUIButton(new RectTransform(new Vector2(0.8f, 0.0f), buttonLayout.RectTransform), "Continue") { TextBlock = { AutoScaleHorizontal = true }, OnClicked = (btn, userdata) => { _isClientPromptActive = false; onSelection(true); messageBox.Close(); return true; } }; new GUIButton(new RectTransform(new Vector2(0.8f, 0.0f), buttonLayout.RectTransform), "Cancel") { OnClicked = (btn, userdata) => { _isClientPromptActive = false; onSelection(false); messageBox.Close(); return true; } }; } private void SetupServicesProviderClient(IServicesProvider serviceProvider) { serviceProvider.RegisterServiceType(ServiceLifetime.Singleton); // supplied via factory //serviceProvider.RegisterServiceType(ServiceLifetime.Transient); serviceProvider.RegisterServiceType, ModConfigFileParserService>(ServiceLifetime.Transient); serviceProvider.RegisterServiceType(ServiceLifetime.Transient); serviceProvider.RegisterServiceType(ServiceLifetime.Singleton); } /// /// Handles changes in game states tracked by screen changes. /// /// The new game screen. public partial void OnScreenSelected(Screen screen) { /*Note: This logic needs to be run after the triggering event so that recursion scenarios (ie. resetting the EventService) do not occur, so we delay it by one game tick.*/ CoroutineManager.Invoke(() => { switch (screen) { // menus and navigation states case MainMenuScreen: case ModDownloadScreen: case ServerListScreen: SetRunState(RunState.Unloaded); SetRunState(RunState.LoadedNoExec); break; // running lobby or editor states case CampaignEndScreen: case CharacterEditorScreen: case EventEditorScreen: case GameScreen: case LevelEditorScreen: case NetLobbyScreen: case ParticleEditorScreen: case RoundSummaryScreen: case SpriteEditorScreen: case SubEditorScreen: case TestScreen: // notes: TestScreen is a Linux edge case editor screen and is deprecated. CheckReadyToRun(() => { SetRunState(RunState.Running); }); break; default: Logger.LogError( $"{nameof(LuaCsSetup)}: Received an unknown screen {screen?.GetType().Name ?? "'null screen'"}. Retarding load state to 'unloaded'."); SetRunState(RunState.Unloaded); break; } }, delay: 0f); // min is one tick delay. } } }