valence_registry/
lib.rs
1#![doc = include_str!("../README.md")]
2
3pub mod biome;
4pub mod codec;
5pub mod dimension_type;
6pub mod tags;
7
8use std::fmt::Debug;
9use std::hash::Hash;
10use std::marker::PhantomData;
11use std::ops::{Index, IndexMut};
12
13use bevy_app::prelude::*;
14use bevy_ecs::prelude::*;
15pub use biome::BiomeRegistry;
16pub use codec::RegistryCodec;
17pub use dimension_type::DimensionTypeRegistry;
18use indexmap::map::Entry;
19use indexmap::IndexMap;
20pub use tags::TagsRegistry;
21use valence_ident::Ident;
22
23pub struct RegistryPlugin;
24
25#[derive(SystemSet, Copy, Clone, PartialEq, Eq, Hash, Debug)]
31pub struct RegistrySet;
32
33impl Plugin for RegistryPlugin {
34 fn build(&self, app: &mut App) {
35 app.configure_sets(PostUpdate, RegistrySet);
36
37 codec::build(app);
38 tags::build(app);
39 }
40}
41
42#[derive(Clone, Debug)]
43pub struct Registry<I, V> {
44 items: IndexMap<Ident<String>, V>,
45 _marker: PhantomData<I>,
46}
47
48impl<I: RegistryIdx, V> Registry<I, V> {
49 pub fn new() -> Self {
50 Self {
51 items: IndexMap::new(),
52 _marker: PhantomData,
53 }
54 }
55
56 pub fn insert<N: Into<Ident<String>>>(&mut self, name: N, item: V) -> Option<I> {
57 if self.items.len() >= I::MAX {
58 return None;
60 }
61
62 let len = self.items.len();
63
64 match self.items.entry(name.into()) {
65 Entry::Occupied(_) => None,
66 Entry::Vacant(ve) => {
67 ve.insert(item);
68 Some(I::from_index(len))
69 }
70 }
71 }
72
73 pub fn swap_to_front(&mut self, name: Ident<&str>) {
74 if let Some(idx) = self.items.get_index_of(name.as_str()) {
75 self.items.swap_indices(0, idx);
76 }
77 }
78
79 pub fn remove(&mut self, name: Ident<&str>) -> Option<V> {
80 self.items.shift_remove(name.as_str())
81 }
82
83 pub fn clear(&mut self) {
84 self.items.clear();
85 }
86
87 pub fn get(&self, name: Ident<&str>) -> Option<&V> {
88 self.items.get(name.as_str())
89 }
90
91 pub fn get_mut(&mut self, name: Ident<&str>) -> Option<&mut V> {
92 self.items.get_mut(name.as_str())
93 }
94
95 pub fn index_of(&self, name: Ident<&str>) -> Option<I> {
96 self.items.get_index_of(name.as_str()).map(I::from_index)
97 }
98
99 pub fn iter(
100 &self,
101 ) -> impl DoubleEndedIterator<Item = (I, Ident<&str>, &V)> + ExactSizeIterator + '_ {
102 self.items
103 .iter()
104 .enumerate()
105 .map(|(i, (k, v))| (I::from_index(i), k.as_str_ident(), v))
106 }
107
108 pub fn iter_mut(
109 &mut self,
110 ) -> impl DoubleEndedIterator<Item = (I, Ident<&str>, &mut V)> + ExactSizeIterator + '_ {
111 self.items
112 .iter_mut()
113 .enumerate()
114 .map(|(i, (k, v))| (I::from_index(i), k.as_str_ident(), v))
115 }
116}
117
118impl<I: RegistryIdx, V> Index<I> for Registry<I, V> {
119 type Output = V;
120
121 fn index(&self, index: I) -> &Self::Output {
122 self.items
123 .get_index(index.to_index())
124 .unwrap_or_else(|| panic!("out of bounds registry index of {}", index.to_index()))
125 .1
126 }
127}
128
129impl<I: RegistryIdx, V> IndexMut<I> for Registry<I, V> {
130 fn index_mut(&mut self, index: I) -> &mut Self::Output {
131 self.items
132 .get_index_mut(index.to_index())
133 .unwrap_or_else(|| panic!("out of bounds registry index of {}", index.to_index()))
134 .1
135 }
136}
137
138impl<'a, I: RegistryIdx, V> Index<Ident<&'a str>> for Registry<I, V> {
139 type Output = V;
140
141 fn index(&self, index: Ident<&'a str>) -> &Self::Output {
142 if let Some(item) = self.items.get(index.as_str()) {
143 item
144 } else {
145 panic!("missing registry item with name '{index}'")
146 }
147 }
148}
149
150impl<'a, I: RegistryIdx, V> IndexMut<Ident<&'a str>> for Registry<I, V> {
151 fn index_mut(&mut self, index: Ident<&'a str>) -> &mut Self::Output {
152 if let Some(item) = self.items.get_mut(index.as_str()) {
153 item
154 } else {
155 panic!("missing registry item with name '{index}'")
156 }
157 }
158}
159
160impl<I, V> Default for Registry<I, V> {
161 fn default() -> Self {
162 Self {
163 items: IndexMap::new(),
164 _marker: PhantomData,
165 }
166 }
167}
168
169pub trait RegistryIdx: Copy + Clone + PartialEq + Eq + PartialOrd + Ord + Hash + Debug {
170 const MAX: usize;
171
172 fn to_index(self) -> usize;
173 fn from_index(idx: usize) -> Self;
174}