diff --git a/crates/horizon-client/src/crash.rs b/crates/horizon-client/src/crash.rs index e147bfb4c..5490808a1 100644 --- a/crates/horizon-client/src/crash.rs +++ b/crates/horizon-client/src/crash.rs @@ -105,9 +105,13 @@ impl Report { } } -/// The release this binary is (`v0.2.3`); for a release from before 0.2, its tag and the client's -/// crate version; for a build from source, that version alone. +/// The release this binary is (`v0.2.3`); a nightly's label (`Nightly 2026-10-28 · 0c02067`); for a +/// release from before 0.2, its tag and the client's crate version; for a build from source, that +/// version alone. pub fn version() -> String { + if let Some(label) = horizon_core::release::nightly_label() { + return label; + } let version = env!("CARGO_PKG_VERSION"); match (horizon_core::release::RELEASE, release_tag()) { (Some(_), Some(tag)) => tag, @@ -117,8 +121,12 @@ pub fn version() -> String { } /// The release this binary came with: the version release.yml built in (docs/versioning.md), else -/// the folder the launcher installed it in, named after the tag (releases from before 0.2). +/// the folder the launcher installed it in, named after the tag (releases from before 0.2). A +/// nightly is its version as the launcher installs it (`nightly-2026-10-28-0c02067`). pub fn release_tag() -> Option { + if let Some(nightly) = horizon_core::release::nightly_version() { + return Some(nightly); + } if let Some(version) = horizon_core::release::RELEASE { return Some(format!("v{version}")); } @@ -525,6 +533,11 @@ mod tests { #[test] fn a_release_reports_its_built_in_version() { // release.yml builds with HORIZON_VERSION (docs/versioning.md): `v0.2.3`, wherever it is installed. + if let Some(label) = horizon_core::release::nightly_label() { + assert_eq!(super::version(), label); + assert_eq!(release_tag(), horizon_core::release::nightly_version()); + return; + } match horizon_core::release::RELEASE { Some(version) => { assert_eq!(release_tag(), Some(format!("v{version}"))); diff --git a/crates/horizon-client/src/main.rs b/crates/horizon-client/src/main.rs index 7144a1670..8d03455af 100644 --- a/crates/horizon-client/src/main.rs +++ b/crates/horizon-client/src/main.rs @@ -23,6 +23,8 @@ fn main() { }; if !help { logging::init(&home, thread); + // The log's first line names the build, so a bug report that carries the log says which one it was. + log::info!("Horizon {}", crash::version()); crash::install(home.clone(), side); } if let Err(error) = game::run() { diff --git a/crates/horizon-client/src/title.rs b/crates/horizon-client/src/title.rs index b2fcfe8f4..d08917303 100644 --- a/crates/horizon-client/src/title.rs +++ b/crates/horizon-client/src/title.rs @@ -966,6 +966,11 @@ impl Title { } let version = format!("Horizon {} (Rust)", horizon_core::VANILLA_VERSION); batch.text(atlas, &version, 2.0, h - 10.0, u32::MAX, true); + // A nightly names its build in the top-left corner, the one spot no button reaches at any GUI + // scale, so screenshots and reports say which build they come from. + if let Some(nightly) = horizon_core::release::nightly_label() { + batch.text(atlas, &nightly, 2.0, 2.0, u32::MAX, true); + } let notice = "Not affiliated with Mojang or Microsoft"; let tw = HudBatch::text_width(atlas, notice); batch.text(atlas, notice, w - tw - 2.0, h - 10.0, u32::MAX, true); diff --git a/crates/horizon-core/src/release.rs b/crates/horizon-core/src/release.rs index 54a3cb94e..4e7378601 100644 --- a/crates/horizon-core/src/release.rs +++ b/crates/horizon-core/src/release.rs @@ -15,8 +15,43 @@ pub const VERSION: &str = match RELEASE { None => env!("CARGO_PKG_VERSION"), }; +/// A nightly's date and commit (`2026-10-28 0c02067`): nightly-build.yml builds the opt-in Nightly +/// channel with `HORIZON_NIGHTLY` set (docs/release-flow.md). None for a release or a build from source. +pub const NIGHTLY: Option<&str> = match option_env!("HORIZON_NIGHTLY") { + Some(nightly) if !nightly.is_empty() => Some(nightly), + _ => None, +}; + +/// How a nightly names itself where players read it, so their reports say which build they come +/// from: `Nightly 2026-10-28 · 0c02067`. None for any other build. +pub fn nightly_label() -> Option { + NIGHTLY.map(label) +} + +/// A nightly's version as the launcher installs it (`nightly-2026-10-28-0c02067`). +pub fn nightly_version() -> Option { + NIGHTLY.map(|n| format!("nightly-{}", n.replace(' ', "-"))) +} + +fn label(nightly: &str) -> String { + match nightly.split_once(' ') { + Some((date, commit)) => format!("Nightly {date} · {commit}"), + None => format!("Nightly {nightly}"), + } +} + #[cfg(test)] mod tests { + #[test] + fn a_nightly_names_its_date_and_commit() { + assert_eq!( + super::label("2026-10-28 0c02067"), + "Nightly 2026-10-28 · 0c02067" + ); + assert_eq!(super::label("2026-10-28"), "Nightly 2026-10-28"); + assert_eq!(super::nightly_label().is_some(), super::NIGHTLY.is_some()); + } + #[test] fn the_version_is_the_release_or_the_crate() { assert_eq!(