steel_core/entity/
spawn.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum EntitySpawnReason {
4 Natural,
5 ChunkGeneration,
6 Spawner,
7 Structure,
8 Breeding,
9 MobSummoned,
10 Jockey,
11 Event,
12 Conversion,
13 Reinforcement,
14 Triggered,
15 Bucket,
16 SpawnItemUse,
17 Command,
18 Dispenser,
19 Patrol,
20 TrialSpawner,
21 Load,
22 DimensionTravel,
23}
24
25impl EntitySpawnReason {
26 #[must_use]
27 pub const fn is_spawner(self) -> bool {
28 matches!(self, Self::Spawner | Self::TrialSpawner)
29 }
30
31 #[must_use]
32 pub const fn ignores_light_requirements(self) -> bool {
33 matches!(self, Self::TrialSpawner)
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq)]
38pub enum SpawnGroupData {
39 AgeableMob(AgeableMobGroupData),
40}
41
42#[derive(Debug, Clone, Copy, PartialEq)]
43pub struct AgeableMobGroupData {
44 group_size: i32,
45 should_spawn_baby: bool,
46 baby_spawn_chance: f32,
47}
48
49impl AgeableMobGroupData {
50 pub const DEFAULT_BABY_SPAWN_CHANCE: f32 = 0.05;
51
52 #[must_use]
53 pub const fn new(should_spawn_baby: bool, baby_spawn_chance: f32) -> Self {
54 Self {
55 group_size: 0,
56 should_spawn_baby,
57 baby_spawn_chance,
58 }
59 }
60
61 #[must_use]
62 pub const fn with_should_spawn_baby(should_spawn_baby: bool) -> Self {
63 Self::new(should_spawn_baby, Self::DEFAULT_BABY_SPAWN_CHANCE)
64 }
65
66 #[must_use]
67 pub const fn with_baby_spawn_chance(baby_spawn_chance: f32) -> Self {
68 Self::new(true, baby_spawn_chance)
69 }
70
71 #[must_use]
72 pub const fn group_size(self) -> i32 {
73 self.group_size
74 }
75
76 #[must_use]
77 pub const fn should_spawn_baby(self) -> bool {
78 self.should_spawn_baby
79 }
80
81 #[must_use]
82 pub const fn baby_spawn_chance(self) -> f32 {
83 self.baby_spawn_chance
84 }
85
86 pub const fn increase_group_size_by_one(&mut self) {
87 self.group_size += 1;
88 }
89
90 #[must_use]
91 pub const fn needs_baby_spawn_roll(self) -> bool {
92 self.should_spawn_baby && self.group_size > 0
93 }
94
95 pub fn finalize_ageable_spawn(&mut self, baby_roll: impl FnOnce() -> f32) -> bool {
96 let spawn_baby = self.needs_baby_spawn_roll() && baby_roll() <= self.baby_spawn_chance;
97 self.increase_group_size_by_one();
98 spawn_baby
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::AgeableMobGroupData;
105
106 #[test]
107 fn ageable_group_data_increments_before_later_baby_rolls_can_apply() {
108 let mut group_data = AgeableMobGroupData::with_should_spawn_baby(true);
109
110 assert!(!group_data.finalize_ageable_spawn(|| {
111 panic!("first group member should not roll for baby spawn")
112 }));
113 assert_eq!(group_data.group_size(), 1);
114
115 assert!(group_data.finalize_ageable_spawn(|| 0.05));
116 assert_eq!(group_data.group_size(), 2);
117 }
118
119 #[test]
120 fn ageable_group_data_can_disable_baby_spawns() {
121 let mut group_data = AgeableMobGroupData::with_should_spawn_baby(false);
122
123 assert!(
124 !group_data
125 .finalize_ageable_spawn(|| { panic!("disabled baby spawning should not roll") })
126 );
127 assert!(
128 !group_data
129 .finalize_ageable_spawn(|| { panic!("disabled baby spawning should not roll") })
130 );
131 assert_eq!(group_data.group_size(), 2);
132 }
133}