aboutsummaryrefslogtreecommitdiff
path: root/azalea-core/src/registry_holder/enchantment.rs
blob: 8d825baf772759833b8339efa8ad368812179400 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::{any::Any, fmt::Debug, str::FromStr};

use azalea_registry::builtin::EnchantmentEffectComponentKind;
use indexmap::IndexMap;
use simdnbt::{DeserializeError, borrow::NbtCompound};

use crate::registry_holder::components::{
    EffectComponentTrait, EffectComponentUnion, EffectNbtTag, ResolvedEffectComponent,
};

pub struct EnchantmentData {
    // TODO: make these two deserializable
    // pub description: TextComponent,
    // pub exclusive_set: HolderSet<Enchantment, ResourceLocation>,
    effects: IndexMap<EnchantmentEffectComponentKind, Vec<EffectComponentUnion>>,
}

impl EnchantmentData {
    pub fn get<T: EffectComponentTrait>(&self) -> Option<Vec<&T>> {
        let components = self.get_kind(T::KIND)?;
        let components_any = components
            .into_iter()
            .map(|c| (c as &dyn Any).downcast_ref::<T>())
            .collect::<Option<_>>()?;
        Some(components_any)
    }

    pub fn get_kind(
        &self,
        kind: EnchantmentEffectComponentKind,
    ) -> Option<Vec<&dyn ResolvedEffectComponent>> {
        self.effects.get(&kind).map(|c| {
            c.iter()
                .map(|c| {
                    // SAFETY: we just got the component from the map, so it must be the correct
                    // kind
                    unsafe { c.as_kind(kind) }
                })
                .collect()
        })
    }
}

impl simdnbt::Deserialize for EnchantmentData {
    fn from_compound(nbt: NbtCompound) -> Result<Self, DeserializeError> {
        let mut effects: IndexMap<EnchantmentEffectComponentKind, Vec<EffectComponentUnion>> =
            IndexMap::new();

        if let Some(effects_tag) = nbt.compound("effects") {
            for (key, list) in effects_tag.iter() {
                let kind = EnchantmentEffectComponentKind::from_str(&key.to_str())
                    .map_err(|_| DeserializeError::UnknownField(key.to_string()))?;

                let mut components = Vec::new();
                if let Some(tag) = list.compound() {
                    if !tag.is_empty() {
                        let value = EffectComponentUnion::from_effect_nbt_tag_as(
                            kind,
                            EffectNbtTag::Compound(tag),
                        )?;
                        components.push(value);
                    }
                } else {
                    let list = list.list().ok_or_else(|| {
                        DeserializeError::MismatchedFieldType("effects".to_owned())
                    })?;

                    if let Some(tags) = list.compounds() {
                        for tag in tags {
                            let value = EffectComponentUnion::from_effect_nbt_tag_as(
                                kind,
                                EffectNbtTag::Compound(tag),
                            )?;
                            components.push(value);
                        }
                    } else {
                        let value = EffectComponentUnion::from_effect_nbt_tag_as(
                            kind,
                            EffectNbtTag::List(list),
                        )?;
                        components.push(value);
                    }
                }

                effects.insert(kind, components);
            }
        }

        let value = Self { effects };
        Ok(value)
    }
}

impl Debug for EnchantmentData {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("EnchantmentData")
            .field("effects", &self.effects.keys())
            .finish()
    }
}

impl Clone for EnchantmentData {
    fn clone(&self) -> Self {
        let mut effects = IndexMap::with_capacity(self.effects.len());
        for (kind, effect) in &self.effects {
            effects.insert(
                *kind,
                effect
                    .iter()
                    .map(|e| unsafe { e.clone_as(*kind) })
                    .collect(),
            );
        }
        EnchantmentData { effects }
    }
}