More Bedrock work
This commit is contained in:
parent
2d30f7af23
commit
637aada913
62
pumpkin-protocol/src/bedrock/ack.rs
Normal file
62
pumpkin-protocol/src/bedrock/ack.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use pumpkin_macros::packet;
|
||||||
|
|
||||||
|
use crate::{ClientPacket, codec::u24::U24, ser::NetworkWriteExt};
|
||||||
|
|
||||||
|
#[packet(0xC0)]
|
||||||
|
pub struct Ack {
|
||||||
|
sequences: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ack {
|
||||||
|
pub fn new(sequences: Vec<u32>) -> Self {
|
||||||
|
Self { sequences }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ack {
|
||||||
|
fn write_range(
|
||||||
|
start: u32,
|
||||||
|
end: u32,
|
||||||
|
mut write: impl std::io::Write,
|
||||||
|
) -> Result<(), crate::ser::WritingError> {
|
||||||
|
if start == end {
|
||||||
|
write.write_u8_be(1)?;
|
||||||
|
U24::encode(&U24(start), &mut write)?;
|
||||||
|
} else {
|
||||||
|
write.write_u8_be(0)?;
|
||||||
|
U24::encode(&U24(start), &mut write)?;
|
||||||
|
U24::encode(&U24(end), &mut write)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientPacket for Ack {
|
||||||
|
fn write_packet_data(
|
||||||
|
&self,
|
||||||
|
mut write: impl std::io::Write,
|
||||||
|
) -> Result<(), crate::ser::WritingError> {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
let mut start = self.sequences[0];
|
||||||
|
let mut end = start;
|
||||||
|
for seq in self.sequences.clone() {
|
||||||
|
if seq == end + 1 {
|
||||||
|
end = seq
|
||||||
|
} else {
|
||||||
|
Self::write_range(start, end, &mut buffer)?;
|
||||||
|
count += 1;
|
||||||
|
start = seq;
|
||||||
|
end = seq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::write_range(start, end, &mut buffer)?;
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
write.write_u16_be(count)?;
|
||||||
|
write.write_slice(&buffer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -1,3 +1 @@
|
|||||||
pub mod connection;
|
pub mod raknet;
|
||||||
pub mod open_connection;
|
|
||||||
pub mod unconnected_pong;
|
|
||||||
|
|||||||
34
pumpkin-protocol/src/bedrock/client/raknet/connection.rs
Normal file
34
pumpkin-protocol/src/bedrock/client/raknet/connection.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use crate::ser::network_serialize_no_prefix;
|
||||||
|
use pumpkin_macros::packet;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::codec::socket_address::SocketAddress;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[packet(0x10)]
|
||||||
|
pub struct CConnectionRequestAccepted {
|
||||||
|
client_address: SocketAddress,
|
||||||
|
system_index: u16,
|
||||||
|
#[serde(serialize_with = "network_serialize_no_prefix")]
|
||||||
|
system_addresses: Vec<SocketAddress>,
|
||||||
|
requested_timestamp: u64,
|
||||||
|
timestamp: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CConnectionRequestAccepted {
|
||||||
|
pub fn new(
|
||||||
|
client_address: SocketAddress,
|
||||||
|
system_index: u16,
|
||||||
|
system_addresses: Vec<SocketAddress>,
|
||||||
|
requested_timestamp: u64,
|
||||||
|
timestamp: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
client_address,
|
||||||
|
system_index,
|
||||||
|
system_addresses,
|
||||||
|
requested_timestamp,
|
||||||
|
timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
pumpkin-protocol/src/bedrock/client/raknet/mod.rs
Normal file
3
pumpkin-protocol/src/bedrock/client/raknet/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod connection;
|
||||||
|
pub mod open_connection;
|
||||||
|
pub mod unconnected_pong;
|
||||||
@ -28,6 +28,7 @@ impl COpenConnectionReply1 {
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[packet(0x08)]
|
#[packet(0x08)]
|
||||||
pub struct COpenConnectionReply2 {
|
pub struct COpenConnectionReply2 {
|
||||||
|
magic: [u8; 16],
|
||||||
server_guid: u64,
|
server_guid: u64,
|
||||||
client_address: SocketAddress,
|
client_address: SocketAddress,
|
||||||
mtu: u16,
|
mtu: u16,
|
||||||
@ -37,6 +38,7 @@ pub struct COpenConnectionReply2 {
|
|||||||
impl COpenConnectionReply2 {
|
impl COpenConnectionReply2 {
|
||||||
pub fn new(server_guid: u64, client_address: SocketAddress, mtu: u16, security: bool) -> Self {
|
pub fn new(server_guid: u64, client_address: SocketAddress, mtu: u16, security: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
magic: RAKNET_MAGIC,
|
||||||
server_guid,
|
server_guid,
|
||||||
client_address,
|
client_address,
|
||||||
mtu,
|
mtu,
|
||||||
131
pumpkin-protocol/src/bedrock/frame_set.rs
Normal file
131
pumpkin-protocol/src/bedrock/frame_set.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
use bytes::Bytes;
|
||||||
|
use pumpkin_macros::packet;
|
||||||
|
|
||||||
|
use crate::bedrock::{RAKNET_SPLIT, RakReliability};
|
||||||
|
use crate::codec::u24::U24;
|
||||||
|
use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
|
||||||
|
use crate::{ClientPacket, ServerPacket};
|
||||||
|
|
||||||
|
#[packet[0x80]]
|
||||||
|
pub struct FrameSet {
|
||||||
|
pub sequence: U24,
|
||||||
|
pub frames: Vec<Frame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerPacket for FrameSet {
|
||||||
|
fn read(mut read: impl std::io::Read) -> Result<Self, ReadingError> {
|
||||||
|
Ok(Self {
|
||||||
|
sequence: read.get_u24()?,
|
||||||
|
frames: Frame::read(read)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientPacket for FrameSet {
|
||||||
|
fn write_packet_data(&self, mut write: impl Write) -> Result<(), WritingError> {
|
||||||
|
write.write_u24_be(self.sequence)?;
|
||||||
|
for frame in &self.frames {
|
||||||
|
frame.write(&mut write)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Frame {
|
||||||
|
pub reliability: RakReliability,
|
||||||
|
pub payload: Bytes,
|
||||||
|
pub reliable_index: u32,
|
||||||
|
pub sequence_index: u32,
|
||||||
|
pub order_index: u32,
|
||||||
|
pub order_channel: u8,
|
||||||
|
pub split_size: u32,
|
||||||
|
pub split_id: u16,
|
||||||
|
pub split_index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
pub fn read(mut read: impl std::io::Read) -> Result<Vec<Self>, crate::ser::ReadingError> {
|
||||||
|
let mut frames = Vec::new();
|
||||||
|
|
||||||
|
while let Ok(header) = read.get_u8_be() {
|
||||||
|
let reliability_id = (header & 0xE0) >> 5;
|
||||||
|
let reliability = match RakReliability::from_id(reliability_id) {
|
||||||
|
Some(reliability) => reliability,
|
||||||
|
None => {
|
||||||
|
return Err(ReadingError::Message(format!(
|
||||||
|
"Invalid RakReliability {reliability_id}"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let split = (header & RAKNET_SPLIT) != 0;
|
||||||
|
let length = (read.get_u16_be()? as f32 / 8.0).ceil();
|
||||||
|
|
||||||
|
let reliable_index = if reliability.is_reliable() {
|
||||||
|
read.get_u24()?.0
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let sequence_index = if reliability.is_sequenced() {
|
||||||
|
read.get_u24()?.0
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let (order_index, order_channel) = if reliability.is_ordered() {
|
||||||
|
(read.get_u24()?.0, read.get_u8_be()?)
|
||||||
|
} else {
|
||||||
|
(0, 0)
|
||||||
|
};
|
||||||
|
let (split_size, split_id, split_index) = if split {
|
||||||
|
(read.get_u32_be()?, read.get_u16_be()?, read.get_u32_be()?)
|
||||||
|
} else {
|
||||||
|
(0, 0, 0)
|
||||||
|
};
|
||||||
|
let payload = read.read_boxed_slice(length as usize)?;
|
||||||
|
frames.push(Self {
|
||||||
|
reliability,
|
||||||
|
payload: payload.into(),
|
||||||
|
reliable_index,
|
||||||
|
sequence_index,
|
||||||
|
order_index,
|
||||||
|
order_channel,
|
||||||
|
split_size,
|
||||||
|
split_id,
|
||||||
|
split_index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(frames)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, mut write: impl Write) -> Result<(), WritingError> {
|
||||||
|
let is_split = self.split_size > 0;
|
||||||
|
write.write_u8_be(
|
||||||
|
(self.reliability.to_id() >> 5) & if is_split { RAKNET_SPLIT } else { 0 },
|
||||||
|
)?;
|
||||||
|
write.write_u16_be((self.payload.len() >> 3) as u16)?;
|
||||||
|
if self.reliability.is_reliable() {
|
||||||
|
write.write_u24_be(U24(self.reliable_index))?;
|
||||||
|
}
|
||||||
|
if self.reliability.is_sequenced() {
|
||||||
|
write.write_u24_be(U24(self.sequence_index))?;
|
||||||
|
}
|
||||||
|
if self.reliability.is_ordered() {
|
||||||
|
write.write_u24_be(U24(self.order_index))?;
|
||||||
|
write.write_u8_be(self.order_channel)?;
|
||||||
|
}
|
||||||
|
if is_split {
|
||||||
|
write.write_u32_be(self.split_size)?;
|
||||||
|
write.write_u16_be(self.split_id)?;
|
||||||
|
write.write_u32_be(self.split_index)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write.write_slice(&self.payload).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
|
pub mod ack;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
pub mod frame_set;
|
||||||
pub mod packet_decoder;
|
pub mod packet_decoder;
|
||||||
pub mod packet_encoder;
|
pub mod packet_encoder;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
@ -6,3 +8,85 @@ pub mod server;
|
|||||||
pub const RAKNET_MAGIC: [u8; 16] = [
|
pub const RAKNET_MAGIC: [u8; 16] = [
|
||||||
0x00, 0xff, 0xff, 0x0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0x12, 0x34, 0x56, 0x78,
|
0x00, 0xff, 0xff, 0x0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0x12, 0x34, 0x56, 0x78,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const RAKNET_VALID: u8 = 0x80;
|
||||||
|
pub const RAKNET_ACK: u8 = 0xC0;
|
||||||
|
pub const RAKNET_NACK: u8 = 0xA0;
|
||||||
|
pub const RAKNET_SPLIT: u8 = 0x10;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
|
||||||
|
pub enum RakReliability {
|
||||||
|
Unreliable,
|
||||||
|
UnreliableSequenced,
|
||||||
|
Reliable,
|
||||||
|
#[default]
|
||||||
|
ReliableOrdered,
|
||||||
|
ReliableSequenced,
|
||||||
|
UnreliableWithAckReceipt,
|
||||||
|
ReliableWithAckReceipt,
|
||||||
|
ReliableOrderedWithAckReceipt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RakReliability {
|
||||||
|
pub fn is_reliable(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
RakReliability::Reliable
|
||||||
|
| RakReliability::ReliableOrdered
|
||||||
|
| RakReliability::ReliableSequenced
|
||||||
|
| RakReliability::ReliableWithAckReceipt
|
||||||
|
| RakReliability::ReliableOrderedWithAckReceipt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_sequenced(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
RakReliability::ReliableSequenced | RakReliability::UnreliableSequenced
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_ordered(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
RakReliability::UnreliableSequenced
|
||||||
|
| RakReliability::ReliableOrdered
|
||||||
|
| RakReliability::ReliableSequenced
|
||||||
|
| RakReliability::ReliableOrderedWithAckReceipt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_order_exclusive(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
RakReliability::ReliableOrdered | RakReliability::ReliableOrderedWithAckReceipt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_id(id: u8) -> Option<Self> {
|
||||||
|
match id {
|
||||||
|
0 => Some(RakReliability::Unreliable),
|
||||||
|
1 => Some(RakReliability::UnreliableSequenced),
|
||||||
|
2 => Some(RakReliability::Reliable),
|
||||||
|
3 => Some(RakReliability::ReliableOrdered),
|
||||||
|
4 => Some(RakReliability::ReliableSequenced),
|
||||||
|
5 => Some(RakReliability::UnreliableWithAckReceipt),
|
||||||
|
6 => Some(RakReliability::ReliableWithAckReceipt),
|
||||||
|
7 => Some(RakReliability::ReliableOrderedWithAckReceipt),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_id(&self) -> u8 {
|
||||||
|
match self {
|
||||||
|
RakReliability::Unreliable => 0,
|
||||||
|
RakReliability::UnreliableSequenced => 1,
|
||||||
|
RakReliability::Reliable => 2,
|
||||||
|
RakReliability::ReliableOrdered => 3,
|
||||||
|
RakReliability::ReliableSequenced => 4,
|
||||||
|
RakReliability::UnreliableWithAckReceipt => 5,
|
||||||
|
RakReliability::ReliableWithAckReceipt => 6,
|
||||||
|
RakReliability::ReliableOrderedWithAckReceipt => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use async_compression::tokio::bufread::ZlibDecoder;
|
use async_compression::tokio::bufread::ZlibDecoder;
|
||||||
use bytes::Buf;
|
use bytes::Bytes;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, BufReader};
|
use tokio::io::{AsyncRead, AsyncReadExt, BufReader};
|
||||||
|
|
||||||
use crate::{Aes128Cfb8Dec, CompressionThreshold, PacketDecodeError, RawPacket, StreamDecryptor};
|
use crate::{Aes128Cfb8Dec, CompressionThreshold, PacketDecodeError, StreamDecryptor};
|
||||||
|
|
||||||
// decrypt -> decompress -> raw
|
// decrypt -> decompress -> raw
|
||||||
pub enum DecompressionReader<R: AsyncRead + Unpin> {
|
pub enum DecompressionReader<R: AsyncRead + Unpin> {
|
||||||
@ -97,26 +97,16 @@ impl UDPNetworkDecoder {
|
|||||||
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_raw_packet(
|
pub async fn get_packet_payload(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut reader: Cursor<Vec<u8>>,
|
mut reader: Cursor<Vec<u8>>,
|
||||||
) -> Result<RawPacket, PacketDecodeError> {
|
) -> Result<Bytes, PacketDecodeError> {
|
||||||
// TODO: Serde is sync so we need to write to a buffer here :(
|
|
||||||
// Is there a way to deserialize in an asynchronous manner?
|
|
||||||
|
|
||||||
let packet_id = reader
|
|
||||||
.try_get_u8()
|
|
||||||
.map_err(|_| PacketDecodeError::DecodeID)?;
|
|
||||||
|
|
||||||
let mut payload = Vec::new();
|
let mut payload = Vec::new();
|
||||||
reader
|
reader
|
||||||
.read_to_end(&mut payload)
|
.read_to_end(&mut payload)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
||||||
|
|
||||||
Ok(RawPacket {
|
Ok(payload.into())
|
||||||
id: packet_id as i32,
|
|
||||||
payload: payload.into(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
use pumpkin_macros::packet;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[packet(0x09)]
|
|
||||||
pub struct SConnectionRequest {
|
|
||||||
pub client_guid: u64,
|
|
||||||
pub time: u64,
|
|
||||||
pub security: bool,
|
|
||||||
}
|
|
||||||
@ -1,3 +1 @@
|
|||||||
pub mod connection;
|
pub mod raknet;
|
||||||
pub mod open_connection;
|
|
||||||
pub mod unconnected_ping;
|
|
||||||
|
|||||||
25
pumpkin-protocol/src/bedrock/server/raknet/connection.rs
Normal file
25
pumpkin-protocol/src/bedrock/server/raknet/connection.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use pumpkin_macros::packet;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::codec::socket_address::SocketAddress;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[packet(0x09)]
|
||||||
|
pub struct SConnectionRequest {
|
||||||
|
pub client_guid: u64,
|
||||||
|
pub time: u64,
|
||||||
|
pub security: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[packet(0x13)]
|
||||||
|
pub struct SNewIncomingConnection {
|
||||||
|
pub server_address: SocketAddress,
|
||||||
|
pub internal_address: SocketAddress,
|
||||||
|
pub ping_time: u64,
|
||||||
|
pub pong_time: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[packet(0x15)]
|
||||||
|
pub struct SDisconnect;
|
||||||
3
pumpkin-protocol/src/bedrock/server/raknet/mod.rs
Normal file
3
pumpkin-protocol/src/bedrock/server/raknet/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod connection;
|
||||||
|
pub mod open_connection;
|
||||||
|
pub mod unconnected_ping;
|
||||||
@ -2,5 +2,6 @@ pub mod ascii_string;
|
|||||||
pub mod bit_set;
|
pub mod bit_set;
|
||||||
pub mod item_stack_seralizer;
|
pub mod item_stack_seralizer;
|
||||||
pub mod socket_address;
|
pub mod socket_address;
|
||||||
|
pub mod u24;
|
||||||
pub mod var_int;
|
pub mod var_int;
|
||||||
pub mod var_long;
|
pub mod var_long;
|
||||||
|
|||||||
64
pumpkin-protocol/src/codec/u24.rs
Normal file
64
pumpkin-protocol/src/codec/u24.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
|
||||||
|
use serde::{
|
||||||
|
Deserialize,
|
||||||
|
de::{self, SeqAccess},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct U24(pub u32);
|
||||||
|
|
||||||
|
impl U24 {
|
||||||
|
pub fn decode(read: &mut impl Read) -> Result<Self, ReadingError> {
|
||||||
|
let a = read.get_u8_le()?;
|
||||||
|
let b = read.get_u8_le()?;
|
||||||
|
let c = read.get_u8_le()?;
|
||||||
|
Ok(U24(u32::from_le_bytes([a, b, c, 0])))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode(&self, write: &mut impl Write) -> Result<(), WritingError> {
|
||||||
|
let data = self.0 & 0xFFFFFF; // Get the internal u32 value
|
||||||
|
write.write_u8_be((data & 0xFF) as u8)?;
|
||||||
|
write.write_u8_be(((data >> 8) & 0xFF) as u8)?;
|
||||||
|
write.write_u8_be(((data >> 16) & 0xFF) as u8)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for U24 {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct Visitor;
|
||||||
|
impl<'de> de::Visitor<'de> for Visitor {
|
||||||
|
type Value = U24;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("a valid u24")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut data: u32 = 0;
|
||||||
|
|
||||||
|
// Read the first byte (LSB)
|
||||||
|
data |= seq.next_element::<u8>()?.unwrap() as u32;
|
||||||
|
|
||||||
|
// Read the second byte and shift it by 8 bits
|
||||||
|
data |= (seq.next_element::<u8>()?.unwrap() as u32) << 8;
|
||||||
|
|
||||||
|
// Read the third next_element and shift it by 16 bits
|
||||||
|
data |= (seq.next_element::<u8>()?.unwrap() as u32) << 16;
|
||||||
|
|
||||||
|
// Mask to ensure only the lower 24 bits are kept
|
||||||
|
Ok(U24(data & 0xFFFFFF))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_seq(Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ use std::io::{Read, Write};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FixedBitSet,
|
FixedBitSet,
|
||||||
codec::{bit_set::BitSet, var_int::VarInt, var_long::VarLong},
|
codec::{bit_set::BitSet, u24::U24, var_int::VarInt, var_long::VarLong},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod deserializer;
|
pub mod deserializer;
|
||||||
@ -48,6 +48,8 @@ pub enum WritingError {
|
|||||||
pub trait NetworkReadExt {
|
pub trait NetworkReadExt {
|
||||||
fn get_i8_be(&mut self) -> Result<i8, ReadingError>;
|
fn get_i8_be(&mut self) -> Result<i8, ReadingError>;
|
||||||
fn get_u8_be(&mut self) -> Result<u8, ReadingError>;
|
fn get_u8_be(&mut self) -> Result<u8, ReadingError>;
|
||||||
|
fn get_u8_le(&mut self) -> Result<u8, ReadingError>;
|
||||||
|
|
||||||
fn get_i16_be(&mut self) -> Result<i16, ReadingError>;
|
fn get_i16_be(&mut self) -> Result<i16, ReadingError>;
|
||||||
fn get_u16_be(&mut self) -> Result<u16, ReadingError>;
|
fn get_u16_be(&mut self) -> Result<u16, ReadingError>;
|
||||||
fn get_i32_be(&mut self) -> Result<i32, ReadingError>;
|
fn get_i32_be(&mut self) -> Result<i32, ReadingError>;
|
||||||
@ -63,6 +65,7 @@ pub trait NetworkReadExt {
|
|||||||
fn read_remaining_to_boxed_slice(&mut self, bound: usize) -> Result<Box<[u8]>, ReadingError>;
|
fn read_remaining_to_boxed_slice(&mut self, bound: usize) -> Result<Box<[u8]>, ReadingError>;
|
||||||
|
|
||||||
fn get_bool(&mut self) -> Result<bool, ReadingError>;
|
fn get_bool(&mut self) -> Result<bool, ReadingError>;
|
||||||
|
fn get_u24(&mut self) -> Result<U24, ReadingError>;
|
||||||
fn get_var_int(&mut self) -> Result<VarInt, ReadingError>;
|
fn get_var_int(&mut self) -> Result<VarInt, ReadingError>;
|
||||||
fn get_var_long(&mut self) -> Result<VarLong, ReadingError>;
|
fn get_var_long(&mut self) -> Result<VarLong, ReadingError>;
|
||||||
fn get_string_bounded(&mut self, bound: usize) -> Result<String, ReadingError>;
|
fn get_string_bounded(&mut self, bound: usize) -> Result<String, ReadingError>;
|
||||||
@ -100,6 +103,14 @@ impl<R: Read> NetworkReadExt for R {
|
|||||||
Ok(u8::from_be_bytes(buf))
|
Ok(u8::from_be_bytes(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_u8_le(&mut self) -> Result<u8, ReadingError> {
|
||||||
|
let mut buf = [0u8];
|
||||||
|
self.read_exact(&mut buf)
|
||||||
|
.map_err(|err| ReadingError::Incomplete(err.to_string()))?;
|
||||||
|
|
||||||
|
Ok(u8::from_le_bytes(buf))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_i16_be(&mut self) -> Result<i16, ReadingError> {
|
fn get_i16_be(&mut self) -> Result<i16, ReadingError> {
|
||||||
let mut buf = [0u8; 2];
|
let mut buf = [0u8; 2];
|
||||||
self.read_exact(&mut buf)
|
self.read_exact(&mut buf)
|
||||||
@ -116,6 +127,10 @@ impl<R: Read> NetworkReadExt for R {
|
|||||||
Ok(u16::from_be_bytes(buf))
|
Ok(u16::from_be_bytes(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_u24(&mut self) -> Result<U24, ReadingError> {
|
||||||
|
U24::decode(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_i32_be(&mut self) -> Result<i32, ReadingError> {
|
fn get_i32_be(&mut self) -> Result<i32, ReadingError> {
|
||||||
let mut buf = [0u8; 4];
|
let mut buf = [0u8; 4];
|
||||||
self.read_exact(&mut buf)
|
self.read_exact(&mut buf)
|
||||||
@ -289,6 +304,7 @@ pub trait NetworkWriteExt {
|
|||||||
fn write_u8_be(&mut self, data: u8) -> Result<(), WritingError>;
|
fn write_u8_be(&mut self, data: u8) -> Result<(), WritingError>;
|
||||||
fn write_i16_be(&mut self, data: i16) -> Result<(), WritingError>;
|
fn write_i16_be(&mut self, data: i16) -> Result<(), WritingError>;
|
||||||
fn write_u16_be(&mut self, data: u16) -> Result<(), WritingError>;
|
fn write_u16_be(&mut self, data: u16) -> Result<(), WritingError>;
|
||||||
|
fn write_u24_be(&mut self, data: U24) -> Result<(), WritingError>;
|
||||||
fn write_i32_be(&mut self, data: i32) -> Result<(), WritingError>;
|
fn write_i32_be(&mut self, data: i32) -> Result<(), WritingError>;
|
||||||
fn write_u32_be(&mut self, data: u32) -> Result<(), WritingError>;
|
fn write_u32_be(&mut self, data: u32) -> Result<(), WritingError>;
|
||||||
fn write_i64_be(&mut self, data: i64) -> Result<(), WritingError>;
|
fn write_i64_be(&mut self, data: i64) -> Result<(), WritingError>;
|
||||||
@ -371,6 +387,10 @@ impl<W: Write> NetworkWriteExt for W {
|
|||||||
.map_err(WritingError::IoError)
|
.map_err(WritingError::IoError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_u24_be(&mut self, data: U24) -> Result<(), WritingError> {
|
||||||
|
data.encode(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn write_i32_be(&mut self, data: i32) -> Result<(), WritingError> {
|
fn write_i32_be(&mut self, data: i32) -> Result<(), WritingError> {
|
||||||
self.write_all(&data.to_be_bytes())
|
self.write_all(&data.to_be_bytes())
|
||||||
.map_err(WritingError::IoError)
|
.map_err(WritingError::IoError)
|
||||||
|
|||||||
34
pumpkin/src/net/bedrock/connection.rs
Normal file
34
pumpkin/src/net/bedrock/connection.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use std::{net::SocketAddr, time::UNIX_EPOCH};
|
||||||
|
|
||||||
|
use pumpkin_protocol::{
|
||||||
|
bedrock::{
|
||||||
|
RakReliability, client::raknet::connection::CConnectionRequestAccepted,
|
||||||
|
server::raknet::connection::SConnectionRequest,
|
||||||
|
},
|
||||||
|
codec::socket_address::SocketAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::net::{Client, bedrock::BedrockClientPlatform};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn handle_connection_request(
|
||||||
|
&self,
|
||||||
|
bedrock: &BedrockClientPlatform,
|
||||||
|
packet: SConnectionRequest,
|
||||||
|
) {
|
||||||
|
dbg!("send connection accepted");
|
||||||
|
bedrock
|
||||||
|
.send_framed_packet(
|
||||||
|
self,
|
||||||
|
&CConnectionRequestAccepted::new(
|
||||||
|
SocketAddress(*self.address.lock().await),
|
||||||
|
0,
|
||||||
|
vec![],
|
||||||
|
packet.time,
|
||||||
|
UNIX_EPOCH.elapsed().unwrap().as_millis() as u64,
|
||||||
|
),
|
||||||
|
RakReliability::Unreliable,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,25 +1,34 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{Cursor, Write},
|
io::{Cursor, Write},
|
||||||
sync::Arc,
|
sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{AtomicBool, AtomicU32, Ordering},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
ClientPacket, PacketDecodeError, PacketEncodeError, RawPacket, ServerPacket,
|
ClientPacket, PacketDecodeError, PacketEncodeError, ServerPacket,
|
||||||
bedrock::{
|
bedrock::{
|
||||||
|
RAKNET_ACK, RAKNET_NACK, RAKNET_VALID, RakReliability,
|
||||||
|
ack::Ack,
|
||||||
|
frame_set::{Frame, FrameSet},
|
||||||
packet_decoder::UDPNetworkDecoder,
|
packet_decoder::UDPNetworkDecoder,
|
||||||
packet_encoder::UDPNetworkEncoder,
|
packet_encoder::UDPNetworkEncoder,
|
||||||
server::{
|
server::raknet::{
|
||||||
|
connection::{SConnectionRequest, SDisconnect},
|
||||||
open_connection::{SOpenConnectionRequest1, SOpenConnectionRequest2},
|
open_connection::{SOpenConnectionRequest1, SOpenConnectionRequest2},
|
||||||
unconnected_ping::SUnconnectedPing,
|
unconnected_ping::SUnconnectedPing,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
codec::u24::U24,
|
||||||
packet::Packet,
|
packet::Packet,
|
||||||
ser::{NetworkWriteExt, ReadingError, WritingError},
|
ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError},
|
||||||
};
|
};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use tokio::{net::UdpSocket, sync::Mutex};
|
use tokio::{net::UdpSocket, sync::Mutex};
|
||||||
|
|
||||||
|
pub mod connection;
|
||||||
pub mod open_connection;
|
pub mod open_connection;
|
||||||
pub mod unconnected;
|
pub mod unconnected;
|
||||||
|
|
||||||
@ -33,6 +42,10 @@ pub struct BedrockClientPlatform {
|
|||||||
network_writer: Arc<Mutex<UDPNetworkEncoder>>,
|
network_writer: Arc<Mutex<UDPNetworkEncoder>>,
|
||||||
/// The packet decoder for incoming packets.
|
/// The packet decoder for incoming packets.
|
||||||
network_reader: Mutex<UDPNetworkDecoder>,
|
network_reader: Mutex<UDPNetworkDecoder>,
|
||||||
|
|
||||||
|
use_frame_sets: AtomicBool,
|
||||||
|
output_sequence: AtomicU32,
|
||||||
|
output_reliable_index: AtomicU32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BedrockClientPlatform {
|
impl BedrockClientPlatform {
|
||||||
@ -43,19 +56,18 @@ impl BedrockClientPlatform {
|
|||||||
addr,
|
addr,
|
||||||
network_writer: Arc::new(Mutex::new(UDPNetworkEncoder::new())),
|
network_writer: Arc::new(Mutex::new(UDPNetworkEncoder::new())),
|
||||||
network_reader: Mutex::new(UDPNetworkDecoder::new()),
|
network_reader: Mutex::new(UDPNetworkDecoder::new()),
|
||||||
|
use_frame_sets: AtomicBool::new(false),
|
||||||
|
output_sequence: AtomicU32::new(0),
|
||||||
|
output_reliable_index: AtomicU32::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process_packet(&self, client: &Client, server: &Server, packet: Cursor<Vec<u8>>) {
|
pub async fn process_packet(&self, client: &Client, server: &Server, packet: Cursor<Vec<u8>>) {
|
||||||
let packet = self.get_packet(client, packet).await;
|
let packet = self.get_packet_payload(client, packet).await;
|
||||||
if let Some(packet) = packet {
|
if let Some(packet) = packet {
|
||||||
if let Err(error) = Self::handle_packet(client, server, &packet).await {
|
if let Err(error) = self.handle_packet_payload(client, server, packet).await {
|
||||||
let _text = format!("Error while reading incoming packet {error}");
|
let _text = format!("Error while reading incoming packet {error}");
|
||||||
log::error!(
|
log::error!("Failed to read incoming packet with : {error}");
|
||||||
"Failed to read incoming packet with id {}: {}",
|
|
||||||
packet.id,
|
|
||||||
error
|
|
||||||
);
|
|
||||||
//self.kick(TextComponent::text(text)).await;
|
//self.kick(TextComponent::text(text)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,12 +90,34 @@ impl BedrockClientPlatform {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_packet_now(&self, client: &Client, packet: Vec<u8>) {
|
pub async fn send_framed_packet<P: ClientPacket>(
|
||||||
|
&self,
|
||||||
|
client: &Client,
|
||||||
|
packet: &P,
|
||||||
|
reliability: RakReliability,
|
||||||
|
) {
|
||||||
|
let mut packet_buf = Vec::new();
|
||||||
|
let writer = &mut packet_buf;
|
||||||
|
Self::write_packet(packet, writer).unwrap();
|
||||||
|
let frame = Frame {
|
||||||
|
payload: packet_buf.into(),
|
||||||
|
reliability,
|
||||||
|
reliable_index: self.output_reliable_index.fetch_add(1, Ordering::Relaxed),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: this is really bad, batch this
|
||||||
|
let frame_set = FrameSet {
|
||||||
|
sequence: U24(self.output_sequence.fetch_add(1, Ordering::Relaxed)),
|
||||||
|
frames: vec![frame],
|
||||||
|
};
|
||||||
|
let mut packet_buf = Vec::new();
|
||||||
|
Self::write_packet(&frame_set, &mut packet_buf).unwrap();
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.network_writer
|
.network_writer
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.write_packet(packet.into(), self.addr, &self.socket)
|
.write_packet(packet_buf.into(), self.addr, &self.socket)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
// It is expected that the packet will fail if we are closed
|
// It is expected that the packet will fail if we are closed
|
||||||
@ -96,13 +130,124 @@ impl BedrockClientPlatform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_packet(
|
pub async fn send_packet_now(&self, client: &Client, packet: Vec<u8>) {
|
||||||
|
if !self.use_frame_sets.load(Ordering::Relaxed) {
|
||||||
|
// Sent the packet directly
|
||||||
|
if let Err(err) = self
|
||||||
|
.network_writer
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.write_packet(packet.into(), self.addr, &self.socket)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
// It is expected that the packet will fail if we are closed
|
||||||
|
if !client.closed.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
|
log::warn!("Failed to send packet to client {}: {}", client.id, err);
|
||||||
|
// We now need to close the connection to the client since the stream is in an
|
||||||
|
// unknown state
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_packet_payload(
|
||||||
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
server: &Server,
|
server: &Server,
|
||||||
packet: &RawPacket,
|
packet: Bytes,
|
||||||
) -> Result<(), ReadingError> {
|
) -> Result<(), ReadingError> {
|
||||||
let payload = &packet.payload[..];
|
let mut payload = &packet[..];
|
||||||
match packet.id {
|
|
||||||
|
let Ok(id) = payload.get_u8_be() else {
|
||||||
|
return Err(ReadingError::CleanEOF(String::new()));
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_valid = id & RAKNET_VALID == RAKNET_VALID;
|
||||||
|
if !is_valid {
|
||||||
|
// Offline packets just have Packet ID + Payload
|
||||||
|
return Self::handle_offline_packet(client, server, i32::from(id), payload).await;
|
||||||
|
}
|
||||||
|
self.use_frame_sets.store(true, Ordering::Relaxed);
|
||||||
|
let header = id;
|
||||||
|
|
||||||
|
match header {
|
||||||
|
RAKNET_ACK => {
|
||||||
|
dbg!("received ack");
|
||||||
|
}
|
||||||
|
RAKNET_NACK => {
|
||||||
|
dbg!("received non ack");
|
||||||
|
}
|
||||||
|
0x80..0x8d => {
|
||||||
|
self.handle_frame_set(client, server, FrameSet::read(payload)?)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
log::warn!("Received unknown online packet {header}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_frame_set(&self, client: &Client, server: &Server, frame_set: FrameSet) {
|
||||||
|
// TODO: this is bad
|
||||||
|
client
|
||||||
|
.send_packet_now(&Ack::new(vec![frame_set.sequence.0]))
|
||||||
|
.await;
|
||||||
|
// TODO
|
||||||
|
for frame in frame_set.frames {
|
||||||
|
self.handle_frame(client, server, &frame).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_frame(
|
||||||
|
&self,
|
||||||
|
client: &Client,
|
||||||
|
server: &Server,
|
||||||
|
frame: &Frame,
|
||||||
|
) -> Result<(), ReadingError> {
|
||||||
|
if frame.split_size > 0 {
|
||||||
|
dbg!("oh no, frame is split, TODO");
|
||||||
|
}
|
||||||
|
dbg!(frame.reliability);
|
||||||
|
|
||||||
|
let mut payload = &frame.payload[..];
|
||||||
|
let id = payload.get_u8_be()?;
|
||||||
|
self.handle_packet(client, server, i32::from(id), payload)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_packet(
|
||||||
|
&self,
|
||||||
|
client: &Client,
|
||||||
|
_server: &Server,
|
||||||
|
packet_id: i32,
|
||||||
|
payload: &[u8],
|
||||||
|
) -> Result<(), ReadingError> {
|
||||||
|
match packet_id {
|
||||||
|
SConnectionRequest::PACKET_ID => {
|
||||||
|
client
|
||||||
|
.handle_connection_request(self, SConnectionRequest::read(payload)?)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
SDisconnect::PACKET_ID => {
|
||||||
|
dbg!("Bedrock client disconnected");
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
log::warn!("Received Online online packet {packet_id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_offline_packet(
|
||||||
|
client: &Client,
|
||||||
|
server: &Server,
|
||||||
|
packet_id: i32,
|
||||||
|
payload: &[u8],
|
||||||
|
) -> Result<(), ReadingError> {
|
||||||
|
match packet_id {
|
||||||
SUnconnectedPing::PACKET_ID => {
|
SUnconnectedPing::PACKET_ID => {
|
||||||
client
|
client
|
||||||
.handle_unconnected_ping(server, SUnconnectedPing::read(payload)?)
|
.handle_unconnected_ping(server, SUnconnectedPing::read(payload)?)
|
||||||
@ -119,20 +264,24 @@ impl BedrockClientPlatform {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Failed to handle bedrock client packet id {}", packet.id);
|
log::error!("Failed to handle bedrock client packet id {packet_id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_packet(&self, client: &Client, packet: Cursor<Vec<u8>>) -> Option<RawPacket> {
|
pub async fn get_packet_payload(
|
||||||
|
&self,
|
||||||
|
client: &Client,
|
||||||
|
packet: Cursor<Vec<u8>>,
|
||||||
|
) -> Option<Bytes> {
|
||||||
let mut network_reader = self.network_reader.lock().await;
|
let mut network_reader = self.network_reader.lock().await;
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
() = client.await_close_interrupt() => {
|
() = client.await_close_interrupt() => {
|
||||||
log::debug!("Canceling player packet processing");
|
log::debug!("Canceling player packet processing");
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
packet_result = network_reader.get_raw_packet(packet) => {
|
packet_result = network_reader.get_packet_payload(packet) => {
|
||||||
match packet_result {
|
match packet_result {
|
||||||
Ok(packet) => Some(packet),
|
Ok(packet) => Some(packet),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
bedrock::{
|
bedrock::{
|
||||||
client::open_connection::{COpenConnectionReply1, COpenConnectionReply2},
|
client::raknet::open_connection::{COpenConnectionReply1, COpenConnectionReply2},
|
||||||
server::open_connection::{SOpenConnectionRequest1, SOpenConnectionRequest2},
|
server::raknet::open_connection::{SOpenConnectionRequest1, SOpenConnectionRequest2},
|
||||||
},
|
},
|
||||||
codec::socket_address::SocketAddress,
|
codec::socket_address::SocketAddress,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use pumpkin_config::BASIC_CONFIG;
|
use pumpkin_config::BASIC_CONFIG;
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
bedrock::{
|
bedrock::{
|
||||||
client::unconnected_pong::{CUnconnectedPong, ServerInfo},
|
client::raknet::unconnected_pong::{CUnconnectedPong, ServerInfo},
|
||||||
server::unconnected_ping::SUnconnectedPing,
|
server::raknet::unconnected_ping::SUnconnectedPing,
|
||||||
},
|
},
|
||||||
codec::ascii_string::AsciiString,
|
codec::ascii_string::AsciiString,
|
||||||
};
|
};
|
||||||
@ -14,8 +14,8 @@ impl Client {
|
|||||||
let motd_string = ServerInfo {
|
let motd_string = ServerInfo {
|
||||||
edition: "MCPE",
|
edition: "MCPE",
|
||||||
motd_line_1: &BASIC_CONFIG.motd,
|
motd_line_1: &BASIC_CONFIG.motd,
|
||||||
protocol_version: 527,
|
protocol_version: 818,
|
||||||
version_name: "1.19.1",
|
version_name: "1.21.90",
|
||||||
player_count: 1,
|
player_count: 1,
|
||||||
max_player_count: BASIC_CONFIG.max_players,
|
max_player_count: BASIC_CONFIG.max_players,
|
||||||
server_unique_id: server.server_guid,
|
server_unique_id: server.server_guid,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user