use std::collections::HashMap; use std::f64::consts::PI; use std::net::SocketAddr; use std::sync::Arc; use nalgebra::point; use rapier2d_f64::na::Vector2; use rapier2d_f64::prelude::{IntegrationParameters, PhysicsPipeline, IslandManager, BroadPhase, NarrowPhase, ImpulseJointSet, MultibodyJointSet, CCDSolver, RigidBodySet, ColliderSet, RigidBodyHandle, ImpulseJointHandle, RigidBodyBuilder, ColliderBuilder, FixedJointBuilder, Real, MassProperties, Isometry, PrismaticJointBuilder}; use async_std::sync::RwLock; use async_std::channel::Sender; use starkingdoms_protocol::api::APISavedPlayerData; use starkingdoms_protocol::module::ModuleType; use crate::SCALE; use crate::entity::{EntityId, EntityHandler, Entity, get_entity_id}; #[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 child in &self.children { if let Some(attachment) = child { 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 heading: f64, 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 mut 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, rotation: f64) { 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 mut 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"); } }; // create attachment module let module_collider = ColliderBuilder::cuboid(25.0 / SCALE, 25.0 / SCALE) .mass_properties(module.mass_properties) .build(); let module_body = RigidBodyBuilder::fixed() .translation(module.translation) .rotation(module.heading) .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 anchor = point![ -0. / SCALE * rotation.cos() +100. / SCALE * rotation.sin(), -0. / SCALE * rotation.sin() -100. / SCALE * rotation.cos() ]; let attach_joint = PrismaticJointBuilder::new(Vector2::x_axis()) .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 child in &self.children { if let Some(attachment) = child { let child_module = entities.entities.get(&attachment.child).unwrap(); 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 }, }