1#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23#[derive(Debug, Clone)]
24pub struct FoodDef {
25 pub nutrition: u32,
27 pub saturation: f32,
29 pub can_always_eat: bool,
31}
32
33impl FoodDef {
34 pub fn new(nutrition: u32, saturation: f32) -> Self {
35 Self {
36 nutrition,
37 saturation,
38 can_always_eat: false,
39 }
40 }
41
42 pub fn can_always_eat(mut self) -> Self {
43 self.can_always_eat = true;
44 self
45 }
46}
47
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50#[derive(Debug, Clone)]
51pub struct ItemDef {
52 pub id: String,
53 pub max_stack: u8,
54 pub name: Option<String>,
55 pub tooltip: Option<String>,
56 pub max_damage: u32,
58 pub fire_resistant: bool,
60 pub fuel_ticks: u32,
62 pub food: Option<FoodDef>,
64}
65
66impl ItemDef {
67 pub fn new(id: impl Into<String>) -> Self {
68 Self {
69 id: id.into(),
70 max_stack: 64,
71 name: None,
72 tooltip: None,
73 max_damage: 0,
74 fire_resistant: false,
75 fuel_ticks: 0,
76 food: None,
77 }
78 }
79
80 pub fn max_stack(mut self, n: u8) -> Self {
82 self.max_stack = n;
83 self
84 }
85
86 pub fn name(mut self, name: impl Into<String>) -> Self {
88 self.name = Some(name.into());
89 self
90 }
91
92 pub fn tooltip(mut self, tooltip: impl Into<String>) -> Self {
94 self.tooltip = Some(tooltip.into());
95 self
96 }
97
98 pub fn max_damage(mut self, durability: u32) -> Self {
100 self.max_damage = durability;
101 self
102 }
103
104 pub fn fire_resistant(mut self) -> Self {
106 self.fire_resistant = true;
107 self
108 }
109
110 pub fn fuel(mut self, ticks: u32) -> Self {
112 self.fuel_ticks = ticks;
113 self
114 }
115
116 pub fn food(mut self, food: FoodDef) -> Self {
118 self.food = Some(food);
119 self
120 }
121}
122
123#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
134#[derive(Debug, Clone)]
135pub struct ShapedRecipe {
136 pub id: String,
137 pub output: String,
138 pub count: u32,
139 rows: Vec<String>,
140 keys: Vec<(char, String)>,
141}
142
143impl ShapedRecipe {
144 pub fn new(id: impl Into<String>, output: impl Into<String>, count: u32) -> Self {
145 Self {
146 id: id.into(),
147 output: output.into(),
148 count,
149 rows: Vec::new(),
150 keys: Vec::new(),
151 }
152 }
153
154 pub fn row(mut self, pattern: impl Into<String>) -> Self {
155 self.rows.push(pattern.into());
156 self
157 }
158
159 pub fn key(mut self, symbol: char, item_id: impl Into<String>) -> Self {
160 self.keys.push((symbol, item_id.into()));
161 self
162 }
163
164 pub fn to_json(&self) -> String {
166 let pattern: String = self
167 .rows
168 .iter()
169 .map(|r| format!("\"{}\"", r))
170 .collect::<Vec<_>>()
171 .join(",");
172 let keys: String = self
173 .keys
174 .iter()
175 .map(|(ch, item)| format!("\"{}\":{{\"item\":\"{}\"}}", ch, item))
176 .collect::<Vec<_>>()
177 .join(",");
178 format!(
179 "{{\"type\":\"minecraft:crafting_shaped\",\"pattern\":[{}],\"key\":{{{}}},\"result\":{{\"item\":\"{}\",\"count\":{}}}}}",
180 pattern, keys, self.output, self.count
181 )
182 }
183
184 pub fn ns_name(&self) -> (&str, &str) {
186 self.id.split_once(':').unwrap_or(("minecraft", &self.id))
187 }
188}
189
190#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
192#[derive(Debug, Clone)]
193pub struct ShapelessRecipe {
194 pub id: String,
195 pub output: String,
196 pub count: u32,
197 pub ingredients: Vec<String>,
198}
199
200impl ShapelessRecipe {
201 pub fn new(id: impl Into<String>, output: impl Into<String>, count: u32) -> Self {
202 Self {
203 id: id.into(),
204 output: output.into(),
205 count,
206 ingredients: Vec::new(),
207 }
208 }
209
210 pub fn ingredient(mut self, item_id: impl Into<String>) -> Self {
211 self.ingredients.push(item_id.into());
212 self
213 }
214
215 pub fn to_json(&self) -> String {
216 let ingr: String = self
217 .ingredients
218 .iter()
219 .map(|i| format!("{{\"item\":\"{}\"}}", i))
220 .collect::<Vec<_>>()
221 .join(",");
222 format!(
223 "{{\"type\":\"minecraft:crafting_shapeless\",\"ingredients\":[{}],\"result\":{{\"item\":\"{}\",\"count\":{}}}}}",
224 ingr, self.output, self.count
225 )
226 }
227
228 pub fn ns_name(&self) -> (&str, &str) {
229 self.id.split_once(':').unwrap_or(("minecraft", &self.id))
230 }
231}
232
233#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
235#[derive(Debug, Clone)]
236pub struct FurnaceRecipe {
237 pub id: String,
238 pub input: String,
239 pub output: String,
240 pub count: u32,
241 pub experience: f32,
242 pub cook_time: u32,
243}
244
245impl FurnaceRecipe {
246 pub fn new(
247 id: impl Into<String>,
248 input: impl Into<String>,
249 output: impl Into<String>,
250 count: u32,
251 ) -> Self {
252 Self {
253 id: id.into(),
254 input: input.into(),
255 output: output.into(),
256 count,
257 experience: 0.1,
258 cook_time: 200,
259 }
260 }
261
262 pub fn experience(mut self, xp: f32) -> Self {
263 self.experience = xp;
264 self
265 }
266
267 pub fn cook_time(mut self, ticks: u32) -> Self {
269 self.cook_time = ticks;
270 self
271 }
272
273 pub fn to_json(&self) -> String {
274 format!(
275 "{{\"type\":\"minecraft:smelting\",\"ingredient\":{{\"item\":\"{}\"}},\"result\":\"{}\",\"experience\":{},\"cookingtime\":{}}}",
276 self.input, self.output, self.experience, self.cook_time
277 )
278 }
279
280 pub fn ns_name(&self) -> (&str, &str) {
281 self.id.split_once(':').unwrap_or(("minecraft", &self.id))
282 }
283}
284
285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
290#[derive(Debug, Clone)]
291pub struct BookRecipe {
292 pub id: String,
293 pub book: String,
294 pub ingredients: Vec<String>,
295}
296
297impl BookRecipe {
298 pub fn new(id: impl Into<String>, book: impl Into<String>) -> Self {
299 Self {
300 id: id.into(),
301 book: book.into(),
302 ingredients: Vec::new(),
303 }
304 }
305
306 pub fn ingredient(mut self, item_id: impl Into<String>) -> Self {
307 self.ingredients.push(item_id.into());
308 self
309 }
310
311 pub fn to_json(&self) -> String {
312 let ingr: String = self
313 .ingredients
314 .iter()
315 .map(|i| format!("{{\"item\":\"{}\"}}", i))
316 .collect::<Vec<_>>()
317 .join(",");
318 format!(
319 "{{\"type\":\"yog:crafting_book\",\"ingredients\":[{}],\"book\":\"{}\"}}",
320 ingr, self.book
321 )
322 }
323
324 pub fn ns_name(&self) -> (&str, &str) {
325 self.id.split_once(':').unwrap_or(("yog", &self.id))
326 }
327}
328
329#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
333#[derive(Debug, Clone)]
334pub struct ItemModifier {
335 pub id: String,
336 pub function: String,
338 pub parameters: std::collections::HashMap<String, String>,
340}
341
342impl ItemModifier {
343 pub fn new(id: impl Into<String>, function: impl Into<String>) -> Self {
344 Self {
345 id: id.into(),
346 function: function.into(),
347 parameters: std::collections::HashMap::new(),
348 }
349 }
350
351 pub fn param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
352 self.parameters.insert(key.into(), value.into());
353 self
354 }
355
356 pub fn to_json(&self) -> String {
357 let params: String = self
358 .parameters
359 .iter()
360 .map(|(k, v)| format!("\"{}\":{}", k, v))
361 .collect::<Vec<_>>()
362 .join(",");
363 format!(
364 "{{\"function\":\"{}\",{}}}",
365 self.function,
366 if params.is_empty() {
367 String::new()
368 } else {
369 params
370 }
371 )
372 }
373}
374
375#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
380#[derive(Debug, Clone)]
381pub struct StartupGrant {
382 pub id: String,
383 pub items: Vec<String>,
384 pub book: Option<String>,
385 pub command: Option<String>,
386}
387
388impl StartupGrant {
389 pub fn new(id: impl Into<String>) -> Self {
390 Self {
391 id: id.into(),
392 items: Vec::new(),
393 book: None,
394 command: None,
395 }
396 }
397
398 pub fn item(mut self, item_id: impl Into<String>) -> Self {
399 self.items.push(item_id.into());
400 self
401 }
402
403 pub fn book(mut self, book: impl Into<String>) -> Self {
404 self.book = Some(book.into());
405 self
406 }
407
408 pub fn command(mut self, cmd: impl Into<String>) -> Self {
409 self.command = Some(cmd.into());
410 self
411 }
412
413 pub fn to_json(&self) -> String {
414 let items: Vec<String> = self
415 .items
416 .iter()
417 .map(|i| format!("{{\"item\":\"{}\"}}", i))
418 .collect();
419 let mut entries = String::new();
420 if !items.is_empty() {
421 entries.push_str(&format!("[{}]", items.join(",")));
422 }
423 if let Some(book) = &self.book {
424 if !entries.is_empty() {
425 entries.push(',');
426 }
427 let book_entry = format!(
428 "{{\"type\":\"item\",\"name\":\"minecraft:written_book\",\"functions\":[{{\"function\":\"set_nbt\",\"tag\":\"{{yog_book:\\\"{}\\\"}}\"}}]}}",
429 book
430 );
431 entries.push_str(&book_entry);
432 }
433 if let Some(cmd) = &self.command {
434 if !entries.is_empty() {
435 entries.push(',');
436 }
437 entries.push_str(&format!(
438 "{{\"type\":\"minecraft:command\",\"command\":\"{}\"}}",
439 cmd.replace('"', "\\\"")
440 ));
441 }
442 format!(
443 "{{\"type\":\"yog:startup_grant\",\"entries\":{},\"id\":\"{}\"}}",
444 if entries.is_empty() {
445 "[]".to_string()
446 } else {
447 entries
448 },
449 self.id
450 )
451 }
452}
453
454#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
456#[derive(Debug, Clone)]
457pub struct AdvancementReward {
458 pub id: String,
459 pub item: String,
461 pub nbt: Option<String>,
463 pub book: Option<String>,
465}
466
467impl AdvancementReward {
468 pub fn new(id: impl Into<String>) -> Self {
469 Self {
470 id: id.into(),
471 item: "minecraft:written_book".into(),
472 nbt: None,
473 book: None,
474 }
475 }
476
477 pub fn item(mut self, item: impl Into<String>) -> Self {
478 self.item = item.into();
479 self
480 }
481
482 pub fn nbt(mut self, nbt: impl Into<String>) -> Self {
483 self.nbt = Some(nbt.into());
484 self
485 }
486
487 pub fn book(mut self, book: impl Into<String>) -> Self {
488 let book_str: String = book.into();
489 self.book = Some(book_str.clone());
490 self.nbt = Some(format!(
491 "{{yog_book:\"{}\",title:\"Yog Book\",author:\"Yog\"}}",
492 book_str
493 ));
494 self
495 }
496
497 pub fn to_json(&self) -> String {
498 let nbt_part = self
499 .nbt
500 .as_ref()
501 .map(|n| format!("{{\"function\":\"set_nbt\",\"tag\":{}}}", n));
502 let entries = if let Some(nbt_part) = nbt_part {
503 format!(
504 "[{{\"type\":\"item\",\"name\":\"{}\",\"functions\":[{}]}}]",
505 self.item, nbt_part
506 )
507 } else {
508 format!("[{{\"type\":\"item\",\"name\":\"{}\"}}]", self.item)
509 };
510 format!(
511 "{{\"type\":\"advancement_reward\",\"pools\":[{{\"rolls\":1,\"entries\":{}}}]}}",
512 entries
513 )
514 }
515}
516
517#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
521#[derive(Debug, Clone)]
522pub struct BlockDef {
523 pub id: String,
524 pub hardness: f32,
525 pub resistance: f32,
526 pub name: Option<String>,
527 pub shape: Option<[f32; 6]>,
530 pub light_level: u8,
532 pub sound: Option<String>,
536 pub requires_tool: bool,
538 pub no_collision: bool,
540 pub slipperiness: f32,
542 pub connects: bool,
548 pub connect_groups: Vec<String>,
554 pub inventory_id: Option<String>,
557}
558
559impl BlockDef {
560 pub fn new(id: impl Into<String>) -> Self {
561 Self {
562 id: id.into(),
563 hardness: 1.5,
564 resistance: 6.0,
565 name: None,
566 shape: None,
567 light_level: 0,
568 sound: None,
569 requires_tool: false,
570 no_collision: false,
571 slipperiness: 0.0,
572 connects: false,
573 connect_groups: Vec::new(),
574 inventory_id: None,
575 }
576 }
577
578 pub fn strength(mut self, hardness: f32, resistance: f32) -> Self {
580 self.hardness = hardness;
581 self.resistance = resistance;
582 self
583 }
584
585 pub fn name(mut self, name: impl Into<String>) -> Self {
587 self.name = Some(name.into());
588 self
589 }
590
591 pub fn shape(mut self, x1: f32, y1: f32, z1: f32, x2: f32, y2: f32, z2: f32) -> Self {
593 self.shape = Some([x1, y1, z1, x2, y2, z2]);
594 self
595 }
596
597 pub fn light_level(mut self, level: u8) -> Self {
599 self.light_level = level.min(15);
600 self
601 }
602
603 pub fn sound(mut self, group: impl Into<String>) -> Self {
606 self.sound = Some(group.into());
607 self
608 }
609
610 pub fn requires_tool(mut self) -> Self {
612 self.requires_tool = true;
613 self
614 }
615
616 pub fn no_collision(mut self) -> Self {
618 self.no_collision = true;
619 self
620 }
621
622 pub fn slipperiness(mut self, value: f32) -> Self {
624 self.slipperiness = value;
625 self
626 }
627
628 pub fn connects_to_neighbors(mut self) -> Self {
634 self.connects = true;
635 self
636 }
637
638 pub fn connect_groups(mut self, groups: &[&str]) -> Self {
645 self.connect_groups = groups.iter().map(|s| s.to_string()).collect();
646 self
647 }
648
649 pub fn inventory(mut self, id: impl Into<String>) -> Self {
653 self.inventory_id = Some(id.into());
654 self
655 }
656}