Skip to content

Commit 7d2a852

Browse files
committed
feat(player): packet response loop after login
1 parent 2216c00 commit 7d2a852

File tree

6 files changed

+232
-19
lines changed

6 files changed

+232
-19
lines changed

src/net/io.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
use std::{io::ErrorKind, net::SocketAddr, time::Duration};
2121

2222
use bytes::BytesMut;
23-
use color_eyre::eyre::{Context, Result};
23+
use color_eyre::eyre::{bail, Context, Result};
2424
use tokio::{
2525
io::{AsyncReadExt, AsyncWriteExt},
2626
net::TcpStream,
@@ -132,4 +132,31 @@ impl NetIo {
132132
self.stream.flush().await?;
133133
Ok(())
134134
}
135+
136+
pub async fn rx_raw(&mut self) -> Result<Frame> {
137+
if let Some(frame) = self
138+
.decoder
139+
.try_read_next()
140+
.context("failed try_read_next")?
141+
{
142+
return Ok(frame);
143+
};
144+
145+
self.decoder.reserve_additional(BUF_SIZE);
146+
let mut buf = self.decoder.take_all();
147+
148+
if self
149+
.stream
150+
.read_buf(&mut buf)
151+
.await
152+
.context("failed read_buf")?
153+
== 0
154+
{
155+
return Err(std::io::Error::from(ErrorKind::UnexpectedEof).into());
156+
}
157+
158+
self.decoder.add_bytes(buf);
159+
160+
bail!("No packet available")
161+
}
135162
}

src/net/player.rs

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use thiserror::Error;
2626
use tokio::{
2727
net::TcpStream,
2828
sync::{Mutex, OwnedSemaphorePermit, RwLock},
29-
time::{self, timeout},
29+
time::{self, timeout, Instant},
3030
};
3131
use uuid::Uuid;
3232

@@ -38,10 +38,11 @@ use crate::{
3838
play::{
3939
ConfirmTeleportS, GameEvent, GameEventC, Gamemode, KeepAliveC, LoginPlayC,
4040
PlayerInfoUpdateC, PlayerStatus, SetBorderCenterC, SetBorderSizeC, SetCenterChunkC,
41-
SetTickingStateC, StepTicksC, SynchronisePositionC,
41+
SetPlayerPositionAndRotationS, SetPlayerPositionS, SetTickingStateC, StepTicksC,
42+
SynchronisePositionC,
4243
},
4344
},
44-
PacketState,
45+
Frame, Packet, PacketState,
4546
},
4647
CrawlState,
4748
};
@@ -62,6 +63,8 @@ pub struct Player {
6263

6364
uuid: RwLock<Option<Uuid>>,
6465
tp_state: Mutex<TeleportState>,
66+
67+
last_keepalive: RwLock<Instant>,
6568
}
6669

6770
#[derive(Debug)]
@@ -85,12 +88,14 @@ impl SharedPlayer {
8588
id,
8689
io: Mutex::new(NetIo::new(connection)),
8790
_permit: permit,
88-
uuid: RwLock::new(None),
8991

9092
crawlstate,
9193
packet_state: RwLock::new(PacketState::Handshaking),
9294

9395
tp_state: Mutex::new(TeleportState::Clear),
96+
uuid: RwLock::new(None),
97+
98+
last_keepalive: RwLock::new(Instant::now()),
9499
}))
95100
}
96101

@@ -333,20 +338,27 @@ impl SharedPlayer {
333338
// thread but realistically who knows burhhhh
334339
state.player_send.send(self.clone()).await?;
335340

336-
loop {
337-
tokio::select! {
338-
_ = self.keepalive() => {
339-
// keepalive needs to be sent every ~15 sec after keepalive response
340-
time::sleep(Duration::from_secs(12)).await;
341-
}
342-
_ = state.shutdown_token.cancelled() => {
343-
return Ok(());
344-
}
345-
}
346-
}
341+
state.shutdown_token.cancelled().await;
342+
Ok(())
343+
}
344+
345+
pub async fn handle_all_packets(&self) -> Result<()> {
346+
let packets = self.rx_all().await;
347+
self.handle_frames(packets).await
347348
}
348349

