Initial scaffold: Nakama backend, Godot client, content schema
Sets up the Step 1 (Project Foundation) and Step 2 (Content Schemas) scaffold from the implementation sequence. Includes Docker Compose stack, Nakama TypeScript module stubs, PostgreSQL migration, Godot 4 project shell with scene stubs and NakamaClient singleton, YAML content schemas for all entity types, and example data for 3 characters, 2 jobs, and all 7 core resources. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
fb00954954
37 changed files with 2730 additions and 0 deletions
127
tools/validate_content.py
Normal file
127
tools/validate_content.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/env python3
|
||||
"""validate_content.py — Validate all content YAML files against their schemas.
|
||||
|
||||
Usage:
|
||||
python3 tools/validate_content.py
|
||||
|
||||
Requires:
|
||||
pip install pyyaml jsonschema
|
||||
|
||||
Exit codes:
|
||||
0 — all files valid
|
||||
1 — one or more validation errors
|
||||
"""
|
||||
|
||||
import sys
|
||||
import pathlib
|
||||
import yaml
|
||||
import json
|
||||
|
||||
try:
|
||||
import jsonschema
|
||||
except ImportError:
|
||||
print("ERROR: jsonschema not installed. Run: pip install pyyaml jsonschema")
|
||||
sys.exit(1)
|
||||
|
||||
CONTENT_ROOT = pathlib.Path(__file__).parent.parent / "content"
|
||||
SCHEMA_DIR = CONTENT_ROOT / "schema"
|
||||
DATA_DIR = CONTENT_ROOT / "data"
|
||||
|
||||
# Map schema file names to data subdirectories
|
||||
SCHEMA_DATA_MAP = {
|
||||
"character.yaml": DATA_DIR / "characters",
|
||||
"job.yaml": DATA_DIR / "jobs",
|
||||
"resource.yaml": DATA_DIR / "resources",
|
||||
"banner.yaml": DATA_DIR / "banners",
|
||||
"event.yaml": DATA_DIR / "events",
|
||||
}
|
||||
|
||||
errors_found = 0
|
||||
|
||||
|
||||
def load_yaml(path: pathlib.Path) -> list[dict]:
|
||||
"""Load a YAML file, returning a list of documents (multi-doc files are split)."""
|
||||
with open(path) as f:
|
||||
docs = list(yaml.safe_load_all(f))
|
||||
return [d for d in docs if d is not None]
|
||||
|
||||
|
||||
def yaml_schema_to_jsonschema(schema_doc: dict) -> dict:
|
||||
"""
|
||||
Our schema files are JSON-Schema-like YAML. Extract the JSON Schema portion.
|
||||
We strip the custom '$schema' key and pass the rest to jsonschema.
|
||||
"""
|
||||
s = dict(schema_doc)
|
||||
s.pop("$schema", None)
|
||||
return s
|
||||
|
||||
|
||||
def validate_directory(schema_path: pathlib.Path, data_dir: pathlib.Path) -> int:
|
||||
"""Validate all YAML files in data_dir against schema_path. Returns error count."""
|
||||
global errors_found
|
||||
|
||||
if not data_dir.exists():
|
||||
print(f" [SKIP] Directory not found: {data_dir}")
|
||||
return 0
|
||||
|
||||
schema_docs = load_yaml(schema_path)
|
||||
if not schema_docs:
|
||||
print(f" [WARN] Empty schema: {schema_path.name}")
|
||||
return 0
|
||||
|
||||
schema = yaml_schema_to_jsonschema(schema_docs[0])
|
||||
|
||||
local_errors = 0
|
||||
yaml_files = sorted(data_dir.glob("*.yaml"))
|
||||
|
||||
if not yaml_files:
|
||||
print(f" [INFO] No data files in {data_dir.name}/")
|
||||
return 0
|
||||
|
||||
for data_file in yaml_files:
|
||||
docs = load_yaml(data_file)
|
||||
for i, doc in enumerate(docs):
|
||||
try:
|
||||
# jsonschema uses JSON Schema draft-07 by default
|
||||
jsonschema.validate(instance=doc, schema=schema)
|
||||
except jsonschema.ValidationError as e:
|
||||
print(f" [FAIL] {data_file.name} (doc {i+1}): {e.message}")
|
||||
local_errors += 1
|
||||
except jsonschema.SchemaError as e:
|
||||
print(f" [SCHEMA ERROR] {schema_path.name}: {e.message}")
|
||||
local_errors += 1
|
||||
break
|
||||
|
||||
if local_errors == 0:
|
||||
pass # silent success; only print failures
|
||||
|
||||
if local_errors == 0:
|
||||
print(f" [OK] {data_dir.name}/ — {len(yaml_files)} file(s) valid")
|
||||
|
||||
return local_errors
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("Xyvera content validation\n")
|
||||
|
||||
for schema_name, data_dir in SCHEMA_DATA_MAP.items():
|
||||
schema_path = SCHEMA_DIR / schema_name
|
||||
if not schema_path.exists():
|
||||
print(f" [WARN] Schema not found: {schema_name}")
|
||||
continue
|
||||
|
||||
print(f"Schema: {schema_name}")
|
||||
errs = validate_directory(schema_path, data_dir)
|
||||
errors_found += errs
|
||||
|
||||
print()
|
||||
if errors_found:
|
||||
print(f"FAILED — {errors_found} validation error(s) found.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("All content valid.")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue