fix: stabilize rpg creation entry and opening cg
This commit is contained in:
@@ -599,6 +599,37 @@ pub fn canonicalize_custom_world_profile_before_save(profile: &mut Value) -> boo
|
||||
true
|
||||
}
|
||||
|
||||
pub fn resolve_custom_world_publish_setting_text(
|
||||
payload: &Map<String, Value>,
|
||||
draft_profile: &Map<String, Value>,
|
||||
seed_text: &str,
|
||||
) -> String {
|
||||
// 中文注释:发布按钮的前端契约只保证提交动作名;正式 settingText 必须从草稿真相补齐,
|
||||
// 避免旧会话 seed_text 为空时通过 publish gate,却在最终 compile/publish 阶段失败。
|
||||
read_nested_text_field(payload, &["settingText"])
|
||||
.or_else(|| {
|
||||
read_nested_text_field(
|
||||
draft_profile,
|
||||
&[
|
||||
"settingText",
|
||||
"creatorIntent.rawSettingText",
|
||||
"creatorIntent.worldHook",
|
||||
"worldHook",
|
||||
"anchorContent.worldPromise",
|
||||
"anchorContent.worldPromise.hook",
|
||||
"summary",
|
||||
"name",
|
||||
"title",
|
||||
],
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
let seed = seed_text.trim();
|
||||
(!seed.is_empty()).then(|| seed.to_string())
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn empty_agent_anchor_content_json() -> String {
|
||||
r#"{"worldPromise":null,"playerFantasy":null,"themeBoundary":null,"playerEntryPoint":null,"coreConflict":null,"keyRelationships":null,"hiddenLines":null,"iconicElements":null}"#.to_string()
|
||||
}
|
||||
@@ -804,6 +835,32 @@ fn read_text(object: &Map<String, Value>, key: &str) -> Option<String> {
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
fn read_nested_text_field(object: &Map<String, Value>, keys: &[&str]) -> Option<String> {
|
||||
for key in keys {
|
||||
let mut current = Value::Object(object.clone());
|
||||
let mut found = true;
|
||||
for segment in key.split('.') {
|
||||
if let Some(next) = current.get(segment) {
|
||||
current = next.clone();
|
||||
} else {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if found {
|
||||
if let Some(value) = current
|
||||
.as_str()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
return Some(value.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn read_string_list(object: &Map<String, Value>, key: &str) -> Vec<String> {
|
||||
object
|
||||
.get(key)
|
||||
@@ -955,3 +1012,56 @@ fn build_compiled_profile_payload_json(
|
||||
serde_json::to_string(&Value::Object(payload))
|
||||
.map_err(|_| CustomWorldFieldError::InvalidDraftProfileJson)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn publish_setting_text_falls_back_to_draft_profile_when_seed_is_empty() {
|
||||
let payload = Map::new();
|
||||
let draft_profile = json!({
|
||||
"settingText": "海雾会吞掉记错航线的人。",
|
||||
"worldHook": "在失真的海图上追查一场被篡改的沉船事故。",
|
||||
"summary": "守灯人与群岛议会围绕沉船旧案对峙。"
|
||||
})
|
||||
.as_object()
|
||||
.cloned()
|
||||
.expect("draft profile should be object");
|
||||
|
||||
let setting_text =
|
||||
resolve_custom_world_publish_setting_text(&payload, &draft_profile, "");
|
||||
|
||||
assert_eq!(setting_text, "海雾会吞掉记错航线的人。");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn publish_setting_text_prefers_payload_then_draft_then_seed() {
|
||||
let mut payload = Map::new();
|
||||
payload.insert(
|
||||
"settingText".to_string(),
|
||||
Value::String("发布载荷设定".to_string()),
|
||||
);
|
||||
let draft_profile = json!({
|
||||
"worldHook": "草稿世界一句话",
|
||||
"summary": "草稿摘要"
|
||||
})
|
||||
.as_object()
|
||||
.cloned()
|
||||
.expect("draft profile should be object");
|
||||
|
||||
assert_eq!(
|
||||
resolve_custom_world_publish_setting_text(&payload, &draft_profile, "用户原始设定"),
|
||||
"发布载荷设定"
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_custom_world_publish_setting_text(&Map::new(), &draft_profile, "用户原始设定"),
|
||||
"草稿世界一句话"
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_custom_world_publish_setting_text(&Map::new(), &Map::new(), "用户原始设定"),
|
||||
"用户原始设定"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user