~starkingdoms/starkingdoms

eb52c7256a2b805a2c656644ee79a7d7478fa434 — ghostlyzsh 2 years ago c5c5951
converted planets and players to entities
M server/Cargo.toml => server/Cargo.toml +1 -1
@@ 27,4 27,4 @@ rapier2d-f64 = { version = "0.17.2", features = [ "simd-stable" ] }
nalgebra = "0.32.2"

[build-dependencies]
cargo_metadata = "0.15"
\ No newline at end of file
cargo_metadata = "0.15"

A server/src/entity.rs => server/src/entity.rs +117 -0
@@ 0,0 1,117 @@
use std::{sync::atomic::AtomicU32, collections::HashMap, net::SocketAddr};

use nalgebra::Vector2;
use starkingdoms_protocol::planet::PlanetType;

use crate::{planet::Planet, SCALE, manager::{ClientHandlerMessage, Player}};

pub type EntityId = u32;
pub type Entities = HashMap<EntityId, Entity>;
static mut ENTITY_ID_COUNT: AtomicU32 = AtomicU32::new(0);
pub fn get_entity_id() -> EntityId {
    let last_entity_id = unsafe { &ENTITY_ID_COUNT };
    let id = last_entity_id.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
    if id > 2_147_483_600 { panic!("No remaining entity ids") };
    id
}

pub struct EntityHandler {
    pub entities: Entities,
}

impl EntityHandler {
    pub fn new() -> EntityHandler {
        EntityHandler {
            entities: Entities::new()
        }
    }
    pub fn get_planets(&self) -> Vec<Planet> {
        let mut ids = Vec::new();
        for entity in self.entities.values() {
            if let Entity::Planet(planet) = entity {
                ids.push(planet.clone());
            }
        }
        ids
    }
    pub fn get_planet(&self, planet_type: PlanetType) -> Option<Planet> {
        let mut planets = self.get_planets();
        for i in 0..planets.len() {
            if planets[i].planet_type == planet_type {
                planets.remove(i);
            }
        }
        if planets.len() == 0 {
            return None;
        }
        Some(planets[0].clone())
    }

    pub fn get_players(&self) -> Vec<(SocketAddr, Player)> {
        let mut players = Vec::new();
        for entity in self.entities.values() {
            if let Entity::Player(player) = entity {
                players.push((player.addr, player.clone()));
            }
        }
        players
    }
    pub fn get_player_id(&self, addr: SocketAddr) -> Option<EntityId> {
        for (id, entity) in self.entities.iter() {
            if let Entity::Player(player) = entity {
                if player.addr == addr {
                    return Some(*id);
                }
            }
        }
        None
    }
    pub fn get_player(&self, addr: SocketAddr) -> Option<Player> {
        let mut players = self.get_players();
        for i in 0..players.len() {
            if players[i].0 != addr {
                players.remove(i);
            }
        }
        if players.len() == 0 {
            return None;
        }
        Some(players[0].clone().1)
    }

    pub fn gravity(&self, position: (f64, f64), mass: f64) -> (f64, f64) {
        let mut direction = Vector2::zeros();
        let planets = self.get_planets();
        for planet in planets.clone() {
            let planet_grav = planet.gravity(position, mass);
            direction.x += planet_grav.0;
            direction.y += planet_grav.1;
        }
        (direction.x, direction.y)
    }

    pub fn to_protocol(&self) -> ClientHandlerMessage {
        let mut planets = vec![];

        for planet in self.get_planets().clone() {
            // TODO: Adjust codegen to use f64
            planets.push(starkingdoms_protocol::planet::Planet {
                planet_type: planet.planet_type.into(),
                x: (planet.position.0 * SCALE) as f32,
                y: (planet.position.1 * SCALE) as f32,
                radius: planet.radius as f32, // DO NOT * SCALE
                special_fields: Default::default(),
            });
        }

        ClientHandlerMessage::PlanetData {
            planets
        }
    }
}

