mirror of
https://github.com/RaidMax/IW4M-Admin.git
synced 2025-06-07 21:58:06 -05:00
make bad GUID parse throw an exception so we don't have a client connect with GUID of 0 no longer print out ac debug messages fix small issue of trying to parse empty chat messages fix issue with set level on accounts with multi guid, same IP
191 lines
8.5 KiB
C#
191 lines
8.5 KiB
C#
using SharedLibraryCore;
|
|
using SharedLibraryCore.Database.Models;
|
|
using SharedLibraryCore.Exceptions;
|
|
using SharedLibraryCore.Interfaces;
|
|
using SharedLibraryCore.RCon;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using static SharedLibraryCore.Server;
|
|
|
|
namespace IW4MAdmin.Application.RconParsers
|
|
{
|
|
class BaseRConParser : IRConParser
|
|
{
|
|
public BaseRConParser()
|
|
{
|
|
Configuration = new DynamicRConParserConfiguration()
|
|
{
|
|
CommandPrefixes = new CommandPrefix()
|
|
{
|
|
Tell = "tell {0} {1}",
|
|
Say = "say {0}",
|
|
Kick = "clientkick {0} \"{1}\"",
|
|
Ban = "clientkick {0} \"{1}\"",
|
|
TempBan = "tempbanclient {0} \"{1}\"",
|
|
RConCommand = "ÿÿÿÿrcon {0} {1}",
|
|
RConGetDvar = "ÿÿÿÿrcon {0} {1}",
|
|
RConSetDvar = "ÿÿÿÿrcon {0} set {1}",
|
|
RConGetStatus = "ÿÿÿÿgetstatus",
|
|
RConGetInfo = "ÿÿÿÿgetinfo",
|
|
RConResponse = "ÿÿÿÿprint",
|
|
},
|
|
};
|
|
|
|
Configuration.Status.Pattern = @"^ *([0-9]+) +-?([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) +(.{0,32}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$";
|
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConClientNumber, 1);
|
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConScore, 2);
|
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConPing, 3);
|
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConNetworkId, 4);
|
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConName, 5);
|
|
Configuration.Status.AddMapping(ParserRegex.GroupType.RConIpAddress, 7);
|
|
|
|
Configuration.Dvar.Pattern = "^\"(.+)\" is: \"(.+)?\" default: \"(.+)?\"\n(?:latched: \"(.+)?\"\n)? *(.+)$";
|
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarName, 1);
|
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarValue, 2);
|
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDefaultValue, 3);
|
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarLatchedValue, 4);
|
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDomain, 5);
|
|
}
|
|
|
|
public IRConParserConfiguration Configuration { get; set; }
|
|
|
|
public string Version { get; set; } = "CoD";
|
|
public Game GameName { get; set; } = Game.COD;
|
|
public bool CanGenerateLogPath { get; set; } = true;
|
|
|
|
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
|
{
|
|
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command);
|
|
return response.Skip(1).ToArray();
|
|
}
|
|
|
|
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)
|
|
{
|
|
string[] lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.GET_DVAR, dvarName);
|
|
string response = string.Join('\n', lineSplit.Skip(1));
|
|
|
|
if (!lineSplit[0].Contains(Configuration.CommandPrefixes.RConResponse))
|
|
{
|
|
throw new DvarException($"Could not retrieve DVAR \"{dvarName}\"");
|
|
}
|
|
|
|
if (response.Contains("Unknown command"))
|
|
{
|
|
throw new DvarException($"DVAR \"{dvarName}\" does not exist");
|
|
}
|
|
|
|
var match = Regex.Match(response, Configuration.Dvar.Pattern);
|
|
|
|
if (!match.Success)
|
|
{
|
|
throw new DvarException($"Could not retrieve DVAR \"{dvarName}\"");
|
|
}
|
|
|
|
string value = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarValue]].Value.StripColors();
|
|
string defaultValue = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarDefaultValue]].Value.StripColors();
|
|
string latchedValue = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarLatchedValue]].Value.StripColors();
|
|
|
|
return new Dvar<T>()
|
|
{
|
|
Name = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarName]].Value.StripColors(),
|
|
Value = string.IsNullOrEmpty(value) ? default(T) : (T)Convert.ChangeType(value, typeof(T)),
|
|
DefaultValue = string.IsNullOrEmpty(defaultValue) ? default(T) : (T)Convert.ChangeType(defaultValue, typeof(T)),
|
|
LatchedValue = string.IsNullOrEmpty(latchedValue) ? default(T) : (T)Convert.ChangeType(latchedValue, typeof(T)),
|
|
Domain = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarDomain]].Value.StripColors()
|
|
};
|
|
}
|
|
|
|
public async Task<List<EFClient>> GetStatusAsync(Connection connection)
|
|
{
|
|
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
|
return ClientsFromStatus(response);
|
|
}
|
|
|
|
public async Task<bool> SetDvarAsync(Connection connection, string dvarName, object dvarValue)
|
|
{
|
|
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, $"{dvarName} {dvarValue}")).Length > 0;
|
|
}
|
|
|
|
private List<EFClient> ClientsFromStatus(string[] Status)
|
|
{
|
|
List<EFClient> StatusPlayers = new List<EFClient>();
|
|
|
|
if (Status.Length < 4)
|
|
{
|
|
throw new ServerException("Unexpected status response received");
|
|
}
|
|
|
|
int validMatches = 0;
|
|
foreach (string statusLine in Status)
|
|
{
|
|
string responseLine = statusLine.Trim();
|
|
|
|
var regex = Regex.Match(responseLine, Configuration.Status.Pattern, RegexOptions.IgnoreCase);
|
|
|
|
if (regex.Success)
|
|
{
|
|
validMatches++;
|
|
int clientNumber = int.Parse(regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConClientNumber]].Value);
|
|
int score = int.Parse(regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConScore]].Value);
|
|
|
|
int ping = 999;
|
|
|
|
// their state can be CNCT, ZMBI etc
|
|
if (regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]].Value.Length <= 3)
|
|
{
|
|
ping = int.Parse(regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConPing]].Value);
|
|
}
|
|
|
|
long networkId;
|
|
try
|
|
{
|
|
networkId = regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]].Value.ConvertGuidToLong();
|
|
}
|
|
|
|
catch (FormatException)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string name = regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].Value.StripColors().Trim();
|
|
int? ip = regex.Groups[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConIpAddress]].Value.Split(':')[0].ConvertToIP();
|
|
|
|
var client = new EFClient()
|
|
{
|
|
CurrentAlias = new EFAlias()
|
|
{
|
|
Name = name
|
|
},
|
|
NetworkId = networkId,
|
|
ClientNumber = clientNumber,
|
|
IPAddress = ip,
|
|
Ping = ping,
|
|
Score = score,
|
|
IsBot = ip == null,
|
|
State = EFClient.ClientState.Connecting
|
|
};
|
|
|
|
//// they've not fully connected yet
|
|
//if (!client.IsBot && ping == 999)
|
|
//{
|
|
// continue;
|
|
//}
|
|
|
|
StatusPlayers.Add(client);
|
|
}
|
|
}
|
|
|
|
// this happens if status is requested while map is rotating
|
|
if (Status.Length > 5 && validMatches == 0)
|
|
{
|
|
throw new ServerException("Server is rotating map");
|
|
}
|
|
|
|
return StatusPlayers;
|
|
}
|
|
}
|
|
}
|