//! attachment system overview //! //! hearty has a `Ship` marker component, and a `Parts` auto component containing all parts of the //! ship //! //! parts of the ship have a `PartInShip` pointing back to hearty //! //! parts have many `Joint`s, which are separate children entities representing an attachment point //! get pointers to joints with the `Joints` auto component //! //! joints have `JointOf` pointing to the part they belong to //! if a part is connected to another point at a joint, that joint will have a `Peer`, pointing to //! the Joint entity on the other part, and containing a pointer to the physics world joint //! //! snaps are also a thing and can be generally disregarded use bevy::ecs::entity::MapEntities; use crate::prelude::*; use serde::{Deserialize, Serialize}; use std::ops::Deref; #[derive(Component, Serialize, Deserialize)] #[require(Replicated)] /// The primary component for a ship structure. Will be present on Hearty pub struct Ship; #[derive(Component, Serialize, Deserialize, MapEntities, Deref)] #[relationship_target(relationship = PartInShip, linked_spawn)] #[require(Replicated)] /// List of all parts in this Ship. Will be present on Hearty. /// Managed automatically by attachment system (do not modify)y, pub struct Parts(#[entities] Vec); #[derive(Component, Serialize, Deserialize, MapEntities, Debug)] #[relationship(relationship_target = Parts)] #[require(Replicated)] /// A Pointer to the `Ship` that this part belongs to. Managed automatically by attachment system /// (do not add/remove manually) pub struct PartInShip(#[entities] pub Entity); #[derive(Component, Serialize, Deserialize)] #[require(Transform)] #[require(Replicated)] /// A `Joint` is a separate entity (child of a part) that represents a single possible attachment /// point for that part. pub struct Joint { pub id: JointId, pub transform: Transform, } #[derive(Component, Serialize, Deserialize, MapEntities)] #[require(Replicated)] /// A `Peer` is a pointer component of a `Joint` that references the Joint entity it is connected to. /// Two joints are said to be 'peered' when they are attached to each other. /// Two Parts are connected when they have a set of peered `Joint`s pub struct Peer { #[entities] pub peer_joint_entity_id: Entity, #[entities] pub physics_joint: Entity } #[derive(Component, Serialize, Deserialize, MapEntities)] #[relationship(relationship_target = Joints)] #[require(Replicated)] /// A pointer to the `Part` that this `Joint` belongs to. Managed automatically, do not add/remove pub struct JointOf(#[entities] pub Entity); #[derive(Component, Serialize, Deserialize, MapEntities, Debug, Clone)] #[relationship_target(relationship = JointOf)] #[require(Replicated)] /// All the `Joint`s that belong to this `Part`. Managed automatically, do not modify pub struct Joints(#[entities] Vec); impl Deref for Joints { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Component, Serialize, Deserialize, MapEntities)] #[relationship(relationship_target = Snaps)] #[require(Replicated)] /// The `Part` that this Snap belongs to. A Snap is an internal entity used for snapping during /// the attachment routine. Managed automatically. pub struct SnapOf(#[entities] pub Entity); #[derive(Component, Serialize, Deserialize, MapEntities)] #[relationship_target(relationship = SnapOf)] #[require(Replicated)] /// All the `Snap`s of this `Joint`. Managed automatically. pub struct Snaps(#[entities] Vec); impl Deref for Snaps { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct JointId(pub String); impl JointId { #[must_use] pub fn from_part_and_joint_id(part: impl AsRef, joint: impl AsRef) -> Self { Self(format!("{}:{}", part.as_ref(), joint.as_ref())) } } #[derive(Serialize, Deserialize, Component, MapEntities)] #[require(Replicated)] /// The `Joint` that this `Snap` belongs to pub struct SnapOfJoint(#[entities] pub Entity);