diff --git a/docs/FALUKANT_PRODUCTION_CERTIFICATE.md b/docs/FALUKANT_PRODUCTION_CERTIFICATE.md index 478787c..90c84c8 100644 --- a/docs/FALUKANT_PRODUCTION_CERTIFICATE.md +++ b/docs/FALUKANT_PRODUCTION_CERTIFICATE.md @@ -1,6 +1,6 @@ # Falukant: Produktionszertifikate (Daemon) -Die Zertifikatslogik läuft im **24h-Daily-Tick** von `FalukantFamilyWorker` (`run_iteration`), **nicht** in einem eigenen Worker-Thread. Sie ist von der **Familien-Migration** entkoppelt: Schuldturm + Zertifikat laufen **immer** im Daily-Intervall; Liebhaber/Ehe/Monatslogik nur, wenn `QUERY_FAMILY_SCHEMA_READY` (Spalte `relationship_state.last_daily_processed_at`) erfüllt ist. Sie schreibt `falukant_user.certificate` fort (max. **+1** pro Tag, keine normale Herabstufung außer Bankrott / Erbfolge). +Die Zertifikatslogik läuft im **FalukantFamilyWorker** (`run_iteration`) **etwa 1× pro Minute** (`CERTIFICATE_RECALC_INTERVAL`), **nicht** in einem eigenen Worker-Thread. Der **24h-Daily-Block** enthält weiter Schuldturm und (bei Schema) Liebhaber/Ehe/Monatslogik — Zertifikat ist davon **getrennt**. Sie schreibt `falukant_user.certificate` fort (max. **+1** pro erfolgreicher Prüfung, keine normale Herabstufung außer Bankrott / Erbfolge). Implementierung: `src/worker/falukant_certificate.rs` (`run_daily`). diff --git a/docs/FALUKANT_UI_WEBSOCKET.md b/docs/FALUKANT_UI_WEBSOCKET.md index 23b67ce..5575f52 100644 --- a/docs/FALUKANT_UI_WEBSOCKET.md +++ b/docs/FALUKANT_UI_WEBSOCKET.md @@ -12,7 +12,7 @@ Dieses Dokument beschreibt die **Nachrichten**, die der **YpDaemon** (`FalukantF |---------|----------------|----------------------| | `falukantUpdateFamily` | `user_id`, `reason` | Gezielter Refresh Familie/Liebe/Geld je nach `reason` | | `falukantUpdateStatus` | `user_id` | Allgemeiner Status-/Spielstand-Refresh (wie bisher) | -| `falukantUpdateProductionCertificate` | `user_id`, `reason`, `old_certificate`, `new_certificate` | Produkte / Produktions-UI / Zertifikat neu laden (nach Daily-Recalc oder Bankrott) | +| `falukantUpdateProductionCertificate` | `user_id`, `reason`, `old_certificate`, `new_certificate` | Produkte / Produktions-UI / Zertifikat neu laden (nach Recalc, ca. 1×/Min., oder Bankrott) | | `children_update` | `user_id` | Kinderliste / FamilyView aktualisieren | | `falukant_family_scandal_hint` | `relationship_id` | Optional: Toast, Log – **kein** `user_id` (siehe unten) | | `falukantUpdateChurch` | `user_id`, `reason` | Kirchenämter: Bewerbungen, Ernennungen (`PoliticsWorker`) | diff --git a/src/worker/falukant_certificate.rs b/src/worker/falukant_certificate.rs index 6d858c6..a6cab7c 100644 --- a/src/worker/falukant_certificate.rs +++ b/src/worker/falukant_certificate.rs @@ -1,5 +1,6 @@ -//! Produktionszertifikat: tägliche Neuberechnung von `falukant_user.certificate` im **FalukantFamilyWorker**-24h-Tick -//! (`run_iteration`, unabhängig von der Familien-Schema-Migration; nicht in einem eigenen Worker-Thread). Spec: `docs/FALUKANT_PRODUCTION_CERTIFICATE.md` und +//! Produktionszertifikat: regelmäßige Neuberechnung von `falukant_user.certificate` im **FalukantFamilyWorker** +//! (Standard: **1× pro Minute**, `CERTIFICATE_RECALC_INTERVAL` in `falukant_family.rs`; unabhängig von der Familien-Schema-Migration). +//! Spec: `docs/FALUKANT_PRODUCTION_CERTIFICATE.md` und //! „Falukant: Produktionszertifikate – Fach- und Integrationsspezifikation“. use crate::db::{DbError, Row}; @@ -14,7 +15,7 @@ use crate::worker::sql::{ /// Wenn `money` darunter liegt, gilt der Spieler als bankrott → Zertifikat auf Stufe 1 (Spec §4.7). const BANKRUPTCY_MONEY_THRESHOLD: f64 = -5000.0; -/// Einmal pro Daily-Tick (`FalukantFamilyWorker::process_daily`). +/// Periodischer Tick (`FalukantFamilyWorker::run_iteration`, Standard: 1×/Minute). pub fn run_daily(base: &BaseWorker, broker: &MessageBroker) -> Result<(), DbError> { let pool = &base.pool; let mut conn = pool diff --git a/src/worker/falukant_family.rs b/src/worker/falukant_family.rs index 324eb8a..3632e3a 100644 --- a/src/worker/falukant_family.rs +++ b/src/worker/falukant_family.rs @@ -36,6 +36,8 @@ use crate::message_broker::MessageBroker; const DAILY_INTERVAL: Duration = Duration::from_secs(24 * 3600); /// Wie `DAILY_INTERVAL`: 1 Spieljahr = 1 Kalendertag — Monats-Stempel/„monthly“-Batch pro Spieltag, nicht alle 30 echten Tage. const MONTHLY_INTERVAL: Duration = DAILY_INTERVAL; +/// Produktionszertifikat: Aufstieg/Herabstufung gegen Mindestwerte (nicht nur 1×/Tag). +const CERTIFICATE_RECALC_INTERVAL: Duration = Duration::from_secs(60); /// 12 Monatsticke pro Spieltag (24 h = 1 Spieljahr); 2 h = 1 Spielmonat (Liebschaft + Dienerschaft). const GAME_MONTH_SLICE_INTERVAL: Duration = Duration::from_secs(2 * 3600); @@ -47,6 +49,7 @@ pub struct FalukantFamilyWorker { last_monthly: Option, /// Gemeinsamer Tick für Liebschafts-Raten + Dienerschaft (Monatstick ≈ 2 h). last_game_month_slice: Option, + last_certificate_recalc: Option, schema_ready: bool, /// Migration `004_falukant_servants_daemon.sql` (Dienerschaft-Ticks). servants_schema_ready: bool, @@ -63,6 +66,7 @@ impl FalukantFamilyWorker { last_daily: None, last_monthly: None, last_game_month_slice: None, + last_certificate_recalc: None, schema_ready: false, servants_schema_ready: false, lover_installment_schema_ready: false, @@ -79,13 +83,17 @@ impl FalukantFamilyWorker { } } + if Self::should_run(self.last_certificate_recalc, now, CERTIFICATE_RECALC_INTERVAL) { + if let Err(e) = super::falukant_certificate::run_daily(&self.base, &self.base.broker) { + eprintln!("[FalukantFamilyWorker] falukant_certificate::run_daily: {e}"); + } + self.last_certificate_recalc = Some(now); + } + if Self::should_run(self.last_daily, now, DAILY_INTERVAL) { if let Err(e) = super::falukant_debtors::run_daily(&self.base, &self.base.broker) { eprintln!("[FalukantFamilyWorker] falukant_debtors::run_daily: {e}"); } - if let Err(e) = super::falukant_certificate::run_daily(&self.base, &self.base.broker) { - eprintln!("[FalukantFamilyWorker] falukant_certificate::run_daily: {e}"); - } if self.schema_ready { if let Err(e) = self.process_daily() { eprintln!("[FalukantFamilyWorker] process_daily: {e}");