ClassiCube / MCGalaxy

A Minecraft Classic / ClassiCube server software
GNU General Public License v3.0
168 stars 79 forks source link

Large message boxes are forced to contain unknown delays. #657

Open rdebath opened 2 years ago

rdebath commented 2 years ago

If you have quite a few commands in a message box, it becomes necessary to add /delay commands to avoid tripping the command spam errors. This is usually using the default timing, but in general it is impossible to predict how much delay is required. This is especially true if the is more than one message box running, or the user starts entering comands.

If you are happy with changing the anti-spam, this change means that any delays required by the anti-spam are automatically inserted between commands in a message box. The delays are chosen so that the user also has a small margin within which they can enter commands without tripping the anti-spam.

I suspect you have a more preferred way of doing this, so I'm just providing this as an example.

Note this does not insert any delays between commands sent directly from the client, they are only added where a user could already place a /delay command.

commit b4f2fdb4bfbbcc77615bafb3201a7733b02c690a
Author: Robert de Bath <rdebath@tvisiontech.co.uk>
Date:   Thu Sep 16 17:49:11 2021 +0100

    Automatically insert /delay commands into messagebox

diff --git a/MCGalaxy/Player/Player.Handlers.cs b/MCGalaxy/Player/Player.Handlers.cs
index 3efbaffc9..8bdc52d04 100644
--- a/MCGalaxy/Player/Player.Handlers.cs
+++ b/MCGalaxy/Player/Player.Handlers.cs
@@ -721,7 +721,18 @@ namespace MCGalaxy
                 Message(e.GetType() + ": " + e.Message);
                 return false;
             }
-            if (spamChecker != null && spamChecker.CheckCommandSpam()) return false;
+            if (spamChecker != null) {
+                if (data.Context == CommandContext.MessageBlock) {
+                    int ms = spamChecker.ReadCommandSpam();
+                    if (ms>10) Thread.Sleep(ms);
+
+                    // If commands are blocked abort.
+                    TimeSpan delta = cmdUnblocked - DateTime.UtcNow;
+                    if (delta.TotalSeconds > 0)
+                        return false;
+                } else
+                    if (spamChecker.CheckCommandSpam()) return false;
+            }
             return true;
         }

diff --git a/MCGalaxy/Player/SpamChecker.cs b/MCGalaxy/Player/SpamChecker.cs
index 29ca7da54..9fcd34913 100644
--- a/MCGalaxy/Player/SpamChecker.cs
+++ b/MCGalaxy/Player/SpamChecker.cs
@@ -83,5 +83,30 @@ namespace MCGalaxy {
                 return true;
             }
         }
+
+        public int ReadCommandSpam() {
+            if (!Server.Config.CmdSpamCheck || p.IsSuper) return 0;
+
+            lock (cmdLock) {
+                // Filling up the list.
+                if (cmdLog.Count < Server.Config.CmdSpamCount - 2 || cmdLog.Count < 4) {
+                    if (cmdLog.AddSpamEntry(Server.Config.CmdSpamCount, Server.Config.CmdSpamInterval))
+                        return (int)(Server.Config.CmdSpamInterval.TotalMilliseconds / Server.Config.CmdSpamCount);
+
+                    return (int)(Server.Config.CmdSpamInterval.TotalMilliseconds / Server.Config.CmdSpamCount * 2);
+                }
+
+                cmdLog.AddSpamEntry(Server.Config.CmdSpamCount, Server.Config.CmdSpamInterval);
+
+                DateTime next = DateTime.UtcNow - Server.Config.CmdSpamInterval -
+                    TimeSpan.FromMilliseconds(Server.Config.CmdSpamInterval.TotalMilliseconds / Server.Config.CmdSpamCount * 2);
+
+                if (cmdLog[0] < next && cmdLog[1] < next)
+                    return 0;
+
+                return (int)(Server.Config.CmdSpamInterval.TotalMilliseconds / Server.Config.CmdSpamCount * 2);
+            }
+        }
+
     }
 }
UnknownShadow200 commented 2 years ago

What are you putting in MBs such that it exceeds 25 commands in 1 second?

rdebath commented 2 years ago

Just a few /pl commands to build things, for example a tiny bridge. And no, the user may not have access to /z.