README | Build Guide | Configuration Reference
This project is currently in Beta. The release script defaults to -Channel beta, names packages with the -beta suffix, and publishes GitHub releases with the prerelease flag. GitHub does not allow prereleases to be marked as the repository's "Latest" release, so only stable releases force the latest flag.
This project uses VERSION as the release version source of truth. The in-game mod version in src/g_local.h must match it before publishing a release.
The release script is scripts/release.ps1. It builds a beta zip package shaped like the muffmode-0.22.15-beta.zip release asset, plus a Windows installer asset:
muffmode-<version>-beta/
README.html
CHANGELOG.md
LICENSE
MuffModeUpdater.exe
rerelease/
baseq2/
game_x64.dll
muffmode-version.json
muffmode.version
...
muffmode-<version>-beta.zip
muffmode-<version>-beta-windows-installer.exe
The script prefers GitHub Copilot CLI for both CHANGELOG.md and README.html in non-interactive mode. If Copilot is not installed or authenticated, it falls back to deterministic release notes and a styled end-user HTML README so packaging can still complete. Pass -RequireCopilot when you intentionally want the release to fail unless Copilot generation succeeds.
It also writes rerelease/baseq2/muffmode-version.json and rerelease/baseq2/muffmode.version so the Windows updater and launcher can compare the installed version with GitHub releases.
The package also includes the published Windows updater and launcher executable at the package root.
The Windows installer is built with Inno Setup 6. The release script looks for ISCC.exe on PATH, then in the normal Inno Setup install folders. You can pass -InnoSetupCompiler "C:\Path\To\ISCC.exe" to override detection or -SkipInstaller for a zip-only local package.
| Channel | Package suffix | GitHub release flag |
|---|---|---|
alpha |
-alpha |
Prerelease, not latest |
beta |
-beta |
Prerelease, not latest |
rc |
-rc |
Prerelease, not latest |
stable |
none | Latest release |
Use the default beta channel until the project is ready to leave beta.
| Mode | Behavior |
|---|---|
auto |
Inspects changes since the previous release and chooses major, minor, or patch. Breaking-change markers select major; new features, installer/updater/package/workflow additions, commands, cvars, maps, rulesets, gametypes, menu, or voting work select minor; smaller fixes and docs select patch. If the committed source version is already at or above the detected target, it is kept. |
major |
Bumps from the latest release to the next major version. |
minor |
Bumps from the latest release to the next minor version. |
patch |
Bumps from the latest release to the next patch version. |
latch |
Accepted as a patch alias. |
You can also pass -Version 0.23.0 to use an exact version.
Use this when the selected target version does not match VERSION and GAMEMOD_VERSION:
.\scripts\release.ps1 -VersionMode patch -UpdateVersionFiles -SkipBuild -AllowDirtyPackageCommit the version changes before publishing a GitHub release.
Place package-only files in packaging/release-assets using the final package layout. For example:
packaging/release-assets/
rerelease/
baseq2/
muff-sv.cfg
SERVER_CONFIGS.md
bots/navigation/*.nav
maps/*.ent
maps/*.bsp
The script copies these files into the generated package, then overwrites/adds the built DLL, README.html, and CHANGELOG.md.
Run from a Visual Studio developer shell:
.\scripts\release.ps1 -VersionMode autoUse -SkipBuild only when game_x64.dll already exists at the repository root.
Use -SkipUpdaterBuild only when MuffModeUpdater.exe already exists under the updater publish output.
Use -SkipInstaller only when you intentionally want to create the zip without the Windows installer asset.
The package and generated release files are written to dist/release.
The installer is generated from packaging/installer/muffmode-installer.iss. It installs the same payload as the zip into the outer Quake II folder, not directly into rerelease or baseq2.
Installer behavior:
| Choice | Default path |
|---|---|
| Steam | C:\Program Files (x86)\Steam\steamapps\common\Quake 2 |
| Epic Games Store | C:\Program Files\Epic Games\Quake 2 |
| GOG | C:\GOG Games\Quake II |
| Custom or another library | User-selected folder |
The installer checks Steam's install registry and libraryfolders.vdf, Epic Games Store manifest files, and GOG registry/common install locations before showing the store choices. It displays whether Steam, Epic Games Store, or GOG was detected and shows the selected path before the folder page. It still offers an Other location choice for custom libraries. The installer shows the project license, lets users browse after choosing a preset, warns if rerelease\baseq2 is not found, corrects accidental rerelease or baseq2 folder selection back to the outer Quake II folder, prompts users to close applications holding files open, offers Desktop and Start menu shortcuts for the updater and launcher, and backs up an existing rerelease\baseq2\game_x64.dll under rerelease\baseq2\MuffModeBackups before replacing it.
Silent installer runs should pass /DIR="C:\Path\To\Quake 2" explicitly. In silent mode the installer preserves the supplied destination and refuses to continue unless it points at an outer Quake II folder containing rerelease\baseq2.
The release script publishes the Windows updater and launcher automatically and includes MuffModeUpdater.exe in every release package. To publish a self-contained executable manually:
dotnet publish updater\MuffMode.Updater\MuffMode.Updater.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=trueSee the Updater Guide for the updater workflow and local version marker behavior.
Use the Release Muff Mode workflow in GitHub Actions for normal releases. It runs scripts/release.ps1, updates and commits version files when requested, builds the DLL, publishes the updater, builds the Windows installer, creates the GitHub release, uploads the zip and installer assets, and posts the Discord announcement.
GitHub's workflow graph shows jobs, not individual steps. This workflow is intentionally split into visible release jobs: Preflight, Resolve Version, Build And Package, Publish GitHub Release, and Announce On Discord.
Use the separate Validate Release Workflow action when you only want to verify workflow startup and version resolution. It never builds, publishes, or announces a release, which keeps dry-run validation out of the actual release graph.
Required repository secrets:
| Secret | Purpose |
|---|---|
COPILOT_GITHUB_TOKEN |
Fine-grained user PAT used only by the standalone copilot CLI. It must belong to a user with GitHub Copilot access and include the Copilot Requests permission. |
DISCORD_RELEASE_WEBHOOK |
Discord webhook consumed by the release announcement job. The release workflow checks that it exists before publishing. |
Optional repository variables:
| Variable | Purpose |
|---|---|
DISCORD_RELEASE_EMOJI |
Emoji prepended to the Discord announcement headline. Defaults to <:quake2:1174744083403657316>. |
DISCORD_RELEASE_MENTIONS |
Text appended to the Discord announcement headline. Defaults to <@&1424165484491964667> <@&1390287267276525628> for the @quake2 and @playtester roles. Use Discord role mention IDs such as <@&123456789> if you want actual role notifications. |
DISCORD_FEEDBACK_CHANNEL |
Channel link used in the feedback line. Defaults to <#1509926054175834133> for #muffmode. |
RELEASE_BOT_TOKEN is accepted as a legacy fallback for Copilot authentication, but the built-in GITHUB_TOKEN now handles version-file commits and gh release create. If no Copilot token is present, the workflow warns and uses the deterministic documentation generator unless require_copilot is enabled. Because releases created with GITHUB_TOKEN do not trigger other workflows, this release workflow posts the Discord announcement itself after the GitHub release is published. The separate Broadcast Release To Discord workflow remains useful for releases published manually through GitHub.
Workflow inputs:
| Input | Purpose |
|---|---|
version_mode |
auto, major, minor, patch, or latch as a patch alias. |
version |
Optional exact version, such as 0.23.0. |
previous_tag |
Optional changelog start tag override. |
channel |
Defaults to beta; non-stable channels publish as prereleases. |
commit_version_files |
Updates VERSION and src/g_local.h, commits, and pushes before publishing. |
skip_installer |
Creates only the zip package when the installer is intentionally not wanted. |
require_copilot |
Requires GitHub Copilot CLI generation and fails if Copilot authentication is unavailable. Leave disabled to use the deterministic fallback when needed. |
When a Copilot token is configured, the release workflow installs the current standalone GitHub Copilot CLI with npm install -g @github/copilot, exports COPILOT_GITHUB_TOKEN, and primes copilot --help before generating the changelog and end-user HTML README.
After committing version changes and ensuring the working tree is clean:
.\scripts\release.ps1 -VersionMode auto -CreateGitHubReleaseThe script creates v<version>, uploads the package zip and Windows installer, and uses the generated changelog as release notes. Stable releases pass --latest; beta, alpha, and release-candidate builds pass --prerelease --latest=false because GitHub rejects releases that are both latest and prerelease.
The changelog is generated from git log <previous-release-tag>..HEAD, so it includes only commits since the previous release. Pass -PreviousTag v0.22.15 to override the detected start tag.
When Copilot is available, it receives a structured change context for that exact range: commit subjects, merge subjects, changed files, diff stats, and compare URL. The script writes the full prompt to dist/release/copilot-prompts, then gives Copilot a short programmatic instruction to read that file, which avoids Windows command-line length limits. The changelog prompt uses silent/no-question mode and grants only Git shell access for inspection. It is prompted to summarize by practical impact for casual players, competitive players, and server hosts, using only relevant categories such as player experience, competitive play, server hosting, gameplay and balance, fixes, documentation, packaging, and internal maintenance.
The script validates Copilot output before packaging. If Copilot is unavailable and -RequireCopilot is not used, the deterministic fallback still scopes the changelog to the same git range and creates a Quake II styled end-user README focused on installation, usage, hosting, package contents, and the changelog.