Use server protocol version/player max once known for status responses

This commit is contained in:
timvisee 2021-11-08 13:07:49 +01:00
parent d4c0b4c146
commit 049fce78b7
No known key found for this signature in database
GPG Key ID: B8DB720BC383E172
6 changed files with 54 additions and 19 deletions

4
Cargo.lock generated
View File

@ -249,7 +249,7 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "minecraft-protocol"
version = "0.1.0"
source = "git+https://github.com/timvisee/minecraft-protocol?rev=c181117#c1811171c20a88bc7ecac1cda3257fbaa9f9c10c"
source = "git+https://github.com/timvisee/minecraft-protocol?rev=4348c27#4348c27fa95d304b154c66b414738f41927db23e"
dependencies = [
"byteorder",
"minecraft-protocol-derive",
@ -262,7 +262,7 @@ dependencies = [
[[package]]
name = "minecraft-protocol-derive"
version = "0.0.0"
source = "git+https://github.com/timvisee/minecraft-protocol?rev=c181117#c1811171c20a88bc7ecac1cda3257fbaa9f9c10c"
source = "git+https://github.com/timvisee/minecraft-protocol?rev=4348c27#4348c27fa95d304b154c66b414738f41927db23e"
dependencies = [
"proc-macro2",
"quote",

View File

@ -22,7 +22,7 @@ edition = "2021"
bytes = "1.1"
futures = { version = "0.3", default-features = false }
libc = "0.2"
minecraft-protocol = { git = "https://github.com/timvisee/minecraft-protocol", rev = "c181117" }
minecraft-protocol = { git = "https://github.com/timvisee/minecraft-protocol", rev = "4348c27" }
tokio = { version = "1", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "macros", "time", "process", "signal"] }
dotenv = "0.15"

View File

@ -24,7 +24,7 @@ use tokio::io::AsyncWriteExt;
use tokio::net::{TcpListener, TcpStream};
use config::*;
use proto::{Client, ClientState, RawPacket};
use proto::{Client, ClientState, RawPacket, PROTO_DEFAULT_PROTOCOL, PROTO_DEFAULT_VERSION};
use server::ServerState;
#[tokio::main]
@ -157,22 +157,32 @@ async fn serve_status(
// Hijack server status packet
if client.state() == ClientState::Status && packet.id == proto::STATUS_PACKET_ID_STATUS {
// Build status response
// TODO: grab latest protocol version from online server!
// Select version and player max from last known server status
let (version, max) = match server.clone_status() {
Some(status) => (status.version, status.players.max),
None => (
ServerVersion {
name: String::from(PROTO_DEFAULT_VERSION),
protocol: PROTO_DEFAULT_PROTOCOL,
},
0,
),
};
// Select description
let description = if server.starting() {
LABEL_SERVER_STARTING
} else {
LABEL_SERVER_SLEEPING
};
// Build status resposne
let server_status = ServerStatus {
version: ServerVersion {
name: String::from("1.16.5"),
protocol: 754,
},
version,
description: Message::new(Payload::text(description)),
players: OnlinePlayers {
online: 0,
max: 0,
max,
sample: vec![],
},
};

View File

@ -13,12 +13,9 @@ use minecraft_protocol::version::v1_14_4::status::StatusResponse;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
use crate::proto::{self, ClientState, RawPacket};
use crate::proto::{self, ClientState, RawPacket, PROTO_DEFAULT_PROTOCOL};
use crate::server::ServerState;
/// Minecraft protocol version used when polling server status.
const PROTOCOL_VERSION: i32 = 754;
/// Monitor ping inverval in seconds.
const MONITOR_PING_INTERVAL: u64 = 2;
@ -37,6 +34,7 @@ pub async fn monitor_server(addr: SocketAddr, state: Arc<ServerState>) {
state.set_status(status);
}
// TODO: use interval instead, for a more reliable polling interval?
tokio::time::sleep(Duration::from_secs(MONITOR_PING_INTERVAL)).await;
}
}
@ -60,7 +58,7 @@ async fn fetch_status(addr: SocketAddr) -> Result<ServerStatus, ()> {
/// Send handshake.
async fn send_handshake(stream: &mut TcpStream, addr: SocketAddr) -> Result<(), ()> {
let handshake = Handshake {
protocol_version: PROTOCOL_VERSION,
protocol_version: PROTO_DEFAULT_PROTOCOL as i32,
server_addr: addr.ip().to_string(),
server_port: addr.port(),
next_state: ClientState::Status.to_id(),
@ -72,7 +70,6 @@ async fn send_handshake(stream: &mut TcpStream, addr: SocketAddr) -> Result<(),
let raw = RawPacket::new(proto::HANDSHAKE_PACKET_ID_HANDSHAKE, packet)
.encode()
.map_err(|_| ())?;
stream.write_all(&raw).await.map_err(|_| ())?;
Ok(())

View File

@ -7,13 +7,31 @@ use tokio::net::tcp::ReadHalf;
use crate::types;
/// Default minecraft protocol version name.
///
/// Send to clients when the server is sleeping when the real server version is not known yet.
pub const PROTO_DEFAULT_VERSION: &str = "1.16.5";
/// Default minecraft protocol version.
///
/// Send to clients when the server is sleeping when the real server version is not known yet, and
/// with server status polling requests.
pub const PROTO_DEFAULT_PROTOCOL: u32 = 754;
/// Handshake state, handshake packet ID.
pub const HANDSHAKE_PACKET_ID_HANDSHAKE: i32 = 0;
/// Status state, status packet ID.
pub const STATUS_PACKET_ID_STATUS: i32 = 0;
/// Status state, ping packet ID.
pub const STATUS_PACKET_ID_PING: i32 = 1;
/// Login state, login start packet ID.
pub const LOGIN_PACKET_ID_LOGIN_START: i32 = 0;
/// Client state.
// TODO: add encryption/compression state
// TODO: add encryption/compression state?
#[derive(Debug, Default)]
pub struct Client {
/// Current client state.
@ -120,6 +138,10 @@ impl RawPacket {
}
/// Read raw packet from stream.
///
/// Note: this does not support reading compressed/encrypted packets.
/// We should never need this though, as we're done reading user packets before any of this is
/// enabled. See: https://wiki.vg/Protocol#Packet_format
pub async fn read_packet<'a>(
buf: &mut BytesMut,
stream: &mut ReadHalf<'a>,

View File

@ -21,7 +21,8 @@ pub struct ServerState {
/// Last known server status.
///
/// Once set, this will remain set, and isn't cleared when the server goes offline.
status: Mutex<Option<ServerStatus>>,
// TODO: make this private?
pub status: Mutex<Option<ServerStatus>>,
}
impl ServerState {
@ -61,6 +62,11 @@ impl ServerState {
*self.pid.lock().unwrap() = pid;
}
/// Clone the last known server status.
pub fn clone_status(&self) -> Option<ServerStatus> {
self.status.lock().unwrap().clone()
}
/// Update the server status.
pub fn set_status(&self, status: ServerStatus) {
self.status.lock().unwrap().replace(status);