From ab1d0988770c50e91714853aec087e93da889abe Mon Sep 17 00:00:00 2001 From: funman300 Date: Fri, 1 May 2026 17:21:03 +0000 Subject: [PATCH] fix(engine): use resolve_embed for sibling theme assets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `AssetPath::resolve` concatenates, so manifest-relative SVG paths ended up under `…/theme.ron/.svg` and the asset server reported all 53 references missing. `resolve_embed` is the RFC 1808 sibling-resolution method that strips the base path's last segment first, giving the intended `…/.svg`. Default theme now loads cleanly from the embedded:// source. Co-Authored-By: Claude Opus 4.7 (1M context) --- solitaire_engine/src/theme/loader.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/solitaire_engine/src/theme/loader.rs b/solitaire_engine/src/theme/loader.rs index affc764..7e4a488 100644 --- a/solitaire_engine/src/theme/loader.rs +++ b/solitaire_engine/src/theme/loader.rs @@ -35,9 +35,9 @@ pub enum CardThemeLoaderError { Parse(#[from] ron::error::SpannedError), #[error("manifest validation: {0}")] Validation(#[from] ManifestError), - /// `AssetPath::resolve` rejected a manifest-relative path. Almost - /// always means the manifest contains an absolute path or a - /// surface that includes a custom asset source the manifest + /// `AssetPath::resolve_embed` rejected a manifest-relative path. + /// Almost always means the manifest contains an absolute path or + /// a surface that includes a custom asset source the manifest /// shouldn't be reaching across. #[error("could not resolve asset path: {0}")] PathResolve(#[from] ParseAssetPathError), @@ -73,12 +73,18 @@ impl AssetLoader for CardThemeLoader { // it via `.loader()`. let manifest_path: AssetPath<'static> = load_context.path().clone(); - let back_path = manifest_path.resolve(&path_to_str(&manifest.back))?; + // `resolve_embed` is the RFC 1808 sibling-resolution method: + // the last segment of the base path (the manifest filename) is + // stripped before concatenation, so `themes/foo/theme.ron` + + // `hearts_4.svg` resolves to `themes/foo/hearts_4.svg`. Plain + // `resolve` would concatenate, giving `themes/foo/theme.ron/hearts_4.svg`, + // which is never what manifest-relative references mean. + let back_path = manifest_path.resolve_embed(&path_to_str(&manifest.back))?; let face_full: Vec<(CardKey, AssetPath<'static>)> = face_paths .iter() .map(|(k, p)| { manifest_path - .resolve(&path_to_str(p)) + .resolve_embed(&path_to_str(p)) .map(|ap| (*k, ap)) }) .collect::>()?;