Extract character utility nodes

This commit is contained in:
2026-06-26 23:05:03 +02:00
parent efe13beb79
commit d01de98516
5 changed files with 994 additions and 779 deletions
+165
View File
@@ -1848,6 +1848,170 @@ def smoke_node_route_config_registration() -> None:
_expect("weighted cast:" in bias_a[3], "Cast Bias summary lost weighted cast label")
def smoke_node_character_registration() -> None:
required_nodes = [
"SxCPHairLength",
"SxCPHairColor",
"SxCPHairStyle",
"SxCPCharacterAgeRange",
"SxCPCharacterBodyPool",
"SxCPWomanBodyPool",
"SxCPManBodyPool",
"SxCPEyeColorPool",
"SxCPCharacterClothing",
"SxCPCharacterManualDetails",
"SxCPWomanSlot",
"SxCPManSlot",
"SxCPCharacterSlot",
"SxCPCharacterProfileSave",
"SxCPCharacterProfileLoad",
]
for node_name in required_nodes:
_expect(node_name in sxcp_nodes.NODE_CLASS_MAPPINGS, f"{node_name} missing from node registry")
_expect(node_name in sxcp_nodes.NODE_DISPLAY_NAME_MAPPINGS, f"{node_name} missing from display registry")
woman_slot_node = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPWomanSlot"]
woman_slot_inputs = woman_slot_node.INPUT_TYPES().get("required") or {}
_expect("slot_seed" in woman_slot_inputs, "Woman Slot lost slot_seed input")
_expect("tooltip" in woman_slot_inputs["slot_seed"][1], "Woman Slot tooltip injection missing")
hair_config, hair_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPHairColor"]().build(
"replace_axis",
"",
include_blonde=True,
)
parsed_hair = json.loads(hair_config)
_expect(parsed_hair.get("colors") == ["blonde"], "Hair Color did not output selected blonde pool")
_expect("colors=blonde" in hair_summary, "Hair Color summary changed unexpectedly")
age_config, age_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPCharacterAgeRange"]().build(
"replace_axis",
25,
27,
)
parsed_age = json.loads(age_config)
_expect(parsed_age.get("ages") == ["25-year-old adult", "26-year-old adult", "27-year-old adult"], "Age Range output changed")
_expect("25-year-old adult" in age_summary, "Age Range summary lost selected ages")
body_config, _body_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPWomanBodyPool"]().build(
"replace_axis",
"",
include_curvy=True,
)
_expect(json.loads(body_config).get("bodies") == ["curvy"], "Woman Body Pool did not output selected body")
eye_config, _eye_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPEyeColorPool"]().build(
"replace_axis",
"",
include_blue=True,
)
_expect(json.loads(eye_config).get("eyes") == ["blue"], "Eye Color Pool did not output selected eye color")
clothing_config, clothing_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPCharacterClothing"]().build(
"replace_axis",
"lingerie_tease",
"fully_nude",
"",
"",
)
parsed_clothing = json.loads(clothing_config)
_expect(parsed_clothing.get("softcore_outfits"), "Character Clothing lost softcore outfit pool")
_expect(parsed_clothing.get("hardcore_clothing") == ["fully nude"], "Character Clothing lost hardcore clothing state")
_expect("soft_outfits=" in clothing_summary, "Character Clothing summary lost outfit count")
manual_config, manual_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPCharacterManualDetails"]().build(
"merge_nonempty",
"31-year-old adult",
"curvy",
"custom body phrase",
"warm skin",
"short blonde hair",
"blue eyes",
"red dress",
"fully nude",
)
parsed_manual = json.loads(manual_config)
_expect(parsed_manual.get("manual_age") == "31-year-old adult", "Manual Details lost manual_age")
_expect(parsed_manual.get("softcore_outfit") == "red dress", "Manual Details lost softcore outfit")
_expect("manual_age=31-year-old adult" in manual_summary, "Manual Details summary changed unexpectedly")
cast, slot, slot_summary, slot_status = woman_slot_node().build(
True,
"A",
123,
"25-year-old adult",
"western_european",
"balanced",
"curvy",
"full",
True,
0.5,
0.4,
0.8,
"",
"",
"",
hair_config,
"",
)
parsed_slot = json.loads(slot)
_expect(parsed_slot.get("subject_type") == "woman", "Woman Slot output lost subject type")
_expect(parsed_slot.get("slot_seed") == 123, "Woman Slot output lost slot seed")
_expect("Woman A" in slot_summary, "Woman Slot summary lost label")
_expect("1 slot(s)" in slot_status, "Woman Slot status lost cast count")
_expect(json.loads(cast).get("slots"), "Woman Slot did not output chained cast JSON")
man_cast, man_slot, _man_summary, _man_status = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPManSlot"]().build(
True,
"A",
124,
"40-year-old adult",
"western_european",
"average",
"compact",
True,
0.3,
"pov",
0.2,
0.7,
cast,
"",
"",
"",
"",
)
_expect(json.loads(man_slot).get("presence_mode") == "pov", "Man Slot output lost POV presence mode")
_expect(len(json.loads(man_cast).get("slots") or []) == 2, "Man Slot did not append to incoming cast")
save_result = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPCharacterProfileSave"]().build(
"smoke_profile",
"character_slot",
"woman",
"",
"",
"",
"",
"",
"",
"",
False,
character_slot=slot,
)
saved_profile = save_result["result"][0]
_expect(save_result["result"][2] == "smoke_profile", "Profile Save lost profile name")
_expect(save_result["result"][4] == "not_saved", "Profile Save should not write when save_now is false")
loaded_profile = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPCharacterProfileLoad"]().build(
True,
"manual",
"",
False,
False,
fallback_profile_json=saved_profile,
)
_expect(loaded_profile[4] == "fallback", "Profile Load should consume fallback profile JSON")
_expect(json.loads(loaded_profile[0]).get("profile_type") == "character", "Profile Load returned wrong profile type")
def smoke_node_profile_filter_registration() -> None:
required_nodes = [
"SxCPGenerationProfile",
@@ -1955,6 +2119,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
("node_utility_registration", smoke_node_utility_registration),
("node_camera_registration", smoke_node_camera_registration),
("node_route_config_registration", smoke_node_route_config_registration),
("node_character_registration", smoke_node_character_registration),
("node_profile_filter_registration", smoke_node_profile_filter_registration),
]