Minecraft-Console-Client/MinecraftClient/ChatBots/AutoRelog.cs

188 lines
6.1 KiB
C#
Raw Normal View History

using System;
using MinecraftClient.Scripting;
2022-10-05 15:02:30 +08:00
using Tomlet.Attributes;
namespace MinecraftClient.ChatBots
{
/// <summary>
/// This bot automatically re-join the server if kick message contains predefined string (Server is restarting ...)
/// </summary>
public class AutoRelog : ChatBot
{
2022-10-05 15:02:30 +08:00
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoRelog";
public bool Enabled = false;
[TomlInlineComment("$ChatBot.AutoRelog.Delay$")]
2022-10-06 18:12:32 +08:00
public Range Delay = new(3);
2022-10-05 15:02:30 +08:00
[TomlInlineComment("$ChatBot.AutoRelog.Retries$")]
2026-07-19 14:42:10 +02:00
public int Retries = -1;
2022-10-05 15:02:30 +08:00
[TomlInlineComment("$ChatBot.AutoRelog.Ignore_Kick_Message$")]
2022-10-05 15:02:30 +08:00
public bool Ignore_Kick_Message = false;
[TomlPrecedingComment("$ChatBot.AutoRelog.Kick_Messages$")]
2022-10-05 19:39:21 +08:00
public string[] Kick_Messages = new string[] { "Connection has been lost", "Server is restarting", "Server is full", "Too Many people" };
2022-10-05 15:02:30 +08:00
public void OnSettingUpdate()
{
2026-07-19 14:42:10 +02:00
Kick_Messages ??= Array.Empty<string>();
if (!double.IsFinite(Delay.min))
Delay.min = 0.1;
if (!double.IsFinite(Delay.max))
Delay.max = 0.1;
2022-10-06 18:12:32 +08:00
Delay.min = Math.Max(0.1, Delay.min);
Delay.max = Math.Max(0.1, Delay.max);
2026-07-19 14:42:10 +02:00
double maxDelaySeconds = (uint.MaxValue - 1) / 1000D;
2026-03-23 14:29:04 +01:00
Delay.min = Math.Min(maxDelaySeconds, Delay.min);
Delay.max = Math.Min(maxDelaySeconds, Delay.max);
2022-10-06 18:12:32 +08:00
2022-10-05 15:02:30 +08:00
if (Delay.min > Delay.max)
(Delay.min, Delay.max) = (Delay.max, Delay.min);
2026-07-19 14:42:10 +02:00
if (Retries < -1)
Retries = -1;
2022-10-05 15:02:30 +08:00
}
public struct Range
{
2022-10-06 18:12:32 +08:00
public double min, max;
2022-10-05 15:02:30 +08:00
public Range()
{
min = 0;
max = 0;
}
2022-10-05 15:02:30 +08:00
public Range(int value)
{
min = max = value;
}
public Range(int min, int max)
{
this.min = min;
this.max = max;
}
}
}
2026-07-19 14:42:10 +02:00
private static readonly AutoRelogRetryPolicy s_retryPolicy = new(TimeProvider.System);
/// <summary>
/// This bot automatically re-join the server if kick message contains predefined string
/// </summary>
/// <param name="DelayBeforeRelogMin">Minimum delay before re-joining the server (in seconds)</param>
/// <param name="DelayBeforeRelogMax">Maximum delay before re-joining the server (in seconds)</param>
/// <param name="retries">Number of retries if connection fails (-1 = infinite)</param>
2022-10-05 15:02:30 +08:00
public AutoRelog()
{
LogDebugToConsole(string.Format(Translations.bot_autoRelog_launch, Config.Retries));
}
public override void Initialize()
{
2022-12-06 20:32:46 +08:00
_Initialize();
}
public override void AfterGameJoined()
{
2026-07-19 14:42:10 +02:00
s_retryPolicy.MarkJoined();
2026-06-02 10:24:59 +02:00
}
public override void Update()
{
ResetRetriesAfterStableJoin();
}
2022-12-06 20:32:46 +08:00
private void _Initialize()
{
2022-10-05 15:02:30 +08:00
McClient.ReconnectionAttemptsLeft = Config.Retries;
if (Config.Ignore_Kick_Message)
{
LogDebugToConsole(Translations.bot_autoRelog_no_kick_msg);
}
}
public override bool OnDisconnect(DisconnectReason reason, string message)
{
if (reason == DisconnectReason.UserLogout)
{
LogDebugToConsole(Translations.bot_autoRelog_ignore_user_logout);
2026-07-19 14:42:10 +02:00
return false;
}
2019-05-30 11:45:43 +02:00
2026-07-19 14:42:10 +02:00
message = GetVerbatim(message);
LogDebugToConsole(string.Format(Translations.bot_autoRelog_disconnect_msg, message));
2019-05-30 11:45:43 +02:00
2026-07-19 14:42:10 +02:00
if (!AutoRelogRetryPolicy.ShouldReconnect(
reason,
message,
Config.Ignore_Kick_Message,
Config.Kick_Messages,
out string? matchedMessage))
{
LogDebugToConsole(Translations.bot_autoRelog_reconnect_ignore);
2026-07-19 14:42:10 +02:00
return false;
}
2019-05-30 11:45:43 +02:00
2026-07-19 14:42:10 +02:00
return LaunchDelayedReconnection(matchedMessage);
2026-06-02 10:24:59 +02:00
}
private static void ResetRetriesAfterStableJoin()
{
2026-07-19 14:42:10 +02:00
if (s_retryPolicy.ResetAfterStableConnection())
2026-06-02 10:24:59 +02:00
McClient.ReconnectionAttemptsLeft = Config.Retries;
}
private static bool HasUnlimitedRetries()
{
2026-07-19 14:42:10 +02:00
return Config.Retries == -1;
2026-06-02 10:24:59 +02:00
}
2026-06-02 10:24:59 +02:00
private bool LaunchDelayedReconnection(string? msg)
{
2026-07-19 14:42:10 +02:00
if (!s_retryPolicy.TryReserveAttempt(Config.Retries, out int retriesLeft))
2026-06-02 10:24:59 +02:00
return false;
2026-06-02 10:24:59 +02:00
double delay = Random.Shared.NextDouble() * (Config.Delay.max - Config.Delay.min) + Config.Delay.min;
LogDebugToConsole(string.Format(string.IsNullOrEmpty(msg) ? Translations.bot_autoRelog_reconnect_always : Translations.bot_autoRelog_reconnect, msg));
string retriesDisplay = HasUnlimitedRetries()
? Translations.bot_autoRelog_retries_unlimited
: retriesLeft.ToString();
2026-06-02 10:24:59 +02:00
McClient.ReconnectionAttemptsLeft = retriesLeft;
2026-07-19 14:42:10 +02:00
if (Program.TryRestart(TimeSpan.FromSeconds(delay), true))
2026-06-02 10:24:59 +02:00
{
LogToConsole(string.Format(Translations.bot_autoRelog_wait_with_retries, delay, retriesDisplay));
return true;
}
2026-07-19 14:42:10 +02:00
s_retryPolicy.RollBackReservedAttempt();
return Program.HasRestartPending;
}
public static bool OnDisconnectStatic(DisconnectReason reason, string message)
{
2022-10-05 15:02:30 +08:00
if (Config.Enabled)
{
2022-10-05 15:02:30 +08:00
AutoRelog bot = new();
bot.Initialize();
return bot.OnDisconnect(reason, message);
}
return false;
}
}
}