Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Docs/QuasarArchitecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -905,15 +905,15 @@ As of this document:
- initial runtime launch preparation now exists for isolated app-data roots, runtime config sync, `LastSession.sbl`, and enforced headless launch shaping
- server definitions store a saves root (`WorldPath`) plus selected save folder (`WorldSaveName`). The server editor requires a selected save before save/start, lists existing saves from the saves root, and has an always-available Create From Template dialog that can create/import a world template before copying it into a new save.
- neutral light/dark theming exists with local-storage persistence
- config editing is now migrated out of Python into Quasar-managed JSON profiles and rendered runtime artifacts. Profiles cover Quasar root settings, server password (rendered to DS-compatible hash/salt), and DS-visible SE session settings including block type world limits; on server start Quasar writes session settings and mods into the world's authoritative `Sandbox_config.sbc` as well as the runtime DS config. Profile mod order is preserved as the Space Engineers mod load order; the Mods tab lets operators reorder selected mods before saving. On profile open, save, and mod-import paths, Quasar uses Steam Workshop child/dependency metadata to add missing dependency mods and marks every dependency with an `IsDependency` profile flag without reordering the list. That flag is written back to `Sandbox_config.sbc` so DS autodetect treats dependency rows as dependencies instead of root mods. The Mods tab exposes an explicit Auto Sort Dependencies action that topologically sorts dependencies before dependents while keeping unrelated operator order stable. It warns when a dependency is currently after its dependent, when Steam metadata has a circular dependency chain, or when a cycle leaves a dependency order conflict after sorting. Dependency checks also return collapsed flattened outline rows for the Mods tab, tagged as root, dependency, already-listed, or cycle rows for inspection. Quasar hides the DS Autodetect Dependencies root setting and manages it from dependency state: disabled after a clean check/sort, enabled when manual mod edits invalidate the checked state or unresolved warnings remain. World-template import flows can also read a template's current `Sandbox_config.sbc` and create a config profile from its session settings and mods.
- config editing is now migrated out of Python into Quasar-managed JSON profiles and rendered runtime artifacts. Profiles cover Quasar root settings, server password (rendered to DS-compatible hash/salt), and DS-visible SE session settings including block type world limits; on server start Quasar writes session settings and mods into the world's authoritative `Sandbox_config.sbc` as well as the runtime DS config. Profile mod order is preserved as the Space Engineers mod load order; the Mods tab lets operators reorder selected mods before saving. On profile open, save, and mod-import paths, Quasar uses Steam Workshop child/dependency metadata to add missing dependency mods and marks every dependency with an `IsDependency` profile flag without reordering the list. That flag is written back to `Sandbox_config.sbc` so DS autodetect treats dependency rows as dependencies instead of root mods. The Mods tab exposes an explicit Auto Sort Dependencies action that topologically sorts dependencies before dependents while keeping unrelated operator order stable. It warns when a dependency is currently after its dependent, when Steam metadata has a circular dependency chain, or when a cycle leaves a dependency order conflict after sorting. Dependency checks also return collapsed flattened outline rows for the Mods tab, tagged as root, dependency, already-listed, or cycle rows for inspection. Quasar hides the DS Autodetect Dependencies root setting and manages it from dependency state: disabled after a clean check/sort, enabled when manual mod edits invalidate the checked state or unresolved warnings remain. World-template import flows can also read a template's current `Sandbox_config.sbc` and create a config profile from its session settings and mods; fresh installs no longer seed built-in default profiles.
- file watching/reload now exists for manual edits to Quasar-managed server/profile JSON
- backup/restore now exists as versioned ZIP archives for Quasar configuration, server runtime state, and world-only data. Configuration backups cover servers, config profiles, world-template definitions, branding, and singleton settings files, with manual download/upload and semantic-version compatibility checks. The Backup page lists every configured server with per-row Back up server / Restore server / Back up world / Restore world actions; restore buttons use the latest matching stored archive for that server and backup kind. Automatic backup rules are configured separately for Quasar config, server backups, and world backups, each with its own schedule and retention. Quasar config backups include Quasar-managed catalog/config files only; server backups include the server definition plus non-cache Dedicated Server and Magnetar app data but not world saves; world backups include world save files and keep existing server/world config, using the latest Space Engineers `Backup` snapshot when present so backups can be taken while servers run. Restored server definitions from config or server backups are forced to `Off` goal state so restore cannot trigger a failed start loop before matching world files are restored.
- per-server CPU affinity pinning now exists (cpuset strings applied via `taskset` on Linux and `Process.ProcessorAffinity` on Windows), enforced by the supervisor on process start and reconcile alongside process priority; Linux priority elevation can use the optional setuid `/usr/local/bin/quasar-renice` helper instead of granting `CAP_SYS_NICE` to the whole Quasar service
- per-server managed .NET runtime selection now exists on Windows, where Quasar installs both Magnetar builds side-by-side (`MagnetarInterim.exe` on .NET 10, the default, and `MagnetarLegacy.exe` on .NET Framework 4.8) and the runtime resolver launches the build chosen by `DedicatedServerDefinition.ManagedRuntime`; non-Windows hosts always run the .NET 10 build
- runtime config preparation now derives a unique `SteamPort` (`ServerPort + 1000`) and `RemoteApiPort` (`ServerPort + 2000`) per server so multiple servers co-hosted on one machine never collide on the SE defaults (8766 / 8080)
- server naming across the UI now consistently prefers the operator-configured `DedicatedServerDefinition.DisplayName` over the agent's in-game `ConfigDedicated.ServerName` (the analytics filters/legends, Discord per-server panels, the entities/plugins server selectors, the players list, and the plugin log panel all resolve names this way, falling back to the live agent name and then the unique name)
- the Entities page exposes plugin extension targets for supported grids and asteroid voxels. The Entity Viewer UI plugin renders the viewer button and fullscreen metadata-only browser dialog, then requests viewer-specific scene data through `IQuasarCompanionChannel` from its UI-plugin-owned Magnetar companion. Quasar builds/stages owned companion projects declared in the UI plugin manifest and deploys enabled companions as local Magnetar plugins beside `Quasar.Agent.dll` during server preparation. Quasar core provides only the generic companion transport (`ServerCommandType.PluginRequest` through `Quasar.Agent`) and does not ship a viewer scene HTTP API, viewer scene DTOs, `.mwm` files, texture files, extracted mesh geometry, or browser renderer assets. The browser viewer must use a user-selected local Space Engineers `Content` folder and, for modded assets, an optional local Mods or Steam Workshop `content/244850` folder.
- Dashboard server view selection now persists in browser local storage while still accepting `?view=list` / `?view=cards` overrides; card and list layouts use the same catalog order by unique name. Dashboard cards expose the assigned config profile as an actionable chip, the server port as a direct-connect copy chip (`host:port`), and the same create-server entry point the list layout already had.
- Dashboard server view selection now persists in browser local storage while still accepting `?view=list` / `?view=cards` overrides; card and list layouts use the same catalog order by unique name. Dashboard cards expose the assigned config profile as an actionable chip, the server port as a direct-connect copy chip (`host:port`), and the same create-server entry point the list layout already had. Crashed or faulted servers show one latest error line from the Dedicated Server or Magnetar log in the card/list status, and that line opens the console dialog directly in the matching error-excerpt view. The first-setup wizard can be explicitly closed from its final step once Quasar.Agent is connected.
- Quasar Agent now owns in-game `!stop`, `!restart [seconds]`, and `!quit` semantics for managed servers: `!stop` saves and turns the Quasar goal Off, `!restart` broadcasts a restart countdown (default 10 seconds), saves, and lets Quasar track/relaunch the Restarting state, and `!quit` exits without saving while turning the goal Off.
- the Chat page now treats text beginning with `!` as command text automatically, showing up to 30 live command suggestions from the selected agent with a disabled `...` overflow marker when more matches exist, without a separate command-mode toggle.
- startup version logging now records Quasar worker version in the Quasar log and Magnetar/Quasar.Agent version details in the Magnetar-side log path.
Expand Down
9 changes: 5 additions & 4 deletions Docs/StateMachines/ConfigProfileChanges.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ the world-options UI and managed from these results: Quasar disables it after a
clean check or successful sort, and enables it when dependency state is
unchecked or unresolved warnings remain.

