~muirrum/hakkardrs

21841e9b80300ebd0386b43cf237e1705fe6cad5 — Cara Salter 5 months ago 63f4a72
Add quit logic

The `quit` verb is handled as a special case outside of the main verb
code because it needs to be able to drop the player and close the
connection, something that cannot be done within the standard verb
functions.
1 files changed, 18 insertions(+), 6 deletions(-)

M src/game.rs
M src/game.rs => src/game.rs +18 -6
@@ 13,7 13,7 @@ pub struct Game {
    players: std::collections::HashMap<User, Player>,

    // Every active connection to the server -- may not have a player
    logins: std::collections::HashMap<SocketAddr, Login>,
    pub logins: std::collections::HashMap<SocketAddr, Login>,
}

// Custom game errors and results


@@ 41,7 41,7 @@ impl From<io::Error> for GameErr {
}

// Thin wrapper around OwnedWriteHalf
pub struct Wire(tokio::net::tcp::OwnedWriteHalf);
pub struct Wire(pub tokio::net::tcp::OwnedWriteHalf);
impl Wire {
    pub async fn send(&mut self, mut s: String) -> tokio::io::Result<()> {
        use tokio::io::AsyncWriteExt;


@@ 69,14 69,14 @@ pub async fn game_thread(mut msgs: mpsc::UnboundedReceiver<(SocketAddr, Msg)>) {
}

impl Game {
    async fn handle_msg(&mut self, addr: SocketAddr, msg: Msg) -> GameRes<()> {
    async fn handle_msg(&mut self, addr: SocketAddr, msg: Msg) -> GameRes<bool> {
        match msg {
            Msg::Connect(write) => {
                println!("Connecting new client: {}", addr);
                let mut wir = Wire(write);
                send!(wir, "Welcome! Username?");
                self.logins.insert(addr, Login::start(wir));
                Ok(())
                Ok(false)
            }
            Msg::Command(txt) => {
                use GameErr::DeadTalk;


@@ 86,6 86,14 @@ impl Game {

                let res = if let Login::Complete { ref user, .. } = login {
                    if let Some(mut plr) = self.players.remove(user) {
                        // Quit is a special case because it results in the player being removed
                        // from the game entirely.
                        if txt.clone().trim() == "quit" {
                            plr.send("Bye for now! Come back soon!".to_string()).await?;
                            plr.file.write()?;
                            drop(plr);
                            return Ok(true)
                        }
                        let res = self.player_cmd(&mut plr, txt).await;
                        self.players.insert(user.clone(), plr);
                        res


@@ 98,7 106,11 @@ impl Game {
                    res
                };
                self.logins.insert(addr, login);
                res
                if let Err(e) = res {
                    return Err(e);
                } else {
                    return Ok(false);
                }
            }
        }
    }


@@ 142,7 154,7 @@ impl Game {
}

// Login state machine
enum Login {
pub enum Login {
    LoggedOut { wir: Wire },

    EnterPassword { wir: Wire, file: PlayerFile },