M Cargo.lock => Cargo.lock +1 -0
@@ 1371,6 1371,7 @@ dependencies = [
"hyper",
"lazy_static",
"log",
+ "nalgebra",
"rapier2d",
"rmp-serde",
"serde",
M protocol/src/lib.rs => protocol/src/lib.rs +2 -2
@@ 52,7 52,7 @@ pub enum MessageS2C {
},
PlanetData {
- planets: Vec<Planet>
+ planets: Vec<ProtocolPlanet>
}
}
@@ 67,7 67,7 @@ pub enum GoodbyeReason {
}
#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct Planet {
+pub struct ProtocolPlanet {
pub planet_type: PlanetType,
pub x: f64,
pub y: f64,
M server/Cargo.toml => server/Cargo.toml +1 -0
@@ 23,6 23,7 @@ simple_logger = "4.1"
starkingdoms-protocol = { version = "0.1.0", path = "../protocol" }
lazy_static = "1.4.0"
rapier2d = { version = "0.17.2", features = [ "simd-stable" ] }
+nalgebra = "0.32.2"
[build-dependencies]
cargo_metadata = "0.15"
M server/src/handler.rs => server/src/handler.rs +21 -5
@@ 1,19 1,23 @@
use std::error::Error;
use std::net::SocketAddr;
+use std::sync::Arc;
use std::time::{Duration, SystemTime};
use futures::stream::{SplitSink, SplitStream};
use futures::{FutureExt, SinkExt, StreamExt};
use hyper::upgrade::Upgraded;
use log::{error, info, warn};
+use nalgebra::vector;
+use rapier2d::prelude::{RigidBodyBuilder, RigidBodyType, ColliderBuilder};
+use tokio::sync::RwLock;
use tokio::sync::mpsc::Receiver;
use tokio_tungstenite::WebSocketStream;
use tungstenite::Message;
-use starkingdoms_protocol::{GoodbyeReason, MessageC2S, MessageS2C, Planet, PlanetType, PROTOCOL_VERSION, State};
+use starkingdoms_protocol::{GoodbyeReason, MessageC2S, MessageS2C, ProtocolPlanet, PlanetType, PROTOCOL_VERSION, State};
use starkingdoms_protocol::GoodbyeReason::PingPongTimeout;
-use crate::manager::{ClientHandlerMessage, ClientManager};
-use crate::{send, recv};
+use crate::manager::{ClientHandlerMessage, ClientManager, PhysicsData, Player};
+use crate::{send, recv, SCALE};
-pub async fn handle_client(mgr: ClientManager, remote_addr: SocketAddr, mut rx: Receiver<ClientHandlerMessage>, mut client_tx: SplitSink<WebSocketStream<Upgraded>, Message>, mut client_rx: SplitStream<WebSocketStream<Upgraded>>) -> Result<(), Box<dyn Error>> {
+pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, remote_addr: SocketAddr, mut rx: Receiver<ClientHandlerMessage>, mut client_tx: SplitSink<WebSocketStream<Upgraded>, Message>, mut client_rx: SplitStream<WebSocketStream<Upgraded>>) -> Result<(), Box<dyn Error>> {
let mut state = State::Handshake;
let mut username = String::new();
let mut ping_timeout = SystemTime::now() + Duration::from_secs(5);
@@ 91,12 95,24 @@ pub async fn handle_client(mgr: ClientManager, remote_addr: SocketAddr, mut rx:
state = next_state;
username = requested_username;
+ {
+ let mut data_handle = data.write().await;
+ let player_body = RigidBodyBuilder::new(RigidBodyType::Dynamic)
+ .translation(vector![0.0, 2100.0/SCALE])
+ .build();
+ let player_collider = ColliderBuilder::cuboid(1.0 / SCALE, 1.0 / SCALE).build();
+ let player_handle = data_handle.rigid_body_set.insert(player_body);
+ // cannot mutably borrow twice
+ data_handle.collider_set.insert_with_parent(player_collider, player_handle, &mut data_handle.rigid_body_set);
+ mgr.players.write().await.insert(remote_addr, Player { handle: player_handle });
+ }
+
// TODO: Proper planet and position data
// TODO: This is only for testing of the planet rendering code
// TODO: !!!!!!!!!! REMOVE THIS WHEN PLANETS ACTUALLY EXIST !!!!!!!!!!
send!(client_tx, &MessageS2C::PlanetData {
planets: vec![
- Planet {
+ ProtocolPlanet {
planet_type: PlanetType::Earth,
radius: 1f64,
x: 0f64,
M server/src/main.rs => server/src/main.rs +26 -5
@@ 3,6 3,9 @@ use std::net::SocketAddr;
use std::sync::Arc;
use hyper::{Body, header, Request, Response, Server, server::conn::AddrStream, StatusCode, upgrade};
use hyper::service::{make_service_fn, service_fn};
+use manager::PhysicsData;
+use nalgebra::vector;
+use rapier2d::prelude::{MultibodyJointSet, ImpulseJointSet, ColliderSet, RigidBodySet, NarrowPhase, BroadPhase, IslandManager, CCDSolver, IntegrationParameters};
use tokio_tungstenite::WebSocketStream;
use tungstenite::{handshake};
use futures::stream::StreamExt;
@@ 11,7 14,7 @@ use log::{error, info, Level};
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use starkingdoms_protocol::{PROTOCOL_VERSION};
-use crate::manager::{ClientHandler, ClientManager, PhysicsEngine};
+use crate::manager::{ClientHandler, ClientManager};
use crate::handler::handle_client;
use crate::timer::timer_main;
@@ 21,7 24,9 @@ pub mod timer;
#[macro_use]
pub mod macros;
-async fn handle_request(mut request: Request<Body>, remote_addr: SocketAddr, mgr: ClientManager) -> Result<Response<Body>, Infallible> {
+const SCALE: f32 = 1.0 / 10.0;
+
+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) => {
@@ 64,7 69,7 @@ async fn handle_request(mut request: Request<Body>, remote_addr: SocketAddr, mgr
info!("[{}] passing to client handler", remote_addr);
//forward the stream to the sink to achieve echo
- match handle_client(mgr.clone(), remote_addr, rx, ws_write, ws_read).await {
+ 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),
};
@@ 128,6 133,21 @@ lazy_static! {
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()
+ },
+ island_manager: IslandManager::new(),
+ broad_phase: BroadPhase::new(),
+ narrow_phase: NarrowPhase::new(),
+ rigid_body_set: RigidBodySet::new(),
+ collider_set: ColliderSet::new(),
+ impulse_joint_set: ImpulseJointSet::new(),
+ multibody_joint_set: MultibodyJointSet::new(),
+ ccd_solver: CCDSolver::new(),
+ }));
}
#[tokio::main]
@@ 144,7 164,7 @@ async fn main() {
async move {
Ok::<_, Infallible>(service_fn({
move |request: Request<Body>| {
- handle_request(request, remote_addr, CMGR.clone())
+ handle_request(request, remote_addr, CMGR.clone(), DATA.clone())
}
}))
}
@@ 152,8 172,9 @@ async fn main() {
let mgr_timer = CMGR.clone();
+ let physics_data = DATA.clone();
let _timer_thread = tokio::spawn(async move {
- timer_main(mgr_timer).await;
+ timer_main(mgr_timer, physics_data).await;
});
let server = Server::bind(&addr).serve(make_svc);
M server/src/manager.rs => server/src/manager.rs +24 -9
@@ 3,7 3,8 @@ use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
-use rapier2d::prelude::{IntegrationParameters, PhysicsPipeline, IslandManager, BroadPhase, NarrowPhase, ImpulseJointSet, MultibodyJointSet, CCDSolver, EventHandler, PhysicsHooks, RigidBodySet, ColliderSet};
+use rapier2d::na::{Vector3, Vector2};
+use rapier2d::prelude::{IntegrationParameters, PhysicsPipeline, IslandManager, BroadPhase, NarrowPhase, ImpulseJointSet, MultibodyJointSet, CCDSolver, EventHandler, PhysicsHooks, RigidBodySet, ColliderSet, RigidBodyHandle};
use tokio::sync::mpsc::Sender;
use tokio::sync::RwLock;
@@ 16,11 17,7 @@ pub struct ClientManager {
#[derive(Default)]
pub struct Player {
- pub id: u16,
- pub x: f64,
- pub y: f64,
- pub vel_x: f64,
- pub vel_y: f64,
+ pub handle: RigidBodyHandle
}
#[derive(Clone)]
@@ 28,10 25,10 @@ pub struct ClientHandler {
pub tx: Sender<ClientHandlerMessage>
}
-pub struct PhysicsEngine {
- pub gravity: Vec<f32>,
+#[derive(Clone, Default)]
+pub struct PhysicsData {
+ pub gravity: Vector2<f32>,
pub integration_parameters: IntegrationParameters,
- pub pipeline: PhysicsPipeline,
pub island_manager: IslandManager,
pub broad_phase: BroadPhase,
pub narrow_phase: NarrowPhase,
@@ 41,6 38,24 @@ pub struct PhysicsEngine {
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,
+ &(),
+ &()
+ );
+ }
+}
pub enum ClientHandlerMessage {
Tick,
M server/src/timer.rs => server/src/timer.rs +8 -19
@@ 1,29 1,18 @@
-use std::time::Duration;
+use std::{time::Duration, sync::Arc};
use log::{error};
-use rapier2d::prelude::{IntegrationParameters, PhysicsPipeline, IslandManager, BroadPhase, NarrowPhase, ImpulseJointSet, MultibodyJointSet, CCDSolver, RigidBodySet, ColliderSet};
-use tokio::time::sleep;
-use crate::manager::{ClientHandlerMessage, ClientManager, PhysicsEngine};
+use rapier2d::prelude::{PhysicsPipeline};
+use tokio::{time::sleep, sync::RwLock};
+use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData}, SCALE};
-pub async fn timer_main(mgr: ClientManager) {
- // initialize physics engine
- let mut physics_engine = PhysicsEngine {
- gravity: vec![0.0, 0.0],
- integration_parameters: IntegrationParameters::default(),
- pipeline: PhysicsPipeline::new(),
- island_manager: IslandManager::new(),
- broad_phase: BroadPhase::new(),
- narrow_phase: NarrowPhase::new(),
- rigid_body_set: RigidBodySet::new(),
- collider_set: ColliderSet::new(),
- impulse_joint_set: ImpulseJointSet::new(),
- multibody_joint_set: MultibodyJointSet::new(),
- ccd_solver: CCDSolver::new(),
- };
+pub async fn timer_main(mgr: ClientManager, physics_data: Arc<RwLock<PhysicsData>>) {
+ let mut pipeline = PhysicsPipeline::new();
loop {
sleep(Duration::from_millis(5)).await;
+ physics_data.write().await.tick(&mut pipeline);
+
for (_addr, client_thread) in mgr.handlers.read().await.iter() {
match client_thread.tx.send(ClientHandlerMessage::Tick).await {
Ok(_) => (),