Enrichit les declencheurs/actions de scene (clic/survol/affichage, surbrillance/video/son/visibilite/indication/attendre) et fiabilise la pose d'un fond/decor importe
- Ajoute clic/survol/affichage-ecran comme declencheurs, et surbrillance, video, son, visibilite, indication, attendre comme actions, utilisables aussi bien par l'editeur manuel (menu lateral Objets/Ecran) que par Ruby (IA), avec blocs deplacables/supprimables dans une chaine. - Corrige plusieurs variantes du bug "impossible de poser un objet hors du champ de la camera" (troncature du chainage d'actions a 4 maillons, fond importe pose a 128x128 au lieu de sa taille reelle, decalage du fond au vrai glisser-depose, redimensionnement manuel jamais propage au monde). - Ajoute un vrai glisser-depose depuis la galerie vers la scene, la gestion complete de "Mes assets" (sous-sections Fonds/Decors/Sons/ Videos, suppression, reclassement fond<->decor sans re-upload). - Ajoute l'upload de son (limite 3 min) et de video (MP4 uniquement, limite 5 min), avec validation de la duree reelle du fichier, et une replique audio optionnelle dans une bulle de dialogue. - Fixe la taille de pose d'un objet/decor importe a 200x200 avec une boite de collision de 150x150. - Filtre le selecteur de fichier des actions son/video par type reel. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b07b231a61
commit
559331f9cf
@@ -4,9 +4,18 @@ JSON (posée quand l'appelant envoie X-Requested-With: fetch) remplace le
|
||||
rechargement complet de page — sans ça, poser un objet "vidait" un instant
|
||||
l'éditeur de collision/quêtes (tout l'état JS repartait de zéro à chaque
|
||||
ajout)."""
|
||||
import io
|
||||
import struct
|
||||
|
||||
import auth
|
||||
import screens
|
||||
|
||||
|
||||
def _png_bytes(width, height):
|
||||
ihdr = struct.pack(">II", width, height) + b"\x08\x02\x00\x00\x00"
|
||||
return b"\x89PNG\r\n\x1a\n" + b"\x00\x00\x00\x0d" + b"IHDR" + ihdr + b"\x00\x00\x00\x00"
|
||||
|
||||
|
||||
def _create_jeu2d_game(client, tmp_game_slug_cleanup, name="pytest_add_ajax"):
|
||||
resp = client.post("/games/new", data={"name": name}, follow_redirects=False)
|
||||
slug = tmp_game_slug_cleanup(resp.headers["Location"].rstrip("/").split("/")[-1])
|
||||
@@ -31,6 +40,83 @@ def test_ajax_add_returns_json_instead_of_redirecting(client, tmp_game_slug_clea
|
||||
assert body["animations"]
|
||||
|
||||
|
||||
def test_ajax_add_with_drop_position_places_the_object_exactly_there(client, tmp_game_slug_cleanup):
|
||||
"""Vrai glisser-déposer (demande explicite : "n'importe où sur la
|
||||
scène") — x/y postés remplacent le défaut 100/100."""
|
||||
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||
resp = _add_ajax(client, slug, screen_id, kind="decor", x="300", y="220")
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert body["x"] == 300
|
||||
assert body["y"] == 220
|
||||
|
||||
|
||||
def test_ajax_add_with_drop_position_near_the_edge_is_clamped_into_the_camera(client, tmp_game_slug_cleanup):
|
||||
"""Un dépôt trop proche d'un bord ne doit jamais laisser l'objet
|
||||
déborder du cadre visible par la caméra une fois sa taille réelle
|
||||
connue (même esprit que ai/tools.py::_clamp_to_camera pour l'IA)."""
|
||||
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||
resp = _add_ajax(client, slug, screen_id, kind="decor", x="999999", y="999999")
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert body["x"] <= 960 - body["width"]
|
||||
assert body["y"] <= 540 - body["height"]
|
||||
|
||||
|
||||
# ---------- Fond importé ("Mes assets") posé à sa taille RÉELLE — bug :
|
||||
# "je ne peux pas poser un objet hors du champ de la caméra quand
|
||||
# j'utilise un fond de scène importé" (sans ça, l'image retombait
|
||||
# toujours sur 128×128, trop petite pour agrandir le "monde" au-delà de
|
||||
# la caméra nominale 960×540) ----------
|
||||
|
||||
def test_ajax_add_fond_ignores_the_drop_position_and_stays_anchored_at_the_origin(client, tmp_game_slug_cleanup):
|
||||
"""Bug corrigé ("décalage") : le vrai glisser-déposer envoie une
|
||||
position EXACTE même pour un fond — sans ce garde-fou, un fond
|
||||
déposé ailleurs qu'au coin haut-gauche restait décalé, laissant un
|
||||
bandeau de canevas vide visible entre le bord de la scène et
|
||||
l'image."""
|
||||
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||
resp = _add_ajax(client, slug, screen_id, kind="fond", x="450", y="300")
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert (body["x"], body["y"]) == (0, 0)
|
||||
|
||||
|
||||
def test_ajax_add_fond_from_user_asset_uses_the_real_image_dimensions(client, tmp_game_slug_cleanup):
|
||||
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||
with client.session_transaction() as sess:
|
||||
user_id = sess["user_id"]
|
||||
asset_id, _filename = auth.save_user_asset(
|
||||
user_id, _png_bytes(1920, 1080), ".png", original_name="ciel.png", source="upload", scene_kind="fond",
|
||||
)
|
||||
resp = _add_ajax(client, slug, screen_id, kind="fond", asset_id=str(asset_id))
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert body["width"] == 1920
|
||||
assert body["height"] == 1080
|
||||
|
||||
|
||||
# ---------- Redimensionnement manuel d'un "fond" — la route /geometry
|
||||
# doit renvoyer le "monde" recalculé pour que scene-editor.js puisse
|
||||
# rafraîchir SCENE_WIDTH/SCENE_HEIGHT tout de suite (même bug que
|
||||
# ci-dessus, mais via le redimensionnement à la souris plutôt qu'un
|
||||
# import — sans ça, l'agrandissement n'était visible qu'après un
|
||||
# rechargement complet de la page) ----------
|
||||
|
||||
def test_geometry_route_returns_the_recomputed_world_size_for_an_enlarged_fond(client, tmp_game_slug_cleanup):
|
||||
slug, screen_id = _create_jeu2d_game(client, tmp_game_slug_cleanup)
|
||||
resp = _add_ajax(client, slug, screen_id, kind="fond")
|
||||
obj_id = resp.get_json()["id"]
|
||||
geo = client.post(
|
||||
f"/game/{slug}/scene-objects/{obj_id}/geometry",
|
||||
json={"x": 0, "y": 0, "width": 2000, "height": 1200},
|
||||
)
|
||||
assert geo.status_code == 200
|
||||
body = geo.get_json()
|
||||
assert body["world_width"] >= 2000
|
||||
assert body["world_height"] >= 1200
|
||||
|
||||
|
||||
def test_non_ajax_add_still_redirects(client, tmp_game_slug_cleanup):
|
||||
"""Secours pour tout appelant non-JS (aucun connu, mais gratuit à garder) —
|
||||
comportement inchangé : redirection classique, sans le header AJAX."""
|
||||
|
||||
Reference in New Issue
Block a user