Generic way to send/get packets
This commit is contained in:
parent
3279aeae23
commit
17d953fc0c
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -8,9 +8,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.42"
|
version = "0.1.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d"
|
checksum = "36ea56748e10732c49404c153638a15ec3d6211ec5ff35d9bb20e13b93576adf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -374,9 +374,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.60"
|
version = "1.0.64"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -13,7 +13,7 @@ serde_json = "1.0.59"
|
|||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
radix64 = "0.3.0"
|
radix64 = "0.3.0"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
async-trait = "0.1.42"
|
async-trait = "0.1.48"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
# colorful = "0.2.1"
|
# colorful = "0.2.1"
|
||||||
# ozelot = "0.9.0" # Ozelot 0.9.0 supports protocol version 578 (1.15.2)
|
# ozelot = "0.9.0" # Ozelot 0.9.0 supports protocol version 578 (1.15.2)
|
||||||
|
@ -21,10 +21,25 @@ pub mod functions {
|
|||||||
t.read_exact(&mut buffer).await?;
|
t.read_exact(&mut buffer).await?;
|
||||||
Ok(buffer[0])
|
Ok(buffer[0])
|
||||||
}
|
}
|
||||||
|
/// Read `l` bytes from the given `TcpStream`.
|
||||||
|
pub async fn read_bytes(t: &mut TcpStream, l: usize) -> tokio::io::Result<Vec<u8>> {
|
||||||
|
let mut buffer = vec![];
|
||||||
|
for _ in 0..l {
|
||||||
|
buffer.push(read_byte(t).await?);
|
||||||
|
}
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
/// Write a single byte to the given `TcpStream`.
|
/// Write a single byte to the given `TcpStream`.
|
||||||
pub async fn write_byte(t: &mut TcpStream, value: u8) -> tokio::io::Result<u8> {
|
pub async fn write_byte(t: &mut TcpStream, value: u8) -> tokio::io::Result<()> {
|
||||||
t.write(&[value]).await?;
|
t.write(&[value]).await?;
|
||||||
Ok(value)
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Write multiple bytes to the given `TcpStream`.
|
||||||
|
pub async fn write_bytes(t: &mut TcpStream, bytes: &[u8]) -> tokio::io::Result<()> {
|
||||||
|
for b in bytes {
|
||||||
|
write_byte(t, *b).await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
/// Take `l` bytes from the given `Vec<u8>`.
|
/// Take `l` bytes from the given `Vec<u8>`.
|
||||||
pub fn get_bytes(v: Vec<u8>, l: usize) -> Box<[u8]> {
|
pub fn get_bytes(v: Vec<u8>, l: usize) -> Box<[u8]> {
|
||||||
|
@ -128,8 +128,7 @@ impl NetworkClient {
|
|||||||
pub async fn update(&mut self, num_players: usize) -> tokio::io::Result<()> {
|
pub async fn update(&mut self, num_players: usize) -> tokio::io::Result<()> {
|
||||||
match self.state {
|
match self.state {
|
||||||
NetworkClientState::Handshake => {
|
NetworkClientState::Handshake => {
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
let handshake = self.get_packet::<Handshake>().await?;
|
||||||
let handshake = Handshake::read(&mut self.stream).await?;
|
|
||||||
// Minecraft versions 1.8 - 1.8.9 use protocol version 47.
|
// Minecraft versions 1.8 - 1.8.9 use protocol version 47.
|
||||||
let compatible_versions = handshake.protocol_version == 47;
|
let compatible_versions = handshake.protocol_version == 47;
|
||||||
let next_state = match handshake.next_state.into() {
|
let next_state = match handshake.next_state.into() {
|
||||||
@ -144,15 +143,14 @@ impl NetworkClient {
|
|||||||
logindisconnect.reason = MCChat {
|
logindisconnect.reason = MCChat {
|
||||||
text: MCString::from("Incompatible client! Server is on 1.8.9"),
|
text: MCString::from("Incompatible client! Server is on 1.8.9"),
|
||||||
};
|
};
|
||||||
logindisconnect.write(&mut self.stream).await?;
|
self.send_packet(logindisconnect).await?;
|
||||||
self.state = NetworkClientState::Disconnected;
|
self.state = NetworkClientState::Disconnected;
|
||||||
}
|
}
|
||||||
debug!("Got handshake: {:?}", handshake);
|
debug!("{:?}", handshake);
|
||||||
}
|
}
|
||||||
NetworkClientState::Status => {
|
NetworkClientState::Status => {
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
let statusrequest = self.get_packet::<StatusRequest>().await?;
|
||||||
let statusrequest = StatusRequest::read(&mut self.stream).await?;
|
debug!("{:?}", statusrequest);
|
||||||
debug!("Got status request: {:?}", statusrequest);
|
|
||||||
let mut statusresponse = StatusResponse::new();
|
let mut statusresponse = StatusResponse::new();
|
||||||
statusresponse.json_response = json!({
|
statusresponse.json_response = json!({
|
||||||
"version": {
|
"version": {
|
||||||
@ -176,20 +174,17 @@ impl NetworkClient {
|
|||||||
})
|
})
|
||||||
.to_string()
|
.to_string()
|
||||||
.into();
|
.into();
|
||||||
statusresponse.write(&mut self.stream).await?;
|
self.send_packet(statusresponse).await?;
|
||||||
debug!("Sending status response: StatusResponse");
|
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
let statusping = self.get_packet::<StatusPing>().await?;
|
||||||
let statusping = StatusPing::read(&mut self.stream).await?;
|
debug!("{:?}", statusping);
|
||||||
debug!("Got status ping: {:?}", statusping);
|
|
||||||
let mut statuspong = StatusPong::new();
|
let mut statuspong = StatusPong::new();
|
||||||
statuspong.payload = statusping.payload;
|
statuspong.payload = statusping.payload;
|
||||||
statuspong.write(&mut self.stream).await?;
|
self.send_packet(statuspong).await?;
|
||||||
debug!("Sending status pong: {:?}", statuspong);
|
|
||||||
self.state = NetworkClientState::Disconnected;
|
self.state = NetworkClientState::Disconnected;
|
||||||
}
|
}
|
||||||
NetworkClientState::Login => {
|
NetworkClientState::Login => {
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
let loginstart = self.get_packet::<LoginStart>().await?;
|
||||||
let loginstart = LoginStart::read(&mut self.stream).await?;
|
|
||||||
debug!("{:?}", loginstart);
|
debug!("{:?}", loginstart);
|
||||||
// Offline mode skips encryption and compression.
|
// Offline mode skips encryption and compression.
|
||||||
// TODO: Encryption and compression
|
// TODO: Encryption and compression
|
||||||
@ -198,26 +193,20 @@ impl NetworkClient {
|
|||||||
// TODO: Get uuid and username from Mojang servers.
|
// TODO: Get uuid and username from Mojang servers.
|
||||||
loginsuccess.uuid = "00000000-0000-3000-0000-000000000000".into();
|
loginsuccess.uuid = "00000000-0000-3000-0000-000000000000".into();
|
||||||
loginsuccess.username = loginstart.player_name;
|
loginsuccess.username = loginstart.player_name;
|
||||||
loginsuccess.write(&mut self.stream).await?;
|
|
||||||
debug!("{:?}", loginsuccess);
|
|
||||||
self.uuid = Some(loginsuccess.uuid.clone().into());
|
self.uuid = Some(loginsuccess.uuid.clone().into());
|
||||||
self.username = Some(loginsuccess.username.clone().into());
|
self.username = Some(loginsuccess.username.clone().into());
|
||||||
|
self.send_packet(loginsuccess).await?;
|
||||||
self.state = NetworkClientState::Play;
|
self.state = NetworkClientState::Play;
|
||||||
let joingame = JoinGame::new();
|
let joingame = JoinGame::new();
|
||||||
// TODO: Fill out `joingame` with actual information.
|
// TODO: Fill out `joingame` with actual information.
|
||||||
joingame.write(&mut self.stream).await?;
|
self.send_packet(joingame).await?;
|
||||||
debug!("{:?}", joingame);
|
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
let clientsettings = self.get_packet::<ClientSettings>().await?;
|
||||||
let clientsettings = ClientSettings::read(&mut self.stream).await?;
|
// TODO: Actually use client settings.
|
||||||
// TODO: Actualy use client settings.
|
|
||||||
debug!("{:?}", clientsettings);
|
debug!("{:?}", clientsettings);
|
||||||
|
|
||||||
// All good up to here.
|
|
||||||
|
|
||||||
let helditemchange = HeldItemChange::new();
|
let helditemchange = HeldItemChange::new();
|
||||||
// TODO: Retrieve selected slot from storage.
|
// TODO: Retrieve selected slot from storage.
|
||||||
helditemchange.write(&mut self.stream).await?;
|
self.send_packet(helditemchange).await?;
|
||||||
debug!("{:?}", helditemchange);
|
|
||||||
// TODO: S->C Declare Recipes (1.16?)
|
// TODO: S->C Declare Recipes (1.16?)
|
||||||
// TODO: S->C Tags (1.16?)
|
// TODO: S->C Tags (1.16?)
|
||||||
// TODO: S->C Entity Status (optional?)
|
// TODO: S->C Entity Status (optional?)
|
||||||
@ -226,8 +215,7 @@ impl NetworkClient {
|
|||||||
// TODO: S->C Player Position and Look
|
// TODO: S->C Player Position and Look
|
||||||
let playerpositionandlook = PlayerPositionAndLook::new();
|
let playerpositionandlook = PlayerPositionAndLook::new();
|
||||||
// TODO: Retrieve player position from storage.
|
// TODO: Retrieve player position from storage.
|
||||||
playerpositionandlook.write(&mut self.stream).await?;
|
self.send_packet(playerpositionandlook).await?;
|
||||||
debug!("{:?}", playerpositionandlook);
|
|
||||||
// TODO: S->C Player Info (Add Player action) (1.16?)
|
// TODO: S->C Player Info (Add Player action) (1.16?)
|
||||||
// TODO: S->C Player Info (Update latency action) (1.16?)
|
// TODO: S->C Player Info (Update latency action) (1.16?)
|
||||||
// TODO: S->C Update View Position (1.16?)
|
// TODO: S->C Update View Position (1.16?)
|
||||||
@ -236,8 +224,7 @@ impl NetworkClient {
|
|||||||
// TODO: S->C World Border
|
// TODO: S->C World Border
|
||||||
// TODO: S->C Spawn Position
|
// TODO: S->C Spawn Position
|
||||||
let spawnposition = SpawnPosition::new();
|
let spawnposition = SpawnPosition::new();
|
||||||
spawnposition.write(&mut self.stream).await?;
|
self.send_packet(spawnposition).await?;
|
||||||
debug!("{:?}", spawnposition);
|
|
||||||
// Send initial keep alive.
|
// Send initial keep alive.
|
||||||
self.send_chat_message("keep alive").await?;
|
self.send_chat_message("keep alive").await?;
|
||||||
self.keep_alive().await?;
|
self.keep_alive().await?;
|
||||||
@ -267,36 +254,56 @@ impl NetworkClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a generic packet to the client.
|
||||||
|
pub async fn send_packet<P: Into<Packet> + core::fmt::Debug>(
|
||||||
|
&mut self,
|
||||||
|
packet: P,
|
||||||
|
) -> tokio::io::Result<()> {
|
||||||
|
debug!("{:?}", packet);
|
||||||
|
Into::<Packet>::into(packet).write(&mut self.stream).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a generic packet from the network.
|
||||||
|
pub async fn get_packet<T: PacketCommon>(&mut self) -> tokio::io::Result<T> {
|
||||||
|
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
||||||
|
Ok(T::read(&mut self.stream).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send the client a message in chat.
|
||||||
async fn send_chat_message<C: Into<MCChat>>(&mut self, message: C) -> tokio::io::Result<()> {
|
async fn send_chat_message<C: Into<MCChat>>(&mut self, message: C) -> tokio::io::Result<()> {
|
||||||
let mut chatmessage = ClientboundChatMessage::new();
|
let mut chatmessage = ClientboundChatMessage::new();
|
||||||
chatmessage.text = message.into();
|
chatmessage.text = message.into();
|
||||||
chatmessage.write(&mut self.stream).await?;
|
self.send_packet(chatmessage).await?;
|
||||||
debug!("{:?}", chatmessage);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disconnect the client.
|
||||||
|
///
|
||||||
|
/// Sends `0x40 Disconnect` then waits 10 seconds before forcing the connection closed.
|
||||||
async fn disconnect(&mut self, reason: Option<&str>) -> tokio::io::Result<()> {
|
async fn disconnect(&mut self, reason: Option<&str>) -> tokio::io::Result<()> {
|
||||||
self.connected = false;
|
|
||||||
self.state = NetworkClientState::Disconnected;
|
|
||||||
// Send 0x40 Disconnect.
|
|
||||||
let mut disconnect = Disconnect::new();
|
let mut disconnect = Disconnect::new();
|
||||||
disconnect.reason.text = reason.unwrap_or("Disconnected").into();
|
disconnect.reason.text = reason.unwrap_or("Disconnected").into();
|
||||||
disconnect.write(&mut self.stream).await?;
|
self.send_packet(disconnect).await?;
|
||||||
debug!("{:?}", disconnect);
|
|
||||||
// Give the client 10 seconds to disconnect before forcing it.
|
// Give the client 10 seconds to disconnect before forcing it.
|
||||||
tokio::time::sleep(Duration::from_secs(10)).await;
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
self.force_disconnect();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Force disconnect the client by marking it for cleanup as disconnected.
|
||||||
|
async fn force_disconnect(&mut self) {
|
||||||
|
self.connected = false;
|
||||||
|
self.state = NetworkClientState::Disconnected;
|
||||||
|
}
|
||||||
|
|
||||||
/// Send a keep alive packet to the client.
|
/// Send a keep alive packet to the client.
|
||||||
async fn keep_alive(&mut self) -> tokio::io::Result<()> {
|
async fn keep_alive(&mut self) -> tokio::io::Result<()> {
|
||||||
// Keep alive ping to client.
|
// Keep alive ping to client.
|
||||||
let clientboundkeepalive = KeepAlivePing::new();
|
let clientboundkeepalive = KeepAlivePing::new();
|
||||||
clientboundkeepalive.write(&mut self.stream).await?;
|
self.send_packet(clientboundkeepalive).await?;
|
||||||
debug!("{:?}", clientboundkeepalive);
|
|
||||||
// Keep alive pong to server.
|
// Keep alive pong to server.
|
||||||
let (_packet_length, _packet_id) = read_packet_header(&mut self.stream).await?;
|
|
||||||
let serverboundkeepalive = KeepAlivePong::read(&mut self.stream).await?;
|
let serverboundkeepalive = self.get_packet::<KeepAlivePong>().await?;
|
||||||
debug!("{:?}", serverboundkeepalive);
|
debug!("{:?}", serverboundkeepalive);
|
||||||
self.last_keep_alive = Instant::now();
|
self.last_keep_alive = Instant::now();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::PacketCommon;
|
||||||
use crate::mctypes::*;
|
use crate::mctypes::*;
|
||||||
use crate::CONFIG;
|
use crate::CONFIG;
|
||||||
use std::convert::{Into, TryFrom};
|
use std::convert::{Into, TryFrom};
|
||||||
@ -23,18 +24,19 @@ impl TryFrom<Vec<u8>> for StatusResponse {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StatusResponse {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for StatusResponse {
|
||||||
|
fn new() -> Self {
|
||||||
StatusResponse {
|
StatusResponse {
|
||||||
json_response: MCString::from(""),
|
json_response: MCString::from(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &'_ mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &'_ mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut statusresponse = StatusResponse::new();
|
let mut statusresponse = StatusResponse::new();
|
||||||
statusresponse.json_response = MCString::read(t).await?;
|
statusresponse.json_response = MCString::read(t).await?;
|
||||||
Ok(statusresponse)
|
Ok(statusresponse)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &'_ mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &'_ mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -62,16 +64,17 @@ impl TryFrom<Vec<u8>> for StatusPong {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StatusPong {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for StatusPong {
|
||||||
|
fn new() -> Self {
|
||||||
StatusPong { payload: 0.into() }
|
StatusPong { payload: 0.into() }
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut statuspong = StatusPong::new();
|
let mut statuspong = StatusPong::new();
|
||||||
statuspong.payload = MCLong::read(t).await?;
|
statuspong.payload = MCLong::read(t).await?;
|
||||||
Ok(statuspong)
|
Ok(statuspong)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -101,20 +104,21 @@ impl TryFrom<Vec<u8>> for LoginSuccess {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LoginSuccess {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for LoginSuccess {
|
||||||
|
fn new() -> Self {
|
||||||
LoginSuccess {
|
LoginSuccess {
|
||||||
uuid: MCString::from(""),
|
uuid: MCString::from(""),
|
||||||
username: MCString::from(""),
|
username: MCString::from(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut loginsuccess = LoginSuccess::new();
|
let mut loginsuccess = LoginSuccess::new();
|
||||||
loginsuccess.uuid = MCString::read(t).await?;
|
loginsuccess.uuid = MCString::read(t).await?;
|
||||||
loginsuccess.username = MCString::read(t).await?;
|
loginsuccess.username = MCString::read(t).await?;
|
||||||
Ok(loginsuccess)
|
Ok(loginsuccess)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -142,22 +146,23 @@ impl TryFrom<Vec<u8>> for LoginDisconnect {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LoginDisconnect {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for LoginDisconnect {
|
||||||
|
fn new() -> Self {
|
||||||
LoginDisconnect {
|
LoginDisconnect {
|
||||||
reason: MCChat {
|
reason: MCChat {
|
||||||
text: MCString::from(""),
|
text: MCString::from(""),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut logindisconnect = LoginDisconnect::new();
|
let mut logindisconnect = LoginDisconnect::new();
|
||||||
logindisconnect.reason = MCChat {
|
logindisconnect.reason = MCChat {
|
||||||
text: MCString::read(t).await?,
|
text: MCString::read(t).await?,
|
||||||
};
|
};
|
||||||
Ok(logindisconnect)
|
Ok(logindisconnect)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -167,13 +172,13 @@ impl LoginDisconnect {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct JoinGame {
|
pub struct JoinGame {
|
||||||
entity_id: MCInt, // The player's Entity ID (EID)
|
pub entity_id: MCInt, // The player's Entity ID (EID)
|
||||||
gamemode: MCUnsignedByte, // 0: Survival, 1: Creative, 2: Adventure, 3: Spectator. Bit 3 (0x8) is the hardcore flag.
|
pub gamemode: MCUnsignedByte, // 0: Survival, 1: Creative, 2: Adventure, 3: Spectator. Bit 3 (0x8) is the hardcore flag.
|
||||||
dimension: MCByte, // -1: Nether, 0: Overworld, 1: End
|
pub dimension: MCByte, // -1: Nether, 0: Overworld, 1: End
|
||||||
difficulty: MCUnsignedByte, // 0: Peaceful, 1: Easy, 2: Normal, 3: Hard
|
pub difficulty: MCUnsignedByte, // 0: Peaceful, 1: Easy, 2: Normal, 3: Hard
|
||||||
max_players: MCUnsignedByte, // Used by the client to draw the player list
|
pub max_players: MCUnsignedByte, // Used by the client to draw the player list
|
||||||
level_type: MCString, // default, flat, largeBiomes, amplified, default_1_1
|
pub level_type: MCString, // default, flat, largeBiomes, amplified, default_1_1
|
||||||
reduced_debug_info: MCBoolean, // If true, a Notchian client shows reduced information on the debug screen.
|
pub reduced_debug_info: MCBoolean, // If true, a Notchian client shows reduced information on the debug screen.
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for JoinGame {
|
impl Into<Vec<u8>> for JoinGame {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -197,8 +202,9 @@ impl TryFrom<Vec<u8>> for JoinGame {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl JoinGame {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for JoinGame {
|
||||||
|
fn new() -> Self {
|
||||||
JoinGame {
|
JoinGame {
|
||||||
entity_id: 0.into(),
|
entity_id: 0.into(),
|
||||||
gamemode: 1.into(), // Default to creative mode.
|
gamemode: 1.into(), // Default to creative mode.
|
||||||
@ -209,7 +215,7 @@ impl JoinGame {
|
|||||||
reduced_debug_info: false.into(), // The debug info should be useful.
|
reduced_debug_info: false.into(), // The debug info should be useful.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut joingame = JoinGame::new();
|
let mut joingame = JoinGame::new();
|
||||||
joingame.entity_id = MCInt::read(t).await?;
|
joingame.entity_id = MCInt::read(t).await?;
|
||||||
joingame.gamemode = MCUnsignedByte::read(t).await?;
|
joingame.gamemode = MCUnsignedByte::read(t).await?;
|
||||||
@ -220,7 +226,7 @@ impl JoinGame {
|
|||||||
joingame.reduced_debug_info = MCBoolean::read(t).await?;
|
joingame.reduced_debug_info = MCBoolean::read(t).await?;
|
||||||
Ok(joingame)
|
Ok(joingame)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -230,7 +236,7 @@ impl JoinGame {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct HeldItemChange {
|
pub struct HeldItemChange {
|
||||||
selected_slot: MCByte,
|
pub selected_slot: MCByte,
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for HeldItemChange {
|
impl Into<Vec<u8>> for HeldItemChange {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -248,18 +254,19 @@ impl TryFrom<Vec<u8>> for HeldItemChange {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl HeldItemChange {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for HeldItemChange {
|
||||||
|
fn new() -> Self {
|
||||||
HeldItemChange {
|
HeldItemChange {
|
||||||
selected_slot: 0.into(),
|
selected_slot: 0.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut helditemchange = HeldItemChange::new();
|
let mut helditemchange = HeldItemChange::new();
|
||||||
helditemchange.selected_slot = MCByte::read(t).await?;
|
helditemchange.selected_slot = MCByte::read(t).await?;
|
||||||
Ok(helditemchange)
|
Ok(helditemchange)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -269,31 +276,31 @@ impl HeldItemChange {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct EntityStatus {
|
pub struct EntityStatus {
|
||||||
entity_id: MCInt,
|
pub entity_id: MCInt,
|
||||||
entity_status: MCByte, // See table below.
|
pub entity_status: MCByte, // See table below.
|
||||||
// 1: Sent when resetting a mob spawn minecart's timer / Rabbit jump animation
|
// 1: Sent when resetting a mob spawn minecart's timer / Rabbit jump animation
|
||||||
// 2: Living Entity hurt
|
// 2: Living Entity hurt
|
||||||
// 3: Living Entity dead
|
// 3: Living Entity dead
|
||||||
// 4: Iron Golem throwing up arms
|
// 4: Iron Golem throwing up arms
|
||||||
// 6: Wolf/Ocelot/Horse taming — Spawn “heart” particles
|
// 6: Wolf/Ocelot/Horse taming — Spawn “heart” particles
|
||||||
// 7: Wolf/Ocelot/Horse tamed — Spawn “smoke” particles
|
// 7: Wolf/Ocelot/Horse tamed — Spawn “smoke” particles
|
||||||
// 8: Wolf shaking water — Trigger the shaking animation
|
// 8: Wolf shaking water — Trigger the shaking animation
|
||||||
// 9: (of self) Eating accepted by server
|
// 9: (of self) Eating accepted by server
|
||||||
// 10: Sheep eating grass
|
// 10: Sheep eating grass
|
||||||
// 10: Play TNT ignite sound
|
// 10: Play TNT ignite sound
|
||||||
// 11: Iron Golem handing over a rose
|
// 11: Iron Golem handing over a rose
|
||||||
// 12: Villager mating — Spawn “heart” particles
|
// 12: Villager mating — Spawn “heart” particles
|
||||||
// 13: Spawn particles indicating that a villager is angry and seeking revenge
|
// 13: Spawn particles indicating that a villager is angry and seeking revenge
|
||||||
// 14: Spawn happy particles near a villager
|
// 14: Spawn happy particles near a villager
|
||||||
// 15: Witch animation — Spawn “magic” particles
|
// 15: Witch animation — Spawn “magic” particles
|
||||||
// 16: Play zombie converting into a villager sound
|
// 16: Play zombie converting into a villager sound
|
||||||
// 17: Firework exploding
|
// 17: Firework exploding
|
||||||
// 18: Animal in love (ready to mate) — Spawn “heart” particles
|
// 18: Animal in love (ready to mate) — Spawn “heart” particles
|
||||||
// 19: Reset squid rotation
|
// 19: Reset squid rotation
|
||||||
// 20: Spawn explosion particle — works for some living entities
|
// 20: Spawn explosion particle — works for some living entities
|
||||||
// 21: Play guardian sound — works for only for guardians
|
// 21: Play guardian sound — works for only for guardians
|
||||||
// 22: Enables reduced debug for players
|
// 22: Enables reduced debug for players
|
||||||
// 23: Disables reduced debug for players
|
// 23: Disables reduced debug for players
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for EntityStatus {
|
impl Into<Vec<u8>> for EntityStatus {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -312,20 +319,21 @@ impl TryFrom<Vec<u8>> for EntityStatus {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl EntityStatus {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for EntityStatus {
|
||||||
|
fn new() -> Self {
|
||||||
EntityStatus {
|
EntityStatus {
|
||||||
entity_id: 0.into(),
|
entity_id: 0.into(),
|
||||||
entity_status: 0.into(),
|
entity_status: 0.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut entitystatus = EntityStatus::new();
|
let mut entitystatus = EntityStatus::new();
|
||||||
entitystatus.entity_id = MCInt::read(t).await?;
|
entitystatus.entity_id = MCInt::read(t).await?;
|
||||||
entitystatus.entity_status = MCByte::read(t).await?;
|
entitystatus.entity_status = MCByte::read(t).await?;
|
||||||
Ok(entitystatus)
|
Ok(entitystatus)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -335,12 +343,12 @@ impl EntityStatus {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PlayerPositionAndLook {
|
pub struct PlayerPositionAndLook {
|
||||||
x: MCDouble,
|
pub x: MCDouble,
|
||||||
y: MCDouble,
|
pub y: MCDouble,
|
||||||
z: MCDouble,
|
pub z: MCDouble,
|
||||||
yaw: MCFloat,
|
pub yaw: MCFloat,
|
||||||
pitch: MCFloat,
|
pub pitch: MCFloat,
|
||||||
flags: MCByte,
|
pub flags: MCByte,
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for PlayerPositionAndLook {
|
impl Into<Vec<u8>> for PlayerPositionAndLook {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -363,8 +371,9 @@ impl TryFrom<Vec<u8>> for PlayerPositionAndLook {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PlayerPositionAndLook {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for PlayerPositionAndLook {
|
||||||
|
fn new() -> Self {
|
||||||
PlayerPositionAndLook {
|
PlayerPositionAndLook {
|
||||||
x: 0.0.into(),
|
x: 0.0.into(),
|
||||||
y: 0.0.into(),
|
y: 0.0.into(),
|
||||||
@ -374,7 +383,7 @@ impl PlayerPositionAndLook {
|
|||||||
flags: 0x00.into(),
|
flags: 0x00.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut playerpositionandlook = PlayerPositionAndLook::new();
|
let mut playerpositionandlook = PlayerPositionAndLook::new();
|
||||||
playerpositionandlook.x = MCDouble::read(t).await?;
|
playerpositionandlook.x = MCDouble::read(t).await?;
|
||||||
playerpositionandlook.y = MCDouble::read(t).await?;
|
playerpositionandlook.y = MCDouble::read(t).await?;
|
||||||
@ -384,7 +393,7 @@ impl PlayerPositionAndLook {
|
|||||||
playerpositionandlook.flags = MCByte::read(t).await?;
|
playerpositionandlook.flags = MCByte::read(t).await?;
|
||||||
Ok(playerpositionandlook)
|
Ok(playerpositionandlook)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -395,7 +404,7 @@ impl PlayerPositionAndLook {
|
|||||||
// TODO: Actually send the position.
|
// TODO: Actually send the position.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SpawnPosition {
|
pub struct SpawnPosition {
|
||||||
position: MCPosition,
|
pub position: MCPosition,
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for SpawnPosition {
|
impl Into<Vec<u8>> for SpawnPosition {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -414,18 +423,19 @@ impl TryFrom<Vec<u8>> for SpawnPosition {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl SpawnPosition {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for SpawnPosition {
|
||||||
|
fn new() -> Self {
|
||||||
SpawnPosition {
|
SpawnPosition {
|
||||||
position: MCPosition::new(),
|
position: MCPosition::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut spawnposition = SpawnPosition::new();
|
let mut spawnposition = SpawnPosition::new();
|
||||||
spawnposition.position = MCPosition::read(t).await?;
|
spawnposition.position = MCPosition::read(t).await?;
|
||||||
Ok(spawnposition)
|
Ok(spawnposition)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -435,7 +445,7 @@ impl SpawnPosition {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeepAlivePing {
|
pub struct KeepAlivePing {
|
||||||
payload: MCVarInt,
|
pub payload: MCVarInt,
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for KeepAlivePing {
|
impl Into<Vec<u8>> for KeepAlivePing {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -453,16 +463,17 @@ impl TryFrom<Vec<u8>> for KeepAlivePing {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl KeepAlivePing {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for KeepAlivePing {
|
||||||
|
fn new() -> Self {
|
||||||
KeepAlivePing { payload: 0.into() }
|
KeepAlivePing { payload: 0.into() }
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut keepalive = KeepAlivePing::new();
|
let mut keepalive = KeepAlivePing::new();
|
||||||
keepalive.payload = MCVarInt::read(t).await?;
|
keepalive.payload = MCVarInt::read(t).await?;
|
||||||
Ok(keepalive)
|
Ok(keepalive)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -490,20 +501,21 @@ impl TryFrom<Vec<u8>> for Disconnect {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Disconnect {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for Disconnect {
|
||||||
|
fn new() -> Self {
|
||||||
Disconnect {
|
Disconnect {
|
||||||
reason: MCChat {
|
reason: MCChat {
|
||||||
text: "Disconnected".into(),
|
text: "Disconnected".into(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut keepalive = Disconnect::new();
|
let mut keepalive = Disconnect::new();
|
||||||
keepalive.reason = MCChat::read(t).await?;
|
keepalive.reason = MCChat::read(t).await?;
|
||||||
Ok(keepalive)
|
Ok(keepalive)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -533,20 +545,21 @@ impl TryFrom<Vec<u8>> for ClientboundChatMessage {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ClientboundChatMessage {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for ClientboundChatMessage {
|
||||||
|
fn new() -> Self {
|
||||||
ClientboundChatMessage {
|
ClientboundChatMessage {
|
||||||
text: MCChat { text: "".into() },
|
text: MCChat { text: "".into() },
|
||||||
position: 0.into(),
|
position: 0.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut clientboundchatmessage = ClientboundChatMessage::new();
|
let mut clientboundchatmessage = ClientboundChatMessage::new();
|
||||||
clientboundchatmessage.text = MCChat::read(t).await?;
|
clientboundchatmessage.text = MCChat::read(t).await?;
|
||||||
clientboundchatmessage.position = MCByte::read(t).await?;
|
clientboundchatmessage.position = MCByte::read(t).await?;
|
||||||
Ok(clientboundchatmessage)
|
Ok(clientboundchatmessage)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ pub mod serverbound;
|
|||||||
|
|
||||||
use crate::mctypes::MCVarInt;
|
use crate::mctypes::MCVarInt;
|
||||||
pub use clientbound::*;
|
pub use clientbound::*;
|
||||||
|
use core::convert::TryFrom;
|
||||||
pub use serverbound::*;
|
pub use serverbound::*;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
@ -14,3 +15,82 @@ pub async fn read_packet_header(t: &mut TcpStream) -> tokio::io::Result<(MCVarIn
|
|||||||
let id = MCVarInt::read(t).await?;
|
let id = MCVarInt::read(t).await?;
|
||||||
Ok((length, id))
|
Ok((length, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A way to generically encode a packet.
|
||||||
|
macro_rules! register_packets {
|
||||||
|
($($name:ident),*) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Packet {
|
||||||
|
$($name($name),)*
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
impl Packet {
|
||||||
|
pub fn new() -> Packet {
|
||||||
|
Packet::Null
|
||||||
|
}
|
||||||
|
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
|
match self {
|
||||||
|
$(
|
||||||
|
Packet::$name(p) => p.write(t).await,
|
||||||
|
)*
|
||||||
|
Packet::Null => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$(
|
||||||
|
impl $name {
|
||||||
|
pub fn into_packet(&self) -> Packet {
|
||||||
|
Packet::$name(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<Packet> for $name {
|
||||||
|
fn into(self) -> Packet {
|
||||||
|
Packet::$name(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TryFrom<Packet> for $name {
|
||||||
|
type Error = &'static str;
|
||||||
|
fn try_from(p: Packet) -> Result<Self, Self::Error> {
|
||||||
|
match p {
|
||||||
|
Packet::$name(i) => Ok(i),
|
||||||
|
_ => Err("wrong kind"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register all the packets.
|
||||||
|
register_packets!(
|
||||||
|
// Clientbound.
|
||||||
|
StatusResponse,
|
||||||
|
StatusPong,
|
||||||
|
LoginSuccess,
|
||||||
|
LoginDisconnect,
|
||||||
|
JoinGame,
|
||||||
|
HeldItemChange,
|
||||||
|
EntityStatus,
|
||||||
|
PlayerPositionAndLook,
|
||||||
|
SpawnPosition,
|
||||||
|
KeepAlivePing,
|
||||||
|
Disconnect,
|
||||||
|
ClientboundChatMessage,
|
||||||
|
// Serverbound.
|
||||||
|
Handshake,
|
||||||
|
StatusRequest,
|
||||||
|
StatusPing,
|
||||||
|
LoginStart,
|
||||||
|
ClientSettings,
|
||||||
|
KeepAlivePong
|
||||||
|
);
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait PacketCommon
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
fn new() -> Self;
|
||||||
|
async fn read(t: &'_ mut TcpStream) -> tokio::io::Result<Self>;
|
||||||
|
async fn write(&self, t: &'_ mut TcpStream) -> tokio::io::Result<()>;
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::PacketCommon;
|
||||||
use crate::mctypes::*;
|
use crate::mctypes::*;
|
||||||
use std::convert::{Into, TryFrom};
|
use std::convert::{Into, TryFrom};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
@ -29,8 +30,9 @@ impl TryFrom<Vec<u8>> for Handshake {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Handshake {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for Handshake {
|
||||||
|
fn new() -> Self {
|
||||||
Handshake {
|
Handshake {
|
||||||
protocol_version: 0.into(),
|
protocol_version: 0.into(),
|
||||||
server_address: "".into(),
|
server_address: "".into(),
|
||||||
@ -38,7 +40,7 @@ impl Handshake {
|
|||||||
next_state: 0.into(),
|
next_state: 0.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut handshake = Handshake::new();
|
let mut handshake = Handshake::new();
|
||||||
handshake.protocol_version = MCVarInt::read(t).await?;
|
handshake.protocol_version = MCVarInt::read(t).await?;
|
||||||
handshake.server_address = MCString::read(t).await?;
|
handshake.server_address = MCString::read(t).await?;
|
||||||
@ -46,7 +48,7 @@ impl Handshake {
|
|||||||
handshake.next_state = MCVarInt::read(t).await?;
|
handshake.next_state = MCVarInt::read(t).await?;
|
||||||
Ok(handshake)
|
Ok(handshake)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -71,15 +73,16 @@ impl TryFrom<Vec<u8>> for StatusRequest {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StatusRequest {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for StatusRequest {
|
||||||
|
fn new() -> Self {
|
||||||
StatusRequest {}
|
StatusRequest {}
|
||||||
}
|
}
|
||||||
pub async fn read(_t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(_t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let statusrequest = StatusRequest::new();
|
let statusrequest = StatusRequest::new();
|
||||||
Ok(statusrequest)
|
Ok(statusrequest)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -107,16 +110,17 @@ impl TryFrom<Vec<u8>> for StatusPing {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl StatusPing {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for StatusPing {
|
||||||
|
fn new() -> Self {
|
||||||
StatusPing { payload: 0.into() }
|
StatusPing { payload: 0.into() }
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut statusping = StatusPing::new();
|
let mut statusping = StatusPing::new();
|
||||||
statusping.payload = MCLong::read(t).await?;
|
statusping.payload = MCLong::read(t).await?;
|
||||||
Ok(statusping)
|
Ok(statusping)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -144,18 +148,19 @@ impl TryFrom<Vec<u8>> for LoginStart {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl LoginStart {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for LoginStart {
|
||||||
|
fn new() -> Self {
|
||||||
LoginStart {
|
LoginStart {
|
||||||
player_name: "".into(),
|
player_name: "".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut loginstart = LoginStart::new();
|
let mut loginstart = LoginStart::new();
|
||||||
loginstart.player_name = MCString::read(t).await?;
|
loginstart.player_name = MCString::read(t).await?;
|
||||||
Ok(loginstart)
|
Ok(loginstart)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -199,8 +204,9 @@ impl TryFrom<Vec<u8>> for ClientSettings {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ClientSettings {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for ClientSettings {
|
||||||
|
fn new() -> Self {
|
||||||
ClientSettings {
|
ClientSettings {
|
||||||
locale: "en_US".into(),
|
locale: "en_US".into(),
|
||||||
view_distance: 8.into(), // 8 chunks.
|
view_distance: 8.into(), // 8 chunks.
|
||||||
@ -209,7 +215,7 @@ impl ClientSettings {
|
|||||||
displayed_skin_parts: 0xff.into(), // Enable all parts.
|
displayed_skin_parts: 0xff.into(), // Enable all parts.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut clientsettings = ClientSettings::new();
|
let mut clientsettings = ClientSettings::new();
|
||||||
clientsettings.locale = MCString::read(t).await?;
|
clientsettings.locale = MCString::read(t).await?;
|
||||||
clientsettings.view_distance = MCByte::read(t).await?;
|
clientsettings.view_distance = MCByte::read(t).await?;
|
||||||
@ -218,7 +224,7 @@ impl ClientSettings {
|
|||||||
clientsettings.displayed_skin_parts = MCUnsignedByte::read(t).await?;
|
clientsettings.displayed_skin_parts = MCUnsignedByte::read(t).await?;
|
||||||
Ok(clientsettings)
|
Ok(clientsettings)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
@ -228,7 +234,7 @@ impl ClientSettings {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeepAlivePong {
|
pub struct KeepAlivePong {
|
||||||
payload: MCVarInt,
|
pub payload: MCVarInt,
|
||||||
}
|
}
|
||||||
impl Into<Vec<u8>> for KeepAlivePong {
|
impl Into<Vec<u8>> for KeepAlivePong {
|
||||||
fn into(self) -> Vec<u8> {
|
fn into(self) -> Vec<u8> {
|
||||||
@ -246,16 +252,17 @@ impl TryFrom<Vec<u8>> for KeepAlivePong {
|
|||||||
Err("unimplemented")
|
Err("unimplemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl KeepAlivePong {
|
#[async_trait::async_trait]
|
||||||
pub fn new() -> Self {
|
impl PacketCommon for KeepAlivePong {
|
||||||
|
fn new() -> Self {
|
||||||
KeepAlivePong { payload: 0.into() }
|
KeepAlivePong { payload: 0.into() }
|
||||||
}
|
}
|
||||||
pub async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
async fn read(t: &mut TcpStream) -> tokio::io::Result<Self> {
|
||||||
let mut keepalive = KeepAlivePong::new();
|
let mut keepalive = KeepAlivePong::new();
|
||||||
keepalive.payload = MCVarInt::read(t).await?;
|
keepalive.payload = MCVarInt::read(t).await?;
|
||||||
Ok(keepalive)
|
Ok(keepalive)
|
||||||
}
|
}
|
||||||
pub async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
async fn write(&self, t: &mut TcpStream) -> tokio::io::Result<()> {
|
||||||
for b in Into::<Vec<u8>>::into(self.clone()) {
|
for b in Into::<Vec<u8>>::into(self.clone()) {
|
||||||
write_byte(t, b).await?;
|
write_byte(t, b).await?;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user