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 string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
|
||||
public IList<IRConParser> AdditionalRConParsers => _additionalRConParsers.ToList<IRConParser>();
|
||||
|
||||
public IList<IEventParser> AdditionalEventParsers => _additionalEventParsers.ToList<IEventParser>();
|
||||
|
||||
private readonly IList<DynamicRConParser> _additionalRConParsers;
|
||||
private readonly IList<DynamicEventParser> _additionalEventParsers;
|
||||
public IList<IRConParser> AdditionalRConParsers { get; }
|
||||
public IList<IEventParser> AdditionalEventParsers { get; }
|
||||
|
||||
static ApplicationManager Instance;
|
||||
readonly List<AsyncStatus> TaskStatuses;
|
||||
@ -70,8 +66,8 @@ namespace IW4MAdmin.Application
|
||||
StartTime = DateTime.UtcNow;
|
||||
OnQuit = new ManualResetEventSlim();
|
||||
PageList = new PageList();
|
||||
_additionalEventParsers = new List<DynamicEventParser>();
|
||||
_additionalRConParsers = new List<DynamicRConParser>();
|
||||
AdditionalEventParsers = new List<IEventParser>();
|
||||
AdditionalRConParsers = new List<IRConParser>();
|
||||
OnServerEvent += OnGameEvent;
|
||||
OnServerEvent += EventApi.OnGameEvent;
|
||||
}
|
||||
|
@ -665,13 +665,17 @@ namespace IW4MAdmin
|
||||
|
||||
public async Task Initialize()
|
||||
{
|
||||
//RemoteConnection.SetConfiguration(Manager.AdditionalRConParsers.First().Configuration);
|
||||
|
||||
RconParser = ServerConfig.UseT6MParser ?
|
||||
(IRConParser)new T6MRConParser() :
|
||||
new IW3RConParser();
|
||||
new IW4RConParser();
|
||||
|
||||
RemoteConnection.SetConfiguration(RconParser.Configuration);
|
||||
|
||||
var version = await this.GetDvarAsync<string>("version");
|
||||
Version = version.Value;
|
||||
GameName = Utilities.GetGame(version.Value);
|
||||
GameName = Utilities.GetGame(version?.Value);
|
||||
|
||||
if (GameName == Game.IW4)
|
||||
{
|
||||
@ -702,7 +706,7 @@ namespace IW4MAdmin
|
||||
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
|
||||
var hostname = infoResponse == null ?
|
||||
(await this.GetDvarAsync<string>("sv_hostname")).Value :
|
||||
|
@ -9,5 +9,6 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
public CommandPrefix CommandPrefixes { get; set; }
|
||||
public Server.Game GameName { get; set; }
|
||||
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}",
|
||||
Kick = "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
|
||||
};
|
||||
@ -35,6 +39,13 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConNetworkId, 4);
|
||||
Configuration.Status.GroupMapping.Add(ParserRegex.GroupType.RConName, 5);
|
||||
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; }
|
||||
@ -47,32 +58,37 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
|
||||
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");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
throw new DvarException($"Could not retrieve DVAR \"{dvarName}\"");
|
||||
}
|
||||
|
||||
// todo: can this be made more portable and modifiable from plugin
|
||||
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (ValueSplit.Length < 5)
|
||||
if (response.Contains("Unknown command"))
|
||||
{
|
||||
var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||
e.Data["dvar_name"] = dvarName;
|
||||
throw e;
|
||||
throw new DvarException($"DVAR \"{dvarName}\" does not exist");
|
||||
}
|
||||
|
||||
string DvarName = Regex.Replace(ValueSplit[0], @"\^[0-9]", "");
|
||||
string DvarCurrentValue = Regex.Replace(ValueSplit[2], @"\^[0-9]", "");
|
||||
string DvarDefaultValue = Regex.Replace(ValueSplit[4], @"\^[0-9]", "");
|
||||
var match = Regex.Match(response, Configuration.Dvar.Pattern);
|
||||
|
||||
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 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 string Name { get; private set; }
|
||||
public T Value;
|
||||
|
||||
public Dvar(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
public string Name { get; set; }
|
||||
public T Value { get; set; }
|
||||
public T DefaultValue { get; set; }
|
||||
public T LatchedValue { get; set; }
|
||||
public string Domain { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,11 @@ namespace SharedLibraryCore.Interfaces
|
||||
RConNetworkId = 103,
|
||||
RConName = 104,
|
||||
RConIpAddress = 105,
|
||||
RConDvarName = 106,
|
||||
RConDvarValue = 107,
|
||||
RConDvarDefaultValue = 108,
|
||||
RConDvarLatchedValue = 109,
|
||||
RConDvarDomain = 110,
|
||||
AdditionalGroup = 200
|
||||
}
|
||||
public string Pattern { get; set; }
|
||||
|
@ -7,5 +7,6 @@ namespace SharedLibraryCore.Interfaces
|
||||
CommandPrefix CommandPrefixes { get; set; }
|
||||
Server.Game GameName { get; set; }
|
||||
ParserRegex Status { get; set; }
|
||||
ParserRegex Dvar { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -433,9 +433,9 @@ namespace SharedLibraryCore.Database.Models
|
||||
}
|
||||
|
||||
// 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 &&
|
||||
!this.IsPrivileged() && CurrentServer.GameName != Server.Game.T6M /* HACK: temporary */)
|
||||
!this.IsPrivileged())
|
||||
{
|
||||
CurrentServer.Logger.WriteDebug($"Kicking {this} their spot is reserved");
|
||||
Kick(loc["SERVER_KICK_SLOT_IS_RESERVED"], Utilities.IW4MAdminClient(CurrentServer));
|
||||
@ -461,9 +461,10 @@ namespace SharedLibraryCore.Database.Models
|
||||
|
||||
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;
|
||||
}
|
||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||
|
@ -13,5 +13,9 @@ namespace SharedLibraryCore.RCon
|
||||
public string Ban { get; set; }
|
||||
public string Unban { 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; }
|
||||
|
||||
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);
|
||||
RConPassword = password;
|
||||
Log = log;
|
||||
Config = config;
|
||||
}
|
||||
|
||||
public void SetConfiguration(IRConParserConfiguration config)
|
||||
{
|
||||
Config = config;
|
||||
}
|
||||
|
||||
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.COMMAND:
|
||||
var header = "ÿÿÿÿrcon ".Select(Convert.ToByte).ToList();
|
||||
byte[] p = Utilities.EncodingType.GetBytes($"{RConPassword} {parameters}");
|
||||
header.AddRange(p);
|
||||
payload = header.ToArray();
|
||||
payload = Utilities.EncodingType
|
||||
.GetBytes(string.Format(Config.CommandPrefixes.RConQuery, RConPassword, parameters + '\0'));
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_STATUS:
|
||||
payload = "ÿÿÿÿgetstatus".Select(Convert.ToByte).ToArray();
|
||||
payload = (Config.CommandPrefixes.RConGetStatus + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_INFO:
|
||||
payload = "ÿÿÿÿgetinfo".Select(Convert.ToByte).ToArray();
|
||||
payload = (Config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace SharedLibraryCore
|
||||
Logger = Manager.GetLogger(this.EndPoint);
|
||||
Logger.WriteInfo(this.ToString());
|
||||
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]);
|
||||
Reports = new List<Report>();
|
||||
|
@ -347,6 +347,11 @@ namespace SharedLibraryCore
|
||||
|
||||
public static Game GetGame(string gameName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(gameName))
|
||||
{
|
||||
return Game.UKN;
|
||||
}
|
||||
|
||||
if (gameName.Contains("IW4"))
|
||||
{
|
||||
return Game.IW4;
|
||||
|
Loading…
Reference in New Issue
Block a user