Skip to content

Commit 339f0cb

Browse files
committed
wip feat: velocity forwarding
1 parent 18a6995 commit 339f0cb

File tree

5 files changed

+101
-9
lines changed

5 files changed

+101
-9
lines changed

src/args.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ pub struct Args {
3030
/// The port to serve crawlspace on. Defaults to 25565 if not set.
3131
#[arg(short, long, default_value = "25565", env = "LIMBO_PORT")]
3232
pub port: u16,
33+
// Whether or not to enable Velocity forwarding.
34+
#[arg(short, long, default_value = "true", env = "LIMBO_VELOCITY_FORWARDING")]
35+
pub velocity_forwarding: bool,
3336
/// The x coordinate of the spawnpoint.
3437
#[arg(short = 'x', long, default_value = "0", env = "LIMBO_SPAWN_X")]
3538
pub spawn_x: f64,

src/net/player.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use uuid::Uuid;
3838

3939
use crate::{
4040
protocol::{
41-
datatypes::{Bounded, Slot, VarInt},
41+
datatypes::{Bounded, Bytes, Rest, Slot, VarInt},
4242
packets::{
4343
login::*,
4444
play::{
@@ -230,8 +230,16 @@ impl SharedPlayer {
230230
let uuid = login.player_uuid;
231231
let username = login.name.0.to_owned();
232232

233-
#[cfg(feature = "encryption")]
234-
self.login_velocity(&username).await?;
233+
if state.velocity_forwarding {
234+
let understood = self.login_velocity().await?;
235+
236+
if !understood {
237+
warn!(
238+
"Velocity forwarding is on, but client {} did not properly respond to our forwarding request. This will kick in future.",
239+
self.0.id
240+
)
241+
}
242+
}
235243

236244
let success = LoginSuccessC {
237245
uuid,
@@ -262,17 +270,20 @@ impl SharedPlayer {
262270
Ok(())
263271
}
264272

265-
#[cfg(feature = "encryption")]
266-
async fn login_velocity(&self, _username: &str) -> Result<()> {
273+
async fn login_velocity(&self) -> Result<bool> {
267274
let req = PluginRequestC {
268275
message_id: VarInt(0),
269276
channel: Bounded("velocity:player_info"),
270-
data: Bounded(Bytes(&[3])),
277+
data: Rest(Bytes(&[3])),
271278
};
272279

273280
self.0.io.tx(&req).await?;
274281

275-
Ok(())
282+
let res = self.0.io.rx::<PluginResponseS>().await?;
283+
let res: PluginResponseS = res.decode()?;
284+
285+
// todo: replace with a profile maybe?
286+
Ok(res.data.is_some() && req.message_id.0 == res.message_id.0)
276287
}
277288

278289
async fn begin_play(&self) -> Result<()> {

src/protocol/datatypes/string.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,60 @@ impl<'a, const BOUND: usize> Decode<'a> for Bounded<Bytes<'a>, BOUND> {
106106
Ok(Bounded(content))
107107
}
108108
}
109+
110+
#[derive(Debug)]
111+
pub struct Rest<T, const BOUND: usize = 32767>(pub T);
112+
113+
impl<'a, const BOUND: usize> Decode<'a> for Rest<&'a str, BOUND> {
114+
fn decode(r: &mut &'a [u8]) -> Result<Self> {
115+
let (content, rest) = r.split_at(r.len());
116+
let content = std::str::from_utf8(content)?;
117+
let utf16_len = content.encode_utf16().count();
118+
119+
ensure!(
120+
utf16_len <= BOUND,
121+
"utf-16 encoded string exceeds {BOUND} chars (is {utf16_len})"
122+
);
123+
124+
*r = rest;
125+
126+
Ok(Rest(content))
127+
}
128+
}
129+
130+
impl<'a, const BOUND: usize> Encode for Rest<&'a str, BOUND> {
131+
fn encode(&self, mut w: impl std::io::Write) -> Result<()> {
132+
let len = self.0.encode_utf16().count();
133+
134+
ensure!(len < BOUND, "length of string {len} exceeds bound {BOUND}");
135+
136+
Ok(w.write_all(self.0.as_bytes())?)
137+
}
138+
}
139+
140+
impl<'a, const BOUND: usize> Encode for Rest<Bytes<'a>, BOUND> {
141+
fn encode(&self, mut w: impl std::io::Write) -> Result<()> {
142+
let len = self.0.0.len();
143+
144+
ensure!(len < BOUND, "length of bytes {len} exceeds bound {BOUND}");
145+
146+
self.0.encode(&mut w)
147+
}
148+
}
149+
150+
impl<'a, const BOUND: usize> Decode<'a> for Rest<Bytes<'a>, BOUND> {
151+
fn decode(r: &mut &'a [u8]) -> Result<Self> {
152+
let (mut content, rest) = r.split_at(r.len());
153+
let content = Bytes::decode(&mut content)?;
154+
let len = content.0.len();
155+
156+
ensure!(
157+
len <= BOUND,
158+
"raw byte length exceeds {BOUND} chars (is {len})"
159+
);
160+
161+
*r = rest;
162+
163+
Ok(Rest(content))
164+
}
165+
}

src/protocol/packets/login/login.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use color_eyre::eyre::Result;
2121
use uuid::Uuid;
2222

2323
use crate::protocol::{
24-
datatypes::{Bounded, Bytes, VarInt},
24+
datatypes::{Bounded, Bytes, Rest, VarInt},
2525
Decode, Encode, Packet, Property,
2626
};
2727

@@ -74,7 +74,7 @@ impl<'a> Encode for LoginSuccessC<'a> {
7474
pub struct PluginRequestC<'a> {
7575
pub message_id: VarInt,
7676
pub channel: Bounded<&'a str, 32767>,
77-
pub data: Bounded<Bytes<'a>, 1048576>,
77+
pub data: Rest<Bytes<'a>, 1048576>,
7878
}
7979

8080
impl Packet for PluginRequestC<'_> {
@@ -91,6 +91,25 @@ impl<'a> Encode for PluginRequestC<'a> {
9191
}
9292
}
9393

94+
#[derive(Debug)]
95+
pub struct PluginResponseS<'a> {
96+
pub message_id: VarInt,
97+
pub data: Option<Rest<Bytes<'a>, 1048576>>
98+
}
99+
100+
impl Packet for PluginResponseS<'_> {
101+
const ID: i32 = 0x02;
102+
}
103+
104+
impl<'a> Decode<'a> for PluginResponseS<'a> {
105+
fn decode(r: &mut &'a [u8]) -> Result<Self> {
106+
Ok(Self {
107+
message_id: VarInt::decode(r)?,
108+
data: if bool::decode(r)? { Some(Rest::<Bytes<'a>, 1048576>::decode(r)?) } else { None }
109+
})
110+
}
111+
}
112+
94113
#[derive(Debug)]
95114
pub struct LoginAckS;
96115

src/state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub struct State {
3838
pub version_number: i32,
3939
pub addr: String,
4040
pub port: u16,
41+
pub velocity_forwarding: bool,
4142

4243
pub registry_cache: RegistryCache,
4344

@@ -74,6 +75,7 @@ impl State {
7475
version_number: version_number.to_owned(),
7576
addr: args.addr,
7677
port: args.port,
78+
velocity_forwarding: args.velocity_forwarding,
7779

7880
registry_cache: RegistryCache::from(&*ALL_REGISTRIES),
7981

0 commit comments

Comments
 (0)