use crate::{ comp, link::{Is, Link, LinkHandle, Role}, mounting::{Rider, VolumeRider}, uid::{IdMaps, Uid}, }; use serde::{Deserialize, Serialize}; use specs::{Entities, Read, ReadStorage, WriteStorage}; use vek::*; #[derive(Serialize, Deserialize, Debug)] pub struct Leader; impl Role for Leader { type Link = Tethered; } #[derive(Serialize, Deserialize, Debug)] pub struct Follower; impl Role for Follower { type Link = Tethered; } #[derive(Serialize, Deserialize, Debug)] pub struct Tethered { pub leader: Uid, pub follower: Uid, pub tether_length: f32, } #[derive(Debug)] pub enum TetherError { NoSuchEntity, NotTetherable, } impl Link for Tethered { type CreateData<'a> = ( Read<'a, IdMaps>, WriteStorage<'a, Is>, WriteStorage<'a, Is>, ReadStorage<'a, Is>, ReadStorage<'a, Is>, ); type DeleteData<'a> = ( Read<'a, IdMaps>, WriteStorage<'a, Is>, WriteStorage<'a, Is>, ); type Error = TetherError; type PersistData<'a> = ( Read<'a, IdMaps>, Entities<'a>, ReadStorage<'a, comp::Health>, ReadStorage<'a, Is>, ReadStorage<'a, Is>, ); fn create( this: &LinkHandle, (id_maps, is_leaders, is_followers, is_riders, is_volume_rider): &mut Self::CreateData<'_>, ) -> Result<(), Self::Error> { let entity = |uid: Uid| id_maps.uid_entity(uid); if this.leader == this.follower { // Forbid self-tethering Err(TetherError::NotTetherable) } else if let Some((leader, follower)) = entity(this.leader).zip(entity(this.follower)) { // Ensure that neither leader or follower are already part of a conflicting // relationship if !is_riders.contains(follower) && !is_volume_rider.contains(follower) && !is_followers.contains(follower) // TODO: Does this definitely prevent tether cycles? && (!is_leaders.contains(follower) || !is_followers.contains(leader)) { let _ = is_leaders.insert(leader, this.make_role()); let _ = is_followers.insert(follower, this.make_role()); Ok(()) } else { Err(TetherError::NotTetherable) } } else { Err(TetherError::NoSuchEntity) } } fn persist( this: &LinkHandle, (id_maps, entities, healths, is_leaders, is_followers): &mut Self::PersistData<'_>, ) -> bool { let entity = |uid: Uid| id_maps.uid_entity(uid); if let Some((leader, follower)) = entity(this.leader).zip(entity(this.follower)) { let is_alive = |entity| { entities.is_alive(entity) && healths.get(entity).map_or(true, |h| !h.is_dead) }; // Ensure that both entities are alive and that they continue to be linked is_alive(leader) && is_alive(follower) && is_leaders.get(leader).is_some() && is_followers.get(follower).is_some() } else { false } } fn delete( this: &LinkHandle, (id_maps, is_leaders, is_followers): &mut Self::DeleteData<'_>, ) { let entity = |uid: Uid| id_maps.uid_entity(uid); let leader = entity(this.leader); let follower = entity(this.follower); // Delete link components leader.map(|leader| is_leaders.remove(leader)); follower.map(|follower| is_followers.remove(follower)); } }