fix: isolate queued restart settings

This commit is contained in:
Anon 2026-07-26 01:16:07 +02:00
parent 1686d00f30
commit 9b90b535d8
5 changed files with 99 additions and 21 deletions

View file

@ -47,8 +47,9 @@ namespace MinecraftClient.Commands
if (Settings.Config.Main.SetServerIP(new Settings.MainConfigHelper.MainConfig.ServerInfoConfig(server), true))
{
Program.Restart(keepAccountAndServerSettings: true);
return r.SetAndReturn(Status.Done);
return r.SetAndReturn(Program.TryRestart(keepAccountAndServerSettings: true)
? Status.Done
: Status.Fail);
}
else
{
@ -64,8 +65,9 @@ namespace MinecraftClient.Commands
if (Settings.Config.Main.SetServerIP(new Settings.MainConfigHelper.MainConfig.ServerInfoConfig(args[0]), true))
{
Program.Restart(keepAccountAndServerSettings: true);
return string.Empty;
return Program.TryRestart(keepAccountAndServerSettings: true)
? string.Empty
: Translations.general_fail;
}
else
{

View file

@ -47,8 +47,9 @@ namespace MinecraftClient.Commands
if (!Settings.Config.Main.Advanced.SetAccount(account))
return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_connect_unknown, account));
}
Program.Restart(keepAccountAndServerSettings: true);
return r.SetAndReturn(CmdResult.Status.Done);
return r.SetAndReturn(Program.TryRestart(keepAccountAndServerSettings: true)
? CmdResult.Status.Done
: CmdResult.Status.Fail);
}
internal static string DoReconnect(string command)
@ -62,8 +63,9 @@ namespace MinecraftClient.Commands
return string.Format(Translations.cmd_connect_unknown, account);
}
}
Program.Restart(keepAccountAndServerSettings: true);
return String.Empty;
return Program.TryRestart(keepAccountAndServerSettings: true)
? String.Empty
: Translations.general_fail;
}
}
}

View file

@ -923,10 +923,15 @@ namespace MinecraftClient
if (delay < TimeSpan.Zero)
delay = TimeSpan.Zero;
RestartSettingsSnapshot? settingsSnapshot = keepAccountAndServerSettings
? new RestartSettingsSnapshot(InternalConfig.Account, InternalConfig.ServerIP, InternalConfig.ServerPort)
: null;
return restartCoordinator.TrySchedule(new RestartRequest(
Volatile.Read(ref connectionAttempt),
delay,
keepAccountAndServerSettings));
keepAccountAndServerSettings,
settingsSnapshot));
}
private static async Task ExecuteRestartAsync(RestartRequest request, CancellationToken cancellationToken)
@ -951,6 +956,12 @@ namespace MinecraftClient
cancellationToken.ThrowIfCancellationRequested();
ConsoleIO.WriteLine(Translations.mcc_restart);
ReloadSettings(request.KeepAccountAndServerSettings);
if (request.SettingsSnapshot is RestartSettingsSnapshot settingsSnapshot)
{
InternalConfig.Account = settingsSnapshot.Account;
InternalConfig.ServerIP = settingsSnapshot.ServerIP;
InternalConfig.ServerPort = settingsSnapshot.ServerPort;
}
InitializeClient();
}

View file

@ -9,7 +9,14 @@ namespace MinecraftClient
internal readonly record struct RestartRequest(
long ConnectionAttempt,
TimeSpan Delay,
bool KeepAccountAndServerSettings);
bool KeepAccountAndServerSettings,
RestartSettingsSnapshot? SettingsSnapshot = null,
long RequestId = 0);
internal readonly record struct RestartSettingsSnapshot(
Settings.MainConfigHelper.MainConfig.AccountInfoConfig Account,
string ServerIP,
ushort ServerPort);
internal sealed class RestartCoordinator : IDisposable
{
@ -19,8 +26,9 @@ namespace MinecraftClient
private readonly Func<RestartRequest, CancellationToken, Task> restart;
private readonly Action<Exception> reportFailure;
private readonly Task worker;
private readonly HashSet<long> pendingAttempts = [];
private readonly Dictionary<long, long> pendingAttempts = [];
private long highestScheduledAttempt = -1;
private long nextRequestId;
private bool stopped;
internal RestartCoordinator(
@ -44,22 +52,28 @@ namespace MinecraftClient
internal bool HasScheduledRestart(long connectionAttempt)
{
lock (stateLock)
return !stopped && pendingAttempts.Contains(connectionAttempt);
return !stopped && pendingAttempts.ContainsKey(connectionAttempt);
}
internal bool TrySchedule(RestartRequest request)
{
lock (stateLock)
{
if (stopped || request.ConnectionAttempt <= highestScheduledAttempt)
bool hasPendingRequest = pendingAttempts.TryGetValue(request.ConnectionAttempt, out long previousRequestId);
if (stopped || request.ConnectionAttempt < highestScheduledAttempt
|| (request.ConnectionAttempt == highestScheduledAttempt && !hasPendingRequest))
return false;
highestScheduledAttempt = request.ConnectionAttempt;
pendingAttempts.Add(request.ConnectionAttempt);
highestScheduledAttempt = Math.Max(highestScheduledAttempt, request.ConnectionAttempt);
request = request with { RequestId = ++nextRequestId };
pendingAttempts[request.ConnectionAttempt] = request.RequestId;
if (requests.Writer.TryWrite(request))
return true;
pendingAttempts.Remove(request.ConnectionAttempt);
if (hasPendingRequest)
pendingAttempts[request.ConnectionAttempt] = previousRequestId;
else
pendingAttempts.Remove(request.ConnectionAttempt);
return false;
}
}
@ -84,6 +98,13 @@ namespace MinecraftClient
{
await foreach (RestartRequest request in requests.Reader.ReadAllAsync(shutdown.Token).ConfigureAwait(false))
{
lock (stateLock)
{
if (!pendingAttempts.TryGetValue(request.ConnectionAttempt, out long requestId)
|| requestId != request.RequestId)
continue;
}
try
{
await restart(request, shutdown.Token).ConfigureAwait(false);
@ -99,7 +120,11 @@ namespace MinecraftClient
finally
{
lock (stateLock)
pendingAttempts.Remove(request.ConnectionAttempt);
{
if (pendingAttempts.TryGetValue(request.ConnectionAttempt, out long requestId)
&& requestId == request.RequestId)
pendingAttempts.Remove(request.ConnectionAttempt);
}
}
}
}