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<RwLock<HashMap<SocketAddr, ClientHandler>>>,
pub usernames: Arc<RwLock<HashMap<SocketAddr, String>>>,
}
#[derive(Clone)]
pub struct Player {
pub handle: RigidBodyHandle,
pub input: PlayerInput,
pub addr: SocketAddr,
pub auth_token: Option<String>,
pub auth_user: Option<String>,
pub children: [Option<Attachment>; 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<AttachedModule> {
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<Real>,
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<Attachment>; 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<AttachedModule> {
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<ClientHandlerMessage>
}
#[derive(Clone, Default)]
pub struct PhysicsData {
pub gravity: Vector2<f64>,
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<starkingdoms_protocol::player::Player> },
PlanetData { planets: Vec<starkingdoms_protocol::planet::Planet> },
ModulesUpdate { modules: Vec<starkingdoms_protocol::module::Module> },
}