1
This commit is contained in:
@@ -870,24 +870,6 @@ fn normalize_world_attribute_schema(
|
||||
normalized_slots.push(json!({
|
||||
"slotId": slot_id,
|
||||
"name": name,
|
||||
"definition": json_map_text(raw_slot, "definition")
|
||||
.or_else(|| json_map_text(&fallback_slot, "definition"))
|
||||
.unwrap_or_else(|| "这个维度用于描述角色在当前世界中的关键表现。".to_string()),
|
||||
"positiveSignals": json_map_string_array(raw_slot, "positiveSignals")
|
||||
.or_else(|| json_map_string_array(&fallback_slot, "positiveSignals"))
|
||||
.unwrap_or_else(|| vec!["稳定".to_string(), "主动".to_string()]),
|
||||
"negativeSignals": json_map_string_array(raw_slot, "negativeSignals")
|
||||
.or_else(|| json_map_string_array(&fallback_slot, "negativeSignals"))
|
||||
.unwrap_or_else(|| vec!["失衡".to_string(), "被动".to_string()]),
|
||||
"combatUseText": json_map_text(raw_slot, "combatUseText")
|
||||
.or_else(|| json_map_text(&fallback_slot, "combatUseText"))
|
||||
.unwrap_or_else(|| "影响战斗中的推进、承压与应对。".to_string()),
|
||||
"socialUseText": json_map_text(raw_slot, "socialUseText")
|
||||
.or_else(|| json_map_text(&fallback_slot, "socialUseText"))
|
||||
.unwrap_or_else(|| "影响对话中的判断、牵引与立场。".to_string()),
|
||||
"explorationUseText": json_map_text(raw_slot, "explorationUseText")
|
||||
.or_else(|| json_map_text(&fallback_slot, "explorationUseText"))
|
||||
.unwrap_or_else(|| "影响探索中的观察、穿行与续航。".to_string()),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -901,9 +883,6 @@ fn normalize_world_attribute_schema(
|
||||
.and_then(JsonValue::as_i64)
|
||||
.filter(|value| *value > 0)
|
||||
.unwrap_or(1),
|
||||
"schemaName": json_map_text(schema, "schemaName")
|
||||
.filter(|value| !is_invalid_attribute_schema_name(value))
|
||||
.unwrap_or_else(|| build_attribute_schema_name(framework, setting_text)),
|
||||
"generatedFrom": {
|
||||
"worldType": "CUSTOM",
|
||||
"worldName": framework_world_name(framework, setting_text),
|
||||
@@ -945,7 +924,6 @@ fn build_fallback_world_attribute_schema(framework: &JsonValue, setting_text: &s
|
||||
"id": build_attribute_schema_id(framework, setting_text),
|
||||
"worldId": format!("custom:{world_name}"),
|
||||
"schemaVersion": 1,
|
||||
"schemaName": build_attribute_schema_name(framework, setting_text),
|
||||
"generatedFrom": {
|
||||
"worldType": "CUSTOM",
|
||||
"worldName": world_name,
|
||||
@@ -954,35 +932,20 @@ fn build_fallback_world_attribute_schema(framework: &JsonValue, setting_text: &s
|
||||
"conflictCore": conflict_core,
|
||||
},
|
||||
"slots": [
|
||||
build_attribute_slot("axis_a", format!("{prefix}骨"), format!("承受{prefix}压、正面冲击与长期消耗的底子。"), ["承压", "稳阵"], ["虚浮", "易散"], "顶住正面压力并守住行动空间。", "在强压场面里保持可信和稳固。", "穿过危险环境时维持身体与装备状态。"),
|
||||
build_attribute_slot("axis_b", format!("{prefix_alt}步"), format!("顺应{prefix_alt}势、换位穿行与抢占时机的能力。"), ["借势", "轻快"], ["迟滞", "失位"], "切线换位、闪避、追击和抢先手。", "反应灵活,能顺势调整话术。", "穿越复杂地形、封锁线与危险通路。"),
|
||||
build_attribute_slot("axis_c", format!("{prefix}识"), "看清局势、线索、虚实与隐藏代价的能力。", ["洞察", "辨伪"], ["误读", "迟钝"], "识破破绽并判断战局变化。", "听出隐瞒、试探与交换空间。", "整理线索、辨认路径并推断风险。"),
|
||||
build_attribute_slot("axis_d", format!("{prefix_alt}魄"), "在高压变化里仍能推进目标和拍板的胆气。", ["果断", "压前"], ["犹疑", "退缩"], "顶着高压窗口推进突破口。", "在谈判或对峙中定调。", "面对未知异象仍敢继续前探。"),
|
||||
build_attribute_slot("axis_e", format!("{prefix}契"), "与人、物、誓约、地方关系建立牵引的能力。", ["协同", "守诺"], ["疏离", "失信"], "借同伴协同与牵制形成连锁。", "安抚、结盟、交换与维系信任。", "从人情、传闻和旧物中打开线索。"),
|
||||
build_attribute_slot("axis_f", format!("回{prefix_alt}"), "在长线消耗和局势反复中回稳节奏的能力。", ["回稳", "续航"], ["紊乱", "断续"], "久战不乱,把节奏重新拉回手里。", "情绪稳定,不轻易被带偏。", "在漫长探索与恶劣环境里保有余力。"),
|
||||
build_attribute_slot("axis_a", format!("{prefix}骨")),
|
||||
build_attribute_slot("axis_b", format!("{prefix_alt}步")),
|
||||
build_attribute_slot("axis_c", format!("{prefix}识")),
|
||||
build_attribute_slot("axis_d", format!("{prefix_alt}魄")),
|
||||
build_attribute_slot("axis_e", format!("{prefix}契")),
|
||||
build_attribute_slot("axis_f", format!("回{prefix_alt}")),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn build_attribute_slot(
|
||||
slot_id: &str,
|
||||
name: String,
|
||||
definition: impl Into<String>,
|
||||
positive_signals: [&str; 2],
|
||||
negative_signals: [&str; 2],
|
||||
combat_use_text: &str,
|
||||
social_use_text: &str,
|
||||
exploration_use_text: &str,
|
||||
) -> JsonValue {
|
||||
fn build_attribute_slot(slot_id: &str, name: String) -> JsonValue {
|
||||
json!({
|
||||
"slotId": slot_id,
|
||||
"name": name,
|
||||
"definition": definition.into(),
|
||||
"positiveSignals": positive_signals,
|
||||
"negativeSignals": negative_signals,
|
||||
"combatUseText": combat_use_text,
|
||||
"socialUseText": social_use_text,
|
||||
"explorationUseText": exploration_use_text,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1008,20 +971,6 @@ fn build_attribute_schema_id(framework: &JsonValue, setting_text: &str) -> Strin
|
||||
)
|
||||
}
|
||||
|
||||
fn build_attribute_schema_name(framework: &JsonValue, setting_text: &str) -> String {
|
||||
let source = [
|
||||
framework_world_name(framework, setting_text),
|
||||
json_text(framework, "summary").unwrap_or_default(),
|
||||
json_text(framework, "tone").unwrap_or_default(),
|
||||
]
|
||||
.join("。");
|
||||
let terms = collect_attribute_theme_terms(source.as_str());
|
||||
format!(
|
||||
"{}六维",
|
||||
terms.first().cloned().unwrap_or_else(|| "叙境".to_string())
|
||||
)
|
||||
}
|
||||
|
||||
fn collect_attribute_theme_terms(source: &str) -> Vec<String> {
|
||||
let mut terms = Vec::new();
|
||||
let chinese_chars = source
|
||||
@@ -1062,12 +1011,6 @@ fn is_invalid_attribute_name(name: &str, seen_names: &[String]) -> bool {
|
||||
.any(|banned| trimmed.contains(banned))
|
||||
}
|
||||
|
||||
fn is_invalid_attribute_schema_name(name: &str) -> bool {
|
||||
BANNED_ATTRIBUTE_NAMES
|
||||
.iter()
|
||||
.any(|banned| name.trim().contains(banned))
|
||||
}
|
||||
|
||||
fn json_map_text(map: &JsonMap<String, JsonValue>, key: &str) -> Option<String> {
|
||||
map.get(key)
|
||||
.and_then(JsonValue::as_str)
|
||||
@@ -1076,18 +1019,6 @@ fn json_map_text(map: &JsonMap<String, JsonValue>, key: &str) -> Option<String>
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
|
||||
fn json_map_string_array(map: &JsonMap<String, JsonValue>, key: &str) -> Option<Vec<String>> {
|
||||
let items = map
|
||||
.get(key)?
|
||||
.as_array()?
|
||||
.iter()
|
||||
.filter_map(|entry| entry.as_str().map(str::trim))
|
||||
.filter(|entry| !entry.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<Vec<_>>();
|
||||
if items.is_empty() { None } else { Some(items) }
|
||||
}
|
||||
|
||||
fn first_json_string(value: &JsonValue, key: &str) -> Option<String> {
|
||||
value
|
||||
.get(key)
|
||||
@@ -2492,7 +2423,7 @@ mod tests {
|
||||
request_capture.clone(),
|
||||
vec![
|
||||
llm_response(
|
||||
r#"{"name":"雾港归航","subtitle":"失灯旧案","summary":"守灯人与群岛议会围绕沉船旧案对峙。","tone":"海雾悬疑","playerGoal":"查清父亲沉船真相","templateWorldType":"WUXIA","majorFactions":["群岛议会","灯塔署"],"coreConflicts":["守灯塔的旧档案被人改写。"],"attributeSchema":{"schemaName":"雾港六维","slots":[{"slotId":"axis_a","name":"灯骨","definition":"承受封航压力与潮湿险境的底子。","positiveSignals":["承压"],"negativeSignals":["虚浮"],"combatUseText":"顶住正面压迫。","socialUseText":"在质问中稳住姿态。","explorationUseText":"穿过潮湿险境。"},{"slotId":"axis_b","name":"潮步","definition":"顺潮换位与穿行的能力。","positiveSignals":["轻快"],"negativeSignals":["迟滞"],"combatUseText":"切线换位。","socialUseText":"顺势调整说法。","explorationUseText":"穿越雾港通路。"},{"slotId":"axis_c","name":"灯识","definition":"辨认灯号和旧档错页的能力。","positiveSignals":["辨伪"],"negativeSignals":["误读"],"combatUseText":"看破破绽。","socialUseText":"听出遮掩。","explorationUseText":"辨认旧档线索。"},{"slotId":"axis_d","name":"雾魄","definition":"在海雾和旧案压力中推进的胆气。","positiveSignals":["果断"],"negativeSignals":["退缩"],"combatUseText":"压上突破口。","socialUseText":"在对峙中定调。","explorationUseText":"敢进陌生雾区。"},{"slotId":"axis_e","name":"旧约","definition":"维系旧友、信物与地方关系的能力。","positiveSignals":["守诺"],"negativeSignals":["疏离"],"combatUseText":"借同伴协同。","socialUseText":"建立信任交换。","explorationUseText":"从人情旧物找线索。"},{"slotId":"axis_f","name":"回澜","definition":"长线消耗中回稳节奏的能力。","positiveSignals":["回稳"],"negativeSignals":["紊乱"],"combatUseText":"久战不乱。","socialUseText":"不被情绪带偏。","explorationUseText":"远行中保有余力。"}]},"camp":{"name":"旧灯塔归舍","description":"海雾边缘的守灯人旧居。"}}"#,
|
||||
r#"{"name":"雾港归航","subtitle":"失灯旧案","summary":"守灯人与群岛议会围绕沉船旧案对峙。","tone":"海雾悬疑","playerGoal":"查清父亲沉船真相","templateWorldType":"WUXIA","majorFactions":["群岛议会","灯塔署"],"coreConflicts":["守灯塔的旧档案被人改写。"],"attributeSchema":{"slots":[{"name":"灯骨"},{"name":"潮步"},{"name":"灯识"},{"name":"雾魄"},{"name":"旧约"},{"name":"回澜"}]},"camp":{"name":"旧灯塔归舍","description":"海雾边缘的守灯人旧居。"}}"#,
|
||||
),
|
||||
llm_response(
|
||||
r#"{"playableNpcs":[{"name":"岑灯","title":"返乡守灯人","role":"主角代理","description":"追查旧案的人","visualDescription":"灰蓝旧灯披风压着海盐痕,腰侧挂旧海图筒和短灯杖。","actionDescription":"举灯照海图,短杖点地辨认潮声。","sceneVisualDescription":"旧灯塔回廊被海雾压低,墙上挂满潮湿航线图。","initialAffinity":24,"relationshipHooks":["旧案牵连"],"tags":["守灯人"]}]}"#,
|
||||
@@ -2595,6 +2526,16 @@ mod tests {
|
||||
.and_then(JsonValue::as_str),
|
||||
Some("灯骨")
|
||||
);
|
||||
assert_eq!(
|
||||
draft_profile
|
||||
.get("attributeSchema")
|
||||
.and_then(|schema| schema.get("slots"))
|
||||
.and_then(JsonValue::as_array)
|
||||
.and_then(|entries| entries.first())
|
||||
.and_then(JsonValue::as_object)
|
||||
.map(|entry| entry.contains_key("definition")),
|
||||
Some(false)
|
||||
);
|
||||
assert!(
|
||||
draft_profile
|
||||
.get("worldHook")
|
||||
|
||||
Reference in New Issue
Block a user