Keep title panorama optional during full resource preparation

This commit is contained in:
rdbtCVS committed 2026-10-14 19:15:16 +01:00
1 parent eebf5621bf
commit aab88753b6
3 files changed
+58 -11

No files matched your search

+2 -1
View File
@@ -685,7 +685,8 @@ fn steps(
// The JAR holds only gray 1x1 panorama placeholders. Import the indexed
// textures afterwards, including on reruns that just extracted the JAR again.
panorama(repo, minecraft, run.log)?;
// Cosmetic assets are optional when preparing from already-imported JARs.
sounds::optional_panorama(repo, minecraft, run.log);
// One file each, exported again when the exporter or the jar it reads changed.
let single = |what: &str,
+52 -7
View File
@@ -85,6 +85,15 @@ pub fn panorama(root: &Path, minecraft: Option<&Path>, log: Log) -> Result<PathB
copy_assets(root, minecraft, log, is_panorama, "Panorama", &PANORAMA)
}
/// Full preparation can run from cached JARs without an official launcher install.
pub(crate) fn optional_panorama(root: &Path, minecraft: Option<&Path>, log: Log) {
if let Err(error) = panorama(root, minecraft, log) {
log(&format!(
"Title panorama not imported: {error}; run horizon-prepare panorama later"
));
}
}
const PANORAMA: [&str; 7] = [
"minecraft/textures/gui/title/background/panorama_0.png",
"minecraft/textures/gui/title/background/panorama_1.png",
@@ -138,6 +147,7 @@ fn copy_assets(
}
}
let mut total: u64 = 0;
let mut copies = Vec::with_capacity(wanted.len());
for (name, info) in &wanted {
let hash = info
.get("hash")
@@ -151,15 +161,14 @@ fn copy_assets(
let relative = artifacts::safe_relative(name)
.ok_or_else(|| format!("Unsafe asset name {name:?} in the asset index"))?;
let source = launcher_object(&store, hash)?;
artifacts::import_copy(
&source,
&target.join("assets").join(relative),
hash,
"sha1",
"",
)?;
copies.push((source, target.join("assets").join(relative), hash));
total += size;
}
// Check the entire set before replacing any placeholders: a missing late face
// must not leave a mixture of real textures and gray faces in either entry point.
for (source, destination, hash) in copies {
artifacts::import_copy(&source, &destination, hash, "sha1", "")?;
}
log(&format!(
"{label} assets ready: {} files, {:.1} MB",
wanted.len(),
@@ -366,6 +375,42 @@ mod tests {
assert!(!f.root.join(".local/horizon-client/9.9/assets").exists());
}
#[test]
fn full_preparation_keeps_placeholders_when_panorama_is_unavailable() {
for missing in ["store", "install", "last-object"] {
let f = Fixture::new(&format!("optional-panorama-{missing}"));
// The JARs and manifest were imported earlier; the launcher need not remain.
artifacts::import_manifest(&Lock::read(&f.root).unwrap(), &f.minecraft).unwrap();
let target = f.root.join(".local/horizon-client/9.9/assets");
for name in PANORAMA {
let path = target.join(name);
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, b"jar placeholder").unwrap();
}
match missing {
"store" => fs::remove_dir_all(f.minecraft.join("assets")).unwrap(),
"install" => fs::remove_dir_all(&f.minecraft).unwrap(),
_ => fs::remove_file(f.object(f.objects.len() - 1)).unwrap(),
}
// The repair subcommand remains strict, even for a missing final object.
let error = panorama(&f.root, Some(&f.minecraft), &|_| {}).unwrap_err();
let lines = std::cell::RefCell::new(Vec::new());
// This is the optional import step used by full preparation after extraction.
optional_panorama(&f.root, Some(&f.minecraft), &|line| {
lines.borrow_mut().push(line.to_string())
});
assert_eq!(
*lines.borrow(),
[format!(
"Title panorama not imported: {error}; run horizon-prepare panorama later"
)]
);
for name in PANORAMA {
assert_eq!(fs::read(target.join(name)).unwrap(), b"jar placeholder");
}
}
}
#[test]
fn the_index_must_be_the_pinned_one() {
let f = Fixture::new("index");
+4 -3
View File
@@ -23,9 +23,10 @@ verifies it against the pinned checksums, runs vanilla's data generator and smal
exporters against those jars, and extracts the jar's assets and data into ignored
`.local/horizon-client/26.3/`. Sounds (about 380 MB) are copied from your
launcher's asset store by `horizon-prepare sounds`, each file checked against the asset
index's SHA-1. Preparation also replaces the JAR's gray 1×1 title panorama placeholders
with the full textures from that asset store. To repair an existing classic menu background
without rerunning the Java exporters, run `horizon-prepare panorama` (or
index's SHA-1. Preparation also tries to replace the JAR's gray 1×1 title panorama
placeholders with the full textures from that asset store. If the store is missing or
incomplete, preparation logs a warning and keeps the placeholders. To import the panorama
later without rerunning the Java exporters, run `horizon-prepare panorama` (or
`cargo run --release -p horizon-prepare -- panorama` in a checkout). Pass
`--minecraft-dir PATH` when using a different Minecraft installation.
Prepared resources are private; never commit them.