1use std::collections::VecDeque;
2use std::net::{IpAddr, Ipv4Addr};
3use std::sync::{Arc, Mutex};
4use std::time::{Duration, Instant};
5
6use bevy_app::prelude::*;
7use bevy_ecs::prelude::*;
8use bytes::{Buf, BufMut, BytesMut};
9use uuid::Uuid;
10use valence_ident::ident;
11use valence_network::NetworkPlugin;
12use valence_registry::{BiomeRegistry, DimensionTypeRegistry};
13use valence_server::client::{ClientBundle, ClientBundleArgs, ClientConnection, ReceivedPacket};
14use valence_server::keepalive::KeepaliveSettings;
15use valence_server::protocol::decode::PacketFrame;
16use valence_server::protocol::packets::play::{PlayerPositionLookS2c, TeleportConfirmC2s};
17use valence_server::protocol::{Decode, Encode, Packet, PacketDecoder, PacketEncoder, VarInt};
18use valence_server::{ChunkLayer, EntityLayer, Server, ServerSettings};
19
20use crate::DefaultPlugins;
21pub struct ScenarioSingleClient {
22 pub app: App,
24 pub client: Entity,
26 pub helper: MockClientHelper,
28 pub layer: Entity,
30}
31
32impl ScenarioSingleClient {
33 pub fn new() -> Self {
38 let mut app = App::new();
39
40 app.insert_resource(KeepaliveSettings {
41 period: Duration::MAX,
42 })
43 .insert_resource(ServerSettings {
44 compression_threshold: Default::default(),
45 ..Default::default()
46 })
47 .add_plugins(DefaultPlugins.build().disable::<NetworkPlugin>());
48
49 app.update(); let chunk_layer = ChunkLayer::new(
52 ident!("overworld"),
53 app.world().resource::<DimensionTypeRegistry>(),
54 app.world().resource::<BiomeRegistry>(),
55 app.world().resource::<Server>(),
56 );
57 let entity_layer = EntityLayer::new(app.world().resource::<Server>());
58 let layer = app.world_mut().spawn((chunk_layer, entity_layer)).id();
59
60 let (mut client, helper) = create_mock_client("test");
61 client.player.layer.0 = layer;
62 client.visible_chunk_layer.0 = layer;
63 client.visible_entity_layers.0.insert(layer);
64 let client = app.world_mut().spawn(client).id();
65
66 ScenarioSingleClient {
67 app,
68 client,
69 helper,
70 layer,
71 }
72 }
73}
74
75impl Default for ScenarioSingleClient {
76 fn default() -> Self {
77 Self::new()
78 }
79}
80
81pub fn create_mock_client<N: Into<String>>(name: N) -> (ClientBundle, MockClientHelper) {
86 let conn = MockClientConnection::new();
87
88 let bundle = ClientBundle::new(ClientBundleArgs {
89 username: name.into(),
90 uuid: Uuid::from_bytes(rand::random()),
91 ip: IpAddr::V4(Ipv4Addr::LOCALHOST),
92 properties: Default::default(),
93 conn: Box::new(conn.clone()),
94 enc: PacketEncoder::new(),
95 });
96
97 let helper = MockClientHelper::new(conn);
98
99 (bundle, helper)
100}
101
102#[derive(Clone)]
106pub struct MockClientConnection {
107 inner: Arc<Mutex<MockClientConnectionInner>>,
108}
109
110struct MockClientConnectionInner {
111 recv_buf: VecDeque<ReceivedPacket>,
114 send_buf: BytesMut,
116}
117
118impl MockClientConnection {
119 pub fn new() -> Self {
120 Self {
121 inner: Arc::new(Mutex::new(MockClientConnectionInner {
122 recv_buf: VecDeque::new(),
123 send_buf: BytesMut::new(),
124 })),
125 }
126 }
127
128 fn inject_send(&self, mut bytes: BytesMut) {
130 let id = VarInt::decode_partial((&mut bytes).reader()).expect("failed to decode packet ID");
131
132 self.inner
133 .lock()
134 .unwrap()
135 .recv_buf
136 .push_back(ReceivedPacket {
137 timestamp: Instant::now(),
138 id,
139 body: bytes.freeze(),
140 });
141 }
142
143 fn take_received(&self) -> BytesMut {
144 self.inner.lock().unwrap().send_buf.split()
145 }
146
147 fn clear_received(&self) {
148 self.inner.lock().unwrap().send_buf.clear();
149 }
150}
151
152impl ClientConnection for MockClientConnection {
153 fn try_send(&mut self, bytes: BytesMut) -> anyhow::Result<()> {
154 self.inner.lock().unwrap().send_buf.unsplit(bytes);
155 Ok(())
156 }
157
158 fn try_recv(&mut self) -> anyhow::Result<Option<ReceivedPacket>> {
159 Ok(self.inner.lock().unwrap().recv_buf.pop_front())
160 }
161
162 fn len(&self) -> usize {
163 self.inner.lock().unwrap().recv_buf.len()
164 }
165}
166
167impl Default for MockClientConnection {
168 fn default() -> Self {
169 Self::new()
170 }
171}
172
173pub struct MockClientHelper {
176 conn: MockClientConnection,
177 dec: PacketDecoder,
178 scratch: BytesMut,
179}
180
181impl MockClientHelper {
182 pub fn new(conn: MockClientConnection) -> Self {
183 Self {
184 conn,
185 dec: PacketDecoder::new(),
186 scratch: BytesMut::new(),
187 }
188 }
189
190 #[track_caller]
193 pub fn send<P>(&mut self, packet: &P)
194 where
195 P: Packet + Encode,
196 {
197 packet
198 .encode_with_id((&mut self.scratch).writer())
199 .expect("failed to encode packet");
200
201 self.conn.inject_send(self.scratch.split());
202 }
203
204 #[track_caller]
206 pub fn collect_received(&mut self) -> PacketFrames {
207 self.dec.queue_bytes(self.conn.take_received());
208
209 let mut res = vec![];
210
211 while let Some(frame) = self
212 .dec
213 .try_next_packet()
214 .expect("failed to decode packet frame")
215 {
216 res.push(frame);
217 }
218
219 PacketFrames(res)
220 }
221
222 pub fn clear_received(&mut self) {
223 self.conn.clear_received();
224 }
225
226 pub fn confirm_initial_pending_teleports(&mut self) {
227 let mut counter = 0;
228
229 for pkt in self.collect_received().0 {
230 if pkt.id == PlayerPositionLookS2c::ID {
231 pkt.decode::<PlayerPositionLookS2c>().unwrap();
232
233 self.send(&TeleportConfirmC2s {
234 teleport_id: counter.into(),
235 });
236
237 counter += 1;
238 }
239 }
240 }
241}
242
243#[derive(Clone, Debug)]
244pub struct PacketFrames(pub Vec<PacketFrame>);
245
246impl PacketFrames {
247 #[track_caller]
248 pub fn assert_count<P: Packet>(&self, expected_count: usize) {
249 let actual_count = self.0.iter().filter(|f| f.id == P::ID).count();
250
251 assert_eq!(
252 expected_count,
253 actual_count,
254 "unexpected packet count for {} (expected {expected_count}, got {actual_count})",
255 P::NAME,
256 )
257 }
258
259 #[track_caller]
260 pub fn assert_order<L: PacketList>(&self) {
261 let positions: Vec<_> = self
262 .0
263 .iter()
264 .filter_map(|f| L::packets().iter().position(|(id, _)| f.id == *id))
265 .collect();
266
267 let is_sorted = positions.windows(2).all(|w| w[0] <= w[1]);
269
270 assert!(
271 is_sorted,
272 "packets out of order (expected {:?}, got {:?})",
273 L::packets(),
274 self.debug_order::<L>()
275 )
276 }
277
278 #[track_caller]
284 pub fn first<'a, P>(&'a self) -> P
285 where
286 P: Packet + Decode<'a>,
287 {
288 if let Some(frame) = self.0.iter().find(|p| p.id == P::ID) {
289 frame.decode::<P>().unwrap()
290 } else {
291 panic!("failed to find packet {}", P::NAME)
292 }
293 }
294
295 pub fn debug_order<L: PacketList>(&self) -> impl std::fmt::Debug {
296 self.0
297 .iter()
298 .filter_map(|f| L::packets().iter().find(|(id, _)| f.id == *id).copied())
299 .collect::<Vec<_>>()
300 }
301}
302
303pub trait PacketList {
304 fn packets() -> &'static [(i32, &'static str)];
305}
306
307macro_rules! impl_packet_list {
308 ($($ty:ident),*) => {
309 impl<$($ty: Packet,)*> PacketList for ($($ty,)*) {
310 fn packets() -> &'static [(i32, &'static str)] {
311 &[
312 $(
313 (
314 $ty::ID,
315 $ty::NAME
316 ),
317 )*
318 ]
319 }
320 }
321 }
322}
323
324impl_packet_list!(A);
325impl_packet_list!(A, B);
326impl_packet_list!(A, B, C);
327impl_packet_list!(A, B, C, D);
328impl_packet_list!(A, B, C, D, E);
329impl_packet_list!(A, B, C, D, E, F);
330impl_packet_list!(A, B, C, D, E, F, G);
331impl_packet_list!(A, B, C, D, E, F, G, H);
332impl_packet_list!(A, B, C, D, E, F, G, H, I);
333impl_packet_list!(A, B, C, D, E, F, G, H, I, J);
334impl_packet_list!(A, B, C, D, E, F, G, H, I, J, K);