use crate::entity::EntityHandler;
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, Module, PhysicsData},
planet::{Planet, Planets},
SCALE,
};
use async_std::sync::RwLock;
use async_std::task::sleep;
use log::{info, warn};
use nalgebra::{point, vector};
use rand::Rng;
use rapier2d_f64::prelude::{
ColliderBuilder, MassProperties, PhysicsPipeline, RigidBodyBuilder, RigidBodyHandle,
};
use starkingdoms_protocol::{module::ModuleType, planet::PlanetType, player::Player};
use std::{f64::consts::PI, sync::Arc, time::Duration};
pub const ROTATIONAL_FORCE: f64 = 100.0;
pub const LATERAL_FORCE: f64 = 100.0;
pub const MODULE_SPAWN: f64 = 3.0;
pub const MODULE_MAX: u32 = 10;
pub async fn timer_main(
mgr: ClientManager,
physics_data_orig: Arc<RwLock<PhysicsData>>,
entities: Arc<RwLock<EntityHandler>>,
) {
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).unwrap();
let new_earth_position = vector![earth.position.0, earth.position.1];
// update moon
let moon: &mut Planet = &mut planets.get_planet(PlanetType::Moon).unwrap();
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)
.unwrap();
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], 120.0, 122500.0))
.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,
};
entities
.write()
.await
.entities
.insert(get_entity_id(), Entity::Module(module));
}
let mut entities = entities.write().await;
for module in entities.get_modules().iter_mut() {
let module_handle = module.handle;
let module_body = physics_data.rigid_body_set.get_mut(module_handle).unwrap();
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).unwrap();
if let Entity::Module(p_module) = entities.entities.get_mut(&id).unwrap() {
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 (player_id, player) in entities.read().await.get_players().iter() {
let player_handle = player.handle;
let player_body = physics_data.rigid_body_set.get_mut(player_handle).unwrap();
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 left_top_thruster = vector![
-left_top_thruster * rotation.sin(),
left_top_thruster * rotation.cos()
];
let right_top_thruster = vector![
-right_top_thruster * rotation.sin(),
right_top_thruster * rotation.cos()
];
let left_bottom_thruster = vector![
-left_bottom_thruster * rotation.sin(),
left_bottom_thruster * rotation.cos()
];
let right_bottom_thruster = vector![
-right_bottom_thruster * rotation.sin(),
right_bottom_thruster * rotation.cos()
];
let scale = SCALE;
let top_left_point = point![
-25. / scale * rotation.cos() + 25. / scale * rotation.sin(),
-25. / scale * rotation.sin() - 25. / scale * rotation.cos()
] + player_body.translation();
let top_right_point = point![
25. / scale * rotation.cos() + 25. / scale * rotation.sin(),
25. / scale * rotation.sin() - 25. / scale * rotation.cos()
] + player_body.translation();
let bottom_left_point = point![
-25. / scale * rotation.cos() - 25. / scale * rotation.sin(),
-25. / scale * rotation.sin() + 25. / scale * rotation.cos()
] + player_body.translation();
let bottom_right_point = point![
25. / scale * rotation.cos() - 25. / scale * rotation.sin(),
25. / scale * 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).unwrap().clone();
}
// TODO: Figure out how to adjust codegen to use f64
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.iter() {
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 mut modules = entities.read().await.get_modules();
let attached_modules = entities.read().await.get_all_attached();
let attached_handles: Vec<RigidBodyHandle> =
attached_modules.iter().map(|m| m.handle).collect();
modules.append(
&mut attached_modules
.iter()
.map(|m| {
let module = m.to_module();
info!("{:?}", module);
module
})
.collect(),
);
modules.iter().for_each(|module| {
if attached_handles.contains(&module.handle) {
info!(
"{:?}",
physics_data
.rigid_body_set
.get(module.handle)
.unwrap()
.translation()
);
}
});
let protocol_modules: Vec<starkingdoms_protocol::module::Module> = modules
.iter()
.map(|module| {
let body = physics_data.rigid_body_set.get(module.handle).unwrap();
return starkingdoms_protocol::module::Module {
module_type: module.module_type.into(),
rotation: body.rotation().angle(),
x: body.translation().x * SCALE,
y: body.translation().y * SCALE,
special_fields: Default::default(),
};
})
.collect();
match client_thread
.tx
.send(ClientHandlerMessage::ModulesUpdate {
modules: protocol_modules.clone(),
})
.await
{
Ok(_) => (),
Err(e) => {
warn!("unable to send module position packet: {}", e);
}
};
let world = entities.read().await;
let planet_data = world.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);
}
}
}