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 bevy_ecs::component::Component;
11use thiserror::Error;
12
13#[derive(Clone, Component, 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
25 pub block_interaction_range: AttributeInstance,
26 pub entity_interaction_range: AttributeInstance,
27
28 pub step_height: AttributeInstance,
29}
30
31impl Attributes {
32 pub fn get_mut(&mut self, attribute: Attribute) -> Option<&mut AttributeInstance> {
35 let value = match attribute {
36 Attribute::MovementSpeed => &mut self.movement_speed,
37 Attribute::SneakingSpeed => &mut self.sneaking_speed,
38 Attribute::AttackSpeed => &mut self.attack_speed,
39 Attribute::WaterMovementEfficiency => &mut self.water_movement_efficiency,
40 Attribute::MiningEfficiency => &mut self.mining_efficiency,
41 Attribute::BlockInteractionRange => &mut self.block_interaction_range,
42 Attribute::EntityInteractionRange => &mut self.entity_interaction_range,
43 Attribute::StepHeight => &mut self.step_height,
44 _ => return None,
45 };
46 Some(value)
47 }
48}
49
50#[derive(Clone, Debug)]
53pub struct AttributeInstance {
54 pub base: f64,
55 modifiers_by_id: HashMap<Identifier, AttributeModifier>,
56 }
58
59#[derive(Clone, Debug, Error)]
62#[error("A modifier with this ID is already present.")]
63pub struct AlreadyPresentError;
64
65impl AttributeInstance {
66 pub fn new(base: f64) -> Self {
67 Self {
68 base,
69 modifiers_by_id: HashMap::new(),
70 }
71 }
72
73 pub fn calculate(&self) -> f64 {
74 let mut total = self.base;
75 for modifier in self.modifiers_by_id.values() {
76 match modifier.operation {
77 AttributeModifierOperation::AddValue => total += modifier.amount,
78 AttributeModifierOperation::AddMultipliedBase => {
79 total += modifier.amount * self.base
80 }
81 AttributeModifierOperation::AddMultipliedTotal => total *= 1. + modifier.amount,
82 };
83 }
84 total
85 }
86
87 pub fn insert(&mut self, modifier: AttributeModifier) -> Option<AttributeModifier> {
90 self.modifiers_by_id.insert(modifier.id.clone(), modifier)
91 }
92
93 pub fn try_insert(&mut self, modifier: AttributeModifier) -> Result<(), AlreadyPresentError> {
96 match self.modifiers_by_id.entry(modifier.id.clone()) {
97 hash_map::Entry::Occupied(_) => Err(AlreadyPresentError),
98 hash_map::Entry::Vacant(entry) => {
99 entry.insert(modifier);
100 Ok(())
101 }
102 }
103 }
104
105 pub fn remove(&mut self, id: &Identifier) -> Option<AttributeModifier> {
108 self.modifiers_by_id.remove(id)
109 }
110}
111
112pub fn sprinting_modifier() -> AttributeModifier {
113 AttributeModifier {
114 id: Identifier::new("sprinting"),
115 amount: 0.3f32 as f64,
116 operation: AttributeModifierOperation::AddMultipliedTotal,
117 }
118}
119pub fn base_attack_speed_modifier(amount: f64) -> AttributeModifier {
120 AttributeModifier {
121 id: Identifier::new("base_attack_speed"),
122 amount,
123 operation: AttributeModifierOperation::AddValue,
124 }
125}
126pub fn creative_block_interaction_range_modifier() -> AttributeModifier {
127 AttributeModifier {
128 id: Identifier::new("creative_mode_block_range"),
129 amount: 0.5,
130 operation: AttributeModifierOperation::AddValue,
131 }
132}
133
134pub fn creative_entity_interaction_range_modifier() -> AttributeModifier {
135 AttributeModifier {
136 id: Identifier::new("creative_mode_entity_range"),
137 amount: 2.0,
138 operation: AttributeModifierOperation::AddValue,
139 }
140}