Add Avalonia server-host launcher (MVP scaffold)
Cross-platform C# GUI to replace the Qt/C++ Host GUI, on the same dotnet toolchain as the server. MVP: load/save commonwealth-server.json, Start/Stop the CommonwealthOnline.Server process (published exe, then dll, then source run), and stream its output to a live log. Themed to the Commonwealth Online brand (near-black + amber). Builds clean on net8.0. Next: player list + kick/ban via the admin port, then retire the Qt host.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace CommonwealthOnline.Host.Services;
|
||||
|
||||
// Launches the CommonwealthOnline.Server process, preferring a published
|
||||
// apphost, then a framework-dependent DLL, then a source-tree dotnet run.
|
||||
public sealed class ServerController
|
||||
{
|
||||
private Process? _process;
|
||||
|
||||
public bool IsRunning => _process is { HasExited: false };
|
||||
|
||||
public event Action<string>? LogReceived;
|
||||
public event Action<bool>? RunningChanged;
|
||||
|
||||
public void Start(string serverDir, string configPath)
|
||||
{
|
||||
if (IsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var startInfo = ResolveLaunch(serverDir, configPath);
|
||||
var process = new Process { StartInfo = startInfo, EnableRaisingEvents = true };
|
||||
process.OutputDataReceived += (_, e) => Emit(e.Data);
|
||||
process.ErrorDataReceived += (_, e) => Emit(e.Data);
|
||||
process.Exited += (_, _) => RunningChanged?.Invoke(false);
|
||||
|
||||
_process = process;
|
||||
process.Start();
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
RunningChanged?.Invoke(true);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_process is { HasExited: false } process)
|
||||
{
|
||||
try
|
||||
{
|
||||
process.Kill(entireProcessTree: true);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Process already gone or not killable; RunningChanged fires on Exited.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Emit(string? line)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(line))
|
||||
{
|
||||
LogReceived?.Invoke(line);
|
||||
}
|
||||
}
|
||||
|
||||
private static ProcessStartInfo ResolveLaunch(string serverDir, string configPath)
|
||||
{
|
||||
var exeName = OperatingSystem.IsWindows()
|
||||
? "CommonwealthOnline.Server.exe"
|
||||
: "CommonwealthOnline.Server";
|
||||
var apphost = Path.Combine(serverDir, exeName);
|
||||
var dll = Path.Combine(serverDir, "CommonwealthOnline.Server.dll");
|
||||
var project = Path.Combine(serverDir, "CommonwealthOnline.Server.csproj");
|
||||
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
WorkingDirectory = serverDir,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
if (File.Exists(apphost))
|
||||
{
|
||||
info.FileName = apphost;
|
||||
info.ArgumentList.Add("serve");
|
||||
}
|
||||
else if (File.Exists(dll))
|
||||
{
|
||||
info.FileName = "dotnet";
|
||||
info.ArgumentList.Add(dll);
|
||||
info.ArgumentList.Add("serve");
|
||||
}
|
||||
else
|
||||
{
|
||||
info.FileName = "dotnet";
|
||||
info.ArgumentList.Add("run");
|
||||
info.ArgumentList.Add("--project");
|
||||
info.ArgumentList.Add(project);
|
||||
info.ArgumentList.Add("-c");
|
||||
info.ArgumentList.Add("Release");
|
||||
info.ArgumentList.Add("--");
|
||||
info.ArgumentList.Add("serve");
|
||||
}
|
||||
|
||||
info.ArgumentList.Add("--config");
|
||||
info.ArgumentList.Add(configPath);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user