import os from ..connection import connect from ..game_dir import game_dir from ..slugify import slugify from .project_slug import build_slug def create_game(name: str, owner_folder: str | None = None, project_slug_override: str | None = None) -> str: """Feature 1 : crée le dossier du jeu, ses fichiers index.html/css/js reliés entre eux, et sa base de données dédiée (nom du jeu en méta). owner_folder : dossier PROPRIÉTAIRE (voir db/games/project_slug.py — structure de dossiers par utilisateur), l'id du compte en pratique (voir routes/games/games_new.py — opaque, jamais dérivé de l'email) — le slug final composé "_" résout vers un vrai chemin imbriqué projects///. Omis (None) : repli sur l'ancien comportement plat (slug à un seul segment, projects//) — utile pour les tests de la couche données qui n'ont pas de compte utilisateur à représenter. project_slug_override : impose le nom du dossier PROJET au lieu de le dériver de `name` — utilisé par l'inscription (auth/, voir routes/onboarding/) pour que le tout premier projet d'un compte porte un nom de dossier prévisible. Le suffixe d'unicité (-2/-3...) ne compare que parmi les projets déjà présents dans CE `owner_folder` (deux comptes différents peuvent donc avoir chacun un projet nommé pareil, sans collision). Un projet n'a plus de "type" propre (voir game_engine/screens_repo/ ensure_schema.py — fusion des moteurs, "document"/"jeu_2d" est désormais une propriété PAR ÉCRAN) : un projet fraîchement créé n'a par défaut aucun écran, c'est à l'appelant d'en créer un premier avec le "kind" voulu (voir game_engine.create_screen).""" project_part = slugify(project_slug_override) if project_slug_override else slugify(name) base = project_part n = 2 while os.path.isdir(game_dir(build_slug(owner_folder, base) if owner_folder else base)): base = f"{project_part}-{n}" n += 1 project_part = base slug = build_slug(owner_folder, project_part) if owner_folder else project_part os.makedirs(game_dir(slug), exist_ok=True) index_html = f""" {name}

{name}

Squelette généré par le moteur Forge — à remplir au fur et à mesure des fonctionnalités du jeu.

""" index_css = """body { font-family: system-ui, sans-serif; margin: 40px; color: #222; } """ index_js = """// index.js — point d'entrée du jeu, généré par le moteur Forge. console.log("Jeu chargé."); """ with open(os.path.join(game_dir(slug), "index.html"), "w", encoding="utf-8") as f: f.write(index_html) with open(os.path.join(game_dir(slug), "index.css"), "w", encoding="utf-8") as f: f.write(index_css) with open(os.path.join(game_dir(slug), "index.js"), "w", encoding="utf-8") as f: f.write(index_js) conn = connect(slug) conn.executescript( """ CREATE TABLE _meta (key TEXT PRIMARY KEY, value TEXT); CREATE TABLE _definitions ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, table_name TEXT NOT NULL UNIQUE, created_at TEXT DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE _fields ( id INTEGER PRIMARY KEY AUTOINCREMENT, definition_id INTEGER NOT NULL REFERENCES _definitions(id) ON DELETE CASCADE, name TEXT NOT NULL, type TEXT NOT NULL, relation_definition_id INTEGER REFERENCES _definitions(id), required INTEGER NOT NULL DEFAULT 0, position INTEGER NOT NULL DEFAULT 0 ); """ ) conn.execute("INSERT INTO _meta (key, value) VALUES ('name', ?)", (name,)) conn.commit() conn.close() return slug