#[derive(Clone)]
pub enum Entity {
    Player(Player),
    Planet(Planet),
}

M server/src/handler.rs => server/src/handler.rs +23 -9
@@ 4,7 4,7 @@ use std::sync::Arc;
use std::time::{Duration, SystemTime};
use futures::stream::{SplitSink, SplitStream};
use futures::{FutureExt, SinkExt, StreamExt};
use log::{error, info};
use log::{error, info, debug};
use nalgebra::{vector, point};
use rapier2d_f64::prelude::{RigidBodyBuilder, RigidBodyType, ColliderBuilder, MassProperties, Collider};
use tungstenite::Message;


@@ 12,13 12,17 @@ use starkingdoms_protocol::goodbye_reason::GoodbyeReason;
use starkingdoms_protocol::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong};
use starkingdoms_protocol::{MessageS2C, MessageC2S, PROTOCOL_VERSION};
use starkingdoms_protocol::state::State;
use crate::entity::{EntityHandler, get_entity_id, Entity};
use crate::manager::{ClientHandlerMessage, ClientManager, PhysicsData, Player};
use crate::{send, recv, SCALE};
use async_std::{sync::RwLock, channel::Receiver};
use async_std::net::TcpStream;
use async_tungstenite::WebSocketStream;

pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, remote_addr: SocketAddr, rx: Receiver<ClientHandlerMessage>, mut client_tx: SplitSink<WebSocketStream<TcpStream>, Message>, mut client_rx: SplitStream<WebSocketStream<TcpStream>>) -> Result<(), Box<dyn Error>> {
pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandler>>, data: Arc<RwLock<PhysicsData>>,
                           remote_addr: SocketAddr, rx: Receiver<ClientHandlerMessage>,
                           mut client_tx: SplitSink<WebSocketStream<TcpStream>, Message>, mut client_rx: SplitStream<WebSocketStream<TcpStream>>
                          ) -> Result<(), Box<dyn Error>> {
    let mut state = State::Handshake;
    let mut username = String::new();
    let mut ping_timeout = SystemTime::now() + Duration::from_secs(10);


@@ 148,7 152,13 @@ pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, r
                                data_handle.rigid_body_set = rigid_body_set;
                                data_handle.collider_set = collider_set;

                                mgr.players.write().await.insert(remote_addr, Player { handle: player_handle, input: Default::default() });
                                entities.write().await.entities.insert(get_entity_id(),
                                    Entity::Player(Player {
                                        handle: player_handle,
                                        input: Default::default(),
                                        addr: remote_addr
                                    }));
                                debug!("running");
                            }
                        },
                        MessageC2S::Goodbye(pkt) => {


@@ 201,12 211,16 @@ pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, r
                            ping_timeout = SystemTime::now() + Duration::from_secs(10);
                        },
                        MessageC2S::Input(p) => {
                            let mut players = mgr.players.write().await;
                            let me = players.get_mut(&remote_addr).expect("player disconnected but continued to send packets");
                            me.input.up = p.up_pressed;
                            me.input.down = p.down_pressed;
                            me.input.left = p.left_pressed;
                            me.input.right = p.right_pressed;
                            let mut handle = entities.write().await;
                            let mut id = handle.get_player_id(remote_addr)
                                .expect("could not get player id");
                            if let Entity::Player(ref mut me) = handle.entities.get_mut(&id)
                                .expect("player disconnected but continued to send packets") {
                                me.input.up = p.up_pressed;
                                me.input.down = p.down_pressed;
                                me.input.left = p.left_pressed;
                                me.input.right = p.right_pressed;
                            }
                        }
                    }
                }

M server/src/main.rs => server/src/main.rs +25 -156
@@ 3,6 3,7 @@ use std::net::SocketAddr;
use async_std::io::WriteExt;
use async_std::sync::Arc;
use async_std::net::{TcpListener, TcpStream};
use entity::{Entities, EntityHandler};
use manager::PhysicsData;
use nalgebra::vector;
use planet::Planets;


