tools: Add proxy tool to debug packets · feather-rs/feather@d3661c7 · GitHub
Skip to content

Commit d3661c7

Browse files
committed
tools: Add proxy tool to debug packets
1 parent 464759c commit d3661c7

15 files changed

Lines changed: 559 additions & 123 deletions

File tree

Cargo.lock

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions

crates/protocol/src/codec.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ impl MinecraftCodec {
4646
/// Writes a packet into the provided writer.
4747
pub fn encode(&mut self, packet: &impl Writeable, output: &mut Vec<u8>) {
4848
packet.write(&mut self.staging_buf, ProtocolVersion::V1_16_2);
49+
4950
if let Some(threshold) = self.compression {
5051
self.encode_compressed(output, threshold);
5152
} else {
@@ -87,10 +88,16 @@ impl MinecraftCodec {
8788

8889
let mut cursor = Cursor::new(&self.received_buf[..]);
8990
let packet = if let Ok(length) = VarInt::read(&mut cursor, ProtocolVersion::V1_16_2) {
90-
if self.received_buf.len() - cursor.position() as usize >= length.0 as usize {
91+
let length_field_length = cursor.position() as usize;
92+
93+
if self.received_buf.len() - length_field_length >= length.0 as usize {
94+
cursor = Cursor::new(
95+
&self.received_buf
96+
[length_field_length..length_field_length + length.0 as usize],
97+
);
9198
let packet = T::read(&mut cursor, ProtocolVersion::V1_16_2)?;
9299

93-
let bytes_read = cursor.position() as usize;
100+
let bytes_read = cursor.position() as usize + length_field_length;
94101
self.received_buf = self.received_buf.split_off(bytes_read);
95102

96103
Some(packet)

crates/protocol/src/lib.rs

Lines changed: 163 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use anyhow::anyhow;
12
use base::ItemStack;
23

34
pub mod codec;
@@ -23,32 +24,173 @@ pub enum ProtocolVersion {
2324
V1_16_2,
2425
}
2526

26-
/// Denotes a type which may be treated as a packet.
27-
///
28-
/// If you want to store arbitrary packets (e.g. for sending
29-
/// over a channel), use [`Packet`](crate::Packet) instead,
30-
/// as it does not require boxing.
31-
pub trait PacketTrait: Readable + Writeable {
32-
/// Returns the ID of this packet for the given protocol version.
33-
fn id(version: ProtocolVersion) -> u32
34-
where
35-
Self: Sized;
36-
}
37-
38-
/// Current state of the connection.
39-
/// This state is updated during the login
40-
/// sequence. See wiki.vg.
27+
/// A protocol state.
4128
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
42-
pub enum Stage {
29+
pub enum ProtocolState {
4330
Handshake,
4431
Status,
4532
Login,
4633
Play,
4734
}
4835

49-
/// Direction in which a packet is sent.
50-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
51-
pub enum PacketDirection {
52-
Clientbound,
53-
Serverbound,
36+
/// Reads an arbitrary packet sent by a client based on a dynamically-updated
37+
/// protocol state. As opposed to `MinecraftCodec`, this struct does not type-encode
38+
/// the current protocol state using generics.
39+
///
40+
/// This is a wrapper around a `MinecraftCodec` but more useful in certain sitations
41+
/// (e.g. when writing a proxy.)
42+
pub struct ClientPacketCodec {
43+
state: ProtocolState,
44+
codec: MinecraftCodec,
45+
}
46+
47+
impl ClientPacketCodec {
48+
pub fn new() -> Self {
49+
Self {
50+
state: ProtocolState::Handshake,
51+
codec: MinecraftCodec::new(),
52+
}
53+
}
54+
55+
pub fn set_state(&mut self, state: ProtocolState) {
56+
self.state = state
57+
}
58+
59+
/// Decodes a `ClientPacket` using the provided data.
60+
pub fn decode(&mut self, data: &[u8]) -> anyhow::Result<Option<ClientPacket>> {
61+
match self.state {
62+
ProtocolState::Handshake => self
63+
.codec
64+
.decode::<ClientHandshakePacket>(data)
65+
.map(|opt| opt.map(ClientPacket::from)),
66+
ProtocolState::Status => self
67+
.codec
68+
.decode::<ClientStatusPacket>(data)
69+
.map(|opt| opt.map(ClientPacket::from)),
70+
ProtocolState::Login => self
71+
.codec
72+
.decode::<ClientLoginPacket>(data)
73+
.map(|opt| opt.map(ClientPacket::from)),
74+
ProtocolState::Play => self
75+
.codec
76+
.decode::<ClientPlayPacket>(data)
77+
.map(|opt| opt.map(ClientPacket::from)),
78+
}
79+
}
80+
81+
/// Encodes a `ClientPacket` into a buffer.
82+
pub fn encode(&mut self, packet: &ClientPacket, buffer: &mut Vec<u8>) {
83+
match packet {
84+
ClientPacket::Handshake(packet) => self.codec.encode(packet, buffer),
85+
ClientPacket::Status(packet) => self.codec.encode(packet, buffer),
86+
ClientPacket::Login(packet) => self.codec.encode(packet, buffer),
87+
ClientPacket::Play(packet) => self.codec.encode(packet, buffer),
88+
}
89+
}
90+
}
91+
92+
/// Similar to `ClientPacketCodec` but for server-sent packets.
93+
pub struct ServerPacketCodec {
94+
state: ProtocolState,
95+
codec: MinecraftCodec,
96+
}
97+
98+
impl ServerPacketCodec {
99+
pub fn new() -> Self {
100+
Self {
101+
state: ProtocolState::Handshake,
102+
codec: MinecraftCodec::new(),
103+
}
104+
}
105+
106+
pub fn set_state(&mut self, state: ProtocolState) {
107+
self.state = state
108+
}
109+
110+
/// Decodes a `ServerPacket` using the provided data.
111+
pub fn decode(&mut self, data: &[u8]) -> anyhow::Result<Option<ServerPacket>> {
112+
match self.state {
113+
ProtocolState::Handshake => Err(anyhow!("server sent data during handshake state")),
114+
ProtocolState::Status => self
115+
.codec
116+
.decode::<ServerStatusPacket>(data)
117+
.map(|opt| opt.map(ServerPacket::from)),
118+
ProtocolState::Login => self
119+
.codec
120+
.decode::<ServerLoginPacket>(data)
121+
.map(|opt| opt.map(ServerPacket::from)),
122+
ProtocolState::Play => self
123+
.codec
124+
.decode::<ServerPlayPacket>(data)
125+
.map(|opt| opt.map(ServerPacket::from)),
126+
}
127+
}
128+
129+
/// Encodes a `ServerPacket` into a buffer.
130+
pub fn encode(&mut self, packet: &ServerPacket, buffer: &mut Vec<u8>) {
131+
match packet {
132+
ServerPacket::Status(packet) => self.codec.encode(packet, buffer),
133+
ServerPacket::Login(packet) => self.codec.encode(packet, buffer),
134+
ServerPacket::Play(packet) => self.codec.encode(packet, buffer),
135+
}
136+
}
137+
}
138+
139+
/// A packet sent by the client from any one of the packet stages.
140+
#[derive(Debug, Clone)]
141+
pub enum ClientPacket {
142+
Handshake(ClientHandshakePacket),
143+
Status(ClientStatusPacket),
144+
Login(ClientLoginPacket),
145+
Play(ClientPlayPacket),
146+
}
147+
148+
impl From<ClientHandshakePacket> for ClientPacket {
149+
fn from(packet: ClientHandshakePacket) -> Self {
150+
ClientPacket::Handshake(packet)
151+
}
152+
}
153+
154+
impl From<ClientStatusPacket> for ClientPacket {
155+
fn from(packet: ClientStatusPacket) -> Self {
156+
ClientPacket::Status(packet)
157+
}
158+
}
159+
160+
impl From<ClientLoginPacket> for ClientPacket {
161+
fn from(packet: ClientLoginPacket) -> Self {
162+
ClientPacket::Login(packet)
163+
}
164+
}
165+
166+
impl From<ClientPlayPacket> for ClientPacket {
167+
fn from(packet: ClientPlayPacket) -> Self {
168+
ClientPacket::Play(packet)
169+
}
170+
}
171+
172+
/// A packet sent by the server from any one of the packet stages.
173+
#[derive(Debug, Clone)]
174+
pub enum ServerPacket {
175+
Status(ServerStatusPacket),
176+
Login(ServerLoginPacket),
177+
Play(ServerPlayPacket),
178+
}
179+
180+
impl From<ServerStatusPacket> for ServerPacket {
181+
fn from(packet: ServerStatusPacket) -> Self {
182+
ServerPacket::Status(packet)
183+
}
184+
}
185+
186+
impl From<ServerLoginPacket> for ServerPacket {
187+
fn from(packet: ServerLoginPacket) -> Self {
188+
ServerPacket::Login(packet)
189+
}
190+
}
191+
192+
impl From<ServerPlayPacket> for ServerPacket {
193+
fn from(packet: ServerPlayPacket) -> Self {
194+
ServerPacket::Play(packet)
195+
}
54196
}

crates/protocol/src/packets/server/play.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,11 +410,12 @@ impl DimensionCodec {
410410
packets! {
411411
JoinGame {
412412
entity_id i32;
413+
is_hardcore bool;
413414
gamemode Gamemode;
414-
previous_gamemode Gamemode;
415+
previous_gamemode u8; // can be 255 if "not set," otherwise corresponds to a gamemode ID
415416
world_names LengthPrefixedVec<String>;
416417

417-
dimension_codec Nbt<DimensionCodec>;
418+
dimension_codec Nbt<Blob>;
418419
dimension Nbt<Blob>;
419420

420421
world_name String;

crates/server/src/entity.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! Network interface for working with entities.
22
3-
use base::{Position, Setup, State};
3+
use base::{Gamemode, Position, Setup, State};
44
use common::{entity::player, Name};
55
use ecs::{Entity, EntityBuilder, EntityRef, SysResult};
66
use protocol::{packets::server::SpawnPlayer, ServerPlayPacket};
77
use uuid::Uuid;
88

9-
use crate::network::{Network, NewPlayer};
9+
use crate::{network::NewPlayer, session::Session};
1010

1111
/// The network ID of an entity. This is the "entity_id" field
1212
/// for many packets.
@@ -91,9 +91,11 @@ pub fn build_player(s: &State, builder: &mut EntityBuilder, player: NewPlayer) -
9191
builder
9292
.add(SpawnPacket::new(player_spawn_packet)) // TODO
9393
.add(player.uuid)
94-
.add(Network::new(player.worker))
94+
.add(player.worker.clone())
95+
.add(Session::new_vanilla(player.worker))
9596
.add(player.addr)
96-
.add(Name(player.username));
97+
.add(Name(player.username))
98+
.add(Gamemode::Creative);
9799
Ok(())
98100
}
99101

crates/server/src/init.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44

55
use anyhow::Context;
66
use async_executor::Executor;
7-
use base::{Setup, State};
7+
use base::{anvil::level::LevelData, Setup, State};
88
use ecs::SystemExecutor;
99
use future::block_on;
1010
use futures_lite::future;
@@ -40,7 +40,11 @@ pub fn init() -> anyhow::Result<(State, SystemExecutor<State>)> {
4040
);
4141

4242
let mut setup = Setup::new();
43-
setup.resource(server).resource(listener).resource(executor);
43+
setup
44+
.resource(server)
45+
.resource(listener)
46+
.resource(executor)
47+
.resource(LevelData::default());
4448

4549
common::setup(&mut setup);
4650
crate::setup(&mut setup);

crates/server/src/main.rs

Lines changed: 6 additions & 1 deletion

0 commit comments

Comments
 (0)