Initial commit: Brass & Sigil monorepo

Self-hosted Minecraft modpack distribution + administration system.

- launcher/  Avalonia 12 desktop client; single-file win-x64 publish.
             Microsoft auth via XboxAuthNet, manifest+SHA-1 mod sync,
             portable install path, sidecar settings.
- server/    brass-sigil-server daemon (.NET 8, linux-x64). Wraps the
             MC subprocess, embedded Kestrel admin panel with cookie
             auth + rate limiting, RCON bridge, scheduled backups,
             BlueMap CLI integration with player markers + skin proxy,
             friend-side whitelist request flow, world wipe with seed
             selection (keep current / random / custom).
- pack/      pack.lock.json (Modrinth + manual CurseForge entries),
             data-only tweak source under tweaks/, build outputs in
             overrides/ (gitignored).
- scripts/   Build-Pack / Build-Tweaks / Update-Pack / Check-Updates
             plus Deploy-Brass.ps1 unified one-shot deploy with
             version-bump pre-flight and daemon-state detection.
This commit is contained in:
Matt Sijbers
2026-05-05 00:19:05 +01:00
commit a1331212cb
99 changed files with 12640 additions and 0 deletions
+395
View File
@@ -0,0 +1,395 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="900" d:DesignHeight="600"
x:Class="ModpackLauncher.MainWindow"
Title="Modpack Launcher"
Width="900" Height="640"
MinWidth="720" MinHeight="540"
Background="Transparent"
TransparencyLevelHint="Transparent"
WindowDecorations="None"
Icon="/Assets/icon.png"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<!-- Palette: dark navy base + brass trim + cyan magic accent -->
<!-- Brass gradient (lit from top, polished) -->
<LinearGradientBrush x:Key="BrassTrim" StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#F5D88A" />
<GradientStop Offset="0.35" Color="#E8B95C" />
<GradientStop Offset="0.65" Color="#A37A2E" />
<GradientStop Offset="1" Color="#5C4519" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="BrassFill" StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#F5D88A" />
<GradientStop Offset="0.5" Color="#D4A24C" />
<GradientStop Offset="1" Color="#8C6829" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="BrassFillHover" StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#FBE3A0" />
<GradientStop Offset="0.5" Color="#E8B95C" />
<GradientStop Offset="1" Color="#A37A2E" />
</LinearGradientBrush>
<!-- Rivet (radial gradient, lit from upper-left) -->
<RadialGradientBrush x:Key="RivetFill" Center="35%,35%" GradientOrigin="35%,35%" RadiusX="0.55" RadiusY="0.55">
<GradientStop Offset="0" Color="#F8DC95" />
<GradientStop Offset="0.5" Color="#C99843" />
<GradientStop Offset="1" Color="#3F2E10" />
</RadialGradientBrush>
<!-- Card fill (deep navy gradient) -->
<LinearGradientBrush x:Key="CardFill" StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#13192A" />
<GradientStop Offset="1" Color="#0A0F1A" />
</LinearGradientBrush>
<!-- Title bar metallic -->
<LinearGradientBrush x:Key="TitleBarFill" StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Offset="0" Color="#0F1626" />
<GradientStop Offset="1" Color="#070B16" />
</LinearGradientBrush>
<!-- Magic cyan glow (radial) -->
<RadialGradientBrush x:Key="MagicGlow" Center="50%,50%" GradientOrigin="50%,50%" RadiusX="0.8" RadiusY="0.8">
<GradientStop Offset="0" Color="#605DD4E8" />
<GradientStop Offset="0.5" Color="#205DD4E8" />
<GradientStop Offset="1" Color="#005DD4E8" />
</RadialGradientBrush>
<!-- Tileable noise overlay -->
<ImageBrush x:Key="NoiseBrush" Source="/Assets/noise.png"
TileMode="Tile" Stretch="None"
DestinationRect="0,0,128,128" />
</Window.Resources>
<Window.Styles>
<!-- Reusable "brass panel" with metal trim + corner rivets -->
<Style Selector="ContentControl.brass-panel">
<Setter Property="Padding" Value="20" />
<Setter Property="Template">
<ControlTemplate>
<Grid>
<!-- Outer brass trim -->
<Border BorderBrush="{StaticResource BrassTrim}" BorderThickness="2" CornerRadius="6"
Background="{StaticResource CardFill}">
<ContentPresenter Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}" />
</Border>
<!-- Corner rivets -->
<Ellipse Width="6" Height="6" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="6" Fill="{StaticResource RivetFill}" />
<Ellipse Width="6" Height="6" HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="6" Fill="{StaticResource RivetFill}" />
<Ellipse Width="6" Height="6" HorizontalAlignment="Left" VerticalAlignment="Bottom"
Margin="6" Fill="{StaticResource RivetFill}" />
<Ellipse Width="6" Height="6" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Margin="6" Fill="{StaticResource RivetFill}" />
</Grid>
</ControlTemplate>
</Setter>
</Style>
<!-- Primary button: brass gradient + cyan magic hover glow -->
<Style Selector="Button.primary">
<Setter Property="Background" Value="{StaticResource BrassFill}" />
<Setter Property="Foreground" Value="#1A140F" />
<Setter Property="Padding" Value="26 12" />
<Setter Property="FontSize" Value="16" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="CornerRadius" Value="6" />
<Setter Property="BorderBrush" Value="#5C4519" />
<Setter Property="BorderThickness" Value="1" />
</Style>
<Style Selector="Button.primary:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="{StaticResource BrassFillHover}" />
</Style>
<Style Selector="Button.primary:disabled /template/ ContentPresenter">
<Setter Property="Background" Value="#3A2D1E" />
<Setter Property="Foreground" Value="#6B5F4A" />
</Style>
<!-- Secondary button -->
<Style Selector="Button.secondary">
<Setter Property="Background" Value="#1B233A" />
<Setter Property="Foreground" Value="#E8DFC8" />
<Setter Property="Padding" Value="14 8" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="BorderBrush" Value="#A37A2E" />
<Setter Property="BorderThickness" Value="1" />
</Style>
<Style Selector="Button.secondary:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="#26314D" />
<Setter Property="BorderBrush" Value="#E8B95C" />
</Style>
<Style Selector="TextBlock.h1">
<Setter Property="FontSize" Value="22" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="Foreground" Value="#E8DFC8" />
</Style>
<Style Selector="TextBlock.muted">
<Setter Property="Foreground" Value="#7A8497" />
<Setter Property="FontSize" Value="13" />
</Style>
<!-- Brass progress bar -->
<Style Selector="ProgressBar.brass">
<Setter Property="Foreground" Value="{StaticResource BrassFill}" />
<Setter Property="Background" Value="#0A0F1A" />
<Setter Property="BorderBrush" Value="{StaticResource BrassTrim}" />
<Setter Property="BorderThickness" Value="1" />
</Style>
<!-- Custom title bar caption buttons -->
<Style Selector="Button.caption">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Width" Value="46" />
<Setter Property="Height" Value="36" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<Style Selector="Button.caption:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="#1B233A" />
</Style>
<Style Selector="Button.caption Path">
<Setter Property="Stroke" Value="#A37A2E" />
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style Selector="Button.caption:pointerover Path">
<Setter Property="Stroke" Value="#F5D88A" />
</Style>
<Style Selector="Button.caption-close">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Width" Value="46" />
<Setter Property="Height" Value="36" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<Style Selector="Button.caption-close:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="#B94228" />
</Style>
<Style Selector="Button.caption-close Path">
<Setter Property="Stroke" Value="#A37A2E" />
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style Selector="Button.caption-close:pointerover Path">
<Setter Property="Stroke" Value="#F5D88A" />
</Style>
</Window.Styles>
<!-- Outermost: main brass-bordered window + slide-out info panel (separate column, OUTSIDE the window) -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Name="RootBorder" CornerRadius="10"
Background="{StaticResource BrassTrim}"
ClipToBounds="True">
<Border CornerRadius="8" Background="#0B1220" Margin="2" ClipToBounds="True">
<Panel Background="{StaticResource NoiseBrush}">
<Grid RowDefinitions="36,1,*">
<!-- Title bar -->
<Grid Grid.Row="0" Name="TitleBar" Background="{StaticResource TitleBarFill}"
PointerPressed="OnTitleBarPressed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Magic glow halo behind icon + title text -->
<Grid Grid.Column="0" Margin="10 0 0 0" VerticalAlignment="Center" IsHitTestVisible="False">
<Ellipse Width="36" Height="36" HorizontalAlignment="Left"
Margin="-8 0 0 0" Fill="{StaticResource MagicGlow}" />
<StackPanel Orientation="Horizontal" Spacing="10" VerticalAlignment="Center">
<Image Source="/Assets/icon.png" Width="22" Height="22"
RenderOptions.BitmapInterpolationMode="HighQuality" />
<TextBlock Name="TitleText" Text="Brass &amp; Sigil Launcher"
Foreground="#F5D88A" FontSize="12" FontWeight="SemiBold"
VerticalAlignment="Center" />
</StackPanel>
</Grid>
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Stretch">
<Button Classes="caption" Click="OnRefreshClick" ToolTip.Tip="Check for updates">
<Path Width="11" Height="11"
Data="M 9,1.5 A 4,4 0 1 0 10.5,5 M 9,1.5 V 4 H 6.5" />
</Button>
<Button Classes="caption" Click="OnInfoClick" ToolTip.Tip="Pack info">
<Path Width="11" Height="11"
Data="M 5.5,0.5 A 5,5 0 1 1 5.499,0.5 Z M 5.5,4 V 9 M 5.5,2 V 2.5" />
</Button>
<Button Classes="caption" Click="OnMinimizeClick" ToolTip.Tip="Minimize">
<Path Width="10" Height="10" Data="M 0,5 H 10" />
</Button>
<Button Classes="caption-close" Click="OnCloseClick" ToolTip.Tip="Close">
<Path Width="10" Height="10" Data="M 0,0 L 10,10 M 10,0 L 0,10" />
</Button>
</StackPanel>
</Grid>
<!-- Brass divider hairline (own row so hover backgrounds can't paint over it) -->
<Border Grid.Row="1" Background="{StaticResource BrassTrim}" IsHitTestVisible="False" />
<!-- Main content -->
<Grid Grid.Row="2" RowDefinitions="Auto,Auto,*,Auto" Margin="14">
<!-- Update-available banner (hidden until manifest reports a newer launcherVersion) -->
<Border Name="UpdateBanner" Grid.Row="0" IsVisible="False"
Background="#13192A" BorderBrush="#D4A24C" BorderThickness="1"
CornerRadius="6" Padding="12 10" Margin="0 0 0 12">
<Grid ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
<TextBlock Grid.Column="0" Text="ⓘ" FontSize="16"
Foreground="#E8B95C" VerticalAlignment="Center" Margin="0 0 10 0" />
<TextBlock Grid.Column="1" Name="UpdateBannerText" VerticalAlignment="Center"
Foreground="#E8DFC8" FontSize="13" TextWrapping="Wrap"
Text="A newer launcher is available." />
<Button Grid.Column="2" Name="UpdateBannerDownloadButton"
Classes="secondary" Content="Download"
Click="OnUpdateBannerDownloadClick" />
</Grid>
</Border>
<!-- Header card -->
<ContentControl Grid.Row="1" Classes="brass-panel" Margin="0 0 0 14">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" Orientation="Vertical" Spacing="4">
<TextBlock Name="PackNameText" Classes="h1" Text="Modpack" />
<TextBlock Name="PackVersionText" Classes="muted" Text="No pack synced yet" />
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center" Spacing="10">
<TextBlock Name="UserText" Classes="muted" Text="Not signed in" VerticalAlignment="Center" />
<TextBlock Name="WhitelistStatusText" Classes="muted" Text="" IsVisible="False"
VerticalAlignment="Center" FontStyle="Italic" />
<Button Name="RequestAccessButton" Classes="secondary" Content="Request access"
Click="OnRequestAccessClick" IsVisible="False"
ToolTip.Tip="Send the server admin a request to whitelist your account." />
<Button Name="LoginButton" Classes="secondary" Content="Sign in" Click="OnLoginClick" />
<Button Name="LogoutButton" Classes="secondary" Content="Sign out"
Click="OnLogoutClick" IsVisible="False" />
</StackPanel>
</Grid>
</ContentControl>
<!-- Action + log -->
<Grid Grid.Row="2" RowDefinitions="Auto,*">
<ContentControl Grid.Row="0" Classes="brass-panel" Margin="0 0 0 14">
<StackPanel Spacing="14">
<Grid ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center" Spacing="2">
<TextBlock Name="StatusText" Classes="h1" Text="Ready" />
<TextBlock Name="StatusSubtext" Classes="muted"
Text="Click Play to sync the pack and launch Minecraft." />
</StackPanel>
<!-- Play button with subtle cyan glow halo behind -->
<Grid Grid.Column="1" Width="180" Height="48">
<Ellipse HorizontalAlignment="Center" VerticalAlignment="Center"
Width="200" Height="80" Fill="{StaticResource MagicGlow}"
Opacity="0.45" IsHitTestVisible="False" />
<Button Name="PlayButton" Classes="primary" Content="Play"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Click="OnPlayClick" />
</Grid>
</Grid>
<ProgressBar Name="ProgressBar" Classes="brass" Height="8"
Minimum="0" Maximum="100" Value="0" CornerRadius="4" />
</StackPanel>
</ContentControl>
<ContentControl Grid.Row="1" Classes="brass-panel">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" Margin="0 0 0 8">
<TextBlock Grid.Column="0" Classes="h1" Text="Log" FontSize="14" />
<Button Grid.Column="1" Classes="secondary" Content="Open install folder"
Click="OnOpenFolderClick" />
</Grid>
<Border Grid.Row="1" Background="#070B16" CornerRadius="4" Padding="10"
BorderBrush="#1B233A" BorderThickness="1">
<ScrollViewer Name="LogScroll" VerticalScrollBarVisibility="Auto">
<TextBlock Name="LogText" FontFamily="Cascadia Mono, Consolas, monospace"
FontSize="12" Foreground="#B7C0D6" TextWrapping="Wrap" />
</ScrollViewer>
</Border>
</Grid>
</ContentControl>
</Grid>
<!-- Footer / settings -->
<ContentControl Grid.Row="3" Classes="brass-panel" Margin="0 14 0 0">
<StackPanel Spacing="10">
<!-- RAM allocation -->
<Grid ColumnDefinitions="Auto,Auto,*,Auto">
<TextBlock Grid.Column="0" Text="RAM" VerticalAlignment="Center" Classes="muted" />
<NumericUpDown Grid.Column="1" Name="RamBox" Margin="10 0 10 0" Width="140"
Minimum="2048" Maximum="65536" Increment="1024" FormatString="0" />
<TextBlock Grid.Column="2" Text="MB" VerticalAlignment="Center" Classes="muted" Margin="0 0 10 0" />
<TextBlock Grid.Column="3" Name="RamWarningText" VerticalAlignment="Center"
FontSize="11" TextWrapping="Wrap" />
</Grid>
<!-- Install location -->
<Grid ColumnDefinitions="Auto,*,Auto">
<TextBlock Grid.Column="0" Text="Install location" VerticalAlignment="Center" Classes="muted" />
<TextBlock Grid.Column="1" Name="InstallDirText" VerticalAlignment="Center" Margin="10 0 10 0"
TextTrimming="CharacterEllipsis" Foreground="#B7C0D6" FontSize="12" />
<Button Grid.Column="2" Classes="secondary" Content="Change..." Click="OnChangeInstallDirClick" />
</Grid>
<TextBlock Foreground="#5C6478" FontSize="10" TextWrapping="Wrap" HorizontalAlignment="Center"
Text="NOT AN OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT." />
</StackPanel>
</ContentControl>
</Grid>
</Grid>
</Panel>
</Border>
</Border>
<!-- Slide-out container: starts at Width=0 so the Auto column contributes nothing.
InfoPanel inside has fixed Width=320; HorizontalAlignment=Right + ClipToBounds=True
on the container makes the panel "slide in" from the right as the container grows.
Window.Width is animated in lock-step with InfoPanelContainer.Width so the main
content (RootBorder, in the Star column) keeps its current width throughout.
Vertically: outer Grid is single-row (full window height) so this Border
stretches naturally; the inner ScrollViewer inherits it via its Auto,*
Grid row. No code-behind height management needed. -->
<Border Grid.Column="1" Name="InfoPanelContainer" Width="0"
ClipToBounds="True">
<Border Name="InfoPanel" HorizontalAlignment="Right" Width="320" Margin="14 0 0 0"
CornerRadius="10" Background="{StaticResource BrassTrim}"
ClipToBounds="True">
<Border CornerRadius="8" Background="#0F1622" Margin="2" ClipToBounds="True">
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" Margin="14 12 8 8">
<TextBlock Grid.Column="0" Classes="h1" Text="Pack info" FontSize="14"
VerticalAlignment="Center" />
<Button Grid.Column="1" Classes="caption" Click="OnInfoClick" ToolTip.Tip="Close"
Width="32" Height="28">
<Path Width="9" Height="9" Data="M 0,0 L 9,9 M 9,0 L 0,9" />
</Button>
</Grid>
<ScrollViewer Grid.Row="1" Name="InfoScrollViewer"
Padding="14 0 14 40"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<StackPanel Name="InfoPanelContent" Spacing="14" Margin="0 0 0 8" />
</ScrollViewer>
</Grid>
</Border>
</Border>
</Border>
</Grid>
</Window>