veloren_common/comp/body/
plugin.rs1use 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 iter() -> impl Iterator<Item = Self> { std::iter::once(Body { species: 0 }) }
79
80 pub fn mass(&self) -> Mass { Mass(PLUGIN_SPECIES.read().0[self.species].mass) }
81
82 pub fn dimensions(&self) -> Vec3<f32> {
83 Vec3::from_slice(&PLUGIN_SPECIES.read().0[self.species].dimensions)
84 }
85
86 pub fn base_health(&self) -> u16 { PLUGIN_SPECIES.read().0[self.species].base_health }
87
88 pub fn flee_health(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].flee_health }
89
90 pub fn parasite_drag(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].parasite_drag }
91
92 pub fn base_accel(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].base_accel }
93
94 pub fn base_ori_rate(&self) -> f32 { PLUGIN_SPECIES.read().0[self.species].base_ori_rate }
95
96 pub fn swim_thrust(&self) -> Option<f32> { PLUGIN_SPECIES.read().0[self.species].swim_thrust }
97
98 pub fn random() -> Self { Body { species: 0 } }
99
100 pub fn id(&self) -> String { PLUGIN_SPECIES.read().0[self.species].id.clone() }
101
102 #[inline]
103 pub fn random_with(_rng: &mut impl rand::Rng, &species: &Species) -> Self { Self { species } }
104
105 fn from_name(species: &str) -> Result<Body, NotFound> {
106 let guard = PLUGIN_SPECIES.read();
107 let elem = guard
108 .0
109 .iter()
110 .enumerate()
111 .find(|(_n, spec)| spec.id == species);
112 if let Some((n, _)) = elem {
113 Ok(Body { species: n })
114 } else {
115 Err(NotFound)
116 }
117 }
118}
119
120impl From<Body> for super::Body {
121 fn from(body: Body) -> Self { super::Body::Plugin(body) }
122}
123
124pub type Species = usize;
125
126#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
128pub struct AllSpecies<SpeciesMeta> {
129 pub plugin: SpeciesMeta,
130}
131
132impl<'a, SpeciesMeta> core::ops::Index<&'a Species> for AllSpecies<SpeciesMeta> {
133 type Output = SpeciesMeta;
134
135 #[inline]
136 fn index(&self, _index: &'a Species) -> &Self::Output { &self.plugin }
137}
138
139pub struct SpeciesIter {
140 current: usize,
141 max: usize,
142}
143
144impl Iterator for SpeciesIter {
145 type Item = Species;
146
147 fn next(&mut self) -> Option<Self::Item> {
148 if self.current >= self.max {
149 None
150 } else {
151 let result = self.current;
152 self.current += 1;
153 Some(result)
154 }
155 }
156}
157
158impl<'a, SpeciesMeta: 'a> IntoIterator for &'a AllSpecies<SpeciesMeta> {
159 type IntoIter = SpeciesIter;
160 type Item = Species;
161
162 fn into_iter(self) -> Self::IntoIter {
163 SpeciesIter {
164 current: 0,
165 max: PLUGIN_SPECIES.read().0.len(),
166 }
167 }
168}
169
170pub fn parse_name(s: &str) -> Option<NpcBody> {
171 tracing::info!("parse_name {s}");
172 let guard = PLUGIN_SPECIES.read();
173 let elem = guard
174 .0
175 .iter()
176 .enumerate()
177 .find(|(_n, species)| species.id == s);
178 elem.map(|(n, _species)| {
179 NpcBody(
180 crate::npc::NpcKind::Plugin,
181 Box::new(move || crate::comp::body::Body::Plugin(Body { species: n })),
182 )
183 })
184}
185
186pub fn test() {
187 println!("{:?}", &*PLUGIN_SPECIES);
188}