Skip to content

Commit efd54f5

Browse files
committed
compression ????!?!???
1 parent 422a65f commit efd54f5

File tree

14 files changed

+404
-22
lines changed

14 files changed

+404
-22
lines changed

Cargo.lock

Lines changed: 21 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
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ resolver = "2"
99

1010
[workspace.dependencies]
1111
oxcr_protocol.path = "protocol"
12+
oxcr_cli.path = "cli"
1213
tokio = { version = "1", features = [ "macros", "full", "rt", "sync" ] }
1314
derive_more.version = "0.99.17"
1415
tracing.version = "0"
@@ -17,3 +18,4 @@ bytes = { version = "1", features = [ "serde" ] }
1718
bevy = { version = "0.11.2", features = ["multi-threaded"], default-features = false }
1819
rayon = "1"
1920
itertools = "0"
21+
flate2 = "1"

cli/src/cli.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub enum CliCommand {
3232
Decode(ByteInput),
3333
Help,
3434
VarInt(ByteInput),
35+
Decompress(ByteInput),
3536
}
3637

3738
#[derive(Debug, Clone)]
@@ -46,10 +47,11 @@ pub enum Flag {
4647
Help,
4748
Decode(ByteInput),
4849
VarInt(ByteInput),
50+
Decompress(ByteInput),
4951
}
5052

5153
#[derive(Debug)]
52-
enum FlagName<'a> {
54+
pub enum FlagName<'a> {
5355
Short(&'a str),
5456
Long(&'a str),
5557
}
@@ -90,7 +92,7 @@ fn byte_input(input: &str) -> ByteInput {
9092
}
9193

9294
#[parser(extras = Extra)]
93-
fn flag_list(input: &str) -> Vec<FlagName<'a>> {
95+
pub fn flag_list(input: &str) -> Vec<FlagName<'a>> {
9496
if input.offset.saturating_sub(1) >= input.input.len() {
9597
return Ok(vec![]);
9698
}
@@ -134,6 +136,11 @@ fn flags(input: &str) -> Vec<Flag> {
134136

135137
Flag::Decode(byte_input(input)?)
136138
}
139+
FlagName::Short("c") | FlagName::Long("decompress") => {
140+
one_of(" =")(input)?;
141+
142+
Flag::Decompress(byte_input(input)?)
143+
}
137144
FlagName::Short("V") | FlagName::Long("varint") => {
138145
one_of(" =")(input)?;
139146

@@ -160,6 +167,7 @@ fn flags_handle<'a>(
160167
Flag::Help => cli.command = CliCommand::Help,
161168
Flag::Decode(input) => cli.command = CliCommand::Decode(input),
162169
Flag::VarInt(input) => cli.command = CliCommand::VarInt(input),
170+
Flag::Decompress(input) => cli.command = CliCommand::Decompress(input),
163171
}
164172
}
165173
try { flags(input)?.into_iter().for_each(|flag| handle(cli, flag)) }

cli/src/error.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{ops::Range, str::FromStr};
1+
use std::{borrow::Cow, num::ParseIntError, ops::Range, str::FromStr};
22

33
use oxcr_protocol::{
44
aott,
@@ -17,6 +17,8 @@ pub enum ParseError {
1717
found: char,
1818
#[label = "here"]
1919
at: SourceSpan,
20+
#[help]
21+
help: Option<Cow<'static, str>>,
2022
},
2123
#[error("unexpected end of input{}", .expected.as_ref().map(|expectation| format!(", expected {expectation}")).unwrap_or_else(String::new))]
2224
#[diagnostic(
@@ -44,6 +46,18 @@ pub enum ParseError {
4446
#[label = "here"]
4547
at: SourceSpan,
4648
},
49+
#[error("expected a number with radix {radix}, got {actual}")]
50+
#[diagnostic(code(cli::expected_number))]
51+
ExpectedNumber {
52+
radix: u32,
53+
actual: String,
54+
#[label = "here"]
55+
at: SourceSpan,
56+
#[help]
57+
help: Option<Cow<'static, str>>,
58+
#[source]
59+
error: ParseIntError,
60+
},
4761
}
4862

4963
#[derive(Debug, thiserror::Error)]
@@ -79,6 +93,7 @@ impl<'a> aott::error::Error<&'a str> for ParseError {
7993
expected: Expectation::AnyOf(expected),
8094
found: found.into_clone(),
8195
at: span.into(),
96+
help: None,
8297
}
8398
}
8499

