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) => !matches!(
45            quad_med.species,
46            quadruped_medium::Species::Catoblepas
47                | quadruped_medium::Species::Mammoth
48                | quadruped_medium::Species::Elephant
49                | quadruped_medium::Species::Hirdrasil
50        ),
51        Body::QuadrupedLow(_)
52        | Body::QuadrupedSmall(_)
53        | Body::BirdMedium(_)
54        | Body::Crustacean(_) => true,
55        _ => false,
56    }
57}
58
59pub fn is_mountable(
60    mount: &Body,
61    mount_mass: &Mass,
62    rider: Option<&Body>,
63    rider_mass: Option<&Mass>,
64) -> bool {
65    let is_light_enough = rider_mass.is_some_and(|r| r.0 / mount_mass.0 < 0.7);
66
67    match mount {
68        Body::Humanoid(_) => matches!(rider, Some(Body::BirdMedium(_))) && is_light_enough,
69        Body::Ship(_) => true,
70        Body::Object(_) => false,
71        Body::Item(_) => false,
72        _ => is_light_enough,
73    }
74}
75
76impl Component for Pet {
77    // Using `DenseVecStorage` has a u64 space overhead per entity and `Pet` just
78    // has an `Arc` pointer which is the same size on 64-bit platforms. So it
79    // isn't worth using `DenseVecStorage` here.
80    type Storage = specs::VecStorage<Self>;
81}