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 yog_data::expected(
47 cx,
48 "\"auto\" (the model's bounds), \"full\" or [x1, y1, z1, x2, y2, z2] in pixels",
49 other,
50 );
51 None
52 }
53 }
54 }
55 fn write(&self) -> Value {
56 match self {
57 BlockShape::Auto => Value::from("auto"),
58 BlockShape::Full => Value::from("full"),
59 BlockShape::Box(b) => b.write(),
60 }
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq)]
66pub enum DropCount {
67 Exactly(f64),
68 Between(f64, f64),
69}
70
71impl Schema for DropCount {
72 fn shape() -> Shape {
73 Shape::Any
74 }
75 fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
76 let n = match v {
77 ValueRef::List(_) => {
78 let [lo, hi] = <[f64; 2]>::read(v, cx)?;
79 (lo, hi, DropCount::Between(lo, hi))
80 }
81 _ => {
82 let n = f64::read(v, cx)?;
83 (n, n, DropCount::Exactly(n))
84 }
85 };
86 let stack = 0.0..=f64::from(MAX_STACK);
87 if !stack.contains(&n.0) || !stack.contains(&n.1) || n.0 > n.1 {
88 cx.problem("a count is 1–64, or [min, max] within 0–64");
89 return None;
90 }
91 Some(n.2)
92 }
93 fn write(&self) -> Value {
94 match *self {
95 DropCount::Exactly(n) => Value::Float(n),
96 DropCount::Between(a, b) => Value::List(vec![Value::Float(a), Value::Float(b)]),
97 }
98 }
99}
100
101#[derive(Schema, Debug, Clone)]
103pub struct DropItem {
104 #[data(with = "Opt<RefTo<Item>>")]
105 pub item: Option<String>,
106 pub count: Option<DropCount>,
107}
108
109#[derive(Debug, Clone)]
111pub enum Drops {
112 Itself,
113 Nothing,
114 Item(DropItem),
115}
116
117impl Schema for Drops {
118 fn shape() -> Shape {
119 Shape::Any
120 }
121 fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self> {
122 match v {
123 ValueRef::Str(s) if *s == "self" => Some(Drops::Itself),
124 ValueRef::Str(s) if *s == "none" => Some(Drops::Nothing),
125 ValueRef::Map(_) => DropItem::read(v, cx).map(Drops::Item),
126 other => {
127 yog_data::expected(
128 cx,
129 "\"self\", \"none\" or { item: \"@item:ns:item\", count: [1, 3] }",
130 other,
131 );
132 None
133 }
134 }
135 }
136 fn write(&self) -> Value {
137 match self {
138 Drops::Itself => Value::from("self"),
139 Drops::Nothing => Value::from("none"),
140 Drops::Item(d) => d.write(),
141 }
142 }
143}
144
145#[derive(Schema, Debug, Clone, Copy, PartialEq, Eq, Default)]
147pub enum TriggeredBy {
148 #[default]
150 Everything,
151 Mobs,
153}
154
155#[derive(Schema, Debug, Clone, Default)]
157pub struct BlockProps {
158 #[data(range = "-1..=1000000")]
160 pub hardness: Option<f64>,
161 #[data(range = "0..=10000000")]
163 pub resistance: Option<f64>,
164 #[data(with = "Opt<SoundRef>")]
167 pub sound: Option<String>,
168 #[data(range = "0..=15")]
170 pub light: Option<u8>,
171 #[data(with = "OneOrMany<ToolTag>")]
174 pub tool: Vec<BlockTag>,
175 #[data(with = "Opt<LevelRef>")]
178 pub tool_level: Option<String>,
179 #[data(default)]
181 pub requires_tool: bool,
182 pub collision: Option<bool>,
184 #[data(range = "0..=1")]
185 pub slipperiness: Option<f64>,
186 pub shape: Option<BlockShape>,
187 pub render_layer: Option<RenderLayer>,
188 pub drops: Option<Drops>,
189 #[data(default)]
191 pub connect_groups: Vec<String>,
192 pub inventory: Option<String>,
194 #[data(default)]
196 pub redstone: bool,
197 pub powered: Option<String>,
200 pub comparator: Option<String>,
202 #[data(default)]
205 pub accepts_items: bool,
206 pub occludes: Option<bool>,
209 #[data(with = "Opt<RefTo<yog_data::kinds::Block>>")]
212 pub base: Option<String>,
213 pub set: Option<String>,
217 #[data(range = "1..=1000000")]
219 pub press_ticks: Option<u32>,
220 pub triggered_by: Option<TriggeredBy>,
222}