2026-05-10 19:32:27 -05:00
|
|
|
@using LANCommander.SDK.Enums
|
|
|
|
|
@using LANCommander.Server.Extensions
|
2025-02-23 09:17:46 -06:00
|
|
|
@inherits FeedbackComponent<ScriptEditorOptions, Script>
|
2025-02-01 02:21:34 -06:00
|
|
|
@inject ScriptService ScriptService
|
2025-12-08 00:51:32 -06:00
|
|
|
@inject ArchiveService ArchiveService
|
|
|
|
|
@inject ServerService ServerService
|
2025-02-23 09:17:46 -06:00
|
|
|
@inject ModalService ModalService
|
2023-11-28 20:48:03 -06:00
|
|
|
@inject IMessageService MessageService
|
2024-01-04 18:23:54 -06:00
|
|
|
@inject ILogger<ScriptEditorDialog> Logger
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
<Flex Justify="FlexJustify.SpaceBetween" Align="FlexAlign.Center" Style="margin-bottom: 16px;">
|
|
|
|
|
<Flex Gap="FlexGap.Small" Wrap="FlexWrap.Wrap" Align="FlexAlign.Center">
|
2025-02-23 09:17:46 -06:00
|
|
|
@foreach (var group in Snippets.Select(s => s.Group).Distinct())
|
|
|
|
|
{
|
|
|
|
|
<Dropdown>
|
|
|
|
|
<Overlay>
|
|
|
|
|
<Menu>
|
|
|
|
|
@foreach (var snippet in Snippets.Where(s => s.Group == group))
|
|
|
|
|
{
|
|
|
|
|
<MenuItem OnClick="() => InsertSnippet(snippet)">
|
|
|
|
|
@snippet.Name
|
|
|
|
|
</MenuItem>
|
|
|
|
|
}
|
|
|
|
|
</Menu>
|
|
|
|
|
</Overlay>
|
|
|
|
|
|
|
|
|
|
<ChildContent>
|
|
|
|
|
<Button Type="@ButtonType.Primary">@group</Button>
|
|
|
|
|
</ChildContent>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
@if (_variables.Any())
|
|
|
|
|
{
|
|
|
|
|
<Dropdown>
|
|
|
|
|
<Overlay>
|
|
|
|
|
<Menu>
|
|
|
|
|
@foreach (var variable in _variables)
|
|
|
|
|
{
|
|
|
|
|
<MenuItem OnClick="() => InsertText(variable)">
|
|
|
|
|
@variable
|
|
|
|
|
</MenuItem>
|
|
|
|
|
}
|
|
|
|
|
</Menu>
|
|
|
|
|
</Overlay>
|
|
|
|
|
|
|
|
|
|
<ChildContent>
|
|
|
|
|
<Button Type="@ButtonType.Primary">Variables</Button>
|
|
|
|
|
</ChildContent>
|
|
|
|
|
</Dropdown>
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-08 00:51:32 -06:00
|
|
|
@if (_archive != null)
|
2025-02-23 09:17:46 -06:00
|
|
|
{
|
|
|
|
|
<Button Icon="@IconType.Outline.FolderOpen" OnClick="BrowseForPath" Type="@ButtonType.Text">Browse</Button>
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 00:01:12 -05:00
|
|
|
<Button Icon="@IconType.Outline.Build" OnClick="() => _regToPowerShell.Open()" Type="@ButtonType.Text">Import .reg</Button>
|
2026-05-10 19:32:27 -05:00
|
|
|
|
|
|
|
|
@if (IsDebuggable && HasDebugTarget)
|
2025-12-10 20:55:38 -06:00
|
|
|
{
|
|
|
|
|
<Tooltip Title="Debug">
|
2025-12-10 21:46:46 -06:00
|
|
|
<Button Icon="@IconType.Outline.CaretRight" Type="@ButtonType.Text" OnClick="Debug" Disabled="@_debugging" />
|
2025-12-10 20:55:38 -06:00
|
|
|
</Tooltip>
|
|
|
|
|
}
|
2026-05-10 19:32:27 -05:00
|
|
|
</Flex>
|
2025-02-23 09:17:46 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
<Checkbox @bind-Checked="_script.RequiresAdmin">Requires Admin</Checkbox>
|
|
|
|
|
</Flex>
|
2026-03-20 00:01:12 -05:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
<CodeInput @ref="_codeInput" @bind-Value="_script.Contents" Language="Languages.PowerShell" OnSave="Save" ScriptType="@_script.Type.ToString()" OnReady="OnEditorReady" />
|
|
|
|
|
|
|
|
|
|
<PowerShellConsole @ref="_console" Id="_id" @bind-Active="_debugging"/>
|
2025-02-23 09:17:46 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
<Form @ref="@_form" Model="@_script" Layout="@FormLayout.Vertical">
|
2025-02-23 09:17:46 -06:00
|
|
|
<FormItem Label="Name" Required Rules=@(new[] { new FormValidationRule { Required = true } })>
|
|
|
|
|
<Input @bind-Value="@context.Name" />
|
|
|
|
|
</FormItem>
|
|
|
|
|
|
|
|
|
|
<FormItem Label="Description">
|
|
|
|
|
<TextArea @bind-Value="context.Description" MaxLength=500 ShowCount />
|
|
|
|
|
</FormItem>
|
|
|
|
|
</Form>
|
|
|
|
|
|
2026-03-20 00:01:12 -05:00
|
|
|
<RegToPowerShell @ref="_regToPowerShell" OnParsed="(text) => InsertText(text)" />
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2024-03-11 17:38:29 -05:00
|
|
|
@code {
|
2026-03-20 00:01:12 -05:00
|
|
|
Guid _id = Guid.NewGuid();
|
2026-05-10 19:32:27 -05:00
|
|
|
|
2026-03-20 00:01:12 -05:00
|
|
|
Form<Script>? _form;
|
|
|
|
|
CodeInput? _codeInput;
|
|
|
|
|
RegToPowerShell? _regToPowerShell;
|
|
|
|
|
PowerShellConsole? _console;
|
|
|
|
|
IEnumerable<Snippet> Snippets { get; set; } = [];
|
2026-05-10 19:32:27 -05:00
|
|
|
List<string> _variables = new();
|
2025-12-08 00:51:32 -06:00
|
|
|
|
2025-12-10 21:46:46 -06:00
|
|
|
bool _debugging;
|
2026-05-10 19:32:27 -05:00
|
|
|
bool _isNewScript;
|
2025-12-10 21:46:46 -06:00
|
|
|
|
2025-12-08 00:51:32 -06:00
|
|
|
Archive? _archive;
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2026-03-20 00:01:12 -05:00
|
|
|
Script _script = new();
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2025-12-10 20:55:38 -06:00
|
|
|
bool IsDebuggable =>
|
2026-03-20 00:01:12 -05:00
|
|
|
_script.Type == ScriptType.Package;
|
2025-12-10 20:55:38 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
bool HasDebugTarget =>
|
|
|
|
|
(Options.GameId.HasValue && Options.GameId != Guid.Empty) ||
|
|
|
|
|
(Options.ToolId.HasValue && Options.ToolId != Guid.Empty) ||
|
|
|
|
|
(Options.RedistributableId.HasValue && Options.RedistributableId != Guid.Empty);
|
|
|
|
|
|
|
|
|
|
static readonly string[] GameClientScriptTypes = ["Install", "Uninstall", "BeforeStart", "AfterStop", "NameChange", "KeyChange", "SaveUpload", "SaveDownload", "DetectInstall"];
|
|
|
|
|
|
|
|
|
|
static readonly Dictionary<string, string[]> VariablesByScriptType = new()
|
|
|
|
|
{
|
|
|
|
|
["Install"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$ToolManifest", "$RedistributableManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["Uninstall"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["BeforeStart"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$PlayerAlias", "$Server", "$ServerId", "$ServerName", "$ServerHost", "$ServerPort", "$GameTitle", "$GameId", "$ToolManifest", "$RedistributableManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["AfterStop"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$PlayerAlias", "$Server", "$ServerId", "$ServerName", "$ServerHost", "$ServerPort", "$GameTitle", "$GameId", "$ToolManifest", "$RedistributableManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["NameChange"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$OldPlayerAlias", "$NewPlayerAlias", "$RedistributableManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["KeyChange"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$AllocatedKey", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["DetectInstall"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$ToolManifest", "$RedistributableManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["SaveUpload"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["SaveDownload"] = ["$InstallDirectory", "$WorkingDirectory", "$ServerAddress", "$DefaultInstallDirectory", "$GameManifest", "$DisplayWidth", "$DisplayHeight", "$DisplayRefreshRate", "$DisplayBitDepth", "$IPXRelayHost", "$IPXRelayPort"],
|
|
|
|
|
["Package"] = ["$WorkingDirectory", "$Game", "$Tool", "$Redistributable"],
|
|
|
|
|
["GameStarted"] = ["$WorkingDirectory", "$Server", "$Game", "$User", "$ServerId", "$ServerName", "$ServerHost", "$ServerPort", "$GameTitle", "$GameId"],
|
|
|
|
|
["GameStopped"] = ["$WorkingDirectory", "$Server", "$Game", "$User", "$ServerId", "$ServerName", "$ServerHost", "$ServerPort", "$GameTitle", "$GameId"],
|
|
|
|
|
["UserRegistration"] = ["$WorkingDirectory", "$User"],
|
|
|
|
|
["UserLogin"] = ["$WorkingDirectory", "$User"],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void UpdateVariables()
|
|
|
|
|
{
|
|
|
|
|
var key = _script.Type.ToString();
|
|
|
|
|
|
|
|
|
|
if (VariablesByScriptType.TryGetValue(key, out var vars))
|
|
|
|
|
_variables = vars.ToList();
|
|
|
|
|
else
|
|
|
|
|
_variables = ["$WorkingDirectory"];
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-28 20:48:03 -06:00
|
|
|
protected override async Task OnInitializedAsync()
|
|
|
|
|
{
|
2025-02-01 02:21:34 -06:00
|
|
|
if (Options.ScriptId != Guid.Empty)
|
2026-05-10 19:32:27 -05:00
|
|
|
{
|
2026-03-20 00:01:12 -05:00
|
|
|
_script = await ScriptService.GetAsync(Options.ScriptId);
|
2026-05-10 19:32:27 -05:00
|
|
|
}
|
|
|
|
|
else
|
2025-12-08 00:51:32 -06:00
|
|
|
{
|
2026-05-10 19:32:27 -05:00
|
|
|
_isNewScript = true;
|
|
|
|
|
var scriptType = Options.ScriptType ?? ScriptType.Install;
|
|
|
|
|
|
2026-03-20 00:01:12 -05:00
|
|
|
_script = new Script
|
2025-02-01 02:21:34 -06:00
|
|
|
{
|
2026-05-10 19:32:27 -05:00
|
|
|
Type = scriptType,
|
|
|
|
|
Name = scriptType.GetDisplayName(),
|
2025-02-01 02:21:34 -06:00
|
|
|
};
|
2025-12-08 00:51:32 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
if (Options.GameId.HasValue && Options.GameId != Guid.Empty)
|
2025-02-01 02:21:34 -06:00
|
|
|
{
|
2026-05-10 19:32:27 -05:00
|
|
|
_script.GameId = Options.GameId;
|
|
|
|
|
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.GameId == Options.GameId);
|
|
|
|
|
}
|
|
|
|
|
else if (Options.RedistributableId.HasValue && Options.RedistributableId != Guid.Empty)
|
2025-02-01 02:21:34 -06:00
|
|
|
{
|
2026-05-10 19:32:27 -05:00
|
|
|
_script.RedistributableId = Options.RedistributableId;
|
|
|
|
|
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.RedistributableId == Options.RedistributableId);
|
|
|
|
|
}
|
|
|
|
|
else if (Options.ServerId.HasValue && Options.ServerId != Guid.Empty)
|
|
|
|
|
{
|
|
|
|
|
_script.ServerId = Options.ServerId;
|
|
|
|
|
var server = await ServerService.GetAsync(Options.ServerId.Value);
|
|
|
|
|
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.GameId == server.GameId);
|
|
|
|
|
}
|
|
|
|
|
else if (Options.ToolId.HasValue && Options.ToolId != Guid.Empty)
|
|
|
|
|
{
|
|
|
|
|
_script.ToolId = Options.ToolId;
|
|
|
|
|
_archive = await ArchiveService.GetLatestArchiveAsync(a => a.ToolId == Options.ToolId);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-08 00:51:32 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
UpdateVariables();
|
|
|
|
|
Snippets = ScriptService.GetSnippets();
|
|
|
|
|
}
|
2025-12-08 00:51:32 -06:00
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
async Task OnEditorReady()
|
|
|
|
|
{
|
|
|
|
|
if (_isNewScript && _codeInput != null && Options.ScriptType.HasValue)
|
2026-02-08 02:24:53 -06:00
|
|
|
{
|
2026-05-10 19:32:27 -05:00
|
|
|
await _codeInput.InsertTemplateAsync(Options.ScriptType.Value.ToString());
|
2026-02-08 02:24:53 -06:00
|
|
|
}
|
2023-12-05 19:10:34 -06:00
|
|
|
}
|
|
|
|
|
|
2023-11-28 20:48:03 -06:00
|
|
|
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)
|
|
|
|
|
{
|
2024-03-11 17:38:29 -05:00
|
|
|
var success = await Save();
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2024-03-11 17:38:29 -05:00
|
|
|
if (success)
|
2026-03-20 00:01:12 -05:00
|
|
|
await base.OkCancelRefWithResult!.OnOk(_script);
|
2024-03-11 17:38:29 -05:00
|
|
|
else
|
|
|
|
|
args.Reject();
|
2023-11-28 20:48:03 -06:00
|
|
|
}
|
|
|
|
|
|
2024-11-22 02:04:04 -06:00
|
|
|
async Task<bool> Save()
|
2023-11-28 20:48:03 -06:00
|
|
|
{
|
2024-11-22 02:04:04 -06:00
|
|
|
try
|
2023-11-28 20:48:03 -06:00
|
|
|
{
|
2026-03-20 00:01:12 -05:00
|
|
|
if (_form.Validate())
|
2025-02-23 09:17:46 -06:00
|
|
|
{
|
2026-03-20 00:01:12 -05:00
|
|
|
if (_script.Id == Guid.Empty)
|
|
|
|
|
_script = await ScriptService.AddAsync(_script);
|
2025-02-23 09:17:46 -06:00
|
|
|
else
|
2026-03-20 00:01:12 -05:00
|
|
|
_script = await ScriptService.UpdateAsync(_script);
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2025-02-23 09:17:46 -06:00
|
|
|
MessageService.Success("Script saved!");
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2025-02-23 09:17:46 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-05-10 19:32:27 -05:00
|
|
|
|
2025-02-23 09:17:46 -06:00
|
|
|
return false;
|
2024-11-22 02:04:04 -06:00
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
2023-11-30 19:12:25 -06:00
|
|
|
{
|
2024-11-22 02:04:04 -06:00
|
|
|
MessageService.Error("Script could not be saved!");
|
|
|
|
|
Logger.LogError(ex, "Script could not be saved!");
|
2023-11-28 20:48:03 -06:00
|
|
|
|
2024-03-11 17:38:29 -05:00
|
|
|
return false;
|
2024-11-22 02:04:04 -06:00
|
|
|
}
|
2023-11-28 20:48:03 -06:00
|
|
|
}
|
2025-12-10 21:46:46 -06:00
|
|
|
|
|
|
|
|
async Task Debug()
|
|
|
|
|
{
|
|
|
|
|
if (!IsDebuggable)
|
|
|
|
|
return;
|
2026-05-10 19:32:27 -05:00
|
|
|
|
2025-12-10 21:46:46 -06:00
|
|
|
var saved = await Save();
|
|
|
|
|
|
|
|
|
|
if (!saved)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-05-10 19:32:27 -05:00
|
|
|
if (Options.GameId.HasValue && Options.GameId != Guid.Empty)
|
2025-12-10 21:46:46 -06:00
|
|
|
await _console.DebugPackagingScript(Options.GameId.Value);
|
2026-05-10 19:32:27 -05:00
|
|
|
else if (Options.ToolId.HasValue && Options.ToolId != Guid.Empty)
|
|
|
|
|
await _console.DebugToolPackagingScript(Options.ToolId.Value);
|
|
|
|
|
else if (Options.RedistributableId.HasValue && Options.RedistributableId != Guid.Empty)
|
|
|
|
|
await _console.DebugRedistributablePackagingScript(Options.RedistributableId.Value);
|
2025-12-10 21:46:46 -06:00
|
|
|
}
|
2026-05-10 19:32:27 -05:00
|
|
|
|
2026-03-20 00:01:12 -05:00
|
|
|
async Task BrowseForPath()
|
2025-02-23 09:17:46 -06:00
|
|
|
{
|
|
|
|
|
var modalOptions = new ModalOptions()
|
|
|
|
|
{
|
|
|
|
|
Title = "Choose Reference",
|
|
|
|
|
Maximizable = false,
|
|
|
|
|
DefaultMaximized = true,
|
|
|
|
|
Closable = true,
|
|
|
|
|
OkText = "Insert File Path"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var browserOptions = new FilePickerOptions()
|
|
|
|
|
{
|
2025-12-08 00:51:32 -06:00
|
|
|
ArchiveId = _archive?.Id ?? Guid.Empty,
|
2025-02-23 09:17:46 -06:00
|
|
|
Select = true,
|
|
|
|
|
Multiple = false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);
|
|
|
|
|
|
|
|
|
|
modalRef.OnOk = (results) =>
|
|
|
|
|
{
|
|
|
|
|
var path = results.FirstOrDefault().Path;
|
|
|
|
|
|
|
|
|
|
InsertText($"$InstallDirectory\\{path.Replace('/', '\\')}");
|
|
|
|
|
|
|
|
|
|
StateHasChanged();
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async Task InsertText(string text)
|
|
|
|
|
{
|
2026-03-20 00:01:12 -05:00
|
|
|
if (_codeInput != null)
|
|
|
|
|
await _codeInput.InsertText(text);
|
2025-02-23 09:17:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async Task InsertSnippet(Snippet snippet)
|
|
|
|
|
{
|
2026-05-10 19:32:27 -05:00
|
|
|
if (_codeInput != null)
|
|
|
|
|
await _codeInput.InsertSnippet(snippet.Content);
|
2025-02-23 09:17:46 -06:00
|
|
|
}
|
2023-11-28 20:48:03 -06:00
|
|
|
}
|