1use yog_data::kinds::Item;
4use yog_data::with::{Opt, RefTo};
5use yog_data::{Reader, Schema, Shape, Value, ValueRef};
6use yog_ids::units::{BLOCK_PIXELS, MAX_STACK};
7
8use super::refs::{BlockTag, LevelRef, OneOrMany, SoundRef, ToolTag};
9
10#[derive(Schema, Debug, Clone, Copy, PartialEq, Eq)]
11pub enum RenderLayer {
12 Solid,
13 Cutout,
14 CutoutMipped,
15 Translucent,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq)]
21pub enum BlockShape {
22 Auto,
23 Full,
24 Box([f64; 6]),
25}
26
27impl Schema for BlockShape {
28 fn shape() -> Shape {
29 Shape::Any
30 }
31 fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
32 match v {
33 ValueRef::Str(s) if *s == "auto" => Some(BlockShape::Auto),
34 ValueRef::Str(s) if *s == "full" => Some(BlockShape::Full),
35 ValueRef::List(_) => {
36 let b = <[f64; 6]>::read(v, cx)?;
37 if b.iter()
38 .any(|n| !(0.0..=f64::from(BLOCK_PIXELS)).contains(n))
39 {
40 cx.problem("a box is [x1, y1, z1, x2, y2, z2] in pixels, 0–16");
41 return None;
42 }
43 Some(BlockShape::Box(b))
44 }
45 other => {
46 cx.expected(
47 "\"auto\" (the model's bounds), \"full\" or [x1, y1, z1, x2, y2, z2] in pixels",
48 other,
49 );
50 None
51 }
52 }
53 }
54 fn write(&self) -> Value {
55 match self {
56 BlockShape::Auto => Value::from("auto"),
57 BlockShape::Full => Value::from("full"),
58 BlockShape::Box(b) => b.write(),
59 }
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq)]
65pub enum DropCount {
66 Exactly(f64),
67 Between(f64, f64),
68}
69
70impl Schema for DropCount {
71 fn shape() -> Shape {
72 Shape::Any
73 }
74 fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
75 let n = match v {
76 ValueRef::List(_) => {
77 let [lo, hi] = <[f64; 2]>::read(v, cx)?;
78 (lo, hi, DropCount::Between(lo, hi))
79 }
80 _ => {
81 let n = f64::read(v, cx)?;
82 (n, n, DropCount::Exactly(n))
83 }
84 };
85 let stack = 0.0..=f64::from(MAX_STACK);
86 if !stack.contains(&n.0) || !stack.contains(&n.1) || n.0 > n.1 {
87 cx.problem("a count is 1–64, or [min, max] within 0–64");
88 return None;
89 }
90 Some(n.2)
91 }
92 fn write(&self) -> Value {
93 match *self {
94 DropCount::Exactly(n) => Value::Float(n),
95 DropCount::Between(a, b) => Value::List(vec![Value::Float(a), Value::Float(b)]),
96 }
97 }
98}
99
100#[derive(Schema, Debug, Clone)]
102pub struct DropItem {
103 #[data(with = "Opt<RefTo<Item>>")]
104 pub item: Option<String>,
105 pub count: Option<DropCount>,
106}
107
108#[derive(Debug, Clone)]
110pub enum Drops {
111 Itself,
112 Nothing,
113 Item(DropItem),
114}
115
116impl Schema for Drops {
117 fn shape() -> Shape {
118 Shape::Any
119 }
120 fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
121 match v {
122 ValueRef::Str(s) if *s == "self" => Some(Drops::Itself),
123 ValueRef::Str(s) if *s == "none" => Some(Drops::Nothing),
124 ValueRef::Map(_) => DropItem::read(v, cx).map(Drops::Item),
125 other => {
126 cx.expected(
127 "\"self\", \"none\" or { item: \"@item:ns:item\", count: [1, 3] }",
128 other,
129 );
130 None
131 }
132 }
133 }
134 fn write(&self) -> Value {
135 match self {
136 Drops::Itself => Value::from("self"),
137 Drops::Nothing => Value::from("none"),
138 Drops::Item(d) => d.write(),
139 }
140 }
141}
142
143#[derive(Schema, Debug, Clone, Copy, PartialEq, Eq, Default)]
145pub enum TriggeredBy {
146 #[default]
148 Everything,
149 Mobs,
151}
152
153#[derive(Schema, Debug, Clone, Default)]
155pub struct BlockProps {
156 #[data(range = "-1..=1000000")]
158 pub hardness: Option<f64>,
159 #[data(range = "0..=10000000")]
161 pub resistance: Option<f64>,
162 #[data(with = "Opt<SoundRef>")]
165 pub sound: Option<String>,
166 #[data(range = "0..=15")]
168 pub light: Option<u8>,
169 #[data(with = "OneOrMany<ToolTag>")]
172 pub tool: Vec<BlockTag>,
173 #[data(with = "Opt<LevelRef>")]
176 pub tool_level: Option<String>,
177 #[data(default)]
179 pub requires_tool: bool,
180 pub collision: Option<bool>,
182 #[data(range = "0..=1")]
183 pub slipperiness: Option<f64>,
184 pub shape: Option<BlockShape>,
185 pub render_layer: Option<RenderLayer>,
186 pub drops: Option<Drops>,
187 #[data(default)]
189 pub connect_groups: Vec<String>,
190 pub inventory: Option<String>,
192 #[data(default)]
194 pub redstone: bool,
195 pub powered: Option<String>,
198 pub comparator: Option<String>,
200 #[data(default)]
203 pub accepts_items: bool,
204 pub occludes: Option<bool>,
207 #[data(with = "Opt<RefTo<yog_data::kinds::Block>>")]
210 pub base: Option<String>,
211 pub set: Option<String>,
215 #[data(range = "1..=1000000")]
217 pub press_ticks: Option<u32>,
218 pub triggered_by: Option<TriggeredBy>,
220}