use crate::entity::EntityHandler; use crate::module::{Module, AttachedModule}; use crate::orbit::constants::{GAME_ORBITS_ENABLED, MARS_APHELION, MARS_ORBIT_TIME, MARS_PERIHELION, MOON_APOAPSIS, MOON_ORBIT_TIME, MOON_PERIAPSIS}; use crate::orbit::orbit::{calculate_point_on_orbit, calculate_world_position_of_orbit}; use crate::{ entity::{get_entity_id, Entity}, manager::{ClientHandlerMessage, ClientManager, PhysicsData}, planet::Planets, SCALE, }; use async_std::sync::RwLock; use async_std::task::sleep; use log::warn; use nalgebra::{point, vector}; use protobuf::SpecialFields; use rand::Rng; use rapier2d_f64::prelude::{ColliderBuilder, MassProperties, PhysicsPipeline, RigidBodyBuilder}; use starkingdoms_protocol::{module::ModuleType, planet::PlanetType, player::Player}; use std::error::Error; use std::{f64::consts::PI, sync::Arc, time::Duration}; pub const LATERAL_FORCE: f64 = 0.0002; pub const MODULE_SPAWN: f64 = 3.0; pub const MODULE_MAX: u32 = 10; //noinspection ALL pub async fn timer_main( mgr: ClientManager, physics_data_orig: Arc>, entities: Arc>, ) -> Result<(), Box> { let mut pipeline = PhysicsPipeline::new(); let mut time = 0.0; let mut module_timer = 0.0; { let mut data_handle = physics_data_orig.write().await; let mut rigid_body_set = data_handle.rigid_body_set.clone(); let mut collider_set = data_handle.collider_set.clone(); let _ = Planets::create_planets( &mut rigid_body_set, &mut collider_set, &mut entities.write().await.entities, ); data_handle.rigid_body_set = rigid_body_set; data_handle.collider_set = collider_set; } #[allow(clippy::significant_drop_tightening)] // underdeveloped lint, TODO remove when its better loop { sleep(Duration::from_millis(5)).await; time += 5.0 / 1000.0; // 5ms, time is in seconds module_timer += 5.0 / 1000.0; let mut physics_data = physics_data_orig.write().await; // update orbits (but dont, actually, yet) // DO NOT SIMPLIFY EXPRESSION // IT MAY ALWAYS BE TRUE // THATS FINE if GAME_ORBITS_ENABLED { let mut planets = entities.write().await; let mut map = planets.entities.clone(); // update earth (nothing changes, yet) let earth_id = planets.get_planet_id(PlanetType::Earth).ok_or("earth does not exist")?; if let Entity::Planet(earth) = map .get(&earth_id) .ok_or("earth does not exist")? { let new_earth_position = vector![earth.position.0, earth.position.1]; // update moon let moon_id = planets.get_planet_id(PlanetType::Moon).ok_or("moon does not exist")?; if let Entity::Planet(moon) = map .get_mut(&moon_id) .ok_or("moon does not exist")? { let new_moon_position = calculate_world_position_of_orbit( calculate_point_on_orbit(MOON_PERIAPSIS, MOON_APOAPSIS, time / MOON_ORBIT_TIME), new_earth_position, ); let new_moon_position = new_moon_position / SCALE; let moon_body = physics_data .rigid_body_set .get_mut(moon.body_handle) .ok_or("moon does not exist")?; moon_body.set_next_kinematic_translation(new_moon_position); moon.position = ( moon_body.translation()[0], moon_body.translation()[1], ); // update mars let mars_id = planets.get_planet_id(PlanetType::Mars).ok_or("mars does not exist")?; if let Entity::Planet(mars) = map .get_mut(&mars_id) .ok_or("mars does not exist")? { let new_mars_position = calculate_world_position_of_orbit( calculate_point_on_orbit(MARS_PERIHELION, MARS_APHELION, time / MARS_ORBIT_TIME), new_moon_position, ); let new_mars_position = new_mars_position/SCALE; let mars_body = physics_data .rigid_body_set .get_mut(mars.body_handle) .ok_or("mars does not exist")?; mars_body.set_next_kinematic_translation(new_mars_position); mars.position = ( mars_body.translation()[0], mars_body.translation()[1], ); } } } planets.entities = map; } physics_data.tick(&mut pipeline); let mut protocol_players = vec![]; { if module_timer > MODULE_SPAWN && entities.read().await.get_module_count() < MODULE_MAX { module_timer = 0.; let mut rigid_body_set = physics_data.rigid_body_set.clone(); let mut collider_set = physics_data.collider_set.clone(); let module_collider = ColliderBuilder::cuboid(18.75 / SCALE, 23.4375 / SCALE) .translation(vector![0.0, 1.5625 / SCALE]) .mass_properties(MassProperties::new(point![0.0, 0.0], 0.000075, 0.005)) .build(); let angle: f64 = { let mut rng = rand::thread_rng(); rng.gen::() * PI * 2. }; let module_body = RigidBodyBuilder::dynamic() .translation(vector![ angle.cos() * 2050. / SCALE, angle.sin() * 2050.0 / SCALE ]) .build(); let module_handler = rigid_body_set.insert(module_body); collider_set.insert_with_parent( module_collider, module_handler, &mut rigid_body_set, ); physics_data.rigid_body_set = rigid_body_set; physics_data.collider_set = collider_set; let module = Module { handle: module_handler, module_type: ModuleType::Cargo, lifetime: 0.0, flags: 0, }; entities .write() .await .entities .insert(get_entity_id(), Entity::Module(module)); } let mut entities = entities.write().await; for module in &mut entities.get_modules() { let module_handle = module.handle; let module_body = physics_data .rigid_body_set .get_mut(module_handle) .ok_or("module does not exist")?; module_body.reset_forces(true); module_body.reset_torques(true); let grav_force = entities.gravity( (module_body.translation().x, module_body.translation().y), module_body.mass(), ); module_body.apply_impulse(vector![grav_force.0, grav_force.1], true); let id = entities .get_from_module(module) .ok_or("module entity does not exist")?; if let Entity::Module(p_module) = entities .entities .get_mut(&id) .ok_or("module does not exist")? { p_module.lifetime += 5. / 1000.; } if module.lifetime > 80. { let mut rigid_body_set = physics_data.rigid_body_set.clone(); let mut island_manager = physics_data.island_manager.clone(); let mut collider_set = physics_data.collider_set.clone(); let mut impulse_joint_set = physics_data.impulse_joint_set.clone(); let mut multibody_joint_set = physics_data.multibody_joint_set.clone(); rigid_body_set.remove( module.handle, &mut island_manager, &mut collider_set, &mut impulse_joint_set, &mut multibody_joint_set, true, ); physics_data.rigid_body_set = rigid_body_set; physics_data.collider_set = collider_set; physics_data.island_manager = island_manager; physics_data.impulse_joint_set = impulse_joint_set; physics_data.multibody_joint_set = multibody_joint_set; entities.entities.remove(&id); } } for module in &mut entities.get_all_attached() { let module_handle = module.handle; let module_body = physics_data .rigid_body_set .get_mut(module_handle) .ok_or("module does not exist")?; module_body.reset_forces(true); module_body.reset_torques(true); let grav_force = entities.gravity( (module_body.translation().x, module_body.translation().y), module_body.mass(), ); module_body.apply_impulse(vector![grav_force.0, grav_force.1], true); for child in module.children.clone() { if let Some(child) = child { let joint = physics_data.impulse_joint_set .get(child.connection).ok_or("module joint does not exist")?; if joint.impulses.magnitude() > 0.00012 { let module: Option; if let Some(Entity::AttachedModule(p_module)) = entities.entities.get_mut(&child.child) { module = Some(p_module.clone()); } else { warn!("attempted to detach nonexistent module"); continue; } let player_id = module.as_ref().ok_or("cannot detach module that doesn't exist")?.player_id; AttachedModule::detach( &mut physics_data, &mut entities, player_id, &module.ok_or("cannot detach module that doesn't exist")?, ); } } } } } { let mut entities = entities.write().await; for (player_id, player) in &entities.get_players() { let player_handle = player.handle; let player_body = physics_data .rigid_body_set .get_mut(player_handle) .ok_or("player body does not exist")?; player_body.reset_forces(true); player_body.reset_torques(true); let grav_force = entities.gravity( (player_body.translation().x, player_body.translation().y), player_body.mass(), ); player_body.apply_impulse(vector![grav_force.0, grav_force.1], true); let mut left_top_thruster: f64 = 0.0; let mut right_top_thruster: f64 = 0.0; let mut left_bottom_thruster: f64 = 0.0; let mut right_bottom_thruster: f64 = 0.0; if player.input.right { left_top_thruster -= 1.0; right_bottom_thruster += 1.0; } if player.input.left { right_top_thruster -= 1.0; left_bottom_thruster += 1.0; } if player.input.up { left_bottom_thruster -= 1.0; right_bottom_thruster -= 1.0; } if player.input.down { left_top_thruster += 1.0; right_top_thruster += 1.0; } left_top_thruster = LATERAL_FORCE * left_top_thruster.clamp(-1.0, 1.0); right_top_thruster = LATERAL_FORCE * right_top_thruster.clamp(-1.0, 1.0); left_bottom_thruster = LATERAL_FORCE * left_bottom_thruster.clamp(-1.0, 1.0); right_bottom_thruster = LATERAL_FORCE * right_bottom_thruster.clamp(-1.0, 1.0); let rotation = player_body.rotation().clone().angle(); let scale = SCALE; let left_top_thruster = vector![ -left_top_thruster / scale * rotation.sin(), left_top_thruster / scale * rotation.cos() ]; let right_top_thruster = vector![ -right_top_thruster / scale * rotation.sin(), right_top_thruster / scale * rotation.cos() ]; let left_bottom_thruster = vector![ -left_bottom_thruster / scale * rotation.sin(), left_bottom_thruster / scale * rotation.cos() ]; let right_bottom_thruster = vector![ -right_bottom_thruster / scale * rotation.sin(), right_bottom_thruster / scale * rotation.cos() ]; let top_left_point = point![ (-25. / scale).mul_add(rotation.cos(), 25. / scale * rotation.sin()), (-25. / scale).mul_add(rotation.sin(), -25. / scale * rotation.cos()) ] + player_body.translation(); let top_right_point = point![ (25. / scale).mul_add(rotation.cos(), 25. / scale * rotation.sin()), (25. / scale).mul_add(rotation.sin(), -25. / scale * rotation.cos()) ] + player_body.translation(); let bottom_left_point = point![ (-25. / scale).mul_add(rotation.cos(), -25. / scale * rotation.sin()), (-25. / scale).mul_add(rotation.sin(), 25. / scale * rotation.cos()) ] + player_body.translation(); let bottom_right_point = point![ (25. / scale).mul_add(rotation.cos(), -25. / scale * rotation.sin()), (25. / scale).mul_add(rotation.sin(), 25. / scale * rotation.cos()) ] + player_body.translation(); player_body.add_force_at_point(left_top_thruster, top_left_point, true); player_body.add_force_at_point(right_top_thruster, top_right_point, true); player_body.add_force_at_point(left_bottom_thruster, bottom_left_point, true); player_body.add_force_at_point(right_bottom_thruster, bottom_right_point, true); let translation = player_body.translation(); let username; { let usernames = mgr.usernames.read().await; username = usernames .get(player_id) .ok_or("username does not exist")? .clone(); } protocol_players.push(Player { rotation, x: (translation.x * SCALE), y: (translation.y * SCALE), username, special_fields: SpecialFields::default(), }); for child in player.children.clone() { if let Some(child) = child { let joint = physics_data.impulse_joint_set .get(child.connection).ok_or("module joint does not exist")?; // displays impulse on joint * 10000 so its visible, use to tune breaking // force //debug!("impulse: {}", joint.impulses.magnitude() * 10000.); if joint.impulses.magnitude() > 0.00012 { let module: Option; if let Some(Entity::AttachedModule(p_module)) = entities.entities.get_mut(&child.child) { module = Some(p_module.clone()); } else { warn!("attempted to detach nonexistent module"); continue; } let player_id = module.as_ref().ok_or("cannot detach module that doesn't exist")?.player_id; AttachedModule::detach( &mut physics_data, &mut entities, player_id, &module.ok_or("cannot detach module that doesn't exist")?, ); } } } } } let mut to_remove = vec![]; let mut mgr_w = mgr.handlers.write().await; let mgr_r = mgr_w.clone(); for (addr, client_thread) in &mgr_r { match client_thread.tx.send(ClientHandlerMessage::Tick).await { Ok(_) => { match client_thread .tx .send(ClientHandlerMessage::PlayersUpdate { players: protocol_players.clone(), }) .await { Ok(_) => (), Err(e) => { warn!("unable to send position packet: {}", e); } }; let modules = entities.read().await.get_modules_id(); let entities = entities.read().await; let this_player = entities.get_player_id(*addr); let mut attached_modules: Vec = Vec::new(); let unattached_modules = entities.get_all_attached(); let mut unattached_modules: Vec = unattached_modules .iter() .filter(|m| match this_player { Some(id) => { if m.player_id == id { #[allow(clippy::expect_used)] { attached_modules.push( m.to_protocol( &entities, &physics_data.rigid_body_set, ) .expect("module does not exist"), ); } false } else { true } } None => true, }) .map(|m| { let id; let module; #[allow(clippy::expect_used)] { (id, module) = m.to_module_id(&entities).expect("unable to get module id"); } //info!("{:?}", module); let body; #[allow(clippy::expect_used)] { body = physics_data .rigid_body_set .get(module.handle) .expect("module body does not exist"); } starkingdoms_protocol::module::Module { module_type: module.module_type.into(), rotation: body.rotation().angle(), x: body.translation().x * SCALE, y: body.translation().y * SCALE, id, flags: module.flags, special_fields: SpecialFields::default(), } }) .collect(); let mut protocol_modules: Vec = modules .iter() .map(|(id, module)| { let body; #[allow(clippy::expect_used)] { body = physics_data .rigid_body_set .get(module.handle) .expect("module body does not exist"); } starkingdoms_protocol::module::Module { module_type: module.module_type.into(), rotation: body.rotation().angle(), x: body.translation().x * SCALE, y: body.translation().y * SCALE, id: *id, flags: module.flags, special_fields: SpecialFields::default(), } }) .collect(); protocol_modules.append(&mut unattached_modules); match client_thread .tx .send(ClientHandlerMessage::ModulesUpdate { modules: protocol_modules.clone(), }) .await { Ok(_) => (), Err(e) => { warn!("unable to send module position packet: {}", e); } }; match client_thread .tx .send(ClientHandlerMessage::ModuleTreeUpdate { modules: attached_modules, }) .await { Ok(_) => (), Err(e) => { warn!("unable to send module tree update packet: {}", e); } } let planet_data = entities.to_protocol(); match client_thread.tx.send(planet_data).await { Ok(_) => (), Err(e) => { warn!("unable to send earth packet: {}", e); } }; } Err(e) => { warn!("unable to update a client thread: {}", e); to_remove.push(addr); } } } for pending_removal in to_remove { mgr_w.remove(pending_removal); } } }