From a0e355ddded4fd61d992672115c0946e41f29ede Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Wed, 17 Mar 2021 21:28:02 -0600 Subject: [PATCH] Send keep alive packets every 10s --- src/mctypes.rs | 19 ++----- src/server/mod.rs | 24 ++++++++- src/server/packets/clientbound.rs | 85 ++++++++++++++++++++++--------- src/server/packets/serverbound.rs | 37 ++++++++++++++ 4 files changed, 126 insertions(+), 39 deletions(-) diff --git a/src/mctypes.rs b/src/mctypes.rs index 9cae875..5054a49 100644 --- a/src/mctypes.rs +++ b/src/mctypes.rs @@ -257,13 +257,7 @@ pub mod other { } impl Display for MCPosition { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "({}, {}, {})", - self.x, - self.y, - self.z, - ) + write!(f, "({}, {}, {})", self.x, self.y, self.z,) } } impl TryFrom> for MCPosition { @@ -279,13 +273,10 @@ pub mod other { let mut out = vec![]; let mut temp = vec![]; temp.extend_from_slice( - &( - ( - ((Into::::into(self.x) & 0x3FFFFFF) << 38) - | ((Into::::into(self.y) & 0xFFF) << 26) - | (Into::::into(self.z) & 0x3FFFFFF) - ) as u64 - ).to_be_bytes() + &((((Into::::into(self.x) & 0x3FFFFFF) << 38) + | ((Into::::into(self.y) & 0xFFF) << 26) + | (Into::::into(self.z) & 0x3FFFFFF)) as u64) + .to_be_bytes(), ); // temp.extend_from_slice(&"{\"text\": \"".to_owned().into_bytes()); // temp.extend_from_slice(&self.text.value.into_bytes()); diff --git a/src/server/mod.rs b/src/server/mod.rs index bbf30d7..f46fd98 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -7,6 +7,7 @@ use log::{debug, info}; use packets::*; use serde_json::json; use std::sync::mpsc::{self, Receiver, TryRecvError}; +use std::time::{Duration, Instant}; use tokio::net::{TcpListener, TcpStream, ToSocketAddrs}; /// The struct containing all the data and running all the updates. @@ -101,6 +102,7 @@ pub struct NetworkClient { pub state: NetworkClientState, pub uuid: Option, pub username: Option, + pub last_keep_alive: Instant, } impl NetworkClient { /// Create a new `NetworkClient` @@ -112,6 +114,7 @@ impl NetworkClient { state: NetworkClientState::Handshake, uuid: None, username: None, + last_keep_alive: Instant::now(), } } @@ -237,16 +240,35 @@ impl NetworkClient { let spawnposition = SpawnPosition::new(); spawnposition.write(&mut self.stream).await.unwrap(); debug!("{:?}", spawnposition); + // Send initial keep alive. + self.keep_alive().await; // TODO: S->C Player Position and Look // TODO: C->S Teleport Confirm // TODO: C->S Player Position and Look // TODO: C->S Client Status // TODO: S->C inventories, entities, etc. } - NetworkClientState::Play => {} + NetworkClientState::Play => { + if self.last_keep_alive.elapsed() > Duration::from_secs(10) { + self.keep_alive().await; + } + } NetworkClientState::Disconnected => { self.connected = false; } } } + + /// Send a keep alive packet to the client. + async fn keep_alive(&mut self) { + // Keep alive ping to client. + let clientboundkeepalive = KeepAlivePing::new(); + clientboundkeepalive.write(&mut self.stream).await.unwrap(); + debug!("{:?}", clientboundkeepalive); + // Keep alive pong to server. + let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await.unwrap(); + let serverboundkeepalive = KeepAlivePong::read(&mut self.stream).await.unwrap(); + debug!("{:?}", serverboundkeepalive); + self.last_keep_alive = Instant::now(); + } } diff --git a/src/server/packets/clientbound.rs b/src/server/packets/clientbound.rs index 9962b5a..3eb409c 100644 --- a/src/server/packets/clientbound.rs +++ b/src/server/packets/clientbound.rs @@ -271,29 +271,29 @@ impl HeldItemChange { pub struct EntityStatus { entity_id: MCInt, entity_status: MCByte, // See table below. - // 1: Sent when resetting a mob spawn minecart's timer / Rabbit jump animation - // 2: Living Entity hurt - // 3: Living Entity dead - // 4: Iron Golem throwing up arms - // 6: Wolf/Ocelot/Horse taming — Spawn “heart” particles - // 7: Wolf/Ocelot/Horse tamed — Spawn “smoke” particles - // 8: Wolf shaking water — Trigger the shaking animation - // 9: (of self) Eating accepted by server - // 10: Sheep eating grass - // 10: Play TNT ignite sound - // 11: Iron Golem handing over a rose - // 12: Villager mating — Spawn “heart” particles - // 13: Spawn particles indicating that a villager is angry and seeking revenge - // 14: Spawn happy particles near a villager - // 15: Witch animation — Spawn “magic” particles - // 16: Play zombie converting into a villager sound - // 17: Firework exploding - // 18: Animal in love (ready to mate) — Spawn “heart” particles - // 19: Reset squid rotation - // 20: Spawn explosion particle — works for some living entities - // 21: Play guardian sound — works for only for guardians - // 22: Enables reduced debug for players - // 23: Disables reduced debug for players + // 1: Sent when resetting a mob spawn minecart's timer / Rabbit jump animation + // 2: Living Entity hurt + // 3: Living Entity dead + // 4: Iron Golem throwing up arms + // 6: Wolf/Ocelot/Horse taming — Spawn “heart” particles + // 7: Wolf/Ocelot/Horse tamed — Spawn “smoke” particles + // 8: Wolf shaking water — Trigger the shaking animation + // 9: (of self) Eating accepted by server + // 10: Sheep eating grass + // 10: Play TNT ignite sound + // 11: Iron Golem handing over a rose + // 12: Villager mating — Spawn “heart” particles + // 13: Spawn particles indicating that a villager is angry and seeking revenge + // 14: Spawn happy particles near a villager + // 15: Witch animation — Spawn “magic” particles + // 16: Play zombie converting into a villager sound + // 17: Firework exploding + // 18: Animal in love (ready to mate) — Spawn “heart” particles + // 19: Reset squid rotation + // 20: Spawn explosion particle — works for some living entities + // 21: Play guardian sound — works for only for guardians + // 22: Enables reduced debug for players + // 23: Disables reduced debug for players } impl Into> for EntityStatus { fn into(self) -> Vec { @@ -401,7 +401,7 @@ impl Into> for SpawnPosition { fn into(self) -> Vec { let mut out = vec![]; let mut temp: Vec = MCVarInt::from(0x05).into(); // 0x05 Spawn Position. - // temp.extend_from_slice(&Into::>::into(self.position)); + // temp.extend_from_slice(&Into::>::into(self.position)); temp.extend_from_slice(&0u64.to_be_bytes()); out.extend_from_slice(&Into::>::into(MCVarInt::from(temp.len() as i32))); out.extend_from_slice(&temp); @@ -432,3 +432,40 @@ impl SpawnPosition { Ok(()) } } + +#[derive(Debug, Clone)] +pub struct KeepAlivePing { + payload: MCVarInt, +} +impl Into> for KeepAlivePing { + fn into(self) -> Vec { + let mut out = vec![]; + let mut temp: Vec = MCVarInt::from(0x00).into(); // 0x00 Keep Alive. + temp.extend_from_slice(&Into::>::into(self.payload)); + out.extend_from_slice(&Into::>::into(MCVarInt::from(temp.len() as i32))); + out.extend_from_slice(&temp); + out + } +} +impl TryFrom> for KeepAlivePing { + type Error = &'static str; + fn try_from(_bytes: Vec) -> Result { + Err("unimplemented") + } +} +impl KeepAlivePing { + pub fn new() -> Self { + KeepAlivePing { payload: 0.into() } + } + pub async fn read(t: &mut TcpStream) -> tokio::io::Result { + let mut keepalive = KeepAlivePing::new(); + keepalive.payload = MCVarInt::read(t).await?; + Ok(keepalive) + } + pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> { + for b in Into::>::into(self.clone()) { + write_byte(t, b).await?; + } + Ok(()) + } +} diff --git a/src/server/packets/serverbound.rs b/src/server/packets/serverbound.rs index acfbfe6..7e237bc 100644 --- a/src/server/packets/serverbound.rs +++ b/src/server/packets/serverbound.rs @@ -225,3 +225,40 @@ impl ClientSettings { Ok(()) } } + +#[derive(Debug, Clone)] +pub struct KeepAlivePong { + payload: MCVarInt, +} +impl Into> for KeepAlivePong { + fn into(self) -> Vec { + let mut out = vec![]; + let mut temp: Vec = MCVarInt::from(0x00).into(); // 0x00 Keep Alive. + temp.extend_from_slice(&Into::>::into(self.payload)); + out.extend_from_slice(&Into::>::into(MCVarInt::from(temp.len() as i32))); + out.extend_from_slice(&temp); + out + } +} +impl TryFrom> for KeepAlivePong { + type Error = &'static str; + fn try_from(_bytes: Vec) -> Result { + Err("unimplemented") + } +} +impl KeepAlivePong { + pub fn new() -> Self { + KeepAlivePong { payload: 0.into() } + } + pub async fn read(t: &mut TcpStream) -> tokio::io::Result { + let mut keepalive = KeepAlivePong::new(); + keepalive.payload = MCVarInt::read(t).await?; + Ok(keepalive) + } + pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> { + for b in Into::>::into(self.clone()) { + write_byte(t, b).await?; + } + Ok(()) + } +}