Skip to content
This repository was archived by the owner on Apr 15, 2026. It is now read-only.

Commit 50e7a2f

Browse files
author
Dankrushen
authored
Merge pull request #250 from ServerMod/dank-input
Update input system and minor logging changes
2 parents 27b9487 + bfdf48b commit 50e7a2f

9 files changed

Lines changed: 163 additions & 80 deletions

File tree

MultiAdmin/Config/MultiAdminConfig.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public class MultiAdminConfig : InheritableConfigRegister
5454
new ConfigEntry<bool>("use_new_input_system", true,
5555
"Use New Input System", "Whether to use the new input system, if false, the original input system will be used");
5656

57+
public ConfigEntry<bool> HideInput { get; } =
58+
new ConfigEntry<bool>("hide_input", false,
59+
"Hide Console Input", "Whether to hide console input, if true, typed input will not be printed");
60+
5761
public ConfigEntry<uint> Port { get; } =
5862
new ConfigEntry<uint>("port", 7777,
5963
"Game Port", "The port for the server to use");
@@ -98,10 +102,18 @@ public class MultiAdminConfig : InheritableConfigRegister
98102
new ConfigEntry<decimal>("restart_low_memory", 400,
99103
"Restart Low Memory", "Restart if the game's remaining memory falls below this value in megabytes");
100104

105+
public ConfigEntry<uint> RestartLowMemoryTicks { get; } =
106+
new ConfigEntry<uint>("restart_low_memory_ticks", 10,
107+
"Restart Low Memory Ticks", "The number of ticks the memory can be over the limit before restarting");
108+
101109
public ConfigEntry<decimal> RestartLowMemoryRoundEnd { get; } =
102110
new ConfigEntry<decimal>("restart_low_memory_roundend", 450,
103111
"Restart Low Memory Round-End", "Restart at the end of the round if the game's remaining memory falls below this value in megabytes");
104112

113+
public ConfigEntry<uint> RestartLowMemoryRoundEndTicks { get; } =
114+
new ConfigEntry<uint>("restart_low_memory_roundend_ticks", 10,
115+
"Restart Low Memory Round-End Ticks", "The number of ticks the memory can be over the limit before restarting at the end of the round");
116+
105117
public ConfigEntry<bool> RandomInputColors { get; } =
106118
new ConfigEntry<bool>("random_input_colors", false,
107119
"Random Input Colors", "Randomize the new input system's colors every time a message is input");
@@ -142,6 +154,10 @@ public class MultiAdminConfig : InheritableConfigRegister
142154
new ConfigEntry<int>("server_start_retry_delay", 10000,
143155
"Server Start Retry Delay", "The time in milliseconds to wait before trying to start the server again after crashing");
144156

157+
public ConfigEntry<int> MultiAdminTickDelay { get; } =
158+
new ConfigEntry<int>("multiadmin_tick_delay", 1000,
159+
"MultiAdmin Tick Delay", "The time in milliseconds between MultiAdmin ticks (any features that update over time)");
160+
145161
public ConfigEntry<string> ServersFolder { get; } =
146162
new ConfigEntry<string>("servers_folder", "servers",
147163
"Servers Folder", "The location of the `servers` folder for MultiAdmin to load multiple server configurations from");

MultiAdmin/Features/ConfigGenerator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Collections.Generic;
22
using System.IO;
3-
using System.Text;
43
using MultiAdmin.Config;
54
using MultiAdmin.Config.ConfigHandler;
65
using MultiAdmin.Features.Attributes;

MultiAdmin/Features/MemoryChecker.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ internal class MemoryChecker : Feature, IEventTick, IEventRoundEnd
1313
private uint tickCount;
1414
private uint tickCountSoft;
1515

16-
private const uint MaxTicks = 10;
17-
private const uint MaxTicksSoft = 10;
16+
private uint maxTicks = 10;
17+
private uint maxTicksSoft = 10;
1818

1919
private bool restart;
2020

