added velocity support
This commit is contained in:
parent
8434884747
commit
d4cf718214
10 changed files with 221 additions and 35 deletions
83
Cargo.lock
generated
83
Cargo.lock
generated
|
@ -38,6 +38,15 @@ version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
|
@ -108,6 +117,15 @@ version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -117,6 +135,16 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.83"
|
version = "1.0.83"
|
||||||
|
@ -161,6 +189,17 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -220,6 +259,16 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hematite-nbt"
|
name = "hematite-nbt"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -241,6 +290,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -465,10 +523,12 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"hematite-nbt",
|
"hematite-nbt",
|
||||||
|
"hmac",
|
||||||
"log",
|
"log",
|
||||||
"mlua",
|
"mlua",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -561,6 +621,23 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.105"
|
version = "1.0.105"
|
||||||
|
@ -592,6 +669,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
|
|
@ -14,3 +14,5 @@ uuid = "1.2"
|
||||||
log = "0.4.0"
|
log = "0.4.0"
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
hmac = "0.12"
|
||||||
|
sha2 = "0.10"
|
||||||
|
|
|
@ -2,13 +2,25 @@ use std::{net::IpAddr, fs::OpenOptions};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum LoginMode {
|
||||||
|
Offline,
|
||||||
|
Velocity,
|
||||||
|
// TODO online, bungeecord
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub addr: IpAddr,
|
pub addr: IpAddr,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
|
pub login: LoginMode,
|
||||||
|
pub velocity_secret: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config() -> Result<Config, Box<dyn std::error::Error>> {
|
pub fn load_config() -> Result<Config, Box<dyn std::error::Error>> {
|
||||||
let config = serde_json::from_reader(OpenOptions::new().read(true).open("./config.json")?)?;
|
let config: Config = serde_json::from_reader(OpenOptions::new().read(true).open("./config.json")?)?;
|
||||||
|
if config.login == LoginMode::Velocity && config.velocity_secret.is_none() {
|
||||||
|
Err("Velocity is enabled but no secret is configured")?
|
||||||
|
}
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
@ -41,17 +40,16 @@ fn main() {
|
||||||
writeln!(buf, "\x1b[90m[\x1b[37m{} {color}{}\x1b[37m {}\x1b[90m]\x1b[0m {}", now, record.level(), target, record.args())
|
writeln!(buf, "\x1b[90m[\x1b[37m{} {color}{}\x1b[37m {}\x1b[90m]\x1b[0m {}", now, record.level(), target, record.args())
|
||||||
}).init();
|
}).init();
|
||||||
|
|
||||||
let config = load_config().expect("Failed to load config");
|
|
||||||
let addr = SocketAddr::new(config.addr, config.port);
|
|
||||||
|
|
||||||
info!("Starting Quectocraft version {}", VERSION);
|
info!("Starting Quectocraft version {}", VERSION);
|
||||||
|
|
||||||
|
let config = load_config().expect("Failed to load config");
|
||||||
|
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let mut plugins = Plugins::new(&lua).expect("Error initializing lua environment");
|
let mut plugins = Plugins::new(&lua).expect("Error initializing lua environment");
|
||||||
std::fs::create_dir_all("plugins").expect("Couldn't create the plugins directory");
|
std::fs::create_dir_all("plugins").expect("Couldn't create the plugins directory");
|
||||||
plugins.load_plugins();
|
plugins.load_plugins();
|
||||||
|
|
||||||
let mut server = NetworkServer::new(addr, plugins);
|
let mut server = NetworkServer::new(config, plugins);
|
||||||
let sleep_dur = Duration::from_millis(5);
|
let sleep_dur = Duration::from_millis(5);
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::Player;
|
||||||
|
|
||||||
pub struct NetworkClient {
|
pub struct NetworkClient {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub play: bool,
|
pub verified: bool,
|
||||||
pub closed: bool,
|
pub closed: bool,
|
||||||
pub stream: TcpStream,
|
pub stream: TcpStream,
|
||||||
pub serverbound: Receiver<ServerBoundPacket>,
|
pub serverbound: Receiver<ServerBoundPacket>,
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use std::{net::{TcpListener, SocketAddr}, thread, sync::mpsc::{Receiver, Sender, channel}, collections::HashSet};
|
use std::{net::{TcpListener, SocketAddr}, thread, sync::mpsc::{Receiver, Sender, channel}, collections::HashSet};
|
||||||
|
|
||||||
use log::{info, warn, debug};
|
use hmac::{Hmac, Mac};
|
||||||
|
use log::{info, warn, debug, trace};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use sha2::Sha256;
|
||||||
|
|
||||||
use crate::protocol::{data::PacketEncoder, serverbound::*, clientbound::*, command::Commands, Position};
|
use crate::{protocol::{data::PacketEncoder, serverbound::*, clientbound::*, command::Commands, Position}, config::{Config, LoginMode}};
|
||||||
use crate::plugins::{Plugins, Response};
|
use crate::plugins::{Plugins, Response};
|
||||||
use crate::VERSION;
|
use crate::VERSION;
|
||||||
|
|
||||||
|
@ -14,18 +16,20 @@ pub struct NetworkServer<'lua> {
|
||||||
commands: Commands,
|
commands: Commands,
|
||||||
new_clients: Receiver<NetworkClient>,
|
new_clients: Receiver<NetworkClient>,
|
||||||
clients: Vec<NetworkClient>,
|
clients: Vec<NetworkClient>,
|
||||||
|
config: Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'lua> NetworkServer<'lua> {
|
impl <'lua> NetworkServer<'lua> {
|
||||||
pub fn new(addr: SocketAddr, mut plugins: Plugins<'lua>) -> Self {
|
pub fn new(config: Config, mut plugins: Plugins<'lua>) -> Self {
|
||||||
let (send, recv) = channel();
|
let (send, recv) = channel();
|
||||||
info!("Initializing plugins");
|
info!("Initializing plugins");
|
||||||
plugins.init();
|
plugins.init();
|
||||||
let mut commands = Commands::new();
|
let mut commands = Commands::new();
|
||||||
commands.create_simple_cmd("qc");
|
commands.create_simple_cmd("qc");
|
||||||
let commands = plugins.register_commands(commands).unwrap();
|
let commands = plugins.register_commands(commands).unwrap();
|
||||||
thread::spawn(move || Self::listen(&addr, send));
|
thread::spawn(move || Self::listen(&SocketAddr::new(config.addr, config.port), send));
|
||||||
Self {
|
Self {
|
||||||
|
config,
|
||||||
plugins,
|
plugins,
|
||||||
commands,
|
commands,
|
||||||
new_clients: recv,
|
new_clients: recv,
|
||||||
|
@ -44,7 +48,7 @@ impl <'lua> NetworkServer<'lua> {
|
||||||
thread::spawn(|| NetworkClient::listen(stream_2, send));
|
thread::spawn(|| NetworkClient::listen(stream_2, send));
|
||||||
let client = NetworkClient {
|
let client = NetworkClient {
|
||||||
id: id as i32,
|
id: id as i32,
|
||||||
play: false,
|
verified: false,
|
||||||
closed: false,
|
closed: false,
|
||||||
stream,
|
stream,
|
||||||
serverbound: recv,
|
serverbound: recv,
|
||||||
|
@ -63,13 +67,11 @@ impl <'lua> NetworkServer<'lua> {
|
||||||
pub fn send_keep_alive(&mut self) {
|
pub fn send_keep_alive(&mut self) {
|
||||||
let mut closed = Vec::new();
|
let mut closed = Vec::new();
|
||||||
for client in self.clients.iter_mut() {
|
for client in self.clients.iter_mut() {
|
||||||
if client.play {
|
if client.player.is_some() {
|
||||||
let result = client.send_packet(ClientBoundPacket::KeepAlive(0));
|
let result = client.send_packet(ClientBoundPacket::KeepAlive(0));
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
client.close();
|
client.close();
|
||||||
if let Some(pl) = &client.player {
|
self.plugins.player_leave(client.player.as_ref().unwrap());
|
||||||
self.plugins.player_leave(pl);
|
|
||||||
}
|
|
||||||
closed.push(client.id);
|
closed.push(client.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +89,7 @@ impl <'lua> NetworkServer<'lua> {
|
||||||
while let Some(packet) = client.recv_packet(&mut alive) {
|
while let Some(packet) = client.recv_packet(&mut alive) {
|
||||||
let result = self.handle_packet(client, packet);
|
let result = self.handle_packet(client, packet);
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
|
warn!("error: {}", result.unwrap_err());
|
||||||
alive = false;
|
alive = false;
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -102,7 +105,7 @@ impl <'lua> NetworkServer<'lua> {
|
||||||
for response in self.plugins.get_responses() {
|
for response in self.plugins.get_responses() {
|
||||||
let _ = self.handle_plugin_response(response);
|
let _ = self.handle_plugin_response(response);
|
||||||
}
|
}
|
||||||
self.clients.retain(|x| !closed.contains(&x.id));
|
self.clients.retain(|x| !closed.contains(&x.id) && !x.closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_plugin_response(&mut self, response: Response) -> std::io::Result<()> {
|
fn handle_plugin_response(&mut self, response: Response) -> std::io::Result<()> {
|
||||||
|
@ -137,7 +140,8 @@ impl <'lua> NetworkServer<'lua> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_packet(&mut self, client: &mut NetworkClient, packet: ServerBoundPacket) -> std::io::Result<()> {
|
fn handle_packet(&mut self, client: &mut NetworkClient, packet: ServerBoundPacket) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
trace!("Recieved packet from client {}:", client.id);
|
||||||
match packet {
|
match packet {
|
||||||
ServerBoundPacket::Ignored(_) => (),
|
ServerBoundPacket::Ignored(_) => (),
|
||||||
ServerBoundPacket::Unknown(id) => warn!("Unknown packet: {}", id),
|
ServerBoundPacket::Unknown(id) => warn!("Unknown packet: {}", id),
|
||||||
|
@ -152,21 +156,80 @@ impl <'lua> NetworkServer<'lua> {
|
||||||
}
|
}
|
||||||
ServerBoundPacket::LoginStart(login_start) => {
|
ServerBoundPacket::LoginStart(login_start) => {
|
||||||
if self.clients.iter().filter_map(|x| x.player.as_ref()).any(|x| x.uuid == login_start.uuid) {
|
if self.clients.iter().filter_map(|x| x.player.as_ref()).any(|x| x.uuid == login_start.uuid) {
|
||||||
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({"translate": "multiplayer.disconnect.duplicate_login"})))?;
|
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({
|
||||||
|
"translate": "multiplayer.disconnect.duplicate_login"
|
||||||
|
})))?;
|
||||||
client.close();
|
client.close();
|
||||||
} else {
|
return Ok(())
|
||||||
|
}
|
||||||
client.player = Some(Player {
|
client.player = Some(Player {
|
||||||
name: login_start.name.clone(),
|
name: login_start.name.clone(),
|
||||||
uuid: login_start.uuid,
|
uuid: login_start.uuid,
|
||||||
});
|
});
|
||||||
client.play = true;
|
match self.config.login {
|
||||||
|
LoginMode::Offline => {
|
||||||
|
client.verified = true;
|
||||||
|
client.send_packet(ClientBoundPacket::LoginPluginRequest{
|
||||||
|
id: -1,
|
||||||
|
channel: "qc:init".to_owned(),
|
||||||
|
data: Vec::new()
|
||||||
|
})?;
|
||||||
|
},
|
||||||
|
LoginMode::Velocity => {
|
||||||
|
client.send_packet(ClientBoundPacket::LoginPluginRequest{
|
||||||
|
id: 10,
|
||||||
|
channel: "velocity:player_info".to_owned(),
|
||||||
|
data: vec![1],
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Finalize login
|
||||||
|
ServerBoundPacket::LoginPluginResponse { id: -1, .. } => {
|
||||||
|
if !client.verified {
|
||||||
|
client.send_packet(ClientBoundPacket::Disconnect(json!({
|
||||||
|
"text": "Failed to verify your connection",
|
||||||
|
"color": "red",
|
||||||
|
})))?;
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
client.send_packet(ClientBoundPacket::LoginSuccess(LoginSuccess {
|
client.send_packet(ClientBoundPacket::LoginSuccess(LoginSuccess {
|
||||||
name: login_start.name,
|
name: client.player.as_ref().unwrap().name.to_owned(),
|
||||||
uuid: login_start.uuid,
|
uuid: client.player.as_ref().unwrap().uuid,
|
||||||
}))?;
|
}))?;
|
||||||
self.plugins.player_join(client.player.as_ref().unwrap());
|
self.plugins.player_join(client.player.as_ref().unwrap());
|
||||||
self.post_login(client)?;
|
self.post_login(client)?;
|
||||||
}
|
}
|
||||||
|
// Velocity login
|
||||||
|
ServerBoundPacket::LoginPluginResponse { id: 10, data } => {
|
||||||
|
let Some(data) = data else {
|
||||||
|
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({
|
||||||
|
"text": "This server can only be connected to via a Velocity proxy",
|
||||||
|
"color": "red"
|
||||||
|
})))?;
|
||||||
|
client.close();
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let (sig, data) = data.split_at(32);
|
||||||
|
let mut mac = Hmac::<Sha256>::new_from_slice(self.config.velocity_secret.clone().unwrap().as_bytes())?;
|
||||||
|
mac.update(data);
|
||||||
|
if let Err(_) = mac.verify_slice(sig) {
|
||||||
|
client.send_packet(ClientBoundPacket::Disconnect(json!({
|
||||||
|
"text": "Could not verify secret. Ensure that the secrets configured for Velocity and Quectocraft match."
|
||||||
|
})))?;
|
||||||
|
client.close();
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
client.verified = true;
|
||||||
|
client.send_packet(ClientBoundPacket::LoginPluginRequest{
|
||||||
|
id: -1,
|
||||||
|
channel: "qc:init".to_owned(),
|
||||||
|
data: Vec::new()
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
ServerBoundPacket::LoginPluginResponse { .. } => {
|
||||||
|
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({"text": "bad plugin response"})))?;
|
||||||
|
client.close();
|
||||||
}
|
}
|
||||||
ServerBoundPacket::ChatMessage(msg) => {
|
ServerBoundPacket::ChatMessage(msg) => {
|
||||||
self.plugins.chat_message(client.player.as_ref().unwrap(), &msg.message);
|
self.plugins.chat_message(client.player.as_ref().unwrap(), &msg.message);
|
||||||
|
|
|
@ -142,6 +142,7 @@ pub enum ClientBoundPacket {
|
||||||
StatusResponse(String),
|
StatusResponse(String),
|
||||||
PingResponse(i64),
|
PingResponse(i64),
|
||||||
// login
|
// login
|
||||||
|
LoginPluginRequest { id: i32, channel: String, data: Vec<u8> },
|
||||||
LoginSuccess(LoginSuccess),
|
LoginSuccess(LoginSuccess),
|
||||||
LoginDisconnect(serde_json::Value),
|
LoginDisconnect(serde_json::Value),
|
||||||
// play
|
// play
|
||||||
|
@ -175,6 +176,12 @@ impl ClientBoundPacket {
|
||||||
packet.write_string(262144, &message.to_string());
|
packet.write_string(262144, &message.to_string());
|
||||||
finalize_packet(packet, 0)
|
finalize_packet(packet, 0)
|
||||||
}
|
}
|
||||||
|
Self::LoginPluginRequest { id, channel, data } => {
|
||||||
|
packet.write_varint(id);
|
||||||
|
packet.write_string(32767, &channel);
|
||||||
|
packet.write_bytes(&data);
|
||||||
|
finalize_packet(packet, 4)
|
||||||
|
}
|
||||||
Self::LoginSuccess(login_success) => {
|
Self::LoginSuccess(login_success) => {
|
||||||
login_success.encode(&mut packet);
|
login_success.encode(&mut packet);
|
||||||
finalize_packet(packet, 2)
|
finalize_packet(packet, 2)
|
||||||
|
|
|
@ -50,7 +50,8 @@ pub trait PacketEncoder: Write {
|
||||||
self.write_all(&data.to_be_bytes()).unwrap();
|
self.write_all(&data.to_be_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_varint(&mut self, mut data: i32) {
|
fn write_varint(&mut self, data: i32) {
|
||||||
|
let mut data = data as u32;
|
||||||
loop {
|
loop {
|
||||||
let mut byte = (data & 0b11111111) as u8;
|
let mut byte = (data & 0b11111111) as u8;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
|
@ -64,7 +65,8 @@ pub trait PacketEncoder: Write {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_varlong(&mut self, mut data: i64) {
|
fn write_varlong(&mut self, data: i64) {
|
||||||
|
let mut data = data as u64;
|
||||||
loop {
|
loop {
|
||||||
let mut byte = (data & 0b11111111) as u8;
|
let mut byte = (data & 0b11111111) as u8;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
|
@ -161,6 +163,12 @@ impl PacketDecoder {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_to_end(&mut self) -> &[u8] {
|
||||||
|
let ret = &self.data[self.idx..];
|
||||||
|
self.idx = self.data.len();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_bool(&mut self) -> bool {
|
pub fn read_bool(&mut self) -> bool {
|
||||||
self.idx += 1;
|
self.idx += 1;
|
||||||
self.data[self.idx-1] != 0
|
self.data[self.idx-1] != 0
|
||||||
|
|
|
@ -71,6 +71,7 @@ pub enum ServerBoundPacket {
|
||||||
PingRequest(i64),
|
PingRequest(i64),
|
||||||
// login
|
// login
|
||||||
LoginStart(LoginStart),
|
LoginStart(LoginStart),
|
||||||
|
LoginPluginResponse { id: i32, data: Option<Vec<u8>> },
|
||||||
// play
|
// play
|
||||||
ChatMessage(ChatMessage),
|
ChatMessage(ChatMessage),
|
||||||
ChatCommand(ChatMessage),
|
ChatCommand(ChatMessage),
|
||||||
|
@ -94,9 +95,21 @@ impl ServerBoundPacket {
|
||||||
(NS::Status, 1)
|
(NS::Status, 1)
|
||||||
=> ServerBoundPacket::PingRequest(decoder.read_long()),
|
=> ServerBoundPacket::PingRequest(decoder.read_long()),
|
||||||
(NS::Login, 0) => {
|
(NS::Login, 0) => {
|
||||||
*state = NS::Play;
|
|
||||||
ServerBoundPacket::LoginStart(LoginStart::decode(decoder))
|
ServerBoundPacket::LoginStart(LoginStart::decode(decoder))
|
||||||
},
|
},
|
||||||
|
(NS::Login, 2) => {
|
||||||
|
let id = decoder.read_varint();
|
||||||
|
let success = decoder.read_bool();
|
||||||
|
let data = if success {
|
||||||
|
Some(decoder.read_to_end().to_vec())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if id == -1 {
|
||||||
|
*state = NetworkState::Play;
|
||||||
|
}
|
||||||
|
ServerBoundPacket::LoginPluginResponse { id, data }
|
||||||
|
},
|
||||||
(NS::Play, 4) => ServerBoundPacket::ChatCommand(ChatMessage::decode(decoder)),
|
(NS::Play, 4) => ServerBoundPacket::ChatCommand(ChatMessage::decode(decoder)),
|
||||||
(NS::Play, 5) => ServerBoundPacket::ChatMessage(ChatMessage::decode(decoder)),
|
(NS::Play, 5) => ServerBoundPacket::ChatMessage(ChatMessage::decode(decoder)),
|
||||||
(NS::Play, id @ (17 | 19 | 20 | 21 | 29)) => ServerBoundPacket::Ignored(id),
|
(NS::Play, id @ (17 | 19 | 20 | 21 | 29)) => ServerBoundPacket::Ignored(id),
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue