From 99bd77e18bfb4e4792dfda6175f7b9d894f7f020 Mon Sep 17 00:00:00 2001 From: Corback Date: Tue, 16 Jun 2026 08:25:59 +0000 Subject: [PATCH] fix: params page cfg=None + hot-reload config chaque jour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dashboard/app.py: load_sim_config() retourne None (pas {}) quand le fichier est absent — {} est falsy en Python, masquait le formulaire même quand la config était chargeable mais vide. None est explicitement distinguable. load_all_modes() charge toujours depuis sim_001.json (référence 5 modes) — sim_002 n'a qu'un seul mode dans son bloc 'modes', le tableau comparatif était vide pour S2. {% if cfg is not none %} dans le template au lieu de {% if cfg %} Message d'avertissement sous le bouton save : prise en compte au prochain jour Message d'erreur précis si fichier introuvable (path + hint mount Docker) /params/save: vérification if cfg is None run.py: Hot-reload config à chaque tick==0 (frontière de jour) : cfg.load(config_path, session_id=SESSION_ID) effective_mode mis à jour depuis la config rechargée tick_sleep recalculé (TICK_SLEEP_SEC env var prime toujours) → Changer mode/drain/encounter via dashboard prend effet le jour suivant sans redémarrer le process --- dashboard/app.py | 33 +++++++++++++++++++++++++-------- src/engine/run.py | 6 +++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/dashboard/app.py b/dashboard/app.py index c37147c..10e3bcf 100644 --- a/dashboard/app.py +++ b/dashboard/app.py @@ -47,13 +47,21 @@ def execute(sql, params=None): finally: conn.close() -def load_sim_config(session_id: int) -> dict: +_REFERENCE_CONFIG_ID = 1 # sim_001.json = référence pour la liste des modes + +def load_sim_config(session_id: int) -> dict | None: + """Retourne le cfg JSON ou None si introuvable (None est falsy ET distinguable de {}).""" path = os.path.join(SIM_CONFIGS_DIR, f"sim_{session_id:03d}.json") try: with open(path) as f: return json.load(f) - except Exception: - return {} + except Exception as e: + return None + +def load_all_modes() -> dict: + """Charge les modes depuis sim_001.json (référence complète des 5 modes).""" + cfg = load_sim_config(_REFERENCE_CONFIG_ID) or {} + return cfg.get("modes", {}) def save_sim_config(session_id: int, cfg: dict): path = os.path.join(SIM_CONFIGS_DIR, f"sim_{session_id:03d}.json") @@ -407,7 +415,7 @@ if (el) {

⚙ CONFIG SIM_{{ '%03d' % current_sid }}.JSON

- {% if cfg %} + {% if cfg is not none %}

GÉNÉRAL

@@ -466,8 +474,17 @@ if (el) {
+

+ ⚠ Prise en compte au prochain jour (J{{ (session.current_day or 0) + 1 }}). + Pour effet immédiat : STOP → relancer via terminal. +

{% else %} -

Fichier sim_{{ '%03d' % current_sid }}.json introuvable dans {{ sim_configs_dir }}

+

+ Fichier sim_{{ '%03d' % current_sid }}.json introuvable dans {{ sim_configs_dir }} +

+

+ Vérifier le mount Docker : /home/ubuntu/fallout-venice/src/config → /app/src/config +

{% endif %}
@@ -673,7 +690,7 @@ def params(): sid = int(request.args.get("sid", all_sessions[-1]["id"] if all_sessions else 1)) session = query_one("SELECT * FROM sessions WHERE id = %s", (sid,)) cfg = load_sim_config(sid) - modes = cfg.get("modes", {}) + modes = load_all_modes() # toujours les 5 modes depuis sim_001 (référence) flash_msg = request.args.get("msg") flash_ok = request.args.get("ok", "1") == "1" return render_template_string(TEMPLATE, @@ -697,8 +714,8 @@ def params(): def params_save(): sid = int(request.args.get("sid", 1)) cfg = load_sim_config(sid) - if not cfg: - return redirect(url_for("params", sid=sid, msg="Fichier config introuvable", ok=0)) + if cfg is None: + return redirect(url_for("params", sid=sid, msg=f"Fichier sim_{sid:03d}.json introuvable dans {SIM_CONFIGS_DIR}", ok=0)) f = request.form diff --git a/src/engine/run.py b/src/engine/run.py index c27b6fe..947bff2 100644 --- a/src/engine/run.py +++ b/src/engine/run.py @@ -77,8 +77,12 @@ def run(config_path: str | None = None): day, current_tick = tick_engine.next_tick(day, current_tick) - # Réinit world_state au début de chaque nouveau jour + # Début d'un nouveau jour : hot-reload config depuis le JSON (permet les changements dashboard) if current_tick == 0: + cfg.load(config_path, session_id=SESSION_ID) + effective_mode = cfg.mode() or db_mode + tick_sleep = float(os.getenv("TICK_SLEEP_SEC", + cfg.get("tick", {}).get("tick_sleep_sec", tick_sleep))) _init_world_state(SESSION_ID, day) except KeyboardInterrupt: