veloren_common/
tether.rs

1use crate::{
2    comp,
3    link::{Is, Link, LinkHandle, Role},
4    mounting::{Rider, VolumeRider},
5    uid::{IdMaps, Uid},
6};
7use serde::{Deserialize, Serialize};
8use specs::{Entities, Read, ReadStorage, WriteStorage};
9use vek::*;
10
11#[derive(Serialize, Deserialize, Debug)]
12pub struct Leader;
13
14impl Role for Leader {
15    type Link = Tethered;
16}
17
18#[derive(Serialize, Deserialize, Debug)]
19pub struct Follower;
20
21impl Role for Follower {
22    type Link = Tethered;
23}
24
25#[derive(Serialize, Deserialize, Debug)]
26pub struct Tethered {
27    pub leader: Uid,
28    pub follower: Uid,
29    pub tether_length: f32,
30}
31
32#[derive(Debug)]
33pub enum TetherError {
34    NoSuchEntity,
35    NotTetherable,
36}
37
38impl Link for Tethered {
39    type CreateData<'a> = (
40        Read<'a, IdMaps>,
41        WriteStorage<'a, Is<Leader>>,
42        WriteStorage<'a, Is<Follower>>,
43        ReadStorage<'a, Is<Rider>>,
44        ReadStorage<'a, Is<VolumeRider>>,
45    );
46    type DeleteData<'a> = (
47        Read<'a, IdMaps>,
48        WriteStorage<'a, Is<Leader>>,
49        WriteStorage<'a, Is<Follower>>,
50    );
51    type Error = TetherError;
52    type PersistData<'a> = (
53        Read<'a, IdMaps>,
54        Entities<'a>,
55        ReadStorage<'a, comp::Health>,
56        ReadStorage<'a, Is<Leader>>,
57        ReadStorage<'a, Is<Follower>>,
58    );
59
60    fn create(
61        this: &LinkHandle<Self>,
62        (id_maps, is_leaders, is_followers, is_riders, is_volume_rider): &mut Self::CreateData<'_>,
63    ) -> Result<(), Self::Error> {
64        let entity = |uid: Uid| id_maps.uid_entity(uid);
65
66        if this.leader == this.follower {
67            // Forbid self-tethering
68            Err(TetherError::NotTetherable)
69        } else if let Some((leader, follower)) = entity(this.leader).zip(entity(this.follower)) {
70            // Ensure that neither leader or follower are already part of a conflicting
71            // relationship
72            if !is_riders.contains(follower)
73                && !is_volume_rider.contains(follower)
74                && !is_followers.contains(follower)
75                // TODO: Does this definitely prevent tether cycles?
76                && (!is_leaders.contains(follower) || !is_followers.contains(leader))
77            {
78                let _ = is_leaders.insert(leader, this.make_role());
79                let _ = is_followers.insert(follower, this.make_role());
80                Ok(())
81            } else {
82                Err(TetherError::NotTetherable)
83            }
84        } else {
85            Err(TetherError::NoSuchEntity)
86        }
87    }
88
89    fn persist(
90        this: &LinkHandle<Self>,
91        (id_maps, entities, healths, is_leaders, is_followers): &mut Self::PersistData<'_>,
92    ) -> bool {
93        let entity = |uid: Uid| id_maps.uid_entity(uid);
94
95        if let Some((leader, follower)) = entity(this.leader).zip(entity(this.follower)) {
96            let is_alive = |entity| {
97                entities.is_alive(entity) && healths.get(entity).is_none_or(|h| !h.is_dead)
98            };
99
100            // Ensure that both entities are alive and that they continue to be linked
101            is_alive(leader)
102                && is_alive(follower)
103                && is_leaders.get(leader).is_some()
104                && is_followers.get(follower).is_some()
105        } else {
106            false
107        }
108    }
109
110    fn delete(
111        this: &LinkHandle<Self>,
112        (id_maps, is_leaders, is_followers): &mut Self::DeleteData<'_>,
113    ) {
114        let entity = |uid: Uid| id_maps.uid_entity(uid);
115
116        let leader = entity(this.leader);
117        let follower = entity(this.follower);
118
119        // Delete link components
120        leader.map(|leader| is_leaders.remove(leader));
121        follower.map(|follower| is_followers.remove(follower));
122    }
123}