Enhance character event notifications in EventsWorker: Update character health change and death handling to include first and last names in notifications. Modify SQL queries to retrieve character names, ensuring accurate user feedback. Refactor notification structure for better organization and clarity.

This commit is contained in:
Torsten Schulz (local)
2026-01-07 11:33:23 +01:00
parent 282f6542fe
commit 01d45d5f65
2 changed files with 114 additions and 32 deletions

View File

@@ -595,7 +595,7 @@ impl EventsWorker {
max_change,
} => {
if effect_roll < *probability
&& let Ok((character_id, health_change, died)) = Self::apply_character_health_change(
&& let Ok((character_id, health_change, died, first_name, last_name)) = Self::apply_character_health_change(
&mut conn,
pool,
broker,
@@ -608,23 +608,30 @@ impl EventsWorker {
effect_results.push(json!({
"type": "character_health_change",
"character_id": character_id,
"change": health_change
"change": health_change,
"character_first_name": first_name,
"character_last_name": last_name
}));
if died {
effect_results.push(json!({
"type": "character_death",
"character_id": character_id
"character_id": character_id,
"character_first_name": first_name,
"character_last_name": last_name
}));
}
}
}
EventEffect::CharacterDeath { probability } => {
if effect_roll < *probability
&& let Ok(character_id) = Self::apply_character_death(&mut conn, user_id, pool, broker)
&& let Ok((character_id, first_name, last_name)) =
Self::apply_character_death(&mut conn, user_id, pool, broker)
{
effect_results.push(json!({
"type": "character_death",
"character_id": character_id
"character_id": character_id,
"character_first_name": first_name,
"character_last_name": last_name
}));
}
}
@@ -675,18 +682,56 @@ impl EventsWorker {
eff.get("character_id").and_then(|v| v.as_i64()).map(|n| n as i32)
});
// Optional: Namen-Snapshot aus Effekten extrahieren (auch wenn der Charakter danach stirbt/gelöscht wird)
let (top_first_name, top_last_name) = if let Some(cid) = top_character_id {
let eff = effect_results.iter().find(|e| {
e.get("character_id")
.and_then(|v| v.as_i64())
.map(|n| n as i32)
== Some(cid)
});
let fn_ = eff
.and_then(|e| e.get("character_first_name"))
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let ln_ = eff
.and_then(|e| e.get("character_last_name"))
.and_then(|v| v.as_str())
.map(|s| s.to_string());
(fn_, ln_)
} else {
(None, None)
};
// Frontend: `tr` ist der i18n-Key, Details liegen in `value` (Interpolation/Detailansicht)
let mut notification_json = serde_json::json!({
"tr": format!("random_event.{}", event.id),
"event_id": event.id,
"event_type": "personal",
"effects": effect_results
"value": {
"event_id": event.id,
"event_type": "personal",
"title": event.title,
"description": event.description,
"effects": effect_results
}
});
if let Some(cid) = top_character_id {
notification_json["character_id"] = serde_json::json!(cid);
notification_json["value"]["character_id"] = serde_json::json!(cid);
}
if let Some(fn_) = top_first_name {
notification_json["value"]["character_first_name"] = serde_json::json!(fn_);
}
if let Some(ln_) = top_last_name {
notification_json["value"]["character_last_name"] = serde_json::json!(ln_);
}
Self::notify_user(pool, broker, user_id, &notification_json.to_string())?;
Self::notify_user(
pool,
broker,
user_id,
&notification_json.to_string(),
top_character_id,
)?;
// Sende Benachrichtigung über WebSocket
let mut notification = json!({
@@ -753,6 +798,9 @@ impl EventsWorker {
}
};
let first_name = rows.first().and_then(|r| r.get("first_name")).cloned();
let last_name = rows.first().and_then(|r| r.get("last_name")).cloned();
// Wende Effekte an (in diesem Fall nur CharacterDeath)
let mut effect_results = Vec::new();
for effect in &event.effects {
@@ -764,7 +812,9 @@ impl EventsWorker {
{
effect_results.push(json!({
"type": "character_death",
"character_id": character_id
"character_id": character_id,
"character_first_name": first_name,
"character_last_name": last_name
}));
}
}
@@ -780,12 +830,25 @@ impl EventsWorker {
// Schreibe Benachrichtigung in die Datenbank mit Event-Details
let notification_json = serde_json::json!({
"tr": format!("random_event.{}", event.id),
"event_id": event.id,
"event_type": "personal",
"character_id": character_id,
"effects": effect_results
"value": {
"event_id": event.id,
"event_type": "personal",
"title": event.title,
"description": event.description,
"character_id": character_id,
"character_first_name": first_name,
"character_last_name": last_name,
"effects": effect_results
}
});
Self::notify_user(pool, broker, user_id, &notification_json.to_string())?;
// Falls das Kind inzwischen gelöscht wurde, halten wir Name + ID im Payload fest.
Self::notify_user(
pool,
broker,
user_id,
&notification_json.to_string(),
Some(character_id),
)?;
// Sende Benachrichtigung über WebSocket
let notification = json!({
@@ -1041,12 +1104,18 @@ impl EventsWorker {
// Schreibe Benachrichtigung in die Datenbank mit Event-Details
let notification_json = serde_json::json!({
"tr": format!("random_event.{}", event.id),
"event_id": event.id,
"event_type": "regional",
"region_id": region_id,
"effects": effect_results
"value": {
"event_id": event.id,
"event_type": "regional",
"title": event.title,
"description": event.description,
"region_id": region_id,
"effects": effect_results
}
});
if let Err(err) = Self::notify_user(pool, broker, uid, &notification_json.to_string()) {
if let Err(err) =
Self::notify_user(pool, broker, uid, &notification_json.to_string(), None)
{
eprintln!("[EventsWorker] Fehler beim Schreiben der Benachrichtigung für User {}: {}", uid, err);
}
@@ -1350,7 +1419,7 @@ impl EventsWorker {
min_change: i32,
max_change: i32,
rng: &mut impl Rng,
) -> Result<(i32, i32, bool), DbError> {
) -> Result<(i32, i32, bool, Option<String>, Option<String>), DbError> {
// Hole einen zufälligen Charakter des Spielers
conn.prepare("get_random_character", QUERY_GET_RANDOM_CHARACTER)?;
let rows = conn.execute("get_random_character", &[&user_id])?;
@@ -1374,6 +1443,10 @@ impl EventsWorker {
.and_then(|v| v.parse::<i32>().ok())
.unwrap_or(100);
// Namen-Snapshot (wichtig, falls der Charakter durch das Event stirbt und gelöscht wird)
let first_name = rows.first().and_then(|r| r.get("first_name")).cloned();
let last_name = rows.first().and_then(|r| r.get("last_name")).cloned();
let health_change = rng.gen_range(min_change..=max_change);
let new_health = (current_health + health_change).clamp(0, 100);
@@ -1389,7 +1462,7 @@ impl EventsWorker {
let _ = Self::handle_character_death(pool, broker, character_id);
}
Ok((character_id, health_change, died))
Ok((character_id, health_change, died, first_name, last_name))
}
fn apply_character_death(
@@ -1397,7 +1470,7 @@ impl EventsWorker {
user_id: i32,
pool: &ConnectionPool,
broker: &MessageBroker,
) -> Result<i32, DbError> {
) -> Result<(i32, Option<String>, Option<String>), DbError> {
// Hole einen zufälligen Charakter des Spielers
conn.prepare("get_random_character_death", QUERY_GET_RANDOM_CHARACTER)?;
let rows = conn.execute("get_random_character_death", &[&user_id])?;
@@ -1415,11 +1488,14 @@ impl EventsWorker {
}
};
let first_name = rows.first().and_then(|r| r.get("first_name")).cloned();
let last_name = rows.first().and_then(|r| r.get("last_name")).cloned();
// Verwende die existierende Logik zum Löschen von Charakteren
// (ähnlich wie in CharacterCreationWorker)
Self::handle_character_death(pool, broker, character_id)?;
Ok(character_id)
Ok((character_id, first_name, last_name))
}
fn apply_regional_character_health_change(
@@ -1535,7 +1611,7 @@ impl EventsWorker {
.get("employer_user_id")
.and_then(|v| v.parse::<i32>().ok())
{
Self::notify_user(pool, broker, user_id, "director_death")?;
Self::notify_user(pool, broker, user_id, "director_death", None)?;
}
}
@@ -1547,7 +1623,7 @@ impl EventsWorker {
.get("related_user_id")
.and_then(|v| v.parse::<i32>().ok())
{
Self::notify_user(pool, broker, related_user_id, "relationship_death")?;
Self::notify_user(pool, broker, related_user_id, "relationship_death", None)?;
}
}
@@ -1575,13 +1651,13 @@ impl EventsWorker {
.get("father_user_id")
.and_then(|v| v.parse::<i32>().ok())
{
Self::notify_user(pool, broker, father_user_id, "child_death")?;
Self::notify_user(pool, broker, father_user_id, "child_death", None)?;
}
if let Some(mother_user_id) = row
.get("mother_user_id")
.and_then(|v| v.parse::<i32>().ok())
{
Self::notify_user(pool, broker, mother_user_id, "child_death")?;
Self::notify_user(pool, broker, mother_user_id, "child_death", None)?;
}
}
@@ -1744,9 +1820,10 @@ impl EventsWorker {
broker: &MessageBroker,
user_id: i32,
event_type: &str,
character_id: Option<i32>,
) -> Result<(), DbError> {
// DB-Notification (zentralisiert). Historisch wird hier als `tr` der event_type-String gespeichert.
insert_notification(pool, user_id, event_type, None)?;
insert_notification(pool, user_id, event_type, character_id)?;
// Frontend-Update (zentralisiert)
publish_update_status(broker, user_id);