veloren_common/comp/
pet.rs

1use crate::comp::{body::Body, quadruped_medium};
2use crossbeam_utils::atomic::AtomicCell;
3use specs::Component;
4use std::{num::NonZeroU64, sync::Arc};
5
6use super::Mass;
7
8pub type PetId = AtomicCell<Option<NonZeroU64>>;
9
10// TODO: move to server crate
11#[derive(Clone, Debug)]
12pub struct Pet {
13    database_id: Arc<PetId>,
14}
15
16impl Pet {
17    /// Not to be used outside of persistence - provides mutable access to the
18    /// pet component's database ID which is required to save the pet's data
19    /// from the persistence thread.
20    #[doc(hidden)]
21    pub fn get_database_id(&self) -> Arc<PetId> { Arc::clone(&self.database_id) }
22
23    pub fn new_from_database(database_id: NonZeroU64) -> Self {
24        Self {
25            database_id: Arc::new(AtomicCell::new(Some(database_id))),
26        }
27    }
28}
29
30impl Default for Pet {
31    fn default() -> Self {
32        Self {
33            database_id: Arc::new(AtomicCell::new(None)),
34        }
35    }
36}
37
38/// Determines whether an entity of a particular body variant is tameable.
39pub fn is_tameable(body: &Body) -> bool {
40    // Currently only Quadruped animals can be tamed pending further work
41    // on the pets feature (allowing larger animals to be tamed will
42    // require balance issues to be addressed).
43    match body {
44        Body::QuadrupedMedium(quad_med) =>
45        // NOTE: the reason we ban mammoth from being tameable even though they're
46        // agressive anyway, is that UncomfySilence is going to make them
47        // peaceful after this MR gets merged. Please, remove this note in your MR,
48        // UncomfySilence!
49        {
50            !matches!(
51                quad_med.species,
52                quadruped_medium::Species::Catoblepas
53                    | quadruped_medium::Species::Mammoth
54                    | quadruped_medium::Species::Hirdrasil
55            )
56        },
57        Body::QuadrupedLow(_)
58        | Body::QuadrupedSmall(_)
59        | Body::BirdMedium(_)
60        | Body::Crustacean(_) => true,
61        _ => false,
62    }
63}
64
65pub fn is_mountable(
66    mount: &Body,
67    mount_mass: &Mass,
68    rider: Option<&Body>,
69    rider_mass: Option<&Mass>,
70) -> bool {
71    let is_light_enough = rider_mass.is_some_and(|r| r.0 / mount_mass.0 < 0.7);
72
73    match mount {
74        Body::Humanoid(_) => matches!(rider, Some(Body::BirdMedium(_))) && is_light_enough,
75        Body::Ship(_) => true,
76        Body::Object(_) => false,
77        Body::ItemDrop(_) => false,
78        _ => is_light_enough,
79    }
80}
81
82impl Component for Pet {
83    // Using `DenseVecStorage` has a u64 space overhead per entity and `Pet` just
84    // has an `Arc` pointer which is the same size on 64-bit platforms. So it
85    // isn't worth using `DenseVecStorage` here.
86    type Storage = specs::VecStorage<Self>;
87}