**World-template import.** The world-template UI can derive a new config profile
from a template's current `Sandbox_config.sbc`. It imports DS-visible session
settings and workshop mods, then persists the result through the same
`UpsertAsync` path.
**Profile creation.** Profiles start empty when created directly, or can be
derived by the world-template UI from a template's current `Sandbox_config.sbc`.
Template-derived profiles import DS-visible session settings and workshop mods,
then persist the result through the same `UpsertAsync` path. Quasar does not
seed or restore built-in default profiles.

**Live vs restart-required.** Changes that the running server/agent can apply
dynamically go live immediately; changes flagged restart-required are applied on
Expand Down
19 changes: 19 additions & 0 deletions Quasar/Components/Dashboard/ServerCard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@
{
<MudText Typo="Typo.caption">@Runtime.HealthSummary</MudText>
}
@if (ShouldShowLatestErrorLine)
{
<MudTooltip Text="Open console at latest error lines">
<MudLink Typo="Typo.caption"
Color="Color.Error"
Underline="Underline.Hover"
Style="display:block;max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;"
@onclick="OpenErrorConsoleAsync">
@Runtime!.LatestErrorLogLine
</MudLink>
</MudTooltip>
}
<MudStack Row="true" Wrap="Wrap.Wrap" Spacing="1" Class="mt-1">
<MudTooltip Text="@GetDirectConnectTooltip()">
<MudChip T="string"
Expand Down Expand Up @@ -194,6 +206,10 @@
!string.IsNullOrWhiteSpace(Server.ConfigProfileId) &&
ConfigProfiles.GetProfile(Server.ConfigProfileId) is not null;

