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 { nutrition, saturation, can_always_eat: false }
36 }
37
38 pub fn can_always_eat(mut self) -> Self {
39 self.can_always_eat = true;
40 self
41 }
42}
43
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46#[derive(Debug, Clone)]
47pub struct ItemDef {
48 pub id: String,
49 pub max_stack: u8,
50 pub name: Option<String>,
51 pub tooltip: Option<String>,
52 pub max_damage: u32,
54 pub fire_resistant: bool,
56 pub fuel_ticks: u32,
58 pub food: Option<FoodDef>,
60}
61
62impl ItemDef {
63 pub fn new(id: impl Into<String>) -> Self {
64 Self {
65 id: id.into(),
66 max_stack: 64,
67 name: None,
68 tooltip: None,
69 max_damage: 0,
70 fire_resistant: false,
71 fuel_ticks: 0,
72 food: None,
73 }
74 }
75
76 pub fn max_stack(mut self, n: u8) -> Self {
78 self.max_stack = n;
79 self
80 }
81
82 pub fn name(mut self, name: impl Into<String>) -> Self {
84 self.name = Some(name.into());
85 self
86 }
87
88 pub fn tooltip(mut self, tooltip: impl Into<String>) -> Self {
90 self.tooltip = Some(tooltip.into());
91 self
92 }
93
94 pub fn max_damage(mut self, durability: u32) -> Self {
96 self.max_damage = durability;
97 self
98 }
99
100 pub fn fire_resistant(mut self) -> Self {
102 self.fire_resistant = true;
103 self
104 }
105
106 pub fn fuel(mut self, ticks: u32) -> Self {
108 self.fuel_ticks = ticks;
109 self
110 }
111
112 pub fn food(mut self, food: FoodDef) -> Self {
114 self.food = Some(food);
115 self
116 }
117}
118
119#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
130#[derive(Debug, Clone)]
131pub struct ShapedRecipe {
132 pub id: String,
133 pub output: String,
134 pub count: u32,
135 rows: Vec<String>,
136 keys: Vec<(char, String)>,
137}
138
139impl ShapedRecipe {
140 pub fn new(id: impl Into<String>, output: impl Into<String>, count: u32) -> Self {
141 Self { id: id.into(), output: output.into(), count, rows: Vec::new(), keys: Vec::new() }
142 }
143
144 pub fn row(mut self, pattern: impl Into<String>) -> Self {
145 self.rows.push(pattern.into());
146 self
147 }
148
149 pub fn key(mut self, symbol: char, item_id: impl Into<String>) -> Self {
150 self.keys.push((symbol, item_id.into()));
151 self
152 }
153
154 pub fn to_json(&self) -> String {
156 let pattern: String = self.rows.iter()
157 .map(|r| format!("\"{}\"", r))
158 .collect::<Vec<_>>()
159 .join(",");
160 let keys: String = self.keys.iter()
161 .map(|(ch, item)| format!("\"{}\":{{\"item\":\"{}\"}}", ch, item))
162 .collect::<Vec<_>>()
163 .join(",");
164 format!(
165 "{{\"type\":\"minecraft:crafting_shaped\",\"pattern\":[{}],\"key\":{{{}}},\"result\":{{\"item\":\"{}\",\"count\":{}}}}}",
166 pattern, keys, self.output, self.count
167 )
168 }
169
170 pub fn ns_name(&self) -> (&str, &str) {
172 self.id.split_once(':').unwrap_or(("minecraft", &self.id))
173 }
174}
175
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
178#[derive(Debug, Clone)]
179pub struct ShapelessRecipe {
180 pub id: String,
181 pub output: String,
182 pub count: u32,
183 pub ingredients: Vec<String>,
184}
185
186impl ShapelessRecipe {
187 pub fn new(id: impl Into<String>, output: impl Into<String>, count: u32) -> Self {
188 Self { id: id.into(), output: output.into(), count, ingredients: Vec::new() }
189 }
190
191 pub fn ingredient(mut self, item_id: impl Into<String>) -> Self {
192 self.ingredients.push(item_id.into());
193 self
194 }
195
196 pub fn to_json(&self) -> String {
197 let ingr: String = self.ingredients.iter()
198 .map(|i| format!("{{\"item\":\"{}\"}}", i))
199 .collect::<Vec<_>>()
200 .join(",");
201 format!(
202 "{{\"type\":\"minecraft:crafting_shapeless\",\"ingredients\":[{}],\"result\":{{\"item\":\"{}\",\"count\":{}}}}}",
203 ingr, self.output, self.count
204 )
205 }
206
207 pub fn ns_name(&self) -> (&str, &str) {
208 self.id.split_once(':').unwrap_or(("minecraft", &self.id))
209 }
210}
211
212#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
214#[derive(Debug, Clone)]
215pub struct FurnaceRecipe {
216 pub id: String,
217 pub input: String,
218 pub output: String,
219 pub count: u32,
220 pub experience: f32,
221 pub cook_time: u32,
222}
223
224impl FurnaceRecipe {
225 pub fn new(
226 id: impl Into<String>,
227 input: impl Into<String>,
228 output: impl Into<String>,
229 count: u32,
230 ) -> Self {
231 Self { id: id.into(), input: input.into(), output: output.into(), count, experience: 0.1, cook_time: 200 }
232 }
233
234 pub fn experience(mut self, xp: f32) -> Self {
235 self.experience = xp;
236 self
237 }
238
239 pub fn cook_time(mut self, ticks: u32) -> Self {
241 self.cook_time = ticks;
242 self
243 }
244
245 pub fn to_json(&self) -> String {
246 format!(
247 "{{\"type\":\"minecraft:smelting\",\"ingredient\":{{\"item\":\"{}\"}},\"result\":\"{}\",\"experience\":{},\"cookingtime\":{}}}",
248 self.input, self.output, self.experience, self.cook_time
249 )
250 }
251
252 pub fn ns_name(&self) -> (&str, &str) {
253 self.id.split_once(':').unwrap_or(("minecraft", &self.id))
254 }
255}
256
257#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
262#[derive(Debug, Clone)]
263pub struct BookRecipe {
264 pub id: String,
265 pub book: String,
266 pub ingredients: Vec<String>,
267}
268
269impl BookRecipe {
270 pub fn new(id: impl Into<String>, book: impl Into<String>) -> Self {
271 Self { id: id.into(), book: book.into(), ingredients: Vec::new() }
272 }
273
274 pub fn ingredient(mut self, item_id: impl Into<String>) -> Self {
275 self.ingredients.push(item_id.into());
276 self
277 }
278
279 pub fn to_json(&self) -> String {
280 let ingr: String = self.ingredients.iter()
281 .map(|i| format!("{{\"item\":\"{}\"}}", i))
282 .collect::<Vec<_>>()
283 .join(",");
284 format!(
285 "{{\"type\":\"yog:crafting_book\",\"ingredients\":[{}],\"book\":\"{}\"}}",
286 ingr, self.book
287 )
288 }
289
290 pub fn ns_name(&self) -> (&str, &str) {
291 self.id.split_once(':').unwrap_or(("yog", &self.id))
292 }
293}
294
295#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
299#[derive(Debug, Clone)]
300pub struct ItemModifier {
301 pub id: String,
302 pub function: String,
304 pub parameters: std::collections::HashMap<String, String>,
306}
307
308impl ItemModifier {
309 pub fn new(id: impl Into<String>, function: impl Into<String>) -> Self {
310 Self { id: id.into(), function: function.into(), parameters: std::collections::HashMap::new() }
311 }
312
313 pub fn param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
314 self.parameters.insert(key.into(), value.into());
315 self
316 }
317
318 pub fn to_json(&self) -> String {
319 let params: String = self.parameters.iter()
320 .map(|(k, v)| format!("\"{}\":{}", k, v))
321 .collect::<Vec<_>>()
322 .join(",");
323 format!(
324 "{{\"function\":\"{}\",{}}}",
325 self.function, if params.is_empty() { String::new() } else { params }
326 )
327 }
328}
329
330#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
335#[derive(Debug, Clone)]
336pub struct StartupGrant {
337 pub id: String,
338 pub items: Vec<String>,
339 pub book: Option<String>,
340 pub command: Option<String>,
341}
342
343impl StartupGrant {
344 pub fn new(id: impl Into<String>) -> Self {
345 Self { id: id.into(), items: Vec::new(), book: None, command: None }
346 }
347
348 pub fn item(mut self, item_id: impl Into<String>) -> Self {
349 self.items.push(item_id.into());
350 self
351 }
352
353 pub fn book(mut self, book: impl Into<String>) -> Self {
354 self.book = Some(book.into());
355 self
356 }
357
358 pub fn command(mut self, cmd: impl Into<String>) -> Self {
359 self.command = Some(cmd.into());
360 self
361 }
362
363 pub fn to_json(&self) -> String {
364 let items: Vec<String> = self.items.iter().map(|i| format!("{{\"item\":\"{}\"}}", i)).collect();
365 let mut entries = String::new();
366 if !items.is_empty() {
367 entries.push_str(&format!("[{}]", items.join(",")));
368 }
369 if let Some(book) = &self.book {
370 if !entries.is_empty() {
371 entries.push(',');
372 }
373 let book_entry = format!(
374 "{{\"type\":\"item\",\"name\":\"minecraft:written_book\",\"functions\":[{{\"function\":\"set_nbt\",\"tag\":\"{{yog_book:\\\"{}\\\"}}\"}}]}}",
375 book
376 );
377 entries.push_str(&book_entry);
378 }
379 if let Some(cmd) = &self.command {
380 if !entries.is_empty() {
381 entries.push(',');
382 }
383 entries.push_str(&format!(
384 "{{\"type\":\"minecraft:command\",\"command\":\"{}\"}}",
385 cmd.replace('"', "\\\"")
386 ));
387 }
388 format!(
389 "{{\"type\":\"yog:startup_grant\",\"entries\":{},\"id\":\"{}\"}}",
390 if entries.is_empty() { "[]".to_string() } else { entries },
391 self.id
392 )
393 }
394}
395
396#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
398#[derive(Debug, Clone)]
399pub struct AdvancementReward {
400 pub id: String,
401 pub item: String,
403 pub nbt: Option<String>,
405 pub book: Option<String>,
407}
408
409impl AdvancementReward {
410 pub fn new(id: impl Into<String>) -> Self {
411 Self { id: id.into(), item: "minecraft:written_book".into(), nbt: None, book: None }
412 }
413
414 pub fn item(mut self, item: impl Into<String>) -> Self {
415 self.item = item.into();
416 self
417 }
418
419 pub fn nbt(mut self, nbt: impl Into<String>) -> Self {
420 self.nbt = Some(nbt.into());
421 self
422 }
423
424 pub fn book(mut self, book: impl Into<String>) -> Self {
425 let book_str: String = book.into();
426 self.book = Some(book_str.clone());
427 self.nbt = Some(format!("{{yog_book:\"{}\",title:\"Yog Book\",author:\"Yog\"}}", book_str));
428 self
429 }
430
431 pub fn to_json(&self) -> String {
432 let nbt_part = self.nbt.as_ref().map(|n| format!("{{\"function\":\"set_nbt\",\"tag\":{}}}", n));
433 let entries = if let Some(nbt_part) = nbt_part {
434 format!("[{{\"type\":\"item\",\"name\":\"{}\",\"functions\":[{}]}}]", self.item, nbt_part)
435 } else {
436 format!("[{{\"type\":\"item\",\"name\":\"{}\"}}]", self.item)
437 };
438 format!(
439 "{{\"type\":\"advancement_reward\",\"pools\":[{{\"rolls\":1,\"entries\":{}}}]}}",
440 entries
441 )
442 }
443}
444
445#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
449#[derive(Debug, Clone)]
450pub struct BlockDef {
451 pub id: String,
452 pub hardness: f32,
453 pub resistance: f32,
454 pub name: Option<String>,
455 pub shape: Option<[f32; 6]>,
458 pub light_level: u8,
460 pub sound: Option<String>,
464 pub requires_tool: bool,
466 pub no_collision: bool,
468 pub slipperiness: f32,
470}
471
472impl BlockDef {
473 pub fn new(id: impl Into<String>) -> Self {
474 Self {
475 id: id.into(),
476 hardness: 1.5,
477 resistance: 6.0,
478 name: None,
479 shape: None,
480 light_level: 0,
481 sound: None,
482 requires_tool: false,
483 no_collision: false,
484 slipperiness: 0.0,
485 }
486 }
487
488 pub fn strength(mut self, hardness: f32, resistance: f32) -> Self {
490 self.hardness = hardness;
491 self.resistance = resistance;
492 self
493 }
494
495 pub fn name(mut self, name: impl Into<String>) -> Self {
497 self.name = Some(name.into());
498 self
499 }
500
501 pub fn shape(mut self, x1: f32, y1: f32, z1: f32, x2: f32, y2: f32, z2: f32) -> Self {
503 self.shape = Some([x1, y1, z1, x2, y2, z2]);
504 self
505 }
506
507 pub fn light_level(mut self, level: u8) -> Self {
509 self.light_level = level.min(15);
510 self
511 }
512
513 pub fn sound(mut self, group: impl Into<String>) -> Self {
516 self.sound = Some(group.into());
517 self
518 }
519
520 pub fn requires_tool(mut self) -> Self {
522 self.requires_tool = true;
523 self
524 }
525
526 pub fn no_collision(mut self) -> Self {
528 self.no_collision = true;
529 self
530 }
531
532 pub fn slipperiness(mut self, value: f32) -> Self {
534 self.slipperiness = value;
535 self
536 }
537}