valence_registry/
codec.rs
1use std::collections::BTreeMap;
2
3use bevy_app::prelude::*;
4use bevy_ecs::prelude::*;
5use tracing::error;
6use valence_ident::Ident;
7use valence_nbt::{compound, Compound, List, Value};
8
9use crate::RegistrySet;
10
11pub(super) fn build(app: &mut App) {
12 app.init_resource::<RegistryCodec>()
13 .add_systems(PostUpdate, cache_registry_codec.in_set(RegistrySet));
14}
15
16#[derive(Resource, Debug)]
22pub struct RegistryCodec {
23 pub registries: BTreeMap<Ident<String>, Vec<RegistryValue>>,
24 cached_codec: Compound,
26}
27
28#[derive(Clone, Debug)]
29pub struct RegistryValue {
30 pub name: Ident<String>,
31 pub element: Compound,
32}
33
34impl RegistryCodec {
35 pub fn cached_codec(&self) -> &Compound {
36 &self.cached_codec
37 }
38
39 pub fn registry(&self, registry_key: Ident<&str>) -> &Vec<RegistryValue> {
40 self.registries
41 .get(registry_key.as_str())
42 .unwrap_or_else(|| panic!("missing registry for {registry_key}"))
43 }
44
45 pub fn registry_mut(&mut self, registry_key: Ident<&str>) -> &mut Vec<RegistryValue> {
46 self.registries
47 .get_mut(registry_key.as_str())
48 .unwrap_or_else(|| panic!("missing registry for {registry_key}"))
49 }
50}
51
52impl Default for RegistryCodec {
53 fn default() -> Self {
54 let codec = include_bytes!("../extracted/registry_codec.dat");
55 let compound = valence_nbt::from_binary(&mut codec.as_slice())
56 .expect("failed to decode vanilla registry codec")
57 .0;
58
59 let mut registries = BTreeMap::new();
60
61 for (k, v) in compound {
62 let reg_name: Ident<String> = Ident::new(k).expect("invalid registry name").into();
63 let mut reg_values = vec![];
64
65 let Value::Compound(mut outer) = v else {
66 error!("registry {reg_name} is not a compound");
67 continue;
68 };
69
70 let values = match outer.remove("value") {
71 Some(Value::List(List::Compound(values))) => values,
72 Some(Value::List(List::End)) => continue,
73 _ => {
74 error!("missing \"value\" compound in {reg_name}");
75 continue;
76 }
77 };
78
79 for mut value in values {
80 let Some(Value::String(name)) = value.remove("name") else {
81 error!("missing \"name\" string in value for {reg_name}");
82 continue;
83 };
84
85 let name = match Ident::new(name) {
86 Ok(n) => n.into(),
87 Err(e) => {
88 error!("invalid registry value name \"{}\"", e.0);
89 continue;
90 }
91 };
92
93 let Some(Value::Compound(element)) = value.remove("element") else {
94 error!("missing \"element\" compound in value for {reg_name}");
95 continue;
96 };
97
98 reg_values.push(RegistryValue { name, element });
99 }
100
101 registries.insert(reg_name, reg_values);
102 }
103
104 Self {
105 registries,
106 cached_codec: Compound::new(),
108 }
109 }
110}
111
112fn cache_registry_codec(codec: ResMut<RegistryCodec>) {
113 if codec.is_changed() {
114 let codec = codec.into_inner();
115
116 codec.cached_codec.clear();
117
118 for (reg_name, reg) in &codec.registries {
119 let mut value = vec![];
120
121 for (id, v) in reg.iter().enumerate() {
122 value.push(compound! {
123 "id" => id as i32,
124 "name" => v.name.as_str(),
125 "element" => v.element.clone(),
126 });
127 }
128
129 let registry = compound! {
130 "type" => reg_name.as_str(),
131 "value" => List::Compound(value),
132 };
133
134 codec.cached_codec.insert(reg_name.as_str(), registry);
135 }
136 }
137}