Update version and edition in Cargo.toml; enhance breakup risk management in FalukantFamilyWorker: Added logic to automatically deactivate low-affection relationships and notify users of high breakup risks. Updated SQL queries to support these changes.
Some checks failed
Deploy yourpart (blue-green) / deploy (push) Failing after 3s

This commit is contained in:
Torsten Schulz (local)
2026-04-13 12:21:35 +02:00
parent 10f71ece0e
commit 2cca0da750
3 changed files with 71 additions and 2 deletions

View File

@@ -1,7 +1,7 @@
[package]
name = "YpDaemon"
version = "0.1.0"
edition = "2024"
version = "0.5.0"
edition = "2026"
[dependencies]
rand = "0.8"

View File

@@ -18,6 +18,7 @@ use rand::SeedableRng;
use super::base::{BaseWorker, Worker, WorkerState};
use super::sql::{
QUERY_DEACTIVATE_LOVER_RELATIONSHIP,
QUERY_COUNT_LOVER_CHILDREN_FOR_USER, QUERY_FAMILY_SCHEMA_READY,
QUERY_GET_ACTIVE_LOVER_ROWS_FOR_DAILY, QUERY_GET_ACTIVE_LOVER_ROWS_FOR_MONTHLY,
QUERY_GET_ACTIVE_LOVER_ROWS_FOR_INSTALLMENT, QUERY_GET_LOVER_PREGNANCY_CANDIDATES,
@@ -32,6 +33,7 @@ use super::sql::{
};
use crate::db::{ConnectionPool, DbError};
use crate::message_broker::MessageBroker;
use serde_json::json;
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.
@@ -258,6 +260,10 @@ impl FalukantFamilyWorker {
}
conn.prepare("upd_vd", QUERY_UPDATE_LOVER_VISIBILITY_DISCRETION)?;
conn.prepare("deactivate_lover", QUERY_DEACTIVATE_LOVER_RELATIONSHIP)?;
let mut ended_rel_ids: HashSet<i32> = HashSet::new();
let mut breakup_socket_users: HashSet<i32> = HashSet::new();
let mut breakup_risk_notified: HashSet<(i32, i32)> = HashSet::new();
for l in &mut lovers {
let ehe_conflict = marriages.iter().any(|m| {
(m.m1 == l.c1 || m.m2 == l.c1 || m.m1 == l.c2 || m.m2 == l.c2) && m.satisfaction < 40
@@ -304,7 +310,42 @@ impl FalukantFamilyWorker {
)?;
l.visibility = new_vis;
l.discretion = new_disc;
// Je niedriger die Zuneigung, desto höher das tägliche Trennungsrisiko.
let breakup_risk_pct = breakup_risk_percent(l);
if breakup_risk_pct > 50.0 {
for uid in [l.user1_id, l.user2_id].into_iter().flatten() {
if uid <= 0 || !breakup_risk_notified.insert((l.rel_id, uid)) {
continue;
}
let payload = json!({
"tr": "random_event.lover_breakup_risk_high",
"event_id": "lover_breakup_risk_high",
"event_type": "family",
"relationship_id": l.rel_id,
"risk_percent": breakup_risk_pct,
"affection": l.affection,
"visibility": l.visibility,
"discretion": l.discretion,
"months_underfunded": l.months_underfunded
})
.to_string();
if let Err(e) = super::notify::insert_notification_conn(&mut conn, uid, &payload, None) {
eprintln!(
"[FalukantFamilyWorker] high breakup risk notification failed rel_id={} uid={}: {}",
l.rel_id, uid, e
);
}
}
}
if breakup_risk_pct > 0.0 && self.dist.sample(&mut self.rng) * 100.0 < breakup_risk_pct {
conn.execute("deactivate_lover", &[&l.rel_id])?;
ended_rel_ids.insert(l.rel_id);
push_user_id(&mut breakup_socket_users, l.user1_id);
push_user_id(&mut breakup_socket_users, l.user2_id);
}
}
lovers.retain(|l| !ended_rel_ids.contains(&l.rel_id));
conn.prepare("mark_daily", QUERY_MARK_LOVER_DAILY_DONE)?;
conn.prepare("mark_monthly", QUERY_MARK_LOVER_MONTHLY_DONE)?;
@@ -673,6 +714,7 @@ impl FalukantFamilyWorker {
}
notify.extend(marriage_socket_users);
notify.extend(tension_socket_users);
notify.extend(breakup_socket_users);
self.publish_falukant_update_family_batch(&notify, "daily");
drop(conn);
@@ -1279,6 +1321,19 @@ fn visibility_young_penalty(min_age_years: i32, visibility: i32) -> f64 {
}
}
fn breakup_risk_percent(l: &LoverData) -> f64 {
if l.affection >= 45 {
return 0.0;
}
let affection_risk = (45 - l.affection).max(0) as f64 * 0.5;
let underfund_risk = (l.months_underfunded.max(0) as f64 * 1.5).min(10.0);
let visibility_risk = if l.visibility >= 70 { 2.0 } else { 0.0 };
let discretion_risk = if l.discretion <= 30 { 3.0 } else { 0.0 };
(affection_risk + underfund_risk + visibility_risk + discretion_risk).clamp(0.0, 30.0)
}
/// Spec Skandalrisiko: stufenweise Zusatz (exklusiv).
fn scandal_age_extra_pct(min_age_years: i32) -> f64 {
if min_age_years <= 13 {

View File

@@ -444,6 +444,11 @@ SELECT tpw.region_id, tpw.product_id, tpw.worth_percent FROM falukant_data.town_
"#;
// Political offices and cumulative tax
//
// `falukant_type.political_office_type.term_length`: überall als **Kalendertage** (Integer),
// nie als Jahre. Ablauf: `po.created_at + term_length * INTERVAL '1 day'`.
// Steht in den Stammdaten z.B. `4` für „4 Jahre“, wären das faktisch **4 Tage** — dann
// Werte auf Tage umrechnen (z.B. 4 Jahre → 1460) oder die Spalte/Seed-Daten korrigieren.
pub const QUERY_GET_USER_OFFICES: &str = r#"
SELECT po.id AS office_id, pot.name AS office_name, po.region_id, rt.label_tr AS region_type
FROM falukant_data.political_office po
@@ -3574,6 +3579,15 @@ pub const QUERY_MARK_LOVER_MONTHLY_DONE: &str = r#"
WHERE relationship_id = $1::int;
"#;
/// Daily: automatisches Beenden einer Liebschaft bei anhaltend niedriger Zuneigung.
pub const QUERY_DEACTIVATE_LOVER_RELATIONSHIP: &str = r#"
UPDATE falukant_data.relationship_state
SET active = false,
updated_at = NOW()
WHERE relationship_id = $1::int
AND active = true;
"#;
/// Liebschaft: fällige Teilzahlung (alle 2 h), Migration `006_falukant_lover_installments.sql`.
pub const QUERY_GET_ACTIVE_LOVER_ROWS_FOR_INSTALLMENT: &str = r#"
SELECT