mirror of
https://github.com/zyllian/classics.git
synced 2025-01-18 11:47:14 -08:00
add /stop command
This commit is contained in:
parent
e49e35fe82
commit
d5530a1449
4 changed files with 44 additions and 13 deletions
|
@ -4,6 +4,7 @@ const CMD_ME: &str = "me";
|
||||||
const CMD_SAY: &str = "say";
|
const CMD_SAY: &str = "say";
|
||||||
const CMD_SET_PERM: &str = "setperm";
|
const CMD_SET_PERM: &str = "setperm";
|
||||||
const CMD_KICK: &str = "kick";
|
const CMD_KICK: &str = "kick";
|
||||||
|
const CMD_STOP: &str = "stop";
|
||||||
|
|
||||||
/// enum for possible commands
|
/// enum for possible commands
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -19,10 +20,13 @@ pub enum Command<'m> {
|
||||||
player_username: &'m str,
|
player_username: &'m str,
|
||||||
permissions: PlayerType,
|
permissions: PlayerType,
|
||||||
},
|
},
|
||||||
|
/// kicks a player from the server
|
||||||
Kick {
|
Kick {
|
||||||
username: &'m str,
|
username: &'m str,
|
||||||
message: Option<&'m str>,
|
message: Option<&'m str>,
|
||||||
},
|
},
|
||||||
|
/// command to stop the server
|
||||||
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'m> Command<'m> {
|
impl<'m> Command<'m> {
|
||||||
|
@ -45,6 +49,7 @@ impl<'m> Command<'m> {
|
||||||
let message = (!message.is_empty()).then_some(message);
|
let message = (!message.is_empty()).then_some(message);
|
||||||
Self::Kick { username, message }
|
Self::Kick { username, message }
|
||||||
}
|
}
|
||||||
|
CMD_STOP => Self::Stop,
|
||||||
_ => return Err(format!("Unknown command: {command_name}")),
|
_ => return Err(format!("Unknown command: {command_name}")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -53,6 +58,7 @@ impl<'m> Command<'m> {
|
||||||
pub fn perms_required(&self) -> PlayerType {
|
pub fn perms_required(&self) -> PlayerType {
|
||||||
match self {
|
match self {
|
||||||
Self::Me { .. } => PlayerType::Normal,
|
Self::Me { .. } => PlayerType::Normal,
|
||||||
|
Self::Stop => PlayerType::Operator,
|
||||||
_ => PlayerType::Moderator,
|
_ => PlayerType::Moderator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ async fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
println!("starting server with config: {config:#?}");
|
println!("starting server with config: {config:#?}");
|
||||||
|
|
||||||
let mut server = Server::new(config).await?;
|
let server = Server::new(config).await?;
|
||||||
|
|
||||||
server.run().await?;
|
server.run().await?;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
||||||
block::{BlockType, BLOCK_INFO},
|
block::{BlockType, BLOCK_INFO},
|
||||||
BlockUpdate, Level,
|
BlockUpdate, Level,
|
||||||
},
|
},
|
||||||
|
packet::server::ServerPacket,
|
||||||
player::Player,
|
player::Player,
|
||||||
util::neighbors_minus_up,
|
util::neighbors_minus_up,
|
||||||
CONFIG_FILE,
|
CONFIG_FILE,
|
||||||
|
@ -41,6 +42,8 @@ pub struct ServerData {
|
||||||
pub config: ServerConfig,
|
pub config: ServerConfig,
|
||||||
/// whether the server config needs to be resaved or not
|
/// whether the server config needs to be resaved or not
|
||||||
pub config_needs_saving: bool,
|
pub config_needs_saving: bool,
|
||||||
|
/// whether the server should be stopped
|
||||||
|
pub stop: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
|
@ -70,27 +73,34 @@ impl Server {
|
||||||
free_player_ids: Vec::new(),
|
free_player_ids: Vec::new(),
|
||||||
config,
|
config,
|
||||||
config_needs_saving: true,
|
config_needs_saving: true,
|
||||||
|
stop: false,
|
||||||
})),
|
})),
|
||||||
listener,
|
listener,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// starts the server
|
/// 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();
|
let data = self.data.clone();
|
||||||
tokio::spawn(async move {
|
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 {
|
handle_ticks(self.data).await;
|
||||||
let (stream, addr) = self.listener.accept().await?;
|
tokio::time::sleep(std::time::Duration::from_millis(1)).await;
|
||||||
println!("connection from {addr}");
|
|
||||||
let data = self.data.clone();
|
// TODO: cancel pending tasks/send out "Server is stopping" messages *here* instead of elsewhere
|
||||||
tokio::spawn(async move {
|
// rn the message isn't guaranteed to actually go out........
|
||||||
network::handle_stream(stream, addr, data)
|
|
||||||
.await
|
Ok(())
|
||||||
.expect("failed to handle client stream");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +121,17 @@ async fn handle_ticks(data: Arc<RwLock<ServerData>>) {
|
||||||
.expect("failed to save config file");
|
.expect("failed to save config file");
|
||||||
data.config_needs_saving = false;
|
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);
|
current_tick = current_tick.wrapping_add(1);
|
||||||
|
|
|
@ -467,6 +467,10 @@ async fn handle_stream_inner(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Command::Stop => {
|
||||||
|
data.stop = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue