LuaCs CSharp Enabled Rework
- New UI for the prompt - Third time's the charm. - Fixed TOCTOU for cs prompt on main menu. - Fixed SubEditor not running lua when don't run is selected for cs. - LuaCs CSharp Enabled Rework
This commit is contained in:
committed by
Evil Factory
parent
d440ccbce2
commit
ebe8ec455f
@@ -7,6 +7,8 @@ using System.Text;
|
||||
using Barotrauma.CharacterEditor;
|
||||
using Barotrauma.LuaCs;
|
||||
using Barotrauma.LuaCs.Data;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
// ReSharper disable ObjectCreationAsStatement
|
||||
|
||||
@@ -15,120 +17,147 @@ namespace Barotrauma
|
||||
partial class LuaCsSetup
|
||||
{
|
||||
private bool _isClientPromptActive;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether execution should continue
|
||||
/// </summary>
|
||||
public bool CheckReadyToRun()
|
||||
private bool _isCsEnabledForSession = false;
|
||||
|
||||
public void CheckRunConditionalHostingCsEnabled(Action onReadyToRun)
|
||||
{
|
||||
// Fast exit if enabled
|
||||
if (this.IsCsEnabled)
|
||||
var res = ReadyToRunNoPrompt();
|
||||
if (res.ShouldRun)
|
||||
{
|
||||
return true;
|
||||
onReadyToRun?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (ContentPackage cp in PackageManagementService.GetLoadedAssemblyPackages())
|
||||
DisplayCsModsPromptClient(res.Item2, (selectedYes) =>
|
||||
{
|
||||
if (cp.NameMatches(PackageId))
|
||||
if (selectedYes)
|
||||
{
|
||||
continue;
|
||||
onReadyToRun?.Invoke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (cp.UgcId.TryUnwrap(out ContentPackageId id))
|
||||
{
|
||||
sb.AppendLine($"- {cp.Name} ({id})");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine($"- {cp.Name} (Not On Workshop)");
|
||||
}
|
||||
private (bool ShouldRun, ImmutableArray<ContentPackage> PromptPackages) ReadyToRunNoPrompt()
|
||||
{
|
||||
if (this.IsCsEnabled)
|
||||
{
|
||||
return (true, ImmutableArray<ContentPackage>.Empty);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(sb.ToString()))
|
||||
if (!ShouldPromptForCs)
|
||||
{
|
||||
return true;
|
||||
return (true, ImmutableArray<ContentPackage>.Empty);
|
||||
}
|
||||
|
||||
if (!_isClientPromptActive)
|
||||
ImmutableArray<ContentPackage> contentPackages = PackageManagementService.GetLoadedAssemblyPackages()
|
||||
.Where(p => p.Name != PackageId)
|
||||
.ToImmutableArray();
|
||||
|
||||
return (contentPackages.IsEmpty, contentPackages);
|
||||
}
|
||||
|
||||
partial void CheckReadyToRun(Action onReadyToRun)
|
||||
{
|
||||
var res = ReadyToRunNoPrompt();
|
||||
if (res.ShouldRun)
|
||||
{
|
||||
_isClientPromptActive = true;
|
||||
if (GameMain.Client == null || GameMain.Client.IsServerOwner)
|
||||
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)
|
||||
{
|
||||
DisplayCsModsPromptServer(sb);
|
||||
SetRunState(RunState.LoadedNoExec);
|
||||
}
|
||||
this._isCsEnabledForSession = csSessionExecutionPolicy;
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
if (CurrentRunState != prevRunState)
|
||||
{
|
||||
SetRunState(prevRunState);
|
||||
}
|
||||
onReadyToRun?.Invoke();
|
||||
}, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayCsModsPromptClient(ImmutableArray<ContentPackage> contentPackages, Action<bool> 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;
|
||||
}
|
||||
else
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.8f, 0.0f), buttonLayout.RectTransform), "Cancel")
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
DisplayCsModsPromptClient(sb);
|
||||
return false;
|
||||
_isClientPromptActive = false;
|
||||
onSelection(false);
|
||||
messageBox.Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DisplayCsModsPromptServer(StringBuilder sb)
|
||||
{
|
||||
var msg = new GUIMessageBox("", $"You have CSharp mods enabled but don't have the CSharp Scripting enabled, " +
|
||||
$"those mods might not work, go to the Main Menu, click on LuaCs Settings and check Enable CSharp Scripting.\n\n{sb}");
|
||||
foreach (var button in msg.Buttons)
|
||||
{
|
||||
var old = button.OnClicked;
|
||||
button.OnClicked = (btn, obj) =>
|
||||
{
|
||||
var ret = old?.Invoke(btn, obj);
|
||||
_isClientPromptActive = false;
|
||||
return ret ?? true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayCsModsPromptClient(StringBuilder sb)
|
||||
{
|
||||
GUIMessageBox msg = new GUIMessageBox(
|
||||
"Confirm",
|
||||
$"This server has the following CSharp mods installed: \n{sb}\nDo you wish to run them? Cs mods are not sandboxed so make sure you trust these mods.",
|
||||
new LocalizedString[2] { "Run", "Don't Run" });
|
||||
|
||||
msg.Buttons[0].OnClicked = (GUIButton button, object obj) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
this._isClientPromptActive = false;
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
SetRunState(RunState.LoadedNoExec);
|
||||
this.IsCsEnabled = true;
|
||||
SetRunState(RunState.Running);
|
||||
}, 0f);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
msg.Close();
|
||||
}
|
||||
};
|
||||
|
||||
msg.Buttons[1].OnClicked = (GUIButton button, object obj) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// avoid a TOCTOU scenario.
|
||||
this.IsCsEnabled = false;
|
||||
this._isClientPromptActive = false;
|
||||
SetRunState(RunState.LoadedNoExec);
|
||||
SetRunState(RunState.Running);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
msg.Close();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void SetupServicesProviderClient(IServicesProvider serviceProvider)
|
||||
@@ -172,16 +201,10 @@ namespace Barotrauma
|
||||
case SpriteEditorScreen:
|
||||
case SubEditorScreen:
|
||||
case TestScreen: // notes: TestScreen is a Linux edge case editor screen and is deprecated.
|
||||
if (!CheckReadyToRun())
|
||||
CheckReadyToRun(() =>
|
||||
{
|
||||
if (CurrentRunState >= RunState.Running)
|
||||
{
|
||||
SetRunState(RunState.LoadedNoExec);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SetRunState(RunState.Running);
|
||||
SetRunState(RunState.Running);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
Logger.LogError(
|
||||
|
||||
@@ -1012,20 +1012,25 @@ namespace Barotrauma
|
||||
|
||||
private void TryStartServer()
|
||||
{
|
||||
if (SubmarineInfo.SavedSubmarines.Any(s => s.CalculatingHash))
|
||||
LuaCsSetup.Instance.CheckRunConditionalHostingCsEnabled(() =>
|
||||
{
|
||||
var waitBox = new GUIMessageBox(TextManager.Get("pleasewait"), TextManager.Get("waitforsubmarinehashcalculations"), new LocalizedString[] { TextManager.Get("cancel") });
|
||||
var waitCoroutine = CoroutineManager.StartCoroutine(WaitForSubmarineHashCalculations(waitBox), "WaitForSubmarineHashCalculations");
|
||||
waitBox.Buttons[0].OnClicked += (btn, userdata) =>
|
||||
if (SubmarineInfo.SavedSubmarines.Any(s => s.CalculatingHash))
|
||||
{
|
||||
CoroutineManager.StopCoroutines(waitCoroutine);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
StartServer();
|
||||
}
|
||||
var waitBox = new GUIMessageBox(TextManager.Get("pleasewait"), TextManager.Get("waitforsubmarinehashcalculations"), new LocalizedString[] { TextManager.Get("cancel") });
|
||||
var waitCoroutine = CoroutineManager.StartCoroutine(WaitForSubmarineHashCalculations(waitBox), "WaitForSubmarineHashCalculations");
|
||||
waitBox.Buttons[0].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
CoroutineManager.StopCoroutines(waitCoroutine);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
StartServer();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private IEnumerable<CoroutineStatus> WaitForSubmarineHashCalculations(GUIMessageBox messageBox)
|
||||
|
||||
@@ -6,6 +6,11 @@ namespace Barotrauma;
|
||||
|
||||
partial class LuaCsSetup
|
||||
{
|
||||
partial void CheckReadyToRun(Action onReadyToRun)
|
||||
{
|
||||
onReadyToRun?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles changes in game states tracked by screen changes.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,7 +2,14 @@
|
||||
<Configuration>
|
||||
<Settings>
|
||||
<Setting Name="HideUserNamesInLogs" Type="bool" Value="true"/>
|
||||
<Setting Name="IsCsEnabled" Type="bool" Value="false" AllowChangesWhileExecuting="false"/>
|
||||
<Setting Name="CsRunPolicy" Type="listString" Value="Prompt" AllowChangesWhileExecuting="false">
|
||||
<Values>
|
||||
<Value Value="Disabled"/>
|
||||
<Value Value="Prompt"/>
|
||||
<Value Value="Enabled"/>
|
||||
</Values>
|
||||
</Setting>
|
||||
<Setting Name="UseCaching" Type="bool" Value="true" AllowChangesWhileExecuting="false"/>
|
||||
<Setting Name="CsRunPolicySession" Type="bool" AllowChangesWhileExecuting="false" ShowInMenus="false"/>
|
||||
</Settings>
|
||||
</Configuration>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<LuaCsForBarotrauma.SettingsMenu.ModGameplayButton>Mod Gameplay Settings</LuaCsForBarotrauma.SettingsMenu.ModGameplayButton>
|
||||
<!-- Settings -->
|
||||
<!-- Is Cs Enabled-->
|
||||
<LuaCsForBarotrauma.IsCsEnabled.DisplayName>Are C# Mods Allowed</LuaCsForBarotrauma.IsCsEnabled.DisplayName>
|
||||
<LuaCsForBarotrauma.IsCsEnabled.Tooltip>Should unsandboxed scripts and dlls be allowed to run.</LuaCsForBarotrauma.IsCsEnabled.Tooltip>
|
||||
<LuaCsForBarotrauma.IsCsEnabled.DisplayCategory>General</LuaCsForBarotrauma.IsCsEnabled.DisplayCategory>
|
||||
<LuaCsForBarotrauma.CsRunPolicy.DisplayName>Are C# Mods Allowed</LuaCsForBarotrauma.CsRunPolicy.DisplayName>
|
||||
<LuaCsForBarotrauma.CsRunPolicy.Tooltip>Should unsandboxed scripts and dlls be allowed to run.</LuaCsForBarotrauma.CsRunPolicy.Tooltip>
|
||||
<LuaCsForBarotrauma.CsRunPolicy.DisplayCategory>General</LuaCsForBarotrauma.CsRunPolicy.DisplayCategory>
|
||||
<!-- Use Caching -->
|
||||
<LuaCsForBarotrauma.UseCaching.DisplayName>Use Pre-Caching</LuaCsForBarotrauma.UseCaching.DisplayName>
|
||||
<LuaCsForBarotrauma.UseCaching.Tooltip>Should mod files be preloaded to speed up loading. Should only be turned off if you have mods that have issues with this.</LuaCsForBarotrauma.UseCaching.Tooltip>
|
||||
|
||||
@@ -84,18 +84,22 @@ namespace Barotrauma
|
||||
private LuaGame _game;
|
||||
public LuaGame Game => _game ??= _servicesProvider.GetService<LuaGame>();
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether C# plugin code is enabled.
|
||||
/// </summary>
|
||||
public bool IsCsEnabled
|
||||
{
|
||||
get => _isCsEnabled?.Value ?? false;
|
||||
internal set => _isCsEnabled?.TrySetValue(value);
|
||||
#if CLIENT
|
||||
get => _csRunPolicy?.Value == "Enabled" || _isCsEnabledForSession;
|
||||
#elif SERVER
|
||||
// cs settings cannot be changed on the server after launch
|
||||
get => _csRunPolicy?.Value is "Enabled" or "Prompt";
|
||||
#endif
|
||||
}
|
||||
|
||||
private ISettingBase<bool> _isCsEnabled;
|
||||
|
||||
private ISettingList<string> _csRunPolicy;
|
||||
private bool ShouldPromptForCs => _csRunPolicy?.Value is "Prompt";
|
||||
|
||||
/// <summary>
|
||||
/// Whether usernames are anonymized or show in logs.
|
||||
/// </summary>
|
||||
@@ -123,8 +127,8 @@ namespace Barotrauma
|
||||
{
|
||||
var luaCsPackage = GetLuaCsPackage();
|
||||
|
||||
_isCsEnabled =
|
||||
ConfigService.TryGetConfig<ISettingBase<bool>>(luaCsPackage, "IsCsEnabled", out var val1)
|
||||
_csRunPolicy =
|
||||
ConfigService.TryGetConfig<ISettingList<string>>(luaCsPackage, "CsRunPolicy", out var val1)
|
||||
? val1
|
||||
: null;
|
||||
_hideUserNamesInLogs =
|
||||
@@ -380,16 +384,27 @@ namespace Barotrauma
|
||||
void RunStateRunning_OnExit(State<RunState> currentState)
|
||||
{
|
||||
EventService.Call("stop");
|
||||
|
||||
#if CLIENT
|
||||
_isCsEnabledForSession = false;
|
||||
#endif
|
||||
Logger.LogResults(PackageManagementService.StopRunningPackages());
|
||||
|
||||
Logger.LogMessage("LuaCs running state exited");
|
||||
}
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Checks for Cs Execution Policy (ie. prompting the user) and then calls the delegate once completed.
|
||||
/// </summary>
|
||||
/// <param name="onReadyToRun"></param>
|
||||
partial void CheckReadyToRun(Action onReadyToRun);
|
||||
|
||||
#region LegacyRedirects
|
||||
|
||||
// --- Compatibility
|
||||
@@ -457,7 +472,7 @@ namespace Barotrauma
|
||||
|
||||
void DisposeLuaCsConfig()
|
||||
{
|
||||
_isCsEnabled = null;
|
||||
_csRunPolicy = null;
|
||||
_hideUserNamesInLogs = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user