diff --git a/Cargo.lock b/Cargo.lock index 5290d4a..002637b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,8 @@ dependencies = [ "serde", "serde_json", "tokio", + "tokio-stream", + "tokio-util", ] [[package]] @@ -31,6 +33,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -297,6 +311,31 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-stream" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 84cbfa6..0d976a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,9 @@ edition = "2018" [dependencies] tokio = { version = "1.15", features = ["full"] } +tokio-util = { version = "0.7", features = ["codec"] } +tokio-stream = "0.1" serde = { version = "1.0", features = ["derive", "std"] } -bytes = "1.1" serde_json = "1.0" -lixcraft-derive = { path = "lixcraft-derive" } +bytes = "1.1" +lixcraft-derive = { path = "lixcraft-derive" } \ No newline at end of file diff --git a/lixcraft-derive/Cargo.toml b/lixcraft-derive/Cargo.toml index f48d69f..2eab2d9 100644 --- a/lixcraft-derive/Cargo.toml +++ b/lixcraft-derive/Cargo.toml @@ -9,4 +9,4 @@ proc-macro = true [dependencies] syn = { version = "1.0", features = ["full"] } -quote = "1.0" +quote = "1.0" \ No newline at end of file diff --git a/lixcraft-derive/src/lib.rs b/lixcraft-derive/src/lib.rs index 08ddecd..00b8af5 100644 --- a/lixcraft-derive/src/lib.rs +++ b/lixcraft-derive/src/lib.rs @@ -1,55 +1,91 @@ use proc_macro::TokenStream; -use syn::{Data, DeriveInput, parse_macro_input}; +use syn::{Data, DeriveInput, Fields, parse_macro_input}; use quote::quote; -#[proc_macro_derive(Wrapper)] -pub fn derive_wrapper(input: TokenStream) -> TokenStream { +macro_rules! iter_named_fields { + ($f:expr, $m:expr, $r:expr) => { + $f.iter().map(|field| { + let ty = &field.ty; + let ident = &field.ident.as_ref().unwrap(); + $m(ty, ident) + }).reduce($r).unwrap_or_default() + } +} +macro_rules! iter_unnamed_fields { + ($f:expr, $m:expr, $r:expr) => { + $f.iter().enumerate().map(|(id, field)| { + let ty = &field.ty; + $m(ty, id) + }).reduce($r).unwrap_or_default() + } +} + +macro_rules! impl_serializable { + ($struct_ident:expr, $size:expr, $serialize:expr, $deserialize:expr) => { + { + let struct_ident = $struct_ident; + let mut size = $size; + if size.is_empty() { + size = quote!{ 0 } + } + let serialize = $serialize; + let deserialize = $deserialize; + quote!{ + impl JavaSerializable for #struct_ident { + fn size_in_bytes(&self) -> usize { + #size + } + + fn serialize(&self, buf: &mut bytes::BytesMut) { + #serialize + } + + fn deserialize(buf: &mut bytes::Bytes) -> Result { + Ok(#deserialize) + } + } + } + } + } +} + +#[proc_macro_derive(JavaSerializable)] +pub fn derive_serializable(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - let ident = &input.ident; + let struct_ident = &input.ident; - match &input.data { - Data::Struct(s) => { - if s.fields.len() != 1 { - panic!("#[derive(Wrapper)] only usable with one value") - } - for field in s.fields.iter() { - if field.ident.is_some() { - panic!("#[derive(Wrapper)] only usable on newtype structs") - } + let s = match &input.data { + Data::Struct(s) => s, + _ => panic!("#[derive(JavaSerializable)] currently only usable on structs") + }; - let field_type = &field.ty; - let output = quote!{ - impl From<#ident> for #field_type { - fn from(v: #ident) -> Self { - v.0 - } - } - - impl Deref for #ident { - type Target = #field_type; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl DerefMut for #ident { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - - impl From<#field_type> for #ident { - fn from(v: #field_type) -> Self { - #ident(v) - } - } - }; - - return output.into(); - } - panic!("Unreachable") + let result = match &s.fields { + Fields::Named(named) => { + let fields = &named.named; + fields.iter().map(|field| { + let ty = &field.ty; + let ident = &field.ident.as_ref().unwrap(); + quote!{ #ident: #ty::deserialize(buf)? } + }).reduce(|a, b| quote!{ #a, #b }).unwrap_or_default(); + let (size_in_bytes, serialize, deserialize) = ( + iter_named_fields!(fields, |_, ident| quote!{ self.#ident.size_in_bytes() }, |a, b| quote!{ #a + #b }), + iter_named_fields!(fields, |_, ident| quote!{ self.#ident.serialize(buf); }, |a, b| quote!{ #a #b }), + iter_named_fields!(fields, |ty, ident| quote!{ #ident: #ty::deserialize(buf)? }, |a, b| quote!{ #a, #b }) + ); + impl_serializable!(struct_ident, size_in_bytes, serialize, quote! { #struct_ident {#deserialize} }) }, - _ => panic!("#[derive(Wrapper)] only usable on structs") - } + Fields::Unnamed(unnamed) => { + let fields = &unnamed.unnamed; + let (size_in_bytes, serialize, deserialize) = ( + iter_unnamed_fields!(fields, |_, ident| quote!{ self.#ident.size_in_bytes() }, |a, b| quote!{ #a + #b }), + iter_unnamed_fields!(fields, |_, ident| quote!{ self.#ident.serialize(buf); }, |a, b| quote!{ #a #b }), + iter_unnamed_fields!(fields, |ty, _| quote!{ #ty::deserialize(buf)? }, |a, b| quote!{ #a, #b }) + ); + impl_serializable!(struct_ident, size_in_bytes, serialize, quote! { #struct_ident (#deserialize) }) + }, + Fields::Unit => impl_serializable!(struct_ident, quote! { 0 }, quote! {}, quote! { #struct_ident {} }) + }.into(); + println!("{}", result); + result } \ No newline at end of file diff --git a/src/datatypes.rs b/src/datatypes.rs index 7333778..dcf63b3 100644 --- a/src/datatypes.rs +++ b/src/datatypes.rs @@ -1,6 +1,7 @@ +use std::fmt::{Formatter, Write}; use std::ops::{Deref, DerefMut}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use serde::de::Error; +use serde::de::{EnumAccess, Error, MapAccess, SeqAccess, Visitor}; use lixcraft_derive::Wrapper; #[derive(Copy, Clone, Debug, PartialEq, Eq, Wrapper)] @@ -21,12 +22,14 @@ impl From for VarInt { impl Serialize for VarInt { fn serialize(&self, serializer: S) -> Result where S: Serializer { let mut v = self.0 as u32; + let mut result = Vec::with_capacity(5); loop { if v & 0x80 == 0 { - return serializer.serialize_u8(v as u8); + result.push(v as u8); + return serializer.serialize_bytes(&result); } - serializer.serialize_u8((v as u8 & 0x7f) | 0x80)?; + result.push((v as u8 & 0x7f) | 0x80); v >>= 7; } } @@ -37,7 +40,7 @@ impl<'de> Deserialize<'de> for VarInt { let mut num_read = 0; let mut result = 0; loop { - let read = u8::deserialize(deserializer)?; + let read = (&mut *deserializer).deserialize_u8(VarIntVisitor{})?; let value = i32::from(read & 0b0111_1111); result |= value.overflowing_shl(7 * num_read).0; @@ -81,35 +84,35 @@ impl<'de> Deserialize<'de> for NextState { #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponseVersion { - name: String, - protocol: i32 + pub name: String, + pub protocol: i32 } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponseSample { - name: String, - id: String + pub name: String, + pub id: String } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponsePlayers { - max: i32, - online: i32, - sample: Vec + pub max: i32, + pub online: i32, + pub sample: Vec } #[derive(Debug, Serialize, Deserialize)] pub struct StatusResponseDescription { - text: String + pub text: String } #[derive(Debug)] pub struct StatusResponse { - version: StatusResponseVersion, - players: StatusResponsePlayers, - description: StatusResponseDescription, + pub version: StatusResponseVersion, + pub players: StatusResponsePlayers, + pub description: StatusResponseDescription, //#[serde(skip_serializing_if = "Option::is_none")] - favicon: Option + pub favicon: Option } impl Serialize for StatusResponse { @@ -131,4 +134,103 @@ impl<'de> Deserialize<'de> for StatusResponse { Err(err) => Err(err) } } +} + +#[derive(Debug, Serialize, Deserialize)] +//TODO: Serialize, Deserialize +pub enum Font { + Uniform, //minecraft:uniform + Alt, //minecraft:alt + Default //minecraft:default +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum ClickEventAction { + open_url, + run_command, + suggest_command, + change_page, + copy_to_clipboard +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ClickEvent { + action: ClickEventAction, + value: String +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum HoverEventAction { + show_text, + show_item, + show_entity +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct HoverEvent { + action: HoverEventAction, + value: String //or Chat (Recursion!) +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SharedChat { + //#[serde(skip_serializing_if = "Option::is_none")] + bold: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + italic: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + underlined: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + strikethrough: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + obfuscated: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + font: Font, + //#[serde(skip_serializing_if = "Option::is_none")] + color: String, //TODO Color code, format code or hex code + //#[serde(skip_serializing_if = "Option::is_none")] + insertion: String, + //#[serde(skip_serializing_if = "Option::is_none")] + clickEvent: ClickEvent, + //#[serde(skip_serializing_if = "Option::is_none")] + hoverEvent: HoverEvent, + //#[serde(skip_serializing_if = "Option::is_none")] + extra: Vec +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Score { + name: String, //Or UUID + objective: String, + value: String +} + +#[derive(Debug, Serialize, Deserialize)] +//TODO: Serialize, Deserialize +pub enum Chat { + StringComponent { + #[serde(flatten)] + options: SharedChat, + text: String + }, + TranslationComponent { + #[serde(flatten)] + options: SharedChat, + translate: String //TODO Special strings + }, + KeybindComponent { + #[serde(flatten)] + options: SharedChat, + keybind: String + }, + ScoreComponent { + #[serde(flatten)] + options: SharedChat, + score: Score + }, + SelectorComponent { + #[serde(flatten)] + options: SharedChat, + selector: String //TODO ominous + } } \ No newline at end of file diff --git a/src/deserializer.rs b/src/deserializer.rs index 26d1fa2..cb0292b 100644 --- a/src/deserializer.rs +++ b/src/deserializer.rs @@ -30,6 +30,10 @@ pub struct JavaDeserializer { } impl JavaDeserializer { + pub fn from_bytes<'a, T: Deserialize<'a>>(data: Bytes) -> Result { + let mut deserializer = JavaDeserializer{input : data }; + T::deserialize(&mut deserializer) + } fn assert_remaining(&self, size: usize) -> Result<(), JavaDeserError> { match self.input.remaining() >= size { @@ -114,7 +118,7 @@ impl<'a, 'de> Deserializer<'de> for &'a mut JavaDeserializer { } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de> { - let size = VarInt::deserialize(self)?; + let size = VarInt::deserialize(&mut *self)?; if *size > 32767 { return Err(JavaDeserError::InvalidValue) } @@ -151,12 +155,12 @@ impl<'a, 'de> Deserializer<'de> for &'a mut JavaDeserializer { } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de> { - let size = VarInt::deserialize(self)?; - visitor.visit_seq(LengthPrefixedSeq { de: self, remaining: usize::from(size) }) + let size = VarInt::deserialize(&mut *self)?; + visitor.visit_seq(KnownLengthSeq { de: self, remaining: usize::from(size) }) } fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: Visitor<'de> { - panic!("Tuple not deserializable in Java protocol") + visitor.visit_seq(KnownLengthSeq { de: self, remaining: len }) } fn deserialize_tuple_struct(self, name: &'static str, len: usize, visitor: V) -> Result where V: Visitor<'de> { @@ -184,12 +188,12 @@ impl<'a, 'de> Deserializer<'de> for &'a mut JavaDeserializer { } } -struct LengthPrefixedSeq<'a> { +struct KnownLengthSeq<'a> { de: &'a mut JavaDeserializer, remaining: usize } -impl<'de, 'a> SeqAccess<'de> for LengthPrefixedSeq<'a> { +impl<'de, 'a> SeqAccess<'de> for KnownLengthSeq<'a> { type Error = <&'a mut JavaDeserializer as Deserializer<'de>>::Error; fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where T: DeserializeSeed<'de> { @@ -197,7 +201,7 @@ impl<'de, 'a> SeqAccess<'de> for LengthPrefixedSeq<'a> { 0 => Ok(None), _ => { self.remaining -= 1; - seed.deserialize(self.de).map(Some) + seed.deserialize(&mut *self.de).map(Some) } } } diff --git a/src/main.rs b/src/main.rs index 472b001..10f8043 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,103 +1,11 @@ extern crate core; -mod serializer; -mod datatypes; -mod deserializer; +pub mod serde; mod packets; -use tokio::io::{AsyncRead}; -use tokio::net::{TcpListener, TcpStream}; - use std::error::Error; -use std::sync::Arc; -use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; -use async_trait::async_trait; #[tokio::main] async fn main() -> Result<(), Box> { - let listen_addr = String::from("127.0.0.1:25565"); - - println!("Listening on: {}", listen_addr); - - let listener = TcpListener::bind(listen_addr).await?; - - while let Ok((inbound, addr)) = listener.accept().await { - //TODO - } - Ok(()) -} -pub struct Stoppable { - interruptor: tokio::sync::oneshot::Receiver, - interrupted: tokio::sync::oneshot::Sender -} - -pub struct Stopper { - interruptable: tokio::sync::oneshot::Sender, - interrupted: tokio::sync::oneshot::Receiver -} - -impl Stopper { - pub fn new() -> (Stopper, Stoppable) { - let (interruptable, interruptor) = tokio::sync::oneshot::channel(); - let (interrupted_s, interrupted_r) = tokio::sync::oneshot::channel(); - - (Stopper {interruptable, interrupted: interrupted_r}, Stoppable {interruptor, interrupted: interrupted_s}) - } - - pub async fn stop(&mut self) { - if self.interruptable.is_closed() { - return; - } - self.interruptable.send(true).unwrap_or_default(); - self.interrupted.await.expect_err("Send on Stopper.interrupted occured"); - } -} - -pub trait InputStream {} -pub trait OutputStream {} - -pub struct StoppableAsyncRead { - inner: T, - stoppable: Stoppable -} - -impl StoppableAsyncRead { - pub fn new(inner: T, stoppable: Stoppable) -> StoppableAsyncRead { - StoppableAsyncRead { inner, stoppable } - } - - pub fn unwrap(self) -> T { - self.inner - } -} - -impl InputStream for StoppableAsyncRead {} - -impl OutputStream for OwnedWriteHalf {} - -#[async_trait] -pub trait Reader { - async fn run(self, stream: T, connection: Arc); -} - -pub struct Connection { - writer: Box>, - stopper: Stopper -} - -impl Connection { - pub fn new>>(stream: TcpStream, reader: T) -> Arc { - let (read, write) = stream.into_split(); - let (stopper, stoppable) = Stopper::new(); - - let connection = Arc::new(Connection { - writer: Box::new(parking_lot::Mutex::new(write)), - stopper - }); - - tokio::spawn(reader.run(StoppableAsyncRead::new(read, stoppable), connection.clone())); - - connection - } } \ No newline at end of file diff --git a/src/oldmain.rs b/src/oldmain.rs new file mode 100644 index 0000000..f196865 --- /dev/null +++ b/src/oldmain.rs @@ -0,0 +1,128 @@ +use tokio::io; +use tokio::io::{AsyncRead, AsyncWriteExt}; +use tokio::net::{TcpListener, TcpStream}; + +use futures::FutureExt; +use std::error::Error; +use std::sync::Arc; +use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf}; +use async_trait::async_trait; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let listen_addr = String::from("127.0.0.1:25565"); + let server_addr = String::from("steamwar.de:25565"); + + println!("Listening on: {}", listen_addr); + println!("Proxying to: {}", server_addr); + + let listener = TcpListener::bind(listen_addr).await?; + + while let Ok((inbound, _)) = listener.accept().await { + let transfer = transfer(inbound, server_addr.clone()).map(|r| { + if let Err(e) = r { + println!("Failed to transfer; error={}", e); + } + }); + + tokio::spawn(transfer); + } + + Ok(()) +} + +pub struct Stoppable { + interruptor: tokio::sync::oneshot::Receiver, + interrupted: tokio::sync::oneshot::Sender +} + +pub struct Stopper { + interruptable: tokio::sync::oneshot::Sender, + interrupted: tokio::sync::oneshot::Receiver +} + +impl Stopper { + pub fn new() -> (Stopper, Stoppable) { + let (interruptable, interruptor) = tokio::sync::oneshot::channel(); + let (interrupted_s, interrupted_r) = tokio::sync::oneshot::channel(); + + (Stopper {interruptable, interrupted: interrupted_r}, Stoppable {interruptor, interrupted: interrupted_s}) + } + + pub async fn stop(&mut self) { + if self.interruptable.is_closed() { + return; + } + self.interruptable.send(true).unwrap_or_default(); + self.interrupted.await.expect_err("Send on Stopper.interrupted occured"); + } +} + +pub trait InputStream {} +pub trait OutputStream {} + +pub struct StoppableAsyncRead { + inner: T, + stoppable: Stoppable +} + +impl StoppableAsyncRead { + pub fn new(inner: T, stoppable: Stoppable) -> StoppableAsyncRead { + StoppableAsyncRead { inner, stoppable } + } + + pub fn unwrap(self) -> T { + self.inner + } +} + +impl InputStream for StoppableAsyncRead {} + +impl OutputStream for OwnedWriteHalf {} + +#[async_trait] +pub trait Reader { + async fn run(self, stream: T, connection: Arc); +} + +pub struct Connection { + writer: Box>, + stopper: Stopper +} + +impl Connection { + pub fn new>>(stream: TcpStream, reader: T) -> Arc { + let (read, write) = stream.into_split(); + let (stopper, stoppable) = Stopper::new(); + + let connection = Arc::new(Connection { + writer: Box::new(parking_lot::Mutex::new(write)), + stopper + }); + + tokio::spawn(reader.run(StoppableAsyncRead::new(read, stoppable), connection.clone())); + + connection + } +} + +async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box> { + let mut outbound = TcpStream::connect(proxy_addr).await?; + + let (mut ri, mut wi) = inbound.split(); + let (mut ro, mut wo) = outbound.split(); + + let client_to_server = async { + io::copy(&mut ri, &mut wo).await?; + wo.shutdown().await + }; + + let server_to_client = async { + io::copy(&mut ro, &mut wi).await?; + wi.shutdown().await + }; + + tokio::try_join!(client_to_server, server_to_client)?; + + Ok(()) +} \ No newline at end of file diff --git a/src/packets.rs b/src/packets.rs index 7dc2e5b..149a933 100644 --- a/src/packets.rs +++ b/src/packets.rs @@ -1,31 +1,111 @@ -mod handshake { - use serde::{Serialize, Deserialize}; - use crate::datatypes::{NextState, VarInt}; +pub mod handshake { + use crate::serde::{VarInt, JavaSerializable, NextState}; - #[derive(Serialize, Deserialize, Debug)] + #[derive(JavaSerializable, Debug)] pub struct HandshakePacket { - protocol_version: VarInt, - server_address: String, - server_port: u16, - next_state: NextState + pub protocol_version: VarInt, + pub server_address: String, + pub server_port: u16, + pub next_state: NextState } } -mod status { - use serde::{Serialize, Deserialize}; - use crate::datatypes::StatusResponse; +pub mod status { + use crate::serde::{JavaSerializable, StatusResponse}; - #[derive(Serialize, Deserialize, Debug)] - pub struct RequestPacket {} + #[derive(JavaSerializable, Debug)] + pub struct RequestPacket{} - #[derive(Serialize, Deserialize, Debug)] + #[derive(JavaSerializable, Debug)] pub struct ResponsePacket { - response: StatusResponse + pub response: StatusResponse } - #[derive(Serialize, Deserialize, Debug)] + #[derive(JavaSerializable, Debug)] pub struct PingPacket { - payload: u64 + pub payload: i64 } } +pub mod login { + use bytes::{BufMut, Bytes, BytesMut}; + use crate::serde::{VarInt, JavaSerializable, Chat, JavaDeserError}; + + #[derive(JavaSerializable, Debug)] + pub struct DisconnectPacket{ + reason: Chat + } + + #[derive(JavaSerializable, Debug)] + pub struct EncryptionRequestPacket { + server_id: String, + public_key: Vec::, + verify_token: Vec:: + } + + #[derive(JavaSerializable, Debug)] + pub struct LoginSuccessPacket { + uuid: String, //TODO: UUID + username: String + } + + #[derive(JavaSerializable, Debug)] + pub struct SetCompressionPacket { + threshold: VarInt + } + + #[derive(JavaSerializable, Debug)] + pub struct PluginRequestPacket { + message_id: VarInt, + channel: String, //TODO: Identifier + data: Vec:: //TODO: Length inferred by packet length + } + + #[derive(JavaSerializable, Debug)] + pub struct LoginStartPacket { + name: String + } + + #[derive(JavaSerializable, Debug)] + pub struct EncryptionResponsePacket { + shared_secret: Vec::, + verify_token: Vec:: + } + + #[derive(Debug)] + pub enum PluginResponseSuccessful { + Successful(Vec), + Failed + } + impl JavaSerializable for PluginResponseSuccessful { + fn size_in_bytes(&self) -> usize { + match self { + PluginResponseSuccessful::Successful(v) => true.size_in_bytes() + v.len(), + PluginResponseSuccessful::Failed => false.size_in_bytes() + } + } + + fn serialize(&self, buf: &mut BytesMut) { + match self { + PluginResponseSuccessful::Successful(v) => { + true.serialize(buf); + buf.put_slice(v.as_slice()) + } + PluginResponseSuccessful::Failed => false.serialize(buf) + } + } + + fn deserialize(buf: &mut Bytes) -> Result { + match bool::deserialize(buf)? { + true => Ok(PluginResponseSuccessful::Successful(buf.to_vec())), + false => Ok(PluginResponseSuccessful::Failed) + } + } + } + + #[derive(JavaSerializable, Debug)] + pub struct PluginResponsePacket { + message_id: VarInt, + data: PluginResponseSuccessful + } +} diff --git a/src/serde.rs b/src/serde.rs new file mode 100644 index 0000000..849d11a --- /dev/null +++ b/src/serde.rs @@ -0,0 +1,431 @@ +use std::ops::{DerefMut, Deref}; +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use crate::serde::JavaDeserError::{InvalidValue, MissingBytes}; + +pub use lixcraft_derive::JavaSerializable; + +pub enum JavaDeserError { + InvalidValue, + MissingBytes +} + +pub trait JavaSerializable: Sized { + fn size_in_bytes(&self) -> usize; + fn serialize(&self, buf: &mut BytesMut); + fn deserialize(buf: &mut Bytes) -> Result; // where Self: Sized +} + +impl JavaSerializable for bool { + fn size_in_bytes(&self) -> usize { + 1 + } + + fn serialize(&self, buf: &mut BytesMut) { + match *self { + true => buf.put_u8(1), + false => buf.put_u8(0) + } + } + + fn deserialize(buf: &mut Bytes) -> Result { + match buf.len() > 0 { + true => match buf.get_u8() { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(InvalidValue) + }, + false => Err(MissingBytes) + } + } +} + +macro_rules! save_get { + ($s:expr, $b:expr, $g:ident) => { + match $b.len() >= $s { + true => Ok($b.$g()), + false => Err(MissingBytes) + } + } +} + +macro_rules! impl_num { + ($t:ty, $s:expr, $p:ident, $g:ident) => { + impl JavaSerializable for $t { + fn size_in_bytes(&self) -> usize { + $s + } + + fn serialize(&self, buf: &mut BytesMut) { + buf.$p(*self) + } + + fn deserialize(buf: &mut Bytes) -> Result { + save_get!($s, buf, $g) + } + } + } +} + +impl_num!(i8, 1, put_i8, get_i8); +impl_num!(u8, 1, put_u8, get_u8); +impl_num!(i16, 2, put_i16, get_i16); +impl_num!(u16, 2, put_u16, get_u16); +impl_num!(i32, 4, put_i32, get_i32); +impl_num!(i64, 8, put_i64, get_i64); +impl_num!(f32, 4, put_f32, get_f32); +impl_num!(f64, 8, put_f64, get_f64); + +macro_rules! impl_wrapper { + ($t:ty, $f:ty, $c:expr) => { + impl From<$t> for $f { + fn from(v: $t) -> Self { + v.0 + } + } + + impl Deref for $t { + type Target = $f; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl DerefMut for $t { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + impl From<$f> for $t { + fn from(v: $f) -> Self { + $c(v) + } + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct VarInt(pub i32); +impl_wrapper!(VarInt, i32, VarInt); + +impl From for usize { + fn from(v: VarInt) -> Self { + v.0 as usize + } +} + +impl From for VarInt { + fn from(v: usize) -> Self { + VarInt(v as i32) + } +} + +macro_rules! impl_varnum_ser { + ($u:ty, $v:expr, $b:expr) => { + { + let mut v = $v as $u; + loop { + if v & 0x80 == 0 { + $b.put_u8(v as u8); + return; + } + + $b.put_u8((v as u8 & 0x7f) | 0x80); + v >>= 7; + } + } + } +} + +macro_rules! impl_varnum_de { + ($t:ty, $r:expr, $b:expr, $m:expr) => { + let mut num_read = 0; + loop { + let read = save_get!(1, $b, get_u8)?; + let value = <$t>::from(read & 0x7f); + $r |= value.overflowing_shl(7 * num_read).0; + + num_read += 1; + + if num_read > $m { + return Err(InvalidValue); + } + if read & 0x80 == 0 { + break; + } + } + } +} + +impl JavaSerializable for VarInt { + fn size_in_bytes(&self) -> usize { + match **self { + 0..=127 => 1, + 128..=16383 => 2, + 16384..=2097151 => 3, + 2097152..=268435455 => 4, + _ => 5 + } + } + + fn serialize(&self, buf: &mut BytesMut) { + impl_varnum_ser!(u32, **self, buf) + } + + fn deserialize(buf: &mut Bytes) -> Result { + let mut result = 0; + impl_varnum_de!(i32, result, buf, 5); + Ok(VarInt(result)) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct VarLong(pub i64); +impl_wrapper!(VarLong, i64, VarLong); + +impl JavaSerializable for VarLong { + fn size_in_bytes(&self) -> usize { + match **self { + 0..=127 => 1, + 128..=16383 => 2, + 16384..=2097151 => 3, + 2097152..=268435455 => 4, + 268435456..=34359738367 => 5, + 34359738368..=4398046511103 => 6, + 4398046511104..=562949953421311 => 7, + 562949953421312..=72057594037927935 => 8, + 72057594037927936..=9223372036854775807 => 9, + _ => 10 + } + } + + fn serialize(&self, buf: &mut BytesMut) { + impl_varnum_ser!(u64, **self, buf) + } + + fn deserialize(buf: &mut Bytes) -> Result { + let mut result = 0; + impl_varnum_de!(i64, result, buf, 10); + Ok(VarLong(result)) + } +} + +impl JavaSerializable for String { + fn size_in_bytes(&self) -> usize { + VarInt(self.len() as i32).size_in_bytes() + self.len() + } + + fn serialize(&self, buf: &mut BytesMut) { + VarInt(self.len() as i32).serialize(buf); + buf.put_slice(self.as_bytes()) + } + + fn deserialize(buf: &mut Bytes) -> Result { + let len = VarInt::deserialize(buf)?; + Ok(String::from_utf8(buf.split_to(usize::from(len)).to_vec()).map_err(|_| InvalidValue)?) + } +} + +impl JavaSerializable for Vec { + fn size_in_bytes(&self) -> usize { + VarInt(self.len() as i32).size_in_bytes() + self.len() + } + + fn serialize(&self, buf: &mut BytesMut) { + VarInt(self.len() as i32).serialize(buf); + for i in self.iter() { + i.serialize(buf) + } + } + + fn deserialize(buf: &mut Bytes) -> Result { + let len = VarInt::deserialize(buf)?; + let mut result = Vec::with_capacity(usize::from(len)); + for _ in 0..*len { + result.push(T::deserialize(buf)?) + } + Ok(result) + } +} + +#[derive(Debug)] +pub enum NextState { + Status, + Login +} + +impl JavaSerializable for NextState { + fn size_in_bytes(&self) -> usize { + 1 + } + + fn serialize(&self, buf: &mut BytesMut) { + VarInt::from(match self { + NextState::Status => 1, + NextState::Login => 2 + }).serialize(buf) + } + + fn deserialize(buf: &mut Bytes) -> Result { + match VarInt::deserialize(buf)? { + VarInt(1) => Ok(NextState::Status), + VarInt(2) => Ok(NextState::Login), + _ => Err(InvalidValue) + } + } +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct StatusResponseVersion { + pub name: String, + pub protocol: i32 +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct StatusResponseSample { + pub name: String, + pub id: String +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct StatusResponsePlayers { + pub max: i32, + pub online: i32, + pub sample: Vec +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct StatusResponseDescription { + pub text: String +} + +macro_rules! impl_json { + ($t:ty) => { + impl JavaSerializable for $t { + fn size_in_bytes(&self) -> usize { + serde_json::to_string(self).unwrap().size_in_bytes() + } + + fn serialize(&self, buf: &mut BytesMut) { + serde_json::to_string(self).unwrap().serialize(buf) + } + + fn deserialize(buf: &mut Bytes) -> Result { + match serde_json::from_str(&String::deserialize(buf)?) { + Ok(v) => Ok(v), + Err(_) => Err(InvalidValue) + } + } + } + } +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct StatusResponse { + pub version: StatusResponseVersion, + pub players: StatusResponsePlayers, + pub description: StatusResponseDescription, + #[serde(skip_serializing_if = "Option::is_none")] + pub favicon: Option +} +impl_json!(StatusResponse); + + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +//TODO: Serialize, Deserialize +pub enum Font { + Uniform, //minecraft:uniform + Alt, //minecraft:alt + Default //minecraft:default +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum ClickEventAction { + open_url, + run_command, + suggest_command, + change_page, + copy_to_clipboard +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct ClickEvent { + action: ClickEventAction, + value: String +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum HoverEventAction { + show_text, + show_item, + show_entity +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct HoverEvent { + action: HoverEventAction, + value: String //or Chat (Recursion!) +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct SharedChat { + //#[serde(skip_serializing_if = "Option::is_none")] + bold: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + italic: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + underlined: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + strikethrough: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + obfuscated: bool, + //#[serde(skip_serializing_if = "Option::is_none")] + font: Font, + //#[serde(skip_serializing_if = "Option::is_none")] + color: String, //TODO Color code, format code or hex code + //#[serde(skip_serializing_if = "Option::is_none")] + insertion: String, + //#[serde(skip_serializing_if = "Option::is_none")] + clickEvent: ClickEvent, + //#[serde(skip_serializing_if = "Option::is_none")] + hoverEvent: HoverEvent, + //#[serde(skip_serializing_if = "Option::is_none")] + extra: Vec +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct Score { + name: String, //Or UUID + objective: String, + value: String +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum Chat { + StringComponent { + #[serde(flatten)] + options: SharedChat, + text: String + }, + TranslationComponent { + #[serde(flatten)] + options: SharedChat, + translate: String //TODO Special strings + }, + KeybindComponent { + #[serde(flatten)] + options: SharedChat, + keybind: String + }, + ScoreComponent { + #[serde(flatten)] + options: SharedChat, + score: Score + }, + SelectorComponent { + #[serde(flatten)] + options: SharedChat, + selector: String //TODO ominous + } +} +impl_json!(Chat); \ No newline at end of file diff --git a/src/serdemain.rs b/src/serdemain.rs new file mode 100644 index 0000000..1cb4dc4 --- /dev/null +++ b/src/serdemain.rs @@ -0,0 +1,127 @@ +extern crate core; + +mod serializer; +mod datatypes; +mod deserializer; +mod packets; +mod ser; + +use tokio::net::{TcpListener, TcpStream}; +use tokio_stream::StreamExt; + +use std::error::Error; +use std::io::ErrorKind; +use std::net::SocketAddr; +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use tokio_util::codec::{Decoder, Encoder, Framed}; +use crate::datatypes::VarInt; +use crate::deserializer::JavaDeserializer; +use crate::packets::handshake::HandshakePacket; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let listen_addr = String::from("127.0.0.1:25565"); + + println!("Listening on: {}", listen_addr); + + let listener = TcpListener::bind(listen_addr).await?; + + while let Ok((inbound, addr)) = listener.accept().await { + tokio::spawn(async move {process_initial(inbound, addr)}); + } + + Ok(()) +} + +async fn process_initial(stream: TcpStream, addr: SocketAddr) { + let mut framed = Framed::new(stream, LengthPrefixedFrame {}); + match framed.next().await { + Some(Ok(buf)) => { + match JavaDeserializer::from_bytes(buf.freeze()) { + Ok(v) => { + let v: HandshakePacket = v; + println!("{:?}", v); + }, + Err(_) => {} + } + }, + None | Some(Err(_)) => {} + } +} + + +enum VarIntReadError { + BytesMissing, + InvalidData +} + +pub struct LengthPrefixedFrame {}//TODO: Max expected length + +impl LengthPrefixedFrame { + fn try_read_var_int(src: &mut BytesMut) -> Result<(VarInt, usize), VarIntReadError> { + let src = src.chunk(); + let mut num_read = 0; + let mut result = 0; + loop { + if src.len() <= num_read { + return Err(VarIntReadError::BytesMissing) + } + let read = src[num_read]; + let value = i32::from(read & 0b0111_1111); + result |= value.overflowing_shl((7 * num_read) as u32).0; + + num_read += 1; + + if num_read > 5 { + return Err(VarIntReadError::InvalidData); + } + if read & 0b1000_0000 == 0 { + break; + } + } + Ok((VarInt(result), num_read)) + } +} + +impl Decoder for LengthPrefixedFrame { + type Item = BytesMut; + type Error = tokio::io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + match LengthPrefixedFrame::try_read_var_int(src) { + Ok((length, prefix_length)) => { + let total_length = prefix_length + usize::from(length); + + if src.len() >= total_length { + src.advance(prefix_length); + Ok(Some(src.split_to(usize::from(length)))) + } else { + Ok(None) + } + }, + Err(VarIntReadError::BytesMissing) => Ok(None), + Err(VarIntReadError::InvalidData) => Err(tokio::io::Error::from(ErrorKind::InvalidData)) + } + } +} +impl Encoder for LengthPrefixedFrame { + type Error = tokio::io::Error; + + fn encode(&mut self, data: Bytes, dst: &mut BytesMut) -> Result<(), Self::Error> { + dst.reserve(5 + data.len()); + + let mut v = data.len(); + loop { + if v & 0x80 == 0 { + dst.put_u8(v as u8); + break; + } + + dst.put_u8((v as u8 & 0x7f) | 0x80); + v >>= 7; + } + + dst.put_slice(&data); + Ok(()) + } +} \ No newline at end of file diff --git a/src/serializer.rs b/src/serializer.rs index dc55b9c..8ab7eaf 100644 --- a/src/serializer.rs +++ b/src/serializer.rs @@ -113,7 +113,7 @@ impl<'a> Serializer for &'a mut JavaSerializer { fn serialize_str(self, v: &str) -> Result { let v = v.as_bytes(); - VarInt::serialize(&VarInt::from(v.len()), self)?; + VarInt::serialize(&VarInt::from(v.len()), &mut *self)?; self.serialize_bytes(v) } @@ -155,7 +155,7 @@ impl<'a> Serializer for &'a mut JavaSerializer { fn serialize_seq(self, len: Option) -> Result { match len { - Some(v) => VarInt::from(v).serialize(self)?, + Some(v) => VarInt::from(v).serialize(&mut *self)?, None => () } Ok(self) @@ -191,7 +191,7 @@ impl<'a> SerializeSeq for &'a mut JavaSerializer { type Error = <&'a mut JavaSerializer as Serializer>::Error; fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize { - value.serialize(*self) + value.serialize(&mut **self) } fn end(self) -> Result { @@ -204,7 +204,7 @@ impl<'a> SerializeStruct for &'a mut JavaSerializer { type Error = <&'a mut JavaSerializer as Serializer>::Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: Serialize { - value.serialize(*self) + value.serialize(&mut **self) } fn end(self) -> Result {