use async_std::channel::Sender; use async_std::sync::RwLock; use log::debug; use nalgebra::{point, vector}; use rapier2d_f64::na::Vector2; use rapier2d_f64::prelude::{ BroadPhase, CCDSolver, ColliderBuilder, ColliderSet, FixedJointBuilder, ImpulseJointHandle, ImpulseJointSet, IntegrationParameters, IslandManager, Isometry, MassProperties, MultibodyJointSet, NarrowPhase, PhysicsPipeline, Real, RigidBodyBuilder, RigidBodyHandle, RigidBodySet, }; use starkingdoms_protocol::api::APISavedPlayerData; use starkingdoms_protocol::module::ModuleType; use std::collections::HashMap; use std::f64::consts::PI; use std::net::SocketAddr; use std::sync::Arc; use crate::entity::{get_entity_id, Entity, EntityHandler, EntityId}; use crate::SCALE; #[derive(Clone)] pub struct ClientManager { pub handlers: Arc>>, pub usernames: Arc>>, } #[derive(Clone)] pub struct Player { pub handle: RigidBodyHandle, pub input: PlayerInput, pub addr: SocketAddr, pub auth_token: Option, pub auth_user: Option, pub children: [Option; 4], } impl Player { pub fn as_api_data(&self) -> APISavedPlayerData { APISavedPlayerData {} } pub fn load_api_data(&mut self, _data: &APISavedPlayerData) {} pub fn search_modules(&self, entities: &EntityHandler) -> Vec { let mut modules = Vec::new(); for attachment in self.children.iter().flatten() { if let Entity::AttachedModule(child_module) = entities.entities.get(&attachment.child).unwrap() { modules.append(&mut child_module.search_modules(entities)); } } modules } } #[derive(Debug, Clone)] pub struct Module { pub handle: RigidBodyHandle, pub module_type: ModuleType, pub lifetime: f64, } #[derive(Clone)] pub struct ModuleTemplate { pub translation: Vector2, pub mass_properties: MassProperties, pub module_type: ModuleType, } #[derive(Debug, Clone)] pub struct AttachedModule { pub handle: RigidBodyHandle, pub module_type: ModuleType, pub player_id: EntityId, pub children: [Option; 4], } impl AttachedModule { pub fn attach( data: &mut PhysicsData, entities: &mut EntityHandler, parent: EntityId, player_id: EntityId, module: Module, attachment_slot: usize, ) { let mut entity_map = entities.entities.clone(); let loose_id = entities .get_from_module(&module) .expect("loose module does not exist"); let loose_body = data .rigid_body_set .get(module.handle) .expect("loose module does not exist"); let parent_entity = entity_map .get_mut(&parent) .expect("parent id does not exist"); let parent_handle = match parent_entity { Entity::Player(player) => player.handle, Entity::AttachedModule(module) => module.handle, _ => { panic!("unexpected parent"); } }; //let parent_body = data.rigid_body_set // .get(parent_handle).unwrap(); // create attachment module let module_collider = ColliderBuilder::cuboid(25.0 / SCALE, 25.0 / SCALE) .mass_properties(loose_body.mass_properties().local_mprops) .build(); let module_body = RigidBodyBuilder::dynamic() .translation(*loose_body.translation()) .rotation(loose_body.rotation().angle()) .build(); let attached_handle = data.rigid_body_set.insert(module_body); data.collider_set.insert_with_parent( module_collider, attached_handle, &mut data.rigid_body_set, ); let attach_joint = FixedJointBuilder::new() .local_anchor1(point![0.0, 0.0]) .local_anchor2(point![0.0, 0.0]) .build(); let attach_joint_handle = data.impulse_joint_set .insert(parent_handle, attached_handle, attach_joint, true); let attached_module = AttachedModule { handle: attached_handle, module_type: module.module_type, player_id, children: [None, None, None, None], }; let attached_id = get_entity_id(); match parent_entity { Entity::Player(ref mut player) => { player.children[attachment_slot] = Some(Attachment { child: attached_id, connection: attach_joint_handle, }); } Entity::AttachedModule(ref mut module) => { module.children[attachment_slot] = Some(Attachment { child: attached_id, connection: attach_joint_handle, }); } _ => { panic!("unexpected parent"); } }; entity_map.insert(attached_id, Entity::AttachedModule(attached_module)); // delete loose module data.rigid_body_set.remove( module.handle, &mut data.island_manager, &mut data.collider_set, &mut data.impulse_joint_set, &mut data.multibody_joint_set, true, ); entities.entities.remove(&loose_id); } pub fn attach_new( data: &mut PhysicsData, entities: &mut EntityHandler, parent: EntityId, player_id: EntityId, module: ModuleTemplate, attachment_slot: usize, ) { let mut entity_map = entities.entities.clone(); //let loose_id = entities.get_from_module(&module).expect("loose module does not exist"); //let loose_body = data.rigid_body_set.get(module.handle).expect("loose module does not exist"); let parent_entity = entity_map .get_mut(&parent) .expect("parent id does not exist"); let parent_handle = match parent_entity { Entity::Player(player) => player.handle, Entity::AttachedModule(module) => module.handle, _ => { panic!("unexpected parent"); } }; let parent_body = data.rigid_body_set.get(parent_handle).expect("Parent body does not exist"); let parent_pos = vector![parent_body.translation().x, parent_body.translation().y]; let (anchor, rotation) = match attachment_slot { 0 => { (point![ 0. / SCALE, 53. / SCALE ], PI) } 1 => { (point![ -53. / SCALE, 0. / SCALE ], -PI/2.) } 2 => { (point![ 0. / SCALE, -53. / SCALE ], 0.) } 3 => { (point![ 53. / SCALE, 0. / SCALE ], PI/2.) } _ => { (point![ 0. / SCALE, 53. / SCALE ], 0.) } }; let relative_pos = vector![anchor.y * -(rotation + parent_body.rotation().angle()).sin(), anchor.y * (rotation + parent_body.rotation().angle()).cos()]; let module_pos = parent_pos + relative_pos; // create attachment module let module_collider = ColliderBuilder::cuboid(25.0 / SCALE, 25.0 / SCALE) .mass_properties(module.mass_properties) .build(); let module_body = RigidBodyBuilder::dynamic() .translation(module_pos) .rotation(parent_body.rotation().angle() + rotation) .build(); let attached_handle = data.rigid_body_set.insert(module_body); data.collider_set.insert_with_parent( module_collider, attached_handle, &mut data.rigid_body_set, ); let attach_joint = FixedJointBuilder::new() .local_anchor1(anchor) .local_anchor2(point![0.0, 0.0 / SCALE]) .local_frame2(Isometry::rotation(rotation)) .build(); let attach_joint_handle = data.impulse_joint_set .insert(parent_handle, attached_handle, attach_joint, true); let attached_module = AttachedModule { handle: attached_handle, module_type: module.module_type, player_id, children: [None, None, None, None], }; let attached_id = get_entity_id(); match parent_entity { Entity::Player(ref mut player) => { player.children[attachment_slot] = Some(Attachment { child: attached_id, connection: attach_joint_handle, }); } Entity::AttachedModule(ref mut module) => { module.children[attachment_slot] = Some(Attachment { child: attached_id, connection: attach_joint_handle, }); } _ => { panic!("unexpected parent"); } }; entity_map.insert(attached_id, Entity::AttachedModule(attached_module)); entities.entities = entity_map; } // TODO: remove this function pub fn to_module(&self) -> Module { Module { handle: self.handle, module_type: self.module_type, lifetime: 10., } } pub fn search_modules(&self, entities: &EntityHandler) -> Vec { let mut modules = Vec::new(); for attachment in self.children.iter().flatten() { if let Entity::AttachedModule(child_module) = entities.entities.get(&attachment.child).unwrap() { modules.append(&mut child_module.search_modules(entities)); } } modules } } #[derive(Debug, Clone)] pub struct Attachment { pub child: EntityId, pub connection: ImpulseJointHandle, } #[derive(Default, Clone)] pub struct PlayerInput { pub up: bool, pub left: bool, pub right: bool, pub down: bool, } #[derive(Clone)] pub struct ClientHandler { pub tx: Sender, } #[derive(Clone, Default)] pub struct PhysicsData { pub gravity: Vector2, pub integration_parameters: IntegrationParameters, pub island_manager: IslandManager, pub broad_phase: BroadPhase, pub narrow_phase: NarrowPhase, pub rigid_body_set: RigidBodySet, pub collider_set: ColliderSet, pub impulse_joint_set: ImpulseJointSet, pub multibody_joint_set: MultibodyJointSet, pub ccd_solver: CCDSolver, } impl PhysicsData { pub fn tick(&mut self, pipeline: &mut PhysicsPipeline) { pipeline.step( &self.gravity, &self.integration_parameters, &mut self.island_manager, &mut self.broad_phase, &mut self.narrow_phase, &mut self.rigid_body_set, &mut self.collider_set, &mut self.impulse_joint_set, &mut self.multibody_joint_set, &mut self.ccd_solver, None, &(), &(), ); } } #[derive(Debug, Clone)] pub enum ClientHandlerMessage { Tick, ChatMessage { from: String, message: String, }, PlayersUpdate { players: Vec, }, PlanetData { planets: Vec, }, ModulesUpdate { modules: Vec, }, }