Better error handling
This commit is contained in:
parent
bdc56326c0
commit
3279aeae23
@ -11,7 +11,7 @@ pub async fn main() {
|
|||||||
|
|
||||||
// The main server loop.
|
// The main server loop.
|
||||||
loop {
|
loop {
|
||||||
server.update().await;
|
server.update().await.unwrap();
|
||||||
std::thread::sleep(Duration::from_millis(2));
|
std::thread::sleep(Duration::from_millis(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ impl Server {
|
|||||||
/// Update the network server.
|
/// Update the network server.
|
||||||
///
|
///
|
||||||
/// Update each client in `self.network_clients`.
|
/// Update each client in `self.network_clients`.
|
||||||
async fn update_network(&mut self) {
|
async fn update_network(&mut self) -> tokio::io::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
match self.network_receiver.try_recv() {
|
match self.network_receiver.try_recv() {
|
||||||
Ok(client) => {
|
Ok(client) => {
|
||||||
@ -67,18 +67,21 @@ impl Server {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
for client in self.network_clients.iter_mut() {
|
for client in self.network_clients.iter_mut() {
|
||||||
client.update(num_players).await;
|
client.update(num_players).await?;
|
||||||
}
|
}
|
||||||
// Remove disconnected clients.
|
// Remove disconnected clients.
|
||||||
self.network_clients
|
self.network_clients
|
||||||
.retain(|nc| nc.state != NetworkClientState::Disconnected);
|
.retain(|nc| nc.state != NetworkClientState::Disconnected);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the game server.
|
/// Update the game server.
|
||||||
///
|
///
|
||||||
/// Start by updating the network.
|
/// Start by updating the network.
|
||||||
pub async fn update(&mut self) {
|
pub async fn update(&mut self) -> tokio::io::Result<()> {
|
||||||
self.update_network().await;
|
self.update_network().await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,12 +125,11 @@ impl NetworkClient {
|
|||||||
///
|
///
|
||||||
/// Updating could mean connecting new clients, reading packets,
|
/// Updating could mean connecting new clients, reading packets,
|
||||||
/// writing packets, or disconnecting clients.
|
/// writing packets, or disconnecting clients.
|
||||||
pub async fn update(&mut self, num_players: usize) {
|
pub async fn update(&mut self, num_players: usize) -> tokio::io::Result<()> {
|
||||||
match self.state {
|
match self.state {
|
||||||
NetworkClientState::Handshake => {
|
NetworkClientState::Handshake => {
|
||||||
let (_packet_length, _packet_id) =
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
read_packet_header(&mut self.stream).await.unwrap();
|
let handshake = Handshake::read(&mut self.stream).await?;
|
||||||
let handshake = Handshake::read(&mut self.stream).await.unwrap();
|
|
||||||
// Minecraft versions 1.8 - 1.8.9 use protocol version 47.
|
// Minecraft versions 1.8 - 1.8.9 use protocol version 47.
|
||||||
let compatible_versions = handshake.protocol_version == 47;
|
let compatible_versions = handshake.protocol_version == 47;
|
||||||
let next_state = match handshake.next_state.into() {
|
let next_state = match handshake.next_state.into() {
|
||||||
@ -142,15 +144,14 @@ impl NetworkClient {
|
|||||||
logindisconnect.reason = MCChat {
|
logindisconnect.reason = MCChat {
|
||||||
text: MCString::from("Incompatible client! Server is on 1.8.9"),
|
text: MCString::from("Incompatible client! Server is on 1.8.9"),
|
||||||
};
|
};
|
||||||
logindisconnect.write(&mut self.stream).await.unwrap();
|
logindisconnect.write(&mut self.stream).await?;
|
||||||
self.state = NetworkClientState::Disconnected;
|
self.state = NetworkClientState::Disconnected;
|
||||||
}
|
}
|
||||||
debug!("Got handshake: {:?}", handshake);
|
debug!("Got handshake: {:?}", handshake);
|
||||||
}
|
}
|
||||||
NetworkClientState::Status => {
|
NetworkClientState::Status => {
|
||||||
let (_packet_length, _packet_id) =
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
read_packet_header(&mut self.stream).await.unwrap();
|
let statusrequest = StatusRequest::read(&mut self.stream).await?;
|
||||||
let statusrequest = StatusRequest::read(&mut self.stream).await.unwrap();
|
|
||||||
debug!("Got status request: {:?}", statusrequest);
|
debug!("Got status request: {:?}", statusrequest);
|
||||||
let mut statusresponse = StatusResponse::new();
|
let mut statusresponse = StatusResponse::new();
|
||||||
statusresponse.json_response = json!({
|
statusresponse.json_response = json!({
|
||||||
@ -175,22 +176,20 @@ impl NetworkClient {
|
|||||||
})
|
})
|
||||||
.to_string()
|
.to_string()
|
||||||
.into();
|
.into();
|
||||||
statusresponse.write(&mut self.stream).await.unwrap();
|
statusresponse.write(&mut self.stream).await?;
|
||||||
debug!("Sending status response: StatusResponse");
|
debug!("Sending status response: StatusResponse");
|
||||||
let (_packet_length, _packet_id) =
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
read_packet_header(&mut self.stream).await.unwrap();
|
let statusping = StatusPing::read(&mut self.stream).await?;
|
||||||
let statusping = StatusPing::read(&mut self.stream).await.unwrap();
|
|
||||||
debug!("Got status ping: {:?}", statusping);
|
debug!("Got status ping: {:?}", statusping);
|
||||||
let mut statuspong = StatusPong::new();
|
let mut statuspong = StatusPong::new();
|
||||||
statuspong.payload = statusping.payload;
|
statuspong.payload = statusping.payload;
|
||||||
statuspong.write(&mut self.stream).await.unwrap();
|
statuspong.write(&mut self.stream).await?;
|
||||||
debug!("Sending status pong: {:?}", statuspong);
|
debug!("Sending status pong: {:?}", statuspong);
|
||||||
self.state = NetworkClientState::Disconnected;
|
self.state = NetworkClientState::Disconnected;
|
||||||
}
|
}
|
||||||
NetworkClientState::Login => {
|
NetworkClientState::Login => {
|
||||||
let (_packet_length, _packet_id) =
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
read_packet_header(&mut self.stream).await.unwrap();
|
let loginstart = LoginStart::read(&mut self.stream).await?;
|
||||||
let loginstart = LoginStart::read(&mut self.stream).await.unwrap();
|
|
||||||
debug!("{:?}", loginstart);
|
debug!("{:?}", loginstart);
|
||||||
// Offline mode skips encryption and compression.
|
// Offline mode skips encryption and compression.
|
||||||
// TODO: Encryption and compression
|
// TODO: Encryption and compression
|
||||||
@ -199,18 +198,17 @@ impl NetworkClient {
|
|||||||
// TODO: Get uuid and username from Mojang servers.
|
// TODO: Get uuid and username from Mojang servers.
|
||||||
loginsuccess.uuid = "00000000-0000-3000-0000-000000000000".into();
|
loginsuccess.uuid = "00000000-0000-3000-0000-000000000000".into();
|
||||||
loginsuccess.username = loginstart.player_name;
|
loginsuccess.username = loginstart.player_name;
|
||||||
loginsuccess.write(&mut self.stream).await.unwrap();
|
loginsuccess.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", loginsuccess);
|
debug!("{:?}", loginsuccess);
|
||||||
self.uuid = Some(loginsuccess.uuid.clone().into());
|
self.uuid = Some(loginsuccess.uuid.clone().into());
|
||||||
self.username = Some(loginsuccess.username.clone().into());
|
self.username = Some(loginsuccess.username.clone().into());
|
||||||
self.state = NetworkClientState::Play;
|
self.state = NetworkClientState::Play;
|
||||||
let joingame = JoinGame::new();
|
let joingame = JoinGame::new();
|
||||||
// TODO: Fill out `joingame` with actual information.
|
// TODO: Fill out `joingame` with actual information.
|
||||||
joingame.write(&mut self.stream).await.unwrap();
|
joingame.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", joingame);
|
debug!("{:?}", joingame);
|
||||||
let (_packet_length, _packet_id) =
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
read_packet_header(&mut self.stream).await.unwrap();
|
let clientsettings = ClientSettings::read(&mut self.stream).await?;
|
||||||
let clientsettings = ClientSettings::read(&mut self.stream).await.unwrap();
|
|
||||||
// TODO: Actualy use client settings.
|
// TODO: Actualy use client settings.
|
||||||
debug!("{:?}", clientsettings);
|
debug!("{:?}", clientsettings);
|
||||||
|
|
||||||
@ -218,7 +216,7 @@ impl NetworkClient {
|
|||||||
|
|
||||||
let helditemchange = HeldItemChange::new();
|
let helditemchange = HeldItemChange::new();
|
||||||
// TODO: Retrieve selected slot from storage.
|
// TODO: Retrieve selected slot from storage.
|
||||||
helditemchange.write(&mut self.stream).await.unwrap();
|
helditemchange.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", helditemchange);
|
debug!("{:?}", helditemchange);
|
||||||
// TODO: S->C Declare Recipes (1.16?)
|
// TODO: S->C Declare Recipes (1.16?)
|
||||||
// TODO: S->C Tags (1.16?)
|
// TODO: S->C Tags (1.16?)
|
||||||
@ -228,7 +226,7 @@ impl NetworkClient {
|
|||||||
// TODO: S->C Player Position and Look
|
// TODO: S->C Player Position and Look
|
||||||
let playerpositionandlook = PlayerPositionAndLook::new();
|
let playerpositionandlook = PlayerPositionAndLook::new();
|
||||||
// TODO: Retrieve player position from storage.
|
// TODO: Retrieve player position from storage.
|
||||||
playerpositionandlook.write(&mut self.stream).await.unwrap();
|
playerpositionandlook.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", playerpositionandlook);
|
debug!("{:?}", playerpositionandlook);
|
||||||
// TODO: S->C Player Info (Add Player action) (1.16?)
|
// TODO: S->C Player Info (Add Player action) (1.16?)
|
||||||
// TODO: S->C Player Info (Update latency action) (1.16?)
|
// TODO: S->C Player Info (Update latency action) (1.16?)
|
||||||
@ -238,11 +236,11 @@ impl NetworkClient {
|
|||||||
// TODO: S->C World Border
|
// TODO: S->C World Border
|
||||||
// TODO: S->C Spawn Position
|
// TODO: S->C Spawn Position
|
||||||
let spawnposition = SpawnPosition::new();
|
let spawnposition = SpawnPosition::new();
|
||||||
spawnposition.write(&mut self.stream).await.unwrap();
|
spawnposition.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", spawnposition);
|
debug!("{:?}", spawnposition);
|
||||||
// Send initial keep alive.
|
// Send initial keep alive.
|
||||||
self.send_chat_message("keep alive").await;
|
self.send_chat_message("keep alive").await?;
|
||||||
self.keep_alive().await;
|
self.keep_alive().await?;
|
||||||
// TODO: S->C Player Position and Look
|
// TODO: S->C Player Position and Look
|
||||||
// TODO: C->S Teleport Confirm
|
// TODO: C->S Teleport Confirm
|
||||||
// TODO: C->S Player Position and Look
|
// TODO: C->S Player Position and Look
|
||||||
@ -252,51 +250,55 @@ impl NetworkClient {
|
|||||||
"Welcome {} to the server!",
|
"Welcome {} to the server!",
|
||||||
self.username.as_ref().unwrap_or(&"unknown".to_owned())
|
self.username.as_ref().unwrap_or(&"unknown".to_owned())
|
||||||
))
|
))
|
||||||
.await;
|
.await?;
|
||||||
}
|
}
|
||||||
NetworkClientState::Play => {
|
NetworkClientState::Play => {
|
||||||
if self.last_keep_alive.elapsed() > Duration::from_secs(10) {
|
if self.last_keep_alive.elapsed() > Duration::from_secs(10) {
|
||||||
self.send_chat_message("keep alive").await;
|
self.send_chat_message("keep alive").await?;
|
||||||
self.keep_alive().await;
|
self.keep_alive().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NetworkClientState::Disconnected => {
|
NetworkClientState::Disconnected => {
|
||||||
if self.connected {
|
if self.connected {
|
||||||
self.disconnect(None).await;
|
self.disconnect(None).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_chat_message<C: Into<MCChat>>(&mut self, message: C) {
|
async fn send_chat_message<C: Into<MCChat>>(&mut self, message: C) -> tokio::io::Result<()> {
|
||||||
let mut chatmessage = ClientboundChatMessage::new();
|
let mut chatmessage = ClientboundChatMessage::new();
|
||||||
chatmessage.text = message.into();
|
chatmessage.text = message.into();
|
||||||
chatmessage.write(&mut self.stream).await.unwrap();
|
chatmessage.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", chatmessage);
|
debug!("{:?}", chatmessage);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn disconnect(&mut self, reason: Option<&str>) {
|
async fn disconnect(&mut self, reason: Option<&str>) -> tokio::io::Result<()> {
|
||||||
self.connected = false;
|
self.connected = false;
|
||||||
self.state = NetworkClientState::Disconnected;
|
self.state = NetworkClientState::Disconnected;
|
||||||
// Send 0x40 Disconnect.
|
// Send 0x40 Disconnect.
|
||||||
let mut disconnect = Disconnect::new();
|
let mut disconnect = Disconnect::new();
|
||||||
disconnect.reason.text = reason.unwrap_or("Disconnected").into();
|
disconnect.reason.text = reason.unwrap_or("Disconnected").into();
|
||||||
disconnect.write(&mut self.stream).await.unwrap();
|
disconnect.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", disconnect);
|
debug!("{:?}", disconnect);
|
||||||
// Give the client 10 seconds to disconnect before forcing it.
|
// Give the client 10 seconds to disconnect before forcing it.
|
||||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a keep alive packet to the client.
|
/// Send a keep alive packet to the client.
|
||||||
async fn keep_alive(&mut self) {
|
async fn keep_alive(&mut self) -> tokio::io::Result<()> {
|
||||||
// Keep alive ping to client.
|
// Keep alive ping to client.
|
||||||
let clientboundkeepalive = KeepAlivePing::new();
|
let clientboundkeepalive = KeepAlivePing::new();
|
||||||
clientboundkeepalive.write(&mut self.stream).await.unwrap();
|
clientboundkeepalive.write(&mut self.stream).await?;
|
||||||
debug!("{:?}", clientboundkeepalive);
|
debug!("{:?}", clientboundkeepalive);
|
||||||
// Keep alive pong to server.
|
// Keep alive pong to server.
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await.unwrap();
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
let serverboundkeepalive = KeepAlivePong::read(&mut self.stream).await.unwrap();
|
let serverboundkeepalive = KeepAlivePong::read(&mut self.stream).await?;
|
||||||
debug!("{:?}", serverboundkeepalive);
|
debug!("{:?}", serverboundkeepalive);
|
||||||
self.last_keep_alive = Instant::now();
|
self.last_keep_alive = Instant::now();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user