Finish dynamic dvar parsing for IW4x
This commit is contained in:
parent
f1dd4f7c7f
commit
59e0072744
@ -36,12 +36,8 @@ namespace IW4MAdmin.Application
|
|||||||
public DateTime StartTime { get; private set; }
|
public DateTime StartTime { get; private set; }
|
||||||
public string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
public string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
public IList<IRConParser> AdditionalRConParsers => _additionalRConParsers.ToList<IRConParser>();
|
public IList<IRConParser> AdditionalRConParsers { get; }
|
||||||
|
public IList<IEventParser> AdditionalEventParsers { get; }
|
||||||
public IList<IEventParser> AdditionalEventParsers => _additionalEventParsers.ToList<IEventParser>();
|
|
||||||
|
|
||||||
private readonly IList<DynamicRConParser> _additionalRConParsers;
|
|
||||||
private readonly IList<DynamicEventParser> _additionalEventParsers;
|
|
||||||
|
|
||||||
static ApplicationManager Instance;
|
static ApplicationManager Instance;
|
||||||
readonly List<AsyncStatus> TaskStatuses;
|
readonly List<AsyncStatus> TaskStatuses;
|
||||||
@ -70,8 +66,8 @@ namespace IW4MAdmin.Application
|
|||||||
StartTime = DateTime.UtcNow;
|
StartTime = DateTime.UtcNow;
|
||||||
OnQuit = new ManualResetEventSlim();
|
OnQuit = new ManualResetEventSlim();
|
||||||
PageList = new PageList();
|
PageList = new PageList();
|
||||||
_additionalEventParsers = new List<DynamicEventParser>();
|
AdditionalEventParsers = new List<IEventParser>();
|
||||||
_additionalRConParsers = new List<DynamicRConParser>();
|
AdditionalRConParsers = new List<IRConParser>();
|
||||||
OnServerEvent += OnGameEvent;
|
OnServerEvent += OnGameEvent;
|
||||||
OnServerEvent += EventApi.OnGameEvent;
|
OnServerEvent += EventApi.OnGameEvent;
|
||||||
}
|
}
|
||||||
|
@ -665,13 +665,17 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
public async Task Initialize()
|
public async Task Initialize()
|
||||||
{
|
{
|
||||||
|
//RemoteConnection.SetConfiguration(Manager.AdditionalRConParsers.First().Configuration);
|
||||||
|
|
||||||
RconParser = ServerConfig.UseT6MParser ?
|
RconParser = ServerConfig.UseT6MParser ?
|
||||||
(IRConParser)new T6MRConParser() :
|
(IRConParser)new T6MRConParser() :
|
||||||
new IW3RConParser();
|
new IW4RConParser();
|
||||||
|
|
||||||
|
RemoteConnection.SetConfiguration(RconParser.Configuration);
|
||||||
|
|
||||||
var version = await this.GetDvarAsync<string>("version");
|
var version = await this.GetDvarAsync<string>("version");
|
||||||
Version = version.Value;
|
Version = version.Value;
|
||||||
GameName = Utilities.GetGame(version.Value);
|
GameName = Utilities.GetGame(version?.Value);
|
||||||
|
|
||||||
if (GameName == Game.IW4)
|
if (GameName == Game.IW4)
|
||||||
{
|
{
|
||||||
@ -702,7 +706,7 @@ namespace IW4MAdmin
|
|||||||
RconParser = Manager.AdditionalRConParsers.FirstOrDefault(_parser => (_parser as DynamicRConParser).Version == version.Value) ?? RconParser;
|
RconParser = Manager.AdditionalRConParsers.FirstOrDefault(_parser => (_parser as DynamicRConParser).Version == version.Value) ?? RconParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
var infoResponse = await this.GetInfoAsync();
|
var infoResponse = RconParser.Configuration.CommandPrefixes.RConGetInfo != null ? await this.GetInfoAsync() : null;
|
||||||
// this is normally slow, but I'm only doing it because different games have different prefixes
|
// this is normally slow, but I'm only doing it because different games have different prefixes
|
||||||
var hostname = infoResponse == null ?
|
var hostname = infoResponse == null ?
|
||||||
(await this.GetDvarAsync<string>("sv_hostname")).Value :
|
(await this.GetDvarAsync<string>("sv_hostname")).Value :
|
||||||
|
@ -9,5 +9,6 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
public CommandPrefix CommandPrefixes { get; set; }
|
public CommandPrefix CommandPrefixes { get; set; }
|
||||||
public Server.Game GameName { get; set; }
|
public Server.Game GameName { get; set; }
|
||||||
public ParserRegex Status { get; set; } = new ParserRegex();
|
public ParserRegex Status { get; set; } = new ParserRegex();
|
||||||
|
public ParserRegex Dvar { get; set; } = new ParserRegex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,11 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
Say = "sayraw {0}",
|
Say = "sayraw {0}",
|
||||||
Kick = "clientkick {0} \"{1}\"",
|
Kick = "clientkick {0} \"{1}\"",
|
||||||
Ban = "clientkick {0} \"{1}\"",
|
Ban = "clientkick {0} \"{1}\"",
|
||||||
TempBan = "tempbanclient {0} \"{1}\""
|
TempBan = "tempbanclient {0} \"{1}\"",
|
||||||
|
RConQuery = "ÿÿÿÿrcon {0} {1}",
|
||||||
|
RConGetStatus = "ÿÿÿÿgetstatus",
|
||||||
|
RConGetInfo = "ÿÿÿÿgetinfo",
|
||||||
|
RConResponse = "ÿÿÿÿprint",
|
||||||
},
|
},
|
||||||
GameName = Server.Game.IW4
|
GameName = Server.Game.IW4
|
||||||
};
|
};
|
||||||
@ -35,6 +39,13 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConNetworkId, 4);
|
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConNetworkId, 4);
|
||||||
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConName, 5);
|
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConName, 5);
|
||||||
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConIpAddress, 7);
|
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConIpAddress, 7);
|
||||||
|
|
||||||
|
Configuration.Dvar.Pattern = "^\"(.+)\" is: \"(.+)\" default: \"(.+)\"\n(?:latched: \"(.+)\"\n)? *(.+)$";
|
||||||
|
Configuration.Dvar.GroupMapping.Add(ParserRegex.GroupType.RConDvarName, 1);
|
||||||
|
Configuration.Dvar.GroupMapping.Add(ParserRegex.GroupType.RConDvarValue, 2);
|
||||||
|
Configuration.Dvar.GroupMapping.Add(ParserRegex.GroupType.RConDvarDefaultValue, 3);
|
||||||
|
Configuration.Dvar.GroupMapping.Add(ParserRegex.GroupType.RConDvarLatchedValue, 4);
|
||||||
|
Configuration.Dvar.GroupMapping.Add(ParserRegex.GroupType.RConDvarDomain, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRConParserConfiguration Configuration { get; set; }
|
public IRConParserConfiguration Configuration { get; set; }
|
||||||
@ -47,32 +58,37 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)
|
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)
|
||||||
{
|
{
|
||||||
string[] LineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.DVAR, dvarName);
|
string[] lineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.DVAR, dvarName);
|
||||||
|
string response = string.Join('\n', lineSplit.Skip(1));
|
||||||
|
|
||||||
if (LineSplit.Length < 3)
|
if (lineSplit[0] != Configuration.CommandPrefixes.RConResponse)
|
||||||
{
|
{
|
||||||
var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
|
throw new DvarException($"Could not retrieve DVAR \"{dvarName}\"");
|
||||||
e.Data["dvar_name"] = dvarName;
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: can this be made more portable and modifiable from plugin
|
if (response.Contains("Unknown command"))
|
||||||
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
if (ValueSplit.Length < 5)
|
|
||||||
{
|
{
|
||||||
var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
|
throw new DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||||
e.Data["dvar_name"] = dvarName;
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string DvarName = Regex.Replace(ValueSplit[0], @"\^[0-9]", "");
|
var match = Regex.Match(response, Configuration.Dvar.Pattern);
|
||||||
string DvarCurrentValue = Regex.Replace(ValueSplit[2], @"\^[0-9]", "");
|
|
||||||
string DvarDefaultValue = Regex.Replace(ValueSplit[4], @"\^[0-9]", "");
|
|
||||||
|
|
||||||
return new Dvar<T>(DvarName)
|
if (!match.Success)
|
||||||
{
|
{
|
||||||
Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T))
|
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()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +60,10 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
string DvarName = dvarName;
|
string DvarName = dvarName;
|
||||||
string DvarCurrentValue = Regex.Replace(ValueSplit[1], @"\^[0-9]", "");
|
string DvarCurrentValue = Regex.Replace(ValueSplit[1], @"\^[0-9]", "");
|
||||||
|
|
||||||
return new Dvar<T>(DvarName)
|
return new Dvar<T>()
|
||||||
{
|
{
|
||||||
Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T))
|
Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T)),
|
||||||
|
Name = DvarName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
{
|
{
|
||||||
public class Dvar<T>
|
public class Dvar<T>
|
||||||
{
|
{
|
||||||
public string Name { get; private set; }
|
public string Name { get; set; }
|
||||||
public T Value;
|
public T Value { get; set; }
|
||||||
|
public T DefaultValue { get; set; }
|
||||||
public Dvar(string name)
|
public T LatchedValue { get; set; }
|
||||||
{
|
public string Domain { get; set; }
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,11 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
RConNetworkId = 103,
|
RConNetworkId = 103,
|
||||||
RConName = 104,
|
RConName = 104,
|
||||||
RConIpAddress = 105,
|
RConIpAddress = 105,
|
||||||
|
RConDvarName = 106,
|
||||||
|
RConDvarValue = 107,
|
||||||
|
RConDvarDefaultValue = 108,
|
||||||
|
RConDvarLatchedValue = 109,
|
||||||
|
RConDvarDomain = 110,
|
||||||
AdditionalGroup = 200
|
AdditionalGroup = 200
|
||||||
}
|
}
|
||||||
public string Pattern { get; set; }
|
public string Pattern { get; set; }
|
||||||
|
@ -7,5 +7,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
CommandPrefix CommandPrefixes { get; set; }
|
CommandPrefix CommandPrefixes { get; set; }
|
||||||
Server.Game GameName { get; set; }
|
Server.Game GameName { get; set; }
|
||||||
ParserRegex Status { get; set; }
|
ParserRegex Status { get; set; }
|
||||||
|
ParserRegex Dvar { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -433,9 +433,9 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reserved slots stuff
|
// reserved slots stuff
|
||||||
// todo: is this broken on T6?
|
// todo: bots don't seem to honor party_maxplayers/sv_maxclients
|
||||||
if (CurrentServer.MaxClients - (CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged())) < CurrentServer.ServerConfig.ReservedSlotNumber &&
|
if (CurrentServer.MaxClients - (CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged())) < CurrentServer.ServerConfig.ReservedSlotNumber &&
|
||||||
!this.IsPrivileged() && CurrentServer.GameName != Server.Game.T6M /* HACK: temporary */)
|
!this.IsPrivileged())
|
||||||
{
|
{
|
||||||
CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved");
|
CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved");
|
||||||
Kick(loc["SERVER_KICK_SLOT_IS_RESERVED"], Utilities.IW4MAdminClient(CurrentServer));
|
Kick(loc["SERVER_KICK_SLOT_IS_RESERVED"], Utilities.IW4MAdminClient(CurrentServer));
|
||||||
@ -461,9 +461,10 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
if (ipAddress != null)
|
if (ipAddress != null)
|
||||||
{
|
{
|
||||||
if (IPAddressString == "66.150.121.184")
|
// todo: remove this in a few weeks because it's just temporary for server forwarding
|
||||||
|
if (IPAddressString == "66.150.121.184" || IPAddressString == "62.210.178.177")
|
||||||
{
|
{
|
||||||
Kick("Your favorite servers are outdated. Please re-add the server.", autoKickClient);
|
Kick($"Your favorite servers are outdated. Please remove and re-add this server. ({CurrentServer.Hostname})", autoKickClient);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||||
|
@ -13,5 +13,9 @@ namespace SharedLibraryCore.RCon
|
|||||||
public string Ban { get; set; }
|
public string Ban { get; set; }
|
||||||
public string Unban { get; set; }
|
public string Unban { get; set; }
|
||||||
public string TempBan { get; set; }
|
public string TempBan { get; set; }
|
||||||
|
public string RConQuery { get; set; }
|
||||||
|
public string RConGetStatus { get; set; }
|
||||||
|
public string RConGetInfo { get; set; }
|
||||||
|
public string RConResponse { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,19 @@ namespace SharedLibraryCore.RCon
|
|||||||
public string RConPassword { get; private set; }
|
public string RConPassword { get; private set; }
|
||||||
|
|
||||||
private readonly ILogger Log;
|
private readonly ILogger Log;
|
||||||
|
private IRConParserConfiguration Config;
|
||||||
|
|
||||||
public Connection(string ipAddress, int port, string password, ILogger log)
|
public Connection(string ipAddress, int port, string password, ILogger log, IRConParserConfiguration config)
|
||||||
{
|
{
|
||||||
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
||||||
RConPassword = password;
|
RConPassword = password;
|
||||||
Log = log;
|
Log = log;
|
||||||
|
Config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfiguration(IRConParserConfiguration config)
|
||||||
|
{
|
||||||
|
Config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", bool waitForResponse = true)
|
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", bool waitForResponse = true)
|
||||||
@ -73,16 +80,14 @@ namespace SharedLibraryCore.RCon
|
|||||||
{
|
{
|
||||||
case StaticHelpers.QueryType.DVAR:
|
case StaticHelpers.QueryType.DVAR:
|
||||||
case StaticHelpers.QueryType.COMMAND:
|
case StaticHelpers.QueryType.COMMAND:
|
||||||
var header = "ÿÿÿÿrcon ".Select(Convert.ToByte).ToList();
|
payload = Utilities.EncodingType
|
||||||
byte[] p = Utilities.EncodingType.GetBytes($"{RConPassword} {parameters}");
|
.GetBytes(string.Format(Config.CommandPrefixes.RConQuery, RConPassword, parameters + '\0'));
|
||||||
header.AddRange(p);
|
|
||||||
payload = header.ToArray();
|
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.GET_STATUS:
|
case StaticHelpers.QueryType.GET_STATUS:
|
||||||
payload = "ÿÿÿÿgetstatus".Select(Convert.ToByte).ToArray();
|
payload = (Config.CommandPrefixes.RConGetStatus + '\0').Select(Convert.ToByte).ToArray();
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.GET_INFO:
|
case StaticHelpers.QueryType.GET_INFO:
|
||||||
payload = "ÿÿÿÿgetinfo".Select(Convert.ToByte).ToArray();
|
payload = (Config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ namespace SharedLibraryCore
|
|||||||
Logger = Manager.GetLogger(this.EndPoint);
|
Logger = Manager.GetLogger(this.EndPoint);
|
||||||
Logger.WriteInfo(this.ToString());
|
Logger.WriteInfo(this.ToString());
|
||||||
ServerConfig = config;
|
ServerConfig = config;
|
||||||
RemoteConnection = new RCon.Connection(IP, Port, Password, Logger);
|
RemoteConnection = new RCon.Connection(IP, Port, Password, Logger, null);
|
||||||
|
|
||||||
Clients = new List<EFClient>(new EFClient[18]);
|
Clients = new List<EFClient>(new EFClient[18]);
|
||||||
Reports = new List<Report>();
|
Reports = new List<Report>();
|
||||||
|
@ -347,6 +347,11 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
public static Game GetGame(string gameName)
|
public static Game GetGame(string gameName)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(gameName))
|
||||||
|
{
|
||||||
|
return Game.UKN;
|
||||||
|
}
|
||||||
|
|
||||||
if (gameName.Contains("IW4"))
|
if (gameName.Contains("IW4"))
|
||||||
{
|
{
|
||||||
return Game.IW4;
|
return Game.IW4;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user