mirror of
https://github.com/RaidMax/IW4M-Admin.git
synced 2025-06-11 15:52:25 -05:00
tweaked rcon throttle rate/made async
increased cutoff for server overview messages dont print message if timed out
This commit is contained in:
@ -1,17 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SharedLibrary.Network;
|
||||
using SharedLibrary.Helpers;
|
||||
using SharedLibrary.Objects;
|
||||
using SharedLibrary.Database;
|
||||
using System.Data.Entity;
|
||||
using SharedLibrary.Database;
|
||||
using SharedLibrary.Database.Models;
|
||||
using SharedLibrary.Services;
|
||||
using SharedLibrary.Exceptions;
|
||||
using SharedLibrary.Objects;
|
||||
using SharedLibrary.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Commands
|
||||
{
|
||||
@ -420,9 +417,6 @@ namespace SharedLibrary.Commands
|
||||
|
||||
Player.Permission newPerm = Utilities.MatchPermission(E.Data);
|
||||
|
||||
if (newPerm == Player.Permission.Owner && E.Origin.Level != Player.Permission.Console)
|
||||
newPerm = Player.Permission.Banned;
|
||||
|
||||
if (newPerm == Player.Permission.Owner &&
|
||||
!E.Owner.Manager.GetApplicationSettings().Configuration().EnableMultipleOwners)
|
||||
{
|
||||
@ -981,16 +975,16 @@ namespace SharedLibrary.Commands
|
||||
}
|
||||
}
|
||||
|
||||
public class CRestartServer : Command
|
||||
public class CKillServer : Command
|
||||
{
|
||||
public CRestartServer() : base("restartserver", "restart the server", "restart", Player.Permission.Administrator, false)
|
||||
public CKillServer() : base("killserver", "kill the game server", "kill", Player.Permission.Administrator, false)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
var gameserverProcesses = System.Diagnostics.Process.GetProcessesByName("iw4x");
|
||||
var currentProcess = gameserverProcesses.FirstOrDefault(g => g.GetCommandLine().Contains($"+set net_port {E.Owner.GetPort()}"));
|
||||
var currentProcess = gameserverProcesses.FirstOrDefault(g => g.MainWindowTitle.Contains(E.Owner.Hostname));
|
||||
|
||||
if (currentProcess == null)
|
||||
{
|
||||
@ -999,7 +993,6 @@ namespace SharedLibrary.Commands
|
||||
|
||||
else
|
||||
{
|
||||
var commandLine = currentProcess.GetCommandLine();
|
||||
// attempt to kill it natively
|
||||
try
|
||||
{
|
||||
@ -1021,51 +1014,17 @@ namespace SharedLibrary.Commands
|
||||
try
|
||||
{
|
||||
currentProcess.Kill();
|
||||
await E.Origin.Tell("Successfully killed server process");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await E.Origin.Tell("Could not kill IW4x process");
|
||||
await E.Origin.Tell("Could not kill server process");
|
||||
E.Owner.Logger.WriteDebug("Unable to kill process");
|
||||
E.Owner.Logger.WriteDebug($"Exception: {e.Message}");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
System.Diagnostics.Process process = new System.Diagnostics.Process();
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
#if !DEBUG
|
||||
process.StartInfo.WorkingDirectory = E.Owner.WorkingDirectory;
|
||||
#else
|
||||
process.StartInfo.WorkingDirectory = @"C:\Users\User\Desktop\MW2";
|
||||
#endif
|
||||
process.StartInfo.FileName = $"{process.StartInfo.WorkingDirectory}\\iw4x.exe";
|
||||
process.StartInfo.Arguments = commandLine.Substring(6);
|
||||
|
||||
/*process.StartInfo.UserName = E.Owner.ServerConfig.RestartUsername;
|
||||
|
||||
var pw = new System.Security.SecureString();
|
||||
foreach (char c in E.Owner.ServerConfig.RestartPassword)
|
||||
pw.AppendChar(c);
|
||||
|
||||
process.StartInfo.Password = pw;
|
||||
*/
|
||||
process.Start();
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
await E.Origin.Tell("Could not start the IW4x process");
|
||||
E.Owner.Logger.WriteDebug("Unable to start process");
|
||||
E.Owner.Logger.WriteDebug($"Exception: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ namespace SharedLibrary.Dtos
|
||||
public string Name { get; set; }
|
||||
public int ClientId { get; set; }
|
||||
public string Level { get; set; }
|
||||
public int LevelInt { get; set; }
|
||||
public string IPAddress { get; set; }
|
||||
public long NetworkId { get; set; }
|
||||
public List<string> Aliases { get; set; }
|
||||
|
@ -1,163 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Sockets;
|
||||
|
||||
using SharedLibrary.Objects;
|
||||
|
||||
namespace SharedLibrary.Network
|
||||
{
|
||||
public static class RCON
|
||||
{
|
||||
enum QueryType
|
||||
{
|
||||
GET_STATUS,
|
||||
GET_INFO,
|
||||
DVAR,
|
||||
COMMAND,
|
||||
}
|
||||
|
||||
private static DateTime LastQuery;
|
||||
|
||||
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
|
||||
{
|
||||
using (var ServerOOBConnection = new UdpClient())
|
||||
{
|
||||
// prevent flooding
|
||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 100)
|
||||
Task.Delay(100).Wait();
|
||||
LastQuery = DateTime.Now;
|
||||
|
||||
ServerOOBConnection.Client.SendTimeout = 1000;
|
||||
ServerOOBConnection.Client.ReceiveTimeout = 1000;
|
||||
var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort());
|
||||
|
||||
string QueryString = String.Empty;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case QueryType.DVAR:
|
||||
case QueryType.COMMAND:
|
||||
QueryString = $"ÿÿÿÿrcon {QueryServer.Password} {Parameters}";
|
||||
break;
|
||||
case QueryType.GET_STATUS:
|
||||
QueryString = "ÿÿÿÿ getstatus";
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] Payload = GetRequestBytes(QueryString);
|
||||
|
||||
int attempts = 0;
|
||||
retry:
|
||||
|
||||
try
|
||||
{
|
||||
ServerOOBConnection.Connect(Endpoint);
|
||||
ServerOOBConnection.Send(Payload, Payload.Length);
|
||||
|
||||
byte[] ReceiveBuffer = new byte[8192];
|
||||
StringBuilder QueryResponseString = new StringBuilder();
|
||||
|
||||
do
|
||||
{
|
||||
ReceiveBuffer = ServerOOBConnection.Receive(ref Endpoint);
|
||||
QueryResponseString.Append(Encoding.UTF7.GetString(ReceiveBuffer).TrimEnd('\0'));
|
||||
} while (ServerOOBConnection.Available > 0 && ServerOOBConnection.Client.Connected);
|
||||
|
||||
if (QueryResponseString.ToString().Contains("Invalid password"))
|
||||
throw new Exceptions.NetworkException("RCON password is invalid");
|
||||
if (QueryResponseString.ToString().Contains("rcon_password"))
|
||||
throw new Exceptions.NetworkException("RCON password has not been set");
|
||||
|
||||
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
string[] SplitResponse = QueryResponseString.ToString().Split(new char[] { (char)num }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return SplitResponse;
|
||||
}
|
||||
|
||||
catch (Exceptions.NetworkException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
attempts++;
|
||||
if (attempts > 2)
|
||||
{
|
||||
var ne = new Exceptions.NetworkException("Could not communicate with the server");
|
||||
ne.Data["internal_exception"] = e.Message;
|
||||
ne.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
|
||||
throw ne;
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<DVAR<T>> GetDvarAsync<T>(this Server server, string dvarName)
|
||||
{
|
||||
string[] LineSplit = await Task.FromResult(SendQuery(QueryType.DVAR, server, dvarName));
|
||||
|
||||
if (LineSplit.Length != 3)
|
||||
{
|
||||
var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
}
|
||||
|
||||
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (ValueSplit.Length != 5)
|
||||
{
|
||||
var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
}
|
||||
|
||||
string DvarName = Regex.Replace(ValueSplit[0], @"\^[0-9]", "");
|
||||
string DvarCurrentValue = Regex.Replace(ValueSplit[2], @"\^[0-9]", "");
|
||||
string DvarDefaultValue = Regex.Replace(ValueSplit[4], @"\^[0-9]", "");
|
||||
|
||||
return new DVAR<T>(DvarName) { Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T)) };
|
||||
}
|
||||
|
||||
public static async Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
|
||||
{
|
||||
await Task.FromResult(SendQuery(QueryType.DVAR, server, $"set {dvarName} {dvarValue}"));
|
||||
}
|
||||
|
||||
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName)
|
||||
{
|
||||
return await Task.FromResult(SendQuery(QueryType.COMMAND, server, commandName).Skip(1).ToArray());
|
||||
}
|
||||
|
||||
public static async Task<List<Player>> GetStatusAsync(this Server server)
|
||||
{
|
||||
#if DEBUG && DEBUG_PLAYERS
|
||||
string[] response = await Task.Run(() => System.IO.File.ReadAllLines("players.txt"));
|
||||
#else
|
||||
string[] response = await Task.FromResult(SendQuery(QueryType.DVAR, server, "status"));
|
||||
#endif
|
||||
return Utilities.PlayersFromStatus(response);
|
||||
}
|
||||
|
||||
static byte[] GetRequestBytes(string Request)
|
||||
{
|
||||
Byte[] initialRequestBytes = Encoding.Unicode.GetBytes(Request);
|
||||
Byte[] fixedRequest = new Byte[initialRequestBytes.Length / 2];
|
||||
|
||||
for (int i = 0; i < initialRequestBytes.Length; i++)
|
||||
if (initialRequestBytes[i] != 0)
|
||||
fixedRequest[i / 2] = initialRequestBytes[i];
|
||||
|
||||
return fixedRequest;
|
||||
}
|
||||
}
|
||||
}
|
226
SharedLibrary/RCon/Connection.cs
Normal file
226
SharedLibrary/RCon/Connection.cs
Normal file
@ -0,0 +1,226 @@
|
||||
using SharedLibrary.Exceptions;
|
||||
using SharedLibrary.Interfaces;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.RCon
|
||||
{
|
||||
class ConnectionState
|
||||
{
|
||||
public Socket Client { get; set; }
|
||||
public const int BufferSize = 8192;
|
||||
public byte[] Buffer = new byte[BufferSize];
|
||||
public StringBuilder ResponseString { get; set; }
|
||||
|
||||
public ConnectionState()
|
||||
{
|
||||
ResponseString = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
public class Connection
|
||||
{
|
||||
IPEndPoint Endpoint;
|
||||
string RConPassword;
|
||||
Socket ServerConnection;
|
||||
ILogger Log;
|
||||
int FailedConnections;
|
||||
DateTime LastQuery;
|
||||
string Response;
|
||||
|
||||
ManualResetEvent OnConnected;
|
||||
ManualResetEvent OnSent;
|
||||
ManualResetEvent OnReceived;
|
||||
|
||||
public Connection(string ipAddress, int port, string password, ILogger log)
|
||||
{
|
||||
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
||||
RConPassword = password;
|
||||
Log = log;
|
||||
|
||||
OnConnected = new ManualResetEvent(false);
|
||||
OnSent = new ManualResetEvent(false);
|
||||
OnReceived = new ManualResetEvent(false);
|
||||
|
||||
try
|
||||
{
|
||||
ServerConnection = new Socket(Endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
ServerConnection.BeginConnect(Endpoint, new AsyncCallback(OnConnectedCallback), ServerConnection);
|
||||
if (!OnConnected.WaitOne(StaticHelpers.SocketTimeout))
|
||||
throw new SocketException((int)SocketError.TimedOut);
|
||||
FailedConnections = 0;
|
||||
}
|
||||
|
||||
catch (SocketException e)
|
||||
{
|
||||
throw new NetworkException(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
~Connection()
|
||||
{
|
||||
ServerConnection.Shutdown(SocketShutdown.Both);
|
||||
ServerConnection.Close();
|
||||
ServerConnection.Dispose();
|
||||
}
|
||||
|
||||
private void OnConnectedCallback(IAsyncResult ar)
|
||||
{
|
||||
var serverSocket = (Socket)ar.AsyncState;
|
||||
|
||||
try
|
||||
{
|
||||
serverSocket.EndConnect(ar);
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"Successfully initialized socket to {serverSocket.RemoteEndPoint}");
|
||||
#endif
|
||||
OnConnected.Set();
|
||||
}
|
||||
|
||||
catch (SocketException e)
|
||||
{
|
||||
throw new NetworkException($"Could not connect to RCon - {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSentCallback(IAsyncResult ar)
|
||||
{
|
||||
Socket serverConnection = (Socket)ar.AsyncState;
|
||||
|
||||
try
|
||||
{
|
||||
int sentByteNum = serverConnection.EndSend(ar);
|
||||
FailedConnections = 0;
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"Sent {sentByteNum} bytes to server");
|
||||
#endif
|
||||
OnSent.Set();
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
FailedConnections++;
|
||||
if (FailedConnections < 1)
|
||||
Log.WriteWarning($"Could not send RCon data to server - {e.Message}");
|
||||
//throw new NetworkException($"Could not send RCon message to server - {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceivedCallback(IAsyncResult ar)
|
||||
{
|
||||
var connectionState = (ConnectionState)ar.AsyncState;
|
||||
var serverConnection = connectionState.Client;
|
||||
|
||||
try
|
||||
{
|
||||
int bytesRead = serverConnection.EndReceive(ar);
|
||||
FailedConnections = 0;
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"Received {bytesRead} bytes from server");
|
||||
#endif
|
||||
connectionState.ResponseString.Append(Encoding.UTF7.GetString(connectionState.Buffer, 0, bytesRead).TrimEnd('\0'));
|
||||
|
||||
if (serverConnection.Available > 0)
|
||||
{
|
||||
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||
new AsyncCallback(OnReceivedCallback), connectionState);
|
||||
}
|
||||
else
|
||||
{
|
||||
Response = connectionState.ResponseString.ToString();
|
||||
OnReceived.Set();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OnReceived.Set();
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
FailedConnections++;
|
||||
if (FailedConnections < 1)
|
||||
Log.WriteWarning($"Could not receive data from server - {e.Message}");
|
||||
//throw new NetworkException($"Could not recieve message from server - {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
||||
{
|
||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 150)
|
||||
{
|
||||
await Task.Delay(150);
|
||||
LastQuery = DateTime.Now;
|
||||
}
|
||||
|
||||
OnSent.Reset();
|
||||
OnReceived.Reset();
|
||||
string queryString = "";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case StaticHelpers.QueryType.DVAR:
|
||||
case StaticHelpers.QueryType.COMMAND:
|
||||
queryString = $"ÿÿÿÿrcon {RConPassword} {parameters}";
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_STATUS:
|
||||
queryString = "ÿÿÿÿgetstatus";
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] payload = Encoding.Default.GetBytes(queryString);
|
||||
retrySend:
|
||||
ServerConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), ServerConnection);
|
||||
bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
|
||||
|
||||
if (!success)
|
||||
{
|
||||
FailedConnections++;
|
||||
if (FailedConnections < 4)
|
||||
goto retrySend;
|
||||
else
|
||||
throw new NetworkException($"Could not send data to server - {new SocketException((int)SocketError.TimedOut).Message}");
|
||||
}
|
||||
|
||||
var connectionState = new ConnectionState
|
||||
{
|
||||
Client = ServerConnection
|
||||
};
|
||||
|
||||
retryReceive:
|
||||
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||
new AsyncCallback(OnReceivedCallback), connectionState);
|
||||
success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
|
||||
|
||||
if (!success)
|
||||
{
|
||||
FailedConnections++;
|
||||
if (FailedConnections < 4)
|
||||
goto retryReceive;
|
||||
else
|
||||
throw new NetworkException($"Could not send data to server - {new SocketException((int)SocketError.TimedOut).Message}");
|
||||
}
|
||||
|
||||
string queryResponse = Response;//connectionState.ResponseString.ToString();
|
||||
|
||||
if (queryResponse.Contains("Invalid password"))
|
||||
throw new NetworkException("RCON password is invalid");
|
||||
if (queryResponse.ToString().Contains("rcon_password"))
|
||||
throw new NetworkException("RCON password has not been set");
|
||||
|
||||
string[] splitResponse = queryResponse.Split(new char[]
|
||||
{
|
||||
StaticHelpers.SeperatorChar
|
||||
}, StringSplitOptions.RemoveEmptyEntries);
|
||||
return splitResponse;
|
||||
}
|
||||
}
|
||||
}
|
24
SharedLibrary/RCon/StaticHelpers.cs
Normal file
24
SharedLibrary/RCon/StaticHelpers.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using SharedLibrary.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.RCon
|
||||
{
|
||||
public static class StaticHelpers
|
||||
{
|
||||
public enum QueryType
|
||||
{
|
||||
GET_STATUS,
|
||||
GET_INFO,
|
||||
DVAR,
|
||||
COMMAND,
|
||||
}
|
||||
|
||||
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 1);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
using SharedLibrary.Network;
|
||||
using SharedLibrary.RCon;
|
||||
using SharedLibrary.Commands;
|
||||
using System.Threading.Tasks;
|
||||
using SharedLibrary.Helpers;
|
||||
@ -36,6 +36,7 @@ namespace SharedLibrary
|
||||
Manager = mgr;
|
||||
Logger = Manager.GetLogger();
|
||||
ServerConfig = config;
|
||||
RemoteConnection = new RCon.Connection(IP, Port, Password, Logger);
|
||||
|
||||
Players = new List<Player>(new Player[18]);
|
||||
Reports = new List<Report>();
|
||||
@ -312,6 +313,7 @@ namespace SharedLibrary
|
||||
public bool Throttled { get; protected set; }
|
||||
public bool CustomCallback { get; protected set; }
|
||||
public string WorkingDirectory { get; protected set; }
|
||||
public RCon.Connection RemoteConnection { get; protected set; }
|
||||
|
||||
// Internal
|
||||
protected string IP;
|
||||
|
@ -196,7 +196,8 @@
|
||||
<Compile Include="Objects\Report.cs" />
|
||||
<Compile Include="PluginImporter.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RCON.cs" />
|
||||
<Compile Include="RCon\Connection.cs" />
|
||||
<Compile Include="RCon\StaticHelpers.cs" />
|
||||
<Compile Include="Server.cs" />
|
||||
<Compile Include="Configuration\ApplicationConfiguration.cs" />
|
||||
<Compile Include="Services\AliasService.cs" />
|
||||
|
@ -11,6 +11,9 @@ using static SharedLibrary.Server;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using static SharedLibrary.RCon.StaticHelpers;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
@ -359,36 +362,6 @@ namespace SharedLibrary
|
||||
};
|
||||
}
|
||||
|
||||
/*https://stackoverflow.com/questions/2633628/can-i-get-command-line-arguments-of-other-processes-from-net-c*/
|
||||
// Define an extension method for type System.Process that returns the command
|
||||
// line via WMI.
|
||||
public static string GetCommandLine(this Process process)
|
||||
{
|
||||
string cmdLine = null;
|
||||
using (var searcher = new ManagementObjectSearcher(
|
||||
$"SELECT CommandLine FROM Win32_Process WHERE ProcessId = {process.Id}"))
|
||||
{
|
||||
// By definition, the query returns at most 1 match, because the process
|
||||
// is looked up by ID (which is unique by definition).
|
||||
var matchEnum = searcher.Get().GetEnumerator();
|
||||
if (matchEnum.MoveNext()) // Move to the 1st item.
|
||||
{
|
||||
cmdLine = matchEnum.Current["CommandLine"]?.ToString();
|
||||
}
|
||||
}
|
||||
if (cmdLine == null)
|
||||
{
|
||||
// Not having found a command line implies 1 of 2 exceptions, which the
|
||||
// WMI query masked:
|
||||
// An "Access denied" exception due to lack of privileges.
|
||||
// A "Cannot process request because the process (<pid>) has exited."
|
||||
// exception due to the process having terminated.
|
||||
// We provoke the same exception again simply by accessing process.MainModule.
|
||||
var dummy = process.MainModule; // Provoke exception.
|
||||
}
|
||||
return cmdLine;
|
||||
}
|
||||
|
||||
public static bool IsPrivileged(this Player p) => p.Level > Player.Permission.User;
|
||||
|
||||
public static bool PromptBool(string question)
|
||||
@ -409,5 +382,52 @@ namespace SharedLibrary
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public static async Task<DVAR<T>> GetDvarAsync<T>(this Server server, string dvarName)
|
||||
{
|
||||
string[] LineSplit = await server.RemoteConnection.SendQueryAsync(QueryType.DVAR, dvarName);
|
||||
|
||||
if (LineSplit.Length != 3)
|
||||
{
|
||||
var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
}
|
||||
|
||||
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (ValueSplit.Length != 5)
|
||||
{
|
||||
var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
}
|
||||
|
||||
string DvarName = Regex.Replace(ValueSplit[0], @"\^[0-9]", "");
|
||||
string DvarCurrentValue = Regex.Replace(ValueSplit[2], @"\^[0-9]", "");
|
||||
string DvarDefaultValue = Regex.Replace(ValueSplit[4], @"\^[0-9]", "");
|
||||
|
||||
return new DVAR<T>(DvarName) { Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T)) };
|
||||
}
|
||||
|
||||
public static async Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
|
||||
{
|
||||
await server.RemoteConnection.SendQueryAsync(QueryType.DVAR, $"set {dvarName} {dvarValue}");
|
||||
}
|
||||
|
||||
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName)
|
||||
{
|
||||
return (await server.RemoteConnection.SendQueryAsync(QueryType.COMMAND, commandName)).Skip(1).ToArray();
|
||||
}
|
||||
|
||||
public static async Task<List<Player>> GetStatusAsync(this Server server)
|
||||
{
|
||||
#if DEBUG && DEBUG_PLAYERS
|
||||
string[] response = await Task.Run(() => System.IO.File.ReadAllLines("players.txt"));
|
||||
#else
|
||||
string[] response = await server.RemoteConnection.SendQueryAsync(QueryType.DVAR, "status");
|
||||
#endif
|
||||
return Utilities.PlayersFromStatus(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user