M api/src/config.rs => api/src/config.rs +22 -12
@@ 1,9 1,9 @@
+use log::error;
+use once_cell::sync::Lazy;
+use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
-use log::error;
-use once_cell::sync::Lazy;
-use serde::{Serialize, Deserialize};
pub static CONFIG: Lazy<StarkingdomsApiConfig> = Lazy::new(|| {
let config_str = match fs::read_to_string("/etc/starkingdoms/config.toml") {
@@ 31,7 31,7 @@ pub struct StarkingdomsApiConfig {
pub jwt_signing_secret: String,
pub base: String,
pub game: String,
- pub realms: HashMap<String, StarkingdomsApiConfigRealm>
+ pub realms: HashMap<String, StarkingdomsApiConfigRealm>,
}
#[derive(Serialize, Deserialize, Debug)]
@@ 50,13 50,13 @@ pub struct StarkingdomsApiConfigDatabase {
#[serde(default = "time_defaults")]
pub max_lifetime: u64,
#[serde(default = "sqlx_logging_default")]
- pub sqlx_logging: bool
+ pub sqlx_logging: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct StarkingdomsApiConfigServer {
#[serde(default = "socketaddr_8080")]
- pub bind: SocketAddr
+ pub bind: SocketAddr,
}
/*
@@ 69,11 69,21 @@ issuer = "https://api.e3t.cc"
pub struct StarkingdomsApiConfigRealm {
pub authorize_url: String,
pub public_key: String,
- pub issuer: String
+ pub issuer: String,
}
-fn max_connections_default() -> u32 { 100 }
-fn min_connections_default() -> u32 { 5 }
-fn time_defaults() -> u64 { 8 }
-fn sqlx_logging_default() -> bool { true }
-fn socketaddr_8080() -> SocketAddr { SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([0, 0, 0, 0]), 8080)) }>
\ No newline at end of file
+fn max_connections_default() -> u32 {
+ 100
+}
+fn min_connections_default() -> u32 {
+ 5
+}
+fn time_defaults() -> u64 {
+ 8
+}
+fn sqlx_logging_default() -> bool {
+ true
+}
+fn socketaddr_8080() -> SocketAddr {
+ SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([0, 0, 0, 0]), 8080))
+}
M api/src/error.rs => api/src/error.rs +45 -57
@@ 1,9 1,9 @@
use actix_web::error::{JsonPayloadError, PayloadError};
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct APIErrorsResponse {
- pub errors: Vec<APIError>
+ pub errors: Vec<APIError>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct APIError {
@@ 11,10 11,12 @@ pub struct APIError {
pub message: String,
#[serde(skip_serializing_if = "is_none")]
#[serde(default)]
- pub path: Option<String>
+ pub path: Option<String>,
}
-fn is_none<T>(o: &Option<T>) -> bool { o.is_none() }
+fn is_none<T>(o: &Option<T>) -> bool {
+ o.is_none()
+}
impl From<&JsonPayloadError> for APIError {
fn from(value: &JsonPayloadError) -> Self {
@@ 71,58 73,44 @@ impl From<&JsonPayloadError> for APIError {
impl From<&PayloadError> for APIError {
fn from(value: &PayloadError) -> Self {
match value {
- PayloadError::Incomplete(e) => {
- APIError {
- code: "ERR_UNEXPECTED_EOF".to_string(),
- message: match e {
- None => "Payload reached EOF but was incomplete".to_string(),
- Some(e) => format!("Payload reached EOF but was incomplete: {}", e)
- },
- path: None,
- }
- }
- PayloadError::EncodingCorrupted => {
- APIError {
- code: "ERR_CORRUPTED_PAYLOAD".to_string(),
- message: "Payload content encoding corrupted".to_string(),
- path: None,
- }
- }
- PayloadError::Overflow => {
- APIError {
- code: "ERR_PAYLOAD_OVERFLOW".to_string(),
- message: "Payload reached size limit".to_string(),
- path: None,
- }
- }
- PayloadError::UnknownLength => {
- APIError {
- code: "ERR_PAYLOAD_UNKNOWN_LENGTH".to_string(),
- message: "Unable to determine payload length".to_string(),
- path: None,
- }
- }
- PayloadError::Http2Payload(e) => {
- APIError {
- code: "ERR_HTTP2_ERROR".to_string(),
- message: format!("HTTP/2 error: {}", e),
- path: None,
- }
- }
- PayloadError::Io(e) => {
- APIError {
- code: "ERR_IO_ERROR".to_string(),
- message: format!("I/O error: {}", e),
- path: None,
- }
- }
- _ => {
- APIError {
- code: "ERR_UNKNOWN_ERROR".to_string(),
- message: "An unknown error has occured".to_string(),
- path: None,
- }
- }
+ PayloadError::Incomplete(e) => APIError {
+ code: "ERR_UNEXPECTED_EOF".to_string(),
+ message: match e {
+ None => "Payload reached EOF but was incomplete".to_string(),
+ Some(e) => format!("Payload reached EOF but was incomplete: {}", e),
+ },
+ path: None,
+ },
+ PayloadError::EncodingCorrupted => APIError {
+ code: "ERR_CORRUPTED_PAYLOAD".to_string(),
+ message: "Payload content encoding corrupted".to_string(),
+ path: None,
+ },
+ PayloadError::Overflow => APIError {
+ code: "ERR_PAYLOAD_OVERFLOW".to_string(),
+ message: "Payload reached size limit".to_string(),
+ path: None,
+ },
+ PayloadError::UnknownLength => APIError {
+ code: "ERR_PAYLOAD_UNKNOWN_LENGTH".to_string(),
+ message: "Unable to determine payload length".to_string(),
+ path: None,
+ },
+ PayloadError::Http2Payload(e) => APIError {
+ code: "ERR_HTTP2_ERROR".to_string(),
+ message: format!("HTTP/2 error: {}", e),
+ path: None,
+ },
+ PayloadError::Io(e) => APIError {
+ code: "ERR_IO_ERROR".to_string(),
+ message: format!("I/O error: {}", e),
+ path: None,
+ },
+ _ => APIError {
+ code: "ERR_UNKNOWN_ERROR".to_string(),
+ message: "An unknown error has occured".to_string(),
+ path: None,
+ },
}
}
-}>
\ No newline at end of file
+}
M api/src/main.rs => api/src/main.rs +21 -17
@@ 1,23 1,23 @@
-use std::error::Error;
-use std::time::Duration;
+use crate::config::CONFIG;
+use crate::error::{APIError, APIErrorsResponse};
use actix_request_identifier::RequestIdentifier;
-use actix_web::{App, HttpResponse, HttpServer};
use actix_web::http::header::HeaderValue;
use actix_web::web::{Data, JsonConfig};
+use actix_web::{App, HttpResponse, HttpServer};
use log::{info, Level};
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
-use tera::Tera;
use starkingdoms_api_migration::{Migrator, MigratorTrait};
-use crate::config::CONFIG;
-use crate::error::{APIError, APIErrorsResponse};
+use std::error::Error;
+use std::time::Duration;
+use tera::Tera;
pub mod config;
-pub mod routes;
pub mod error;
+pub mod routes;
pub struct AppState {
pub conn: DatabaseConnection,
- pub templates: Tera
+ pub templates: Tera,
}
#[actix_web::main]
@@ 46,7 46,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let data = Data::new(AppState {
conn: db,
- templates: tera
+ templates: tera,
});
HttpServer::new(move || {
@@ 57,19 57,23 @@ async fn main() -> Result<(), Box<dyn Error>> {
actix_web::error::InternalError::from_response(
err,
HttpResponse::BadRequest().json(APIErrorsResponse {
- errors: vec![
- api_error
- ],
- })
- ).into()
+ errors: vec![api_error],
+ }),
+ )
+ .into()
+ }))
+ .wrap(RequestIdentifier::with_generator(|| {
+ HeaderValue::from_str(&ulid::Ulid::new().to_string()).unwrap()
}))
- .wrap(RequestIdentifier::with_generator(|| HeaderValue::from_str(&ulid::Ulid::new().to_string()).unwrap()))
.service(routes::select_realm::select_realm)
.service(routes::callback::callback)
.service(routes::beamin::beam_in)
.service(routes::beamout::beam_out)
.service(actix_files::Files::new("/static", "static"))
- }).bind(CONFIG.server.bind)?.run().await?;
+ })
+ .bind(CONFIG.server.bind)?
+ .run()
+ .await?;
Ok(())
-}>
\ No newline at end of file
+}
M api/src/routes/beamin.rs => api/src/routes/beamin.rs +49 -54
@@ 1,6 1,8 @@
-use std::collections::BTreeMap;
-use actix_web::{HttpResponse, post};
+use crate::config::CONFIG;
+use crate::error::{APIError, APIErrorsResponse};
+use crate::AppState;
use actix_web::web::{Data, Json};
+use actix_web::{post, HttpResponse};
use hmac::digest::KeyInit;
use hmac::Hmac;
use jwt::VerifyWithKey;
@@ 9,35 11,31 @@ use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder};
use serde::{Deserialize, Serialize};
use sha2::Sha256;
use starkingdoms_protocol::api::APISavedPlayerData;
-use crate::AppState;
-use crate::config::CONFIG;
-use crate::error::{APIError, APIErrorsResponse};
+use std::collections::BTreeMap;
#[derive(Serialize, Deserialize)]
pub struct BeaminRequest {
pub api_token: String,
pub user_auth_realm_id: String,
- pub user_auth_token: String
+ pub user_auth_token: String,
}
#[derive(Serialize, Deserialize)]
pub struct BeaminResponse {
pub save_id: String,
- pub save: APISavedPlayerData
+ pub save: APISavedPlayerData,
}
#[post("/beamin")]
pub async fn beam_in(data: Json<BeaminRequest>, state: Data<AppState>) -> HttpResponse {
if !CONFIG.internal_tokens.contains(&data.api_token) {
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_BAD_TOKEN".to_string(),
- message: "Missing or invalid api token".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_BAD_TOKEN".to_string(),
+ message: "Missing or invalid api token".to_string(),
+ path: None,
+ }],
+ });
}
let key: Hmac<Sha256> = Hmac::new_from_slice(CONFIG.jwt_signing_secret.as_bytes()).unwrap();
@@ 46,67 44,64 @@ pub async fn beam_in(data: Json<BeaminRequest>, state: Data<AppState>) -> HttpRe
Err(e) => {
error!("verifying error: {}", e);
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_BAD_TOKEN".to_string(),
- message: "Missing or invalid user token".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_BAD_TOKEN".to_string(),
+ message: "Missing or invalid user token".to_string(),
+ path: None,
+ }],
+ });
}
};
if !token.contains_key("user") || !token.contains_key("nonce") {
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_BAD_TOKEN".to_string(),
- message: "Missing or invalid user token (missing scopes)".to_string(),
- path: None,
- }
- ],
+ errors: vec![APIError {
+ code: "ERR_BAD_TOKEN".to_string(),
+ message: "Missing or invalid user token (missing scopes)".to_string(),
+ path: None,
+ }],
});
}
let user_id = token.get("user").unwrap();
- let user_savefile: Vec<starkingdoms_api_entities::entity::user_savefile::Model> = match starkingdoms_api_entities::entity::user_savefile::Entity::find().filter(
- starkingdoms_api_entities::entity::user_savefile::Column::User.eq(user_id))
- .order_by_desc(starkingdoms_api_entities::entity::user_savefile::Column::Timestamp).all(&state.conn).await {
- Ok(sf) => sf,
- Err(e) => {
- error!("database error: {}", e);
- return HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
+ let user_savefile: Vec<starkingdoms_api_entities::entity::user_savefile::Model> =
+ match starkingdoms_api_entities::entity::user_savefile::Entity::find()
+ .filter(starkingdoms_api_entities::entity::user_savefile::Column::User.eq(user_id))
+ .order_by_desc(starkingdoms_api_entities::entity::user_savefile::Column::Timestamp)
+ .all(&state.conn)
+ .await
+ {
+ Ok(sf) => sf,
+ Err(e) => {
+ error!("database error: {}", e);
+ return HttpResponse::InternalServerError().json(APIErrorsResponse {
+ errors: vec![APIError {
code: "ERR_DB_ERROR".to_string(),
message: "Unable to fetch user savefiles".to_string(),
path: None,
- }
- ],
- });
- }
- };
+ }],
+ });
+ }
+ };
if user_savefile.is_empty() {
return HttpResponse::NoContent().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_NO_SAVES".to_string(),
- message: "This user has no savefiles".to_string(),
- path: None,
- }
- ],
+ errors: vec![APIError {
+ code: "ERR_NO_SAVES".to_string(),
+ message: "This user has no savefiles".to_string(),
+ path: None,
+ }],
});
}
let save = &user_savefile[0];
let save_id = &save.id;
let save_data_str = &save.data;
- let save_data: APISavedPlayerData = toml::from_str(save_data_str).expect("database contained corrupted player save data");
+ let save_data: APISavedPlayerData =
+ toml::from_str(save_data_str).expect("database contained corrupted player save data");
HttpResponse::Ok().json(BeaminResponse {
save_id: save_id.clone(),
- save: save_data
+ save: save_data,
})
-}>
\ No newline at end of file
+}
M api/src/routes/beamout.rs => api/src/routes/beamout.rs +35 -40
@@ 1,7 1,8 @@
-use std::collections::BTreeMap;
-use std::time::{SystemTime, UNIX_EPOCH};
-use actix_web::{HttpResponse, post};
+use crate::config::CONFIG;
+use crate::error::{APIError, APIErrorsResponse};
+use crate::AppState;
use actix_web::web::{Data, Json};
+use actix_web::{post, HttpResponse};
use hmac::digest::KeyInit;
use hmac::Hmac;
use jwt::VerifyWithKey;
@@ 9,18 10,17 @@ use log::error;
use sea_orm::{ActiveModelTrait, IntoActiveModel};
use serde::{Deserialize, Serialize};
use sha2::Sha256;
-use ulid::Ulid;
use starkingdoms_protocol::api::APISavedPlayerData;
-use crate::AppState;
-use crate::config::CONFIG;
-use crate::error::{APIError, APIErrorsResponse};
+use std::collections::BTreeMap;
+use std::time::{SystemTime, UNIX_EPOCH};
+use ulid::Ulid;
#[derive(Serialize, Deserialize)]
pub struct BeamoutRequest {
pub api_token: String,
pub user_auth_realm_id: String,
pub user_auth_token: String,
- pub data: APISavedPlayerData
+ pub data: APISavedPlayerData,
}
#[derive(Serialize, Deserialize)]
@@ 30,14 30,12 @@ pub struct BeamoutResponse {}
pub async fn beam_out(data: Json<BeamoutRequest>, state: Data<AppState>) -> HttpResponse {
if !CONFIG.internal_tokens.contains(&data.api_token) {
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_BAD_TOKEN".to_string(),
- message: "Missing or invalid api token".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_BAD_TOKEN".to_string(),
+ message: "Missing or invalid api token".to_string(),
+ path: None,
+ }],
+ });
}
let key: Hmac<Sha256> = Hmac::new_from_slice(CONFIG.jwt_signing_secret.as_bytes()).unwrap();
@@ 46,26 44,22 @@ pub async fn beam_out(data: Json<BeamoutRequest>, state: Data<AppState>) -> Http
Err(e) => {
error!("verifying error: {}", e);
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_BAD_TOKEN".to_string(),
- message: "Missing or invalid user token".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_BAD_TOKEN".to_string(),
+ message: "Missing or invalid user token".to_string(),
+ path: None,
+ }],
+ });
}
};
if !token.contains_key("user") || !token.contains_key("nonce") {
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_BAD_TOKEN".to_string(),
- message: "Missing or invalid user token (missing scopes)".to_string(),
- path: None,
- }
- ],
+ errors: vec![APIError {
+ code: "ERR_BAD_TOKEN".to_string(),
+ message: "Missing or invalid user token (missing scopes)".to_string(),
+ path: None,
+ }],
});
}
@@ 74,7 68,10 @@ pub async fn beam_out(data: Json<BeamoutRequest>, state: Data<AppState>) -> Http
id: format!("save-{}", Ulid::new().to_string()),
user: token.get("user").unwrap().clone(),
data: saved_data,
- timestamp: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64,
+ timestamp: SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs() as i64,
};
let savefile_active_model = savefile_model.into_active_model();
match savefile_active_model.insert(&state.conn).await {
@@ 82,16 79,14 @@ pub async fn beam_out(data: Json<BeamoutRequest>, state: Data<AppState>) -> Http
Err(e) => {
error!("database error: {}", e);
return HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_DB_ERROR".to_string(),
- message: "database failure".to_string(),
- path: None,
- }
- ],
+ errors: vec![APIError {
+ code: "ERR_DB_ERROR".to_string(),
+ message: "database failure".to_string(),
+ path: None,
+ }],
});
}
}
HttpResponse::Ok().json(BeamoutResponse {})
-}>
\ No newline at end of file
+}
M api/src/routes/callback.rs => api/src/routes/callback.rs +72 -63
@@ 1,7 1,8 @@
-use std::collections::BTreeMap;
-use std::time::{SystemTime, UNIX_EPOCH};
-use actix_web::{get, HttpResponse};
+use crate::config::CONFIG;
+use crate::error::{APIError, APIErrorsResponse};
+use crate::AppState;
use actix_web::web::{Data, Query};
+use actix_web::{get, HttpResponse};
use hmac::digest::KeyInit;
use hmac::Hmac;
use jwt::{PKeyWithDigest, SignWithKey, VerifyWithKey};
@@ 11,16 12,15 @@ use openssl::pkey::PKey;
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter};
use serde::Deserialize;
use sha2::Sha256;
-use ulid::Ulid;
use starkingdoms_api_entities::entity;
-use crate::AppState;
-use crate::config::CONFIG;
-use crate::error::{APIError, APIErrorsResponse};
+use std::collections::BTreeMap;
+use std::time::{SystemTime, UNIX_EPOCH};
+use ulid::Ulid;
#[derive(Deserialize)]
pub struct CallbackQueryParams {
pub token: String,
- pub realm: String
+ pub realm: String,
}
#[get("/callback")]
@@ 33,20 33,18 @@ pub async fn callback(query: Query<CallbackQueryParams>, state: Data<AppState>)
None => {
error!("realm not found");
return HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_UNKNOWN_REALM".to_string(),
- message: "Unknown realm".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_UNKNOWN_REALM".to_string(),
+ message: "Unknown realm".to_string(),
+ path: None,
+ }],
+ });
}
};
let rs256_pub_key = PKeyWithDigest {
digest: MessageDigest::sha256(),
- key: PKey::public_key_from_pem(realm.public_key.as_bytes()).unwrap()
+ key: PKey::public_key_from_pem(realm.public_key.as_bytes()).unwrap(),
};
let token: BTreeMap<String, String> = match query.token.verify_with_key(&rs256_pub_key) {
@@ 59,35 57,35 @@ pub async fn callback(query: Query<CallbackQueryParams>, state: Data<AppState>)
let realm = match token.get("realm").ok_or(generic_unauthorized()) {
Ok(r) => r,
- Err(e) => return e
+ Err(e) => return e,
};
let realm_local_id = match token.get("realm_native_id").ok_or(generic_unauthorized()) {
Ok(r) => r,
- Err(e) => return e
+ Err(e) => return e,
};
- debug!("got authenticated realm native authorization: authenticated as {}:{}", realm, realm_local_id);
+ debug!(
+ "got authenticated realm native authorization: authenticated as {}:{}",
+ realm, realm_local_id
+ );
// see if a user on this realm already exists
let maybe_user = match entity::user_auth_realm::Entity::find()
- .filter(
- entity::user_auth_realm::Column::RealmNativeId.eq(realm_local_id.clone())
- )
- .filter(
- entity::user_auth_realm::Column::Realm.eq(realm.clone())
- ).one(&state.conn).await {
+ .filter(entity::user_auth_realm::Column::RealmNativeId.eq(realm_local_id.clone()))
+ .filter(entity::user_auth_realm::Column::Realm.eq(realm.clone()))
+ .one(&state.conn)
+ .await
+ {
Ok(r) => r,
Err(e) => {
error!("database error: {}", e);
return HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_DB_ERROR".to_string(),
- message: "Database error".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_DB_ERROR".to_string(),
+ message: "Database error".to_string(),
+ path: None,
+ }],
+ });
}
};
@@ 98,17 96,27 @@ pub async fn callback(query: Query<CallbackQueryParams>, state: Data<AppState>)
claims.insert("nonce", Ulid::new().to_string());
let token_str = claims.sign_with_key(&key).unwrap();
let auth_url = format!("{}/?token={}&user={}", CONFIG.game, token_str, user.id);
- return HttpResponse::Found().append_header(("Location", auth_url)).finish();
+ return HttpResponse::Found()
+ .append_header(("Location", auth_url))
+ .finish();
}
// create the user
let new_user = entity::user::Model {
id: format!("user-{}", Ulid::new().to_string()),
username: Ulid::new().to_string(),
- created_on: SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64,
+ created_on: SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_secs() as i64,
};
let new_user_realm = entity::user_auth_realm::Model {
- id: format!("{}-{}:{}", new_user.id.clone(), realm.clone(), realm_local_id.clone()),
+ id: format!(
+ "{}-{}:{}",
+ new_user.id.clone(),
+ realm.clone(),
+ realm_local_id.clone()
+ ),
realm: realm.clone(),
realm_native_id: realm_local_id.clone(),
user: new_user.id.clone(),
@@ 119,7 127,12 @@ pub async fn callback(query: Query<CallbackQueryParams>, state: Data<AppState>)
claims.insert("user", new_user.id.clone());
claims.insert("nonce", Ulid::new().to_string());
let token_str = claims.sign_with_key(&key).unwrap();
- let auth_url = format!("{}/?token={}&user={}", CONFIG.game, token_str, new_user.id.clone());
+ let auth_url = format!(
+ "{}/?token={}&user={}",
+ CONFIG.game,
+ token_str,
+ new_user.id.clone()
+ );
let new_user_active_model = new_user.into_active_model();
let new_user_realm_active_model = new_user_realm.into_active_model();
@@ 129,14 142,12 @@ pub async fn callback(query: Query<CallbackQueryParams>, state: Data<AppState>)
Err(e) => {
error!("database error: {}", e);
return HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_DB_ERROR".to_string(),
- message: "Database error".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_DB_ERROR".to_string(),
+ message: "Database error".to_string(),
+ path: None,
+ }],
+ });
}
}
@@ 145,28 156,26 @@ pub async fn callback(query: Query<CallbackQueryParams>, state: Data<AppState>)
Err(e) => {
error!("database error: {}", e);
return HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_DB_ERROR".to_string(),
- message: "Database error".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_DB_ERROR".to_string(),
+ message: "Database error".to_string(),
+ path: None,
+ }],
+ });
}
}
- HttpResponse::Found().append_header(("Location", auth_url)).finish()
+ HttpResponse::Found()
+ .append_header(("Location", auth_url))
+ .finish()
}
fn generic_unauthorized() -> HttpResponse {
HttpResponse::Unauthorized().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_INVALID_STATE".to_string(),
- message: "Unknown/invalid login state".to_string(),
- path: None,
- }
- ],
+ errors: vec![APIError {
+ code: "ERR_INVALID_STATE".to_string(),
+ message: "Unknown/invalid login state".to_string(),
+ path: None,
+ }],
})
-}>
\ No newline at end of file
+}
M api/src/routes/mod.rs => api/src/routes/mod.rs +2 -2
@@ 1,4 1,4 @@
pub mod beamin;
-pub mod select_realm;
+pub mod beamout;
pub mod callback;
-pub mod beamout;>
\ No newline at end of file
+pub mod select_realm;
M api/src/routes/select_realm.rs => api/src/routes/select_realm.rs +21 -23
@@ 1,17 1,17 @@
-use std::collections::HashMap;
+use crate::config::{StarkingdomsApiConfigRealm, CONFIG};
+use crate::error::{APIError, APIErrorsResponse};
+use crate::AppState;
+use actix_web::web::Data;
use actix_web::{get, HttpResponse};
-use actix_web::web::{Data};
use log::error;
-use serde::{Serialize};
+use serde::Serialize;
+use std::collections::HashMap;
use tera::Context;
-use crate::AppState;
-use crate::config::{CONFIG, StarkingdomsApiConfigRealm};
-use crate::error::{APIError, APIErrorsResponse};
#[derive(Serialize)]
pub struct RealmsListTemplateContext {
pub realms: HashMap<String, StarkingdomsApiConfigRealm>,
- pub back_to: String
+ pub back_to: String,
}
#[get("/select-realm")]
@@ 24,14 24,13 @@ pub async fn select_realm(state: Data<AppState>) -> HttpResponse {
Err(e) => {
error!("[context] error creating render context: {}", e);
return HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_INTERNAL_SERVER_ERROR".to_string(),
- message: "There was an error processing your request. Please try again later.".to_string(),
- path: None,
- }
- ],
- })
+ errors: vec![APIError {
+ code: "ERR_INTERNAL_SERVER_ERROR".to_string(),
+ message: "There was an error processing your request. Please try again later."
+ .to_string(),
+ path: None,
+ }],
+ });
}
};
match state.templates.render("select_realm.tera", &context) {
@@ 39,14 38,13 @@ pub async fn select_realm(state: Data<AppState>) -> HttpResponse {
Err(e) => {
error!("[context] error creating render context: {}", e);
HttpResponse::InternalServerError().json(APIErrorsResponse {
- errors: vec![
- APIError {
- code: "ERR_INTERNAL_SERVER_ERROR".to_string(),
- message: "There was an error processing your request. Please try again later.".to_string(),
- path: None,
- }
- ],
+ errors: vec![APIError {
+ code: "ERR_INTERNAL_SERVER_ERROR".to_string(),
+ message: "There was an error processing your request. Please try again later."
+ .to_string(),
+ path: None,
+ }],
})
}
}
-}>
\ No newline at end of file
+}
M api/starkingdoms_api_entities/src/lib.rs => api/starkingdoms_api_entities/src/lib.rs +1 -1
@@ 1,1 1,1 @@
-pub mod entity;>
\ No newline at end of file
+pub mod entity;
M api/starkingdoms_api_migration/src/m20230417_162824_create_table_users.rs => api/starkingdoms_api_migration/src/m20230417_162824_create_table_users.rs +16 -9
@@ 6,14 6,21 @@ pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
- manager.create_table(
- Table::create()
- .table(User::Table)
- .col(ColumnDef::new(User::Id).string().primary_key().not_null())
- .col(ColumnDef::new(User::Username).string().unique_key().not_null())
- .col(ColumnDef::new(User::CreatedOn).big_unsigned().not_null())
- .to_owned()
- ).await
+ manager
+ .create_table(
+ Table::create()
+ .table(User::Table)
+ .col(ColumnDef::new(User::Id).string().primary_key().not_null())
+ .col(
+ ColumnDef::new(User::Username)
+ .string()
+ .unique_key()
+ .not_null(),
+ )
+ .col(ColumnDef::new(User::CreatedOn).big_unsigned().not_null())
+ .to_owned(),
+ )
+ .await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
@@ 29,5 36,5 @@ pub enum User {
Table,
Id,
Username,
- CreatedOn
+ CreatedOn,
}
M api/starkingdoms_api_migration/src/m20230417_164240_create_table_user_auth_realms.rs => api/starkingdoms_api_migration/src/m20230417_164240_create_table_user_auth_realms.rs +27 -15
@@ 1,5 1,5 @@
-use sea_orm_migration::prelude::*;
use crate::m20230417_162824_create_table_users::User;
+use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
@@ 7,19 7,31 @@ pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
- manager.create_table(
- Table::create()
- .table(UserAuthRealm::Table)
- .col(ColumnDef::new(UserAuthRealm::Id).string().not_null().primary_key())
- .col(ColumnDef::new(UserAuthRealm::Realm).string().not_null())
- .col(ColumnDef::new(UserAuthRealm::RealmNativeId).string().not_null())
- .col(ColumnDef::new(UserAuthRealm::User).string().not_null())
- .foreign_key(
- ForeignKey::create()
- .from(UserAuthRealm::Table, UserAuthRealm::User)
- .to(User::Table, User::Id)
- ).to_owned()
- ).await
+ manager
+ .create_table(
+ Table::create()
+ .table(UserAuthRealm::Table)
+ .col(
+ ColumnDef::new(UserAuthRealm::Id)
+ .string()
+ .not_null()
+ .primary_key(),
+ )
+ .col(ColumnDef::new(UserAuthRealm::Realm).string().not_null())
+ .col(
+ ColumnDef::new(UserAuthRealm::RealmNativeId)
+ .string()
+ .not_null(),
+ )
+ .col(ColumnDef::new(UserAuthRealm::User).string().not_null())
+ .foreign_key(
+ ForeignKey::create()
+ .from(UserAuthRealm::Table, UserAuthRealm::User)
+ .to(User::Table, User::Id),
+ )
+ .to_owned(),
+ )
+ .await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
@@ 36,5 48,5 @@ pub enum UserAuthRealm {
Id,
Realm,
RealmNativeId,
- User
+ User,
}
M api/starkingdoms_api_migration/src/m20230420_144333_create_table_user_data.rs => api/starkingdoms_api_migration/src/m20230420_144333_create_table_user_data.rs +28 -16
@@ 1,5 1,5 @@
-use sea_orm_migration::prelude::*;
use crate::m20230417_164240_create_table_user_auth_realms::UserAuthRealm;
+use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
@@ 7,20 7,32 @@ pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
- manager.create_table(
- Table::create()
- .table(UserSavefile::Table)
- .col(ColumnDef::new(UserSavefile::Id).string().not_null().primary_key())
- .col(ColumnDef::new(UserSavefile::User).string().not_null())
- .col(ColumnDef::new(UserSavefile::Data).string().not_null())
- .col(ColumnDef::new(UserSavefile::Timestamp).big_unsigned().not_null().unique_key())
- .foreign_key(
- ForeignKey::create()
- .from(UserSavefile::Table, UserSavefile::User)
- .to(UserAuthRealm::Table, UserAuthRealm::Id)
- )
- .to_owned()
- ).await
+ manager
+ .create_table(
+ Table::create()
+ .table(UserSavefile::Table)
+ .col(
+ ColumnDef::new(UserSavefile::Id)
+ .string()
+ .not_null()
+ .primary_key(),
+ )
+ .col(ColumnDef::new(UserSavefile::User).string().not_null())
+ .col(ColumnDef::new(UserSavefile::Data).string().not_null())
+ .col(
+ ColumnDef::new(UserSavefile::Timestamp)
+ .big_unsigned()
+ .not_null()
+ .unique_key(),
+ )
+ .foreign_key(
+ ForeignKey::create()
+ .from(UserSavefile::Table, UserSavefile::User)
+ .to(UserAuthRealm::Table, UserAuthRealm::Id),
+ )
+ .to_owned(),
+ )
+ .await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
@@ 37,5 49,5 @@ pub enum UserSavefile {
Id,
User,
Data,
- Timestamp
+ Timestamp,
}
M protocol/src/api.rs => protocol/src/api.rs +1 -3
@@ 2,6 2,4 @@ use serde::{Deserialize, Serialize};
// ALL FIELDS **MUST** BE WRAPPED IN Option<>
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
-pub struct APISavedPlayerData {
-
-}>
\ No newline at end of file
+pub struct APISavedPlayerData {}
M protocol/src/legacy.rs => protocol/src/legacy.rs +14 -15
@@ 5,7 5,7 @@ pub const PROTOCOL_VERSION: u32 = 1;
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub enum State {
Handshake,
- Play
+ Play,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ 13,15 13,15 @@ pub enum MessageC2S {
Hello {
version: u32,
requested_username: String,
- next_state: State
+ next_state: State,
},
Goodbye {
- reason: GoodbyeReason
+ reason: GoodbyeReason,
},
Chat {
- message: String
+ message: String,
},
Ping {},
@@ 32,28 32,27 @@ pub enum MessageS2C {
Hello {
version: u32,
given_username: String,
- next_state: State
+ next_state: State,
},
Goodbye {
- reason: GoodbyeReason
+ reason: GoodbyeReason,
},
Chat {
from: String,
- message: String
+ message: String,
},
Pong {},
PlayersUpdate {
- players: Vec<ProtocolPlayer>
+ players: Vec<ProtocolPlayer>,
},
-
PlanetData {
- planets: Vec<ProtocolPlanet>
- }
+ planets: Vec<ProtocolPlanet>,
+ },
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ 61,7 60,7 @@ pub struct ProtocolPlayer {
pub rotation: f64,
pub x: f64,
pub y: f64,
- pub username: String
+ pub username: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ 79,18 78,18 @@ pub struct ProtocolPlanet {
pub planet_type: PlanetType,
pub x: f64,
pub y: f64,
- pub radius: f64
+ pub radius: f64,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum PlanetType {
- Earth
+ Earth,
}
impl PlanetType {
pub fn as_texture_id(&self) -> String {
match self {
- PlanetType::Earth => "earth".to_string()
+ PlanetType::Earth => "earth".to_string(),
}
}
}
M protocol/src/lib.rs => protocol/src/lib.rs +112 -71
@@ 1,9 1,15 @@
-use std::error::Error;
-use protobuf::{Enum, Message};
-use crate::message_c2s::{MessageC2SAuthenticateAndBeamOut, MessageC2SChat, MessageC2SGoodbye, MessageC2SHello, MessageC2SInput, MessageC2SMouseInput, MessageC2SPing};
-use crate::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong, MessageS2CModulesUpdate};
+use crate::message_c2s::{
+ MessageC2SAuthenticateAndBeamOut, MessageC2SChat, MessageC2SGoodbye, MessageC2SHello,
+ MessageC2SInput, MessageC2SMouseInput, MessageC2SPing,
+};
+use crate::message_s2c::{
+ MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CModulesUpdate,
+ MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong,
+};
use crate::planet::PlanetType;
use crate::starkingdoms_protocol::PacketWrapper;
+use protobuf::{Enum, Message};
+use std::error::Error;
include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));
pub const PROTOCOL_VERSION: u32 = 4;
@@ 18,7 24,7 @@ pub enum MessageC2S {
Ping(MessageC2SPing),
Input(MessageC2SInput),
AuthenticateAndBeamOut(MessageC2SAuthenticateAndBeamOut),
- MouseInput(MessageC2SMouseInput)
+ MouseInput(MessageC2SMouseInput),
}
#[derive(Debug)]
@@ 41,26 47,35 @@ impl TryFrom<&[u8]> for MessageC2S {
let deser_pkt = match pkt.packet_id {
_id if _id == message_c2s::message_c2shello::Packet_info::type_.value() as i64 => {
MessageC2S::Hello(MessageC2SHello::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_c2s::message_c2sgoodbye::Packet_info::type_.value() as i64 => {
MessageC2S::Goodbye(MessageC2SGoodbye::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_c2s::message_c2schat::Packet_info::type_.value() as i64 => {
MessageC2S::Chat(MessageC2SChat::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_c2s::message_c2sping::Packet_info::type_.value() as i64 => {
MessageC2S::Ping(MessageC2SPing::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_c2s::message_c2sinput::Packet_info::type_.value() as i64 => {
MessageC2S::Input(MessageC2SInput::parse_from_bytes(&pkt.packet_data)?)
- },
- _id if _id == message_c2s::message_c2sauthenticate_and_beam_out::Packet_info::type_.value() as i64 => {
- MessageC2S::AuthenticateAndBeamOut(MessageC2SAuthenticateAndBeamOut::parse_from_bytes(&pkt.packet_data)?)
- },
- _id if _id == message_c2s::message_c2smouse_input::Packet_info::type_.value() as i64 => {
+ }
+ _id if _id
+ == message_c2s::message_c2sauthenticate_and_beam_out::Packet_info::type_.value()
+ as i64 =>
+ {
+ MessageC2S::AuthenticateAndBeamOut(
+ MessageC2SAuthenticateAndBeamOut::parse_from_bytes(&pkt.packet_data)?,
+ )
+ }
+ _id if _id
+ == message_c2s::message_c2smouse_input::Packet_info::type_.value() as i64 =>
+ {
MessageC2S::MouseInput(MessageC2SMouseInput::parse_from_bytes(&pkt.packet_data)?)
}
- _id => { return Err(format!("Unrecognized C2S packet {}", _id).into()); }
+ _id => {
+ return Err(format!("Unrecognized C2S packet {}", _id).into());
+ }
};
Ok(deser_pkt)
@@ 72,27 87,34 @@ impl TryInto<Vec<u8>> for MessageC2S {
fn try_into(self) -> Result<Vec<u8>, Self::Error> {
let (pkt_id, pkt_bytes) = match self {
- MessageC2S::Hello(p) => {
- (message_c2s::message_c2shello::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageC2S::Goodbye(p) => {
- (message_c2s::message_c2sgoodbye::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageC2S::Chat(p) => {
- (message_c2s::message_c2schat::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageC2S::Ping(p) => {
- (message_c2s::message_c2sping::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageC2S::Input(p) => {
- (message_c2s::message_c2sping::Packet_info::type_.value(), p.write_to_bytes()?)
- },
- MessageC2S::AuthenticateAndBeamOut(p) => {
- (message_c2s::message_c2sauthenticate_and_beam_out::Packet_info::type_.value(), p.write_to_bytes()?)
- },
- MessageC2S::MouseInput(p) => {
- (message_c2s::message_c2smouse_input::Packet_info::type_.value(), p.write_to_bytes()?)
- }
+ MessageC2S::Hello(p) => (
+ message_c2s::message_c2shello::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageC2S::Goodbye(p) => (
+ message_c2s::message_c2sgoodbye::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageC2S::Chat(p) => (
+ message_c2s::message_c2schat::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageC2S::Ping(p) => (
+ message_c2s::message_c2sping::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageC2S::Input(p) => (
+ message_c2s::message_c2sping::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageC2S::AuthenticateAndBeamOut(p) => (
+ message_c2s::message_c2sauthenticate_and_beam_out::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageC2S::MouseInput(p) => (
+ message_c2s::message_c2smouse_input::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
};
let pkt = PacketWrapper {
@@ 114,26 136,38 @@ impl TryFrom<&[u8]> for MessageS2C {
let deser_pkt = match pkt.packet_id {
_id if _id == message_s2c::message_s2chello::Packet_info::type_.value() as i64 => {
MessageS2C::Hello(MessageS2CHello::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_s2c::message_s2cgoodbye::Packet_info::type_.value() as i64 => {
MessageS2C::Goodbye(MessageS2CGoodbye::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_s2c::message_s2cchat::Packet_info::type_.value() as i64 => {
MessageS2C::Chat(MessageS2CChat::parse_from_bytes(&pkt.packet_data)?)
- },
+ }
_id if _id == message_s2c::message_s2cpong::Packet_info::type_.value() as i64 => {
MessageS2C::Pong(MessageS2CPong::parse_from_bytes(&pkt.packet_data)?)
- },
- _id if _id == message_s2c::message_s2cplayers_update::Packet_info::type_.value() as i64 => {
- MessageS2C::PlayersUpdate(MessageS2CPlayersUpdate::parse_from_bytes(&pkt.packet_data)?)
- },
- _id if _id == message_s2c::message_s2cplanet_data::Packet_info::type_.value() as i64 => {
+ }
+ _id if _id
+ == message_s2c::message_s2cplayers_update::Packet_info::type_.value() as i64 =>
+ {
+ MessageS2C::PlayersUpdate(MessageS2CPlayersUpdate::parse_from_bytes(
+ &pkt.packet_data,
+ )?)
+ }
+ _id if _id
+ == message_s2c::message_s2cplanet_data::Packet_info::type_.value() as i64 =>
+ {
MessageS2C::PlanetData(MessageS2CPlanetData::parse_from_bytes(&pkt.packet_data)?)
- },
- _id if _id == message_s2c::message_s2cmodules_update::Packet_info::type_.value() as i64 => {
- MessageS2C::ModulesUpdate(MessageS2CModulesUpdate::parse_from_bytes(&pkt.packet_data)?)
- },
- _ => { return Err("Not a S2C packet".into()); }
+ }
+ _id if _id
+ == message_s2c::message_s2cmodules_update::Packet_info::type_.value() as i64 =>
+ {
+ MessageS2C::ModulesUpdate(MessageS2CModulesUpdate::parse_from_bytes(
+ &pkt.packet_data,
+ )?)
+ }
+ _ => {
+ return Err("Not a S2C packet".into());
+ }
};
Ok(deser_pkt)
@@ 145,27 179,34 @@ impl TryInto<Vec<u8>> for MessageS2C {
fn try_into(self) -> Result<Vec<u8>, Self::Error> {
let (pkt_id, pkt_bytes) = match self {
- MessageS2C::Hello(p) => {
- (message_s2c::message_s2chello::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageS2C::Goodbye(p) => {
- (message_s2c::message_s2cgoodbye::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageS2C::Chat(p) => {
- (message_s2c::message_s2cchat::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageS2C::Pong(p) => {
- (message_s2c::message_s2cpong::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageS2C::PlayersUpdate(p) => {
- (message_s2c::message_s2cplayers_update::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageS2C::PlanetData(p) => {
- (message_s2c::message_s2cplanet_data::Packet_info::type_.value(), p.write_to_bytes()?)
- }
- MessageS2C::ModulesUpdate(p) => {
- (message_s2c::message_s2cmodules_update::Packet_info::type_.value(), p.write_to_bytes()?)
- }
+ MessageS2C::Hello(p) => (
+ message_s2c::message_s2chello::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageS2C::Goodbye(p) => (
+ message_s2c::message_s2cgoodbye::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageS2C::Chat(p) => (
+ message_s2c::message_s2cchat::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageS2C::Pong(p) => (
+ message_s2c::message_s2cpong::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageS2C::PlayersUpdate(p) => (
+ message_s2c::message_s2cplayers_update::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageS2C::PlanetData(p) => (
+ message_s2c::message_s2cplanet_data::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
+ MessageS2C::ModulesUpdate(p) => (
+ message_s2c::message_s2cmodules_update::Packet_info::type_.value(),
+ p.write_to_bytes()?,
+ ),
};
let pkt = PacketWrapper {
@@ 183,7 224,7 @@ impl planet::PlanetType {
match self {
PlanetType::Earth => "earth".to_string(),
PlanetType::Moon => "moon".to_string(),
- PlanetType::UNKNOWN => "missing".to_string()
+ PlanetType::UNKNOWN => "missing".to_string(),
}
}
}
M server/build.rs => server/build.rs +19 -6
@@ 1,5 1,5 @@
-use std::process::Command;
use cargo_metadata::MetadataCommand;
+use std::process::Command;
fn main() {
let path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
@@ 14,16 14,29 @@ fn main() {
let version = root.version.to_string();
let version_name = root.metadata["version-name"].to_string().replace('"', "");
- let description = root.metadata["slp-description"].to_string().replace('"', "");
+ let description = root.metadata["slp-description"]
+ .to_string()
+ .replace('"', "");
- let output = Command::new("git").args(["rev-parse", "--short", "HEAD"]).output().unwrap();
+ let output = Command::new("git")
+ .args(["rev-parse", "--short", "HEAD"])
+ .output()
+ .unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=STK_VERSION={}", version);
println!("cargo:rustc-env=STK_VERSION_NAME={}", version_name);
println!("cargo:rustc-env=STK_SLP_DESCRIPTION={}", description);
- println!("cargo:rustc-env=STK_CHANNEL={}", std::env::var("STK_CHANNEL").unwrap_or("dev".to_string()));
- println!("cargo:rustc-env=STK_BUILD={}-{}-{}", std::env::var("STK_CHANNEL").unwrap_or("dev".to_string()), std::env::var("STK_BUILD_NUM").unwrap_or("local".to_string()), git_hash);
+ println!(
+ "cargo:rustc-env=STK_CHANNEL={}",
+ std::env::var("STK_CHANNEL").unwrap_or("dev".to_string())
+ );
+ println!(
+ "cargo:rustc-env=STK_BUILD={}-{}-{}",
+ std::env::var("STK_CHANNEL").unwrap_or("dev".to_string()),
+ std::env::var("STK_BUILD_NUM").unwrap_or("local".to_string()),
+ git_hash
+ );
println!("cargo:rerun-if-changed=Cargo.toml");
println!("cargo:rerun-if-env-changed=STK_BUILD_NUM");
-}>
\ No newline at end of file
+}
M server/src/api.rs => server/src/api.rs +44 -17
@@ 1,40 1,53 @@
-use std::error::Error;
use log::error;
use reqwest::StatusCode;
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
use starkingdoms_protocol::api::APISavedPlayerData;
+use std::error::Error;
#[derive(Serialize, Deserialize)]
pub struct BeaminRequest {
pub api_token: String,
pub user_auth_realm_id: String,
- pub user_auth_token: String
+ pub user_auth_token: String,
}
#[derive(Serialize, Deserialize)]
pub struct BeaminResponse {
pub save_id: String,
- pub save: APISavedPlayerData
+ pub save: APISavedPlayerData,
}
-pub async fn load_player_data_from_api(token: &str, user_id: &str, internal_token: &str) -> Result<APISavedPlayerData, Box<dyn Error>> {
+pub async fn load_player_data_from_api(
+ token: &str,
+ user_id: &str,
+ internal_token: &str,
+) -> Result<APISavedPlayerData, Box<dyn Error>> {
let client = reqwest::Client::new();
let req_body = BeaminRequest {
api_token: internal_token.to_owned(),
user_auth_realm_id: user_id.to_owned(),
- user_auth_token: token.to_owned()
+ user_auth_token: token.to_owned(),
};
- let res = client.post(format!("{}/beamin", std::env::var("STK_API_URL").unwrap())).header("Content-Type", "application/json").body(serde_json::to_string(&req_body)?).send().await?;
+ let res = client
+ .post(format!("{}/beamin", std::env::var("STK_API_URL").unwrap()))
+ .header("Content-Type", "application/json")
+ .body(serde_json::to_string(&req_body)?)
+ .send()
+ .await?;
if res.status() == StatusCode::NO_CONTENT {
- return Ok(APISavedPlayerData::default())
+ return Ok(APISavedPlayerData::default());
}
if res.status() != StatusCode::OK {
- error!("error with API call (status: {}, body: {})", res.status(), res.text().await?);
- return Err("Error with API call".into())
+ error!(
+ "error with API call (status: {}, body: {})",
+ res.status(),
+ res.text().await?
+ );
+ return Err("Error with API call".into());
}
let resp: BeaminResponse = serde_json::from_str(&res.text().await?)?;
@@ 47,25 60,39 @@ pub struct BeamoutRequest {
pub api_token: String,
pub user_auth_realm_id: String,
pub user_auth_token: String,
- pub data: APISavedPlayerData
+ pub data: APISavedPlayerData,
}
-pub async fn save_player_data_to_api(data: &APISavedPlayerData, token: &str, user_id: &str, internal_token: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
+pub async fn save_player_data_to_api(
+ data: &APISavedPlayerData,
+ token: &str,
+ user_id: &str,
+ internal_token: &str,
+) -> Result<(), Box<dyn Error + Send + Sync>> {
let client = reqwest::Client::new();
let req_body = BeamoutRequest {
api_token: internal_token.to_owned(),
user_auth_realm_id: user_id.to_owned(),
user_auth_token: token.to_owned(),
- data: data.to_owned()
+ data: data.to_owned(),
};
- let res = client.post(format!("{}/beamout", std::env::var("STK_API_URL").unwrap())).header("Content-Type", "application/json").body(serde_json::to_string(&req_body)?).send().await?;
+ let res = client
+ .post(format!("{}/beamout", std::env::var("STK_API_URL").unwrap()))
+ .header("Content-Type", "application/json")
+ .body(serde_json::to_string(&req_body)?)
+ .send()
+ .await?;
if res.status() != StatusCode::OK {
- error!("error with API call (status: {}, body: {})", res.status(), res.text().await?);
- return Err("Error with API call".into())
+ error!(
+ "error with API call (status: {}, body: {})",
+ res.status(),
+ res.text().await?
+ );
+ return Err("Error with API call".into());
}
Ok(())
-}>
\ No newline at end of file
+}
M server/src/entity.rs => server/src/entity.rs +11 -7
@@ 1,9 1,13 @@
-use std::{sync::atomic::AtomicU32, collections::HashMap, net::SocketAddr};
+use std::{collections::HashMap, net::SocketAddr, sync::atomic::AtomicU32};
use nalgebra::Vector2;
use starkingdoms_protocol::planet::PlanetType;
-use crate::{planet::Planet, SCALE, manager::{ClientHandlerMessage, Player, Module, AttachedModule}};
+use crate::{
+ manager::{AttachedModule, ClientHandlerMessage, Module, Player},
+ planet::Planet,
+ SCALE,
+};
pub type EntityId = u32;
pub type Entities = HashMap<EntityId, Entity>;
@@ 11,7 15,9 @@ 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 > 4_147_483_600 { panic!("No remaining entity ids") };
+ if id > 4_147_483_600 {
+ panic!("No remaining entity ids")
+ };
id
}
@@ 23,7 29,7 @@ pub struct EntityHandler {
impl EntityHandler {
pub fn new() -> EntityHandler {
EntityHandler {
- entities: Entities::new()
+ entities: Entities::new(),
}
}
pub fn get_planets(&self) -> Vec<Planet> {
@@ 160,9 166,7 @@ impl EntityHandler {
});
}
- ClientHandlerMessage::PlanetData {
- planets
- }
+ ClientHandlerMessage::PlanetData { planets }
}
}
M server/src/handler.rs => server/src/handler.rs +240 -127
@@ 1,32 1,44 @@
+use crate::api::{load_player_data_from_api, save_player_data_to_api};
+use crate::entity::{get_entity_id, Entity, EntityHandler};
+use crate::manager::{
+ AttachedModule, ClientHandlerMessage, ClientManager, ModuleTemplate, PhysicsData, Player,
+};
+use crate::{recv, send, SCALE};
+use async_std::net::TcpStream;
+use async_std::{channel::Receiver, sync::RwLock};
+use async_tungstenite::WebSocketStream;
+use futures::stream::{SplitSink, SplitStream};
+use futures::{FutureExt, SinkExt, StreamExt};
+use log::{debug, error, info, warn};
+use nalgebra::{point, vector};
+use rand::Rng;
+use rapier2d_f64::prelude::{
+ Collider, ColliderBuilder, MassProperties, RigidBodyBuilder, RigidBodyType,
+};
+use starkingdoms_protocol::goodbye_reason::GoodbyeReason;
+use starkingdoms_protocol::message_s2c::{
+ MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CModulesUpdate,
+ MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong,
+};
+use starkingdoms_protocol::module::ModuleType;
+use starkingdoms_protocol::state::State;
+use starkingdoms_protocol::{MessageC2S, MessageS2C, PROTOCOL_VERSION};
use std::error::Error;
use std::f64::consts::PI;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
-use futures::stream::{SplitSink, SplitStream};
-use futures::{FutureExt, SinkExt, StreamExt};
-use log::{error, info, debug, warn};
-use nalgebra::{vector, point};
-use rand::Rng;
-use rapier2d_f64::prelude::{RigidBodyBuilder, RigidBodyType, ColliderBuilder, MassProperties, Collider};
-use starkingdoms_protocol::module::ModuleType;
use tungstenite::Message;
-use starkingdoms_protocol::goodbye_reason::GoodbyeReason;
-use starkingdoms_protocol::message_s2c::{MessageS2CChat, MessageS2CGoodbye, MessageS2CHello, MessageS2CPlanetData, MessageS2CPlayersUpdate, MessageS2CPong, MessageS2CModulesUpdate};
-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, AttachedModule, ModuleTemplate};
-use crate::{send, recv, SCALE};
-use async_std::{sync::RwLock, channel::Receiver};
-use async_std::net::TcpStream;
-use async_tungstenite::WebSocketStream;
-use crate::api::{load_player_data_from_api, save_player_data_to_api};
-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>> {
+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);
@@ 41,7 53,8 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
from,
message,
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
}
}
@@ 50,7 63,8 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
let msg = MessageS2C::PlayersUpdate(MessageS2CPlayersUpdate {
players,
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
}
}
@@ 59,7 73,8 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
let msg = MessageS2C::PlanetData(MessageS2CPlanetData {
planets,
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
}
}
@@ 68,7 83,8 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
let msg = MessageS2C::ModulesUpdate(MessageS2CModulesUpdate {
modules,
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
}
}
@@ 83,7 99,8 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
reason: GoodbyeReason::PingPongTimeout.into(),
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
break;
}
@@ 96,34 113,52 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
MessageC2S::Hello(pkt) => {
info!("client sent hello");
if !matches!(pkt.next_state.unwrap(), State::Play) {
- error!("client sent unexpected state {:?} (expected: Play)", pkt.next_state);
+ error!(
+ "client sent unexpected state {:?} (expected: Play)",
+ pkt.next_state
+ );
let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
reason: GoodbyeReason::UnexpectedNextState.into(),
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
break;
}
// check version
if pkt.version != PROTOCOL_VERSION {
- error!("client sent incompatible version {} (expected: {})", pkt.version, PROTOCOL_VERSION);
+ error!(
+ "client sent incompatible version {} (expected: {})",
+ pkt.version, PROTOCOL_VERSION
+ );
let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
reason: GoodbyeReason::UnsupportedProtocol.into(),
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
break;
}
// determine if we can give them that username
{
- if mgr.usernames.read().await.values().any(|u| *u == pkt.requested_username) {
- error!("client requested username {} but it is in use", pkt.requested_username);
+ if mgr
+ .usernames
+ .read()
+ .await
+ .values()
+ .any(|u| *u == pkt.requested_username)
+ {
+ error!(
+ "client requested username {} but it is in use",
+ pkt.requested_username
+ );
let msg: Vec<u8> = MessageS2C::Goodbye(MessageS2CGoodbye {
reason: GoodbyeReason::UsernameTaken.into(),
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
break;
}
@@ 131,7 166,10 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
// username is fine
{
- mgr.usernames.write().await.insert(remote_addr, pkt.requested_username.clone());
+ mgr.usernames
+ .write()
+ .await
+ .insert(remote_addr, pkt.requested_username.clone());
}
let msg = MessageS2C::Hello(MessageS2CHello {
@@ 139,7 177,8 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
given_username: pkt.requested_username.clone(),
special_fields: Default::default(),
next_state: pkt.next_state,
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
@@ 158,16 197,27 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
rng.gen::<f64>() * PI * 2.
};
let player_body = RigidBodyBuilder::new(RigidBodyType::Dynamic)
- .translation(vector![angle.cos() * 2050. / SCALE, angle.sin() * 2050.0/SCALE])
+ .translation(vector![
+ angle.cos() * 2050. / SCALE,
+ angle.sin() * 2050.0 / SCALE
+ ])
.rotation(angle + PI / 2.)
.build();
- let player_collider: Collider = ColliderBuilder::cuboid(25.0 / SCALE, 25.0 / SCALE)
- .mass_properties(MassProperties::new(point![0.0, 0.0], 120.0, 122500.0))
- .build();
+ let player_collider: Collider =
+ ColliderBuilder::cuboid(25.0 / SCALE, 25.0 / SCALE)
+ .mass_properties(MassProperties::new(
+ point![0.0, 0.0],
+ 120.0,
+ 122500.0,
+ ))
+ .build();
let player_handle = rigid_body_set.insert(player_body);
- collider_set.insert_with_parent(player_collider, player_handle, &mut rigid_body_set);
-
+ collider_set.insert_with_parent(
+ player_collider,
+ player_handle,
+ &mut rigid_body_set,
+ );
let mut player = Player {
handle: player_handle,
@@ 183,128 233,191 @@ pub async fn handle_client(mgr: ClientManager, entities: Arc<RwLock<EntityHandle
if !pkt.user.is_empty() && !pkt.token.is_empty() {
player.auth_token = Some(pkt.token.clone());
player.auth_user = Some(pkt.user.clone());
- info!("[{}] * Beamin: beaming in {} as {} with token {}", remote_addr, username, pkt.user, pkt.token);
+ info!(
+ "[{}] * Beamin: beaming in {} as {} with token {}",
+ remote_addr, username, pkt.user, pkt.token
+ );
- let player_data = match load_player_data_from_api(&pkt.token, &pkt.user, &std::env::var("STK_API_KEY").unwrap()).await {
+ let player_data = match load_player_data_from_api(
+ &pkt.token,
+ &pkt.user,
+ &std::env::var("STK_API_KEY").unwrap(),
+ )
+ .await
+ {
Ok(d) => d,
Err(e) => {
- warn!("[{}] * Beamin: ABORTED. API returned error: {}", remote_addr, e);
- e_write_handle.entities.insert(get_entity_id(), Entity::Player(player));
+ warn!(
+ "[{}] * Beamin: ABORTED. API returned error: {}",
+ remote_addr, e
+ );
+ e_write_handle
+ .entities
+ .insert(get_entity_id(), Entity::Player(player));
continue;
}
};
- info!("[{}] Beamin: loaded player data! {:?}", remote_addr, player_data);
+ info!(
+ "[{}] Beamin: loaded player data! {:?}",
+ remote_addr, player_data
+ );
player.load_api_data(&player_data);
}
let player_id = get_entity_id();
- e_write_handle.entities.insert(player_id, Entity::Player(player));
- AttachedModule::attach_new(&mut data_handle, &mut e_write_handle,
- player_id, player_id,
- ModuleTemplate {
- translation: vector![0.0, 50.0],
- heading: 0.0,
- mass_properties: MassProperties::new(point![0.0, 0.0], 120.0, 122500.0),
- module_type: ModuleType::Cargo,
- }, 0, angle);
+ e_write_handle
+ .entities
+ .insert(player_id, Entity::Player(player));
+ AttachedModule::attach_new(
+ &mut data_handle,
+ &mut e_write_handle,
+ player_id,
+ player_id,
+ ModuleTemplate {
+ translation: vector![0.0, 50.0],
+ heading: 0.0,
+ mass_properties: MassProperties::new(
+ point![0.0, 0.0],
+ 120.0,
+ 122500.0,
+ ),
+ module_type: ModuleType::Cargo,
+ },
+ 0,
+ angle,
+ );
data_handle.rigid_body_set = rigid_body_set;
data_handle.collider_set = collider_set;
debug!("running");
}
- },
+ }
MessageC2S::Goodbye(pkt) => {
info!("client sent goodbye: {:?}", pkt.reason);
break;
- },
+ }
_ => {
- error!("client sent unexpected packet {:?} for state {:?}", pkt, state);
+ error!(
+ "client sent unexpected packet {:?} for state {:?}",
+ pkt, state
+ );
let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
reason: GoodbyeReason::UnexpectedPacket.into(),
special_fields: Default::default(),
- }).try_into()?;
+ })
+ .try_into()?;
send!(client_tx, msg).await?;
break;
}
}
}
- State::Play => {
- match pkt {
- MessageC2S::Hello { .. } => {
- error!("client sent unexpected packet {:?} for state {:?}", pkt, state);
- let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
- reason: GoodbyeReason::UnexpectedPacket.into(),
- special_fields: Default::default(),
- }).try_into()?;
- send!(client_tx, msg).await?;
- break;
- },
- MessageC2S::Goodbye(pkt) => {
- info!("client sent goodbye: {:?}", pkt.reason);
- break;
- },
- MessageC2S::Chat(pkt) => {
- info!("[{}] CHAT: [{}] {}", remote_addr, username, pkt.message);
+ State::Play => match pkt {
+ MessageC2S::Hello { .. } => {
+ error!(
+ "client sent unexpected packet {:?} for state {:?}",
+ pkt, state
+ );
+ let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
+ reason: GoodbyeReason::UnexpectedPacket.into(),
+ special_fields: Default::default(),
+ })
+ .try_into()?;
+ send!(client_tx, msg).await?;
+ break;
+ }
+ MessageC2S::Goodbye(pkt) => {
+ info!("client sent goodbye: {:?}", pkt.reason);
+ break;
+ }
+ MessageC2S::Chat(pkt) => {
+ info!("[{}] CHAT: [{}] {}", remote_addr, username, pkt.message);
- for (_addr, client_thread) in mgr.handlers.read().await.iter() {
- match client_thread.tx.send(ClientHandlerMessage::ChatMessage { from: username.clone(), message: pkt.message.clone() }).await {
- Ok(_) => (),
- Err(e) => {
- error!("unable to update a client thread: {}", e);
- }
+ for (_addr, client_thread) in mgr.handlers.read().await.iter() {
+ match client_thread
+ .tx
+ .send(ClientHandlerMessage::ChatMessage {
+ from: username.clone(),
+ message: pkt.message.clone(),
+ })
+ .await
+ {
+ Ok(_) => (),
+ Err(e) => {
+ error!("unable to update a client thread: {}", e);
}
}
- },
- MessageC2S::Ping(_) => {
- let msg = MessageS2C::Pong(MessageS2CPong {
- special_fields: Default::default(),
- }).try_into()?;
- send!(client_tx, msg).await?;
- ping_timeout = SystemTime::now() + Duration::from_secs(10);
- },
- MessageC2S::Input(p) => {
- let mut handle = entities.write().await;
- let 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;
- }
- },
- MessageC2S::AuthenticateAndBeamOut(p) => {
- info!("[{}] * Beaming out {} as {} with realm token {}", remote_addr, username, p.user_id, p.token);
+ }
+ }
+ MessageC2S::Ping(_) => {
+ let msg = MessageS2C::Pong(MessageS2CPong {
+ special_fields: Default::default(),
+ })
+ .try_into()?;
+ send!(client_tx, msg).await?;
+ ping_timeout = SystemTime::now() + Duration::from_secs(10);
+ }
+ MessageC2S::Input(p) => {
+ let mut handle = entities.write().await;
+ let 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;
+ }
+ }
+ MessageC2S::AuthenticateAndBeamOut(p) => {
+ info!(
+ "[{}] * Beaming out {} as {} with realm token {}",
+ remote_addr, username, p.user_id, p.token
+ );
- let player = entities.read().await.get_player(remote_addr).expect("Player sending messages after disconnect");
+ let player = entities
+ .read()
+ .await
+ .get_player(remote_addr)
+ .expect("Player sending messages after disconnect");
- if Some(p.token) != player.auth_token || Some(p.user_id) != player.auth_user {
- warn!("[{}] invalid beamout packet, ignoring", remote_addr);
- continue;
- }
+ if Some(p.token) != player.auth_token || Some(p.user_id) != player.auth_user
+ {
+ warn!("[{}] invalid beamout packet, ignoring", remote_addr);
+ continue;
+ }
- match save_player_data_to_api(&player.as_api_data(), &player.auth_token.unwrap(), &player.auth_user.unwrap(), &std::env::var("STK_API_KEY").unwrap()).await {
- Ok(_) => {
- info!("[{}] * Beamed out successfully", remote_addr);
- let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
- reason: GoodbyeReason::Done.into(),
- special_fields: Default::default(),
- }).try_into()?;
- send!(client_tx, msg).await?;
- break;
- }
- Err(e) => {
- error!("[{}] error beaming out: {}", remote_addr, e);
- }
+ match save_player_data_to_api(
+ &player.as_api_data(),
+ &player.auth_token.unwrap(),
+ &player.auth_user.unwrap(),
+ &std::env::var("STK_API_KEY").unwrap(),
+ )
+ .await
+ {
+ Ok(_) => {
+ info!("[{}] * Beamed out successfully", remote_addr);
+ let msg = MessageS2C::Goodbye(MessageS2CGoodbye {
+ reason: GoodbyeReason::Done.into(),
+ special_fields: Default::default(),
+ })
+ .try_into()?;
+ send!(client_tx, msg).await?;
+ break;
+ }
+ Err(e) => {
+ error!("[{}] error beaming out: {}", remote_addr, e);
}
- },
- MessageC2S::MouseInput(p) => {
- debug!("[{}] player input: {:?}", remote_addr, p);
}
}
- }
+ MessageC2S::MouseInput(p) => {
+ debug!("[{}] player input: {:?}", remote_addr, p);
+ }
+ },
}
}
}
M server/src/macros.rs => server/src/macros.rs +39 -43
@@ 13,49 13,13 @@ pub fn _generic_pkt_into(p: Vec<u8>) -> Message {
#[macro_export]
macro_rules! recv {
- ($reader:expr) => {
- {
- if let Some(future_result) = $reader.next().now_or_never() {
- if let Some(msg) = future_result {
- match msg {
- Ok(msg) => {
- if msg.is_binary() {
- match MessageC2S::try_from(msg.into_data().as_slice()) {
- Ok(d) => Ok(Some(d)),
- Err(e) => {
- log::error!("error deserializing message: {}", e);
- Ok(None)
- }
- }
- } else {
- Ok(None)
- }
- },
- Err(e) => {
- log::error!("error receiving message: {}", e);
- Ok(None)
- }
- }
- } else {
- log::error!("pipe closed");
- Err("Pipe closed")
- }
- } else {
- Ok(None)
- }
- }
- }
-}
-
-#[macro_export]
-macro_rules! recv_now {
- ($reader:expr) => {
- {
- if let Some(msg) = $reader.next().await {
+ ($reader:expr) => {{
+ if let Some(future_result) = $reader.next().now_or_never() {
+ if let Some(msg) = future_result {
match msg {
Ok(msg) => {
if msg.is_binary() {
- match MessageC2S::try_from(&msg.into_data()) {
+ match MessageC2S::try_from(msg.into_data().as_slice()) {
Ok(d) => Ok(Some(d)),
Err(e) => {
log::error!("error deserializing message: {}", e);
@@ 65,7 29,7 @@ macro_rules! recv_now {
} else {
Ok(None)
}
- },
+ }
Err(e) => {
log::error!("error receiving message: {}", e);
Ok(None)
@@ 75,6 39,38 @@ macro_rules! recv_now {
log::error!("pipe closed");
Err("Pipe closed")
}
+ } else {
+ Ok(None)
}
- };
-}>
\ No newline at end of file
+ }};
+}
+
+#[macro_export]
+macro_rules! recv_now {
+ ($reader:expr) => {{
+ if let Some(msg) = $reader.next().await {
+ match msg {
+ Ok(msg) => {
+ if msg.is_binary() {
+ match MessageC2S::try_from(&msg.into_data()) {
+ Ok(d) => Ok(Some(d)),
+ Err(e) => {
+ log::error!("error deserializing message: {}", e);
+ Ok(None)
+ }
+ }
+ } else {
+ Ok(None)
+ }
+ }
+ Err(e) => {
+ log::error!("error receiving message: {}", e);
+ Ok(None)
+ }
+ }
+ } else {
+ log::error!("pipe closed");
+ Err("Pipe closed")
+ }
+ }};
+}
M server/src/main.rs => server/src/main.rs +92 -39
@@ 1,37 1,45 @@
-use std::error::Error;
-use std::net::SocketAddr;
-use async_std::io::WriteExt;
-use async_std::sync::Arc;
-use async_std::net::{TcpListener, TcpStream};
-use entity::{EntityHandler};
-use manager::PhysicsData;
-use nalgebra::vector;
-use rapier2d_f64::prelude::{MultibodyJointSet, ImpulseJointSet, ColliderSet, RigidBodySet, NarrowPhase, BroadPhase, IslandManager, CCDSolver, IntegrationParameters};
-use lazy_static::lazy_static;
-use log::{error, info, Level, warn};
-use serde::{Deserialize, Serialize};
use crate::entity::Entity;
+use crate::handler::handle_client;
use crate::manager::{ClientHandler, ClientManager};
use crate::timer::timer_main;
+use async_std::io::WriteExt;
+use async_std::net::{TcpListener, TcpStream};
+use async_std::sync::Arc;
use async_std::sync::RwLock;
+use entity::EntityHandler;
use futures::StreamExt;
+use lazy_static::lazy_static;
+use log::{error, info, warn, Level};
+use manager::PhysicsData;
+use nalgebra::vector;
+use rapier2d_f64::prelude::{
+ BroadPhase, CCDSolver, ColliderSet, ImpulseJointSet, IntegrationParameters, IslandManager,
+ MultibodyJointSet, NarrowPhase, RigidBodySet,
+};
+use serde::{Deserialize, Serialize};
use starkingdoms_protocol::PROTOCOL_VERSION;
-use crate::handler::handle_client;
+use std::error::Error;
+use std::net::SocketAddr;
pub mod handler;
pub mod manager;
pub mod timer;
#[macro_use]
pub mod macros;
-pub mod planet;
-pub mod orbit;
-pub mod entity;
pub mod api;
+pub mod entity;
+pub mod orbit;
+pub mod planet;
const SCALE: f64 = 1.0;
-async fn handle_request(conn: TcpStream, remote_addr: SocketAddr, mgr: ClientManager,
- entities: Arc<RwLock<EntityHandler>>, physics_data: Arc<RwLock<PhysicsData>>) {
+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) => {
@@ 40,8 48,13 @@ async fn handle_request(conn: TcpStream, remote_addr: SocketAddr, mgr: ClientMan
}
}
-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>> {
+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 {
@@ 56,20 69,29 @@ async fn _handle_request(mut conn: TcpStream, remote_addr: SocketAddr, mgr: Clie
let ping_resp = 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
+ number: env!("STK_VERSION").to_string(), // Set by build.rs
protocol: PROTOCOL_VERSION,
channel: env!("STK_CHANNEL").to_string(),
- build: env!("STK_BUILD").to_string()
+ build: env!("STK_BUILD").to_string(),
},
players: CMGR.usernames.read().await.len() as u32,
description: env!("STK_SLP_DESCRIPTION").to_string(),
- }).unwrap();
+ })
+ .unwrap();
- let resp_str = format!("HTTP/1.0 200 OK\nAccess-Control-Allow-Origin: *\nContent-Length: {}\n\n{}", ping_resp.len(), ping_resp);
+ let resp_str = format!(
+ "HTTP/1.0 200 OK\nAccess-Control-Allow-Origin: *\nContent-Length: {}\n\n{}",
+ ping_resp.len(),
+ ping_resp
+ );
let http_resp = resp_str.as_bytes();
conn.write_all(http_resp).await?;
- info!("[{}] sent ping response (200 OK {} bytes)", remote_addr, ping_resp.len());
+ info!(
+ "[{}] sent ping response (200 OK {} bytes)",
+ remote_addr,
+ ping_resp.len()
+ );
return Ok(());
}
info!("[{}] incoming websocket connection", remote_addr);
@@ 91,16 113,28 @@ 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(), entities.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();
+ let e = e
+ .downcast::<async_tungstenite::tungstenite::error::Error>()
+ .unwrap();
if matches!(*e, async_tungstenite::tungstenite::Error::ConnectionClosed) {
info!("[{}] connection closed normally", remote_addr);
} else {
error!("[{}] error in client thread: {}", remote_addr, e);
}
- },
+ }
Err(e) => {
error!("[{}] error in client thread: {}", remote_addr, e);
}
@@ 125,8 159,14 @@ async fn _handle_request(mut conn: TcpStream, remote_addr: SocketAddr, mgr: Clie
}
};
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);
+ 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;
@@ 144,11 184,12 @@ lazy_static! {
handlers: Arc::new(RwLock::new(Default::default())),
usernames: Arc::new(RwLock::new(Default::default())),
};
- static ref DATA: Arc<RwLock<PhysicsData>> = Arc::new(RwLock::new(PhysicsData {
+ 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(),
@@ 156,7 197,8 @@ lazy_static! {
collider_set: ColliderSet::new(),
impulse_joint_set: ImpulseJointSet::new(),
multibody_joint_set: MultibodyJointSet::new(),
- ccd_solver: CCDSolver::new(), }));
+ ccd_solver: CCDSolver::new(),
+ }));
static ref ENTITIES: Arc<RwLock<EntityHandler>> = Arc::new(RwLock::new(EntityHandler::new()));
}
@@ 164,10 206,16 @@ lazy_static! {
async fn main() {
simple_logger::init_with_level(Level::Debug).expect("Unable to start logging service");
- info!("StarKingdoms server (v: {}, build {}) - initializing", env!("STK_VERSION"), env!("STK_BUILD"));
+ info!(
+ "StarKingdoms server (v: {}, build {}) - initializing",
+ env!("STK_VERSION"),
+ env!("STK_BUILD")
+ );
if std::env::var("STK_API_KEY").is_err() {
- error!("Unable to read the API key from STK_API_KEY. Ensure it is set, and has a valid value.");
+ error!(
+ "Unable to read the API key from STK_API_KEY. Ensure it is set, and has a valid value."
+ );
std::process::exit(1);
}
if std::env::var("STK_API_URL").is_err() {
@@ 197,8 245,13 @@ async fn main() {
};
while let Ok((stream, peer_addr)) = listener.accept().await {
- async_std::task::spawn(handle_request(stream, peer_addr, CMGR.clone(),
- ENTITIES.clone(), DATA.clone()));
+ async_std::task::spawn(handle_request(
+ stream,
+ peer_addr,
+ CMGR.clone(),
+ ENTITIES.clone(),
+ DATA.clone(),
+ ));
}
}
@@ 206,7 259,7 @@ async fn main() {
pub struct ServerPingResponse {
pub version: ServerPingResponseVersion,
pub players: u32,
- pub description: String
+ pub description: String,
}
#[derive(Serialize, Deserialize)]
@@ 215,5 268,5 @@ pub struct ServerPingResponseVersion {
pub number: String,
pub protocol: u32,
pub channel: String,
- pub build: String
+ pub build: String,
}
M server/src/manager.rs => server/src/manager.rs +117 -70
@@ 1,16 1,21 @@
-use std::collections::HashMap;
-use std::net::SocketAddr;
-use std::sync::Arc;
+use async_std::channel::Sender;
+use async_std::sync::RwLock;
use nalgebra::point;
use rapier2d_f64::na::Vector2;
-use rapier2d_f64::prelude::{IntegrationParameters, PhysicsPipeline, IslandManager, BroadPhase, NarrowPhase, ImpulseJointSet, MultibodyJointSet, CCDSolver, RigidBodySet, ColliderSet, RigidBodyHandle, ImpulseJointHandle, RigidBodyBuilder, ColliderBuilder, FixedJointBuilder, Real, MassProperties, Isometry};
-use async_std::sync::RwLock;
-use async_std::channel::Sender;
+use rapier2d_f64::prelude::{
+ BroadPhase, CCDSolver, ColliderBuilder, ColliderSet, FixedJointBuilder, ImpulseJointHandle,
+ ImpulseJointSet, IntegrationParameters, IslandManager, Isometry, MassProperties,
+ MultibodyJointSet, NarrowPhase, PhysicsPipeline, Real, RigidBodyBuilder, RigidBodyHandle,
+ RigidBodySet,
+};
use starkingdoms_protocol::api::APISavedPlayerData;
use starkingdoms_protocol::module::ModuleType;
+use std::collections::HashMap;
+use std::net::SocketAddr;
+use std::sync::Arc;
+use crate::entity::{get_entity_id, Entity, EntityHandler, EntityId};
use crate::SCALE;
-use crate::entity::{EntityId, EntityHandler, Entity, get_entity_id};
#[derive(Clone)]
pub struct ClientManager {
@@ 33,13 38,13 @@ impl Player {
APISavedPlayerData {}
}
- pub fn load_api_data(&mut self, _data: &APISavedPlayerData) {
-
- }
+ pub fn load_api_data(&mut self, _data: &APISavedPlayerData) {}
pub fn search_modules(&self, entities: &EntityHandler) -> Vec<AttachedModule> {
let mut modules = Vec::new();
for attachment in self.children.iter().flatten() {
- if let Entity::AttachedModule(child_module) = entities.entities.get(&attachment.child).unwrap() {
+ if let Entity::AttachedModule(child_module) =
+ entities.entities.get(&attachment.child).unwrap()
+ {
modules.append(&mut child_module.search_modules(entities));
}
}
@@ 70,20 75,29 @@ pub struct AttachedModule {
pub children: [Option<Attachment>; 4],
}
impl AttachedModule {
- pub fn attach(data: &mut PhysicsData, entities: &mut EntityHandler, parent: EntityId,
- player_id: EntityId, module: Module, attachment_slot: usize) {
+ pub fn attach(
+ data: &mut PhysicsData,
+ entities: &mut EntityHandler,
+ parent: EntityId,
+ player_id: EntityId,
+ module: Module,
+ attachment_slot: usize,
+ ) {
let mut entity_map = entities.entities.clone();
- let loose_id = entities.get_from_module(&module).expect("loose module does not exist");
- let loose_body = data.rigid_body_set.get(module.handle).expect("loose module does not exist");
- let parent_entity = entity_map.get_mut(&parent).expect("parent id does not exist");
+ let loose_id = entities
+ .get_from_module(&module)
+ .expect("loose module does not exist");
+ let loose_body = data
+ .rigid_body_set
+ .get(module.handle)
+ .expect("loose module does not exist");
+ let parent_entity = entity_map
+ .get_mut(&parent)
+ .expect("parent id does not exist");
let parent_handle = match parent_entity {
- Entity::Player(player) => {
- player.handle
- },
- Entity::AttachedModule(module) => {
- module.handle
- },
+ Entity::Player(player) => player.handle,
+ Entity::AttachedModule(module) => module.handle,
_ => {
panic!("unexpected parent");
}
@@ 99,12 113,18 @@ impl AttachedModule {
.rotation(loose_body.rotation().angle())
.build();
let attached_handle = data.rigid_body_set.insert(module_body);
- data.collider_set.insert_with_parent(module_collider, attached_handle, &mut data.rigid_body_set);
+ data.collider_set.insert_with_parent(
+ module_collider,
+ attached_handle,
+ &mut data.rigid_body_set,
+ );
let attach_joint = FixedJointBuilder::new()
.local_anchor1(point![0.0, 0.0])
.local_anchor2(point![0.0, 0.0])
.build();
- let attach_joint_handle = data.impulse_joint_set.insert(parent_handle, attached_handle, attach_joint, true);
+ let attach_joint_handle =
+ data.impulse_joint_set
+ .insert(parent_handle, attached_handle, attach_joint, true);
let attached_module = AttachedModule {
handle: attached_handle,
module_type: module.module_type,
@@ 118,40 138,48 @@ impl AttachedModule {
child: attached_id,
connection: attach_joint_handle,
});
- },
- Entity::AttachedModule(ref mut module) => {
+ }
+ Entity::AttachedModule(ref mut module) => {
module.children[attachment_slot] = Some(Attachment {
child: attached_id,
connection: attach_joint_handle,
});
- },
+ }
_ => {
panic!("unexpected parent");
}
};
entity_map.insert(attached_id, Entity::AttachedModule(attached_module));
// delete loose module
- data.rigid_body_set.remove(module.handle,
- &mut data.island_manager,
- &mut data.collider_set,
- &mut data.impulse_joint_set,
- &mut data.multibody_joint_set, true);
+ data.rigid_body_set.remove(
+ module.handle,
+ &mut data.island_manager,
+ &mut data.collider_set,
+ &mut data.impulse_joint_set,
+ &mut data.multibody_joint_set,
+ true,
+ );
entities.entities.remove(&loose_id);
}
- pub fn attach_new(data: &mut PhysicsData, entities: &mut EntityHandler, parent: EntityId,
- player_id: EntityId, module: ModuleTemplate, attachment_slot: usize, rotation: f64) {
+ pub fn attach_new(
+ data: &mut PhysicsData,
+ entities: &mut EntityHandler,
+ parent: EntityId,
+ player_id: EntityId,
+ module: ModuleTemplate,
+ attachment_slot: usize,
+ rotation: f64,
+ ) {
let mut entity_map = entities.entities.clone();
//let loose_id = entities.get_from_module(&module).expect("loose module does not exist");
//let loose_body = data.rigid_body_set.get(module.handle).expect("loose module does not exist");
- let parent_entity = entity_map.get_mut(&parent).expect("parent id does not exist");
+ let parent_entity = entity_map
+ .get_mut(&parent)
+ .expect("parent id does not exist");
let parent_handle = match parent_entity {
- Entity::Player(player) => {
- player.handle
- },
- Entity::AttachedModule(module) => {
- module.handle
- },
+ Entity::Player(player) => player.handle,
+ Entity::AttachedModule(module) => module.handle,
_ => {
panic!("unexpected parent");
}
@@ 165,17 193,23 @@ impl AttachedModule {
.rotation(module.heading)
.build();
let attached_handle = data.rigid_body_set.insert(module_body);
- data.collider_set.insert_with_parent(module_collider, attached_handle, &mut data.rigid_body_set);
+ data.collider_set.insert_with_parent(
+ module_collider,
+ attached_handle,
+ &mut data.rigid_body_set,
+ );
let anchor = point![
- -0. / SCALE * rotation.cos() +100. / SCALE * rotation.sin(),
- -0. / SCALE * rotation.sin() -100. / SCALE * rotation.cos()
+ -0. / SCALE * rotation.cos() + 100. / SCALE * rotation.sin(),
+ -0. / SCALE * rotation.sin() - 100. / SCALE * rotation.cos()
];
let attach_joint = FixedJointBuilder::new()
.local_anchor1(anchor)
.local_anchor2(point![0.0, 0.0 / SCALE])
.local_frame2(Isometry::rotation(rotation))
.build();
- let attach_joint_handle = data.impulse_joint_set.insert(parent_handle, attached_handle, attach_joint, true);
+ let attach_joint_handle =
+ data.impulse_joint_set
+ .insert(parent_handle, attached_handle, attach_joint, true);
let attached_module = AttachedModule {
handle: attached_handle,
module_type: module.module_type,
@@ 189,13 223,13 @@ impl AttachedModule {
child: attached_id,
connection: attach_joint_handle,
});
- },
- Entity::AttachedModule(ref mut module) => {
+ }
+ Entity::AttachedModule(ref mut module) => {
module.children[attachment_slot] = Some(Attachment {
child: attached_id,
connection: attach_joint_handle,
});
- },
+ }
_ => {
panic!("unexpected parent");
}
@@ 215,7 249,9 @@ impl AttachedModule {
pub fn search_modules(&self, entities: &EntityHandler) -> Vec<AttachedModule> {
let mut modules = Vec::new();
for attachment in self.children.iter().flatten() {
- if let Entity::AttachedModule(child_module) = entities.entities.get(&attachment.child).unwrap() {
+ if let Entity::AttachedModule(child_module) =
+ entities.entities.get(&attachment.child).unwrap()
+ {
modules.append(&mut child_module.search_modules(entities));
}
}
@@ 234,19 270,20 @@ pub struct PlayerInput {
pub up: bool,
pub left: bool,
pub right: bool,
- pub down: bool
+ pub down: bool,
}
#[derive(Clone)]
pub struct ClientHandler {
- pub tx: Sender<ClientHandlerMessage>
+ pub tx: Sender<ClientHandlerMessage>,
}
#[derive(Clone, Default)]
pub struct PhysicsData {
pub gravity: Vector2<f64>,
pub integration_parameters: IntegrationParameters,
- pub island_manager: IslandManager, pub broad_phase: BroadPhase,
+ pub island_manager: IslandManager,
+ pub broad_phase: BroadPhase,
pub narrow_phase: NarrowPhase,
pub rigid_body_set: RigidBodySet,
pub collider_set: ColliderSet,
@@ 256,28 293,38 @@ pub struct PhysicsData {
}
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,
- &(),
- &()
- );
+ 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,
+ &(),
+ &(),
+ );
}
}
#[derive(Debug, Clone)]
pub enum ClientHandlerMessage {
Tick,
- ChatMessage { from: String, message: String },
- PlayersUpdate { players: Vec<starkingdoms_protocol::player::Player> },
- PlanetData { planets: Vec<starkingdoms_protocol::planet::Planet> },
- ModulesUpdate { modules: Vec<starkingdoms_protocol::module::Module> },
+ ChatMessage {
+ from: String,
+ message: String,
+ },
+ PlayersUpdate {
+ players: Vec<starkingdoms_protocol::player::Player>,
+ },
+ PlanetData {
+ planets: Vec<starkingdoms_protocol::planet::Planet>,
+ },
+ ModulesUpdate {
+ modules: Vec<starkingdoms_protocol::module::Module>,
+ },
}
M server/src/orbit/constants.rs => server/src/orbit/constants.rs +2 -2
@@ 22,6 22,6 @@ pub const MOON_RADIUS: f64 = MOON_RADIUS_RL * GAME_SCALE_DISTANCE * MOON_RADIUS_
pub const MOON_MASS_RL: f64 = 73476730900000000000000.0;
pub const MOON_MASS: f64 = MOON_MASS_RL * GAME_SCALE_MASS * MOON_MASS_BIAS;
pub const MOON_PERIAPSIS: f64 = 363228900.0 * GAME_SCALE_DISTANCE * MOON_PERIAPSIS_BIAS;
-pub const MOON_APOAPSIS: f64 = 405400000.0 * GAME_SCALE_DISTANCE * MOON_APOAPSIS_BIAS;
+pub const MOON_APOAPSIS: f64 = 405400000.0 * GAME_SCALE_DISTANCE * MOON_APOAPSIS_BIAS;
pub const MOON_ORBIT_TIME_RL: f64 = 2332800.0;
-pub const MOON_ORBIT_TIME: f64 = MOON_ORBIT_TIME_RL * GAME_SCALE_TIME * MOON_ORBIT_TIME_BIAS;>
\ No newline at end of file
+pub const MOON_ORBIT_TIME: f64 = MOON_ORBIT_TIME_RL * GAME_SCALE_TIME * MOON_ORBIT_TIME_BIAS;
M server/src/orbit/kepler.rs => server/src/orbit/kepler.rs +1 -1
@@ 4,4 4,4 @@
/// e is the eccentricity of the orbit (0 = perfect circle, and up to 1 is increasingly elliptical)
pub fn kepler_equation(eccentric_anomaly: f64, mean_anomaly: f64, eccentricity: f64) -> f64 {
mean_anomaly - eccentric_anomaly + eccentricity * eccentric_anomaly.sin()
-}>
\ No newline at end of file
+}
M server/src/orbit/mod.rs => server/src/orbit/mod.rs +3 -3
@@ 1,6 1,6 @@
pub mod constants;
+pub mod kepler;
+pub mod newtonian;
#[allow(clippy::module_inception)]
pub mod orbit;
-pub mod newtonian;
-pub mod kepler;
-pub mod vis_viva;>
\ No newline at end of file
+pub mod vis_viva;
M server/src/orbit/newtonian.rs => server/src/orbit/newtonian.rs +8 -3
@@ 3,7 3,11 @@ use crate::orbit::kepler::kepler_equation;
pub const NEWTONIAN_STEP_SIZE: f64 = 0.0001;
pub const NEWTONIAN_ACCEPTABLE_ERROR: f64 = 0.00000001;
-pub fn solve_kepler_with_newtonian(mean_anomaly: f64, eccentricity: f64, max_iterations: u64) -> f64 {
+pub fn solve_kepler_with_newtonian(
+ mean_anomaly: f64,
+ eccentricity: f64,
+ max_iterations: u64,
+) -> f64 {
let mut guess = mean_anomaly;
for _ in 0..max_iterations {
@@ 15,10 19,11 @@ pub fn solve_kepler_with_newtonian(mean_anomaly: f64, eccentricity: f64, max_ite
}
// otherwise, update guess
- let slope = (kepler_equation(guess + NEWTONIAN_STEP_SIZE, mean_anomaly, eccentricity) - y) / NEWTONIAN_STEP_SIZE;
+ let slope = (kepler_equation(guess + NEWTONIAN_STEP_SIZE, mean_anomaly, eccentricity) - y)
+ / NEWTONIAN_STEP_SIZE;
let step = y / slope;
guess -= step;
}
guess
-}>
\ No newline at end of file
+}
M server/src/orbit/orbit.rs => server/src/orbit/orbit.rs +23 -6
@@ 1,15 1,28 @@
// Mostly stolen from SebLague's plane game
// thanks
-use nalgebra::{vector, Vector2};
use crate::orbit::newtonian::solve_kepler_with_newtonian;
+use nalgebra::{vector, Vector2};
#[allow(clippy::too_many_arguments)]
-pub fn calculate_vector_of_orbit(periapsis: f64, apoapsis: f64, t: f64, current_x: f64, current_y: f64, orbiting_x: f64, orbiting_y: f64, mass: f64, step: f64) -> Vector2<f64> {
+pub fn calculate_vector_of_orbit(
+ periapsis: f64,
+ apoapsis: f64,
+ t: f64,
+ current_x: f64,
+ current_y: f64,
+ orbiting_x: f64,
+ orbiting_y: f64,
+ mass: f64,
+ step: f64,
+) -> Vector2<f64> {
let semi_major_length = (apoapsis + periapsis) / 2.0;
let _linear_eccentricity = semi_major_length - periapsis; // distance between center and focus
- let target = calculate_world_position_of_orbit(calculate_point_on_orbit(periapsis, apoapsis, t), vector![orbiting_x, orbiting_y]);
+ let target = calculate_world_position_of_orbit(
+ calculate_point_on_orbit(periapsis, apoapsis, t),
+ vector![orbiting_x, orbiting_y],
+ );
let target_x = target[0];
let target_y = target[1];
@@ 32,7 45,8 @@ pub fn calculate_point_on_orbit(periapsis: f64, apoapsis: f64, t: f64) -> Vector
let semi_major_length = (apoapsis + periapsis) / 2.0;
let linear_eccentricity = semi_major_length - periapsis; // distance between center and focus
let eccentricity = linear_eccentricity / semi_major_length; // 0: circle. 1: parabola. in between: ellipse
- let semi_minor_length = (semi_major_length * semi_major_length - linear_eccentricity * linear_eccentricity).sqrt();
+ let semi_minor_length =
+ (semi_major_length * semi_major_length - linear_eccentricity * linear_eccentricity).sqrt();
let mean_anomaly = t * std::f64::consts::PI * 2.0;
let eccentric_anomaly = solve_kepler_with_newtonian(mean_anomaly, eccentricity, 100);
@@ 44,8 58,11 @@ pub fn calculate_point_on_orbit(periapsis: f64, apoapsis: f64, t: f64) -> Vector
vector![point_x, point_y]
}
-pub fn calculate_world_position_of_orbit(point: Vector2<f64>, orbiting_on: Vector2<f64>) -> Vector2<f64> {
+pub fn calculate_world_position_of_orbit(
+ point: Vector2<f64>,
+ orbiting_on: Vector2<f64>,
+) -> Vector2<f64> {
// i have no idea if this is actually right or not
// we'll find out
vector![point[0] + orbiting_on[0], point[1] + orbiting_on[1]]
-}>
\ No newline at end of file
+}
M server/src/orbit/vis_viva.rs => server/src/orbit/vis_viva.rs +7 -2
@@ 1,3 1,8 @@
-pub fn vis_viva(distance_between_centers: f64, semi_major: f64, g: f64, mass_of_bigger: f64) -> f64 {
+pub fn vis_viva(
+ distance_between_centers: f64,
+ semi_major: f64,
+ g: f64,
+ mass_of_bigger: f64,
+) -> f64 {
(g * mass_of_bigger * (2.0 / distance_between_centers - 1.0 / semi_major)).sqrt()
-}>
\ No newline at end of file
+}
M server/src/planet.rs => server/src/planet.rs +51 -31
@@ 1,12 1,16 @@
-use std::collections::HashMap;
-use nalgebra::{Vector2, vector};
-use rapier2d_f64::prelude::{RigidBodyHandle, RigidBodySet, ColliderBuilder, RigidBodyBuilder, ColliderSet};
+use nalgebra::{vector, Vector2};
+use rapier2d_f64::prelude::{
+ ColliderBuilder, ColliderSet, RigidBodyBuilder, RigidBodyHandle, RigidBodySet,
+};
use starkingdoms_protocol::planet::PlanetType;
+use std::collections::HashMap;
-use crate::entity::{Entities, get_entity_id, Entity, EntityId};
-use crate::{SCALE, manager::ClientHandlerMessage};
-use crate::orbit::constants::{EARTH_MASS, EARTH_RADIUS, MOON_APOAPSIS, MOON_MASS, MOON_PERIAPSIS, MOON_RADIUS};
+use crate::entity::{get_entity_id, Entities, Entity, EntityId};
+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};
+use crate::{manager::ClientHandlerMessage, SCALE};
//const GRAVITY: f64 = 0.001;
pub const GRAVITY: f64 = 12.6674;
@@ 17,14 21,17 @@ pub struct Planet {
pub body_handle: RigidBodyHandle,
pub position: (f64, f64),
pub radius: f64,
- pub mass: f64
+ pub mass: f64,
}
impl Planet {
pub fn gravity(&self, position: (f64, f64), mass: f64) -> (f64, f64) {
- let distance = ((position.0 - self.position.0).powi(2) + (position.1 - self.position.1).powi(2)).sqrt();
+ let distance = ((position.0 - self.position.0).powi(2)
+ + (position.1 - self.position.1).powi(2))
+ .sqrt();
let force = GRAVITY * ((self.mass * mass) / (distance * distance));
- let mut direction = Vector2::new(self.position.0 - position.0, self.position.1 - position.1);
+ let mut direction =
+ Vector2::new(self.position.0 - position.0, self.position.1 - position.1);
direction.set_magnitude(force);
(direction.x, direction.y)
}
@@ 44,12 51,16 @@ impl Planets {
self.planets.get_mut(planet_id)
}
- 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();
+ 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::kinematic_position_based()
.translation(vector![position.0 / SCALE, position.1 / SCALE])
.dominance_group(127)
@@ 59,17 70,23 @@ impl Planets {
collider_set.insert_with_parent(collider, body_handle, rigid_body_set);
let entity_id = get_entity_id();
- (entity_id, Entity::Planet(Planet {
- planet_type,
- body_handle,
- position,
- radius,
- mass,
- }))
+ (
+ entity_id,
+ Entity::Planet(Planet {
+ planet_type,
+ body_handle,
+ position,
+ radius,
+ mass,
+ }),
+ )
}
- pub async fn create_planets(rigid_body_set: &mut RigidBodySet, collider_set: &mut ColliderSet,
- entities: &mut Entities) -> Vec<EntityId> {
+ pub async fn create_planets(
+ 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",
@@ 79,13 96,17 @@ impl Planets {
(100.0, 100.0),
rigid_body_set,
collider_set,
- ).await;
+ )
+ .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]);
+ 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.];
}
@@ 97,8 118,9 @@ impl Planets {
MOON_RADIUS,
(moon_start_point[0], moon_start_point[1]),
rigid_body_set,
- collider_set
- ).await;
+ collider_set,
+ )
+ .await;
entities.insert(moon_id, moon);
planet_ids.push(moon_id);
planet_ids
@@ 118,9 140,7 @@ impl Planets {
});
}
- ClientHandlerMessage::PlanetData {
- planets
- }
+ ClientHandlerMessage::PlanetData { planets }
}
pub fn gravity(&self, position: (f64, f64), mass: f64) -> (f64, f64) {
M server/src/timer.rs => server/src/timer.rs +125 -58
@@ 1,22 1,35 @@
-use std::{time::Duration, sync::Arc, f64::consts::PI};
-use log::{warn, info};
-use nalgebra::{vector, point};
-use rand::Rng;
-use rapier2d_f64::prelude::{PhysicsPipeline, ColliderBuilder, RigidBodyBuilder, MassProperties, RigidBodyHandle};
-use async_std::sync::RwLock;
-use async_std::task::sleep;
-use starkingdoms_protocol::{player::Player, planet::PlanetType, module::ModuleType};
-use crate::{manager::{ClientHandlerMessage, ClientManager, PhysicsData, Module}, SCALE, planet::{Planets, Planet}, entity::{get_entity_id, Entity}};
use crate::entity::EntityHandler;
-use crate::orbit::constants::{GAME_ORBITS_ENABLED, MOON_APOAPSIS, MOON_ORBIT_TIME, MOON_PERIAPSIS};
+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>>) {
+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;
@@ 29,7 42,12 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
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;
+ _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;
@@ 55,10 73,19 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
// 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();
+ 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);
+ moon.position = (
+ moon_body.translation()[0] / SCALE,
+ moon_body.translation()[1] / SCALE,
+ );
}
physics_data.tick(&mut pipeline);
@@ 66,7 93,8 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
let mut protocol_players = vec![];
{
- if module_timer > MODULE_SPAWN && entities.read().await.get_module_count() < MODULE_MAX {
+ 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();
@@ 81,10 109,17 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
rng.gen::<f64>() * PI * 2.
};
let module_body = RigidBodyBuilder::dynamic()
- .translation(vector![angle.cos() * 2050. / SCALE, angle.sin() * 2050.0/SCALE])
+ .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);
+ 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;
@@ 94,7 129,11 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
module_type: ModuleType::Cargo,
lifetime: 0.0,
};
- entities.write().await.entities.insert(get_entity_id(), Entity::Module(module));
+ 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() {
@@ 102,11 141,14 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
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());
+ 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.;
+ p_module.lifetime += 5. / 1000.;
}
if module.lifetime > 80. {
let mut rigid_body_set = physics_data.rigid_body_set.clone();
@@ 114,8 156,14 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
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);
+ 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;
@@ 133,7 181,10 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
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());
+ 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;
@@ 182,35 233,26 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
];
let scale = SCALE;
let top_left_point = point![
- -25. / scale * rotation.cos() +25. / scale * rotation.sin(),
- -25. / scale * rotation.sin() -25. / scale * rotation.cos()
+ -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()
+ 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()
+ -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()
+ 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);
-
+ 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();
@@ 239,7 281,13 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
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 {
+ match client_thread
+ .tx
+ .send(ClientHandlerMessage::PlayersUpdate {
+ players: protocol_players.clone(),
+ })
+ .await
+ {
Ok(_) => (),
Err(e) => {
warn!("unable to send position packet: {}", e);
@@ 247,20 295,32 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
};
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());
+ 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());
+ info!(
+ "{:?}",
+ physics_data
+ .rigid_body_set
+ .get(module.handle)
+ .unwrap()
+ .translation()
+ );
}
});
- let protocol_modules: Vec<starkingdoms_protocol::module::Module> = modules.iter()
+ 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 {
@@ 270,8 330,15 @@ pub async fn timer_main(mgr: ClientManager, physics_data_orig: Arc<RwLock<Physic
y: body.translation().y * SCALE,
special_fields: Default::default(),
};
- }).collect();
- match client_thread.tx.send(ClientHandlerMessage::ModulesUpdate { modules: protocol_modules.clone() }).await {
+ })
+ .collect();
+ match client_thread
+ .tx
+ .send(ClientHandlerMessage::ModulesUpdate {
+ modules: protocol_modules.clone(),
+ })
+ .await
+ {
Ok(_) => (),
Err(e) => {
warn!("unable to send module position packet: {}", e);