diff --git a/TODO.md b/TODO.md index 5cb0faa..77f2ab2 100644 --- a/TODO.md +++ b/TODO.md @@ -25,8 +25,3 @@ - hold back packets (whitelist), forward to server at connect before joining - add support for forge (emulate mod list communication) - on login plugin request during login state, respond with empty payload, not supported - -# Extra - -- simply don't occupy in lobby if we don't have probed data -- dont use mutex for server data diff --git a/src/forge.rs b/src/forge.rs index 3218a55..ffa9a40 100644 --- a/src/forge.rs +++ b/src/forge.rs @@ -38,6 +38,10 @@ pub const CHANNEL_LOGIN_WRAPPER: &str = "fml:loginwrapper"; /// Forge handshake channel. pub const CHANNEL_HANDSHAKE: &str = "fml:handshake"; +/// Timeout for draining Forge plugin responses from client. +#[cfg(feature = "lobby")] +const CLIENT_DRAIN_FORGE_TIMEOUT: Duration = Duration::from_secs(5); + /// Respond with Forge login wrapper packet. pub async fn respond_forge_login_packet( client: &Client, @@ -165,14 +169,14 @@ pub async fn replay_login_payload( debug!(target: "lazymc::lobby", "Replaying Forge login procedure for lobby client..."); // Replay each Forge packet - for packet in server.forge_payload.lock().await.as_slice() { + for packet in server.forge_payload.read().await.as_slice() { inbound.write_all(packet).await.map_err(|err| { error!(target: "lazymc::lobby", "Failed to send Forge join payload to lobby client, will likely cause issues: {}", err); })?; } // Drain all responses - let count = server.forge_payload.lock().await.len(); + let count = server.forge_payload.read().await.len(); drain_forge_responses(client, inbound, inbound_buf, count).await?; trace!(target: "lazymc::lobby", "Forge join payload replayed"); @@ -197,10 +201,9 @@ async fn drain_forge_responses( return Ok(()); } - // TODO: move timeout into constant + // Read packet from stream with timeout let read_packet_task = packet::read_packet(client, buf, &mut reader); - let timeout = time::timeout(Duration::from_secs(5), read_packet_task).await; - + let timeout = time::timeout(CLIENT_DRAIN_FORGE_TIMEOUT, read_packet_task).await; let read_packet_task = match timeout { Ok(result) => result, Err(_) => { diff --git a/src/join/lobby.rs b/src/join/lobby.rs index afbfe0d..aaf18e3 100644 --- a/src/join/lobby.rs +++ b/src/join/lobby.rs @@ -37,7 +37,7 @@ pub async fn occupy( /// Check whether we still have to probe before we can use the lobby. async fn must_still_probe(config: &Config, server: &Server) -> bool { - must_probe(config) && server.probed_join_game.lock().await.is_none() + must_probe(config) && server.probed_join_game.read().await.is_none() } /// Check whether we must have probed data. diff --git a/src/probe.rs b/src/probe.rs index 53ab876..d200d64 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -53,7 +53,7 @@ pub async fn probe(config: Arc, server: Arc) -> Result<(), ()> { // Connect to server, record Forge payload let forge_payload = connect_to_server(&config, &server).await?; - *server.forge_payload.lock().await = forge_payload; + *server.forge_payload.write().await = forge_payload; Ok(()) } @@ -277,7 +277,11 @@ async fn connect_to_server_no_timeout( let join_game_data = wait_for_server_join_game(&tmp_client, &tmp_client_info, &mut outbound, &mut buf) .await?; - server.probed_join_game.lock().await.replace(join_game_data); + server + .probed_join_game + .write() + .await + .replace(join_game_data); // Gracefully close connection let _ = net::close_tcp_stream(outbound).await; diff --git a/src/proto/packets/play/join_game.rs b/src/proto/packets/play/join_game.rs index 27e1694..2af74f4 100644 --- a/src/proto/packets/play/join_game.rs +++ b/src/proto/packets/play/join_game.rs @@ -106,18 +106,17 @@ pub async fn lobby_send( server: &Server, ) -> Result<(), ()> { let status = server.status().await; - let join_game = server.probed_join_game.lock().await; + let join_game = server.probed_join_game.read().await; // Get dimension codec and build lobby dimension - let dimension_codec: CompoundTag = - if let Some(join_game) = server.probed_join_game.lock().await.as_ref() { - join_game - .dimension_codec - .clone() - .unwrap_or_else(dimension::default_dimension_codec) - } else { - dimension::default_dimension_codec() - }; + let dimension_codec: CompoundTag = if let Some(join_game) = join_game.as_ref() { + join_game + .dimension_codec + .clone() + .unwrap_or_else(dimension::default_dimension_codec) + } else { + dimension::default_dimension_codec() + }; // Get other values from status and probed join game data let dimension: CompoundTag = dimension::lobby_dimension(&dimension_codec); diff --git a/src/server.rs b/src/server.rs index 75f4dd5..566ef17 100644 --- a/src/server.rs +++ b/src/server.rs @@ -81,10 +81,13 @@ pub struct Server { #[cfg(feature = "rcon")] rcon_last_stop: Mutex>, - // TODO: dont use mutex, do not make public, dont use bytesmut - pub forge_payload: Mutex>>, - // TODO: dont use mutex, do not make public, dont use bytesmut - pub probed_join_game: Mutex>, + /// Probed join game data. + pub probed_join_game: RwLock>, + + /// Forge payload. + /// + /// Sent to clients when they connect to lobby. Recorded from server by probe. + pub forge_payload: RwLock>>, } impl Server { @@ -372,8 +375,8 @@ impl Default for Server { rcon_lock: Semaphore::new(1), #[cfg(feature = "rcon")] rcon_last_stop: Default::default(), - forge_payload: Default::default(), probed_join_game: Default::default(), + forge_payload: Default::default(), } } }