use crate::entity::EntityHandler;
use crate::module::Module;
use crate::orbit::constants::{
GAME_ORBITS_ENABLED, 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::{Planet, Planets},
SCALE,
};
use async_std::sync::RwLock;
use async_std::task::sleep;
use log::warn;
use nalgebra::{point, vector};
use rand::Rng;
use rapier2d_f64::prelude::{ColliderBuilder, MassProperties, PhysicsPipeline, RigidBodyBuilder};
use starkingdoms_protocol::{module::ModuleType, planet::PlanetType, player::Player};
use std::{f64::consts::PI, sync::Arc, time::Duration};
use std::error::Error;
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<RwLock<PhysicsData>>,
entities: Arc<RwLock<EntityHandler>>,
) -> Result<(), Box<dyn Error>> {
let mut pipeline = PhysicsPipeline::new();
let mut time = 0.0;
let mut module_timer = 0.0;
let _planet_ids;
{
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();
_planet_ids = Planets::create_planets(
&mut rigid_body_set,
&mut collider_set,
&mut entities.write().await.entities,
)
.await;
data_handle.rigid_body_set = rigid_body_set;
data_handle.collider_set = collider_set;
}
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 planets = entities.write().await;
// update earth (nothing changes, yet)
let earth = planets.get_planet(PlanetType::Earth).ok_or("earth does not exist")?;
let new_earth_position = vector![earth.position.0, earth.position.1];
// update moon
let moon: &mut Planet = &mut planets.get_planet(PlanetType::Moon).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 moon_body = physics_data
.rigid_body_set
.get_mut(moon.body_handle)
.ok_or("moon does not exist")?;
moon_body.set_next_kinematic_position(new_moon_position.into());
moon.position = (
moon_body.translation()[0] / SCALE,
moon_body.translation()[1] / SCALE,
);
}
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.0001, 0.005))
.build();
let angle: f64 = {
let mut rng = rand::thread_rng();
rng.gen::<f64>() * 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 (player_id, player) in &entities.read().await.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 planets = entities.read().await;
let grav_force = planets.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: Default::default(),
});
}
}
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<starkingdoms_protocol::module::AttachedModule> =
Vec::new();
let unattached_modules = entities.get_all_attached();
let mut unattached_modules: Vec<starkingdoms_protocol::module::Module> =
unattached_modules
.iter()
.filter(|m| match this_player {
Some(id) => {
if m.player_id != id {
true
} else {
#[allow(clippy::expect_used)] {
attached_modules.push(
m.to_protocol(&entities, &physics_data.rigid_body_set).expect("module does not exist"),
);
}
false
}
}
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: Default::default(),
}
})
.collect();
let mut protocol_modules: Vec<starkingdoms_protocol::module::Module> = 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: Default::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);
}
}
}