Skip to content

Commit

Permalink
Add query options to config
Browse files Browse the repository at this point in the history
Added packet data types
Correctly parse a handshake packet
Add tokio to pumpkin protocol for `AsyncReadExt` convenience functions
  • Loading branch information
neeleshpoli committed Oct 31, 2024
1 parent 14c8c7e commit 813ef02
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 1 deletion.
3 changes: 3 additions & 0 deletions pumpkin-config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use log::warn;
use logging::LoggingConfig;
use pumpkin_core::{Difficulty, GameMode};
use query::QueryConfig;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

// TODO: when https://github.com/rust-lang/rfcs/pull/3681 gets merged, replace serde-inline-default with native syntax
Expand All @@ -17,6 +18,7 @@ pub mod auth;
pub mod logging;
pub mod proxy;
pub mod resource_pack;
pub mod query;

pub use auth::AuthenticationConfig;
pub use commands::CommandsConfig;
Expand Down Expand Up @@ -53,6 +55,7 @@ pub struct AdvancedConfiguration {
pub rcon: RCONConfig,
pub pvp: PVPConfig,
pub logging: LoggingConfig,
pub query: QueryConfig,
}

#[serde_inline_default]
Expand Down
21 changes: 21 additions & 0 deletions pumpkin-config/src/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};
use serde_inline_default::serde_inline_default;

#[serde_inline_default]
#[derive(Deserialize, Serialize)]
pub struct QueryConfig {
#[serde_inline_default(false)]
pub enabled: bool,
// Optional so if not specified the port server is running on will be used
#[serde_inline_default(None)]
pub port: Option<u16>,
}

impl Default for QueryConfig {
fn default() -> Self {
Self {
enabled: false,
port: None,
}
}
}
2 changes: 1 addition & 1 deletion pumpkin-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ serde.workspace = true
thiserror.workspace = true
itertools.workspace = true
log.workspace = true

tokio.workspace = true
num-traits.workspace = true
num-derive.workspace = true

Expand Down
1 change: 1 addition & 0 deletions pumpkin-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod packet_decoder;
pub mod packet_encoder;
pub mod server;
pub mod slot;
pub mod query;

mod var_int;
pub use var_int::*;
Expand Down
89 changes: 89 additions & 0 deletions pumpkin-protocol/src/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use tokio::io::AsyncReadExt;

#[derive(Debug)]
pub enum PacketType {
Handshake = 9,
Stat = 0,
}

#[derive(Debug)]
pub struct SBasePacket {
pub magic: u16,
pub packet_type: PacketType,
pub session_id: i32,
pub payload: SBasePayload,
}

#[derive(Debug)]
pub enum SBasePayload {
Handshake,
BasicInfo(i32),
FullInfo(i32),
}

impl SBasePacket {
pub async fn decode(mut reader: impl AsyncReadExt + Unpin) -> Self {
let magic = reader.read_u16().await.unwrap();
match reader.read_u8().await.unwrap() {
0 => todo!(),
// Handshake
9 => Self {
magic,
packet_type: PacketType::Handshake,
session_id: reader.read_i32().await.unwrap(),
payload: SBasePayload::Handshake,
},
_ => todo!(),
}
}
}

pub struct CBasePacket {
pub packet_type: PacketType,
pub session_id: i32,
pub payload: CBasePayload,
}

pub enum CBasePayload {
Handshake {
// For simplicity use a number type
// Should be encoded as string here
// Will be converted in encoding
challange_token: i32
},
BasicInfo {
// Use CString as protocol requires nul terminated strings
motd: String,
gametype: String,
map: String,
num_players: String,
max_players: String,
host_port: u16,
host_ip: String,
},
FullInfo {
hostname: String,
// Game type and game id are hardcoded into protocol
// They are not here as they cannot be changed
version: String,
plugins: String,
map: String,
num_players: u16,
max_players: u16,
host_port: u16,
host_ip: String,
players: Vec<String>,
}
}

impl CBasePacket {
fn encode(&self) -> Vec<u8> {
// let buf = Vec::new();

match &self.payload {
CBasePayload::Handshake { challange_token } => todo!(),
CBasePayload::BasicInfo { motd, gametype, map, num_players, max_players, host_port, host_ip } => todo!(),
CBasePayload::FullInfo { hostname, version, plugins, map, num_players, max_players, host_port, host_ip, players } => todo!(),
}
}
}
8 changes: 8 additions & 0 deletions pumpkin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub mod proxy;
pub mod rcon;
pub mod server;
pub mod world;
pub mod query;

fn scrub_address(ip: &str) -> String {
use pumpkin_config::BASIC_CONFIG;
Expand Down Expand Up @@ -140,6 +141,13 @@ async fn main() -> io::Result<()> {
RCONServer::new(&rcon, server).await.unwrap();
});
}

if ADVANCED_CONFIG.query.enabled {
let server = server.clone();
log::info!("Query protocol enabled. Starting...");
tokio::spawn(query::start_query_handler());
}

{
let server = server.clone();
tokio::spawn(async move {
Expand Down
25 changes: 25 additions & 0 deletions pumpkin/src/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Query protocol

use std::io::Cursor;

use pumpkin_protocol::query::SBasePacket;
use tokio::net::UdpSocket;

pub async fn start_query_handler() {
let socket = UdpSocket::bind("0.0.0.0:25565").await.expect("Unable to bind to address");
log::info!("Query socket created");

loop {
let mut buf= vec![0; 1024];
log::info!("Waiting for requests");
let (len, addr) = socket.recv_from(&mut buf).await.unwrap();

tokio::spawn(async move {
let cursor = Cursor::new(buf);
let packet = SBasePacket::decode(cursor).await;

println!("{:#?}", packet);

});
}
}

0 comments on commit 813ef02

Please sign in to comment.