refactored

This commit is contained in:
TriMill 2022-12-18 00:43:01 -05:00
parent a3375c53a4
commit 278e28ad18
5 changed files with 321 additions and 227 deletions

View file

@ -43,8 +43,8 @@ impl NetworkClient {
} }
} }
pub fn send_packet(&mut self, packet: ClientBoundPacket) -> std::io::Result<()> { pub fn send_packet(&mut self, packet: impl ClientBoundPacket) -> std::io::Result<()> {
self.stream.write_all(&packet.encode())?; self.stream.write_all(&encode_packet(packet))?;
Ok(()) Ok(())
} }

View file

@ -68,7 +68,7 @@ impl <'lua> NetworkServer<'lua> {
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.player.is_some() { if client.player.is_some() {
let result = client.send_packet(ClientBoundPacket::KeepAlive(0)); let result = client.send_packet(KeepAlive { data: 0 });
if result.is_err() { if result.is_err() {
client.close(); client.close();
self.plugins.player_leave(client.player.as_ref().unwrap()); self.plugins.player_leave(client.player.as_ref().unwrap());
@ -114,7 +114,7 @@ impl <'lua> NetworkServer<'lua> {
for client in self.clients.iter_mut() { for client in self.clients.iter_mut() {
if let Some(p) = &client.player { if let Some(p) = &client.player {
if p.name == player || p.uuid.to_string() == player { if p.name == player || p.uuid.to_string() == player {
client.send_packet(ClientBoundPacket::SystemChatMessage(message, false))?; client.send_packet(SystemChatMessage { message, overlay: false })?;
break break
} }
} }
@ -123,7 +123,7 @@ impl <'lua> NetworkServer<'lua> {
Response::Broadcast { message } => { Response::Broadcast { message } => {
for client in self.clients.iter_mut() { for client in self.clients.iter_mut() {
if client.player.is_some() { if client.player.is_some() {
client.send_packet(ClientBoundPacket::SystemChatMessage(message.clone(), false))?; client.send_packet(SystemChatMessage { message: message.clone(), overlay: false })?;
} }
} }
}, },
@ -131,7 +131,7 @@ impl <'lua> NetworkServer<'lua> {
for client in self.clients.iter_mut() { for client in self.clients.iter_mut() {
if let Some(pl) = &client.player { if let Some(pl) = &client.player {
if pl.name == player || pl.uuid.to_string() == player { if pl.name == player || pl.uuid.to_string() == player {
client.send_packet(ClientBoundPacket::Disconnect(reason.clone()))?; client.send_packet(Disconnect { reason: reason.clone() })?;
} }
} }
} }
@ -147,88 +147,21 @@ impl <'lua> NetworkServer<'lua> {
ServerBoundPacket::Unknown(id) => warn!("Unknown packet: {}", id), ServerBoundPacket::Unknown(id) => warn!("Unknown packet: {}", id),
ServerBoundPacket::Handshake(_) => (), ServerBoundPacket::Handshake(_) => (),
ServerBoundPacket::StatusRequest() ServerBoundPacket::StatusRequest()
=> client.send_packet(ClientBoundPacket::StatusResponse( => client.send_packet(StatusResponse {
r#"{"version":{"name":"1.19.3","protocol":761}}"#.to_owned() data: r#"{"version":{"name":"1.19.3","protocol":761}}"#.to_owned()
))?, })?,
ServerBoundPacket::PingRequest(n) => { ServerBoundPacket::PingRequest(n) => {
client.send_packet(ClientBoundPacket::PingResponse(n))?; client.send_packet(PingResponse { data: n })?;
client.close(); client.close();
} }
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) { => self.start_login(client, login_start)?,
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({ ServerBoundPacket::LoginPluginResponse(LoginPluginResponse { id: 10, data })
"translate": "multiplayer.disconnect.duplicate_login" => self.velocity_login(client, data)?,
})))?; ServerBoundPacket::LoginPluginResponse(LoginPluginResponse{ id: -1, .. })
client.close(); => self.login(client)?,
return Ok(())
}
client.player = Some(Player {
name: login_start.name.clone(),
uuid: login_start.uuid,
});
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 {
name: client.player.as_ref().unwrap().name.to_owned(),
uuid: client.player.as_ref().unwrap().uuid,
}))?;
self.plugins.player_join(client.player.as_ref().unwrap());
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 { .. } => { ServerBoundPacket::LoginPluginResponse { .. } => {
client.send_packet(ClientBoundPacket::LoginDisconnect(json!({"text": "bad plugin response"})))?; client.send_packet(LoginDisconnect { reason: json!({"text": "bad plugin response"}) })?;
client.close(); client.close();
} }
ServerBoundPacket::ChatMessage(msg) => { ServerBoundPacket::ChatMessage(msg) => {
@ -238,10 +171,10 @@ impl <'lua> NetworkServer<'lua> {
let mut parts = msg.message.splitn(1, " "); let mut parts = msg.message.splitn(1, " ");
if let Some(cmd) = parts.next() { if let Some(cmd) = parts.next() {
if cmd == "qc" { if cmd == "qc" {
client.send_packet(ClientBoundPacket::SystemChatMessage(json!({ client.send_packet(SystemChatMessage { message: json!({
"text": format!("QuectoCraft version {}", VERSION), "text": format!("QuectoCraft version {}", VERSION),
"color": "green" "color": "green"
}), false))?; }), overlay: false })?;
} else { } else {
let args = parts.next().unwrap_or_default(); let args = parts.next().unwrap_or_default();
self.plugins.command(client.player.as_ref().unwrap(), cmd, args); self.plugins.command(client.player.as_ref().unwrap(), cmd, args);
@ -252,12 +185,85 @@ impl <'lua> NetworkServer<'lua> {
Ok(()) Ok(())
} }
fn post_login(&mut self, client: &mut NetworkClient) -> std::io::Result<()> { fn start_login(&mut self, client: &mut NetworkClient, login_start: LoginStart) -> Result<(), Box<dyn std::error::Error>> {
client.send_packet(ClientBoundPacket::LoginPlay(LoginPlay { if self.clients.iter().filter_map(|x| x.player.as_ref()).any(|x| x.uuid == login_start.uuid) {
client.send_packet(LoginDisconnect { reason: json!({
"translate": "multiplayer.disconnect.duplicate_login"
})})?;
client.close();
return Ok(())
}
client.player = Some(Player {
name: login_start.name.clone(),
uuid: login_start.uuid,
});
match self.config.login {
LoginMode::Offline => {
client.verified = true;
client.send_packet(LoginPluginRequest{
id: -1,
channel: "qc:init".to_owned(),
data: Vec::new()
})?;
},
LoginMode::Velocity => {
client.send_packet(LoginPluginRequest{
id: 10,
channel: "velocity:player_info".to_owned(),
data: vec![1],
})?
}
}
Ok(())
}
fn velocity_login(&mut self, client: &mut NetworkClient, data: Option<Vec<u8>>) -> Result<(), Box<dyn std::error::Error>> {
let Some(data) = data else {
client.send_packet(LoginDisconnect { reason: 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(Disconnect { reason: 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(LoginPluginRequest{
id: -1,
channel: "qc:init".to_owned(),
data: Vec::new()
})?;
Ok(())
}
fn login(&mut self, client: &mut NetworkClient) -> std::io::Result<()> {
if !client.verified {
client.send_packet(Disconnect { reason: json!({
"text": "Failed to verify your connection",
"color": "red",
})})?;
client.close();
return Ok(())
}
client.send_packet(LoginSuccess {
name: client.player.as_ref().unwrap().name.to_owned(),
uuid: client.player.as_ref().unwrap().uuid,
})?;
self.plugins.player_join(client.player.as_ref().unwrap());
client.send_packet(LoginPlay {
eid: client.id, eid: client.id,
is_hardcore: false, is_hardcore: false,
gamemode: 1, gamemode: 3,
prev_gamemode: 1, prev_gamemode: 3,
dimensions: vec![ dimensions: vec![
"qc:world".to_owned(), "qc:world".to_owned(),
], ],
@ -273,16 +279,16 @@ impl <'lua> NetworkServer<'lua> {
is_debug: false, is_debug: false,
is_flat: false, is_flat: false,
death_location: None, death_location: None,
}))?; })?;
client.send_packet(ClientBoundPacket::PluginMessage(PluginMessage { client.send_packet(PluginMessage {
channel: "minecraft:brand".to_owned(), channel: "minecraft:brand".to_owned(),
data: { data: {
let mut data = Vec::new(); let mut data = Vec::new();
data.write_string(32767, &format!("Quectocraft {}", VERSION)); data.write_string(32767, &format!("Quectocraft {}", VERSION));
data data
} }
}))?; })?;
client.send_packet(ClientBoundPacket::Commands(self.commands.clone()))?; client.send_packet(self.commands.clone())?;
let mut chunk_data: Vec<u8> = Vec::new(); let mut chunk_data: Vec<u8> = Vec::new();
for _ in 0..(384 / 16) { for _ in 0..(384 / 16) {
// number of non-air blocks // number of non-air blocks
@ -299,16 +305,16 @@ impl <'lua> NetworkServer<'lua> {
let hmdata = vec![0i64; 37]; let hmdata = vec![0i64; 37];
let mut heightmap = nbt::Blob::new(); let mut heightmap = nbt::Blob::new();
heightmap.insert("MOTION_BLOCKING", hmdata).unwrap(); heightmap.insert("MOTION_BLOCKING", hmdata).unwrap();
client.send_packet(ClientBoundPacket::ChunkData(ChunkData { client.send_packet(ChunkData {
x: 0, x: 0,
z: 0, z: 0,
heightmap, heightmap,
chunk_data, chunk_data,
}))?; })?;
client.send_packet(ClientBoundPacket::SetDefaultSpawnPosition( client.send_packet(SetDefaultSpawnPosition {
Position { x: 0, y: 0, z: 0 }, 0.0 pos: Position { x: 0, y: 0, z: 0 }, angle: 0.0
))?; })?;
client.send_packet(ClientBoundPacket::SyncPlayerPosition(SyncPlayerPosition { client.send_packet(SyncPlayerPosition {
x: 0.0, x: 0.0,
y: 64.0, y: 64.0,
z: 0.0, z: 0.0,
@ -317,7 +323,7 @@ impl <'lua> NetworkServer<'lua> {
flags: 0, flags: 0,
teleport_id: 0, teleport_id: 0,
dismount: false dismount: false
}))?; })?;
// TODO why doesn't this work with quilt? // TODO why doesn't this work with quilt?
// client.send_packet(ClientBoundPacket::PlayerAbilities(0x0f, 0.05, 0.1))?; // client.send_packet(ClientBoundPacket::PlayerAbilities(0x0f, 0.05, 0.1))?;
Ok(()) Ok(())

View file

@ -1,6 +1,50 @@
use uuid::Uuid; use uuid::Uuid;
use super::{data::{PacketEncoder, finalize_packet}, Position, command::Commands}; use super::{data::{PacketEncoder, finalize_packet}, Position};
pub trait ClientBoundPacket: std::fmt::Debug {
fn encode(&self, encoder: &mut impl PacketEncoder);
fn packet_id(&self) -> i32;
}
//////////////////
// //
// Status //
// //
//////////////////
#[derive(Debug)]
pub struct PingResponse {
pub data: i64
}
impl ClientBoundPacket for PingResponse {
fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_long(self.data)
}
fn packet_id(&self) -> i32 { 0x01 }
}
#[derive(Debug)]
pub struct StatusResponse {
pub data: String
}
impl ClientBoundPacket for StatusResponse {
fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_string(32767, &self.data)
}
fn packet_id(&self) -> i32 { 0x00 }
}
/////////////////
// //
// Login //
// //
/////////////////
#[derive(Debug)] #[derive(Debug)]
pub struct LoginSuccess { pub struct LoginSuccess {
@ -8,14 +52,52 @@ pub struct LoginSuccess {
pub name: String, pub name: String,
} }
impl LoginSuccess { impl ClientBoundPacket for LoginSuccess {
pub fn encode(self, encoder: &mut impl PacketEncoder) { fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_uuid(self.uuid); encoder.write_uuid(self.uuid);
encoder.write_string(16, &self.name); encoder.write_string(16, &self.name);
encoder.write_varint(0); encoder.write_varint(0);
} }
fn packet_id(&self) -> i32 { 0x02 }
} }
#[derive(Debug)]
pub struct LoginPluginRequest {
pub id: i32,
pub channel: String,
pub data: Vec<u8>,
}
impl ClientBoundPacket for LoginPluginRequest {
fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_varint(self.id);
encoder.write_string(32767, &self.channel);
encoder.write_bytes(&self.data);
}
fn packet_id(&self) -> i32 { 0x04 }
}
#[derive(Debug)]
pub struct LoginDisconnect {
pub reason: serde_json::Value
}
impl ClientBoundPacket for LoginDisconnect {
fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_string(262144, &self.reason.to_string())
}
fn packet_id(&self) -> i32 { 0x00 }
}
////////////////
// //
// Play //
// //
////////////////
#[derive(Debug)] #[derive(Debug)]
pub struct LoginPlay { pub struct LoginPlay {
pub eid: i32, pub eid: i32,
@ -37,14 +119,14 @@ pub struct LoginPlay {
pub death_location: Option<(String, Position)> pub death_location: Option<(String, Position)>
} }
impl LoginPlay { impl ClientBoundPacket for LoginPlay {
pub fn encode(self, encoder: &mut impl PacketEncoder) { fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_int(self.eid); encoder.write_int(self.eid);
encoder.write_bool(self.is_hardcore); encoder.write_bool(self.is_hardcore);
encoder.write_ubyte(self.gamemode); encoder.write_ubyte(self.gamemode);
encoder.write_ubyte(self.prev_gamemode); encoder.write_ubyte(self.prev_gamemode);
encoder.write_varint(self.dimensions.len() as i32); encoder.write_varint(self.dimensions.len() as i32);
for dim in self.dimensions { for dim in &self.dimensions {
encoder.write_string(32767, &dim); encoder.write_string(32767, &dim);
} }
encoder.write_bytes(&self.registry_codec); encoder.write_bytes(&self.registry_codec);
@ -59,11 +141,13 @@ impl LoginPlay {
encoder.write_bool(self.is_debug); encoder.write_bool(self.is_debug);
encoder.write_bool(self.is_flat); encoder.write_bool(self.is_flat);
encoder.write_bool(self.death_location.is_some()); encoder.write_bool(self.death_location.is_some());
if let Some(dl) = self.death_location { if let Some(dl) = &self.death_location {
encoder.write_string(32767, &dl.0); encoder.write_string(32767, &dl.0);
encoder.write_position(dl.1); encoder.write_position(dl.1);
} }
} }
fn packet_id(&self) -> i32 { 0x24 }
} }
#[derive(Debug)] #[derive(Debug)]
@ -72,11 +156,13 @@ pub struct PluginMessage {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
impl PluginMessage { impl ClientBoundPacket for PluginMessage {
pub fn encode(self, encoder: &mut impl PacketEncoder) { fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_string(32767, &self.channel); encoder.write_string(32767, &self.channel);
encoder.write_bytes(&self.data); encoder.write_bytes(&self.data);
} }
fn packet_id(&self) -> i32 { 0x15 }
} }
#[derive(Debug)] #[derive(Debug)]
@ -91,8 +177,8 @@ pub struct SyncPlayerPosition {
pub dismount: bool, pub dismount: bool,
} }
impl SyncPlayerPosition { impl ClientBoundPacket for SyncPlayerPosition {
pub fn encode(self, encoder: &mut impl PacketEncoder) { fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_double(self.x); encoder.write_double(self.x);
encoder.write_double(self.y); encoder.write_double(self.y);
encoder.write_double(self.z); encoder.write_double(self.z);
@ -102,6 +188,8 @@ impl SyncPlayerPosition {
encoder.write_varint(self.teleport_id); encoder.write_varint(self.teleport_id);
encoder.write_bool(self.dismount); encoder.write_bool(self.dismount);
} }
fn packet_id(&self) -> i32 { 0x38 }
} }
#[derive(Debug)] #[derive(Debug)]
@ -112,8 +200,8 @@ pub struct ChunkData {
pub chunk_data: Vec<u8>, pub chunk_data: Vec<u8>,
} }
impl ChunkData { impl ClientBoundPacket for ChunkData {
pub fn encode(self, encoder: &mut impl PacketEncoder) { fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_int(self.x); encoder.write_int(self.x);
encoder.write_int(self.z); encoder.write_int(self.z);
self.heightmap.to_writer(encoder).unwrap(); self.heightmap.to_writer(encoder).unwrap();
@ -133,104 +221,86 @@ impl ChunkData {
// block light array // block light array
encoder.write_varint(0); encoder.write_varint(0);
} }
fn packet_id(&self) -> i32 { 0x20 }
} }
#[allow(unused)]
#[derive(Debug)] #[derive(Debug)]
pub enum ClientBoundPacket { pub struct KeepAlive {
// status pub data: i64
StatusResponse(String),
PingResponse(i64),
// login
LoginPluginRequest { id: i32, channel: String, data: Vec<u8> },
LoginSuccess(LoginSuccess),
LoginDisconnect(serde_json::Value),
// play
LoginPlay(LoginPlay),
PluginMessage(PluginMessage),
Commands(Commands),
ChunkData(ChunkData),
SyncPlayerPosition(SyncPlayerPosition),
KeepAlive(i64),
PlayerAbilities(i8, f32, f32),
Disconnect(serde_json::Value),
SetDefaultSpawnPosition(Position, f32),
SystemChatMessage(serde_json::Value, bool),
} }
impl ClientBoundPacket { impl ClientBoundPacket for KeepAlive {
pub fn encode(self) -> Vec<u8> { fn encode(&self, encoder: &mut impl PacketEncoder) {
let mut packet = Vec::new(); encoder.write_long(self.data)
match self {
// Status
Self::StatusResponse(status) => {
packet.write_string(32767, &status);
finalize_packet(packet, 0)
},
Self::PingResponse(n) => {
packet.write_long(n);
finalize_packet(packet, 1)
},
// Login
Self::LoginDisconnect(message) => {
packet.write_string(262144, &message.to_string());
finalize_packet(packet, 0)
} }
Self::LoginPluginRequest { id, channel, data } => {
packet.write_varint(id); fn packet_id(&self) -> i32 { 0x1f }
packet.write_string(32767, &channel);
packet.write_bytes(&data);
finalize_packet(packet, 4)
} }
Self::LoginSuccess(login_success) => {
login_success.encode(&mut packet); #[derive(Debug)]
finalize_packet(packet, 2) pub struct PlayerAbilities {
pub flags: i8,
pub fly_speed: f32,
pub fov_modifier: f32,
} }
// Play
Self::Disconnect(message) => { impl ClientBoundPacket for PlayerAbilities {
packet.write_string(262144, &message.to_string()); fn encode(&self, encoder: &mut impl PacketEncoder) {
finalize_packet(packet, 23) encoder.write_byte(self.flags);
encoder.write_float(self.fly_speed);
encoder.write_float(self.fov_modifier);
} }
Self::LoginPlay(login_play) => {
login_play.encode(&mut packet); fn packet_id(&self) -> i32 { 0x30 }
finalize_packet(packet, 36)
} }
Self::PluginMessage(plugin_message) => {
plugin_message.encode(&mut packet);
finalize_packet(packet, 21) #[derive(Debug)]
pub struct Disconnect {
pub reason: serde_json::Value
} }
Self::Commands(commands) => {
commands.encode(&mut packet); impl ClientBoundPacket for Disconnect {
finalize_packet(packet, 14) fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_string(262144, &self.reason.to_string())
} }
Self::ChunkData(chunk_data) => {
chunk_data.encode(&mut packet); fn packet_id(&self) -> i32 { 0x17 }
finalize_packet(packet, 32)
} }
Self::SyncPlayerPosition(sync_player_position) => {
sync_player_position.encode(&mut packet); #[derive(Debug)]
finalize_packet(packet, 56) pub struct SetDefaultSpawnPosition {
pub pos: Position,
pub angle: f32
} }
Self::KeepAlive(n) => {
packet.write_long(n); impl ClientBoundPacket for SetDefaultSpawnPosition {
finalize_packet(packet, 31) fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_position(self.pos);
encoder.write_float(self.angle);
} }
Self::SetDefaultSpawnPosition(pos, angle) => {
packet.write_position(pos); fn packet_id(&self) -> i32 { 0x4c }
packet.write_float(angle);
finalize_packet(packet, 76)
} }
Self::PlayerAbilities(flags, speed, view) => {
packet.write_byte(flags); #[derive(Debug)]
packet.write_float(speed); pub struct SystemChatMessage {
packet.write_float(view); pub message: serde_json::Value,
finalize_packet(packet, 48) pub overlay: bool
}
Self::SystemChatMessage(msg, overlay) => {
packet.write_string(262144, &msg.to_string());
packet.write_bool(overlay);
finalize_packet(packet, 96)
} }
impl ClientBoundPacket for SystemChatMessage {
fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_string(262144, &self.message.to_string());
encoder.write_bool(self.overlay);
} }
fn packet_id(&self) -> i32 { 0x60 }
} }
pub fn encode_packet(packet: impl ClientBoundPacket) -> Vec<u8> {
let mut buffer = Vec::new();
packet.encode(&mut buffer);
finalize_packet(buffer, packet.packet_id())
} }

View file

@ -1,10 +1,23 @@
use super::data::PacketEncoder; use super::{data::PacketEncoder, clientbound::ClientBoundPacket};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Commands { pub struct Commands {
nodes: Vec<CommandNode>, nodes: Vec<CommandNode>,
} }
impl ClientBoundPacket for Commands {
fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_varint(self.nodes.len() as i32);
for node in &self.nodes {
node.encode(encoder);
}
// root node
encoder.write_varint(0);
}
fn packet_id(&self) -> i32 { 0x0e }
}
impl Commands { impl Commands {
pub fn new() -> Self { pub fn new() -> Self {
let root = CommandNode { let root = CommandNode {
@ -67,14 +80,6 @@ impl Commands {
self.nodes[node as usize].children.push(child); self.nodes[node as usize].children.push(child);
} }
pub fn encode(&self, encoder: &mut impl PacketEncoder) {
encoder.write_varint(self.nodes.len() as i32);
for node in &self.nodes {
node.encode(encoder);
}
// root node
encoder.write_varint(0);
}
} }
pub enum NodeError { pub enum NodeError {

View file

@ -60,6 +60,25 @@ impl ChatMessage {
} }
} }
#[derive(Debug)]
pub struct LoginPluginResponse {
pub id: i32,
pub data: Option<Vec<u8>>,
}
impl LoginPluginResponse {
pub fn decode(mut decoder: PacketDecoder) -> Self {
let id = decoder.read_varint();
let success = decoder.read_bool();
let data = if success {
Some(decoder.read_to_end().to_vec())
} else {
None
};
Self { id, data }
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum ServerBoundPacket { pub enum ServerBoundPacket {
Unknown(i32), Unknown(i32),
@ -71,7 +90,7 @@ pub enum ServerBoundPacket {
PingRequest(i64), PingRequest(i64),
// login // login
LoginStart(LoginStart), LoginStart(LoginStart),
LoginPluginResponse { id: i32, data: Option<Vec<u8>> }, LoginPluginResponse(LoginPluginResponse),
// play // play
ChatMessage(ChatMessage), ChatMessage(ChatMessage),
ChatCommand(ChatMessage), ChatCommand(ChatMessage),
@ -98,17 +117,11 @@ impl ServerBoundPacket {
ServerBoundPacket::LoginStart(LoginStart::decode(decoder)) ServerBoundPacket::LoginStart(LoginStart::decode(decoder))
}, },
(NS::Login, 2) => { (NS::Login, 2) => {
let id = decoder.read_varint(); let lpr = LoginPluginResponse::decode(decoder);
let success = decoder.read_bool(); if lpr.id == -1 {
let data = if success {
Some(decoder.read_to_end().to_vec())
} else {
None
};
if id == -1 {
*state = NetworkState::Play; *state = NetworkState::Play;
} }
ServerBoundPacket::LoginPluginResponse { id, data } ServerBoundPacket::LoginPluginResponse(lpr)
}, },
(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)),