veloren_common/terrain/sprite/
magic.rs1#[macro_export]
2macro_rules! sprites {
3 (
4 $($category_name:ident = $category_disc:literal $(has $($attr:ident),* $(,)?)? {
5 $($sprite_name:ident = $sprite_id:literal),* $(,)?
6 }),* $(,)?
7 ) => {
8 make_case_elim!(
9 category,
10 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, EnumIter, FromPrimitive)]
11 #[repr(u32)]
12 pub enum Category {
13 $($category_name = $category_disc,)*
14 }
15 );
16
17 impl Category {
18 #[inline] pub const fn all() -> &'static [Self] {
19 &[$(Self::$category_name,)*]
20 }
21
22 #[cfg(test)]
23 #[inline] const fn all_sprites(&self) -> &'static [SpriteKind] {
24 match self {
25 $(Self::$category_name => &[$(SpriteKind::$sprite_name,)*],)*
26 }
27 }
28
29 #[inline] pub const fn sprite_id_mask(&self) -> u32 {
31 match self {
32 $(Self::$category_name => ((0u32 $(| $sprite_id)*) + 1).next_power_of_two() - 1,)*
33 }
34 }
35
36 #[inline] pub const fn sprite_id_size(&self) -> u32 { self.sprite_id_mask().count_ones() }
38
39 #[inline(always)] pub const fn sprite_kind_mask(&self) -> u32 { 0x00FF0000 | self.sprite_id_mask() }
41
42 #[expect(non_upper_case_globals)]
45 #[inline] pub(super) const fn from_block(block: Block) -> Option<Self> {
46 $(const $category_name: u8 = Category::$category_name as u8;)*
47 match block.sprite_category_byte() {
48 $($category_name => Some(Self::$category_name),)*
49 _ => None,
50 }
51 }
52
53 #[inline] pub const fn attr_offsets(&self) -> &[Option<u8>; Attributes::all().len()] {
59 match self {
60 $(Self::$category_name => {
61 #[allow(unused_mut, unused_variables, unused_assignments)]
62 const fn gen_attr_offsets() -> [Option<u8>; Attributes::all().len()] {
63 let mut lut = [None; Attributes::all().len()];
64 let mut offset = Category::$category_name.sprite_id_size();
66 $($({
67 if offset + $attr::BITS as u32 > 16 {
69 panic!("Sprite category has an attribute set that will not fit in the block data");
70 } else if lut[$attr::INDEX].is_some() {
71 panic!("Sprite category cannot have more than one instance of an attribute");
72 } else if offset > (!0u8) as u32 {
73 panic!("Uhhh");
74 }
75 lut[$attr::INDEX] = Some(offset as u8);
76 offset += $attr::BITS as u32;
77 })*)*
78 lut
79 }
80 const ATTR_OFFSETS: [Option<u8>; Attributes::all().len()] = gen_attr_offsets();
81 &ATTR_OFFSETS
82 },)*
83 }
84 }
85
86 #[inline] pub fn has_attr<A: Attribute>(&self) -> bool {
88 self.attr_offsets()[A::INDEX].is_some()
89 }
90
91 #[inline] pub(super) fn read_attr<A: Attribute>(&self, block: Block) -> Result<A, AttributeError<A::Error>> {
96 let offset = match self.attr_offsets()[A::INDEX] {
97 Some(offset) => offset,
98 None => return Err(AttributeError::NotPresent),
99 };
100 let bits = (block.to_be_u32() >> offset as u32) & ((1 << A::BITS as u32) - 1);
101 A::from_bits(bits as u16).map_err(AttributeError::Attribute)
102 }
103
104 #[inline] pub(super) fn write_attr<A: Attribute>(&self, block: &mut Block, attr: A) -> Result<(), AttributeError<core::convert::Infallible>> {
109 let offset = match self.attr_offsets()[A::INDEX] {
110 Some(offset) => offset,
111 None => return Err(AttributeError::NotPresent),
112 };
113 let bits = attr.into_bits() as u32;
114 #[cfg(debug_assertions)]
115 assert!(bits < (1 << A::BITS as u32), "The bit representation of the attribute {} must fit within {} bits, but the representation was {:0b}", core::any::type_name::<A>(), A::BITS, bits);
116 let data = ((block.to_be_u32() & (!(((1 << A::BITS as u32) - 1) << offset as u32))) | (bits << offset as u32)).to_be_bytes();
117 *block = block.with_data([data[1], data[2], data[3]]);
118 Ok(())
119 }
120 }
121
122 #[inline] const fn gen_discriminant(category: Category, id: u16) -> u32 {
123 (category as u32) << 16 | id as u32
124 }
125
126 make_case_elim!(
127 sprite_kind,
128 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize, EnumIter, FromPrimitive)]
129 #[repr(u32)]
130 pub enum SpriteKind {
131 $($($sprite_name = $crate::terrain::sprite::gen_discriminant($crate::terrain::sprite::Category::$category_name, $sprite_id),)*)*
132 }
133 );
134
135 #[doc(hidden)]
136 mod categories {
137 use super::*;
138 $(
139 #[doc(hidden)]
141 #[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
142 pub struct $category_name $(($($attr),*))?;
143
144 const _: () = {
145
146 #[doc(hidden)]
147 pub struct Visitor<'a, 'de, O, F> {
148 f: F,
149 expecting: &'a str,
150 _marker: std::marker::PhantomData<O>,
151 _lifetime: std::marker::PhantomData<&'de ()>,
152 }
153
154 #[automatically_derived]
155 impl<'a, 'de, O, F: FnOnce($category_name) -> O> serde::de::Visitor<'de> for Visitor<'a, 'de, O, F> {
156 type Value = O;
157
158 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
159 formatter.write_str(&format!("Variant SpriteKind::{}", self.expecting))
160 }
161
162 #[inline]
163 fn visit_seq<A>(self, mut _seq: A) -> Result<Self::Value, <A as serde::de::SeqAccess<'de>>::Error>
164 where
165 A: serde::de::SeqAccess<'de>,
166 {
167 let res = $category_name $(($(
168 serde::de::SeqAccess::next_element::<$attr>(&mut _seq)?.unwrap_or_default()
169 ),*))?;
170
171 Ok((self.f)(res))
172 }
173 }
174
175 impl $category_name {
176 pub const LEN: usize = ${count($attr)};
177
178 pub fn apply_to_block(self, _block: &mut Block) -> Result<(), AttributeError<core::convert::Infallible>> {
179 $($(
180 _block.set_attr(self.${index()} ${ignore($attr)})?;
181 )*)?
182
183 Ok(())
184 }
185
186 pub fn from_block(_block: &Block) -> Self {
187 Self $(($(_block.get_attr::<$attr>().unwrap_or_default()),*))?
188 }
189
190 pub fn visitor<'de, O, F: FnOnce($category_name) -> O>(f: F, expecting: &str) -> Visitor<'_, 'de, O, F> {
191 Visitor {
192 f,
193 expecting,
194 _marker: std::marker::PhantomData,
195 _lifetime: std::marker::PhantomData,
196 }
197 }
198 }
199 };
200
201 )*
202 }
203 #[doc(hidden)]
204 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
205 #[repr(u32)]
206 enum StructureSpriteKind {
207 $($($sprite_name(categories::$category_name) = SpriteKind::$sprite_name as u32,)*)*
208 }
209
210 impl StructureSpriteKind {
211 fn apply_to_block(self, block: Block) -> Result<Block, Block> {
215 match self {
216 $($(Self::$sprite_name(c) => block.try_with_sprite(SpriteKind::$sprite_name)
217 .map(|mut block| {
218 c.apply_to_block(&mut block).expect("We just added sprite to block");
219 block
220 }),
221 )*)*
222 }
223 }
224
225 pub fn from_block(block: &Block) -> Option<Self> {
226 let sprite = block.get_sprite()?;
227
228 Some(match sprite {
229 $($(SpriteKind::$sprite_name => Self::$sprite_name(categories::$category_name::from_block(block)),)*)*
230 })
231 }
232 }
233
234 const _: () = {
235 mod __priv {
236 use super::{SpriteKind, StructureSpriteKind, categories};
237 use std::{
238 fmt::{self, Formatter},
239 marker::PhantomData,
240 };
241 use serde::{de, Deserialize, Deserializer};
242
243 impl<'de> Deserialize<'de> for StructureSpriteKind {
244 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
245 where
246 D: Deserializer<'de>
247 {
248 #[doc(hidden)]
249 struct Visitor<'de> {
250 lifetime: PhantomData<&'de ()>,
251 }
252
253 impl<'de> de::Visitor<'de> for Visitor<'de> {
254 type Value = StructureSpriteKind;
255
256 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
257 formatter.write_str("enum SpriteKind")
258 }
259
260 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
261 where
262 A: de::EnumAccess<'de>
263 {
264 match de::EnumAccess::variant(data)? {
265 $($(
266 (SpriteKind::$sprite_name, variant) => {
267 let visitor = categories::$category_name::visitor(StructureSpriteKind::$sprite_name, stringify!($sprite_name));
268 de::VariantAccess::tuple_variant(
269 variant,
270 categories::$category_name::LEN,
271 visitor,
272 )
273 },
274 )*)*
275 }
276 }
277 }
278
279 #[doc(hidden)]
280 const VARIANTS: &[&str] = &[
281 $($(stringify!($sprite_name),)*)*
282 ];
283
284 Deserializer::deserialize_enum(
285 deserializer,
286 "SpriteKind",
287 VARIANTS,
288 Visitor {
289 lifetime: PhantomData,
290 },
291 )
292 }
293 }
294 }
295 };
296
297 impl SpriteKind {
298 #[inline] pub const fn all() -> &'static [Self] {
299 &[$($(Self::$sprite_name,)*)*]
300 }
301
302 #[inline] pub const fn category(&self) -> Category {
303 match self {
304 $($(Self::$sprite_name => Category::$category_name,)*)*
305 }
306 }
307
308 #[expect(non_upper_case_globals)]
311 #[inline] pub(super) const fn from_block(block: Block) -> Option<Self> {
312 match block.sprite_category() {
313 None => None,
314 $(Some(category @ Category::$category_name) => {
315 $(const $sprite_name: u32 = SpriteKind::$sprite_name as u32;)*
316 match block.to_be_u32() & category.sprite_kind_mask() {
317 $($sprite_name => Some(Self::$sprite_name),)*
318 _ => None,
319 }
320 },)*
321 }
322 }
323
324 #[inline] pub(super) fn to_initial_bytes(self) -> [u8; 3] {
325 let sprite_bytes = (self as u32).to_be_bytes();
326 let block = Block::from_raw(super::BlockKind::Air, [sprite_bytes[1], sprite_bytes[2], sprite_bytes[3]]);
327 match self.category() {
328 $(Category::$category_name => block$($(.with_attr($attr::default()).unwrap())*)?,)*
329 }
330 .data()
331 }
332 }
333 };
334}
335
336#[derive(Debug)]
337pub enum AttributeError<E> {
338 NotPresent,
340 Attribute(E),
342}
343
344pub trait Attribute: Default + Sized {
345 const INDEX: usize;
348 const BITS: u8;
350 type Error: core::fmt::Debug;
352 fn from_bits(bits: u16) -> Result<Self, Self::Error>;
353 fn into_bits(self) -> u16;
354}
355
356#[macro_export]
357macro_rules! attributes {
358 ($(
359 $name:ident { bits: $bits:literal, err: $err:path, from: $from_bits:expr, into: $into_bits:expr $(,)? }
360 ),* $(,)?) => {
361 #[derive(Copy, Clone, Debug)]
362 #[repr(u16)]
363 pub enum Attributes {
364 $($name,)*
365 }
366
367 impl Attributes {
368 #[inline] pub const fn all() -> &'static [Self] {
369 &[$(Self::$name,)*]
370 }
371 }
372
373 $(
374 impl Attribute for $name {
375 const INDEX: usize = Attributes::$name as usize;
376 const BITS: u8 = $bits;
377 type Error = $err;
378 #[inline(always)] fn from_bits(bits: u16) -> Result<Self, Self::Error> { $from_bits(bits) }
379 #[inline(always)] fn into_bits(self) -> u16 { $into_bits(self) }
380 }
381 )*
382 };
383}