From 4d5f70cb5e3465c0ced4ddeeae8c443e3a7a78ce Mon Sep 17 00:00:00 2001 From: chazmm Date: Thu, 10 Sep 2026 03:27:06 +0100 Subject: [PATCH] Accept original clothing colour resets in outfit validation --- crates/skate-game/src/customiser.rs | 20 ++++++++++++++++++++ crates/skate-game/src/customiser_parts.rs | 3 +++ 2 files changed, 23 insertions(+) diff --git a/crates/skate-game/src/customiser.rs b/crates/skate-game/src/customiser.rs index f22b69ba..b7a706a8 100644 --- a/crates/skate-game/src/customiser.rs +++ b/crates/skate-game/src/customiser.rs @@ -1371,6 +1371,26 @@ mod tests { assert_eq!(option_index(&entry, &p), Some(0)); merge(&mut p, entry.options[1].patch.as_ref().unwrap()); assert_eq!(option_index(&entry, &p), Some(1)); + let material = json!({"name":"original","flags":{},"diffuse":"", + "alpha":false,"tint":[0.4,0.5,0.6],"metallic":0.,"roughness":0.7}); + let library: Library = serde_json::from_value(json!({ + "models":{ + "shoe":{"slot":"Feet","name":"shoe","flags":{},"materials":["new"],"scene":""}, + "head":{"slot":"Rostral","name":"head","flags":{},"materials":["head"],"scene":""}}, + "materials":{"new":material.clone(),"head":material},"defaults":{},"morphs":[] + })).unwrap(); + let parts = Parts::for_test(library); + p["selections"]["Rostral"] = json!({"asset_id":"head","material_id":"head"}); + assert!(parts.resolve(&p).is_ok()); + merge(&mut p, entry.options[0].patch.as_ref().unwrap()); + assert_eq!(option_index(&entry, &p), Some(0)); + assert!(parts.resolve(&p).is_ok(), "original material tint must be selectable"); + let restored: Value = serde_json::from_slice(&serde_json::to_vec(&p).unwrap()).unwrap(); + assert!(parts.resolve(&restored).is_ok(), "saved/online null reset must remain valid"); + for invalid in [json!([2.,0.,0.]),json!([-0.1,0.,0.]),json!([0.,1.]),json!("red")] { + p["colours"]["Feet"] = invalid; + assert_eq!(parts.resolve(&p).unwrap_err(), "Invalid clothing colour"); + } } #[test] fn customiser_owned_menu_presets_tattoos_and_search() { diff --git a/crates/skate-game/src/customiser_parts.rs b/crates/skate-game/src/customiser_parts.rs index 1358fa39..238f8337 100644 --- a/crates/skate-game/src/customiser_parts.rs +++ b/crates/skate-game/src/customiser_parts.rs @@ -117,6 +117,9 @@ impl Parts { } if let Some(colours) = profile["colours"].as_object() { for value in colours.values() { + // The menu uses null to clear a tint and restore the authored + // material colour; profile_material already handles this reset. + if value.is_null() { continue; } let rgb=serde_json::from_value::<[f32;3]>(value.clone()).map_err(|_|"Invalid clothing colour")?; if rgb.iter().any(|v|!(0.0..=1.0).contains(v)) {return Err("Invalid clothing colour".into());} }