azalea_entity/
attributes.rs1use std::collections::{HashMap, hash_map};
6
7use azalea_core::attribute_modifier_operation::AttributeModifierOperation;
8use azalea_inventory::components::AttributeModifier;
9use azalea_registry::{builtin::Attribute, identifier::Identifier};
10use thiserror::Error;
11
12#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
17#[derive(Clone, Debug)]
18pub struct Attributes {
19 pub movement_speed: AttributeInstance,
20 pub sneaking_speed: AttributeInstance,
21 pub attack_speed: AttributeInstance,
22 pub water_movement_efficiency: AttributeInstance,
23 pub mining_efficiency: AttributeInstance,
24 pub block_break_speed: AttributeInstance,
25
26 pub block_interaction_range: AttributeInstance,
27 pub entity_interaction_range: AttributeInstance,
28
29 pub step_height: AttributeInstance,
30}
31
32impl Attributes {
33 pub fn get_mut(&mut self, attribute: Attribute) -> Option<&mut AttributeInstance> {
36 let value = match attribute {
37 Attribute::MovementSpeed => &mut self.movement_speed,
38 Attribute::SneakingSpeed => &mut self.sneaking_speed,
39 Attribute::AttackSpeed => &mut self.attack_speed,
40 Attribute::WaterMovementEfficiency => &mut self.water_movement_efficiency,
41 Attribute::MiningEfficiency => &mut self.mining_efficiency,
42 Attribute::BlockInteractionRange => &mut self.block_interaction_range,
43 Attribute::EntityInteractionRange => &mut self.entity_interaction_range,
44 Attribute::StepHeight => &mut self.step_height,
45 Attribute::BlockBreakSpeed => &mut self.block_break_speed,
46 _ => return None,
47 };
48 Some(value)
49 }
50}
51
52#[derive(Clone, Debug)]
55pub struct AttributeInstance {
56 pub base: f64,
57 modifiers_by_id: HashMap<Identifier, AttributeModifier>,
58 }
60
61#[derive(Clone, Debug, Error)]
64#[error("A modifier with this ID is already present.")]
65pub struct AlreadyPresentError;
66
67impl AttributeInstance {
68 pub fn new(base: f64) -> Self {
69 Self {
70 base,
71 modifiers_by_id: HashMap::new(),
72 }
73 }
74
75 pub fn calculate(&self) -> f64 {
76 let mut total = self.base;
77 for modifier in self.modifiers_by_id.values() {
78 match modifier.operation {
79 AttributeModifierOperation::AddValue => total += modifier.amount,
80 AttributeModifierOperation::AddMultipliedBase => {
81 total += modifier.amount * self.base
82 }
83 AttributeModifierOperation::AddMultipliedTotal => total *= 1. + modifier.amount,
84 };
85 }
86 total
87 }
88
89 pub fn insert(&mut self, modifier: AttributeModifier) -> Option<AttributeModifier> {
92 self.modifiers_by_id.insert(modifier.id.clone(), modifier)
93 }
94
95 pub fn try_insert(&mut self, modifier: AttributeModifier) -> Result<(), AlreadyPresentError> {
98 match self.modifiers_by_id.entry(modifier.id.clone()) {
99 hash_map::Entry::Occupied(_) => Err(AlreadyPresentError),
100 hash_map::Entry::Vacant(entry) => {
101 entry.insert(modifier);
102 Ok(())
103 }
104 }
105 }
106
107 pub fn remove(&mut self, id: &Identifier) -> Option<AttributeModifier> {
110 self.modifiers_by_id.remove(id)
111 }
112}
113
114pub fn sprinting_modifier() -> AttributeModifier {
115 AttributeModifier {
116 id: Identifier::new("sprinting"),
117 amount: 0.3f32 as f64,
118 operation: AttributeModifierOperation::AddMultipliedTotal,
119 }
120}
121pub fn base_attack_speed_modifier(amount: f64) -> AttributeModifier {
122 AttributeModifier {
123 id: Identifier::new("base_attack_speed"),
124 amount,
125 operation: AttributeModifierOperation::AddValue,
126 }
127}
128pub fn creative_block_interaction_range_modifier() -> AttributeModifier {
129 AttributeModifier {
130 id: Identifier::new("creative_mode_block_range"),
131 amount: 0.5,
132 operation: AttributeModifierOperation::AddValue,
133 }
134}
135
136pub fn creative_entity_interaction_range_modifier() -> AttributeModifier {
137 AttributeModifier {
138 id: Identifier::new("creative_mode_entity_range"),
139 amount: 2.0,
140 operation: AttributeModifierOperation::AddValue,
141 }
142}