Files
Forge-Engine/routes/scenes/scene_object_add.py
T
williamandClaude Sonnet 5 b07b231a61
Build and deploy / test-python (push) Successful in 12m24s
Build and deploy / test-js (push) Successful in 1m9s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Ajoute l'assistant IA "Ruby" (Claude + Scenario) et corrige plusieurs bugs de la scène
Intègre un chat IA capable de manipuler la scène via les mêmes fonctions
que l'éditeur manuel (objets, variables, déclencheurs, images générées),
avec conversations multiples par écran façon Claude. Corrige au passage
le rafraîchissement pjax hors-ordre, l'onglet IA/déclencheurs vide après
sélection d'un objet, la comparaison de booléens dans les conditions, et
le blocage du glisser-déposer hors du cadre caméra après un redimensionnement
de fond par l'IA.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 19:40:31 +02:00

68 lines
3.6 KiB
Python

from flask import g, request, redirect, url_for, jsonify, abort
import auth
import screens
from core.flask_app import app
from core.sprite_gate import forbid_admin_only_character, forbid_admin_only_background
@app.route("/game/<slug>/screens/<int:screen_id>/scene-objects/add", methods=["POST"])
def scene_object_add(slug, screen_id):
"""Pose un nouvel objet sur la scène — mirror de routes/elements/
element_add.py, mais pour _scene_objects (voir screens/scenes/
add_scene_object.py).
Appelée en AJAX (voir addSceneObject(), static/js/scenes/scene-editor.js)
plutôt qu'en soumission de formulaire classique — sans ça, poser un
objet rechargeait TOUTE la page : perceptible comme un "vidage" de
l'éditeur de collision/quêtes le temps du rechargement, et perdait tout
état JS en cours (modale ouverte, etc.). Répond en JSON avec de quoi
ajouter l'objet au canevas SANS recharger — jamais sélectionné/ouvert
dans le panneau de propriétés pour autant (ça, voir
onSceneObjectMouseDown, reste un rechargement pour l'instant). La liste
"🧩 Collision" n'est PAS incluse ici : addSceneObject() la redemande
ensuite à routes/scenes/scene_collision_rule_objects.py (même endpoint
que pour un changement de rôle/nom, ou une suppression) plutôt que de
dupliquer ici la logique de build_collision_rule_objects()."""
kind = request.form.get("kind", "personnage")
forge_character = request.form.get("forge_character")
background_slug = request.form.get("background_slug")
asset_id = request.form.get("asset_id", type=int)
if forge_character:
forbid_admin_only_character(forge_character)
if background_slug:
forbid_admin_only_background(background_slug)
image_url = None
if asset_id:
# "Mes assets" (voir auth/user_assets_dir.py) : isolation stricte
# par propriétaire, même esprit que les projets (core/auth_guard.py)
# — jamais poser l'asset d'un autre compte, même en devinant son id.
asset = auth.get_user_asset(asset_id)
if not asset or asset["user_id"] != g.current_user["id"]:
abort(403)
image_url = url_for("serve_user_asset", user_id=asset["user_id"], filename=asset["filename"])
new_id = screens.add_scene_object(
slug, screen_id, kind=kind, forge_character=forge_character,
background_slug=background_slug, image_url=image_url,
)
if request.headers.get("X-Requested-With") == "fetch":
obj = screens.get_scene_object(slug, new_id)
return jsonify({
"id": new_id, "kind": obj["kind"],
"x": obj["x"], "y": obj["y"], "width": obj["width"], "height": obj["height"],
"rendered_html": screens.render_scene_object(obj),
# Relance l'aperçu animé tout de suite (voir personnage-preview.js
# ::restartPersonnageIdlePreview) — sans ça, un personnage
# fraîchement posé restait figé sur sa première frame jusqu'au
# prochain rechargement de page (qui n'arrive plus jamais, voir
# addSceneObject() côté JS).
"animations": screens.resolve_personnage_animations(obj) if obj["kind"] == "personnage" else None,
})
# Même route que l'éditeur document (/game/<slug>/screens/<id>/edit,
# endpoint "screen_edit") — c'est CE dispatcher qui bascule vers la
# vue de scène selon game_type, voir routes/screens/screen_edit.py.
# Conservé pour tout appelant non-JS (aucun connu actuellement, mais
# ne coûte rien à garder en secours).
return redirect(url_for("screen_edit", slug=slug, screen_id=screen_id, selected=new_id))