steel_registry/fluid/
mod.rs1use crate::{TaggedRegistryExt, vanilla_fluid_tags::FluidTag, vanilla_fluids};
4use rustc_hash::FxHashMap;
5use steel_utils::Identifier;
6
7#[derive(Debug)]
9pub struct Fluid {
10 pub key: Identifier,
12 pub is_empty: bool,
14 pub is_source: bool,
16 pub block: Identifier,
18 pub bucket_item: Identifier,
20 pub source_fluid: Option<Identifier>,
22 pub flowing_fluid: Option<Identifier>,
24 pub tick_delay: u32,
26 pub explosion_resistance: f32,
28}
29
30impl Fluid {
31 pub fn has_tag(&'static self, tag: &Identifier) -> bool {
33 REGISTRY.fluids.is_in_tag(self, tag)
34 }
35}
36
37pub type FluidRef = &'static Fluid;
38
39impl PartialEq for FluidRef {
40 fn eq(&self, other: &Self) -> bool {
41 self.key == other.key
42 }
43}
44
45impl Eq for FluidRef {}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub struct FluidState {
52 pub fluid_id: FluidRef,
54 pub amount: u8,
56 pub falling: bool,
58}
59
60impl FluidState {
61 pub const EMPTY: Self = Self {
63 fluid_id: &vanilla_fluids::EMPTY,
64 amount: 0,
65 falling: false,
66 };
67
68 #[must_use]
70 pub const fn new(fluid: FluidRef, amount: u8, falling: bool) -> Self {
71 Self {
72 fluid_id: fluid,
73 amount,
74 falling,
75 }
76 }
77
78 #[must_use]
80 pub const fn source(fluid: FluidRef) -> Self {
81 Self {
82 fluid_id: fluid,
83 amount: 8,
84 falling: false,
85 }
86 }
87
88 #[must_use]
90 pub const fn flowing(fluid: FluidRef, amount: u8, falling: bool) -> Self {
91 Self {
92 fluid_id: fluid,
93 amount,
94 falling,
95 }
96 }
97
98 #[must_use]
100 pub const fn is_empty(&self) -> bool {
101 self.fluid_id.is_empty || self.amount == 0
102 }
103
104 #[must_use]
110 pub const fn is_source(&self) -> bool {
111 self.fluid_id.is_source && self.amount == 8 && !self.falling
112 }
113
114 #[must_use]
116 pub fn own_height(&self) -> f32 {
117 if self.is_empty() {
118 0.0
119 } else {
120 self.amount as f32 / 9.0
121 }
122 }
123
124 #[must_use]
130 pub const fn from_block_level(fluid: FluidRef, level: u8) -> Self {
131 if level == 0 {
132 Self::source(fluid)
134 } else if level <= 7 {
135 Self::flowing(fluid, 8 - level, false)
137 } else {
138 let amount = 16u8.saturating_sub(level).max(1);
141 Self::flowing(fluid, amount, true)
142 }
143 }
144
145 #[must_use]
147 pub const fn to_block_level(self) -> u8 {
148 if self.is_source() {
149 0
150 } else if self.falling {
151 8
152 } else {
153 8 - self.amount
155 }
156 }
157}
158
159pub struct FluidRegistry {
161 fluids_by_id: Vec<FluidRef>,
162 fluids_by_key: FxHashMap<Identifier, usize>,
163 tags: FxHashMap<Identifier, Vec<Identifier>>,
164 allows_registering: bool,
165}
166
167impl Default for FluidRegistry {
168 fn default() -> Self {
169 Self::new()
170 }
171}
172
173impl FluidRegistry {
174 #[must_use]
176 pub fn new() -> Self {
177 Self {
178 fluids_by_id: Vec::new(),
179 fluids_by_key: FxHashMap::default(),
180 tags: FxHashMap::default(),
181 allows_registering: true,
182 }
183 }
184
185 pub fn register(&mut self, fluid: FluidRef) -> usize {
187 assert!(
188 self.allows_registering,
189 "Cannot register fluids after the registry has been frozen"
190 );
191
192 let id = self.fluids_by_id.len();
193 self.fluids_by_key.insert(fluid.key.clone(), id);
194 self.fluids_by_id.push(fluid);
195 id
196 }
197
198 pub fn iter(&self) -> impl Iterator<Item = (usize, FluidRef)> + '_ {
200 self.fluids_by_id
201 .iter()
202 .enumerate()
203 .map(|(id, &fluid)| (id, fluid))
204 }
205}
206
207crate::impl_registry!(FluidRegistry, Fluid, fluids_by_id, fluids_by_key, fluids);
208crate::impl_tagged_registry!(FluidRegistry, fluids_by_key, "fluid");
209
210use crate::REGISTRY;
211
212#[must_use]
214pub fn is_water_fluid(fluid: FluidRef) -> bool {
215 !fluid.is_empty && fluid.has_tag(&FluidTag::WATER)
216}
217
218#[must_use]
220pub fn is_lava_fluid(fluid: FluidRef) -> bool {
221 !fluid.is_empty && fluid.has_tag(&FluidTag::LAVA)
222}
223
224pub trait FluidStateExt {
226 fn is_water(&self) -> bool;
228 fn is_lava(&self) -> bool;
230}
231
232impl FluidStateExt for FluidState {
233 fn is_water(&self) -> bool {
234 is_water_fluid(self.fluid_id)
235 }
236 fn is_lava(&self) -> bool {
237 is_lava_fluid(self.fluid_id)
238 }
239}