mc_core/entity/
codec.rs

1//! Codec basics for ECS entities' components.
2
3use std::marker::PhantomData;
4
5use hecs::{Component, EntityBuilder, EntityRef};
6use nbt::CompoundTag;
7
8
9/// This trait describes a specific way of encoding, decoding and building a default variant
10/// of a component structure for an entity. This trait should usually be implemented for each
11/// component of an entity, however because it doesn't provide any type restriction you can
12/// encode, decode and add whatever default value you want.
13///
14/// Structures implementing this trait can be zero-sized and defined statically, doing this
15/// allows you to make `&'static dyn EntityCodec` references that can be used as constants to
16/// define default codecs for an entity component structure.
17pub trait EntityCodec: Send + Sync {
18
19    /// Encode components stored accessible from the given entity reference into given destination
20    /// compound tag.
21    fn encode(&self, src: &EntityRef, dst: &mut CompoundTag) -> Result<(), String>;
22
23    /// Decode given source compound tag and add decoded components into the given entity builder.
24    fn decode(&self, src: &CompoundTag, dst: &mut EntityBuilder) -> Result<(), String>;
25
26    /// Add default components to the given entity builder.
27    fn default(&self, dst: &mut EntityBuilder);
28
29}
30
31
32/// This trait is a simpler specification of `EntityCodec` with the restriction of allowing only
33/// one component (implementing `hecs::Component`) to be encoded or decoded. The component type
34/// also have to implement `Default` to provide a default `EntityCodec::default` implementation.
35///
36/// Implementing this trait automatically means that you are implementing `EntityCodec` on `Self`,
37/// with `encode`, `decode` and `default` automatically defined to delegate to this trait.
38pub trait SingleEntityCodec {
39
40    /// Component type, an associated type is used to allow only on implementation per codec struct.
41    type Comp: Default + Component;
42
43    fn encode(&self, src: &Self::Comp, dst: &mut CompoundTag);
44    fn decode(&self, src: &CompoundTag) -> Self::Comp;
45
46}
47
48impl<C, D> EntityCodec for C
49where
50    C: Send + Sync,
51    C: SingleEntityCodec<Comp=D>,
52    D: Default + Component
53{
54
55    fn encode(&self, src: &EntityRef, dst: &mut CompoundTag) -> Result<(), String> {
56        if let Some(comp) = src.get::<D>() {
57            <Self as SingleEntityCodec>::encode(self, &*comp, dst);
58        }
59        Ok(())
60    }
61
62    fn decode(&self, src: &CompoundTag, dst: &mut EntityBuilder) -> Result<(), String> {
63        dst.add(<Self as SingleEntityCodec>::decode(self, src));
64        Ok(())
65    }
66
67    fn default(&self, dst: &mut EntityBuilder) {
68        dst.add(D::default());
69    }
70
71}
72
73
74/// A useful structure that implements the method `EntityCodec::default` and add to the given
75/// builder the `Default:default()` value of the generic type `T`. Actually, `EntityCodec` is
76/// only implemented when your type `T` is `Default + Component`. This bound cannot be defined
77/// in the structure definition for now because it would not be possible to define it statically.
78pub struct DefaultEntityCodec<T>(PhantomData<*const T>);
79unsafe impl<T> Send for DefaultEntityCodec<T> {}
80unsafe impl<T> Sync for DefaultEntityCodec<T> {}
81
82impl<T> DefaultEntityCodec<T> {
83    pub const fn new() -> Self {
84        Self(PhantomData)
85    }
86}
87
88#[allow(unused_variables)]
89impl<T> EntityCodec for DefaultEntityCodec<T>
90where
91    T: Default + Component
92{
93
94    fn encode(&self, src: &EntityRef, dst: &mut CompoundTag) -> Result<(), String> {
95        Ok(())
96    }
97
98    fn decode(&self, src: &CompoundTag, dst: &mut EntityBuilder) -> Result<(), String> {
99        Ok(())
100    }
101
102    fn default(&self, dst: &mut EntityBuilder) {
103        dst.add(<T as Default>::default());
104    }
105
106}
107
108
109/// A null codec, this codec make nothing and can be used as a temporary placeholder.
110pub struct NullEntityCodec;
111
112#[allow(unused_variables)]
113impl EntityCodec for NullEntityCodec {
114
115    fn encode(&self, src: &EntityRef, dst: &mut CompoundTag) -> Result<(), String> {
116        Ok(())
117    }
118
119    fn decode(&self, src: &CompoundTag, dst: &mut EntityBuilder) -> Result<(), String> {
120        Ok(())
121    }
122
123    fn default(&self, dst: &mut EntityBuilder) { }
124
125}