Skip to main content

steel_registry/entity_data/
serializer.rs

1//! Entity data serializer registry.
2//!
3//! This registry maps serializer keys to IDs and stores writer functions.
4//! Registration order determines the serializer ID used in the network protocol,
5//! matching vanilla's `EntityDataSerializers.java`.
6
7use rustc_hash::FxHashMap;
8use std::io;
9use steel_utils::Identifier;
10
11use super::EntityData;
12
13/// Writer function for serializing entity data to network format.
14///
15/// Takes a reference to the [`EntityData`] value and writes it to the buffer.
16/// Returns an error if the value doesn't match the expected serializer type.
17pub type EntityDataWriter = fn(&EntityData, &mut Vec<u8>) -> io::Result<()>;
18
19/// Entry for a registered entity data serializer.
20pub struct EntityDataSerializerEntry {
21    /// The serializer's identifier (e.g., "minecraft:byte").
22    pub key: Identifier,
23    /// The writer function for this serializer.
24    pub writer: EntityDataWriter,
25}
26
27pub type EntityDataSerializerEntryRef = &'static EntityDataSerializerEntry;
28
29/// Registry of entity data serializers.
30///
31/// The serializer ID is determined by registration order, which must match
32/// vanilla's `EntityDataSerializers.java` exactly.
33pub struct EntityDataSerializerRegistry {
34    /// Serializer entries in registration order (index = ID).
35    entries_by_id: Vec<EntityDataSerializerEntryRef>,
36    /// Map from key to ID for fast lookup.
37    entries_by_key: FxHashMap<Identifier, usize>,
38    /// Whether registration is still allowed.
39    allows_registering: bool,
40}
41
42impl EntityDataSerializerRegistry {
43    /// Create a new empty registry.
44    #[must_use]
45    pub fn new() -> Self {
46        Self {
47            entries_by_id: Vec::new(),
48            entries_by_key: FxHashMap::default(),
49            allows_registering: true,
50        }
51    }
52
53    /// Register a serializer with its writer function. ID is determined by registration order.
54    ///
55    /// # Panics
56    /// Panics if the registry has been frozen or if the key is already registered.
57    pub fn register(&mut self, key: Identifier, writer: EntityDataWriter) {
58        assert!(
59            self.allows_registering,
60            "Cannot register entity data serializers after the registry has been frozen"
61        );
62        assert!(
63            !self.entries_by_key.contains_key(&key),
64            "Serializer '{key}' already registered",
65        );
66
67        let entry = Box::leak(Box::new(EntityDataSerializerEntry {
68            key: key.clone(),
69            writer,
70        }));
71        let id = self.entries_by_id.len();
72        self.entries_by_id.push(entry);
73        self.entries_by_key.insert(key, id);
74    }
75
76    /// Get the writer function for a serializer by protocol ID.
77    #[must_use]
78    pub fn get_writer(&self, id: i32) -> Option<EntityDataWriter> {
79        self.entries_by_id.get(id as usize).map(|e| e.writer)
80    }
81}
82
83impl Default for EntityDataSerializerRegistry {
84    fn default() -> Self {
85        Self::new()
86    }
87}
88
89crate::impl_registry!(
90    EntityDataSerializerRegistry,
91    EntityDataSerializerEntry,
92    entries_by_id,
93    entries_by_key,
94    entity_data_serializers
95);