veloren_common/comp/body/
plugin.rs

1use common_assets::{AssetCombined, AssetHandle, Concatenate};
2use lazy_static::lazy_static;
3use serde::{Deserialize, Serialize};
4use vek::Vec3;
5
6use crate::{comp::Mass, npc::NpcBody};
7
8#[derive(Debug, Deserialize)]
9struct PluginSpecies {
10    id: String,
11    mass: f32,
12    dimensions: [f32; 3],
13    base_health: u16,
14    flee_health: f32,
15    parasite_drag: f32,
16    base_accel: f32,
17    base_ori_rate: f32,
18    swim_thrust: Option<f32>,
19}
20
21#[derive(Deserialize, Debug)]
22struct PluginSpeciesEntries(Vec<PluginSpecies>);
23
24impl common_assets::Asset for PluginSpeciesEntries {
25    type Loader = common_assets::RonLoader;
26
27    const EXTENSION: &'static str = "ron";
28}
29impl Concatenate for PluginSpeciesEntries {
30    fn concatenate(self, b: Self) -> Self { Self(self.0.concatenate(b.0)) }
31}
32
33lazy_static! {
34    static ref PLUGIN_SPECIES: AssetHandle<PluginSpeciesEntries> =
35        PluginSpeciesEntries::load_expect_combined_static("common.plugin_bodies");
36}
37
38mod spec_parser {
39    use serde::{Deserialize, Deserializer, Serializer};
40
41    use super::{Body, Species};
42
43    pub fn serialize<S>(species: &Species, serializer: S) -> Result<S::Ok, S::Error>
44    where
45        S: Serializer,
46    {
47        serializer.serialize_str(&super::PLUGIN_SPECIES.read().0[*species].id)
48    }
49
50    pub fn deserialize<'de, D>(deserializer: D) -> Result<Species, D::Error>
51    where
52        D: Deserializer<'de>,
53    {
54        String::deserialize(deserializer)
55            .and_then(|species| {
56                Body::from_name(&species).map_err(|_err| {
57                    serde::de::Error::invalid_value(
58                        serde::de::Unexpected::Str(&species),
59                        &"known species",
60                    )
61                })
62            })
63            .map(|body| body.species)
64    }
65}
66
67#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
68pub struct Body {
69    #[serde(with = "spec_parser")]
70    pub species: Species,
71}
72
73struct NotFound;
74
75impl Body {
76    pub fn mass(&self) -> Mass { Mass(PLUGIN_SPECIES.read().0[self.species].mass) }
77
78    pub fn dimensions(&self) -> Vec3<f32> {
79        Vec3::from_slice(&PLUGIN_SPECIES.read().0[self.species].dimensions)
80    }
81
82    pub fn base_health(&self) -> u16 { PLUGIN_SPECIES.read().0[self.species].base_health }
83
84    pub fn flee_health(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].flee_health }
85
86    pub fn parasite_drag(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].parasite_drag }
87
88    pub fn base_accel(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].base_accel }
89
90    pub fn base_ori_rate(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].base_ori_rate }
91
92    pub fn swim_thrust(&self) -> Option<f32> { PLUGIN_SPECIES.read().0[self.species].swim_thrust }
93
94    pub fn random() -> Self { Body { species: 0 } }
95
96    pub fn id(&self) -> String { PLUGIN_SPECIES.read().0[self.species].id.clone() }
97
98    #[inline]
99    pub fn random_with(_rng: &mut impl rand::Rng, &species: &Species) -> Self { Self { species } }
100
101    fn from_name(species: &str) -> Result<Body, NotFound> {
102        let guard = PLUGIN_SPECIES.read();
103        let elem = guard
104            .0
105            .iter()
106            .enumerate()
107            .find(|(_n, spec)| spec.id == species);
108        if let Some((n, _)) = elem {
109            Ok(Body { species: n })
110        } else {
111            Err(NotFound)
112        }
113    }
114}
115
116impl From<Body> for super::Body {
117    fn from(body: Body) -> Self { super::Body::Plugin(body) }
118}
119
120pub type Species = usize;
121
122/// Data representing per-species generic data.
123#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
124pub struct AllSpecies<SpeciesMeta> {
125    pub plugin: SpeciesMeta,
126}
127
128impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies<SpeciesMeta> {
129    type Output = SpeciesMeta;
130
131    #[inline]
132    fn index(&self, _index: &'a Species) -> &Self::Output { &self.plugin }
133}
134
135pub struct SpeciesIter {
136    current: usize,
137    max: usize,
138}
139
140impl Iterator for SpeciesIter {
141    type Item = Species;
142
143    fn next(&mut self) -> Option<Self::Item> {
144        if self.current >= self.max {
145            None
146        } else {
147            let result = self.current;
148            self.current += 1;
149            Some(result)
150        }
151    }
152}
153
154impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
155    type IntoIter = SpeciesIter;
156    type Item = Species;
157
158    fn into_iter(self) -> Self::IntoIter {
159        SpeciesIter {
160            current: 0,
161            max: PLUGIN_SPECIES.read().0.len(),
162        }
163    }
164}
165
166pub fn parse_name(s: &str) -> Option<NpcBody> {
167    tracing::info!("parse_name {s}");
168    let guard = PLUGIN_SPECIES.read();
169    let elem = guard
170        .0
171        .iter()
172        .enumerate()
173        .find(|(_n, species)| species.id == s);
174    elem.map(|(n, _species)| {
175        NpcBody(
176            crate::npc::NpcKind::Plugin,
177            Box::new(move || crate::comp::body::Body::Plugin(Body { species: n })),
178        )
179    })
180}
181
182pub fn test() {
183    println!("{:?}", &*PLUGIN_SPECIES);
184}