veloren_common/comp/body/
parts.rs

1use std::cmp::Ordering;
2
3use rand::Rng;
4use serde::{Deserialize, Serialize};
5use specs::{Component, DerefFlaggedStorage};
6
7use crate::resources::Time;
8
9#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
10pub enum HeadState {
11    Attached,
12    Detached(Time),
13}
14
15impl HeadState {
16    pub fn is_attached(&self) -> bool { matches!(self, Self::Attached) }
17}
18
19#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
20#[serde(deny_unknown_fields)]
21pub struct Heads {
22    heads: Vec<HeadState>,
23}
24
25impl Heads {
26    pub fn new(amount: usize) -> Self {
27        Self {
28            heads: vec![HeadState::Attached; amount],
29        }
30    }
31
32    pub fn capacity(&self) -> usize { self.heads.len() }
33
34    pub fn amount(&self) -> usize { self.heads.iter().filter(|h| h.is_attached()).count() }
35
36    pub fn amount_missing(&self) -> usize { self.capacity() - self.amount() }
37
38    pub fn remove_one(&mut self, rng: &mut impl Rng, time: Time) -> Option<usize> {
39        if self.amount() == 0 {
40            return None;
41        }
42
43        let mut h = rng.gen_range(0..self.amount());
44
45        self.heads.iter_mut().position(|head| {
46            if matches!(head, HeadState::Attached) {
47                if h == 0 {
48                    *head = HeadState::Detached(time);
49                    true
50                } else {
51                    h -= 1;
52                    false
53                }
54            } else {
55                false
56            }
57        })
58    }
59
60    pub fn regrow_oldest(&mut self) -> bool {
61        if self.amount_missing() == 0 {
62            return false;
63        }
64
65        self.heads
66            .iter_mut()
67            .min_by(|a, b| match (a, b) {
68                (HeadState::Attached, HeadState::Attached) => Ordering::Equal,
69                (HeadState::Attached, HeadState::Detached(_)) => Ordering::Greater,
70                (HeadState::Detached(_), HeadState::Attached) => Ordering::Less,
71                (HeadState::Detached(a), HeadState::Detached(b)) => {
72                    // Time should never be NaN, but no need to panic here.
73                    a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal)
74                },
75            })
76            .map(|head| {
77                *head = HeadState::Attached;
78            })
79            .is_some()
80    }
81
82    pub fn reset(&mut self) {
83        for head in self.heads.iter_mut() {
84            *head = HeadState::Attached;
85        }
86    }
87
88    /// For correctness don't change the variant for HeadState here.
89    pub fn heads_mut(&mut self) -> &mut [HeadState] { &mut self.heads }
90
91    pub fn heads(&self) -> &[HeadState] { &self.heads }
92}
93
94impl Component for Heads {
95    type Storage = DerefFlaggedStorage<Self, specs::HashMapStorage<Self>>;
96}