mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-31 08:22:33 +00:00
Initial Bedrock support
You can't join the World, But the base is ready
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -1295,9 +1295,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.4",
|
||||
@@ -1476,9 +1476,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198"
|
||||
checksum = "0281c2e25e62316a5c9d98f2d2e9e95a37841afdaf4383c177dbb5c1dfab0568"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.4",
|
||||
]
|
||||
|
||||
@@ -21,7 +21,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi
|
||||
## Goals
|
||||
|
||||
- **Performance**: Leveraging multi-threading for maximum speed and efficiency.
|
||||
- **Compatibility**: Supports the latest Minecraft server version while adhering to Vanilla game mechanics.
|
||||
- **Compatibility**: Supports the latest Java & Bedrock/Pocket Minecraft server version while adhering to Vanilla game mechanics.
|
||||
- **Security**: Prioritizes security by preventing known security exploits.
|
||||
- **Flexibility**: Highly configurable, with the ability to disable unnecessary features.
|
||||
- **Extensibility**: Provides a foundation for plugin development.
|
||||
|
||||
@@ -108,8 +108,14 @@ pub struct AdvancedConfiguration {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct BasicConfiguration {
|
||||
/// The address to bind the server to.
|
||||
pub server_address: SocketAddr,
|
||||
// Whether Java Edition Client's are Accepted
|
||||
pub java_edition: bool,
|
||||
/// The address and port to which the Java Edition server will bind
|
||||
pub java_edition_address: SocketAddr,
|
||||
// Whether Bedrock/Pocket Edition Client's are Accepted
|
||||
pub bedrock_edition: bool,
|
||||
/// The address and port to which the Bedrock/Pocket Edition server will bind
|
||||
pub bedrock_edition_address: SocketAddr,
|
||||
/// The seed for world generation.
|
||||
pub seed: String,
|
||||
/// The maximum number of players allowed on the server. Specifying `0` disables the limit.
|
||||
@@ -157,7 +163,10 @@ pub struct BasicConfiguration {
|
||||
impl Default for BasicConfiguration {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
server_address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565),
|
||||
java_edition: true,
|
||||
java_edition_address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565),
|
||||
bedrock_edition: true,
|
||||
bedrock_edition_address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 19132),
|
||||
seed: "".to_string(),
|
||||
max_players: 100000,
|
||||
view_distance: NonZeroU8::new(10).unwrap(),
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Default)]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct QueryConfig {
|
||||
pub enabled: bool,
|
||||
/// Optional; if not specified, the port the server is running on will be used.
|
||||
pub port: Option<u16>,
|
||||
pub address: SocketAddr,
|
||||
}
|
||||
|
||||
impl Default for QueryConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::InventoryError;
|
||||
use pumpkin_protocol::server::play::SlotActionType;
|
||||
use pumpkin_protocol::java::server::play::SlotActionType;
|
||||
use pumpkin_world::item::ItemStack;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::entity_equipment::EntityEquipment;
|
||||
use crate::equipment_slot::EquipmentSlot;
|
||||
use crate::screen_handler::InventoryPlayer;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_protocol::client::play::CSetPlayerInventory;
|
||||
use pumpkin_protocol::java::client::play::CSetPlayerInventory;
|
||||
use pumpkin_world::inventory::split_stack;
|
||||
use pumpkin_world::inventory::{Clearable, Inventory};
|
||||
use pumpkin_world::item::ItemStack;
|
||||
|
||||
@@ -2,12 +2,14 @@ use async_trait::async_trait;
|
||||
use log::warn;
|
||||
use pumpkin_data::screen::WindowType;
|
||||
use pumpkin_protocol::{
|
||||
client::play::{
|
||||
CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem,
|
||||
CSetPlayerInventory, CSetSelectedSlot,
|
||||
},
|
||||
codec::item_stack_seralizer::OptionalItemStackHash,
|
||||
server::play::SlotActionType,
|
||||
java::{
|
||||
client::play::{
|
||||
CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem,
|
||||
CSetPlayerInventory, CSetSelectedSlot,
|
||||
},
|
||||
server::play::SlotActionType,
|
||||
},
|
||||
};
|
||||
use pumpkin_util::text::TextComponent;
|
||||
use pumpkin_world::inventory::{ComparableInventory, Inventory};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pumpkin_protocol::{
|
||||
client::play::{
|
||||
CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem,
|
||||
},
|
||||
codec::{
|
||||
item_stack_seralizer::{ItemStackSerializer, OptionalItemStackHash},
|
||||
var_int::VarInt,
|
||||
},
|
||||
java::client::play::{
|
||||
CSetContainerContent, CSetContainerProperty, CSetContainerSlot, CSetCursorItem,
|
||||
},
|
||||
};
|
||||
use pumpkin_world::item::ItemStack;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
@@ -167,7 +167,7 @@ pub fn packet(input: TokenStream, item: TokenStream) -> TokenStream {
|
||||
|
||||
let code = quote! {
|
||||
#item
|
||||
impl #impl_generics crate::ser::packet::Packet for #name #ty_generics {
|
||||
impl #impl_generics crate::packet::Packet for #name #ty_generics {
|
||||
const PACKET_ID: i32 = #input;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,8 +4,7 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["packets", "query"]
|
||||
packets = ["serverbound", "clientbound"]
|
||||
default = ["query"]
|
||||
serverbound = []
|
||||
clientbound = []
|
||||
query = []
|
||||
|
||||
1
pumpkin-protocol/src/bedrock/client/connection.rs
Normal file
1
pumpkin-protocol/src/bedrock/client/connection.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
3
pumpkin-protocol/src/bedrock/client/mod.rs
Normal file
3
pumpkin-protocol/src/bedrock/client/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod connection;
|
||||
pub mod open_connection;
|
||||
pub mod unconnected_pong;
|
||||
46
pumpkin-protocol/src/bedrock/client/open_connection.rs
Normal file
46
pumpkin-protocol/src/bedrock/client/open_connection.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{bedrock::RAKNET_MAGIC, codec::socket_address::SocketAddress};
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x06)]
|
||||
pub struct COpenConnectionReply1 {
|
||||
magic: [u8; 16],
|
||||
server_guid: u64,
|
||||
has_server_security: bool,
|
||||
cookie: u32,
|
||||
mtu: u16,
|
||||
}
|
||||
|
||||
impl COpenConnectionReply1 {
|
||||
pub fn new(server_guid: u64, has_server_security: bool, cookie: u32, mtu: u16) -> Self {
|
||||
Self {
|
||||
magic: RAKNET_MAGIC,
|
||||
server_guid,
|
||||
has_server_security,
|
||||
cookie,
|
||||
mtu,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x08)]
|
||||
pub struct COpenConnectionReply2 {
|
||||
server_guid: u64,
|
||||
client_address: SocketAddress,
|
||||
mtu: u16,
|
||||
security: bool,
|
||||
}
|
||||
|
||||
impl COpenConnectionReply2 {
|
||||
pub fn new(server_guid: u64, client_address: SocketAddress, mtu: u16, security: bool) -> Self {
|
||||
Self {
|
||||
server_guid,
|
||||
client_address,
|
||||
mtu,
|
||||
security,
|
||||
}
|
||||
}
|
||||
}
|
||||
63
pumpkin-protocol/src/bedrock/client/unconnected_pong.rs
Normal file
63
pumpkin-protocol/src/bedrock/client/unconnected_pong.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use core::fmt;
|
||||
|
||||
use pumpkin_macros::packet;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::codec::ascii_string::AsciiString;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[packet(0x1c)]
|
||||
pub struct CUnconnectedPong {
|
||||
time: i64,
|
||||
server_guid: u64,
|
||||
magic: [u8; 16],
|
||||
server_id: AsciiString,
|
||||
}
|
||||
|
||||
pub struct ServerInfo {
|
||||
/// (MCPE or MCEE for Education Edition)
|
||||
pub edition: &'static str,
|
||||
pub motd_line_1: &'static str,
|
||||
pub protocol_version: u32,
|
||||
pub version_name: &'static str,
|
||||
pub player_count: i32,
|
||||
pub max_player_count: u32,
|
||||
pub server_unique_id: u64,
|
||||
pub motd_line_2: &'static str,
|
||||
pub game_mode: &'static str,
|
||||
pub game_mode_numeric: u32,
|
||||
pub port_ipv4: u16,
|
||||
pub port_ipv6: u16,
|
||||
}
|
||||
|
||||
impl fmt::Display for ServerInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{};{};{};{};{};{};{};{};{};{};{};{}",
|
||||
self.edition,
|
||||
self.motd_line_1,
|
||||
self.protocol_version,
|
||||
self.version_name,
|
||||
self.player_count,
|
||||
self.max_player_count,
|
||||
self.server_unique_id,
|
||||
self.motd_line_2,
|
||||
self.game_mode,
|
||||
self.game_mode_numeric,
|
||||
self.port_ipv4,
|
||||
self.port_ipv6
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl CUnconnectedPong {
|
||||
pub fn new(time: i64, server_guid: u64, magic: [u8; 16], server_id: AsciiString) -> Self {
|
||||
Self {
|
||||
time,
|
||||
server_guid,
|
||||
magic,
|
||||
server_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
8
pumpkin-protocol/src/bedrock/mod.rs
Normal file
8
pumpkin-protocol/src/bedrock/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
pub mod client;
|
||||
pub mod packet_decoder;
|
||||
pub mod packet_encoder;
|
||||
pub mod server;
|
||||
|
||||
pub const RAKNET_MAGIC: [u8; 16] = [
|
||||
0x00, 0xff, 0xff, 0x0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0x12, 0x34, 0x56, 0x78,
|
||||
];
|
||||
122
pumpkin-protocol/src/bedrock/packet_decoder.rs
Normal file
122
pumpkin-protocol/src/bedrock/packet_decoder.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use std::io::Cursor;
|
||||
|
||||
use async_compression::tokio::bufread::ZlibDecoder;
|
||||
use bytes::Buf;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, BufReader};
|
||||
|
||||
use crate::{Aes128Cfb8Dec, CompressionThreshold, PacketDecodeError, RawPacket, StreamDecryptor};
|
||||
|
||||
// decrypt -> decompress -> raw
|
||||
pub enum DecompressionReader<R: AsyncRead + Unpin> {
|
||||
Decompress(ZlibDecoder<BufReader<R>>),
|
||||
None(R),
|
||||
}
|
||||
|
||||
impl<R: AsyncRead + Unpin> AsyncRead for DecompressionReader<R> {
|
||||
#[inline]
|
||||
fn poll_read(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> std::task::Poll<std::io::Result<()>> {
|
||||
match self.get_mut() {
|
||||
Self::Decompress(reader) => {
|
||||
let reader = std::pin::Pin::new(reader);
|
||||
reader.poll_read(cx, buf)
|
||||
}
|
||||
Self::None(reader) => {
|
||||
let reader = std::pin::Pin::new(reader);
|
||||
reader.poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DecryptionReader<R: AsyncRead + Unpin> {
|
||||
Decrypt(Box<StreamDecryptor<R>>),
|
||||
None(R),
|
||||
}
|
||||
|
||||
impl<R: AsyncRead + Unpin> DecryptionReader<R> {
|
||||
pub fn upgrade(self, cipher: Aes128Cfb8Dec) -> Self {
|
||||
match self {
|
||||
Self::None(stream) => Self::Decrypt(Box::new(StreamDecryptor::new(cipher, stream))),
|
||||
_ => panic!("Cannot upgrade a stream that already has a cipher!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: AsyncRead + Unpin> AsyncRead for DecryptionReader<R> {
|
||||
#[inline]
|
||||
fn poll_read(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> std::task::Poll<std::io::Result<()>> {
|
||||
match self.get_mut() {
|
||||
Self::Decrypt(reader) => {
|
||||
let reader = std::pin::Pin::new(reader);
|
||||
reader.poll_read(cx, buf)
|
||||
}
|
||||
Self::None(reader) => {
|
||||
let reader = std::pin::Pin::new(reader);
|
||||
reader.poll_read(cx, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Decoder: Client -> Server
|
||||
/// Supports ZLib decoding/decompression
|
||||
/// Supports Aes128 Encryption
|
||||
pub struct UDPNetworkDecoder {
|
||||
compression: Option<CompressionThreshold>,
|
||||
}
|
||||
|
||||
impl Default for UDPNetworkDecoder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl UDPNetworkDecoder {
|
||||
pub fn new() -> Self {
|
||||
Self { compression: None }
|
||||
}
|
||||
|
||||
pub fn set_compression(&mut self, threshold: CompressionThreshold) {
|
||||
self.compression = Some(threshold);
|
||||
}
|
||||
|
||||
/// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted
|
||||
pub fn set_encryption(&mut self, _key: &[u8; 16]) {
|
||||
// if matches!(self.reader, DecryptionReader::Decrypt(_)) {
|
||||
// panic!("Cannot upgrade a stream that already has a cipher!");
|
||||
// }
|
||||
// let cipher = Aes128Cfb8Dec::new_from_slices(key, key).expect("invalid key");
|
||||
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
||||
}
|
||||
|
||||
pub async fn get_raw_packet(
|
||||
&mut self,
|
||||
mut reader: Cursor<Vec<u8>>,
|
||||
) -> Result<RawPacket, 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();
|
||||
reader
|
||||
.read_to_end(&mut payload)
|
||||
.await
|
||||
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
||||
|
||||
Ok(RawPacket {
|
||||
id: packet_id as i32,
|
||||
payload: payload.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
124
pumpkin-protocol/src/bedrock/packet_encoder.rs
Normal file
124
pumpkin-protocol/src/bedrock/packet_encoder.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use bytes::Bytes;
|
||||
use thiserror::Error;
|
||||
use tokio::{io::AsyncWrite, net::UdpSocket};
|
||||
|
||||
use crate::{
|
||||
Aes128Cfb8Enc, CompressionLevel, CompressionThreshold, PacketEncodeError, StreamEncryptor,
|
||||
};
|
||||
|
||||
// raw -> compress -> encrypt
|
||||
|
||||
pub enum EncryptionWriter<W: AsyncWrite + Unpin> {
|
||||
Encrypt(Box<StreamEncryptor<W>>),
|
||||
None(W),
|
||||
}
|
||||
|
||||
impl<W: AsyncWrite + Unpin> EncryptionWriter<W> {
|
||||
pub fn upgrade(self, cipher: Aes128Cfb8Enc) -> Self {
|
||||
match self {
|
||||
Self::None(stream) => Self::Encrypt(Box::new(StreamEncryptor::new(cipher, stream))),
|
||||
_ => panic!("Cannot upgrade a stream that already has a cipher!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: AsyncWrite + Unpin> AsyncWrite for EncryptionWriter<W> {
|
||||
fn poll_write(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> std::task::Poll<Result<usize, std::io::Error>> {
|
||||
match self.get_mut() {
|
||||
Self::Encrypt(writer) => {
|
||||
let writer = std::pin::Pin::new(writer);
|
||||
writer.poll_write(cx, buf)
|
||||
}
|
||||
Self::None(writer) => {
|
||||
let writer = std::pin::Pin::new(writer);
|
||||
writer.poll_write(cx, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Result<(), std::io::Error>> {
|
||||
match self.get_mut() {
|
||||
Self::Encrypt(writer) => {
|
||||
let writer = std::pin::Pin::new(writer);
|
||||
writer.poll_flush(cx)
|
||||
}
|
||||
Self::None(writer) => {
|
||||
let writer = std::pin::Pin::new(writer);
|
||||
writer.poll_flush(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_shutdown(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Result<(), std::io::Error>> {
|
||||
match self.get_mut() {
|
||||
Self::Encrypt(writer) => {
|
||||
let writer = std::pin::Pin::new(writer);
|
||||
writer.poll_shutdown(cx)
|
||||
}
|
||||
Self::None(writer) => {
|
||||
let writer = std::pin::Pin::new(writer);
|
||||
writer.poll_shutdown(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Encoder: Server -> Client
|
||||
/// Supports ZLib endecoding/compression
|
||||
/// Supports Aes128 Encryption
|
||||
pub struct UDPNetworkEncoder {
|
||||
// compression and compression threshold
|
||||
compression: Option<(CompressionThreshold, CompressionLevel)>,
|
||||
}
|
||||
|
||||
impl Default for UDPNetworkEncoder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl UDPNetworkEncoder {
|
||||
pub fn new() -> Self {
|
||||
Self { compression: None }
|
||||
}
|
||||
|
||||
pub fn set_compression(&mut self, compression_info: (CompressionThreshold, CompressionLevel)) {
|
||||
self.compression = Some(compression_info);
|
||||
}
|
||||
|
||||
/// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted
|
||||
pub fn set_encryption(&mut self, _key: &[u8; 16]) {
|
||||
// if matches!(self.writer, EncryptionWriter::Encrypt(_)) {
|
||||
// panic!("Cannot upgrade a stream that already has a cipher!");
|
||||
// }
|
||||
// let cipher = Aes128Cfb8Enc::new_from_slices(key, key).expect("invalid key");
|
||||
// take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
|
||||
}
|
||||
|
||||
pub async fn write_packet(
|
||||
&mut self,
|
||||
packet_data: Bytes,
|
||||
addr: SocketAddr,
|
||||
socket: &UdpSocket,
|
||||
) -> Result<(), PacketEncodeError> {
|
||||
socket.send_to(&packet_data, addr).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("Invalid compression Level")]
|
||||
pub struct CompressionLevelError;
|
||||
10
pumpkin-protocol/src/bedrock/server/connection.rs
Normal file
10
pumpkin-protocol/src/bedrock/server/connection.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
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,
|
||||
}
|
||||
3
pumpkin-protocol/src/bedrock/server/mod.rs
Normal file
3
pumpkin-protocol/src/bedrock/server/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod connection;
|
||||
pub mod open_connection;
|
||||
pub mod unconnected_ping;
|
||||
22
pumpkin-protocol/src/bedrock/server/open_connection.rs
Normal file
22
pumpkin-protocol/src/bedrock/server/open_connection.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use pumpkin_macros::packet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::codec::socket_address::SocketAddress;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[packet(0x05)]
|
||||
/// The client sends this when attempting to join the server
|
||||
pub struct SOpenConnectionRequest1 {
|
||||
pub magic: [u8; 16],
|
||||
pub protocol_version: u8,
|
||||
pub mtu: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[packet(0x07)]
|
||||
pub struct SOpenConnectionRequest2 {
|
||||
pub magic: [u8; 16],
|
||||
pub server_address: SocketAddress,
|
||||
pub mtu: u16,
|
||||
pub client_guid: u64,
|
||||
}
|
||||
11
pumpkin-protocol/src/bedrock/server/unconnected_ping.rs
Normal file
11
pumpkin-protocol/src/bedrock/server/unconnected_ping.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use pumpkin_macros::packet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[packet(0x01)]
|
||||
/// Used to request Server information like MOTD
|
||||
pub struct SUnconnectedPing {
|
||||
pub time: i64,
|
||||
pub magic: [u8; 16],
|
||||
pub client_guid: i64,
|
||||
}
|
||||
21
pumpkin-protocol/src/codec/ascii_string.rs
Normal file
21
pumpkin-protocol/src/codec/ascii_string.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use std::io::Write;
|
||||
|
||||
use bytes::BufMut;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
pub struct AsciiString(pub String);
|
||||
|
||||
impl Serialize for AsciiString {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut buf = Vec::new();
|
||||
|
||||
// Prefixed by a short
|
||||
buf.put_u16(self.0.len() as u16);
|
||||
buf.write_all(self.0.as_bytes()).unwrap();
|
||||
|
||||
serializer.serialize_bytes(&buf)
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ use std::io::Write;
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::ReadingError;
|
||||
use crate::WritingError;
|
||||
use crate::ser::NetworkReadExt;
|
||||
use crate::ser::NetworkWriteExt;
|
||||
use crate::ser::ReadingError;
|
||||
use crate::ser::WritingError;
|
||||
|
||||
pub struct BitSet(pub Box<[i64]>);
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod ascii_string;
|
||||
pub mod bit_set;
|
||||
pub mod item_stack_seralizer;
|
||||
pub mod socket_address;
|
||||
pub mod var_int;
|
||||
pub mod var_long;
|
||||
|
||||
93
pumpkin-protocol/src/codec/socket_address.rs
Normal file
93
pumpkin-protocol/src/codec/socket_address.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
|
||||
use bytes::BufMut;
|
||||
use serde::{
|
||||
Deserialize, Serialize, Serializer,
|
||||
de::{self, SeqAccess},
|
||||
};
|
||||
|
||||
pub struct SocketAddress(pub SocketAddr);
|
||||
|
||||
impl Serialize for SocketAddress {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut buf = Vec::new();
|
||||
|
||||
let version = match self.0 {
|
||||
SocketAddr::V4(_) => 4,
|
||||
SocketAddr::V6(_) => 6,
|
||||
};
|
||||
let ip = match self.0 {
|
||||
SocketAddr::V4(addr) => addr.ip().to_bits(),
|
||||
SocketAddr::V6(addr) => addr.ip().to_bits() as u32,
|
||||
};
|
||||
|
||||
buf.put_u8(version);
|
||||
buf.put_u32(ip);
|
||||
buf.put_u16(self.0.port());
|
||||
|
||||
serializer.serialize_bytes(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for SocketAddress {
|
||||
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 = SocketAddress;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a valid socket addr")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: SeqAccess<'de>,
|
||||
{
|
||||
if let Some(version) = seq.next_element::<u8>()? {
|
||||
match version {
|
||||
4 => {
|
||||
let ip = seq.next_element::<u32>()?.unwrap();
|
||||
let port = seq.next_element::<u16>()?.unwrap();
|
||||
|
||||
return Ok(SocketAddress(SocketAddr::V4(SocketAddrV4::new(
|
||||
Ipv4Addr::from_bits(ip),
|
||||
port,
|
||||
))));
|
||||
}
|
||||
6 => {
|
||||
let _family = seq.next_element::<u16>()?.unwrap();
|
||||
|
||||
let port = seq.next_element::<u16>()?.unwrap();
|
||||
|
||||
let flowinfo = seq.next_element::<u32>()?.unwrap();
|
||||
let ip = seq.next_element::<u128>()?.unwrap();
|
||||
let scope_id = seq.next_element::<u32>()?.unwrap();
|
||||
|
||||
return Ok(SocketAddress(SocketAddr::V6(SocketAddrV6::new(
|
||||
Ipv6Addr::from_bits(ip),
|
||||
port,
|
||||
flowinfo,
|
||||
scope_id,
|
||||
))));
|
||||
}
|
||||
_ => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"Wrong Socket Address version {version}"
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(serde::de::Error::custom("Incomplete Socket Address"))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_seq(Visitor)
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ use std::{
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
|
||||
|
||||
use bytes::BufMut;
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
@@ -13,6 +11,8 @@ use serde::{
|
||||
};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
|
||||
use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
|
||||
|
||||
pub type VarIntType = i32;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,16 @@ use std::{
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
|
||||
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
de::{self, SeqAccess, Visitor},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
WritingError,
|
||||
ser::{NetworkReadExt, NetworkWriteExt, ReadingError},
|
||||
};
|
||||
|
||||
pub type VarLongType = i64;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::io::Write;
|
||||
|
||||
use crate::{
|
||||
ClientPacket,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::{ClientPacket, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
use pumpkin_data::{
|
||||
block_properties::get_block,
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::io::Write;
|
||||
|
||||
use crate::ClientPacket;
|
||||
use crate::client::play::bossevent_action::BosseventAction;
|
||||
use crate::ser::{NetworkWriteExt, WritingError};
|
||||
use crate::java::client::play::BosseventAction;
|
||||
use crate::ser::NetworkWriteExt;
|
||||
use crate::{ClientPacket, WritingError};
|
||||
use pumpkin_data::packet::clientbound::PLAY_BOSS_EVENT;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use crate::WritingError;
|
||||
use crate::codec::bit_set::BitSet;
|
||||
use crate::{
|
||||
ClientPacket, VarInt,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::{ClientPacket, VarInt, ser::NetworkWriteExt};
|
||||
use pumpkin_data::packet::clientbound::PLAY_LEVEL_CHUNK_WITH_LIGHT;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_nbt::END_ID;
|
||||
@@ -3,10 +3,7 @@ use std::io::Write;
|
||||
use pumpkin_data::packet::clientbound::PLAY_COMMANDS;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, VarInt,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::{ClientPacket, VarInt, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
#[packet(PLAY_COMMANDS)]
|
||||
pub struct CCommands<'a> {
|
||||
@@ -5,9 +5,9 @@ use pumpkin_macros::packet;
|
||||
use pumpkin_util::text::TextComponent;
|
||||
|
||||
use crate::{
|
||||
ClientPacket,
|
||||
ClientPacket, WritingError,
|
||||
codec::{bit_set::BitSet, var_int::VarInt},
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
ser::NetworkWriteExt,
|
||||
};
|
||||
|
||||
#[packet(PLAY_PLAYER_CHAT)]
|
||||
@@ -4,10 +4,7 @@ use bitflags::bitflags;
|
||||
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_UPDATE;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, Property,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::{ClientPacket, Property, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
use super::PlayerAction;
|
||||
|
||||
@@ -4,10 +4,7 @@ use pumpkin_data::packet::clientbound::PLAY_PLAYER_POSITION;
|
||||
use pumpkin_macros::packet;
|
||||
use pumpkin_util::math::vector3::Vector3;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, PositionFlag, VarInt,
|
||||
ser::{NetworkWriteExt, WritingError},
|
||||
};
|
||||
use crate::{ClientPacket, PositionFlag, VarInt, WritingError, ser::NetworkWriteExt};
|
||||
|
||||
#[packet(PLAY_PLAYER_POSITION)]
|
||||
pub struct CPlayerPosition<'a> {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user