@@ -87,6 +102,7 @@ impl<'a> aott::error::Error<&'a str> for ParseError {
87102
expected: Expectation::EndOfInput,
88103
found: found.into_clone(),
89104
at: span.into(),
105+
help: None,
90106
}
91107
}
92108
}

cli/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![feature(iterator_try_collect, try_blocks)]
2+
3+
mod cli;
4+
pub use cli::{flag_list, Extra, FlagName};
5+
mod error;
6+
pub use error::*;

cli/src/main.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mod cli;
2020
mod error;
2121

2222
fn run(_path: String, args: &str) -> Result<(), Report> {
23-
let tsub_guard = tracing_subscriber::fmt()
23+
let tracing_set_default_level = tracing_subscriber::fmt()
2424
.pretty()
2525
.with_env_filter(EnvFilter::from_env("OXCR_LOG"))
2626
.finish()
@@ -30,9 +30,9 @@ fn run(_path: String, args: &str) -> Result<(), Report> {
3030
.parse(args)
3131
.map_err(|parse_error| Report::new(parse_error).with_source_code(args.to_owned()))?;
3232

33-
drop(tsub_guard);
33+
drop(tracing_set_default_level);
3434

35-
let _tsub_guard = tracing_subscriber::fmt()
35+
let _tracing_set_real_level = tracing_subscriber::fmt()
3636
.with_env_filter(cli.level.to_string())
3737
.pretty()
3838
.set_default();
@@ -43,17 +43,15 @@ fn run(_path: String, args: &str) -> Result<(), Report> {
4343
CliCommand::Help => help(),
4444
CliCommand::Decode(inp) => {
4545
let bytes = read_byte_input(inp)?;
46-
let spack = SerializedPacket {
47-
length: LoginPlay::ID.length_of() + bytes.len(),
48-
data: bytes,
49-
id: LoginPlay::ID,
50-
};
46+
debug!("{bytes:?}");
47+
let spack = SerializedPacket::deserialize.parse(&bytes)?;
5148
let deserialized: LoginPlay = spack.try_deserialize(LoginPlay::STATE)?;
5249

5350
println!("{:#?}", deserialized);
5451
}
5552
CliCommand::VarInt(inp) => {
5653
let bytes = read_byte_input(inp)?;
54+
5755
println!(
5856
"{:#?}",
5957
VarInt::<i64>::deserialize
@@ -62,7 +60,8 @@ fn run(_path: String, args: &str) -> Result<(), Report> {
6260
.map_err(reconcile(bytes))?
6361
);
6462
}
65-
}
63+
CliCommand::Decompress(inp) => todo!(),
64+
};
6665

6766
Ok(())
6867
}

protocol/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ uuid = { version = "1.4.1", features = ["v3"] }
2121
bitflags = "2.4.0"
2222
miette = { version = "5.10.0", features = ["fancy"] }
2323
indexmap = { version = "2.0.0", features = ["serde"] }
24+
25+
flate2.workspace = true

protocol/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ impl PlayerNet {
156156

157157
return Err::<!, crate::error::Error>(e);
158158
});
159+
159160
let recv_task = tokio::spawn(async move {
160161
async {
161162
let mut buf = BytesMut::new();

protocol/src/model/packets.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,102 @@ impl Serialize for SerializedPacket {
119119
}
120120
}
121121

122+
#[derive(Debug, Clone)]
123+
pub struct SerializedPacketCompressed {
124+
pub length: usize,
125+
pub data_length: usize,
126+
pub id: Compress<super::VarInt, Zlib>,
127+
pub data: Compress<Bytes, Zlib>,
128+
}
129+
130+
impl SerializedPacketCompressed {
131+
pub fn new<P: Packet + Serialize>(packet: P) -> Result<Self, Error> {
132+
Self::new_ref(&packet)
133+
}
134+
135+
pub fn new_ref<P: Packet + Serialize + ?Sized>(packet: &P) -> Result<Self, Error> {
136+
try {
137+
let data = packet.serialize()?;
138+
let id = P::ID;
139+
let data_length = id.length_of() + data.len();
140+
let datalength = VarInt::<i32>(data_length.try_into().unwrap());
141+
let length = datalength.length_of() + Compress(datalength, Zlib).serialize()?.len();
142+
Self {
143+
length,
144+
data_length,
145+
id: Compress(id, Zlib),
146+
data: Compress(data, Zlib),
147+
}
148+
}
149+
}
150+
151+
pub fn try_deserialize<P: Packet + Deserialize<Context = PacketContext>>(
152+
&self,
153+
state: State,
154+
) -> Result<P, Error> {
155+
let context = PacketContext {
156+
id: self.id.0,
157+
state,
158+
};
159+
160+
P::deserialize
161+
.parse_with_context(self.data.0.as_ref(), context)
162+
.map_err(|e| match e {
163+
Error::Ser(error) => Error::SerSrc(WithSource {
164+
source: BytesSource::new(
165+
self.data.0.clone(),
166+
Some(format!("packet_0x{:x}.bin", self.id.0 .0)),
167+
),
168+
span: error.span,
169+
kind: error.kind,
170+
}),
171+
e => e,
172+
})
173+
}
174+
}
175+
176+
impl Deserialize for SerializedPacketCompressed {
177+
#[parser(extras = "Extra<Self::Context>")]
178+
fn deserialize(input: &[u8]) -> Self {
179+
try {
180+
let packet_length_varint = VarInt::<i32>::deserialize(input)?;
181+
assert!(packet_length_varint.0 >= 0);
182+
let packet_length = packet_length_varint.0 as usize;
183+
let data_length_varint = VarInt::<i32>::deserialize(input)?;
184+
assert!(data_length_varint.0 >= 0);
185+
let data_length = data_length_varint.0 as usize;
186+
let id: Compress<VarInt<i32>, Zlib> = Compress::decompress(Bytes::copy_from_slice(
187+
input.input.slice_from(input.offset..),
188+
))?;
189+
let data = Compress::decompress(Bytes::from(
190+
take(data_length - id.0.length_of()).parse_with(input)?,
191+
))?;
192+
Self {
193+
length: packet_length,
194+
data_length,
195+
id,
196+
data,
197+
}
198+
}
199+
}
200+
}
201+
202+
impl Serialize for SerializedPacketCompressed {
203+
fn serialize_to(&self, buf: &mut BytesMut) -> Result<(), Error> {
204+
let length = VarInt::<i32>(self.length.try_into().map_err(|_| Error::VarIntTooBig)?);
205+
length.serialize_to(buf)?;
206+
let data_length = VarInt::<i32>(
207+
self.data_length
208+
.try_into()
209+
.map_err(|_| Error::VarIntTooBig)?,
210+
);
211+
data_length.serialize_to(buf)?;
212+
self.id.serialize_to(buf)?;
213+
self.data.serialize_to(buf)?;
214+
Ok(())
215+
}
216+
}
217+
122218
#[derive(Debug, Clone)]
123219
pub struct PluginMessage {
124220
pub channel: Identifier,

protocol/src/model/packets/play.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,34 @@ impl Packet for SetDefaultSpawnPosition {
196196
const ID: crate::model::VarInt = VarInt(0x50);
197197
const STATE: crate::model::State = State::Play;
198198
}
199+
200+
/// This packet tells the client that it should enable support for the feature flags listed in the `feature_flags` field.
201+
/// Note that adding arbitrary identifiers (instead of the constants under this struct,
202+
/// like `FEATURE_VANILLA` or `FEATURE_BUNDLE`) to the list may cause the client to explode.
203+
///
204+
/// # Info
205+
/// Packet ID: 0x6b
206+
/// State: Play
207+
/// Bound to: Client
208+
///
209+
/// # Layout
210+
/// Total Features: VarInt ;; number of elements in the next array
211+
/// Feature Flags: Array<Identifier>
212+
#[derive(Debug, Clone)]
213+
pub struct FeatureFlags {
214+
pub feature_flags: Array<Identifier>,
215+
}
216+
217+
impl Packet for FeatureFlags {
218+
const ID: crate::model::VarInt = VarInt(0x6b);
219+
const STATE: crate::model::State = State::Play;
220+
}
221+
222+
impl_ser!(|PacketContext| FeatureFlags => [feature_flags]);
223+
224+
impl FeatureFlags {
225+
/// A feature flag that enables all vanilla features in the notchian client.
226+
pub const FEATURE_VANILLA: Identifier = Identifier::new_static(Namespace::Minecraft, "vanilla");
227+
/// A feature flag that enables support for bundles in the notchian client.
228+
pub const FEATURE_BUNDLE: Identifier = Identifier::new_static(Namespace::Minecraft, "bundle");
229+
}

0 commit comments

Comments
 (0)