2020-01-27 17:25:45 +01:00
|
|
|
|
using Model;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net.NetworkInformation;
|
2020-01-29 16:32:23 +01:00
|
|
|
|
using System.IO;
|
2020-01-27 17:25:45 +01:00
|
|
|
|
|
|
|
|
|
namespace Common
|
|
|
|
|
{
|
|
|
|
|
public static class ProcessSpawner
|
|
|
|
|
{
|
|
|
|
|
private const int minPort = 23581;
|
|
|
|
|
private const int maxPort = 23700;
|
|
|
|
|
private const int maximumServers = 80;
|
|
|
|
|
private const string nBloodExecutable = "nblood_server";
|
|
|
|
|
|
|
|
|
|
private static readonly Random rnd = new Random();
|
|
|
|
|
|
2020-01-29 16:32:23 +01:00
|
|
|
|
public static SpawnedServerInfo SpawnServer(int players, string modName, string tempFolderName = "")
|
2020-01-27 17:25:45 +01:00
|
|
|
|
{
|
|
|
|
|
int serversRunning = Process.GetProcessesByName(nBloodExecutable).Count();
|
|
|
|
|
if (serversRunning >= maximumServers)
|
|
|
|
|
throw new Exception("The maximum number of servers are already running.");
|
|
|
|
|
|
|
|
|
|
Mod mod = GetModByName(modName);
|
|
|
|
|
int port = GetPort();
|
|
|
|
|
|
2020-01-29 16:32:23 +01:00
|
|
|
|
var process = Process.Start(GetProcessStartInfo(players, port, mod, tempFolderName));
|
2020-01-27 17:25:45 +01:00
|
|
|
|
return new SpawnedServerInfo(process, port, mod);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Mod GetModByName(string modName)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(modName))
|
|
|
|
|
return Constants.SupportedMods["BLOOD"];
|
|
|
|
|
|
|
|
|
|
if (!Constants.SupportedMods.ContainsKey(modName.ToUpper()))
|
2020-01-29 16:32:23 +01:00
|
|
|
|
throw new Exception($"This mod is not supported: {modName}.");
|
2020-01-27 17:25:45 +01:00
|
|
|
|
|
|
|
|
|
return Constants.SupportedMods[modName.ToUpper()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int GetPort()
|
|
|
|
|
{
|
|
|
|
|
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
|
|
|
|
|
var usedPorts = ipGlobalProperties.GetActiveTcpConnections().Select(c => c.LocalEndPoint.Port).ToList();
|
|
|
|
|
usedPorts.AddRange(ipGlobalProperties.GetActiveTcpListeners().Select(c => c.Port).ToList());
|
|
|
|
|
usedPorts.AddRange(ipGlobalProperties.GetActiveUdpListeners().Select(c => c.Port).ToList());
|
|
|
|
|
|
|
|
|
|
var availablePorts = Enumerable.Range(minPort, maxPort - minPort + 1).ToList().Except(usedPorts).ToList();
|
|
|
|
|
|
|
|
|
|
if (availablePorts.Count == 0)
|
|
|
|
|
throw new Exception($"Cannot obtain free port in range {minPort}-{maxPort}.");
|
|
|
|
|
|
|
|
|
|
int index = rnd.Next(0, availablePorts.Count() - 1);
|
|
|
|
|
int port = availablePorts[index];
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-29 16:32:23 +01:00
|
|
|
|
private static ProcessStartInfo GetProcessStartInfo(int maxPlayers, int port, Mod mod, string tempFolderName = "")
|
2020-01-27 17:25:45 +01:00
|
|
|
|
{
|
2020-01-29 16:32:23 +01:00
|
|
|
|
string cmd = GetCommand(maxPlayers, port, mod, tempFolderName);
|
|
|
|
|
|
|
|
|
|
var psi = new ProcessStartInfo(GetExecutableName(), cmd)
|
2020-01-27 17:25:45 +01:00
|
|
|
|
{
|
|
|
|
|
UseShellExecute = true,
|
2020-01-28 01:29:27 +01:00
|
|
|
|
WorkingDirectory = CommandLineUtils.BloodDir
|
2020-01-27 17:25:45 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return psi;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-29 16:32:23 +01:00
|
|
|
|
private static string GetCommand(int maxPlayers, int port, Mod mod, string tempFolderName)
|
|
|
|
|
{
|
|
|
|
|
string cmd = $"-server {maxPlayers} -port {port} -pname Server {mod.CommandLine}";
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(tempFolderName))
|
|
|
|
|
{
|
|
|
|
|
string tempFolderPath = Path.Combine(CommandLineUtils.TempMapDir, tempFolderName);
|
|
|
|
|
cmd += $" -j={tempFolderPath}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-27 17:25:45 +01:00
|
|
|
|
private static string GetExecutableName()
|
|
|
|
|
{
|
|
|
|
|
string nbloodServer = nBloodExecutable;
|
|
|
|
|
bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
|
|
|
|
if (isWindows)
|
|
|
|
|
nbloodServer += ".exe";
|
|
|
|
|
|
|
|
|
|
return nbloodServer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|