azalea_core/registry_holder/
value.rs1use azalea_registry::{
2 builtin::{
3 Attribute, EnchantmentLevelBasedValueKind as LevelBasedValueKind,
4 EnchantmentValueEffectKind as ValueEffectKind,
5 },
6 identifier::Identifier,
7};
8use simdnbt::{
9 DeserializeError, FromNbtTag,
10 borrow::{NbtCompound, NbtTag},
11};
12
13use crate::{
14 attribute_modifier_operation::AttributeModifierOperation,
15 registry_holder::{components::impl_from_effect_nbt_tag, get_in_compound},
16};
17
18#[derive(Clone, Debug)]
19pub enum ValueEffect {
20 Set {
21 value: LevelBasedValue,
22 },
23 Add {
24 value: LevelBasedValue,
25 },
26 Multiply {
27 factor: LevelBasedValue,
28 },
29 RemoveBinomial {
30 chance: LevelBasedValue,
31 },
32 AllOf {
33 effects: Vec<ValueEffect>,
34 },
35 Exponential {
36 base: LevelBasedValue,
37 exponent: LevelBasedValue,
38 },
39}
40
41impl simdnbt::Deserialize for ValueEffect {
42 fn from_compound(nbt: NbtCompound) -> Result<Self, DeserializeError> {
43 let kind = get_in_compound(&nbt, "type")?;
44 let value = match kind {
45 ValueEffectKind::Set => {
46 let value = get_in_compound(&nbt, "value")?;
47 Self::Set { value }
48 }
49 ValueEffectKind::Add => {
50 let value = get_in_compound(&nbt, "value")?;
51 Self::Add { value }
52 }
53 ValueEffectKind::Multiply => {
54 let factor = get_in_compound(&nbt, "factor")?;
55 Self::Multiply { factor }
56 }
57 ValueEffectKind::RemoveBinomial => {
58 let chance = get_in_compound(&nbt, "chance")?;
59 Self::RemoveBinomial { chance }
60 }
61 ValueEffectKind::AllOf => {
62 let effects = get_in_compound(&nbt, "effects")?;
63 Self::AllOf { effects }
64 }
65 ValueEffectKind::Exponential => {
66 let base = get_in_compound(&nbt, "base")?;
67 let exponent = get_in_compound(&nbt, "exponent")?;
68 Self::Exponential { base, exponent }
69 }
70 };
71 Ok(value)
72 }
73}
74impl_from_effect_nbt_tag!(ValueEffect);
75
76#[derive(Clone, Debug, simdnbt::Deserialize)]
77pub struct AttributeEffect {
78 pub id: Identifier,
79 pub attribute: Attribute,
80 pub amount: LevelBasedValue,
81 pub operation: AttributeModifierOperation,
82}
83impl_from_effect_nbt_tag!(AttributeEffect);
84
85#[derive(Clone, Debug)]
86pub enum LevelBasedValue {
87 Constant(f32),
88 Exponent {
89 base: Box<LevelBasedValue>,
90 power: Box<LevelBasedValue>,
91 },
92 Linear {
93 base: f32,
94 per_level_above_first: f32,
95 },
96 LevelsSquared {
97 added: f32,
98 },
99 Clamped {
100 value: Box<LevelBasedValue>,
101 min: f32,
102 max: f32,
103 },
104 Fraction {
105 numerator: Box<LevelBasedValue>,
106 denominator: Box<LevelBasedValue>,
107 },
108 Lookup {
109 values: Vec<f32>,
110 fallback: Box<LevelBasedValue>,
111 },
112}
113impl LevelBasedValue {
114 pub fn calculate(&self, n: i32) -> f32 {
115 match self {
116 LevelBasedValue::Constant(v) => *v,
117 LevelBasedValue::Exponent { base, power } => {
118 (base.calculate(n) as f64).powf(power.calculate(n) as f64) as f32
119 }
120 LevelBasedValue::Linear {
121 base,
122 per_level_above_first,
123 } => *base + *per_level_above_first * ((n - 1) as f32),
124 LevelBasedValue::LevelsSquared { added } => (n * n) as f32 + *added,
125 LevelBasedValue::Clamped { value, min, max } => value.calculate(n).clamp(*min, *max),
126 LevelBasedValue::Fraction {
127 numerator,
128 denominator,
129 } => {
130 let value = denominator.calculate(n);
131 if value == 0. {
132 0.
133 } else {
134 numerator.calculate(n) / value
135 }
136 }
137 LevelBasedValue::Lookup { values, fallback } => values
138 .get((n - 1) as usize)
139 .copied()
140 .unwrap_or_else(|| fallback.calculate(n)),
141 }
142 }
143}
144
145impl Default for LevelBasedValue {
146 fn default() -> Self {
147 Self::Constant(0.)
148 }
149}
150
151impl FromNbtTag for LevelBasedValue {
152 fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
153 if let Some(f) = tag.float() {
154 return Some(Self::Constant(f));
155 }
156 if let Some(c) = tag.compound() {
157 return Self::from_compound(c).ok();
158 }
159 None
160 }
161}
162impl LevelBasedValue {
163 fn from_compound(nbt: NbtCompound) -> Result<Self, DeserializeError> {
164 let kind = get_in_compound(&nbt, "type")?;
165 let value = match kind {
166 LevelBasedValueKind::Exponent => {
167 let base = Box::new(get_in_compound(&nbt, "base")?);
168 let power = Box::new(get_in_compound(&nbt, "power")?);
169 return Ok(Self::Exponent { base, power });
170 }
171 LevelBasedValueKind::Linear => {
172 let base = get_in_compound(&nbt, "base")?;
173 let per_level_above_first = get_in_compound(&nbt, "per_level_above_first")?;
174 Self::Linear {
175 base,
176 per_level_above_first,
177 }
178 }
179 LevelBasedValueKind::LevelsSquared => {
180 let added = get_in_compound(&nbt, "added")?;
181 Self::LevelsSquared { added }
182 }
183 LevelBasedValueKind::Clamped => {
184 let value = Box::new(get_in_compound(&nbt, "value")?);
185 let min = get_in_compound(&nbt, "min")?;
186 let max = get_in_compound(&nbt, "max")?;
187 Self::Clamped { value, min, max }
188 }
189 LevelBasedValueKind::Fraction => {
190 let numerator = Box::new(get_in_compound(&nbt, "numerator")?);
191 let denominator = Box::new(get_in_compound(&nbt, "denominator")?);
192 Self::Fraction {
193 numerator,
194 denominator,
195 }
196 }
197 LevelBasedValueKind::Lookup => {
198 let values = nbt
199 .list("values")
200 .ok_or(DeserializeError::MissingField)?
201 .floats()
202 .ok_or(DeserializeError::MissingField)?;
203 let fallback = Box::new(get_in_compound(&nbt, "fallback")?);
204 Self::Lookup { values, fallback }
205 }
206 };
207 Ok(value)
208 }
209}