diff --git a/README.md b/README.md index 173df59..ce101ad 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,7 @@ response !Invalid method ``` On a response `!` means it's an error. + +# Methods +### `set_cloak` +- `cloak` -> `string` diff --git a/src/methods/mod.rs b/src/methods/mod.rs index d63cccc..927c12d 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,5 +1,6 @@ mod player; mod set_cloak; +mod set_hat; use std::{ collections::HashMap, @@ -13,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ parser::ParamMap, - response::{Response, Result}, + response::{PlayerResponse, Response, Result}, }; #[derive(Debug, Deserialize, Serialize)] @@ -55,17 +56,14 @@ impl Session { .json() .map_err(|_| crate::response::Error::InvalidSession)?; - let uuid = local_player.id.clone(); - let session = Self { session_token, database, local_player, }; - // Capture the player - match player::player(&session, uuid) { + match player::login(&session) { Ok(player) => Ok((session, player)), Err(crate::response::Error::DatabaseError) => { let player = create(&session)?; @@ -81,8 +79,23 @@ impl Session { "set_cloak" => set_cloak::set_cloak(self, params.parse_param("cloak")?), + "set_hat" => set_hat::set_hat(self, params.parse_param("hat")?), + "player" => player::player(self, params.parse_param("uuid")?), + "players" => { + let mut players: Vec = Vec::new(); + for uuid in params.parse_param::("uuids")?.split("$") { + match player::player(self, uuid.to_string())? { + Response::Player(p) => { + players.push(p); + } + _ => {} + } + } + Ok(Response::Players(players)) + } + _ => Err(crate::response::Error::InvalidRequest), } } diff --git a/src/methods/player.rs b/src/methods/player.rs index 07ba971..0f0660f 100644 --- a/src/methods/player.rs +++ b/src/methods/player.rs @@ -19,37 +19,18 @@ pub fn player(session: &Session, uuid: String) -> Result { match cursor.next() { Some(Ok(player)) => { // Player exists, deserialize and return their data - Ok(Response::Player { + Ok(Response::Player(crate::response::PlayerResponse::Player { cloak: player.cloak, uuid, cloaks: player.cloaks, hats: player.hats, hat: player.hat, - }) + })) } - // No document found or deserialization error - _ => { - let player = Player { - uuid: uuid.clone(), - cloaks: Vec::new(), - cloak: "".to_string(), - hats: Vec::new(), - hat: String::new(), - }; - - // Insert the new player - session.database.players.insert_one(player.clone()).run()?; - - // Return the newly created player's data - Ok(Response::Player { - cloak: player.cloak, - uuid, - cloaks: player.cloaks, - hats: player.hats, - hat: player.hat, - }) - } + _ => Ok(crate::response::Response::Player( + crate::response::PlayerResponse::NonSaturnPlayer, + )), } } @@ -66,11 +47,59 @@ pub fn create(session: &Session) -> Result { session.database.players.insert_one(player.clone()).run()?; - Ok(Response::Player { + Ok(Response::Player(crate::response::PlayerResponse::Player { cloak: player.cloak, uuid, cloaks: player.cloaks, hats: player.hats, hat: player.hat, - }) + })) +} + +pub fn login(session: &Session) -> Result { + let uuid = session.local_player.id.clone(); + + // Try to find the player with the given UUID + let mut cursor = session + .database + .players + .find(doc! { "uuid": uuid.clone() }) + .run()?; + + // Check if there's a document in the cursor + match cursor.next() { + Some(Ok(player)) => { + // Player exists, deserialize and return their data + Ok(Response::Player(crate::response::PlayerResponse::Player { + cloak: player.cloak, + uuid, + cloaks: player.cloaks, + hats: player.hats, + hat: player.hat, + })) + } + + // No document found or deserialization error + _ => { + let player = Player { + uuid: uuid.clone(), + cloaks: Vec::new(), + cloak: "".to_string(), + hats: Vec::new(), + hat: String::new(), + }; + + // Insert the new player + session.database.players.insert_one(player.clone()).run()?; + + // Return the newly created player's data + Ok(Response::Player(crate::response::PlayerResponse::Player { + cloak: player.cloak, + uuid, + cloaks: player.cloaks, + hats: player.hats, + hat: player.hat, + })) + } + } } diff --git a/src/methods/set_cloak.rs b/src/methods/set_cloak.rs index 43f19b9..f02be9c 100644 --- a/src/methods/set_cloak.rs +++ b/src/methods/set_cloak.rs @@ -1,24 +1,32 @@ use mongodb::bson::doc; -use crate::response::{Response, Result}; +use crate::response::{Error, Response, Result}; -use super::Session; +use super::{player, Session}; pub fn set_cloak(session: &Session, cloak: String) -> Result { - session - .database - .players - .update_one( - doc! { - "uuid": session.local_player.id.clone(), - }, - doc! { - "$set": { - "cloak": cloak, - }, - }, - ) - .run()?; - - Ok(Response::Success) + match player::player(session, session.local_player.id.clone())? { + Response::Player(crate::response::PlayerResponse::Player { cloaks, .. }) => { + if cloaks.contains(&cloak) || cloak.is_empty() { + session + .database + .players + .update_one( + doc! { + "uuid": session.local_player.id.clone(), + }, + doc! { + "$set": { + "cloak": cloak, + }, + }, + ) + .run()?; + Ok(Response::Success) + } else { + Err(Error::SomethingWentWrong) + } + } + _ => Err(Error::SomethingWentWrong), + } } diff --git a/src/methods/set_hat.rs b/src/methods/set_hat.rs new file mode 100644 index 0000000..b880adc --- /dev/null +++ b/src/methods/set_hat.rs @@ -0,0 +1,33 @@ +use mongodb::bson::doc; + +use crate::response::{Error, Response, Result}; + +use super::{player, Session}; + +pub fn set_hat(session: &Session, hat: String) -> Result { + match player::player(session, session.local_player.id.clone())? { + Response::Player(crate::response::PlayerResponse::Player { hats, .. }) => { + if hats.contains(&hat) || hat.is_empty() { + session + .database + .players + .update_one( + doc! { + "uuid": session.local_player.id.clone(), + }, + doc! { + "$set": { + "hat": hat, + }, + }, + ) + .run()?; + + Ok(Response::Success) + } else { + Err(Error::SomethingWentWrong) + } + } + _ => Err(Error::SomethingWentWrong), + } +} diff --git a/src/response.rs b/src/response.rs index c2c4a60..422f416 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,9 +1,7 @@ pub type Result = std::result::Result; #[derive(Debug, Clone)] -pub enum Response { - Pong, - Success, +pub enum PlayerResponse { Player { uuid: String, cloaks: Vec, @@ -11,14 +9,12 @@ pub enum Response { hats: Vec, hat: String, }, + NonSaturnPlayer, } - -impl std::fmt::Display for Response { +impl std::fmt::Display for PlayerResponse { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Response::Pong => write!(f, "Pong"), - Response::Success => write!(f, "Success"), - Response::Player { + PlayerResponse::Player { uuid, cloaks, cloak, @@ -26,10 +22,40 @@ impl std::fmt::Display for Response { hat, } => write!( f, - "@cloak={cloak}@uuid={uuid}@cloaks={}@hats={}@hat={hat}", + "player@cloak={cloak}@uuid={uuid}@cloaks={}@hats={}@hat={hat}@saturn=true", cloaks.join("$"), hats.join("$"), ), + PlayerResponse::NonSaturnPlayer => write!(f, "@saturn=false"), + } + } +} + +#[derive(Debug, Clone)] +pub enum Response { + Pong, + Success, + Player(PlayerResponse), + Players(Vec), +} + +impl std::fmt::Display for Response { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Response::Pong => write!(f, "Pong"), + Response::Success => write!(f, "Success"), + Response::Player(player) => write!(f, "{player}"), + Response::Players(players) => { + write!( + f, + "{}", + players + .iter() + .map(|p| format!("{p}")) + .collect::>() + .join("\n") + ) + } } } } @@ -43,6 +69,7 @@ pub enum Error { InvalidSession, InvalidHandshake, DatabaseError, + SomethingWentWrong, } impl std::fmt::Display for Error { @@ -55,6 +82,7 @@ impl std::fmt::Display for Error { Error::InvalidSession => write!(f, "Invalid session"), Error::InvalidHandshake => write!(f, "Invalid handshake"), Error::DatabaseError => write!(f, "Database error"), + Error::SomethingWentWrong => write!(f, "Something went wrong"), } } }