code fixes
All checks were successful
Deploy yourpart (blue-green) / deploy (push) Successful in 1m52s

This commit is contained in:
Torsten Schulz (local)
2026-06-06 13:26:45 +02:00
parent 35377e3b59
commit 41c0e5a6f2
9 changed files with 71 additions and 88 deletions

2
Cargo.lock generated
View File

@@ -11,7 +11,7 @@ dependencies = [
"futures-util", "futures-util",
"libsystemd", "libsystemd",
"postgres", "postgres",
"rand 0.8.5", "rand 0.9.2",
"rustls-pemfile", "rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",

View File

@@ -1,8 +1,7 @@
use crate::db::{ConnectionPool, DbError, Rows}; use crate::db::{ConnectionPool, DbError, Rows};
use crate::message_broker::MessageBroker; use crate::message_broker::MessageBroker;
use rand::distributions::{Distribution, Uniform};
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::{thread_rng, Rng, SeedableRng}; use rand::{Rng, SeedableRng};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
@@ -29,7 +28,6 @@ use crate::worker::sql::{
pub struct CharacterCreationWorker { pub struct CharacterCreationWorker {
pub(crate) base: BaseWorker, pub(crate) base: BaseWorker,
rng: StdRng, rng: StdRng,
dist: Uniform<i32>,
first_name_cache: HashMap<String, HashSet<i32>>, first_name_cache: HashMap<String, HashSet<i32>>,
last_name_cache: HashSet<i32>, last_name_cache: HashSet<i32>,
death_check_running: Arc<AtomicBool>, death_check_running: Arc<AtomicBool>,
@@ -46,8 +44,8 @@ impl CharacterCreationWorker {
/// Interner Konstruktor, der optional den NPC-Todes-Monitor startet. /// Interner Konstruktor, der optional den NPC-Todes-Monitor startet.
fn new_internal(pool: ConnectionPool, broker: MessageBroker, start_death_thread: bool) -> Self { fn new_internal(pool: ConnectionPool, broker: MessageBroker, start_death_thread: bool) -> Self {
let base = BaseWorker::new("CharacterCreationWorker", pool.clone(), broker.clone()); let base = BaseWorker::new("CharacterCreationWorker", pool.clone(), broker.clone());
let rng = StdRng::from_entropy(); let mut base_rng = rand::rng();
let dist = Uniform::from(2..=3); let rng = StdRng::from_rng(&mut base_rng);
let death_check_running = Arc::new(AtomicBool::new(start_death_thread)); let death_check_running = Arc::new(AtomicBool::new(start_death_thread));
let death_thread = if start_death_thread { let death_thread = if start_death_thread {
@@ -80,7 +78,6 @@ impl CharacterCreationWorker {
Self { Self {
base, base,
rng, rng,
dist,
first_name_cache: HashMap::new(), first_name_cache: HashMap::new(),
last_name_cache: HashSet::new(), last_name_cache: HashSet::new(),
death_check_running, death_check_running,
@@ -139,7 +136,7 @@ impl CharacterCreationWorker {
for &nobility in &nobility_stands { for &nobility in &nobility_stands {
for &gender in &genders { for &gender in &genders {
let num_chars = self.rng.sample(self.dist); let num_chars = self.rng.random_range(2..=3);
for _ in 0..num_chars { for _ in 0..num_chars {
self.create_character(region_id, gender, nobility); self.create_character(region_id, gender, nobility);
} }
@@ -248,8 +245,8 @@ impl CharacterCreationWorker {
if set.is_empty() { if set.is_empty() {
return -1; return -1;
} }
let mut rng = thread_rng(); let mut rng = rand::rng();
let idx = rng.gen_range(0..set.len()); let idx = rng.random_range(0..set.len());
*set.iter().nth(idx).unwrap_or(&-1) *set.iter().nth(idx).unwrap_or(&-1)
} }
@@ -390,9 +387,8 @@ impl CharacterCreationWorker {
let death_probability = let death_probability =
base_probability + increase_per_year * (age.saturating_sub(60) as f64); base_probability + increase_per_year * (age.saturating_sub(60) as f64);
let mut rng = thread_rng(); let mut rng = rand::rng();
let dist = Uniform::from(0.0..1.0); let roll: f64 = rng.random_range(0.0..1.0);
let roll: f64 = dist.sample(&mut rng);
roll < death_probability roll < death_probability
} }
@@ -537,4 +533,3 @@ impl CharacterCreationWorker {
} }
} }

View File

@@ -193,7 +193,7 @@ impl DirectorWorker {
.filter_map(Self::map_row_to_resignation_candidate) .filter_map(Self::map_row_to_resignation_candidate)
.collect(); .collect();
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
for candidate in candidates { for candidate in candidates {
let sat = candidate.satisfaction.clamp(0, 100) as f64; let sat = candidate.satisfaction.clamp(0, 100) as f64;
let resignation_probability = 1.0 - (sat / 100.0); let resignation_probability = 1.0 - (sat / 100.0);
@@ -214,7 +214,7 @@ impl DirectorWorker {
); );
let _ = conn.execute("insert_notification", &[&candidate.employer_user_id, &payload]); let _ = conn.execute("insert_notification", &[&candidate.employer_user_id, &payload]);
} }
let roll: f64 = rng.gen_range(0.0..1.0); let roll: f64 = rng.random_range(0.0..1.0);
if roll >= resignation_probability { if roll >= resignation_probability {
continue; continue;
} }

View File

@@ -1,7 +1,7 @@
use crate::db::{ConnectionPool, DbConnection, DbError}; use crate::db::{ConnectionPool, DbConnection, DbError};
use crate::message_broker::MessageBroker; use crate::message_broker::MessageBroker;
use rand::Rng; use rand::Rng;
use rand::seq::SliceRandom; use rand::prelude::SliceRandom;
use serde_json::json; use serde_json::json;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
@@ -447,7 +447,7 @@ impl EventsWorker {
fn run_loop(pool: ConnectionPool, broker: MessageBroker, state: Arc<WorkerState>) { fn run_loop(pool: ConnectionPool, broker: MessageBroker, state: Arc<WorkerState>) {
let mut last_event_check = None; let mut last_event_check = None;
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let events = Self::initialize_events(); let events = Self::initialize_events();
loop { loop {
@@ -502,7 +502,7 @@ impl EventsWorker {
// Prüfe jedes mögliche Ereignis // Prüfe jedes mögliche Ereignis
for event in events { for event in events {
// Zufällige Prüfung basierend auf Wahrscheinlichkeit // Zufällige Prüfung basierend auf Wahrscheinlichkeit
let roll = rng.gen_range(0.0..=1.0); let roll = rng.random_range(0.0..=1.0);
let effective_prob = event.probability_per_minute * Self::EVENT_RATE_SCALE; let effective_prob = event.probability_per_minute * Self::EVENT_RATE_SCALE;
if roll < effective_prob { if roll < effective_prob {
eprintln!( eprintln!(
@@ -560,7 +560,7 @@ impl EventsWorker {
// Wende Effekte an // Wende Effekte an
let mut effect_results = Vec::new(); let mut effect_results = Vec::new();
for effect in &event.effects { for effect in &event.effects {
let effect_roll = rng.gen_range(0.0..=1.0); let effect_roll = rng.random_range(0.0..=1.0);
match effect { match effect {
EventEffect::MoneyChange { EventEffect::MoneyChange {
probability, probability,
@@ -750,7 +750,7 @@ impl EventsWorker {
// Wende Effekte an (in diesem Fall nur CharacterDeath) // Wende Effekte an (in diesem Fall nur CharacterDeath)
let mut effect_results = Vec::new(); let mut effect_results = Vec::new();
for effect in &event.effects { for effect in &event.effects {
let effect_roll = rng.gen_range(0.0..=1.0); let effect_roll = rng.random_range(0.0..=1.0);
match effect { match effect {
EventEffect::CharacterDeath { probability } => { EventEffect::CharacterDeath { probability } => {
if effect_roll < *probability if effect_roll < *probability
@@ -835,7 +835,7 @@ impl EventsWorker {
let mut price_change_note: Option<serde_json::Value> = None; let mut price_change_note: Option<serde_json::Value> = None;
let mut production_quality_note: Option<serde_json::Value> = None; let mut production_quality_note: Option<serde_json::Value> = None;
for effect in &event.effects { for effect in &event.effects {
let effect_roll = rng.gen_range(0.0..=1.0); let effect_roll = rng.random_range(0.0..=1.0);
match effect { match effect {
EventEffect::WeatherChange { probability } => { EventEffect::WeatherChange { probability } => {
if effect_roll < *probability { if effect_roll < *probability {
@@ -851,7 +851,7 @@ impl EventsWorker {
max_change, max_change,
} => { } => {
if effect_roll < *probability { if effect_roll < *probability {
let change = rng.gen_range(*min_change..=*max_change); let change = rng.random_range(*min_change..=*max_change);
Self::apply_production_quality_change(&mut conn, region_id, change)?; Self::apply_production_quality_change(&mut conn, region_id, change)?;
effect_results.push(json!({ effect_results.push(json!({
"type": "production_quality_change", "type": "production_quality_change",
@@ -879,7 +879,7 @@ impl EventsWorker {
max_percent, max_percent,
} => { } => {
if effect_roll < *probability { if effect_roll < *probability {
let percent_change = rng.gen_range(*min_percent..=*max_percent); let percent_change = rng.random_range(*min_percent..=*max_percent);
Self::apply_price_change(&mut conn, region_id, percent_change)?; Self::apply_price_change(&mut conn, region_id, percent_change)?;
effect_results.push(json!({ effect_results.push(json!({
"type": "price_change", "type": "price_change",
@@ -907,7 +907,7 @@ impl EventsWorker {
max_percent, max_percent,
} => { } => {
if effect_roll < *probability { if effect_roll < *probability {
let percent_change = rng.gen_range(*min_percent..=*max_percent); let percent_change = rng.random_range(*min_percent..=*max_percent);
Self::apply_transport_speed_change(&mut conn, region_id, percent_change)?; Self::apply_transport_speed_change(&mut conn, region_id, percent_change)?;
effect_results.push(json!({ effect_results.push(json!({
"type": "transport_speed_change", "type": "transport_speed_change",
@@ -1218,7 +1218,7 @@ impl EventsWorker {
} }
// Berechne die prozentuale Änderung // Berechne die prozentuale Änderung
let percent_change = rng.gen_range(min_percent..=max_percent); let percent_change = rng.random_range(min_percent..=max_percent);
// Reduziere die Kapazität aller Stocks // Reduziere die Kapazität aller Stocks
conn.prepare("update_stock_capacity_regional", QUERY_UPDATE_STOCK_CAPACITY_REGIONAL)?; conn.prepare("update_stock_capacity_regional", QUERY_UPDATE_STOCK_CAPACITY_REGIONAL)?;
@@ -1283,7 +1283,7 @@ impl EventsWorker {
} }
// Berechne die Änderung // Berechne die Änderung
let quality_change = rng.gen_range(min_change..=max_change); let quality_change = rng.random_range(min_change..=max_change);
// Reduziere die Qualität aller Häuser // Reduziere die Qualität aller Häuser
conn.prepare("update_house_quality", QUERY_UPDATE_HOUSE_QUALITY)?; conn.prepare("update_house_quality", QUERY_UPDATE_HOUSE_QUALITY)?;
@@ -1393,7 +1393,7 @@ impl EventsWorker {
// Spezialfall: Unerwarteter Geldsegen -> absoluter Zufallsbetrag 1..500 // Spezialfall: Unerwarteter Geldsegen -> absoluter Zufallsbetrag 1..500
if event.id == "windfall" { if event.id == "windfall" {
let absolute_change: f64 = rng.gen_range(1.0..=500.0); let absolute_change: f64 = rng.random_range(1.0..=500.0);
let percent_change = if current_money > 0.0 { let percent_change = if current_money > 0.0 {
(absolute_change / current_money) * 100.0 (absolute_change / current_money) * 100.0
} else { } else {
@@ -1430,7 +1430,7 @@ impl EventsWorker {
return Ok(None); return Ok(None);
} }
let loss: f64 = rng.gen_range(1.0..=max_loss); let loss: f64 = rng.random_range(1.0..=max_loss);
let percent_change = -(loss / current_money) * 100.0; let percent_change = -(loss / current_money) * 100.0;
let absolute_change = -loss; let absolute_change = -loss;
@@ -1456,7 +1456,7 @@ impl EventsWorker {
} }
// Standardfall: prozentuale Änderung, optional mit Mindestbetrag für positive Änderungen // Standardfall: prozentuale Änderung, optional mit Mindestbetrag für positive Änderungen
let percent_change = rng.gen_range(min_percent..=max_percent); let percent_change = rng.random_range(min_percent..=max_percent);
let computed_change = current_money * (percent_change / 100.0); let computed_change = current_money * (percent_change / 100.0);
let effective_change = match min_absolute_positive { let effective_change = match min_absolute_positive {
Some(min_abs) if percent_change > 0.0 && computed_change < *min_abs => *min_abs, Some(min_abs) if percent_change > 0.0 && computed_change < *min_abs => *min_abs,
@@ -1491,7 +1491,7 @@ impl EventsWorker {
return Ok(None); return Ok(None);
} }
let percent_change = rng.gen_range(min_percent..=max_percent); let percent_change = rng.random_range(min_percent..=max_percent);
Self::apply_storage_capacity_change(conn, user_id, percent_change)?; Self::apply_storage_capacity_change(conn, user_id, percent_change)?;
Ok(Some(json!({ Ok(Some(json!({
@@ -1744,7 +1744,7 @@ impl EventsWorker {
.and_then(|v| v.parse::<i32>().ok()) .and_then(|v| v.parse::<i32>().ok())
.unwrap_or(100); .unwrap_or(100);
let health_change = rng.gen_range(min_change..=max_change); let health_change = rng.random_range(min_change..=max_change);
// Durch Unfälle/Krankheiten soll Gesundheit von Spieler-Charakteren nicht auf 0 fallen // Durch Unfälle/Krankheiten soll Gesundheit von Spieler-Charakteren nicht auf 0 fallen
let new_health = (current_health + health_change).clamp(1, 100); let new_health = (current_health + health_change).clamp(1, 100);
@@ -1816,7 +1816,7 @@ impl EventsWorker {
.and_then(|v| v.parse::<i32>().ok()) .and_then(|v| v.parse::<i32>().ok())
.unwrap_or(100); .unwrap_or(100);
let health_change = rng.gen_range(min_change..=max_change); let health_change = rng.random_range(min_change..=max_change);
let user_id: Option<i32> = row let user_id: Option<i32> = row
.get("user_id") .get("user_id")
.and_then(|v| v.parse::<i32>().ok()); .and_then(|v| v.parse::<i32>().ok());
@@ -2235,9 +2235,9 @@ impl EventsWorker {
// 3. Berechne Schäden // 3. Berechne Schäden
let inventory_damage_percent = let inventory_damage_percent =
rng.gen_range(params.inventory_damage_min_percent..=params.inventory_damage_max_percent); rng.random_range(params.inventory_damage_min_percent..=params.inventory_damage_max_percent);
let storage_destruction_percent = let storage_destruction_percent =
rng.gen_range(params.storage_destruction_min_percent..=params.storage_destruction_max_percent); rng.random_range(params.storage_destruction_min_percent..=params.storage_destruction_max_percent);
let total_stocks = stock_rows.len(); let total_stocks = stock_rows.len();
let stocks_to_destroy_requested = ((total_stocks as f64 * storage_destruction_percent / 100.0) let stocks_to_destroy_requested = ((total_stocks as f64 * storage_destruction_percent / 100.0)
@@ -2455,9 +2455,9 @@ impl EventsWorker {
// 3. Berechne Schäden // 3. Berechne Schäden
let inventory_damage_percent = let inventory_damage_percent =
rng.gen_range(params.inventory_damage_min_percent..=params.inventory_damage_max_percent); rng.random_range(params.inventory_damage_min_percent..=params.inventory_damage_max_percent);
let storage_destruction_percent = let storage_destruction_percent =
rng.gen_range(params.storage_destruction_min_percent..=params.storage_destruction_max_percent); rng.random_range(params.storage_destruction_min_percent..=params.storage_destruction_max_percent);
let total_stocks = stock_rows.len(); let total_stocks = stock_rows.len();
let stocks_to_destroy_requested = ((total_stocks as f64 * storage_destruction_percent / 100.0) let stocks_to_destroy_requested = ((total_stocks as f64 * storage_destruction_percent / 100.0)

View File

@@ -12,9 +12,8 @@ use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use rand::distributions::{Distribution, Uniform};
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::SeedableRng; use rand::{Rng, SeedableRng};
use super::base::{BaseWorker, Worker, WorkerState}; use super::base::{BaseWorker, Worker, WorkerState};
use super::sql::{ use super::sql::{
@@ -46,7 +45,6 @@ const GAME_MONTH_SLICE_INTERVAL: Duration = Duration::from_secs(2 * 3600);
pub struct FalukantFamilyWorker { pub struct FalukantFamilyWorker {
base: BaseWorker, base: BaseWorker,
rng: StdRng, rng: StdRng,
dist: Uniform<f64>,
last_daily: Option<Instant>, last_daily: Option<Instant>,
last_monthly: Option<Instant>, last_monthly: Option<Instant>,
/// Gemeinsamer Tick für Liebschafts-Raten + Dienerschaft (Monatstick ≈ 2 h). /// Gemeinsamer Tick für Liebschafts-Raten + Dienerschaft (Monatstick ≈ 2 h).
@@ -63,8 +61,10 @@ impl FalukantFamilyWorker {
pub fn new(pool: ConnectionPool, broker: MessageBroker) -> Self { pub fn new(pool: ConnectionPool, broker: MessageBroker) -> Self {
Self { Self {
base: BaseWorker::new("FalukantFamilyWorker", pool, broker), base: BaseWorker::new("FalukantFamilyWorker", pool, broker),
rng: StdRng::from_entropy(), rng: {
dist: Uniform::from(0.0..1.0), let mut base_rng = rand::rng();
StdRng::from_rng(&mut base_rng)
},
last_daily: None, last_daily: None,
last_monthly: None, last_monthly: None,
last_game_month_slice: None, last_game_month_slice: None,
@@ -361,7 +361,7 @@ impl FalukantFamilyWorker {
} }
} }
} }
if breakup_risk_pct > 0.0 && self.dist.sample(&mut self.rng) * 100.0 < breakup_risk_pct { if breakup_risk_pct > 0.0 && self.rng.random_range(0.0..1.0) * 100.0 < breakup_risk_pct {
conn.execute("deactivate_lover", &[&l.rel_id])?; conn.execute("deactivate_lover", &[&l.rel_id])?;
ended_rel_ids.insert(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.user1_id);
@@ -676,7 +676,7 @@ impl FalukantFamilyWorker {
p -= 2.0; p -= 2.0;
} }
p = p.clamp(0.0, 25.0); p = p.clamp(0.0, 25.0);
if self.dist.sample(&mut self.rng) * 100.0 < p { if self.rng.random_range(0.0..1.0) * 100.0 < p {
self.base.broker.publish(format!( self.base.broker.publish(format!(
r#"{{"event":"falukant_family_scandal_hint","relationship_id":{}}}"#, r#"{{"event":"falukant_family_scandal_hint","relationship_id":{}}}"#,
l.rel_id l.rel_id
@@ -709,7 +709,7 @@ impl FalukantFamilyWorker {
} }
let mut rng_malus_cids: Vec<i32> = Vec::new(); let mut rng_malus_cids: Vec<i32> = Vec::new();
for cid in unique_cids.iter().copied() { for cid in unique_cids.iter().copied() {
let r = self.dist.sample(&mut self.rng) * 100.0; let r = self.rng.random_range(0.0..1.0) * 100.0;
let malus = if r < 1.0 { let malus = if r < 1.0 {
-5.0 -5.0
} else if r < 3.0 { } else if r < 3.0 {

View File

@@ -177,19 +177,19 @@ fn try_resolve_one_raid(
return Ok(()); return Ok(());
} }
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
// Begegnung (Bande + Sichtbarkeit großer Ladung) // Begegnung (Bande + Sichtbarkeit großer Ladung)
let visibility_penalty = ((transport_size as f64 / vehicle_cap as f64).min(2.0) - 1.0) * 0.04; let visibility_penalty = ((transport_size as f64 / vehicle_cap as f64).min(2.0) - 1.0) * 0.04;
let encounter_p = (0.08_f64 + band_size as f64 * 0.012 + visibility_penalty).clamp(0.05, 0.45); let encounter_p = (0.08_f64 + band_size as f64 * 0.012 + visibility_penalty).clamp(0.05, 0.45);
if !rng.gen_bool(encounter_p) { if !rng.random_bool(encounter_p) {
return Ok(()); return Ok(());
} }
// Kampf // Kampf
let raid_power = band_size + rng.gen_range(0..=band_size); let raid_power = band_size + rng.random_range(0..=band_size);
let gmax = guard_count.max(1); let gmax = guard_count.max(1);
let guard_power = guard_count + rng.gen_range(0..=gmax); let guard_power = guard_count + rng.random_range(0..=gmax);
let outcome = if raid_power > (guard_power as f64 * 1.25) as i32 { let outcome = if raid_power > (guard_power as f64 * 1.25) as i32 {
"major_success" "major_success"
@@ -218,15 +218,15 @@ fn try_resolve_one_raid(
// Beuteanteil (nie Totalverlust) // Beuteanteil (nie Totalverlust)
let base_loot = match outcome { let base_loot = match outcome {
"major_success" => rng.gen_range(0.35..0.60), "major_success" => rng.random_range(0.35..0.60),
_ => rng.gen_range(0.15..0.45), _ => rng.random_range(0.15..0.45),
}; };
let guard_mul = (1.0_f64 - 0.05_f64 * (guard_count.min(12) as f64)).max(0.35); let guard_mul = (1.0_f64 - 0.05_f64 * (guard_count.min(12) as f64)).max(0.35);
let loot_share = (base_loot * guard_mul).clamp(0.05, 0.55); let loot_share = (base_loot * guard_mul).clamp(0.05, 0.55);
let mut stolen = ((transport_size as f64) * loot_share).floor() as i32; let mut stolen = ((transport_size as f64) * loot_share).floor() as i32;
stolen = stolen.clamp(1, transport_size - 1); stolen = stolen.clamp(1, transport_size - 1);
let carry_loss = rng.gen_range(0.65..0.90); let carry_loss = rng.random_range(0.65..0.90);
let mut to_store = (stolen as f64 * carry_loss).floor() as i32; let mut to_store = (stolen as f64 * carry_loss).floor() as i32;
to_store = to_store.max(0).min(stolen); to_store = to_store.max(0).min(stolen);

View File

@@ -1,8 +1,6 @@
use crate::db::{ConnectionPool, DbError}; use crate::db::{ConnectionPool, DbError};
use crate::message_broker::MessageBroker; use crate::message_broker::MessageBroker;
use rand::distributions::{Distribution, Uniform}; use rand::Rng;
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -64,8 +62,7 @@ impl StockageManager {
} }
fn add_local_stocks(pool: &ConnectionPool, broker: &MessageBroker) -> Result<(), DbError> { fn add_local_stocks(pool: &ConnectionPool, broker: &MessageBroker) -> Result<(), DbError> {
let mut rng = StdRng::from_entropy(); let mut rng = rand::rng();
let dist = Uniform::from(0.0..1.0);
let town_ids = Self::get_town_ids(pool)?; let town_ids = Self::get_town_ids(pool)?;
eprintln!("[StockageManager] Prüfe {} Städte auf neue Lager", town_ids.len()); eprintln!("[StockageManager] Prüfe {} Städte auf neue Lager", town_ids.len());
@@ -76,7 +73,7 @@ impl StockageManager {
// Das bedeutet: 2/217 ≈ 0.92% pro Stadt pro Durchlauf // Das bedeutet: 2/217 ≈ 0.92% pro Stadt pro Durchlauf
// Pro Tag (1440 Durchläufe): ~73% Chance pro Stadt // Pro Tag (1440 Durchläufe): ~73% Chance pro Stadt
// Erhöht von 2/2161 (0.0926%) auf 2/217 (0.92%) = 10x höher // Erhöht von 2/2161 (0.0926%) auf 2/217 (0.92%) = 10x höher
let roll: f64 = dist.sample(&mut rng) * 216.0_f64; let roll: f64 = rng.random_range(0.0..1.0) * 216.0_f64;
let chance = roll.round(); let chance = roll.round();
if chance <= 1.0 { if chance <= 1.0 {
eprintln!("[StockageManager] Erstelle Lager für Stadt {}", town_id); eprintln!("[StockageManager] Erstelle Lager für Stadt {}", town_id);
@@ -185,4 +182,3 @@ impl Worker for StockageManager {
} }
} }

View File

@@ -1,7 +1,6 @@
use crate::db::{ConnectionPool, DbError, Row, Rows}; use crate::db::{ConnectionPool, DbError, Row, Rows};
use crate::message_broker::MessageBroker; use crate::message_broker::MessageBroker;
use rand::distributions::{Distribution, Uniform}; use rand::prelude::{IndexedRandom, SliceRandom};
use rand::seq::SliceRandom;
use rand::Rng; use rand::Rng;
use serde_json::json; use serde_json::json;
use serde_json::Value as Json; use serde_json::Value as Json;
@@ -388,9 +387,8 @@ impl UndergroundWorker {
} }
let current = parse_i32(&rows[0], "health", 0); let current = parse_i32(&rows[0], "health", 0);
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let dist = Uniform::from(0..=current.max(0)); let new_health = rng.random_range(0..=current.max(0));
let new_health = dist.sample(&mut rng);
conn.execute("ug_update_char_health", &[&victim_id, &new_health])?; conn.execute("ug_update_char_health", &[&victim_id, &new_health])?;
@@ -705,7 +703,7 @@ impl UndergroundWorker {
})); }));
} }
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
let mut to_remove = random_ll(1, cap); let mut to_remove = random_ll(1, cap);
rows.shuffle(&mut rng); rows.shuffle(&mut rng);
@@ -867,7 +865,7 @@ impl UndergroundWorker {
let cap = max(1_i64, total / 2); let cap = max(1_i64, total / 2);
let mut to_remove = random_ll(1, cap); let mut to_remove = random_ll(1, cap);
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
rows.shuffle(&mut rng); rows.shuffle(&mut rng);
let mut affected = Vec::new(); let mut affected = Vec::new();
@@ -1107,7 +1105,7 @@ impl UndergroundWorker {
} }
let pick = *best_indices let pick = *best_indices
.as_slice() .as_slice()
.choose(&mut rand::thread_rng()) .choose(&mut rand::rng())
.unwrap_or(&scored[0].1); .unwrap_or(&scored[0].1);
let target = &lover_rows[pick]; let target = &lover_rows[pick];
@@ -1542,18 +1540,18 @@ fn parse_opt_i32(row: &Row, key: &str) -> Option<i32> {
// Hilfsfunktionen für Zufall und Parsing // Hilfsfunktionen für Zufall und Parsing
fn random_int(lo: i32, hi: i32) -> i32 { fn random_int(lo: i32, hi: i32) -> i32 {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
rng.gen_range(lo..=hi) rng.random_range(lo..=hi)
} }
fn random_ll(lo: i64, hi: i64) -> i64 { fn random_ll(lo: i64, hi: i64) -> i64 {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
rng.gen_range(lo..=hi) rng.random_range(lo..=hi)
} }
fn random_indices(n: usize, k: usize) -> Vec<usize> { fn random_indices(n: usize, k: usize) -> Vec<usize> {
let mut idx: Vec<usize> = (0..n).collect(); let mut idx: Vec<usize> = (0..n).collect();
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
idx.shuffle(&mut rng); idx.shuffle(&mut rng);
if k < idx.len() { if k < idx.len() {
idx.truncate(k); idx.truncate(k);
@@ -1562,8 +1560,8 @@ fn random_indices(n: usize, k: usize) -> Vec<usize> {
} }
fn random_double(lo: f64, hi: f64) -> f64 { fn random_double(lo: f64, hi: f64) -> f64 {
let mut rng = rand::thread_rng(); let mut rng = rand::rng();
rng.gen_range(lo..hi) rng.random_range(lo..hi)
} }
fn parse_i32(row: &Row, key: &str, default: i32) -> i32 { fn parse_i32(row: &Row, key: &str, default: i32) -> i32 {
@@ -1620,4 +1618,3 @@ fn change_falukant_user_money(
Ok(()) Ok(())
} }

View File

@@ -1,9 +1,8 @@
use crate::db::{ConnectionPool, DbError, Rows}; use crate::db::{ConnectionPool, DbError, Rows};
use crate::message_broker::MessageBroker; use crate::message_broker::MessageBroker;
use chrono::{Local, NaiveDate}; use chrono::{Local, NaiveDate};
use rand::distributions::{Distribution, Uniform};
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::SeedableRng; use rand::{Rng, SeedableRng};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -68,7 +67,6 @@ struct Character {
pub struct UserCharacterWorker { pub struct UserCharacterWorker {
base: BaseWorker, base: BaseWorker,
rng: StdRng, rng: StdRng,
dist: Uniform<f64>,
last_hourly_run: Option<Instant>, last_hourly_run: Option<Instant>,
last_pregnancy_run: Option<Instant>, last_pregnancy_run: Option<Instant>,
/// Letzter Kalendertag, an dem Ehe-Konzeption (oder Legacy-Instant) gelaufen ist — höchstens 1×/Tag. /// Letzter Kalendertag, an dem Ehe-Konzeption (oder Legacy-Instant) gelaufen ist — höchstens 1×/Tag.
@@ -86,13 +84,12 @@ pub struct UserCharacterWorker {
impl UserCharacterWorker { impl UserCharacterWorker {
pub fn new(pool: ConnectionPool, broker: MessageBroker) -> Self { pub fn new(pool: ConnectionPool, broker: MessageBroker) -> Self {
let base = BaseWorker::new("UserCharacterWorker", pool, broker); let base = BaseWorker::new("UserCharacterWorker", pool, broker);
let rng = StdRng::from_entropy(); let mut base_rng = rand::rng();
let dist = Uniform::from(0.0..1.0); let rng = StdRng::from_rng(&mut base_rng);
Self { Self {
base, base,
rng, rng,
dist,
last_hourly_run: None, last_hourly_run: None,
last_pregnancy_run: None, last_pregnancy_run: None,
last_marriage_fertility_date: None, last_marriage_fertility_date: None,
@@ -301,15 +298,14 @@ impl UserCharacterWorker {
if age >= 45 { if age >= 45 {
let probability = (0.1 + (age - 45) as f64 * 0.02).min(1.0); let probability = (0.1 + (age - 45) as f64 * 0.02).min(1.0);
if self.dist.sample(&mut self.rng) < probability { if self.rng.random_range(0.0..1.0) < probability {
let damage_dist = Uniform::from(1..=10); return -self.rng.random_range(1..=10);
return -damage_dist.sample(&mut self.rng);
} }
return 0; return 0;
} }
let probability = (age - 30) as f64 / 30.0; let probability = (age - 30) as f64 / 30.0;
if self.dist.sample(&mut self.rng) < probability { if self.rng.random_range(0.0..1.0) < probability {
-1 -1
} else { } else {
0 0
@@ -686,7 +682,7 @@ impl UserCharacterWorker {
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
.unwrap_or("marriage"); .unwrap_or("marriage");
let gender = if self.dist.sample(&mut self.rng) < 0.5 { let gender = if self.rng.random_range(0.0..1.0) < 0.5 {
"male" "male"
} else { } else {
"female" "female"
@@ -741,7 +737,7 @@ impl UserCharacterWorker {
return Ok(()); return Ok(());
} }
let gender = if self.dist.sample(&mut self.rng) < 0.5 { let gender = if self.rng.random_range(0.0..1.0) < 0.5 {
"male" "male"
} else { } else {
"female" "female"
@@ -1263,4 +1259,3 @@ impl Worker for UserCharacterWorker {
} }
} }