Resolved all compiler warnings, clean-up proto, remove obsolete code

This commit is contained in:
timvisee 2021-11-14 14:28:45 +01:00
parent 3e7f5719cd
commit 802fd2990a
No known key found for this signature in database
GPG Key ID: B8DB720BC383E172
4 changed files with 88 additions and 110 deletions

View File

@ -1,24 +1,17 @@
// TODO: remove this before feature release!
#![allow(unused)]
use std::io::ErrorKind;
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::time::Duration;
use bytes::BytesMut;
use futures::FutureExt;
use minecraft_protocol::data::chat::{Message, Payload};
use minecraft_protocol::data::server_status::*;
use minecraft_protocol::decoder::Decoder;
use minecraft_protocol::encoder::Encoder;
use minecraft_protocol::version::v1_14_4::game::{GameMode, MessagePosition};
use minecraft_protocol::version::v1_14_4::handshake::Handshake;
use minecraft_protocol::version::v1_14_4::login::{LoginDisconnect, LoginStart, LoginSuccess};
use minecraft_protocol::version::v1_14_4::status::StatusResponse;
use minecraft_protocol::version::v1_14_4::login::{LoginStart, LoginSuccess};
use minecraft_protocol::version::v1_17_1::game::{
ChunkData, ClientBoundChatMessage, ClientBoundKeepAlive, GameDisconnect, JoinGame,
PlayerPositionAndLook, PluginMessage, Respawn, SetTitleSubtitle, SetTitleText, SetTitleTimes,
SpawnPosition, TimeUpdate,
ClientBoundKeepAlive, JoinGame, PlayerPositionAndLook, PluginMessage, Respawn,
SetTitleSubtitle, SetTitleText, SetTitleTimes, SpawnPosition, TimeUpdate,
};
use nbt::CompoundTag;
use tokio::io::{self, AsyncWriteExt};
@ -31,14 +24,12 @@ use uuid::Uuid;
use crate::config::*;
use crate::proto::{self, Client, ClientInfo, ClientState, RawPacket};
use crate::proxy;
use crate::server::{self, Server, State};
use crate::service;
use crate::server::{Server, State};
// TODO: remove this before releasing feature
pub const USE_LOBBY: bool = true;
pub const DONT_START_SERVER: bool = false;
const STARTING_BANNER: &str = "§2Server is starting\n§7⌛ Please wait...";
const HOLD_POLL_INTERVAL: Duration = Duration::from_secs(1);
/// Interval for server state polling when waiting on server to come online.
const SERVER_POLL_INTERVAL: Duration = Duration::from_millis(500);
@ -70,13 +61,12 @@ pub async fn serve(
return Err(());
}
// Incoming buffer and packet holding queue
// Incoming buffer
let mut inbound_buf = queue;
let mut server_queue = BytesMut::new();
loop {
// Read packet from stream
let (packet, raw) = match proto::read_packet(&mut inbound_buf, &mut reader).await {
let (packet, _raw) = match proto::read_packet(&mut inbound_buf, &mut reader).await {
Ok(Some(packet)) => packet,
Ok(None) => break,
Err(_) => {
@ -89,7 +79,9 @@ pub async fn serve(
let client_state = client.state();
// Hijack login start
if client_state == ClientState::Login && packet.id == proto::LOGIN_PACKET_ID_LOGIN_START {
if client_state == ClientState::Login
&& packet.id == proto::packets::login::SERVER_LOGIN_START
{
// Parse login start packet
let login_start = LoginStart::decode(&mut packet.data.as_slice()).map_err(|_| ())?;
@ -102,12 +94,11 @@ pub async fn serve(
trace!(target: "lazymc::lobby", "Client login success, sending required play packets for lobby world");
// Send packets to client required to get into workable play state for lobby world
send_lobby_play_packets(&mut writer).await;
send_lobby_play_packets(&mut writer).await?;
// Wait for server to come online, then set up new connection to it
stage_wait(config.clone(), server.clone(), &mut writer).await?;
let (mut outbound, mut server_buf) =
connect_to_server(client, client_info, &config, server).await?;
stage_wait(server.clone(), &mut writer).await?;
let (mut outbound, mut server_buf) = connect_to_server(client_info, &config).await?;
// Grab join game packet from server
let join_game = wait_for_server_join_game(&mut outbound, &mut server_buf).await?;
@ -133,7 +124,7 @@ pub async fn serve(
// Client and server connection ready now, move client to proxy
debug!(target: "lazymc::lobby", "Server connection ready, moving client to proxy");
route_proxy(inbound, outbound, config, server_buf);
route_proxy(inbound, outbound, server_buf);
return Ok(());
}
@ -157,21 +148,6 @@ pub async fn serve(
Ok(())
}
/// Kick client with a message.
///
/// Should close connection afterwards.
async fn kick(msg: &str, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
let packet = LoginDisconnect {
reason: Message::new(Payload::text(msg)),
};
let mut data = Vec::new();
packet.encode(&mut data).map_err(|_| ())?;
let response = RawPacket::new(proto::LOGIN_PACKET_ID_DISCONNECT, data).encode()?;
writer.write_all(&response).await.map_err(|_| ())
}
/// Respond to client with login success packet
// TODO: support online mode here
async fn respond_login_success(
@ -192,7 +168,7 @@ async fn respond_login_success(
let mut data = Vec::new();
packet.encode(&mut data).map_err(|_| ())?;
let response = RawPacket::new(proto::LOGIN_PACKET_ID_LOGIN_SUCCESS, data).encode()?;
let response = RawPacket::new(proto::packets::login::CLIENT_LOGIN_SUCCESS, data).encode()?;
writer.write_all(&response).await.map_err(|_| ())?;
Ok(())
@ -459,11 +435,7 @@ async fn keep_alive_loop(writer: &mut WriteHalf<'_>) -> Result<(), ()> {
///
/// During this stage we keep sending keep-alive and title packets to the client to keep it active.
// TODO: should we use some timeout in here, could be large?
async fn stage_wait<'a>(
config: Arc<Config>,
server: Arc<Server>,
writer: &mut WriteHalf<'a>,
) -> Result<(), ()> {
async fn stage_wait<'a>(server: Arc<Server>, writer: &mut WriteHalf<'a>) -> Result<(), ()> {
// Ensure server poll interval is less than keep alive interval
// We need to wait on the smallest interval in the following loop
assert!(
@ -473,7 +445,7 @@ async fn stage_wait<'a>(
select! {
a = keep_alive_loop(writer) => a,
b = wait_for_server(config, server) => b,
b = wait_for_server(server) => b,
}
}
@ -481,13 +453,13 @@ async fn stage_wait<'a>(
///
/// Returns `Ok(())` once the server is online, returns `Err(())` if waiting failed.
// TODO: go through this, use proper error messages
async fn wait_for_server<'a>(config: Arc<Config>, server: Arc<Server>) -> Result<(), ()> {
async fn wait_for_server<'a>(server: Arc<Server>) -> Result<(), ()> {
debug!(target: "lazymc::lobby", "Waiting on server...");
// Set up polling interval, get timeout
let mut poll_interval = time::interval(HOLD_POLL_INTERVAL);
let since = Instant::now();
let timeout = config.time.hold_client_for as u64;
let mut poll_interval = time::interval(SERVER_POLL_INTERVAL);
// let since = Instant::now();
// let timeout = config.time.hold_client_for as u64;
loop {
// TODO: wait for start signal over channel instead of polling
@ -528,10 +500,8 @@ async fn wait_for_server<'a>(config: Arc<Config>, server: Arc<Server>) -> Result
/// This will initialize the connection to the play state. Client details are used.
// TODO: clean this up
async fn connect_to_server(
real_client: Client,
client_info: ClientInfo,
config: &Config,
server: Arc<Server>,
) -> Result<(TcpStream, BytesMut), ()> {
// Open connection
// TODO: on connect fail, ping server and redirect to serve_status if offline
@ -555,7 +525,7 @@ async fn connect_to_server(
let mut data = Vec::new();
packet.encode(&mut data).map_err(|_| ())?;
let request = RawPacket::new(proto::HANDSHAKE_PACKET_ID_HANDSHAKE, data).encode()?;
let request = RawPacket::new(proto::packets::handshake::SERVER_HANDSHAKE, data).encode()?;
writer.write_all(&request).await.map_err(|_| ())?;
// Request login start
@ -566,7 +536,7 @@ async fn connect_to_server(
let mut data = Vec::new();
packet.encode(&mut data).map_err(|_| ())?;
let request = RawPacket::new(proto::LOGIN_PACKET_ID_LOGIN_START, data).encode()?;
let request = RawPacket::new(proto::packets::login::SERVER_LOGIN_START, data).encode()?;
writer.write_all(&request).await.map_err(|_| ())?;
// Incoming buffer
@ -574,7 +544,7 @@ async fn connect_to_server(
loop {
// Read packet from stream
let (packet, raw) = match proto::read_packet(&mut buf, &mut reader).await {
let (packet, _raw) = match proto::read_packet(&mut buf, &mut reader).await {
Ok(Some(packet)) => packet,
Ok(None) => break,
Err(_) => {
@ -587,7 +557,9 @@ async fn connect_to_server(
let client_state = tmp_client.state();
// Hijack login success
if client_state == ClientState::Login && packet.id == proto::LOGIN_PACKET_ID_LOGIN_SUCCESS {
if client_state == ClientState::Login
&& packet.id == proto::packets::login::CLIENT_LOGIN_SUCCESS
{
trace!(target: "lazymc::lobby", "Received login success from server connection, change to play mode");
// TODO: parse this packet to ensure it's fine
@ -627,14 +599,14 @@ async fn connect_to_server(
// TODO: do not drop error here, return Box<dyn Error>
// TODO: add timeout
async fn wait_for_server_join_game(
mut outbound: &mut TcpStream,
outbound: &mut TcpStream,
buf: &mut BytesMut,
) -> Result<JoinGame, ()> {
let (mut reader, mut writer) = outbound.split();
loop {
// Read packet from stream
let (packet, raw) = match proto::read_packet(buf, &mut reader).await {
let (packet, _raw) = match proto::read_packet(buf, &mut reader).await {
Ok(Some(packet)) => packet,
Ok(None) => break,
Err(_) => {
@ -675,12 +647,7 @@ async fn wait_for_server_join_game(
/// `inbound_queue` is used for data already received from the server, that needs to be pushed to
/// the client.
#[inline]
pub fn route_proxy(
inbound: TcpStream,
outbound: TcpStream,
config: Arc<Config>,
inbound_queue: BytesMut,
) {
pub fn route_proxy(inbound: TcpStream, outbound: TcpStream, inbound_queue: BytesMut) {
// When server is online, proxy all
let service = async move {
proxy::proxy_inbound_outbound_with_queue(inbound, outbound, &inbound_queue, &[])
@ -709,7 +676,7 @@ async fn drain_stream<'a>(reader: &mut ReadHalf<'a>) -> Result<(), ()> {
// TODO: stop if read < drain_buf.len() ?
Ok(read) if read == 0 => return Ok(()),
Err(err) if err.kind() == ErrorKind::WouldBlock => return Ok(()),
Ok(read) => continue,
Ok(_) => continue,
Err(err) => {
// TODO: remove after debug
dbg!("drain err", err);
@ -722,16 +689,16 @@ async fn drain_stream<'a>(reader: &mut ReadHalf<'a>) -> Result<(), ()> {
/// Read NBT CompoundTag from SNBT.
fn snbt_to_compound_tag(data: &str) -> CompoundTag {
use nbt::decode::read_compound_tag;
use quartz_nbt::io::{self, Flavor};
use quartz_nbt::io::{write_nbt, Flavor};
use quartz_nbt::snbt;
use std::io::Cursor;
// Parse SNBT data
let compound = snbt::parse(data).expect("failed to parse SNBT");
// Encode to binary
let mut binary = Vec::new();
io::write_nbt(&mut binary, None, &compound, Flavor::Uncompressed);
write_nbt(&mut binary, None, &compound, Flavor::Uncompressed)
.expect("failed to encode NBT CompoundTag as binary");
// Parse binary with usable NBT create
read_compound_tag(&mut &*binary).unwrap()

View File

@ -126,7 +126,7 @@ async fn send_handshake(
let mut packet = Vec::new();
handshake.encode(&mut packet).map_err(|_| ())?;
let raw = RawPacket::new(proto::HANDSHAKE_PACKET_ID_HANDSHAKE, packet)
let raw = RawPacket::new(proto::packets::handshake::SERVER_HANDSHAKE, packet)
.encode()
.map_err(|_| ())?;
stream.write_all(&raw).await.map_err(|_| ())?;
@ -136,7 +136,7 @@ async fn send_handshake(
/// Send status request.
async fn request_status(stream: &mut TcpStream) -> Result<(), ()> {
let raw = RawPacket::new(proto::STATUS_PACKET_ID_STATUS, vec![])
let raw = RawPacket::new(proto::packets::status::SERVER_STATUS, vec![])
.encode()
.map_err(|_| ())?;
stream.write_all(&raw).await.map_err(|_| ())?;
@ -151,7 +151,7 @@ async fn send_ping(stream: &mut TcpStream) -> Result<u64, ()> {
let mut packet = Vec::new();
ping.encode(&mut packet).map_err(|_| ())?;
let raw = RawPacket::new(proto::STATUS_PACKET_ID_PING, packet)
let raw = RawPacket::new(proto::packets::status::SERVER_PING, packet)
.encode()
.map_err(|_| ())?;
stream.write_all(&raw).await.map_err(|_| ())?;
@ -173,7 +173,7 @@ async fn wait_for_status(stream: &mut TcpStream) -> Result<ServerStatus, ()> {
};
// Catch status response
if packet.id == proto::STATUS_PACKET_ID_STATUS {
if packet.id == proto::packets::status::CLIENT_STATUS {
let status = StatusResponse::decode(&mut packet.data.as_slice()).map_err(|_| ())?;
return Ok(status.server_status);
}
@ -206,7 +206,7 @@ async fn wait_for_ping(stream: &mut TcpStream, token: u64) -> Result<(), ()> {
};
// Catch ping response
if packet.id == proto::STATUS_PACKET_ID_PING {
if packet.id == proto::packets::status::CLIENT_PING {
let ping = PingResponse::decode(&mut packet.data.as_slice()).map_err(|_| ())?;
// Ping token must match

View File

@ -9,51 +9,57 @@ 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.
/// Just something to default to when real server version isn't known or when no hint is specified
/// in the configuration.
///
/// Should be kept up-to-date with latest supported Minecraft version by lazymc.
pub const PROTO_DEFAULT_VERSION: &str = "1.17.1";
/// 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.
/// Just something to default to when real server version isn't known or when no hint is specified
/// in the configuration.
///
/// Should be kept up-to-date with latest supported Minecraft version by lazymc.
pub const PROTO_DEFAULT_PROTOCOL: u32 = 756;
/// 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;
/// Login state, disconnect packet ID.
pub const LOGIN_PACKET_ID_DISCONNECT: i32 = 0;
/// Login state, login success packet ID.
pub const LOGIN_PACKET_ID_LOGIN_SUCCESS: i32 = 2;
/// Minecraft protocol packet IDs.
#[allow(unused)]
pub mod packets {
pub mod handshake {
pub const SERVER_HANDSHAKE: i32 = 0;
}
pub mod status {
pub const CLIENT_STATUS: i32 = 0;
pub const CLIENT_PING: i32 = 1;
pub const SERVER_STATUS: i32 = 0;
pub const SERVER_PING: i32 = 1;
}
pub mod login {
pub const CLIENT_DISCONNECT: i32 = 0;
pub const CLIENT_LOGIN_SUCCESS: i32 = 2;
pub const SERVER_LOGIN_START: i32 = 0;
}
pub mod play {
pub const CLIENT_JOIN_GAME: i32 = 0x26;
pub const SERVER_CLIENT_SETTINGS: i32 = 0x05;
pub const SERVER_PLUGIN_MESSAGE: i32 = 0x0A;
pub const SERVER_PLAYER_POS_ROT: i32 = 0x12;
pub const SERVER_PLAYER_POS: i32 = 0x11;
pub const CLIENT_CHAT_MSG: i32 = 0x0F;
pub const CLIENT_PLUGIN_MESSAGE: i32 = 0x18;
pub const CLIENT_DISCONNECT: i32 = 0x1A;
pub const CLIENT_KEEP_ALIVE: i32 = 0x21;
pub const CLIENT_JOIN_GAME: i32 = 0x26;
pub const CLIENT_PLAYER_POS_LOOK: i32 = 0x38;
pub const CLIENT_RESPAWN: i32 = 0x3D;
pub const CLIENT_SET_TITLE_TEXT: i32 = 0x59;
pub const CLIENT_SET_TITLE_SUBTITLE: i32 = 0x57;
pub const CLIENT_SET_TITLE_TIMES: i32 = 0x5A;
pub const CLIENT_TIME_UPDATE: i32 = 0x58;
pub const CLIENT_CHAT_MSG: i32 = 0x0F;
pub const CLIENT_SPAWN_POS: i32 = 0x4B;
pub const CLIENT_DISCONNECT: i32 = 0x1A;
pub const CLIENT_PLUGIN_MESSAGE: i32 = 0x18;
pub const CLIENT_SET_TITLE_SUBTITLE: i32 = 0x57;
pub const CLIENT_TIME_UPDATE: i32 = 0x58;
pub const CLIENT_SET_TITLE_TEXT: i32 = 0x59;
pub const CLIENT_SET_TITLE_TIMES: i32 = 0x5A;
pub const SERVER_CLIENT_SETTINGS: i32 = 0x05;
pub const SERVER_PLUGIN_MESSAGE: i32 = 0x0A;
pub const SERVER_PLAYER_POS: i32 = 0x11;
pub const SERVER_PLAYER_POS_ROT: i32 = 0x12;
}
}

View File

@ -56,7 +56,9 @@ pub async fn serve(
let client_state = client.state();
// Hijack handshake
if client_state == ClientState::Handshake && packet.id == proto::STATUS_PACKET_ID_STATUS {
if client_state == ClientState::Handshake
&& packet.id == proto::packets::handshake::SERVER_HANDSHAKE
{
// Parse handshake
let handshake = match Handshake::decode(&mut packet.data.as_slice()) {
Ok(handshake) => handshake,
@ -90,7 +92,8 @@ pub async fn serve(
}
// Hijack server status packet
if client_state == ClientState::Status && packet.id == proto::STATUS_PACKET_ID_STATUS {
if client_state == ClientState::Status && packet.id == proto::packets::status::SERVER_STATUS
{
let server_status = server_status(&config, &server).await;
let packet = StatusResponse { server_status };
@ -104,13 +107,15 @@ pub async fn serve(
}
// Hijack ping packet
if client_state == ClientState::Status && packet.id == proto::STATUS_PACKET_ID_PING {
if client_state == ClientState::Status && packet.id == proto::packets::status::SERVER_PING {
writer.write_all(&raw).await.map_err(|_| ())?;
continue;
}
// Hijack login start
if client_state == ClientState::Login && packet.id == proto::LOGIN_PACKET_ID_LOGIN_START {
if client_state == ClientState::Login
&& packet.id == proto::packets::login::SERVER_LOGIN_START
{
// Try to get login username, update client info
// TODO: we should always parse this packet successfully
let username = LoginStart::decode(&mut packet.data.as_slice())
@ -311,7 +316,7 @@ async fn kick(msg: &str, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
let mut data = Vec::new();
packet.encode(&mut data).map_err(|_| ())?;
let response = RawPacket::new(proto::LOGIN_PACKET_ID_DISCONNECT, data).encode()?;
let response = RawPacket::new(proto::packets::login::CLIENT_DISCONNECT, data).encode()?;
writer.write_all(&response).await.map_err(|_| ())
}