a1331212cb
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.
208 lines
7.8 KiB
PowerShell
208 lines
7.8 KiB
PowerShell
#requires -Version 5
|
|
<#
|
|
.SYNOPSIS
|
|
Refreshes pack.lock.json by querying Modrinth + CurseForge for the latest
|
|
compatible version of each mod listed below.
|
|
|
|
.DESCRIPTION
|
|
THIS SCRIPT MUTATES pack.lock.json. Run only when you intentionally want to
|
|
bump versions (and remember to update the server to match).
|
|
|
|
For non-mutating "what's available?" reports, run Check-Updates.ps1.
|
|
|
|
.PARAMETER PackName
|
|
.PARAMETER PackVersion
|
|
.PARAMETER MinecraftVersion
|
|
.PARAMETER LoaderType
|
|
.PARAMETER LoaderVersion
|
|
Override pack metadata. Defaults read from existing lockfile if present.
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$PackName = "",
|
|
[string]$PackVersion = "",
|
|
[string]$MinecraftVersion = "1.21.1",
|
|
[string]$LoaderType = "neoforge",
|
|
[string]$LoaderVersion = ""
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$ProgressPreference = 'SilentlyContinue'
|
|
|
|
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$lockPath = Join-Path $here '..\pack\pack.lock.json'
|
|
|
|
# Read existing lock for defaults
|
|
$existing = if (Test-Path $lockPath) { Get-Content $lockPath -Raw | ConvertFrom-Json } else { $null }
|
|
if (-not $PackName -and $existing) { $PackName = $existing.name }
|
|
if (-not $PackVersion -and $existing) { $PackVersion = $existing.version }
|
|
if (-not $LoaderVersion -and $existing) { $LoaderVersion = $existing.loader.version }
|
|
if (-not $PackName) { $PackName = "Brass and Sigil" }
|
|
if (-not $PackVersion) { $PackVersion = "0.6.0" }
|
|
if (-not $LoaderVersion) { $LoaderVersion = "21.1.228" }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Mod definitions: edit here when adding/removing mods. allowBeta=true allows
|
|
# fallback to beta if no release exists.
|
|
# ---------------------------------------------------------------------------
|
|
$modrinthMods = @(
|
|
@{ slug = "create"; allowBeta = $false }
|
|
@{ slug = "create-aeronautics"; allowBeta = $false }
|
|
@{ slug = "sable"; allowBeta = $false }
|
|
@{ slug = "create-big-cannons"; allowBeta = $false }
|
|
@{ slug = "create-tfmg"; allowBeta = $false }
|
|
@{ slug = "distanthorizons"; allowBeta = $true }
|
|
@{ slug = "sodium"; allowBeta = $false }
|
|
@{ slug = "iris"; allowBeta = $false }
|
|
@{ slug = "modernfix"; allowBeta = $false }
|
|
@{ slug = "ferrite-core"; allowBeta = $false }
|
|
@{ slug = "architectury-api"; allowBeta = $false }
|
|
@{ slug = "rhino"; allowBeta = $true }
|
|
@{ slug = "rpl"; allowBeta = $false }
|
|
@{ slug = "kubejs"; allowBeta = $false }
|
|
@{ slug = "jei"; allowBeta = $true }
|
|
@{ slug = "jade"; allowBeta = $false }
|
|
@{ slug = "chunky"; allowBeta = $false }
|
|
)
|
|
|
|
# CurseForge mods aren't auto-resolved (no public API without a key).
|
|
# Update fileId/version/filename here when bumping.
|
|
$curseforgeMods = @(
|
|
@{
|
|
slug = "ftb-library"
|
|
version = "2101.1.31"
|
|
fileId = "7746959"
|
|
path = "mods/ftb-library-neoforge-2101.1.31.jar"
|
|
url = "https://mediafilez.forgecdn.net/files/7746/959/ftb-library-neoforge-2101.1.31.jar"
|
|
}
|
|
@{
|
|
slug = "ftb-teams"
|
|
version = "2101.1.9"
|
|
fileId = "7369021"
|
|
path = "mods/ftb-teams-neoforge-2101.1.9.jar"
|
|
url = "https://mediafilez.forgecdn.net/files/7369/21/ftb-teams-neoforge-2101.1.9.jar"
|
|
}
|
|
@{
|
|
slug = "ftb-chunks"
|
|
version = "2101.1.14"
|
|
fileId = "7608681"
|
|
path = "mods/ftb-chunks-neoforge-2101.1.14.jar"
|
|
url = "https://mediafilez.forgecdn.net/files/7608/681/ftb-chunks-neoforge-2101.1.14.jar"
|
|
}
|
|
)
|
|
|
|
Add-Type -AssemblyName System.Web
|
|
|
|
function Invoke-Modrinth {
|
|
param([string]$Path)
|
|
Invoke-RestMethod -Uri "https://api.modrinth.com/v2$Path" -Headers @{ 'User-Agent' = 'BrassAndSigil-Launcher/0.1 (matt@sijbers.uk)' }
|
|
}
|
|
|
|
function Get-LatestModrinthVersion {
|
|
param([string]$Slug, [bool]$AllowBeta)
|
|
$encGv = [System.Web.HttpUtility]::UrlEncode('["' + $MinecraftVersion + '"]')
|
|
$encL = [System.Web.HttpUtility]::UrlEncode('["' + $LoaderType + '"]')
|
|
$versions = Invoke-Modrinth ("/project/$Slug/version?game_versions=$encGv" + "&" + "loaders=$encL")
|
|
if (-not $versions -or $versions.Count -eq 0) { return $null }
|
|
if ($AllowBeta) {
|
|
# Take the newest version regardless of stability (Modrinth orders newest first).
|
|
return $versions[0]
|
|
}
|
|
# Stable-only: latest release version, or null if there's no release at all.
|
|
return $versions | Where-Object { $_.version_type -eq 'release' } | Select-Object -First 1
|
|
}
|
|
|
|
$lockedMods = @()
|
|
$missing = @()
|
|
|
|
Write-Host ""
|
|
Write-Host "Querying Modrinth for $($modrinthMods.Count) mods (MC $MinecraftVersion / $LoaderType)..."
|
|
Write-Host ""
|
|
|
|
foreach ($mod in $modrinthMods) {
|
|
try {
|
|
$version = Get-LatestModrinthVersion -Slug $mod.slug -AllowBeta $mod.allowBeta
|
|
} catch {
|
|
Write-Warning " [error] $($mod.slug) - $($_.Exception.Message)"
|
|
$missing += $mod.slug
|
|
continue
|
|
}
|
|
if (-not $version) {
|
|
Write-Warning " [missing] $($mod.slug) - no compatible version"
|
|
$missing += $mod.slug
|
|
continue
|
|
}
|
|
$primary = $version.files | Where-Object { $_.primary -eq $true } | Select-Object -First 1
|
|
if (-not $primary) { $primary = $version.files[0] }
|
|
|
|
$lockedMods += [ordered]@{
|
|
source = "modrinth"
|
|
slug = $mod.slug
|
|
versionId = $version.id
|
|
version = $version.version_number
|
|
path = "mods/$($primary.filename)"
|
|
url = $primary.url
|
|
sha1 = $primary.hashes.sha1
|
|
size = $primary.size
|
|
}
|
|
|
|
$tag = if ($version.version_type -eq 'beta') { '[beta] ' } else { '[release]' }
|
|
Write-Host (" $tag $($mod.slug.PadRight(22)) $($version.version_number.PadRight(28))")
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Hashing $($curseforgeMods.Count) CurseForge mods (manual entries)..."
|
|
$tmpDir = Join-Path $env:TEMP "brassandsigil-cf-cache"
|
|
if (-not (Test-Path $tmpDir)) { New-Item -ItemType Directory -Path $tmpDir | Out-Null }
|
|
|
|
foreach ($cf in $curseforgeMods) {
|
|
$fname = Split-Path -Leaf $cf.path
|
|
$tmpFile = Join-Path $tmpDir $fname
|
|
try {
|
|
if (-not (Test-Path $tmpFile)) {
|
|
Invoke-WebRequest -Uri $cf.url -OutFile $tmpFile -UseBasicParsing -Headers @{ 'User-Agent' = 'BrassAndSigil-Launcher/0.1 (matt@sijbers.uk)' }
|
|
}
|
|
$sha1 = (Get-FileHash -Algorithm SHA1 -Path $tmpFile).Hash.ToLowerInvariant()
|
|
$size = (Get-Item $tmpFile).Length
|
|
|
|
$lockedMods += [ordered]@{
|
|
source = "curseforge"
|
|
slug = $cf.slug
|
|
fileId = $cf.fileId
|
|
version = $cf.version
|
|
path = $cf.path
|
|
url = $cf.url
|
|
sha1 = $sha1
|
|
size = $size
|
|
}
|
|
Write-Host (" [cforge] $($cf.slug.PadRight(22)) $($cf.version)")
|
|
}
|
|
catch {
|
|
Write-Warning " [error] $fname - $($_.Exception.Message)"
|
|
$missing += $fname
|
|
}
|
|
}
|
|
|
|
$lock = [ordered]@{
|
|
'$schema' = "Brass-and-Sigil pack.lock.json - generated, do not edit by hand unless you know what you are doing"
|
|
name = $PackName
|
|
version = $PackVersion
|
|
minecraft = $MinecraftVersion
|
|
loader = [ordered]@{ type = $LoaderType; version = $LoaderVersion }
|
|
lockedAt = (Get-Date -Format 'o')
|
|
mods = $lockedMods
|
|
}
|
|
|
|
$json = $lock | ConvertTo-Json -Depth 10
|
|
[System.IO.File]::WriteAllText($lockPath, $json, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
Write-Host ""
|
|
Write-Host "Lockfile written: $lockPath"
|
|
Write-Host (" Total mods: {0}" -f $lockedMods.Count)
|
|
if ($missing.Count -gt 0) {
|
|
Write-Warning "Missing: $($missing -join ', ')"
|
|
}
|
|
Write-Host ""
|
|
Write-Host "Run Build-Pack.ps1 next to generate the manifest."
|