@@ -82,7 +82,7 @@ public void OnTick()
8282
{
8383
if (LowBytes < 0 && LowBytesSoft < 0 || MaxBytes < 0) return;
8484

85-
if (tickCount < MaxTicks && LowBytes >= 0 && MemoryLeftBytes <= LowBytes)
85+
if (tickCount < maxTicks && LowBytes >= 0 && MemoryLeftBytes <= LowBytes)
8686
{
8787
Server.Write(
8888
$"Warning: Program is running low on memory ({decimal.Round(MemoryLeftMb, OutputPrecision)} MB left), the server will restart if it continues",
@@ -94,7 +94,7 @@ public void OnTick()
9494
tickCount = 0;
9595
}
9696

97-
if (!restart && tickCountSoft < MaxTicksSoft && LowBytesSoft >= 0 && MemoryLeftBytes <= LowBytesSoft)
97+
if (!restart && tickCountSoft < maxTicksSoft && LowBytesSoft >= 0 && MemoryLeftBytes <= LowBytesSoft)
9898
{
9999
Server.Write(
100100
$"Warning: Program is running low on memory ({decimal.Round(MemoryLeftMb, OutputPrecision)} MB left), the server will restart at the end of the round if it continues",
@@ -108,14 +108,14 @@ public void OnTick()
108108

109109
if (Server.Status == ServerStatus.Restarting) return;
110110

111-
if (tickCount >= MaxTicks)
111+
if (tickCount >= maxTicks)
112112
{
113113
Server.Write("Restarting due to low memory...", ConsoleColor.Red);
114114
Server.RestartServer();
115115

116116
restart = false;
117117
}
118-
else if (!restart && tickCountSoft >= MaxTicksSoft)
118+
else if (!restart && tickCountSoft >= maxTicksSoft)
119119
{
120120
Server.Write("Server will restart at the end of the round due to low memory");
121121

@@ -143,6 +143,9 @@ public override string GetFeatureName()
143143

144144
public override void OnConfigReload()
145145
{
146+
maxTicks = Server.ServerConfig.RestartLowMemoryTicks.Value;
147+
maxTicksSoft = Server.ServerConfig.RestartLowMemoryRoundEndTicks.Value;
148+
146149
LowMb = Server.ServerConfig.RestartLowMemory.Value;
147150
LowMbSoft = Server.ServerConfig.RestartLowMemoryRoundEnd.Value;
148151
MaxMb = Server.ServerConfig.MaxMemory.Value;

MultiAdmin/Program.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace MultiAdmin
1515
{
1616
public static class Program
1717
{
18-
public const string MaVersion = "3.3.1.2";
18+
public const string MaVersion = "3.4.0.0";
1919
public const string RecommendedMonoVersion = "5.18";
2020

2121
private static readonly List<Server> InstantiatedServers = new List<Server>();
@@ -27,6 +27,8 @@ public static class Program
2727
? Utils.GetFullPathSafe(Path.Combine(MaDebugLogDir, $"{Utils.DateTime}_MA_{MaVersion}_debug_log.txt"))
2828
: null;
2929

30+
private static StreamWriter debugLogStream = null;
31+
3032
private static uint? portArg;
3133
public static readonly string[] Args = Environment.GetCommandLineArgs();
3234

@@ -78,8 +80,8 @@ public static void Write(string message, ConsoleColor color = ConsoleColor.DarkY
7880
{
7981
if (Headless) return;
8082

81-
new ColoredMessage(Utils.TimeStampMessage(message), color).WriteLine(
82-
MultiAdminConfig.GlobalConfig?.UseNewInputSystem?.Value ?? false);
83+
new ColoredMessage(Utils.TimeStampMessage(message), color).WriteLine((!MultiAdminConfig.GlobalConfig?.HideInput?.Value ?? false) &&
84+
(MultiAdminConfig.GlobalConfig?.UseNewInputSystem?.Value ?? false));
8385
}
8486
}
8587

@@ -109,14 +111,18 @@ public static void LogDebug(string tag, string message)
109111
if ((!MultiAdminConfig.GlobalConfig?.DebugLog?.Value ?? true) ||
110112
string.IsNullOrEmpty(MaDebugLogFile) || tag == null || !IsDebugLogTagAllowed(tag)) return;
111113

112-
Directory.CreateDirectory(MaDebugLogDir);
113-
114-
using (StreamWriter sw = File.AppendText(MaDebugLogFile))
114+
// Assign debug log stream as needed
115+
if (debugLogStream == null)
115116
{
116-
message = Utils.TimeStampMessage($"[{tag}] {message}");
117-
sw.Write(message);
118-
if (!message.EndsWith(Environment.NewLine)) sw.WriteLine();
117+
Directory.CreateDirectory(MaDebugLogDir);
118+
debugLogStream = File.AppendText(MaDebugLogFile);
119119
}
120+
121+
message = Utils.TimeStampMessage($"[{tag}] {message}");
122+
debugLogStream.Write(message);
123+
if (!message.EndsWith(Environment.NewLine)) debugLogStream.WriteLine();
124+
125+
debugLogStream.Flush();
120126
}
121127
catch (Exception e)
122128
{
@@ -157,15 +163,15 @@ private static void OnExit(object sender, EventArgs e)
157163
server.StopServer();
158164

159165
// Wait for server to exit
160-
int timeToWait = Math.Max(MultiAdminConfig.GlobalConfig.SafeShutdownCheckDelay.Value, 0);
166+
int timeToWait = Math.Max(server.ServerConfig.SafeShutdownCheckDelay.Value, 0);
161167
int timeWaited = 0;
162168

163169
while (server.IsGameProcessRunning)
164170
{
165171
Thread.Sleep(timeToWait);
166172
timeWaited += timeToWait;
167173

168-
if (timeWaited >= MultiAdminConfig.GlobalConfig.SafeShutdownTimeout.Value)
174+
if (timeWaited >= server.ServerConfig.SafeShutdownTimeout.Value)
169175
{
170176
Write(
171177
string.IsNullOrEmpty(server.serverId)
@@ -183,12 +189,10 @@ private static void OnExit(object sender, EventArgs e)
183189
}
184190
}
185191

186-
exited = true;
192+
debugLogStream?.Close();
193+
debugLogStream = null;
187194

188-
// For some reason Mono hangs on this, but it works perfectly without it,
189-
// but on Windows it doesn't close immediately unless this is here
190-
if (Utils.IsWindows)
191-
Environment.Exit(0);
195+
exited = true;
192196
}
193197
}
194198

MultiAdmin/Server.cs

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
using System.IO;
55
using System.Linq;
66
using System.Reflection;
7-
using System.Text;
87
using System.Threading;
8+
using System.Threading.Tasks;
99
using MultiAdmin.Config;
1010
using MultiAdmin.ConsoleTools;
1111
using MultiAdmin.Features.Attributes;
@@ -150,7 +150,6 @@ private set
150150
{
151151
MaLogFile = string.IsNullOrEmpty(LogDirFile) ? null : string.Format(LogDirFile, "MA");
152152
ScpLogFile = string.IsNullOrEmpty(LogDirFile) ? null : string.Format(LogDirFile, "SCP");
153-
ModLogFile = string.IsNullOrEmpty(LogDirFile) ? null : string.Format(LogDirFile, "MODERATOR");
154153
}
155154
}
156155
}
@@ -164,7 +163,8 @@ private set
164163
public string LogDirFile { get; private set; }
165164
public string MaLogFile { get; private set; }
166165
public string ScpLogFile { get; private set; }
167-
public string ModLogFile { get; private set; }
166+
167+
private StreamWriter maLogStream;
168168

169169
public Process GameProcess { get; private set; }
170170

@@ -190,17 +190,20 @@ public bool IsGameProcessRunning
190190

191191
private void MainLoop()
192192
{
193+
// Creates and starts a timer
193194
Stopwatch timer = new Stopwatch();
195+
timer.Restart();
196+
194197
while (IsGameProcessRunning)
195198
{
196-
timer.Restart();
197-
198199
foreach (IEventTick tickEvent in tick) tickEvent.OnTick();
199200

200201
timer.Stop();
201202

202-
// Wait 1 second per tick (calculating how long the tick took and compensating)
203-
Thread.Sleep(Math.Max(1000 - timer.Elapsed.Milliseconds, 0));
203+
// Wait the delay per tick (calculating how long the tick took and compensating)
204+
Thread.Sleep(Math.Max(ServerConfig.MultiAdminTickDelay.Value - timer.Elapsed.Milliseconds, 0));
205+
206+
timer.Restart();
204207

205208
if (Status == ServerStatus.Restarting && CheckRestartTimeout)
206209
{
@@ -291,6 +294,11 @@ public void StartServer(bool restartOnCrash = true)
291294

292295
try
293296
{
297+
// Set up logging
298+
maLogStream?.Close();
299+
Directory.CreateDirectory(logDir);
300+
maLogStream = File.AppendText(MaLogFile);
301+
294302
#region Startup Info Printing & Logging
295303

296304
WriteConfigInformation();
@@ -380,15 +388,18 @@ public void StartServer(bool restartOnCrash = true)
380388

381389
Write($"Starting server with the following parameters:\n{scpslExe} {startInfo.Arguments}");
382390

391+
// Reset the supported mod features
392+
supportedModFeatures = ModFeatures.None;
393+
383394
ForEachHandler<IEventServerPreStart>(eventPreStart => eventPreStart.OnServerPreStart());
384395

385396
// Start the input reader
386-
Thread inputHandlerThread = null;
397+
CancellationTokenSource inputHandlerCancellation = new CancellationTokenSource();
398+
Task inputHandler = null;
387399

388400
if (!Program.Headless)
389401
{
390-
inputHandlerThread = new Thread(() => InputHandler.Write(this));
391-
inputHandlerThread.Start();
402+
inputHandler = Task.Run(() => InputHandler.Write(this, inputHandlerCancellation.Token), inputHandlerCancellation.Token);
392403
}
393404

394405
// Start the output reader
@@ -437,9 +448,19 @@ public void StartServer(bool restartOnCrash = true)
437448
GameProcess = null;
438449

439450
// Stop the input handler if it's running
440-
if (inputHandlerThread != null && inputHandlerThread.IsAlive)
451+
if (inputHandler != null)
441452
{
442-
inputHandlerThread.Abort();
453+
inputHandlerCancellation.Cancel();
454+
try
455+
{
456+
inputHandler.Wait();
457+
}
458+
catch (Exception)
459+
{
460+
// Task was cancelled or disposed, this is fine since we're waiting for that
461+
}
462+
inputHandler.Dispose();
463+
inputHandlerCancellation.Dispose();
443464
}
444465

445466
consoleSocket.Disconnect();
@@ -487,6 +508,10 @@ public void StartServer(bool restartOnCrash = true)
487508
}
488509
}
489510
} while (shouldRestart);
511+
512+
// Finish server instance
513+
maLogStream?.Close();
514+
maLogStream = null;
490515
}
491516

492517
public void SetStopStatus(bool killGame = false)
@@ -625,10 +650,10 @@ public void Write(ColoredMessage[] messages, ConsoleColor? timeStampColor = null
625650

626651
ColoredMessage[] timeStampedMessage = Utils.TimeStampMessage(messages, timeStampColor);
627652

628-
timeStampedMessage.WriteLine(ServerConfig.UseNewInputSystem.Value);
653+
timeStampedMessage.WriteLine(!ServerConfig.HideInput.Value && ServerConfig.UseNewInputSystem.Value);
629654

630-
if (ServerConfig.UseNewInputSystem.Value)
631-
InputHandler.WriteInputAndSetCursor();
655+
if (!ServerConfig.HideInput.Value && ServerConfig.UseNewInputSystem.Value)
656+
InputHandler.WriteInputAndSetCursor(ServerConfig);
632657
}
633658
}
634659

@@ -657,14 +682,10 @@ public void Log(string message)
657682

658683
try
659684
{
660-
Directory.CreateDirectory(logDir);
661-
662-
using (StreamWriter sw = File.AppendText(MaLogFile))
663-
{
664-
message = Utils.TimeStampMessage(message);
665-
sw.Write(message);
666-
if (!message.EndsWith(Environment.NewLine)) sw.WriteLine();
667-
}
685+
message = Utils.TimeStampMessage(message);
686+
maLogStream.Write(message);
687+
if (!message.EndsWith(Environment.NewLine)) maLogStream.WriteLine();
688+
maLogStream.Flush();
668689
}
669690
catch (Exception e)
670691
{

0 commit comments

Comments
 (0)