349-
async fn keepalive(&self) -> Result<()> {
350+
pub async fn keepalive(&self) -> Result<()> {
351+
let last_keepalive = self.0.last_keepalive.read().await;
352+
let now = Instant::now();
353+
354+
if now - *last_keepalive < Duration::from_secs(10) {
355+
return Ok(());
356+
}
357+
358+
drop(last_keepalive);
359+
let mut last_keepalive = self.0.last_keepalive.write().await;
360+
*last_keepalive = now;
361+
350362
let id = {
351363
let mut rng = rand::thread_rng();
352364
rng.gen()
@@ -359,6 +371,17 @@ impl SharedPlayer {
359371
}
360372
}
361373

374+
async fn rx_all(&self) -> Vec<Frame> {
375+
let mut io = self.0.io.lock().await;
376+
377+
let mut frames = Vec::new();
378+
while let Ok(frame) = io.rx_raw().await {
379+
frames.push(frame);
380+
}
381+
382+
frames
383+
}
384+
362385
async fn ping(&self, id: i64) -> Result<()> {
363386
let mut io = self.0.io.lock().await;
364387
io.flush().await?;
@@ -417,6 +440,37 @@ impl SharedPlayer {
417440
}
418441
Ok(())
419442
}
443+
444+
async fn handle_frames(&self, frames: Vec<Frame>) -> Result<()> {
445+
for frame in frames {
446+
match frame.id {
447+
SetPlayerPositionS::ID => {
448+
let packet: SetPlayerPositionS = frame.decode()?;
449+
debug!(
450+
"Player {} moved to {}, {}, {}",
451+
self.0.id, packet.x, packet.feet_y, packet.z
452+
);
453+
}
454+
455+
SetPlayerPositionAndRotationS::ID => {
456+
let packet: SetPlayerPositionAndRotationS = frame.decode()?;
457+
debug!(
458+
"Player {} moved to {}, {}, {} rotated {} {}",
459+
self.0.id, packet.x, packet.feet_y, packet.z, packet.pitch, packet.yaw
460+
);
461+
}
462+
463+
id => {
464+
debug!(
465+
"Got packet with id {id} from player {}, ignoring",
466+
self.0.id
467+
);
468+
}
469+
}
470+
}
471+
472+
Ok(())
473+
}
420474
}
421475

422476
#[derive(Debug, Error)]

src/protocol/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub mod packets {
4949
mod game_event;
5050
mod keepalive;
5151
mod login;
52+
mod position;
5253
mod status;
5354
mod teleport;
5455
mod tick;
@@ -57,6 +58,7 @@ pub mod packets {
5758
pub use game_event::*;
5859
pub use keepalive::*;
5960
pub use login::*;
61+
pub use position::*;
6062
pub use status::*;
6163
pub use teleport::*;
6264
pub use tick::*;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2024 Andrew Brower.
3+
* This file is part of Crawlspace.
4+
*
5+
* Crawlspace is free software: you can redistribute it and/or
6+
* modify it under the terms of the GNU Affero General Public
7+
* License as published by the Free Software Foundation, either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* Crawlspace is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public
16+
* License along with Crawlspace. If not, see
17+
* <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
use byteorder::{BigEndian, ReadBytesExt};
21+
22+
use crate::protocol::{Decode, Packet};
23+
24+
#[derive(Debug)]
25+
pub struct SetPlayerPositionS {
26+
pub x: f64,
27+
pub feet_y: f64,
28+
pub z: f64,
29+
pub on_ground: bool,
30+
}
31+
32+
impl Packet for SetPlayerPositionS {
33+
const ID: i32 = 0x1A;
34+
}
35+
36+
impl Decode<'_> for SetPlayerPositionS {
37+
fn decode(r: &mut &'_ [u8]) -> color_eyre::eyre::Result<Self>
38+
where
39+
Self: Sized,
40+
{
41+
Ok(Self {
42+
x: r.read_f64::<BigEndian>()?,
43+
feet_y: r.read_f64::<BigEndian>()?,
44+
z: r.read_f64::<BigEndian>()?,
45+
on_ground: r.read_u8()? == 1,
46+
})
47+
}
48+
}
49+
50+
#[derive(Debug)]
51+
pub struct SetPlayerPositionAndRotationS {
52+
pub x: f64,
53+
pub feet_y: f64,
54+
pub z: f64,
55+
pub yaw: f32,
56+
pub pitch: f32,
57+
pub on_ground: bool,
58+
}
59+
60+
impl Packet for SetPlayerPositionAndRotationS {
61+
const ID: i32 = 0x1B;
62+
}
63+
64+
impl Decode<'_> for SetPlayerPositionAndRotationS {
65+
fn decode(r: &mut &'_ [u8]) -> color_eyre::eyre::Result<Self>
66+
where
67+
Self: Sized,
68+
{
69+
Ok(Self {
70+
x: r.read_f64::<BigEndian>()?,
71+
feet_y: r.read_f64::<BigEndian>()?,
72+
z: r.read_f64::<BigEndian>()?,
73+
yaw: r.read_f32::<BigEndian>()?,
74+
pitch: r.read_f32::<BigEndian>()?,
75+
on_ground: r.read_u8()? == 1,
76+
})
77+
}
78+
}

src/protocol/packets/play/world.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,58 @@ impl From<world::BlockEntity> for BlockEntity {
9292
let data = fastnbt::to_bytes_with_opts(&value.raw_data, fastnbt::SerOpts::network_nbt())
9393
.expect("Failed to parse network nbt for block entity");
9494

95+
let kind = VarInt(match value.id.as_str() {
96+
"minecraft:furnace" => 0,
97+
"minecraft:chest" => 1,
98+
"minecraft:trapped_chest" => 2,
99+
"minecraft:ender_chest" => 3,
100+
"minecraft:jukebox" => 4,
101+
"minecraft:dispenser" => 5,
102+
"minecraft:dropper" => 6,
103+
"minecraft:sign" => 7,
104+
"minecraft:hanging_sign" => 8,
105+
"minecraft:mob_spawner" => 9,
106+
"minecraft:piston" => 10,
107+
"minecraft:brewing_stand" => 11,
108+
"minecraft:enchanting_table" => 12,
109+
"minecraft:end_portal" => 13,
110+
"minecraft:beacon" => 14,
111+
"minecraft:skull" => 15,
112+
"minecraft:daylight_detector" => 16,
113+
"minecraft:hopper" => 17,
114+
"minecraft:comparator" => 18,
115+
"minecraft:banner" => 19,
116+
"minecraft:structure_block" => 20,
117+
"minecraft:end_gateway" => 21,
118+
"minecraft:command_block" => 22,
119+
"minecraft:shulker_box" => 23,
120+
"minecraft:bed" => 24,
121+
"minecraft:conduit" => 25,
122+
"minecraft:barrel" => 26,
123+
"minecraft:smoker" => 27,
124+
"minecraft:blast_furnace" => 28,
125+
"minecraft:lectern" => 29,
126+
"minecraft:bell" => 30,
127+
"minecraft:jigsaw" => 31,
128+
"minecraft:campfire" => 32,
129+
"minecraft:beehive" => 33,
130+
"minecraft:sculk_sensor" => 34,
131+
"minecraft:calibrated_sculk_sensor" => 35,
132+
"minecraft:sculk_catalyst" => 36,
133+
"minecraft:sculk_shrieker" => 37,
134+
"minecraft:chiseled_bookshelf" => 38,
135+
"minecraft:brushable_block" => 39,
136+
"minecraft:decorated_pot" => 40,
137+
"minecraft:crafter" => 41,
138+
"minecraft:trial_spawner" => 42,
139+
"minecraft:vault" => 43,
140+
i => unimplemented!("Block Entity type {i} is unimplemented"),
141+
});
142+
95143
Self {
96144
packed_xz: (((value.x & 15) << 4) | (value.z & 15)) as u8,
97145
y: value.y as i16,
98-
// FIXME: use correct block entity type from registry
99-
kind: VarInt(7),
146+
kind,
100147
data,
101148
}
102149
}

src/server/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ impl Server {
5959
self.players.push(p.clone());
6060
tokio::spawn(Self::send_world_to(p.clone(), self.world_cache.clone()));
6161
}
62+
63+
for player in &self.players {
64+
let _ = player.keepalive().await;
65+
let _ = player.handle_all_packets().await;
66+
}
6267
}
6368

6469
async fn send_world_to(player: SharedPlayer, world_cache: Arc<WorldCache>) -> Result<()> {

0 commit comments

Comments
 (0)