dfraw_json_parser/parser/plant/
raw.rs1use serde::{Deserialize, Serialize};
2use slug::slugify;
3use tracing::{debug, warn};
4
5use crate::parser::{
6 biome,
7 helpers::parse_min_max_range,
8 material::{Material, PROPERTY_TOKEN_MAP, USAGE_TOKEN_MAP},
9 plant_growth::{
10 PlantGrowth, Token as GrowthToken, TypeToken as GrowthTypeToken,
11 TOKEN_MAP as GROWTH_TOKEN_MAP, TYPE_TOKEN_MAP as GROWTH_TYPE_TOKEN_MAP,
12 },
13 serializer_helper,
14 shrub::{Shrub, TOKEN_MAP as SHRUB_TOKEN_MAP},
15 tree::{Tree, TOKEN_MAP as TREE_TOKEN_MAP},
16 Name, ObjectType, {clean_search_vec, Searchable}, {RawMetadata, RawObject},
17};
18
19use super::{phf_table::PLANT_TOKENS, tokens::PlantTag};
20
21#[allow(clippy::module_name_repetitions)]
23#[derive(Serialize, Deserialize, Debug, Clone, Default, specta::Type)]
24#[serde(rename_all = "camelCase")]
25pub struct Plant {
26 #[serde(skip_serializing_if = "Option::is_none")]
28 metadata: Option<RawMetadata>,
29 identifier: String,
30 object_id: String,
31
32 name: Name,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pref_strings: Option<Vec<String>>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 tags: Option<Vec<PlantTag>>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
42 underground_depth: Option<[u32; 2]>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 frequency: Option<u32>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 biomes: Option<Vec<biome::Token>>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 growths: Option<Vec<PlantGrowth>>,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 tree_details: Option<Tree>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 shrub_details: Option<Shrub>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
61 materials: Option<Vec<Material>>,
62}
63
64impl Plant {
65 #[must_use]
71 pub fn empty() -> Self {
72 Self {
73 metadata: Some(
74 RawMetadata::default()
75 .with_object_type(ObjectType::Plant)
76 .with_hidden(true),
77 ),
78 frequency: Some(50),
79 ..Self::default()
80 }
81 }
82 #[must_use]
93 pub fn new(identifier: &str, metadata: &RawMetadata) -> Self {
94 Self {
95 identifier: String::from(identifier),
96 metadata: Some(metadata.clone()),
97 frequency: Some(50),
98 object_id: format!(
99 "{}-{}-{}",
100 metadata.get_raw_identifier(),
101 "PLANT",
102 slugify(identifier)
103 ),
104 ..Self::default()
105 }
106 }
107 #[must_use]
113 pub fn get_biomes(&self) -> Vec<biome::Token> {
114 self.biomes
115 .as_ref()
116 .map_or_else(Vec::new, std::clone::Clone::clone)
117 }
118
119 #[must_use]
134 pub fn cleaned(&self) -> Self {
135 let mut cleaned = self.clone();
136
137 if let Some(metadata) = &cleaned.metadata {
138 if metadata.is_hidden() {
139 cleaned.metadata = None;
140 }
141 }
142
143 if let Some(pref_strings) = &cleaned.pref_strings {
144 if pref_strings.is_empty() {
145 cleaned.pref_strings = None;
146 }
147 }
148
149 if let Some(tags) = &cleaned.tags {
150 if tags.is_empty() {
151 cleaned.tags = None;
152 }
153 }
154
155 if serializer_helper::min_max_is_zeroes(&cleaned.underground_depth) {
156 cleaned.underground_depth = None;
157 }
158
159 if serializer_helper::is_default_frequency(cleaned.frequency) {
160 cleaned.frequency = None;
161 }
162
163 if let Some(biomes) = &cleaned.biomes {
164 if biomes.is_empty() {
165 cleaned.biomes = None;
166 }
167 }
168
169 if let Some(growths) = &cleaned.growths {
170 let mut cleaned_growths = Vec::new();
171 for growth in growths {
172 cleaned_growths.push(growth.cleaned());
173 }
174 cleaned.growths = Some(cleaned_growths);
175 }
176
177 if let Some(materials) = &cleaned.materials {
178 let mut cleaned_materials = Vec::new();
179 for material in materials {
180 cleaned_materials.push(material.cleaned());
181 }
182 if cleaned_materials.is_empty() {
183 cleaned.materials = None;
184 }
185 cleaned.materials = Some(cleaned_materials);
186 }
187
188 cleaned
189 }
190 pub fn add_tag(&mut self, tag: PlantTag) {
198 if self.tags.is_none() {
199 self.tags = Some(Vec::new());
200 }
201 if let Some(tags) = self.tags.as_mut() {
202 tags.push(tag);
203 } else {
204 warn!(
205 "Plant::add_tag: ({}) Failed to add tag {:?}",
206 self.identifier, tag
207 );
208 }
209 }
210}
211
212#[typetag::serde]
213impl RawObject for Plant {
214 fn get_metadata(&self) -> RawMetadata {
215 self.metadata.as_ref().map_or_else(
216 || {
217 warn!(
218 "PlantParsing: Failed to get metadata for plant {}",
219 self.identifier
220 );
221 RawMetadata::default()
222 .with_object_type(ObjectType::Plant)
223 .with_hidden(true)
224 },
225 std::clone::Clone::clone,
226 )
227 }
228 fn get_identifier(&self) -> &str {
229 &self.identifier
230 }
231 fn get_name(&self) -> &str {
232 self.name.get_singular()
233 }
234 fn is_empty(&self) -> bool {
235 self.identifier.is_empty()
236 }
237
238 fn clean_self(&mut self) {
239 *self = self.cleaned();
240 }
241 fn get_type(&self) -> &ObjectType {
242 &ObjectType::Plant
243 }
244 #[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
245 fn parse_tag(&mut self, key: &str, value: &str) {
246 if (PROPERTY_TOKEN_MAP.contains_key(key) || USAGE_TOKEN_MAP.contains_key(key))
247 && !key.eq("USE_MATERIAL_TEMPLATE")
248 {
249 if let Some(materials) = self.materials.as_mut() {
251 if let Some(material) = materials.last_mut() {
252 material.parse_tag(key, value);
253 } else {
254 warn!(
255 "PlantParsing: Failed to find material to add tag {} with value {}",
256 key, value
257 );
258 }
259 }
260 return;
261 }
262
263 if TREE_TOKEN_MAP.contains_key(key) {
264 if self.tree_details.is_none() {
265 self.tree_details = Some(Tree::new(value));
266 }
267 #[allow(clippy::unwrap_used)]
268 let tree = self.tree_details.as_mut().unwrap();
269 tree.parse_tag(key, value);
270 return;
271 }
272
273 if GROWTH_TOKEN_MAP.contains_key(key) {
274 if self.growths.is_none() {
275 self.growths = Some(Vec::new());
276 }
277 let token = GROWTH_TOKEN_MAP.get(key).unwrap_or(&GrowthToken::Unknown);
278 if token == &GrowthToken::Growth {
279 let growth_type = GROWTH_TYPE_TOKEN_MAP
281 .get(value)
282 .unwrap_or(&GrowthTypeToken::None)
283 .clone();
284 let growth = PlantGrowth::new(growth_type);
285 if let Some(growths) = self.growths.as_mut() {
286 growths.push(growth);
287 }
288 return;
289 }
290 if let Some(growths) = self.growths.as_mut() {
292 if let Some(growth) = growths.last_mut() {
293 growth.parse_tag(key, value);
294 } else {
295 warn!(
296 "PlantParsing: Failed to find growth to add tag {} with value {}",
297 key, value
298 );
299 }
300 }
301 return;
302 }
303
304 if SHRUB_TOKEN_MAP.contains_key(key) {
305 if self.shrub_details.is_none() {
306 self.shrub_details = Some(Shrub::new());
307 }
308 self.shrub_details
309 .as_mut()
310 .unwrap_or(&mut Shrub::default())
311 .parse_tag(key, value);
312 return;
313 }
314
315 if !PLANT_TOKENS.contains_key(key) {
316 debug!("PlantParsing: Unknown tag {} with value {}", key, value);
317 return;
318 }
319
320 let Some(tag) = PLANT_TOKENS.get(key) else {
321 warn!(
322 "PlantParsing: called `Option::unwrap()` on a `None` value for presumed plant tag: {}",
323 key
324 );
325 return;
326 };
327
328 match tag {
329 PlantTag::NameSingular => {
330 self.name.update_singular(value);
331 }
332 PlantTag::NamePlural => {
333 self.name.update_plural(value);
334 }
335 PlantTag::NameAdjective => {
336 self.name.update_adjective(value);
337 }
338 PlantTag::AllNames => {
339 self.name = Name::from_value(value);
340 }
341 PlantTag::PrefString => {
342 if self.pref_strings.is_none() {
343 self.pref_strings = Some(Vec::new());
344 }
345 if let Some(pref_strings) = &mut self.pref_strings {
346 pref_strings.push(String::from(value));
347 }
348 }
349 PlantTag::Biome => {
350 let Some(biome) = biome::TOKEN_MAP.get(value) else {
351 warn!(
352 "PlantParsing: called `Option::unwrap()` on a `None` value for presumed biome: {}",
353 value
354 );
355 return;
356 };
357 if self.biomes.is_none() {
358 self.biomes = Some(Vec::new());
359 }
360 if let Some(biomes) = &mut self.biomes {
361 biomes.push(biome.clone());
362 }
363 }
364 PlantTag::UndergroundDepth => {
365 self.underground_depth = Some(parse_min_max_range(value).unwrap_or([0, 0]));
366 }
367 PlantTag::Frequency => {
368 self.frequency = Some(value.parse::<u32>().unwrap_or(50));
369 }
370 PlantTag::UseMaterialTemplate => {
371 if self.materials.is_none() {
372 self.materials = Some(Vec::new());
373 }
374 if let Some(materials) = self.materials.as_mut() {
375 materials.push(Material::use_material_template_from_value(value));
376 }
377 }
378 PlantTag::UseMaterial => {
379 if self.materials.is_none() {
380 self.materials = Some(Vec::new());
381 }
382 if let Some(materials) = self.materials.as_mut() {
383 materials.push(Material::use_material_from_value(value));
384 }
385 }
386 PlantTag::BasicMaterial => {
387 if self.materials.is_none() {
388 self.materials = Some(Vec::new());
389 }
390 if let Some(materials) = self.materials.as_mut() {
391 materials.push(Material::basic_material_from_value(value));
392 }
393 }
394 PlantTag::Material => {
395 if self.materials.is_none() {
396 self.materials = Some(Vec::new());
397 }
398 if let Some(materials) = self.materials.as_mut() {
399 materials.push(Material::from_value(value));
400 }
401 }
402 _ => {
403 self.add_tag(tag.clone());
404 }
405 }
406 }
407
408 fn get_object_id(&self) -> &str {
409 &self.object_id
410 }
411}
412
413impl Searchable for Plant {
414 fn get_search_vec(&self) -> Vec<String> {
415 let mut vec = Vec::new();
416
417 vec.push(self.get_identifier().to_string());
418 vec.extend(self.name.as_vec());
419 if let Some(pref_strings) = &self.pref_strings {
420 vec.extend(pref_strings.clone());
421 }
422 if let Some(biomes) = &self.biomes {
423 vec.extend(biomes.iter().map(std::string::ToString::to_string));
424 }
425 if let Some(tags) = &self.tags {
426 vec.extend(tags.iter().map(std::string::ToString::to_string));
427 }
428 if let Some(growths) = &self.growths {
429 vec.extend(growths.iter().flat_map(Searchable::get_search_vec));
430 }
431 if let Some(materials) = &self.materials {
432 vec.extend(materials.iter().flat_map(Searchable::get_search_vec));
433 }
434
435 clean_search_vec(vec.as_slice())
436 }
437}