mirror of
https://github.com/timvisee/lazymc.git
synced 2025-05-19 12:50:23 -07:00
Extract all packet writing logic to single function
This commit is contained in:
parent
7df3829e00
commit
47fe7d0387
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -685,7 +685,7 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "minecraft-protocol"
|
name = "minecraft-protocol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=d26a525#d26a525c7b29b61d2db64805181fb5471ea4317a"
|
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=4e6a1f9#4e6a1f93807f35671943630c9bdc0d0c5da67eb8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"minecraft-protocol-derive",
|
"minecraft-protocol-derive",
|
||||||
@ -698,7 +698,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "minecraft-protocol-derive"
|
name = "minecraft-protocol-derive"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=d26a525#d26a525c7b29b61d2db64805181fb5471ea4317a"
|
source = "git+https://github.com/timvisee/rust-minecraft-protocol?rev=4e6a1f9#4e6a1f93807f35671943630c9bdc0d0c5da67eb8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -40,7 +40,7 @@ dotenv = "0.15"
|
|||||||
flate2 = { version = "1.0", default-features = false, features = ["default"] }
|
flate2 = { version = "1.0", default-features = false, features = ["default"] }
|
||||||
futures = { version = "0.3", default-features = false }
|
futures = { version = "0.3", default-features = false }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
minecraft-protocol = { git = "https://github.com/timvisee/rust-minecraft-protocol", rev = "d26a525" }
|
minecraft-protocol = { git = "https://github.com/timvisee/rust-minecraft-protocol", rev = "4e6a1f9" }
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
394
src/lobby.rs
394
src/lobby.rs
@ -8,15 +8,13 @@ use bytes::BytesMut;
|
|||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use minecraft_protocol::data::chat::{Message, Payload};
|
use minecraft_protocol::data::chat::{Message, Payload};
|
||||||
use minecraft_protocol::decoder::Decoder;
|
use minecraft_protocol::decoder::Decoder;
|
||||||
use minecraft_protocol::encoder::Encoder;
|
|
||||||
use minecraft_protocol::version::v1_14_4::handshake::Handshake;
|
use minecraft_protocol::version::v1_14_4::handshake::Handshake;
|
||||||
use minecraft_protocol::version::v1_14_4::login::{LoginStart, LoginSuccess, SetCompression};
|
use minecraft_protocol::version::v1_14_4::login::{LoginStart, LoginSuccess, SetCompression};
|
||||||
use minecraft_protocol::version::v1_17_1::game::{
|
use minecraft_protocol::version::v1_17_1::game::{
|
||||||
ClientBoundKeepAlive, JoinGame, NamedSoundEffect, PlayerPositionAndLook, PluginMessage,
|
ClientBoundKeepAlive, ClientBoundPluginMessage, JoinGame, NamedSoundEffect,
|
||||||
Respawn, SetTitleSubtitle, SetTitleText, SetTitleTimes, TimeUpdate,
|
PlayerPositionAndLook, Respawn, SetTitleSubtitle, SetTitleText, SetTitleTimes, TimeUpdate,
|
||||||
};
|
};
|
||||||
use nbt::CompoundTag;
|
use nbt::CompoundTag;
|
||||||
use tokio::io::AsyncWriteExt;
|
|
||||||
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
@ -28,8 +26,7 @@ use crate::mc;
|
|||||||
use crate::net;
|
use crate::net;
|
||||||
use crate::proto;
|
use crate::proto;
|
||||||
use crate::proto::client::{Client, ClientInfo, ClientState};
|
use crate::proto::client::{Client, ClientInfo, ClientState};
|
||||||
use crate::proto::packet::{self, RawPacket};
|
use crate::proto::{packet, packets};
|
||||||
use crate::proto::packets;
|
|
||||||
use crate::proxy;
|
use crate::proxy;
|
||||||
use crate::server::{Server, State};
|
use crate::server::{Server, State};
|
||||||
|
|
||||||
@ -185,15 +182,7 @@ async fn respond_set_compression(
|
|||||||
writer: &mut WriteHalf<'_>,
|
writer: &mut WriteHalf<'_>,
|
||||||
threshold: i32,
|
threshold: i32,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let packet = SetCompression { threshold };
|
packet::write_packet(SetCompression { threshold }, client, writer).await
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
|
||||||
|
|
||||||
let response = RawPacket::new(packets::login::CLIENT_SET_COMPRESSION, data).encode(client)?;
|
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Respond to client with login success packet
|
/// Respond to client with login success packet
|
||||||
@ -203,21 +192,18 @@ async fn respond_login_success(
|
|||||||
writer: &mut WriteHalf<'_>,
|
writer: &mut WriteHalf<'_>,
|
||||||
login_start: &LoginStart,
|
login_start: &LoginStart,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let packet = LoginSuccess {
|
packet::write_packet(
|
||||||
uuid: Uuid::new_v3(
|
LoginSuccess {
|
||||||
&Uuid::new_v3(&Uuid::nil(), b"OfflinePlayer"),
|
uuid: Uuid::new_v3(
|
||||||
login_start.name.as_bytes(),
|
&Uuid::new_v3(&Uuid::nil(), b"OfflinePlayer"),
|
||||||
),
|
login_start.name.as_bytes(),
|
||||||
username: login_start.name.clone(),
|
),
|
||||||
};
|
username: login_start.name.clone(),
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::login::CLIENT_LOGIN_SUCCESS, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Play lobby ready sound effect if configured.
|
/// Play lobby ready sound effect if configured.
|
||||||
@ -271,84 +257,75 @@ async fn send_lobby_join_game(
|
|||||||
server: &Server,
|
server: &Server,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
// Send Minecrafts default states, slightly customised for lobby world
|
// Send Minecrafts default states, slightly customised for lobby world
|
||||||
let packet = {
|
packet::write_packet(
|
||||||
let status = server.status().await;
|
{
|
||||||
|
let status = server.status().await;
|
||||||
|
|
||||||
JoinGame {
|
JoinGame {
|
||||||
// Player ID must be unique, if it collides with another server entity ID the player gets
|
// Player ID must be unique, if it collides with another server entity ID the player gets
|
||||||
// in a weird state and cannot move
|
// in a weird state and cannot move
|
||||||
entity_id: 0,
|
entity_id: 0,
|
||||||
// TODO: use real server value
|
// TODO: use real server value
|
||||||
hardcore: false,
|
hardcore: false,
|
||||||
game_mode: 3,
|
game_mode: 3,
|
||||||
previous_game_mode: -1i8 as u8,
|
previous_game_mode: -1i8 as u8,
|
||||||
world_names: vec![
|
world_names: vec![
|
||||||
"minecraft:overworld".into(),
|
"minecraft:overworld".into(),
|
||||||
"minecraft:the_nether".into(),
|
"minecraft:the_nether".into(),
|
||||||
"minecraft:the_end".into(),
|
"minecraft:the_end".into(),
|
||||||
],
|
],
|
||||||
dimension_codec: snbt_to_compound_tag(include_str!("../res/dimension_codec.snbt")),
|
dimension_codec: snbt_to_compound_tag(include_str!("../res/dimension_codec.snbt")),
|
||||||
dimension: snbt_to_compound_tag(include_str!("../res/dimension.snbt")),
|
dimension: snbt_to_compound_tag(include_str!("../res/dimension.snbt")),
|
||||||
world_name: "lazymc:lobby".into(),
|
world_name: "lazymc:lobby".into(),
|
||||||
hashed_seed: 0,
|
hashed_seed: 0,
|
||||||
max_players: status.as_ref().map(|s| s.players.max as i32).unwrap_or(20),
|
max_players: status.as_ref().map(|s| s.players.max as i32).unwrap_or(20),
|
||||||
// TODO: use real server value
|
// TODO: use real server value
|
||||||
view_distance: 10,
|
view_distance: 10,
|
||||||
// TODO: use real server value
|
// TODO: use real server value
|
||||||
reduced_debug_info: false,
|
reduced_debug_info: false,
|
||||||
// TODO: use real server value
|
// TODO: use real server value
|
||||||
enable_respawn_screen: true,
|
enable_respawn_screen: true,
|
||||||
is_debug: true,
|
is_debug: true,
|
||||||
is_flat: false,
|
is_flat: false,
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
client,
|
||||||
let mut data = Vec::new();
|
writer,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
)
|
||||||
|
.await
|
||||||
let response = RawPacket::new(packets::play::CLIENT_JOIN_GAME, data).encode(client)?;
|
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send lobby brand to client.
|
/// Send lobby brand to client.
|
||||||
async fn send_lobby_brand(client: &Client, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
async fn send_lobby_brand(client: &Client, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
||||||
let packet = PluginMessage {
|
packet::write_packet(
|
||||||
channel: "minecraft:brand".into(),
|
ClientBoundPluginMessage {
|
||||||
data: SERVER_BRAND.into(),
|
channel: "minecraft:brand".into(),
|
||||||
};
|
data: SERVER_BRAND.into(),
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_PLUGIN_MESSAGE, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send lobby player position to client.
|
/// Send lobby player position to client.
|
||||||
async fn send_lobby_player_pos(client: &Client, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
async fn send_lobby_player_pos(client: &Client, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
||||||
// Send player location, disables download terrain screen
|
// Send player location, disables download terrain screen
|
||||||
let packet = PlayerPositionAndLook {
|
packet::write_packet(
|
||||||
x: 0.0,
|
PlayerPositionAndLook {
|
||||||
y: 0.0,
|
x: 0.0,
|
||||||
z: 0.0,
|
y: 0.0,
|
||||||
yaw: 0.0,
|
z: 0.0,
|
||||||
pitch: 90.0,
|
yaw: 0.0,
|
||||||
flags: 0b00000000,
|
pitch: 90.0,
|
||||||
teleport_id: 0,
|
flags: 0b00000000,
|
||||||
dismount_vehicle: true,
|
teleport_id: 0,
|
||||||
};
|
dismount_vehicle: true,
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_PLAYER_POS_LOOK, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send lobby time update to client.
|
/// Send lobby time update to client.
|
||||||
@ -356,38 +333,32 @@ async fn send_lobby_time_update(client: &Client, writer: &mut WriteHalf<'_>) ->
|
|||||||
const MC_TIME_NOON: i64 = 6000;
|
const MC_TIME_NOON: i64 = 6000;
|
||||||
|
|
||||||
// Send time update, required once for keep-alive packets
|
// Send time update, required once for keep-alive packets
|
||||||
let packet = TimeUpdate {
|
packet::write_packet(
|
||||||
world_age: MC_TIME_NOON,
|
TimeUpdate {
|
||||||
time_of_day: MC_TIME_NOON,
|
world_age: MC_TIME_NOON,
|
||||||
};
|
time_of_day: MC_TIME_NOON,
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_TIME_UPDATE, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send keep alive packet to client.
|
/// Send keep alive packet to client.
|
||||||
///
|
///
|
||||||
/// Required periodically in play mode to prevent client timeout.
|
/// Required periodically in play mode to prevent client timeout.
|
||||||
async fn send_keep_alive(client: &Client, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
async fn send_keep_alive(client: &Client, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
||||||
let packet = ClientBoundKeepAlive {
|
packet::write_packet(
|
||||||
// Keep sending new IDs
|
ClientBoundKeepAlive {
|
||||||
id: KEEP_ALIVE_ID.fetch_add(1, Ordering::Relaxed),
|
// Keep sending new IDs
|
||||||
};
|
id: KEEP_ALIVE_ID.fetch_add(1, Ordering::Relaxed),
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_KEEP_ALIVE, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
// TODO: verify we receive keep alive response with same ID from client
|
// TODO: verify we receive keep alive response with same ID from client
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send lobby title packets to client.
|
/// Send lobby title packets to client.
|
||||||
@ -405,50 +376,45 @@ async fn send_lobby_title(
|
|||||||
let subtitle = text.lines().skip(1).collect::<Vec<_>>().join("\n");
|
let subtitle = text.lines().skip(1).collect::<Vec<_>>().join("\n");
|
||||||
|
|
||||||
// Set title
|
// Set title
|
||||||
let packet = SetTitleText {
|
packet::write_packet(
|
||||||
text: Message::new(Payload::text(title)),
|
SetTitleText {
|
||||||
};
|
text: Message::new(Payload::text(title)),
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_SET_TITLE_TEXT, data).encode(client)?;
|
.await?;
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
// Set subtitle
|
// Set subtitle
|
||||||
let packet = SetTitleSubtitle {
|
packet::write_packet(
|
||||||
text: Message::new(Payload::text(&subtitle)),
|
SetTitleSubtitle {
|
||||||
};
|
text: Message::new(Payload::text(&subtitle)),
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_SET_TITLE_SUBTITLE, data).encode(client)?;
|
.await?;
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
// Set title times
|
// Set title times
|
||||||
let packet = if title.is_empty() && subtitle.is_empty() {
|
packet::write_packet(
|
||||||
// Defaults: https://minecraft.fandom.com/wiki/Commands/title#Detail
|
if title.is_empty() && subtitle.is_empty() {
|
||||||
SetTitleTimes {
|
// Defaults: https://minecraft.fandom.com/wiki/Commands/title#Detail
|
||||||
fade_in: 10,
|
SetTitleTimes {
|
||||||
stay: 70,
|
fade_in: 10,
|
||||||
fade_out: 20,
|
stay: 70,
|
||||||
}
|
fade_out: 20,
|
||||||
} else {
|
}
|
||||||
SetTitleTimes {
|
} else {
|
||||||
fade_in: 0,
|
SetTitleTimes {
|
||||||
stay: KEEP_ALIVE_INTERVAL.as_secs() as i32 * mc::TICKS_PER_SECOND as i32 * 2,
|
fade_in: 0,
|
||||||
fade_out: 0,
|
stay: KEEP_ALIVE_INTERVAL.as_secs() as i32 * mc::TICKS_PER_SECOND as i32 * 2,
|
||||||
}
|
fade_out: 0,
|
||||||
};
|
}
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_SET_TITLE_TIMES, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send lobby ready sound effect to client.
|
/// Send lobby ready sound effect to client.
|
||||||
@ -457,23 +423,20 @@ async fn send_lobby_sound_effect(
|
|||||||
writer: &mut WriteHalf<'_>,
|
writer: &mut WriteHalf<'_>,
|
||||||
sound_name: &str,
|
sound_name: &str,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let packet = NamedSoundEffect {
|
packet::write_packet(
|
||||||
sound_name: sound_name.into(),
|
NamedSoundEffect {
|
||||||
sound_category: 0,
|
sound_name: sound_name.into(),
|
||||||
effect_pos_x: 0,
|
sound_category: 0,
|
||||||
effect_pos_y: 0,
|
effect_pos_x: 0,
|
||||||
effect_pos_z: 0,
|
effect_pos_y: 0,
|
||||||
volume: 1.0,
|
effect_pos_z: 0,
|
||||||
pitch: 1.0,
|
volume: 1.0,
|
||||||
};
|
pitch: 1.0,
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_NAMED_SOUND_EFFECT, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send respawn packet to client to jump from lobby into now loaded server.
|
/// Send respawn packet to client to jump from lobby into now loaded server.
|
||||||
@ -484,24 +447,21 @@ async fn send_respawn_from_join(
|
|||||||
writer: &mut WriteHalf<'_>,
|
writer: &mut WriteHalf<'_>,
|
||||||
join_game: JoinGame,
|
join_game: JoinGame,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let packet = Respawn {
|
packet::write_packet(
|
||||||
dimension: join_game.dimension,
|
Respawn {
|
||||||
world_name: join_game.world_name,
|
dimension: join_game.dimension,
|
||||||
hashed_seed: join_game.hashed_seed,
|
world_name: join_game.world_name,
|
||||||
game_mode: join_game.game_mode,
|
hashed_seed: join_game.hashed_seed,
|
||||||
previous_game_mode: join_game.previous_game_mode,
|
game_mode: join_game.game_mode,
|
||||||
is_debug: join_game.is_debug,
|
previous_game_mode: join_game.previous_game_mode,
|
||||||
is_flat: join_game.is_flat,
|
is_debug: join_game.is_debug,
|
||||||
copy_metadata: false,
|
is_flat: join_game.is_flat,
|
||||||
};
|
copy_metadata: false,
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
writer,
|
||||||
|
)
|
||||||
let response = RawPacket::new(packets::play::CLIENT_RESPAWN, data).encode(client)?;
|
.await
|
||||||
writer.write_all(&response).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An infinite keep-alive loop.
|
/// An infinite keep-alive loop.
|
||||||
@ -634,29 +594,27 @@ async fn connect_to_server_no_timeout(
|
|||||||
tmp_client.set_state(ClientState::Login);
|
tmp_client.set_state(ClientState::Login);
|
||||||
|
|
||||||
// Handshake packet
|
// Handshake packet
|
||||||
let packet = Handshake {
|
packet::write_packet(
|
||||||
protocol_version: client_info.protocol_version.unwrap(),
|
Handshake {
|
||||||
server_addr: config.server.address.ip().to_string(),
|
protocol_version: client_info.protocol_version.unwrap(),
|
||||||
server_port: config.server.address.port(),
|
server_addr: config.server.address.ip().to_string(),
|
||||||
next_state: ClientState::Login.to_id(),
|
server_port: config.server.address.port(),
|
||||||
};
|
next_state: ClientState::Login.to_id(),
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
&tmp_client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
&mut writer,
|
||||||
|
)
|
||||||
let request = RawPacket::new(packets::handshake::SERVER_HANDSHAKE, data).encode(&tmp_client)?;
|
.await?;
|
||||||
writer.write_all(&request).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
// Request login start
|
// Request login start
|
||||||
let packet = LoginStart {
|
packet::write_packet(
|
||||||
name: client_info.username.ok_or(())?,
|
LoginStart {
|
||||||
};
|
name: client_info.username.ok_or(())?,
|
||||||
|
},
|
||||||
let mut data = Vec::new();
|
&tmp_client,
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
&mut writer,
|
||||||
|
)
|
||||||
let request = RawPacket::new(packets::login::SERVER_LOGIN_START, data).encode(&tmp_client)?;
|
.await?;
|
||||||
writer.write_all(&request).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
// Incoming buffer
|
// Incoming buffer
|
||||||
let mut buf = BytesMut::new();
|
let mut buf = BytesMut::new();
|
||||||
|
@ -7,18 +7,17 @@ use std::time::Duration;
|
|||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use minecraft_protocol::data::server_status::ServerStatus;
|
use minecraft_protocol::data::server_status::ServerStatus;
|
||||||
use minecraft_protocol::decoder::Decoder;
|
use minecraft_protocol::decoder::Decoder;
|
||||||
use minecraft_protocol::encoder::Encoder;
|
|
||||||
use minecraft_protocol::version::v1_14_4::handshake::Handshake;
|
use minecraft_protocol::version::v1_14_4::handshake::Handshake;
|
||||||
use minecraft_protocol::version::v1_14_4::status::{PingRequest, PingResponse, StatusResponse};
|
use minecraft_protocol::version::v1_14_4::status::{
|
||||||
|
PingRequest, PingResponse, StatusRequest, StatusResponse,
|
||||||
|
};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use tokio::io::AsyncWriteExt;
|
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::proto::client::{Client, ClientState};
|
use crate::proto::client::{Client, ClientState};
|
||||||
use crate::proto::packet::{self, RawPacket};
|
use crate::proto::{packet, packets};
|
||||||
use crate::proto::packets;
|
|
||||||
use crate::server::{Server, State};
|
use crate::server::{Server, State};
|
||||||
|
|
||||||
/// Monitor ping inverval in seconds.
|
/// Monitor ping inverval in seconds.
|
||||||
@ -125,45 +124,28 @@ async fn send_handshake(
|
|||||||
config: &Config,
|
config: &Config,
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let handshake = Handshake {
|
packet::write_packet(
|
||||||
protocol_version: config.public.protocol as i32,
|
Handshake {
|
||||||
server_addr: addr.ip().to_string(),
|
protocol_version: config.public.protocol as i32,
|
||||||
server_port: addr.port(),
|
server_addr: addr.ip().to_string(),
|
||||||
next_state: ClientState::Status.to_id(),
|
server_port: addr.port(),
|
||||||
};
|
next_state: ClientState::Status.to_id(),
|
||||||
|
},
|
||||||
let mut packet = Vec::new();
|
client,
|
||||||
handshake.encode(&mut packet).map_err(|_| ())?;
|
&mut stream.split().1,
|
||||||
|
)
|
||||||
let raw = RawPacket::new(packets::handshake::SERVER_HANDSHAKE, packet)
|
.await
|
||||||
.encode(client)
|
|
||||||
.map_err(|_| ())?;
|
|
||||||
stream.write_all(&raw).await.map_err(|_| ())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send status request.
|
/// Send status request.
|
||||||
async fn request_status(client: &Client, stream: &mut TcpStream) -> Result<(), ()> {
|
async fn request_status(client: &Client, stream: &mut TcpStream) -> Result<(), ()> {
|
||||||
let raw = RawPacket::new(packets::status::SERVER_STATUS, vec![])
|
packet::write_packet(StatusRequest {}, client, &mut stream.split().1).await
|
||||||
.encode(client)
|
|
||||||
.map_err(|_| ())?;
|
|
||||||
stream.write_all(&raw).await.map_err(|_| ())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send status request.
|
/// Send status request.
|
||||||
async fn send_ping(client: &Client, stream: &mut TcpStream) -> Result<u64, ()> {
|
async fn send_ping(client: &Client, stream: &mut TcpStream) -> Result<u64, ()> {
|
||||||
let token = rand::thread_rng().gen();
|
let token = rand::thread_rng().gen();
|
||||||
let ping = PingRequest { time: token };
|
packet::write_packet(PingRequest { time: token }, client, &mut stream.split().1).await?;
|
||||||
|
|
||||||
let mut packet = Vec::new();
|
|
||||||
ping.encode(&mut packet).map_err(|_| ())?;
|
|
||||||
|
|
||||||
let raw = RawPacket::new(packets::status::SERVER_PING, packet)
|
|
||||||
.encode(client)
|
|
||||||
.map_err(|_| ())?;
|
|
||||||
stream.write_all(&raw).await.map_err(|_| ())?;
|
|
||||||
Ok(token)
|
Ok(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,51 +1,36 @@
|
|||||||
use minecraft_protocol::data::chat::{Message, Payload};
|
use minecraft_protocol::data::chat::{Message, Payload};
|
||||||
use minecraft_protocol::encoder::Encoder;
|
|
||||||
use minecraft_protocol::version::v1_14_4::game::GameDisconnect;
|
use minecraft_protocol::version::v1_14_4::game::GameDisconnect;
|
||||||
use minecraft_protocol::version::v1_14_4::login::LoginDisconnect;
|
use minecraft_protocol::version::v1_14_4::login::LoginDisconnect;
|
||||||
use tokio::io::AsyncWriteExt;
|
|
||||||
use tokio::net::tcp::WriteHalf;
|
use tokio::net::tcp::WriteHalf;
|
||||||
|
|
||||||
use crate::proto::client::{Client, ClientState};
|
use crate::proto::client::{Client, ClientState};
|
||||||
use crate::proto::packet::RawPacket;
|
use crate::proto::packet;
|
||||||
use crate::proto::packets;
|
|
||||||
|
|
||||||
/// Kick client with a message.
|
/// Kick client with a message.
|
||||||
///
|
///
|
||||||
/// Should close connection afterwards.
|
/// Should close connection afterwards.
|
||||||
pub async fn kick(client: &Client, msg: &str, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
pub async fn kick(client: &Client, msg: &str, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
||||||
match client.state() {
|
match client.state() {
|
||||||
ClientState::Login => login_kick(client, msg, writer).await,
|
ClientState::Login => {
|
||||||
ClientState::Play => play_kick(client, msg, writer).await,
|
packet::write_packet(
|
||||||
|
LoginDisconnect {
|
||||||
|
reason: Message::new(Payload::text(msg)),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
writer,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
ClientState::Play => {
|
||||||
|
packet::write_packet(
|
||||||
|
GameDisconnect {
|
||||||
|
reason: Message::new(Payload::text(msg)),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
writer,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kick client with a message in login state.
|
|
||||||
///
|
|
||||||
/// Should close connection afterwards.
|
|
||||||
async fn login_kick(client: &Client, 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(packets::login::CLIENT_DISCONNECT, data).encode(client)?;
|
|
||||||
writer.write_all(&response).await.map_err(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Kick client with a message in play state.
|
|
||||||
///
|
|
||||||
/// Should close connection afterwards.
|
|
||||||
async fn play_kick(client: &Client, msg: &str, writer: &mut WriteHalf<'_>) -> Result<(), ()> {
|
|
||||||
let packet = GameDisconnect {
|
|
||||||
reason: Message::new(Payload::text(msg)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut data = Vec::new();
|
|
||||||
packet.encode(&mut data).map_err(|_| ())?;
|
|
||||||
|
|
||||||
let response = RawPacket::new(packets::play::CLIENT_DISCONNECT, data).encode(client)?;
|
|
||||||
writer.write_all(&response).await.map_err(|_| ())
|
|
||||||
}
|
|
||||||
|
@ -4,9 +4,11 @@ use bytes::BytesMut;
|
|||||||
use flate2::read::ZlibDecoder;
|
use flate2::read::ZlibDecoder;
|
||||||
use flate2::write::ZlibEncoder;
|
use flate2::write::ZlibEncoder;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
|
use minecraft_protocol::encoder::Encoder;
|
||||||
|
use minecraft_protocol::version::PacketId;
|
||||||
use tokio::io;
|
use tokio::io;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::net::tcp::ReadHalf;
|
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||||
|
|
||||||
use crate::proto::client::Client;
|
use crate::proto::client::Client;
|
||||||
use crate::proto::BUF_SIZE;
|
use crate::proto::BUF_SIZE;
|
||||||
@ -197,3 +199,18 @@ pub async fn read_packet(
|
|||||||
|
|
||||||
Ok(Some((packet, raw.to_vec())))
|
Ok(Some((packet, raw.to_vec())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write packet to stream writer.
|
||||||
|
pub async fn write_packet(
|
||||||
|
packet: impl PacketId + Encoder,
|
||||||
|
client: &Client,
|
||||||
|
writer: &mut WriteHalf<'_>,
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let mut data = Vec::new();
|
||||||
|
packet.encode(&mut data).map_err(|_| ())?;
|
||||||
|
|
||||||
|
let response = RawPacket::new(packet.packet_id(), data).encode(client)?;
|
||||||
|
writer.write_all(&response).await.map_err(|_| ())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user