Implement character death handling and periodic checks: Add logic to process characters with health <= 0 in EventsWorker and UserCharacterWorker, including immediate death handling during health updates and a scheduled death check every 12 hours. Introduce a new SQL query to retrieve characters with zero health.
This commit is contained in:
@@ -548,6 +548,8 @@ impl EventsWorker {
|
|||||||
*min_change,
|
*min_change,
|
||||||
*max_change,
|
*max_change,
|
||||||
rng,
|
rng,
|
||||||
|
pool,
|
||||||
|
broker,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
effect_results.push(json!({
|
effect_results.push(json!({
|
||||||
@@ -842,6 +844,8 @@ impl EventsWorker {
|
|||||||
*min_change,
|
*min_change,
|
||||||
*max_change,
|
*max_change,
|
||||||
rng,
|
rng,
|
||||||
|
pool,
|
||||||
|
broker,
|
||||||
) {
|
) {
|
||||||
effect_results.push(json!({
|
effect_results.push(json!({
|
||||||
"type": "character_health_change",
|
"type": "character_health_change",
|
||||||
@@ -1273,6 +1277,8 @@ impl EventsWorker {
|
|||||||
min_change: i32,
|
min_change: i32,
|
||||||
max_change: i32,
|
max_change: i32,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
|
pool: &ConnectionPool,
|
||||||
|
broker: &MessageBroker,
|
||||||
) -> Result<(i32, i32), DbError> {
|
) -> Result<(i32, i32), DbError> {
|
||||||
// Hole einen zufälligen Charakter des Spielers
|
// Hole einen zufälligen Charakter des Spielers
|
||||||
conn.prepare("get_random_character", QUERY_GET_RANDOM_CHARACTER)?;
|
conn.prepare("get_random_character", QUERY_GET_RANDOM_CHARACTER)?;
|
||||||
@@ -1304,6 +1310,13 @@ impl EventsWorker {
|
|||||||
conn.prepare("update_health", QUERY_UPDATE_HEALTH)?;
|
conn.prepare("update_health", QUERY_UPDATE_HEALTH)?;
|
||||||
conn.execute("update_health", &[&new_health, &character_id])?;
|
conn.execute("update_health", &[&new_health, &character_id])?;
|
||||||
|
|
||||||
|
// Bei Health <= 0 sofort Tod prüfen und verarbeiten
|
||||||
|
if new_health <= 0 {
|
||||||
|
if let Err(e) = Self::handle_character_death(pool, broker, character_id) {
|
||||||
|
eprintln!("[EventsWorker] handle_character_death nach Health-Update: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok((character_id, health_change))
|
Ok((character_id, health_change))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1343,12 +1356,15 @@ impl EventsWorker {
|
|||||||
min_change: i32,
|
min_change: i32,
|
||||||
max_change: i32,
|
max_change: i32,
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
|
pool: &ConnectionPool,
|
||||||
|
broker: &MessageBroker,
|
||||||
) -> Result<Vec<(i32, i32)>, DbError> {
|
) -> Result<Vec<(i32, i32)>, DbError> {
|
||||||
// Hole alle lebenden Charaktere in der Region
|
// Hole alle lebenden Charaktere in der Region
|
||||||
conn.prepare("get_region_characters", QUERY_GET_REGION_CHARACTERS)?;
|
conn.prepare("get_region_characters", QUERY_GET_REGION_CHARACTERS)?;
|
||||||
let rows = conn.execute("get_region_characters", &[®ion_id])?;
|
let rows = conn.execute("get_region_characters", &[®ion_id])?;
|
||||||
|
|
||||||
let mut affected_characters = Vec::new();
|
let mut affected_characters = Vec::new();
|
||||||
|
let mut dead_character_ids = Vec::new();
|
||||||
|
|
||||||
for row in rows {
|
for row in rows {
|
||||||
let character_id: Option<i32> = row
|
let character_id: Option<i32> = row
|
||||||
@@ -1373,6 +1389,16 @@ impl EventsWorker {
|
|||||||
conn.execute("update_health_regional", &[&new_health, &character_id])?;
|
conn.execute("update_health_regional", &[&new_health, &character_id])?;
|
||||||
|
|
||||||
affected_characters.push((character_id, health_change));
|
affected_characters.push((character_id, health_change));
|
||||||
|
if new_health <= 0 {
|
||||||
|
dead_character_ids.push(character_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bei Health <= 0 Tod verarbeiten
|
||||||
|
for character_id in dead_character_ids {
|
||||||
|
if let Err(e) = Self::handle_character_death(pool, broker, character_id) {
|
||||||
|
eprintln!("[EventsWorker] handle_character_death nach regionalem Health-Update: {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(affected_characters)
|
Ok(affected_characters)
|
||||||
|
|||||||
@@ -587,6 +587,11 @@ pub const QUERY_GET_USERS_TO_UPDATE: &str = r#"
|
|||||||
WHERE user_id IS NOT NULL;
|
WHERE user_id IS NOT NULL;
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
pub const QUERY_GET_CHARACTERS_ZERO_HEALTH: &str = r#"
|
||||||
|
SELECT id FROM falukant_data."character"
|
||||||
|
WHERE user_id IS NOT NULL AND health <= 0;
|
||||||
|
"#;
|
||||||
|
|
||||||
// politics worker queries
|
// politics worker queries
|
||||||
pub const QUERY_COUNT_OFFICES_PER_REGION: &str = r#"
|
pub const QUERY_COUNT_OFFICES_PER_REGION: &str = r#"
|
||||||
WITH
|
WITH
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::time::{Duration, Instant};
|
|||||||
|
|
||||||
use super::base::{BaseWorker, Worker, WorkerState};
|
use super::base::{BaseWorker, Worker, WorkerState};
|
||||||
use crate::worker::sql::{
|
use crate::worker::sql::{
|
||||||
|
QUERY_GET_CHARACTERS_ZERO_HEALTH,
|
||||||
QUERY_GET_USERS_TO_UPDATE,
|
QUERY_GET_USERS_TO_UPDATE,
|
||||||
QUERY_UPDATE_CHARACTERS_HEALTH,
|
QUERY_UPDATE_CHARACTERS_HEALTH,
|
||||||
QUERY_UPDATE_MOOD,
|
QUERY_UPDATE_MOOD,
|
||||||
@@ -59,6 +60,7 @@ pub struct UserCharacterWorker {
|
|||||||
last_hourly_run: Option<Instant>,
|
last_hourly_run: Option<Instant>,
|
||||||
last_pregnancy_run: Option<Instant>,
|
last_pregnancy_run: Option<Instant>,
|
||||||
last_mood_run: Option<Instant>,
|
last_mood_run: Option<Instant>,
|
||||||
|
last_death_check_run: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SQL moved to `src/worker/sql.rs`
|
// SQL moved to `src/worker/sql.rs`
|
||||||
@@ -76,6 +78,7 @@ impl UserCharacterWorker {
|
|||||||
last_hourly_run: None,
|
last_hourly_run: None,
|
||||||
last_pregnancy_run: None,
|
last_pregnancy_run: None,
|
||||||
last_mood_run: None,
|
last_mood_run: None,
|
||||||
|
last_death_check_run: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +86,7 @@ impl UserCharacterWorker {
|
|||||||
self.base.set_current_step("UserCharacterWorker iteration");
|
self.base.set_current_step("UserCharacterWorker iteration");
|
||||||
|
|
||||||
self.maybe_run_hourly_tasks();
|
self.maybe_run_hourly_tasks();
|
||||||
|
self.maybe_run_death_check();
|
||||||
self.maybe_run_mood_updates();
|
self.maybe_run_mood_updates();
|
||||||
self.maybe_run_daily_pregnancies();
|
self.maybe_run_daily_pregnancies();
|
||||||
|
|
||||||
@@ -116,6 +120,51 @@ impl UserCharacterWorker {
|
|||||||
self.last_hourly_run = Some(now);
|
self.last_hourly_run = Some(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Alle 12 Stunden: Charaktere mit health <= 0 finden und Tod verarbeiten
|
||||||
|
fn maybe_run_death_check(&mut self) {
|
||||||
|
const DEATH_CHECK_INTERVAL_SECS: u64 = 12 * 3600;
|
||||||
|
let now = Instant::now();
|
||||||
|
let should_run = match self.last_death_check_run {
|
||||||
|
None => true,
|
||||||
|
Some(last) => now.saturating_duration_since(last) >= Duration::from_secs(DEATH_CHECK_INTERVAL_SECS),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !should_run {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = self.process_zero_health_deaths() {
|
||||||
|
eprintln!("[UserCharacterWorker] Fehler bei Tod-Prüfung (health <= 0): {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_death_check_run = Some(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_zero_health_deaths(&mut self) -> Result<(), DbError> {
|
||||||
|
let ids: Vec<i32> = {
|
||||||
|
let mut conn = self
|
||||||
|
.base
|
||||||
|
.pool
|
||||||
|
.get()
|
||||||
|
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||||
|
|
||||||
|
conn.prepare("get_characters_zero_health", QUERY_GET_CHARACTERS_ZERO_HEALTH)?;
|
||||||
|
let rows = conn.execute("get_characters_zero_health", &[])?;
|
||||||
|
|
||||||
|
rows.into_iter()
|
||||||
|
.filter_map(|r| r.get("id").and_then(|v| v.parse::<i32>().ok()))
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
for character_id in ids {
|
||||||
|
if let Err(e) = self.handle_character_death(character_id) {
|
||||||
|
eprintln!("[UserCharacterWorker] handle_character_death für Charakter {}: {e}", character_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn run_hourly_tasks(&mut self) -> Result<(), DbError> {
|
fn run_hourly_tasks(&mut self) -> Result<(), DbError> {
|
||||||
self.process_character_events()?;
|
self.process_character_events()?;
|
||||||
self.handle_credits()?;
|
self.handle_credits()?;
|
||||||
|
|||||||
Reference in New Issue
Block a user