veloren_rtsim/rule/
cleanup.rs1use crate::{RtState, Rule, RuleError, event::OnTick};
2use rand::prelude::*;
3use rand_chacha::ChaChaRng;
4
5const NPC_SENTIMENT_TICK_SKIP: u64 = 30;
7const NPC_CLEANUP_TICK_SKIP: u64 = 100;
8const FACTION_CLEANUP_TICK_SKIP: u64 = 30;
9const SITE_CLEANUP_TICK_SKIP: u64 = 30;
10
11pub struct CleanUp;
16
17impl Rule for CleanUp {
18 fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
19 rtstate.bind::<Self, OnTick>(|ctx| {
20 let data = &mut *ctx.state.data_mut();
21 let mut rng = ChaChaRng::from_seed(thread_rng().gen::<[u8; 32]>());
22
23 data.npcs
27 .iter_mut()
28 .filter(|(_, npc)| (npc.seed as u64 + ctx.event.tick) % NPC_SENTIMENT_TICK_SKIP == 0)
30 .for_each(|(_, npc)| npc.sentiments.decay(&mut rng, ctx.event.dt * NPC_SENTIMENT_TICK_SKIP as f32));
31
32 data.npcs
36 .retain(|npc_id, npc| if npc.is_dead() {
37 if let Some(home) = npc.home.and_then(|home| data.sites.get_mut(home)) {
39 home.population.remove(&npc_id);
40 }
41 tracing::debug!(?npc_id, "Cleaning up dead NPC");
42 false
43 } else {
44 true
45 });
46
47 data.sites.iter_mut()
49 .filter(|(_, site)| (site.seed as u64 + ctx.event.tick) % SITE_CLEANUP_TICK_SKIP == 0)
50 .for_each(|(id, site)| {
51 site.population.retain(|npc_id| {
52 data.npcs.get(*npc_id).is_some_and(|npc| npc.home == Some(id))
53 });
54 });
55
56 data.npcs
58 .iter_mut()
59 .filter(|(_, npc)| (npc.seed as u64 + ctx.event.tick) % NPC_CLEANUP_TICK_SKIP == 0)
60 .for_each(|(_, npc)| npc.cleanup(&data.reports));
61
62 data.factions
64 .iter_mut()
65 .filter(|(_, faction)| (faction.seed as u64 + ctx.event.tick) % FACTION_CLEANUP_TICK_SKIP == 0)
66 .for_each(|(_, faction)| faction.cleanup());
67
68 data.sites
70 .iter_mut()
71 .filter(|(_, site)| (site.seed as u64 + ctx.event.tick) % SITE_CLEANUP_TICK_SKIP == 0)
72 .for_each(|(_, site)| site.cleanup(&data.reports));
73
74 data.reports.cleanup(data.time_of_day);
76 });
77
78 Ok(Self)
79 }
80}