private bool ShouldShowLatestErrorLine =>
ProcessState is DedicatedServerProcessState.Crashed or DedicatedServerProcessState.Faulted &&
!string.IsNullOrWhiteSpace(Runtime?.LatestErrorLogLine);

private Task StartAsync() => StartRequested.InvokeAsync(Server.UniqueName);

private Task StopAsync() => StopRequested.InvokeAsync(Server.UniqueName);
Expand All @@ -204,6 +220,9 @@

private Task OpenConsoleAsync() => ServerActions.OpenConsoleDialogAsync(Server.UniqueName);

private Task OpenErrorConsoleAsync() =>
ServerActions.OpenConsoleDialogAsync(Server.UniqueName, Runtime?.LatestErrorLogKind ?? string.Empty, "errors");

private Task CloneAsync() => ServerActions.OpenCloneDialogAsync(Server);

private Task CreateTemplateAsync() => ServerActions.CreateWorldTemplateAsync(Server);
Expand Down
33 changes: 0 additions & 33 deletions Quasar/Components/Pages/Configs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@
Create Profile
</MudButton>

<MudButton
Variant="Variant.Outlined"
Color="Color.Secondary"
StartIcon="@Icons.Material.Filled.Restore"
OnClick="RestoreDefaultProfilesAsync">
Restore Default Profiles
</MudButton>

<MudDivider />

@if (Templates.Count == 0)
Expand Down Expand Up @@ -1193,31 +1185,6 @@
Snackbar.Add("Config profile cloned.", Severity.Success);
}

private async Task RestoreDefaultProfilesAsync()
{
if (!await ConfirmPendingChangesBeforeLeavingAsync())
return;

var confirmed = await DialogService.ShowMessageBoxAsync(
"Restore default profiles?",
"Survival (default) and Creative (default) will be recreated or reset to Quasar defaults. Custom profiles will not be changed.",
yesText: "Restore Defaults",
cancelText: "Cancel");

if (confirmed != true)
return;

var selectedProfileId = FirstExistingProfileId(_selectedProfileId) ?? "survival-default";
_selectedProfileId = selectedProfileId;
await ConfigProfiles.RestoreDefaultProfilesAsync();

SelectProfile(FirstExistingProfileId(selectedProfileId)
?? FirstExistingProfileId("survival-default")
?? Templates.FirstOrDefault()?.ConfigProfileId
?? string.Empty);
Snackbar.Add("Default config profiles restored.", Severity.Success);
}

private async Task ClearCurrentProfileModsAsync()
{
if (_editor is null)
Expand Down
12 changes: 12 additions & 0 deletions Quasar/Components/Pages/Home.razor
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,18 @@
</MudText>
</MudStack>

@if (IsSetupStepComplete(4))
{
<MudStack Row="true" Wrap="Wrap.Wrap" Spacing="1" Class="setup-wizard-actions">
<MudButton Variant="Variant.Filled"
Color="Color.Success"
StartIcon="@Icons.Material.Filled.Check"
OnClick="HideSetupWizard">
Close
</MudButton>
</MudStack>
}

</MudStack>

@if (LaunchedServers.Count > 0)
Expand Down
Loading
Loading