Refactored status.rs to use traits
This commit is contained in:
parent
1d717ab8da
commit
e9a3770c1e
|
@ -8,6 +8,7 @@ mod mc_types;
|
||||||
mod handshake;
|
mod handshake;
|
||||||
mod status;
|
mod status;
|
||||||
mod login;
|
mod login;
|
||||||
|
mod status_handle;
|
||||||
|
|
||||||
use mc_types::Packet;
|
use mc_types::Packet;
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ async fn handle_client(client_socket: TcpStream) {
|
||||||
let packet_id: u8 = buffer[0];
|
let packet_id: u8 = buffer[0];
|
||||||
|
|
||||||
if packet_id == 0xFE {
|
if packet_id == 0xFE {
|
||||||
status::respond_legacy_status(&mut client_writer)
|
status_handle::respond_legacy_status(&mut client_writer)
|
||||||
.await.expect("Error handling legacy status request");
|
.await.expect("Error handling legacy status request");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -60,7 +61,7 @@ async fn handle_client(client_socket: TcpStream) {
|
||||||
println!("Next state: {}", handshake_packet.next_state);
|
println!("Next state: {}", handshake_packet.next_state);
|
||||||
if handshake_packet.next_state == 1 {
|
if handshake_packet.next_state == 1 {
|
||||||
println!("Receiving Status Request");
|
println!("Receiving Status Request");
|
||||||
status::respond_status(
|
status_handle::respond_status(
|
||||||
&mut client_reader,
|
&mut client_reader,
|
||||||
&mut client_writer,
|
&mut client_writer,
|
||||||
&mut server_reader,
|
&mut server_reader,
|
||||||
|
|
373
src/status.rs
373
src/status.rs
|
@ -1,40 +1,34 @@
|
||||||
// Yeahbut December 2023
|
// Yeahbut December 2023
|
||||||
|
|
||||||
use std::fs::{self, File};
|
pub mod clientbound {
|
||||||
use std::io::Read;
|
|
||||||
|
|
||||||
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
use tokio::net::tcp::OwnedReadHalf;
|
||||||
use tokio::io::AsyncWriteExt;
|
use serde::{Serialize, Deserialize};
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use serde_json::Value;
|
|
||||||
use base64::{Engine as _, engine::general_purpose};
|
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
use crate::mc_types::{self, Result, Packet};
|
use crate::mc_types::{self, Result, Packet, PacketError};
|
||||||
use crate::handshake;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct StatusVersion {
|
pub struct StatusVersion {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub protocol: i32,
|
pub protocol: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct StatusPlayerInfo {
|
pub struct StatusPlayerInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct StatusPlayers {
|
pub struct StatusPlayers {
|
||||||
pub max: i32,
|
pub max: i32,
|
||||||
pub online: i32,
|
pub online: i32,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub sample: Option<Vec<StatusPlayerInfo>>
|
pub sample: Option<Vec<StatusPlayerInfo>>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct StatusResponseData {
|
pub struct StatusResponseData {
|
||||||
pub version: StatusVersion,
|
pub version: StatusVersion,
|
||||||
pub description: mc_types::Chat,
|
pub description: mc_types::Chat,
|
||||||
pub players: StatusPlayers,
|
pub players: StatusPlayers,
|
||||||
|
@ -44,206 +38,157 @@ pub struct StatusResponseData {
|
||||||
pub enforcesSecureChat: Option<bool>,
|
pub enforcesSecureChat: Option<bool>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub previewsChat: Option<bool>,
|
pub previewsChat: Option<bool>,
|
||||||
}
|
|
||||||
|
|
||||||
async fn online_players(
|
|
||||||
server_reader: &mut OwnedReadHalf,
|
|
||||||
server_writer: &mut OwnedWriteHalf,
|
|
||||||
) -> Result<StatusPlayers> {
|
|
||||||
Ok(get_upstream_status(server_reader, server_writer).await?.players)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn motd() -> String {
|
|
||||||
let default = "A Minecraft Server Proxy".to_string();
|
|
||||||
let file_path = "./motd.json";
|
|
||||||
|
|
||||||
let data = match fs::read_to_string(file_path) {
|
|
||||||
Ok(data) => data,
|
|
||||||
Err(_) => return default,
|
|
||||||
};
|
|
||||||
|
|
||||||
let motd_data: Value = match serde_json::from_str(&data) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(_) => return default,
|
|
||||||
};
|
|
||||||
|
|
||||||
let length1 = motd_data["line1"].as_array().map_or(0, |v| v.len());
|
|
||||||
let length2 = motd_data["line2"].as_array().map_or(0, |v| v.len());
|
|
||||||
|
|
||||||
if length1 == 0 || length2 == 0 {
|
|
||||||
return default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
pub enum StatusPackets {
|
||||||
let rand1 = rng.gen_range(0..length1) as usize;
|
Status(Status),
|
||||||
let rand2 = rng.gen_range(0..length2) as usize;
|
Ping(Ping),
|
||||||
|
}
|
||||||
|
|
||||||
let line1: &str = match motd_data["line1"][rand1].as_str() {
|
impl StatusPackets {
|
||||||
Some(s) => s,
|
pub async fn read(stream: &mut OwnedReadHalf) -> Result<Self> {
|
||||||
None => return default,
|
let mut data = mc_types::read_data(stream).await?;
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Birthdays, Holidays, and Announcements
|
|
||||||
|
|
||||||
let line2: &str = match motd_data["line2"][rand2].as_str() {
|
|
||||||
Some(s) => s,
|
|
||||||
None => return default,
|
|
||||||
};
|
|
||||||
|
|
||||||
let line: String = format!("{}\n{}", line1, line2);
|
|
||||||
line
|
|
||||||
}
|
|
||||||
|
|
||||||
fn favicon() -> Option<String> {
|
|
||||||
let file_path = "./main_icon.png";
|
|
||||||
|
|
||||||
let mut file = match File::open(file_path) {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(_) => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
if let Err(_) = file.read_to_end(&mut buffer) {
|
|
||||||
return None
|
|
||||||
};
|
|
||||||
|
|
||||||
let base64_string = general_purpose::STANDARD_NO_PAD.encode(buffer);
|
|
||||||
let full_string: String =
|
|
||||||
format!("data:image/png;base64,{}", base64_string);
|
|
||||||
|
|
||||||
Some(full_string)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn respond_status(
|
|
||||||
client_reader: &mut OwnedReadHalf,
|
|
||||||
client_writer: &mut OwnedWriteHalf,
|
|
||||||
server_reader: &mut Option<OwnedReadHalf>,
|
|
||||||
server_writer: &mut Option<OwnedWriteHalf>,
|
|
||||||
)-> Result<()> {
|
|
||||||
loop {
|
|
||||||
println!("Status Handling");
|
|
||||||
let mut data = mc_types::read_data(client_reader).await?;
|
|
||||||
let packet_id = mc_types::get_var_int(&mut data)?;
|
let packet_id = mc_types::get_var_int(&mut data)?;
|
||||||
|
if packet_id == Status::packet_id() {
|
||||||
println!("Status Packet ID: {}", packet_id);
|
return Ok(Self::Status(Status::get(&mut data)?))
|
||||||
|
} else if packet_id == Ping::packet_id() {
|
||||||
if packet_id == 0x00 {
|
return Ok(Self::Ping(Ping::get(&mut data)?))
|
||||||
println!("Handling Status");
|
|
||||||
let favicon = favicon();
|
|
||||||
|
|
||||||
let online_players = match server_reader {
|
|
||||||
Some(server_reader) => match server_writer {
|
|
||||||
Some(server_writer) => match online_players(
|
|
||||||
server_reader,
|
|
||||||
server_writer,
|
|
||||||
).await {
|
|
||||||
Ok(value) => Some(value),
|
|
||||||
Err(_) => None,
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let status_response =
|
|
||||||
match online_players {
|
|
||||||
Some(online_players) => StatusResponseData {
|
|
||||||
version: StatusVersion {
|
|
||||||
name: mc_types::VERSION_NAME.to_string(),
|
|
||||||
protocol: mc_types::VERSION_PROTOCOL,
|
|
||||||
},
|
|
||||||
description: mc_types::Chat {
|
|
||||||
text: motd(),
|
|
||||||
},
|
|
||||||
players: StatusPlayers {
|
|
||||||
max: -13,
|
|
||||||
online: online_players.online,
|
|
||||||
sample: online_players.sample,
|
|
||||||
},
|
|
||||||
favicon: favicon,
|
|
||||||
enforcesSecureChat: Some(false),
|
|
||||||
previewsChat: Some(false),
|
|
||||||
},
|
|
||||||
None => StatusResponseData {
|
|
||||||
version: StatusVersion {
|
|
||||||
name: "Old".to_string(),
|
|
||||||
protocol: 0,
|
|
||||||
},
|
|
||||||
description: mc_types::Chat {
|
|
||||||
text: "Server Error (Server may be starting)"
|
|
||||||
.to_string() + "\nPurple Cello Server",
|
|
||||||
},
|
|
||||||
players: StatusPlayers {
|
|
||||||
max: 0,
|
|
||||||
online: 0,
|
|
||||||
sample: None,
|
|
||||||
},
|
|
||||||
favicon: favicon,
|
|
||||||
enforcesSecureChat: Some(false),
|
|
||||||
previewsChat: Some(false),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let json = serde_json::to_string(&status_response)?;
|
|
||||||
|
|
||||||
let mut out_data: Vec<u8> = vec![0];
|
|
||||||
out_data.append(&mut mc_types::convert_string(&json));
|
|
||||||
mc_types::write_data(client_writer, &mut out_data).await?;
|
|
||||||
} else if packet_id == 0x01 {
|
|
||||||
println!("Handling Ping");
|
|
||||||
let mut out_data: Vec<u8> = vec![1];
|
|
||||||
out_data.append(&mut data);
|
|
||||||
mc_types::write_data(client_writer, &mut out_data).await?;
|
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
return Err(Box::new(PacketError::InvalidPacketId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_upstream_status(
|
|
||||||
server_reader: &mut OwnedReadHalf,
|
|
||||||
server_writer: &mut OwnedWriteHalf,
|
|
||||||
) -> Result<StatusResponseData> {
|
|
||||||
handshake::serverbound::Handshake{
|
|
||||||
protocol_version: mc_types::VERSION_PROTOCOL,
|
|
||||||
server_address: "localhost".to_string(),
|
|
||||||
server_port: 25565,
|
|
||||||
next_state: 1,
|
|
||||||
}.write(server_writer).await?;
|
|
||||||
mc_types::write_data(server_writer, &mut vec![0]).await?;
|
|
||||||
let mut data = mc_types::read_data(server_reader).await?;
|
|
||||||
|
|
||||||
mc_types::get_u8(&mut data);
|
|
||||||
let json = mc_types::get_string(&mut data)?;
|
|
||||||
let status_response: StatusResponseData = serde_json::from_str(&json)?;
|
|
||||||
|
|
||||||
// let mut out_data: Vec<u8> = vec![1];
|
|
||||||
// out_data.append(&mut mc_types::convert_i64(0));
|
|
||||||
// mc_types::write_packet(server_writer, &mut out_data).await?;
|
|
||||||
|
|
||||||
Ok(status_response)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn respond_legacy_status(
|
|
||||||
client_writer: &mut OwnedWriteHalf,
|
|
||||||
) -> Result<()> {
|
|
||||||
println!("Old Style Status");
|
|
||||||
client_writer.write_u8(0xFF).await?;
|
|
||||||
|
|
||||||
let s = "§1\0127\0".to_string() +
|
|
||||||
mc_types::VERSION_NAME +
|
|
||||||
"\0YTD Proxy§0§10";
|
|
||||||
let utf16_vec: Vec<u16> = s
|
|
||||||
.encode_utf16()
|
|
||||||
.flat_map(|c| std::iter::once(c).chain(std::iter::once(0)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
client_writer.write_u16((utf16_vec.len() / 2) as u16).await?;
|
|
||||||
for utf16_char in utf16_vec {
|
|
||||||
client_writer.write_u16(utf16_char).await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
pub struct Status {
|
||||||
|
pub response: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Status {
|
||||||
|
|
||||||
|
pub fn from_json(data: StatusResponseData) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
response: serde_json::to_string(&data)?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_json(&self) -> Result<StatusResponseData> {
|
||||||
|
Ok(serde_json::from_str(&self.response)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for Status {
|
||||||
|
|
||||||
|
fn packet_id() -> i32 {0}
|
||||||
|
|
||||||
|
fn get(mut data: &mut Vec<u8>) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
response: mc_types::get_string(&mut data)?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert(&self) -> Vec<u8> {
|
||||||
|
let mut data: Vec<u8> = vec![];
|
||||||
|
data.append(&mut mc_types::convert_var_int(Self::packet_id()));
|
||||||
|
data.append(&mut mc_types::convert_string(&self.response));
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ping {
|
||||||
|
pub payload: i64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for Ping {
|
||||||
|
|
||||||
|
fn packet_id() -> i32 {1}
|
||||||
|
|
||||||
|
fn get(mut data: &mut Vec<u8>) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
payload: mc_types::get_i64(&mut data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert(&self) -> Vec<u8> {
|
||||||
|
let mut data: Vec<u8> = vec![];
|
||||||
|
data.append(&mut mc_types::convert_var_int(Self::packet_id()));
|
||||||
|
data.append(&mut mc_types::convert_i64(self.payload));
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod serverbound {
|
||||||
|
|
||||||
|
use tokio::net::tcp::OwnedReadHalf;
|
||||||
|
|
||||||
|
use crate::mc_types::{self, Result, Packet, PacketError};
|
||||||
|
|
||||||
|
pub enum StatusPackets {
|
||||||
|
Status(Status),
|
||||||
|
Ping(Ping),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatusPackets {
|
||||||
|
pub async fn read(stream: &mut OwnedReadHalf) -> Result<Self> {
|
||||||
|
let mut data = mc_types::read_data(stream).await?;
|
||||||
|
let packet_id = mc_types::get_var_int(&mut data)?;
|
||||||
|
if packet_id == Status::packet_id() {
|
||||||
|
return Ok(Self::Status(Status::get(&mut data)?))
|
||||||
|
} else if packet_id == Ping::packet_id() {
|
||||||
|
return Ok(Self::Ping(Ping::get(&mut data)?))
|
||||||
|
} else {
|
||||||
|
return Err(Box::new(PacketError::InvalidPacketId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Status {}
|
||||||
|
|
||||||
|
impl Packet for Status {
|
||||||
|
|
||||||
|
fn packet_id() -> i32 {0}
|
||||||
|
|
||||||
|
fn get(mut data: &mut Vec<u8>) -> Result<Self> {
|
||||||
|
Ok(Self {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert(&self) -> Vec<u8> {
|
||||||
|
let mut data: Vec<u8> = vec![];
|
||||||
|
data.append(&mut mc_types::convert_var_int(Self::packet_id()));
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ping {
|
||||||
|
pub payload: i64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet for Ping {
|
||||||
|
|
||||||
|
fn packet_id() -> i32 {1}
|
||||||
|
|
||||||
|
fn get(mut data: &mut Vec<u8>) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
payload: mc_types::get_i64(&mut data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert(&self) -> Vec<u8> {
|
||||||
|
let mut data: Vec<u8> = vec![];
|
||||||
|
data.append(&mut mc_types::convert_var_int(Self::packet_id()));
|
||||||
|
data.append(&mut mc_types::convert_i64(self.payload));
|
||||||
|
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
// Yeahbut December 2023
|
||||||
|
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use serde_json::Value;
|
||||||
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use crate::mc_types::{self, Result, Packet};
|
||||||
|
use crate::status;
|
||||||
|
use crate::handshake;
|
||||||
|
|
||||||
|
async fn online_players(
|
||||||
|
server_reader: &mut OwnedReadHalf,
|
||||||
|
server_writer: &mut OwnedWriteHalf,
|
||||||
|
) -> Result<status::clientbound::StatusPlayers> {
|
||||||
|
Ok(get_upstream_status(server_reader, server_writer).await?.players)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motd() -> String {
|
||||||
|
let default = "A Minecraft Server Proxy".to_string();
|
||||||
|
let file_path = "./motd.json";
|
||||||
|
|
||||||
|
let data = match fs::read_to_string(file_path) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(_) => return default,
|
||||||
|
};
|
||||||
|
|
||||||
|
let motd_data: Value = match serde_json::from_str(&data) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(_) => return default,
|
||||||
|
};
|
||||||
|
|
||||||
|
let length1 = motd_data["line1"].as_array().map_or(0, |v| v.len());
|
||||||
|
let length2 = motd_data["line2"].as_array().map_or(0, |v| v.len());
|
||||||
|
|
||||||
|
if length1 == 0 || length2 == 0 {
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let rand1 = rng.gen_range(0..length1) as usize;
|
||||||
|
let rand2 = rng.gen_range(0..length2) as usize;
|
||||||
|
|
||||||
|
let line1: &str = match motd_data["line1"][rand1].as_str() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return default,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Birthdays, Holidays, and Announcements
|
||||||
|
|
||||||
|
let line2: &str = match motd_data["line2"][rand2].as_str() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return default,
|
||||||
|
};
|
||||||
|
|
||||||
|
let line: String = format!("{}\n{}", line1, line2);
|
||||||
|
line
|
||||||
|
}
|
||||||
|
|
||||||
|
fn favicon() -> Option<String> {
|
||||||
|
let file_path = "./main_icon.png";
|
||||||
|
|
||||||
|
let mut file = match File::open(file_path) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
if let Err(_) = file.read_to_end(&mut buffer) {
|
||||||
|
return None
|
||||||
|
};
|
||||||
|
|
||||||
|
let base64_string = general_purpose::STANDARD_NO_PAD.encode(buffer);
|
||||||
|
let full_string: String =
|
||||||
|
format!("data:image/png;base64,{}", base64_string);
|
||||||
|
|
||||||
|
Some(full_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn respond_status(
|
||||||
|
client_reader: &mut OwnedReadHalf,
|
||||||
|
client_writer: &mut OwnedWriteHalf,
|
||||||
|
server_reader: &mut Option<OwnedReadHalf>,
|
||||||
|
server_writer: &mut Option<OwnedWriteHalf>,
|
||||||
|
)-> Result<()> {
|
||||||
|
loop {
|
||||||
|
println!("Status Handling");
|
||||||
|
let packet =
|
||||||
|
status::serverbound::StatusPackets::read(client_reader).await?;
|
||||||
|
match packet {
|
||||||
|
status::serverbound::StatusPackets::Status(_) => {
|
||||||
|
println!("Handling Status");
|
||||||
|
let favicon = favicon();
|
||||||
|
|
||||||
|
let online_players = match server_reader {
|
||||||
|
Some(server_reader) => match server_writer {
|
||||||
|
Some(server_writer) => match online_players(
|
||||||
|
server_reader,
|
||||||
|
server_writer,
|
||||||
|
).await {
|
||||||
|
Ok(value) => Some(value),
|
||||||
|
Err(_) => None,
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let status_response =
|
||||||
|
match online_players {
|
||||||
|
Some(online_players) =>
|
||||||
|
status::clientbound::StatusResponseData {
|
||||||
|
version: status::clientbound::StatusVersion {
|
||||||
|
name: mc_types::VERSION_NAME.to_string(),
|
||||||
|
protocol: mc_types::VERSION_PROTOCOL,
|
||||||
|
},
|
||||||
|
description: mc_types::Chat {
|
||||||
|
text: motd(),
|
||||||
|
},
|
||||||
|
players: status::clientbound::StatusPlayers {
|
||||||
|
max: -13,
|
||||||
|
online: online_players.online,
|
||||||
|
sample: online_players.sample,
|
||||||
|
},
|
||||||
|
favicon: favicon,
|
||||||
|
enforcesSecureChat: Some(false),
|
||||||
|
previewsChat: Some(false),
|
||||||
|
},
|
||||||
|
None => status::clientbound::StatusResponseData {
|
||||||
|
version: status::clientbound::StatusVersion {
|
||||||
|
name: "Old".to_string(),
|
||||||
|
protocol: 0,
|
||||||
|
},
|
||||||
|
description: mc_types::Chat {
|
||||||
|
text: "Server Error (Server may be starting)"
|
||||||
|
.to_string() + "\nPurple Cello Server",
|
||||||
|
},
|
||||||
|
players: status::clientbound::StatusPlayers {
|
||||||
|
max: 0,
|
||||||
|
online: 0,
|
||||||
|
sample: None,
|
||||||
|
},
|
||||||
|
favicon: favicon,
|
||||||
|
enforcesSecureChat: Some(false),
|
||||||
|
previewsChat: Some(false),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let packet =
|
||||||
|
status::clientbound::Status::from_json(status_response)?;
|
||||||
|
packet.write(client_writer).await?;
|
||||||
|
},
|
||||||
|
status::serverbound::StatusPackets::Ping(packet) => {
|
||||||
|
println!("Handling Ping");
|
||||||
|
let new_packet = status::clientbound::Ping{
|
||||||
|
payload: packet.payload,
|
||||||
|
};
|
||||||
|
new_packet.write(client_writer).await?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_upstream_status(
|
||||||
|
server_reader: &mut OwnedReadHalf,
|
||||||
|
server_writer: &mut OwnedWriteHalf,
|
||||||
|
) -> Result<status::clientbound::StatusResponseData> {
|
||||||
|
handshake::serverbound::Handshake{
|
||||||
|
protocol_version: mc_types::VERSION_PROTOCOL,
|
||||||
|
server_address: "localhost".to_string(),
|
||||||
|
server_port: 25565,
|
||||||
|
next_state: 1,
|
||||||
|
}.write(server_writer).await?;
|
||||||
|
mc_types::write_data(server_writer, &mut vec![0]).await?;
|
||||||
|
let mut data = mc_types::read_data(server_reader).await?;
|
||||||
|
|
||||||
|
mc_types::get_u8(&mut data);
|
||||||
|
let json = mc_types::get_string(&mut data)?;
|
||||||
|
let status_response: status::clientbound::StatusResponseData =
|
||||||
|
serde_json::from_str(&json)?;
|
||||||
|
|
||||||
|
// let mut out_data: Vec<u8> = vec![1];
|
||||||
|
// out_data.append(&mut mc_types::convert_i64(0));
|
||||||
|
// mc_types::write_packet(server_writer, &mut out_data).await?;
|
||||||
|
|
||||||
|
Ok(status_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn respond_legacy_status(
|
||||||
|
client_writer: &mut OwnedWriteHalf,
|
||||||
|
) -> Result<()> {
|
||||||
|
println!("Old Style Status");
|
||||||
|
client_writer.write_u8(0xFF).await?;
|
||||||
|
|
||||||
|
let s = "§1\0127\0".to_string() +
|
||||||
|
mc_types::VERSION_NAME +
|
||||||
|
"\0YTD Proxy§0§10";
|
||||||
|
let utf16_vec: Vec<u16> = s
|
||||||
|
.encode_utf16()
|
||||||
|
.flat_map(|c| std::iter::once(c).chain(std::iter::once(0)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
client_writer.write_u16((utf16_vec.len() / 2) as u16).await?;
|
||||||
|
for utf16_char in utf16_vec {
|
||||||
|
client_writer.write_u16(utf16_char).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue