Skip to main content

steel_registry/
jukebox_song.rs

1use rustc_hash::FxHashMap;
2use std::io::{Cursor, Result, Write};
3
4use simdnbt::owned::{NbtCompound, NbtTag};
5use simdnbt::{FromNbtTag, ToNbtTag};
6use steel_utils::Identifier;
7use steel_utils::hash::{ComponentHasher, HashComponent};
8use steel_utils::nbt::NbtNumeric as _;
9use steel_utils::serial::{ReadFrom, WriteTo};
10use text_components::TextComponent;
11
12use crate::sound_event::SoundEventHolder;
13use crate::{REGISTRY, RegistryExt, RegistryHolderEntry, RegistryTags};
14
15#[derive(Debug, Clone)]
16pub struct JukeboxSongValue {
17    pub sound_event: SoundEventHolder,
18    pub description: TextComponent,
19    pub length_in_seconds: f32,
20    pub comparator_output: i32,
21}
22
23impl PartialEq for JukeboxSongValue {
24    fn eq(&self, other: &Self) -> bool {
25        self.sound_event == other.sound_event
26            && self.description == other.description
27            && ((self.length_in_seconds.is_nan() && other.length_in_seconds.is_nan())
28                || self.length_in_seconds.to_bits() == other.length_in_seconds.to_bits())
29            && self.comparator_output == other.comparator_output
30    }
31}
32
33impl WriteTo for JukeboxSongValue {
34    fn write(&self, writer: &mut impl Write) -> Result<()> {
35        self.sound_event.write(writer)?;
36        self.description.write(writer)?;
37        self.length_in_seconds.write(writer)?;
38        steel_utils::codec::VarInt(self.comparator_output).write(writer)
39    }
40}
41
42impl ReadFrom for JukeboxSongValue {
43    fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
44        Ok(Self {
45            sound_event: SoundEventHolder::read(data)?,
46            description: TextComponent::read(data)?,
47            length_in_seconds: f32::read(data)?,
48            comparator_output: steel_utils::codec::VarInt::read(data)?.0,
49        })
50    }
51}
52
53impl ToNbtTag for JukeboxSongValue {
54    fn to_nbt_tag(self) -> NbtTag {
55        let mut compound = NbtCompound::new();
56        compound.insert("sound_event", self.sound_event.to_nbt_tag());
57        compound.insert("description", self.description.to_codec_nbt());
58        compound.insert("length_in_seconds", self.length_in_seconds);
59        compound.insert("comparator_output", self.comparator_output);
60        NbtTag::Compound(compound)
61    }
62}
63
64impl FromNbtTag for JukeboxSongValue {
65    fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
66        let compound = tag.compound()?;
67        let length_in_seconds = compound.get("length_in_seconds")?.codec_f32()?;
68        let comparator_output = compound.get("comparator_output")?.codec_i32()?;
69        if !length_in_seconds.is_finite()
70            || length_in_seconds <= 0.0
71            || !(0..=15).contains(&comparator_output)
72        {
73            return None;
74        }
75        Some(Self {
76            sound_event: SoundEventHolder::from_nbt_tag(compound.get("sound_event")?)?,
77            description: TextComponent::from_nbt(&compound.get("description")?.to_owned())?,
78            length_in_seconds,
79            comparator_output,
80        })
81    }
82}
83
84impl HashComponent for JukeboxSongValue {
85    fn hash_component(&self, hasher: &mut ComponentHasher) {
86        self.clone().to_nbt_tag().hash_component(hasher);
87    }
88}
89
90/// Represents a jukebox song definition from a data pack JSON file.
91#[derive(Debug)]
92pub struct JukeboxSong {
93    pub key: Identifier,
94    value: JukeboxSongValue,
95}
96
97impl JukeboxSong {
98    #[must_use]
99    pub const fn new(key: Identifier, value: JukeboxSongValue) -> Self {
100        Self { key, value }
101    }
102    #[must_use]
103    pub const fn value(&self) -> &JukeboxSongValue {
104        &self.value
105    }
106}
107
108impl ToNbtTag for &JukeboxSong {
109    fn to_nbt_tag(self) -> NbtTag {
110        self.value.clone().to_nbt_tag()
111    }
112}
113
114pub type JukeboxSongRef = &'static JukeboxSong;
115
116pub struct JukeboxSongRegistry {
117    jukebox_songs_by_id: Vec<JukeboxSongRef>,
118    jukebox_songs_by_key: FxHashMap<Identifier, usize>,
119    tags: RegistryTags,
120    allows_registering: bool,
121}
122
123impl JukeboxSongRegistry {
124    #[must_use]
125    pub fn new() -> Self {
126        Self {
127            jukebox_songs_by_id: Vec::new(),
128            jukebox_songs_by_key: FxHashMap::default(),
129            tags: RegistryTags::default(),
130            allows_registering: true,
131        }
132    }
133}
134
135crate::impl_standard_methods!(
136    JukeboxSongRegistry,
137    JukeboxSongRef,
138    jukebox_songs_by_id,
139    jukebox_songs_by_key,
140    allows_registering
141);
142
143crate::impl_registry!(
144    JukeboxSongRegistry,
145    JukeboxSong,
146    jukebox_songs_by_id,
147    jukebox_songs_by_key,
148    jukebox_songs
149);
150crate::impl_tagged_registry!(JukeboxSongRegistry, jukebox_songs_by_key, "jukebox song");
151
152impl RegistryHolderEntry for JukeboxSong {
153    type Value = JukeboxSongValue;
154    const REGISTRY_NAME: &'static str = "jukebox song";
155    fn holder_value(&self) -> &Self::Value {
156        &self.value
157    }
158    fn holder_by_id(id: usize) -> Option<&'static Self> {
159        REGISTRY.jukebox_songs.by_id(id)
160    }
161    fn holder_by_key(key: &Identifier) -> Option<&'static Self> {
162        REGISTRY.jukebox_songs.by_key(key)
163    }
164}