d2r_chargen_validate
Validate a Diablo II Resurrected character YAML file by name, with optional dry-run binary build and scanner pass for modding workflows.
Instructions
Validate a character YAML and optionally run a dry-run binary build.
Args: name: Character name (resolves to chars/.yaml). yaml_only: Skip the dry-run binary build + scanner pass.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| yaml_only | No |
Implementation Reference
- d2r_mcp/server.py:182-190 (registration)MCP tool registration for d2r_chargen_validate as async function decorated with @mcp.tool(), delegates to _chargen_validate (aliased from d2r_mcp.chargen.validate).
@mcp.tool() async def d2r_chargen_validate(name: str, yaml_only: bool = False) -> dict: """Validate a character YAML and optionally run a dry-run binary build. Args: name: Character name (resolves to chars/<name>.yaml). yaml_only: Skip the dry-run binary build + scanner pass. """ return _chargen_validate(name, yaml_only=yaml_only) - d2r_mcp/chargen.py:31-132 (handler)Core handler: validates character YAML (loads via load_character_yaml, validates via validate_char_def), optionally builds a temp .d2s binary, runs the scanner (scan_character_data), and returns structured results with yaml_valid, binary_valid, item_count, and warnings.
def validate(name: str, yaml_only: bool = False) -> dict: """Validate a character YAML, optionally running a dry-run binary build. Args: name: Character name (resolves to chars/<name>.yaml). yaml_only: If True, only validate YAML schema. If False (default), also build to a temp .d2s and run the scanner — same discipline as `python3 -m d2r_chargen validate <name>`. Returns: On ok: {character, yaml_valid, binary_valid (bool or None if yaml_only), item_count, warnings}. On error: error.type in {not_found, yaml_validation_failed, scanner_failed, build_exception}. """ from d2r_chargen.character import load_character_yaml, validate_char_def yaml_path = os.path.join(_chars_dir(), f"{name}.yaml") if not os.path.exists(yaml_path): return error("not_found", f"no character YAML at {yaml_path}") try: char_def = load_character_yaml(yaml_path) validate_char_def(char_def) except Exception as ex: return error( "yaml_validation_failed", f"{type(ex).__name__}: {ex}", character=name, ) if yaml_only: return ok(character=name, yaml_valid=True, binary_valid=None) # Binary validation: mirror cmd_validate in d2r_chargen/cli.py import shutil, struct, tempfile from d2r_chargen.character import build_all_items from d2r_chargen.save import ( set_character_stats, set_skills, rebuild_items, calc_checksum, ) from d2r_chargen.resolve import resolve_skills from d2r_chargen.scanner import scan_character_data from d2r_chargen.config import SAVES try: all_items = build_all_items(char_def) except Exception as ex: return error("build_exception", f"{type(ex).__name__}: {ex}", character=name) template_path = os.path.join( os.path.dirname(__file__), "..", "d2r_chargen", "data", "template.d2s" ) existing = os.path.join(SAVES, f"{char_def['name']}.d2s") if os.path.exists(existing): template_path = existing with tempfile.NamedTemporaryFile(suffix=".d2s", delete=False) as tmp: tmp_path = tmp.name try: shutil.copy2(template_path, tmp_path) data = bytearray(open(tmp_path, "rb").read()) skill_array = resolve_skills(char_def["class"], char_def.get("skills", {})) stats = char_def["stats"] data = set_character_stats( data, stats["strength"], stats["dexterity"], stats["vitality"], stats["energy"], level=char_def.get("level", 99), char_class=char_def["class"], skill_points_spent=sum(skill_array), ) data = set_skills(data, skill_array) struct.pack_into("<I", data, 8, len(data)) data[12:16] = b"\x00\x00\x00\x00" struct.pack_into("<I", data, 12, calc_checksum(data)) with open(tmp_path, "wb") as f: f.write(data) item_bytes_list = [b for _, b in all_items] result_data = rebuild_items(tmp_path, item_bytes_list, []) with open(tmp_path, "wb") as f: f.write(result_data) scan = scan_character_data(tmp_path) finally: if os.path.exists(tmp_path): os.unlink(tmp_path) if scan["errors"]: return error( "scanner_failed", f"{len(scan['errors'])} hard error(s) in dry-run build", character=name, yaml_valid=True, binary_valid=False, scanner_errors=scan["errors"], scanner_warnings=scan["warnings"], ) return ok( character=name, yaml_valid=True, binary_valid=True, item_count=scan["item_count"], warnings=scan["warnings"], ) - d2r_mcp/server.py:182-190 (schema)Schema definition via the function signature: accepts 'name' (str) and optional 'yaml_only' (bool, default False), returns dict.
@mcp.tool() async def d2r_chargen_validate(name: str, yaml_only: bool = False) -> dict: """Validate a character YAML and optionally run a dry-run binary build. Args: name: Character name (resolves to chars/<name>.yaml). yaml_only: Skip the dry-run binary build + scanner pass. """ return _chargen_validate(name, yaml_only=yaml_only)