pfx_play/world/
characters.rs1use pfx_load::scene::Value;
2use pfx_physics::rigid::{Character, CharacterDesc};
3
4use super::{ObjectId, World};
5use crate::PlayError;
6use crate::characters::{self, Setting};
7
8impl World {
9 pub fn character(&mut self, id: ObjectId) -> Result<&mut Character, PlayError> {
10 let place = id.index();
11 if !self.characters.contains_key(&place) {
12 let name = self.name(id).to_string();
13 let desc = *self.roster.get(&name).ok_or_else(|| {
14 PlayError::Body(format!("object {name} has no [object.character]"))
15 })?;
16 if self.bodies.contains_key(&place) {
17 return Err(PlayError::Body(format!(
18 "object {name} has a body; a character brings its own capsule"
19 )));
20 }
21 let feet = self.at(id);
22 let character = Character::spawn(&mut self.physics, desc, feet)
23 .map_err(|why| PlayError::Body(format!("character {name}: {why}")))?;
24 self.owners.insert(character.collider(), place);
25 self.characters.insert(place, character);
26 }
27 let objects = &self.objects;
28 self.characters.get_mut(&place).ok_or_else(|| {
29 PlayError::Body(format!("character {} did not spawn", objects[place].name))
30 })
31 }
32
33 pub fn set_character_desc(
34 &mut self,
35 id: ObjectId,
36 desc: CharacterDesc,
37 ) -> Result<(), PlayError> {
38 let name = self.name(id).to_string();
39 let place = id.index();
40 let refuse = |why: String| PlayError::Body(format!("character {name}: {why}"));
41 match self.characters.get_mut(&place) {
42 Some(character) => {
43 let old = character.collider();
44 character
45 .set_desc(&mut self.physics, desc)
46 .map_err(refuse)?;
47 let new = character.collider();
48 if new != old {
49 self.owners.remove(&old);
50 self.owners.insert(new, place);
51 }
52 }
53 None => desc.check().map_err(refuse)?,
54 }
55 self.roster.insert(name, desc);
56 Ok(())
57 }
58
59 pub fn character_of(&self, id: ObjectId) -> Option<&Character> {
60 self.characters.get(&id.index())
61 }
62
63 pub fn characters(&self) -> impl Iterator<Item = (ObjectId, &Character)> {
64 self.characters
65 .iter()
66 .map(|(place, character)| (ObjectId::from_index(*place), character))
67 }
68
69 pub fn character_desc(&self, id: ObjectId) -> Option<&CharacterDesc> {
70 self.roster.get(self.name(id))
71 }
72
73 pub fn remove_character(&mut self, id: ObjectId) -> bool {
74 match self.characters.remove(&id.index()) {
75 Some(character) => {
76 self.owners.remove(&character.collider());
77 character.remove(&mut self.physics)
78 }
79 None => false,
80 }
81 }
82
83 pub(crate) fn step_characters(&mut self) {
84 for character in self.characters.values_mut() {
85 character.step(&mut self.physics);
86 }
87 }
88
89 pub(crate) fn place_characters(&mut self) {
90 let placed: Vec<(usize, [f32; 3])> = self
91 .characters
92 .iter()
93 .map(|(place, character)| (*place, character.feet()))
94 .collect();
95 for (place, feet) in placed {
96 self.move_to(ObjectId::from_index(place), feet);
97 }
98 }
99
100 pub(crate) fn edit_character(
101 &mut self,
102 id: ObjectId,
103 key: &str,
104 value: &Value,
105 ) -> Result<(), String> {
106 let name = self.name(id).to_string();
107 let mut desc = *self
108 .roster
109 .get(&name)
110 .ok_or_else(|| format!("object {name} has no [object.character]"))?;
111 let setting = Setting::of_value(value).ok_or("not a value")?;
112 characters::set(&mut desc, key, &setting)?;
113 self.set_character_desc(id, desc)
114 .map_err(|error| error.to_string())?;
115 Ok(())
116 }
117}