From d5530a1449e84cfc65f3a7af5ec11e33533d36d6 Mon Sep 17 00:00:00 2001 From: Zoey Date: Tue, 23 Apr 2024 01:14:17 -0700 Subject: [PATCH] add /stop command --- src/command.rs | 6 ++++++ src/main.rs | 2 +- src/server.rs | 45 +++++++++++++++++++++++++++++++------------ src/server/network.rs | 4 ++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/command.rs b/src/command.rs index 109070b..477e9f6 100644 --- a/src/command.rs +++ b/src/command.rs @@ -4,6 +4,7 @@ const CMD_ME: &str = "me"; const CMD_SAY: &str = "say"; const CMD_SET_PERM: &str = "setperm"; const CMD_KICK: &str = "kick"; +const CMD_STOP: &str = "stop"; /// enum for possible commands #[derive(Debug, Clone)] @@ -19,10 +20,13 @@ pub enum Command<'m> { player_username: &'m str, permissions: PlayerType, }, + /// kicks a player from the server Kick { username: &'m str, message: Option<&'m str>, }, + /// command to stop the server + Stop, } impl<'m> Command<'m> { @@ -45,6 +49,7 @@ impl<'m> Command<'m> { let message = (!message.is_empty()).then_some(message); Self::Kick { username, message } } + CMD_STOP => Self::Stop, _ => return Err(format!("Unknown command: {command_name}")), }) } @@ -53,6 +58,7 @@ impl<'m> Command<'m> { pub fn perms_required(&self) -> PlayerType { match self { Self::Me { .. } => PlayerType::Normal, + Self::Stop => PlayerType::Operator, _ => PlayerType::Moderator, } } diff --git a/src/main.rs b/src/main.rs index a37349f..64222ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ async fn main() -> std::io::Result<()> { println!("starting server with config: {config:#?}"); - let mut server = Server::new(config).await?; + let server = Server::new(config).await?; server.run().await?; diff --git a/src/server.rs b/src/server.rs index 90043ca..08145d4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -10,6 +10,7 @@ use crate::{ block::{BlockType, BLOCK_INFO}, BlockUpdate, Level, }, + packet::server::ServerPacket, player::Player, util::neighbors_minus_up, CONFIG_FILE, @@ -41,6 +42,8 @@ pub struct ServerData { pub config: ServerConfig, /// whether the server config needs to be resaved or not pub config_needs_saving: bool, + /// whether the server should be stopped + pub stop: bool, } impl Server { @@ -70,27 +73,34 @@ impl Server { free_player_ids: Vec::new(), config, config_needs_saving: true, + stop: false, })), listener, }) } /// starts the server - pub async fn run(&mut self) -> std::io::Result<()> { + pub async fn run(self) -> std::io::Result<()> { let data = self.data.clone(); tokio::spawn(async move { - handle_ticks(data).await; + loop { + let (stream, addr) = self.listener.accept().await.unwrap(); + println!("connection from {addr}"); + let data = data.clone(); + tokio::spawn(async move { + network::handle_stream(stream, addr, data) + .await + .expect("failed to handle client stream"); + }); + } }); - loop { - let (stream, addr) = self.listener.accept().await?; - println!("connection from {addr}"); - let data = self.data.clone(); - tokio::spawn(async move { - network::handle_stream(stream, addr, data) - .await - .expect("failed to handle client stream"); - }); - } + handle_ticks(self.data).await; + tokio::time::sleep(std::time::Duration::from_millis(1)).await; + + // TODO: cancel pending tasks/send out "Server is stopping" messages *here* instead of elsewhere + // rn the message isn't guaranteed to actually go out........ + + Ok(()) } } @@ -111,6 +121,17 @@ async fn handle_ticks(data: Arc>) { .expect("failed to save config file"); data.config_needs_saving = false; } + + if data.stop { + let packet = ServerPacket::DisconnectPlayer { + disconnect_reason: "Server is stopping!".to_string(), + }; + for player in &mut data.players { + player.packets_to_send.push(packet.clone()); + } + // TODO: save level before exiting + break; + } } current_tick = current_tick.wrapping_add(1); diff --git a/src/server/network.rs b/src/server/network.rs index 92ff546..2c551e1 100644 --- a/src/server/network.rs +++ b/src/server/network.rs @@ -467,6 +467,10 @@ async fn handle_stream_inner( ); } } + + Command::Stop => { + data.stop = true; + } } } Err(msg) => {