@@ 10,6 11,7 @@ use rapier2d_f64::prelude::{MultibodyJointSet, ImpulseJointSet, ColliderSet, Rig
use lazy_static::lazy_static;
use log::{error, info, Level, warn};
use serde::{Deserialize, Serialize};
use crate::entity::Entity;
use crate::manager::{ClientHandler, ClientManager};
use crate::timer::timer_main;
use async_std::sync::RwLock;


@@ 24,11 26,13 @@ pub mod timer;
pub mod macros;
pub mod planet;
pub mod orbit;
pub mod entity;

const SCALE: f64 = 1.0;

async fn handle_request(conn: TcpStream, remote_addr: SocketAddr, mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>) {
    match _handle_request(conn, remote_addr, mgr, physics_data).await {
async fn handle_request(conn: TcpStream, remote_addr: SocketAddr, mgr: ClientManager,
                        entities: Arc<RwLock<EntityHandler>>, physics_data: Arc<RwLock<PhysicsData>>) {
    match _handle_request(conn, remote_addr, mgr, entities, physics_data).await {
        Ok(_) => (),
        Err(e) => {
            error!("[{}] error in handler thread: {}", remote_addr, e);


@@ 36,7 40,8 @@ async fn handle_request(conn: TcpStream, remote_addr: SocketAddr, mgr: ClientMan
    }
}

async fn _handle_request(mut conn: TcpStream, remote_addr: SocketAddr, mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>) -> Result<(), Box<dyn Error>> {
async fn _handle_request(mut conn: TcpStream, remote_addr: SocketAddr, mgr: ClientManager,
                         entities: Arc<RwLock<EntityHandler>>, physics_data: Arc<RwLock<PhysicsData>>) -> Result<(), Box<dyn Error>> {
    let mut peek_buf = [0u8; 9];

    loop {


@@ 84,7 89,7 @@ async fn _handle_request(mut conn: TcpStream, remote_addr: SocketAddr, mgr: Clie
    info!("[{}] passing to client handler", remote_addr);

    //forward the stream to the sink to achieve echo
    match handle_client(mgr.clone(), physics_data.clone(), remote_addr, rx, ws_write, ws_read).await {
    match handle_client(mgr.clone(), entities.clone(), physics_data.clone(), remote_addr, rx, ws_write, ws_read).await {
        Ok(_) => (),
        Err(e) if e.is::<async_tungstenite::tungstenite::error::Error>() => {
            let e = e.downcast::<async_tungstenite::tungstenite::error::Error>().unwrap();


@@ 110,160 115,38 @@ async fn _handle_request(mut conn: TcpStream, remote_addr: SocketAddr, mgr: Clie
        let mut collider_set = data.collider_set.clone();
        let mut impulse_joint_set = data.impulse_joint_set.clone();
        let mut multibody_joint_set = data.multibody_joint_set.clone();
        let handle = match mgr.players.read().await.get(&remote_addr) {
            Some(s) => s.handle,
        let player_id = match entities.read().await.get_player_id(remote_addr) {
            Some(s) => s,
            None => {
                warn!("[{}] player missing from mgr.players", remote_addr);
                return Err("Player missing from mgr.players".into());
                warn!("[{}] player missing from entities.players", remote_addr);
                return Err("Player missing from entities.players".into());
            }
        };
        rigid_body_set.remove(handle, &mut island_manager, &mut collider_set,
                              &mut impulse_joint_set, &mut multibody_joint_set, true);
        if let Entity::Player(player) = entities.read().await.entities.get(&player_id).unwrap() {
            rigid_body_set.remove(player.handle, &mut island_manager, &mut collider_set,
                                    &mut impulse_joint_set, &mut multibody_joint_set, true);
        }
        data.rigid_body_set = rigid_body_set;
        data.collider_set = collider_set;
        data.island_manager = island_manager;
        data.impulse_joint_set = impulse_joint_set;
        data.multibody_joint_set = multibody_joint_set;
        mgr.players.write().await.remove(&remote_addr);
        entities.write().await.entities.remove(&player_id);
    }

    Ok(())
}

/*
async fn handle_request(mut request: Request<Body>, remote_addr: SocketAddr, mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>) -> Result<Response<Body>, Infallible> {
    match (request.uri().path(), request.headers().contains_key(header::UPGRADE)) {
        //if the request is ws_echo and the request headers contains an Upgrade key
        ("/ws", true) => {
            info!("received connection from {}", remote_addr);
            //assume request is a handshake, so create the handshake response
            let response =
                match handshake::server::create_response_with_body(&request, Body::empty) {
                    Ok(response) => {
                        //in case the handshake response creation succeeds,
                        //spawn a task to handle the websocket connection
                        tokio::spawn(async move {
                            //using the hyper feature of upgrading a connection
                            match upgrade::on(&mut request).await {
                                //if successfully upgraded
                                Ok(upgraded) => {
                                    info!("[{}] connection upgraded", remote_addr);
                                    //create a websocket stream from the upgraded object
                                    let ws_stream = WebSocketStream::from_raw_socket(
                                        //pass the upgraded object
                                        //as the base layer stream of the Websocket
                                        upgraded,
                                        tungstenite::protocol::Role::Server,
                                        None,
                                    ).await;

                                    //we can split the stream into a sink and a stream
                                    let (ws_write, ws_read) = ws_stream.split();

                                    let (tx, rx) = tokio::sync::mpsc::channel(128);

                                    let client = ClientHandler {
                                        tx,
                                    };

                                    // Acquire the write lock in a small scope, so it's dropped as quickly as possible
                                    {
                                        mgr.handlers.write().await.insert(remote_addr, client);
                                    }

                                    info!("[{}] passing to client handler", remote_addr);

                                    //forward the stream to the sink to achieve echo
                                    match handle_client(mgr.clone(), physics_data.clone(), remote_addr, rx, ws_write, ws_read).await {
                                        Ok(_) => {},
                                        Err(e) => error!("error on WS connection {}: {}", remote_addr, e),
                                    };

                                    // clean up values left over
                                    {
                                        mgr.handlers.write().await.remove(&remote_addr);
                                        mgr.usernames.write().await.remove(&remote_addr);
                                        // remove player physics body
                                        let mut data = physics_data.write().await;
                                        let mut rigid_body_set = data.rigid_body_set.clone();
                                        let mut island_manager = data.island_manager.clone();
                                        let mut collider_set = data.collider_set.clone();
                                        let mut impulse_joint_set = data.impulse_joint_set.clone();
                                        let mut multibody_joint_set = data.multibody_joint_set.clone();
                                        let handle = match mgr.players.read().await.get(&remote_addr) {
                                            Some(s) => s.handle,
                                            None => {error!("looks like somebody forgot to make their player"); return}
                                        };
                                        rigid_body_set.remove(handle, &mut island_manager, &mut collider_set,
                                            &mut impulse_joint_set, &mut multibody_joint_set, true);
                                        data.rigid_body_set = rigid_body_set;
                                        data.collider_set = collider_set;
                                        data.island_manager = island_manager;
                                        data.impulse_joint_set = impulse_joint_set;
                                        data.multibody_joint_set = multibody_joint_set;
                                        mgr.players.write().await.remove(&remote_addr);
                                    }
                                },
                                Err(e) => {
                                    error!("error upgrading connection from {} to WS: {}", remote_addr, e);
                                }
                            }
                        });
                        //return the response to the handshake request
                        response
                    },
                    Err(e) => {
                        //probably the handshake request is not up to spec for websocket
                        error!("error creating websocket response to {}: {}", remote_addr, e);
                        let mut res = Response::new(Body::from(format!("Failed to create websocket: {}", e)));
                        *res.status_mut() = StatusCode::BAD_REQUEST;
                        return Ok(res);
                    }
                };

            Ok::<_, Infallible>(response)
        },
        ("/ws", false) => {
            Ok(Response::builder().status(400).body(Body::from("Connection-Upgrade header missing")).unwrap())
        },
        ("/ping", false) => {
            Ok(Response::builder().status(200).header("Access-Control-Allow-Origin", "*").body(Body::from(
                serde_json::to_string(&ServerPingResponse {
                    version: ServerPingResponseVersion {
                        name: env!("STK_VERSION_NAME").to_string(), // Set by build.rs
                        number: env!("STK_VERSION").to_string(), // Set by build.rs
                        protocol: PROTOCOL_VERSION,
                    },
                    players: CMGR.usernames.read().await.len() as u32,
                    description: env!("STK_SLP_DESCRIPTION").to_string(),
                }).unwrap()
            )).unwrap())
        },
        (_url, false) => {
            // typical HTTP file request
            // TODO
            Ok(Response::new(Body::empty()))
        },
        (_, true) => {
            // http upgrade on non-/ws endpoint
            Ok(Response::builder().status(400).body(Body::from("Incorrect WebSocket endpoint")).unwrap())
        }
    }
}
*/

lazy_static! {
    static ref CMGR: ClientManager = ClientManager {
        handlers: Arc::new(RwLock::new(Default::default())),
        usernames: Arc::new(RwLock::new(Default::default())),
        players: Arc::new(RwLock::new(Default::default())),
    };
    static ref DATA: Arc<RwLock<PhysicsData>> = Arc::new(RwLock::new(PhysicsData { 
        gravity: vector![0.0, 0.0],
        integration_parameters: IntegrationParameters {
            dt: 1.0 / 20.0,
            ..Default::default()
        },
            ..Default::default() },
        island_manager: IslandManager::new(),
        broad_phase: BroadPhase::new(),
        narrow_phase: NarrowPhase::new(),


@@ 271,9 154,8 @@ lazy_static! {
        collider_set: ColliderSet::new(),
        impulse_joint_set: ImpulseJointSet::new(),
        multibody_joint_set: MultibodyJointSet::new(),
        ccd_solver: CCDSolver::new(),
    }));
    static ref PLANETS: Arc<RwLock<Planets>> = Arc::new(RwLock::new(Planets::default()));
        ccd_solver: CCDSolver::new(), }));
    static ref ENTITIES: Arc<RwLock<EntityHandler>> = Arc::new(RwLock::new(EntityHandler::new()));
}

#[async_std::main]


@@ 284,25 166,11 @@ async fn main() {

    info!("Listening on {} for HTTP/WebSocket connections", addr);

    // make earth
    {
        let mut data_handle = DATA.write().await;

        let mut rigid_body_set = data_handle.rigid_body_set.clone();
        let mut collider_set = data_handle.collider_set.clone();

        let mut planets = PLANETS.write().await;
        planets.planets = Planets::new(&mut rigid_body_set, &mut collider_set).planets;

        data_handle.rigid_body_set = rigid_body_set;
        data_handle.collider_set = collider_set;
    }

    let mgr_timer = CMGR.clone();
    let physics_data = DATA.clone();
    let world_data = PLANETS.clone();
    let entities_timer = ENTITIES.clone();
    let _timer_thread = async_std::task::spawn(async move {
        timer_main(mgr_timer, physics_data, world_data).await;
        timer_main(mgr_timer, physics_data, entities_timer).await;
    });

    let try_socket = TcpListener::bind(&addr).await;


@@ 316,7 184,8 @@ async fn main() {
    };

    while let Ok((stream, peer_addr)) = listener.accept().await {
        async_std::task::spawn(handle_request(stream, peer_addr, CMGR.clone(), DATA.clone()));
        async_std::task::spawn(handle_request(stream, peer_addr, CMGR.clone(),
                                ENTITIES.clone(), DATA.clone()));
    }
}


M server/src/manager.rs => server/src/manager.rs +5 -5
@@ 1,7 1,7 @@
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use rapier2d_f64::na::{Vector2};
use rapier2d_f64::na::Vector2;
use rapier2d_f64::prelude::{IntegrationParameters, PhysicsPipeline, IslandManager, BroadPhase, NarrowPhase, ImpulseJointSet, MultibodyJointSet, CCDSolver, RigidBodySet, ColliderSet, RigidBodyHandle};
use async_std::sync::RwLock;
use async_std::channel::Sender;


@@ 10,16 10,16 @@ use async_std::channel::Sender;
pub struct ClientManager {
    pub handlers: Arc<RwLock<HashMap<SocketAddr, ClientHandler>>>,
    pub usernames: Arc<RwLock<HashMap<SocketAddr, String>>>,
    pub players: Arc<RwLock<HashMap<SocketAddr, Player>>>
}

#[derive(Default)]
#[derive(Clone)]
pub struct Player {
    pub handle: RigidBodyHandle,
    pub input: PlayerInput
    pub input: PlayerInput,
    pub addr: SocketAddr,
}

#[derive(Default)]
#[derive(Default, Clone)]
pub struct PlayerInput {
    pub up: bool,
    pub left: bool,

M server/src/planet.rs => server/src/planet.rs +29 -16
@@ 1,8 1,11 @@
use std::collections::HashMap;
use std::sync::Arc;
use async_std::sync::RwLock;
use nalgebra::{Vector2, vector};
use rapier2d_f64::prelude::{RigidBodyHandle, RigidBodySet, ColliderBuilder, RigidBodyBuilder, ColliderSet};
use starkingdoms_protocol::planet::PlanetType;

use crate::entity::{Entities, get_entity_id, Entity, EntityId, EntityHandler};
use crate::{SCALE, manager::ClientHandlerMessage};
use crate::orbit::constants::{EARTH_MASS, EARTH_RADIUS, MOON_APOAPSIS, MOON_MASS, MOON_PERIAPSIS, MOON_RADIUS};
use crate::orbit::orbit::{calculate_point_on_orbit, calculate_world_position_of_orbit};


@@ 43,7 46,10 @@ impl Planets {
        self.planets.get_mut(planet_id)
    }

    pub fn make_planet(planets: &mut HashMap<String, Planet>, planet_id: &str, planet_type: PlanetType, mass: f64, radius: f64, position: (f64, f64), rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet) {
    pub async fn make_planet(planet_id: &str,
                             planet_type: PlanetType, mass: f64, radius: f64,
                             position: (f64, f64), rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet
                            ) -> (EntityId, Entity) {
        let collider = ColliderBuilder::ball(radius / SCALE)
            .build();
        let body = RigidBodyBuilder::dynamic()


@@ 54,20 60,20 @@ impl Planets {

        collider_set.insert_with_parent(collider, body_handle, rigid_body_set);

        planets.insert(planet_id.to_string(), Planet {
        let entity_id = get_entity_id();
        (entity_id, Entity::Planet(Planet {
            planet_type,
            body_handle,
            position,
            radius,
            mass,
        });
        }))
    }

    pub fn new(rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet) -> Planets {
        let mut planets = HashMap::new();
        
        Planets::make_planet(
            &mut planets,
    pub async fn new(rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet,
               entities: &mut Entities) -> Vec<EntityId> {
        let mut planet_ids: Vec<EntityId> = Vec::new();
        let (earth_id, entity) = Planets::make_planet(
            "earth",
            PlanetType::Earth,
            EARTH_MASS,


@@ 75,12 81,18 @@ impl Planets {
            (100.0, 100.0),
            rigid_body_set,
            collider_set,
        );

        let moon_start_point = calculate_world_position_of_orbit(calculate_point_on_orbit(MOON_PERIAPSIS, MOON_APOAPSIS, 0.0), vector![planets.get("earth").unwrap().position.0, planets.get("earth").unwrap().position.1]);
        ).await;
        entities.insert(earth_id, entity);
        planet_ids.push(earth_id);

        let moon_start_point;
        if let Entity::Planet(earth) = entities.get(&earth_id).unwrap() {
            moon_start_point = calculate_world_position_of_orbit(calculate_point_on_orbit(MOON_PERIAPSIS, MOON_APOAPSIS, 0.0), vector![earth.position.0, earth.position.1]);
        } else {
            moon_start_point = vector![0., 0.];
        }

        Planets::make_planet(
            &mut planets,
        let (moon_id, moon) = Planets::make_planet(
            "moon",
            PlanetType::Moon,
            MOON_MASS,


@@ 88,9 100,10 @@ impl Planets {
            (moon_start_point[0], moon_start_point[1]),
            rigid_body_set,
            collider_set
        );

        Planets { planets }
        ).await;
        entities.insert(moon_id, moon);
        planet_ids.push(moon_id);
        planet_ids
    }

    pub fn to_protocol(&self) -> ClientHandlerMessage {

M server/src/timer.rs => server/src/timer.rs +26 -10
@@ 4,18 4,31 @@ use nalgebra::{vector, point};
use rapier2d_f64::prelude::{PhysicsPipeline};
use async_std::sync::RwLock;
use async_std::task::sleep;
use starkingdoms_protocol::player::Player;
use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData}, SCALE, planet::Planets};
use starkingdoms_protocol::{player::Player, planet::PlanetType};
use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData}, SCALE, planet::{Planets, Planet}, entity::{Entities, Entity, EntityHandler}};
use crate::orbit::constants::{EARTH_MASS, GAME_ORBITS_ENABLED, MOON_APOAPSIS, MOON_MASS, MOON_ORBIT_TIME, MOON_PERIAPSIS};
use crate::orbit::orbit::{calculate_point_on_orbit, calculate_vector_of_orbit, calculate_world_position_of_orbit};

pub const ROTATIONAL_FORCE: f64 = 100.0;
pub const LATERAL_FORCE: f64 = 100.0;

pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>, world_data: Arc<RwLock<Planets>>) {
pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>, entities: Arc<RwLock<EntityHandler>>) {
    let mut pipeline = PhysicsPipeline::new();

    let mut time = 0.0;
    let planet_ids;

    {
        let mut data_handle = physics_data.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::new(&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;


@@ 28,19 41,22 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
        // IT MAY ALWAYS BE TRUE
        // THATS FINE
        if GAME_ORBITS_ENABLED {
            let mut planets = world_data.write().await;
            let mut planets = entities.write().await;

            // update earth (nothing changes, yet)
            let new_earth_position = vector![planets.get_planet("earth").unwrap().position.0, planets.get_planet("earth").unwrap().position.1];
            let new_earth_position;
            let earth = planets.get_planet(PlanetType::Earth).unwrap();
            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(planets.get_planet_mut("moon").unwrap().body_handle).unwrap();
            let moon_body = physics_data.rigid_body_set.get_mut(moon.body_handle).unwrap();
            let moon_force = calculate_vector_of_orbit(MOON_PERIAPSIS, MOON_APOAPSIS, time / MOON_ORBIT_TIME, moon_body.translation().x, moon_body.translation().y, new_earth_position[0], new_earth_position[1],MOON_MASS, 1f64 / 20f64);
            moon_body.reset_forces(true);
            moon_body.add_force(moon_force, true);
            //moon_body.set_linvel(moon_force, true);
            planets.get_planet_mut("moon").unwrap().position = (moon_body.translation()[0] / SCALE, moon_body.translation()[1] / SCALE);
            moon.position = (moon_body.translation()[0] / SCALE, moon_body.translation()[1] / SCALE);
        }

        physics_data.tick(&mut pipeline);


@@ 48,12 64,12 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
        let mut protocol_players = vec![];

        {
            for (player_id, player) in mgr.players.write().await.iter() {
            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 = world_data.read().await;
                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);



@@ 167,7 183,7 @@ pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData
                        }
                    };

                    let world = world_data.read().await;
                    let world = entities.read().await;
                    let planet_data = world.to_protocol();
                    match client_thread.tx.send(planet_data).await {
                        Ok(_) => (),