From b71d0d10133b33f466c6be6462f57577b04bcc2f Mon Sep 17 00:00:00 2001
From: timvisee <tim@visee.me>
Date: Mon, 15 Nov 2021 13:21:12 +0100
Subject: [PATCH] Add delay between RCON commands, hopefully improve reliablity

The Minecraft RCON implementation is very broken/brittle. With this we
hope to improve reliablity.
---
 src/mc/rcon.rs | 20 ++++++++++++++++++++
 src/server.rs  |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/src/mc/rcon.rs b/src/mc/rcon.rs
index 5e15f9a..3c575d7 100644
--- a/src/mc/rcon.rs
+++ b/src/mc/rcon.rs
@@ -1,4 +1,14 @@
+use std::time::Duration;
+
 use rust_rcon::{Connection, Error as RconError};
+use tokio::time;
+
+/// Minecraft RCON quirk.
+///
+/// Wait this time between RCON operations.
+/// The Minecraft RCON implementation is very broken and brittle, this is used in the hopes to
+/// improve reliability.
+const QUIRK_RCON_GRACE_TIME: Duration = Duration::from_millis(200);
 
 /// An RCON client.
 pub struct Rcon {
@@ -19,7 +29,17 @@ impl Rcon {
 
     /// Send command over RCON.
     pub async fn cmd(&mut self, cmd: &str) -> Result<String, RconError> {
+        // Minecraft quirk
+        time::sleep(QUIRK_RCON_GRACE_TIME).await;
+
+        // Actually send RCON command
         debug!(target: "lazymc::rcon", "Sending RCON: {}", cmd);
         self.con.cmd(cmd).await
     }
+
+    /// Close connection.
+    pub async fn close(self) {
+        // Minecraft quirk
+        time::sleep(QUIRK_RCON_GRACE_TIME).await;
+    }
 }
diff --git a/src/server.rs b/src/server.rs
index bae9405..1778ae8 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -443,6 +443,9 @@ async fn stop_server_rcon(config: &Config, server: &Server) -> bool {
     // TODO: set before stop command, revert state on failure
     server.update_state(State::Stopping, config);
 
+    // Gracefully close connection
+    rcon.close().await;
+
     true
 }