Skip to main content

steel_registry/advancement/
registry.rs

1use crate::advancement::{Advancement, positioner};
2use rustc_hash::{FxHashMap, FxHashSet};
3use std::fmt::{Debug, Display};
4use std::hash::{Hash, Hasher};
5use std::io::Write;
6use steel_utils::Identifier;
7use steel_utils::serial::WriteTo;
8
9pub type AdvancementRef = &'static Advancement;
10
11#[derive(Debug)]
12pub struct AdvancementNode {
13    children: Vec<usize>,
14    parent: Option<usize>,
15    value: AdvancementRef,
16    x: f32,
17    y: f32,
18}
19
20pub type AdvancementNodeRef = &'static AdvancementNode;
21
22impl WriteTo for AdvancementNodeRef {
23    fn write(&self, writer: &mut impl Write) -> std::io::Result<()> {
24        self.value.write(writer)?;
25        self.x.write(writer)?;
26        self.y.write(writer)
27    }
28}
29
30impl AdvancementNode {
31    pub fn add_child(&mut self, child: usize) {
32        self.children.push(child);
33    }
34
35    #[must_use]
36    pub const fn new(value: AdvancementRef, parent: Option<usize>) -> Self {
37        Self {
38            value,
39            parent,
40            children: Vec::new(),
41            x: 0f32,
42            y: 0f32,
43        }
44    }
45
46    #[inline]
47    #[must_use]
48    pub const fn has_display(&self) -> bool {
49        self.value.display.is_some()
50    }
51
52    #[inline]
53    pub const fn set_location(&mut self, x: f32, y: f32) {
54        self.x = x;
55        self.y = y;
56    }
57
58    #[inline]
59    #[must_use]
60    pub const fn get_location(&self) -> (f32, f32) {
61        (self.x, self.y)
62    }
63
64    #[must_use]
65    #[inline]
66    pub const fn value(&self) -> AdvancementRef {
67        self.value
68    }
69
70    #[must_use]
71    #[inline]
72    pub fn children(&self) -> Vec<usize> {
73        self.children.clone()
74    }
75
76    #[must_use]
77    #[inline]
78    pub const fn parent(&self) -> Option<usize> {
79        self.parent
80    }
81}
82
83impl PartialEq<Self> for AdvancementNode {
84    fn eq(&self, other: &Self) -> bool {
85        self.value == other.value
86    }
87}
88
89impl Eq for AdvancementNode {}
90
91impl Display for AdvancementNode {
92    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        write!(formatter, "{}", self.value.key)
94    }
95}
96impl Hash for AdvancementNode {
97    fn hash<H: Hasher>(&self, state: &mut H) {
98        self.value.key.hash(state);
99    }
100}
101
102/// equivalent of the `AdvancementTree` of the minecraft source code
103///
104/// TODO add Dynamic allocated Advancement with a enum :
105/// ```rust
106/// use steel_registry::advancement::Advancement;
107/// use steel_registry::advancement::registry::AdvancementRef;
108///
109/// enum AdvancementHolder {
110///    Static(AdvancementRef),
111///    Dynamic(Box<Advancement>),
112/// }
113/// ```
114/// TODO add the ability to reload the registry.
115/// TODO made the registry behind a `ArcSwap` and the `unloaded_advancement` behind a `Mutex` to allow for dynamic reloading of advancements.
116#[derive(Default, Debug)]
117pub struct AdvancementRegistry {
118    pub(crate) advancements: Vec<AdvancementRef>,
119    pub(crate) adv_nodes: Vec<AdvancementNode>,
120    pub(crate) unloaded_advancement: FxHashSet<AdvancementRef>,
121    pub(crate) by_key: FxHashMap<Identifier, usize>,
122    pub(crate) roots: Vec<usize>,
123    pub(crate) tasks: Vec<usize>,
124}
125
126impl AdvancementRegistry {
127    #[must_use]
128    #[inline]
129    pub fn new() -> Self {
130        Self::default()
131    }
132
133    #[must_use]
134    pub fn advancements(&self) -> &[AdvancementRef] {
135        &self.advancements
136    }
137
138    #[must_use]
139    pub fn nodes(&self) -> &[AdvancementNode] {
140        &self.adv_nodes
141    }
142
143    fn register_with_parent(&mut self, advancement: AdvancementRef, parent_idx: Option<usize>) {
144        let id = advancement.key.clone();
145        let node_idx = self.adv_nodes.len();
146        self.adv_nodes
147            .push(AdvancementNode::new(advancement, parent_idx));
148        self.advancements.push(advancement);
149        self.by_key.insert(id, node_idx);
150        if let Some(parent) = parent_idx {
151            let parent_node = self
152                .adv_nodes
153                .get_mut(parent)
154                .expect("unable to get the parent node");
155            parent_node.add_child(node_idx);
156            self.tasks.push(node_idx);
157        } else {
158            self.roots.push(node_idx);
159        }
160    }
161
162    fn try_register(&mut self, advancement: AdvancementRef) -> Option<AdvancementRef> {
163        let parent_id = &advancement.parent;
164        let parent_idx: Option<usize> = match parent_id {
165            Some(id) => match self.by_key.get(id) {
166                Some(node) => Some(*node),
167                None => return Some(advancement),
168            },
169            None => None,
170        };
171        self.register_with_parent(advancement, parent_idx);
172        None
173    }
174
175    fn register_all(&mut self, mut advancements_to_add: Vec<AdvancementRef>) {
176        while !advancements_to_add.is_empty() {
177            let len_before = advancements_to_add.len();
178
179            advancements_to_add = advancements_to_add
180                .into_iter()
181                .filter_map(|advancement| self.try_register(advancement))
182                .collect();
183
184            if advancements_to_add.len() == len_before && !advancements_to_add.is_empty() {
185                eprintln!(
186                    "Couldn't load advancements: {:?}",
187                    advancements_to_add
188                        .iter()
189                        .map(|a| &a.key)
190                        .collect::<Vec<_>>()
191                );
192                break;
193            }
194        }
195    }
196
197    /// Registers an advancement in the registry. Returns true if the advancement was added to the
198    /// unloaded advancements set, false if it was already present.
199    pub fn register(&mut self, advancement: AdvancementRef) -> bool {
200        self.unloaded_advancement.insert(advancement)
201    }
202
203    #[cfg(test)]
204    pub fn register_without_load(&mut self, advancements: &[AdvancementRef]) {
205        self.register_all(advancements.to_vec());
206    }
207
208    #[must_use]
209    #[inline]
210    pub fn value_by_key(&self, key: &Identifier) -> Option<AdvancementRef> {
211        self.by_key.get(key).map(|idx| self.advancements[*idx])
212    }
213
214    #[must_use]
215    #[inline]
216    pub fn by_key(&self, key: &Identifier) -> Option<&AdvancementNode> {
217        self.by_key
218            .get(key)
219            .and_then(|idx| self.adv_nodes.get(*idx))
220    }
221
222    #[must_use]
223    #[inline]
224    pub fn get_by_idx(&self, idx: usize) -> Option<&AdvancementNode> {
225        self.adv_nodes.get(idx)
226    }
227
228    pub fn iter(&self) -> impl Iterator<Item = (usize, &AdvancementNode)> + '_ {
229        self.adv_nodes.iter().enumerate()
230    }
231
232    /// Updates the advancement tree by loading and connecting all unloaded advancements.
233    pub(crate) fn update_tree(&mut self) {
234        let advancements = self.unloaded_advancement.drain().collect();
235        self.register_all(advancements);
236        for advancement_idx in self.roots.clone() {
237            let node = self.adv_nodes.get(advancement_idx);
238            let Some(node) = node else {
239                eprintln!("unable to get the root node with index {advancement_idx}");
240                return;
241            };
242            if node.has_display() {
243                let res = positioner::run(self, advancement_idx);
244                if let Err(e) = res {
245                    eprintln!("{}", e.get_message());
246                }
247            }
248        }
249    }
250
251    #[must_use]
252    pub fn root(&'static self, advancement_node: AdvancementNodeRef) -> AdvancementNodeRef {
253        let mut advancement_node = advancement_node;
254        while let Some(parent) = &advancement_node.parent {
255            advancement_node = &self.adv_nodes[*parent];
256        }
257        advancement_node
258    }
259
260    pub fn remove_unloaded_advancement(&mut self, advancement: &Identifier) {
261        self.unloaded_advancement
262            .retain(|adv| adv.key() != advancement);
263    }
264}