adjustments for T6 and tekno (implement mapped dvars and default values)

This commit is contained in:
RaidMax 2020-06-16 17:16:12 -05:00
parent ba77e0149c
commit bb4e51d9c8
9 changed files with 109 additions and 51 deletions

View File

@ -42,7 +42,7 @@ namespace IW4MAdmin.Application.EventParsers
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3); Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4); Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4);
Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world)?;([^;]{1,24})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"; Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,24})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1); Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1);
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2); Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3); Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
@ -57,7 +57,7 @@ namespace IW4MAdmin.Application.EventParsers
Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12); Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13); Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13);
Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world)?;([^;]{1,24})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"; Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,24})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1); Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1);
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2); Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3); Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);

View File

@ -939,7 +939,7 @@ namespace IW4MAdmin
RemoteConnection.SetConfiguration(RconParser.Configuration); RemoteConnection.SetConfiguration(RconParser.Configuration);
var version = await this.GetDvarAsync<string>("version"); var version = await this.GetMappedDvarValueOrDefaultAsync<string>("version");
Version = version.Value; Version = version.Value;
GameName = Utilities.GetGame(version?.Value ?? RconParser.Version); GameName = Utilities.GetGame(version?.Value ?? RconParser.Version);
@ -956,8 +956,7 @@ namespace IW4MAdmin
Version = RconParser.Version; Version = RconParser.Version;
} }
// these T7 specific things aren't ideal , but it's a quick fix var svRunning = await this.GetMappedDvarValueOrDefaultAsync<string>("sv_running");
var svRunning = await this.GetDvarAsync("sv_running", GameName == Game.T7 ? "1" : null);
if (!string.IsNullOrEmpty(svRunning.Value) && svRunning.Value != "1") if (!string.IsNullOrEmpty(svRunning.Value) && svRunning.Value != "1")
{ {
@ -965,29 +964,17 @@ namespace IW4MAdmin
} }
var infoResponse = RconParser.Configuration.CommandPrefixes.RConGetInfo != null ? await this.GetInfoAsync() : null; 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 ? string hostname = (await this.GetMappedDvarValueOrDefaultAsync<string>("sv_hostname", "hostname", infoResponse)).Value;
(await this.GetDvarAsync<string>("sv_hostname")).Value : string mapname = (await this.GetMappedDvarValueOrDefaultAsync<string>("mapname", infoResponse: infoResponse)).Value;
infoResponse.Where(kvp => kvp.Key.Contains("hostname")).Select(kvp => kvp.Value).First(); int maxplayers = (await this.GetMappedDvarValueOrDefaultAsync<int>("sv_maxclients", infoResponse: infoResponse)).Value;
var mapname = infoResponse == null ? string gametype = (await this.GetMappedDvarValueOrDefaultAsync<string>("g_gametype", "gametype", infoResponse)).Value;
(await this.GetDvarAsync("mapname", "Unknown")).Value : var basepath = (await this.GetMappedDvarValueOrDefaultAsync<string>("fs_basepath"));
infoResponse["mapname"]; var basegame = (await this.GetMappedDvarValueOrDefaultAsync<string>("fs_basegame"));
int maxplayers = (GameName == Game.IW4) ? // gotta love IW4 idiosyncrasies var game = (await this.GetMappedDvarValueOrDefaultAsync<string>("fs_game", infoResponse: infoResponse));
(await this.GetDvarAsync<int>("party_maxplayers")).Value : var logfile = await this.GetMappedDvarValueOrDefaultAsync<string>("g_log");
infoResponse == null || !infoResponse.ContainsKey("sv_maxclients") ? var logsync = await this.GetMappedDvarValueOrDefaultAsync<int>("g_logsync");
(await this.GetDvarAsync<int>("sv_maxclients")).Value : var ip = await this.GetMappedDvarValueOrDefaultAsync<string>("net_ip");
Convert.ToInt32(infoResponse["sv_maxclients"]);
var gametype = infoResponse == null ?
(await this.GetDvarAsync("g_gametype", GameName == Game.T7 ? "" : null)).Value :
infoResponse.Where(kvp => kvp.Key.Contains("gametype")).Select(kvp => kvp.Value).First();
var basepath = await this.GetDvarAsync("fs_basepath", GameName == Game.T7 ? "" : null);
var basegame = await this.GetDvarAsync("fs_basegame", GameName == Game.T7 ? "" : null);
var game = infoResponse == null || !infoResponse.ContainsKey("fs_game") ?
(await this.GetDvarAsync("fs_game", GameName == Game.T7 ? "" : null)).Value :
infoResponse["fs_game"];
var logfile = await this.GetDvarAsync<string>("g_log");
var logsync = await this.GetDvarAsync<int>("g_logsync");
var ip = await this.GetDvarAsync<string>("net_ip");
if (Manager.GetApplicationSettings().Configuration().EnableCustomSayName) if (Manager.GetApplicationSettings().Configuration().EnableCustomSayName)
{ {
@ -996,7 +983,7 @@ namespace IW4MAdmin
try try
{ {
var website = await this.GetDvarAsync<string>("_website"); var website = await this.GetMappedDvarValueOrDefaultAsync<string>("_website");
// this occurs for games that don't give us anything back when // this occurs for games that don't give us anything back when
// the dvar is not set // the dvar is not set
@ -1018,7 +1005,7 @@ namespace IW4MAdmin
WorkingDirectory = basepath.Value; WorkingDirectory = basepath.Value;
this.Hostname = hostname; this.Hostname = hostname;
this.MaxClients = maxplayers; this.MaxClients = maxplayers;
this.FSGame = game; this.FSGame = game.Value;
this.Gametype = gametype; this.Gametype = gametype;
this.IP = ip.Value == "localhost" ? ServerConfig.IPAddress : ip.Value ?? ServerConfig.IPAddress; this.IP = ip.Value == "localhost" ? ServerConfig.IPAddress : ip.Value ?? ServerConfig.IPAddress;
UpdateMap(mapname); UpdateMap(mapname);
@ -1070,7 +1057,7 @@ namespace IW4MAdmin
BaseGameDirectory = basegame.Value, BaseGameDirectory = basegame.Value,
BasePathDirectory = basepath.Value, BasePathDirectory = basepath.Value,
GameDirectory = EventParser.Configuration.GameDirectory ?? "", GameDirectory = EventParser.Configuration.GameDirectory ?? "",
ModDirectory = game ?? "", ModDirectory = game.Value ?? "",
LogFile = logfile.Value, LogFile = logfile.Value,
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
}; };

View File

@ -14,8 +14,6 @@ namespace IW4MAdmin.Application.RconParsers
{ {
public class BaseRConParser : IRConParser public class BaseRConParser : IRConParser
{ {
private const int MAX_FAULTY_STATUS_LINES = 7;
public BaseRConParser(IParserRegexFactory parserRegexFactory) public BaseRConParser(IParserRegexFactory parserRegexFactory)
{ {
Configuration = new DynamicRConParserConfiguration(parserRegexFactory) Configuration = new DynamicRConParserConfiguration(parserRegexFactory)
@ -56,10 +54,14 @@ namespace IW4MAdmin.Application.RconParsers
Configuration.StatusHeader.Pattern = "num +score +ping +guid +name +lastmsg +address +qport +rate *"; Configuration.StatusHeader.Pattern = "num +score +ping +guid +name +lastmsg +address +qport +rate *";
Configuration.MapStatus.Pattern = @"map: (([a-z]|_|\d)+)"; Configuration.MapStatus.Pattern = @"map: (([a-z]|_|\d)+)";
Configuration.MapStatus.AddMapping(ParserRegex.GroupType.RConStatusMap, 1); Configuration.MapStatus.AddMapping(ParserRegex.GroupType.RConStatusMap, 1);
if (!Configuration.DefaultDvarValues.ContainsKey("mapname"))
{
Configuration.DefaultDvarValues.Add("mapname", "Unknown");
}
} }
public IRConParserConfiguration Configuration { get; set; } public IRConParserConfiguration Configuration { get; set; }
public virtual string Version { get; set; } = "CoD"; public virtual string Version { get; set; } = "CoD";
public Game GameName { get; set; } = Game.COD; public Game GameName { get; set; } = Game.COD;
public bool CanGenerateLogPath { get; set; } = true; public bool CanGenerateLogPath { get; set; } = true;
@ -211,14 +213,6 @@ namespace IW4MAdmin.Application.RconParsers
State = EFClient.ClientState.Connecting State = EFClient.ClientState.Connecting
}; };
//#if DEBUG
// if (client.NetworkId < 1000 && client.NetworkId > 0)
// {
// client.IPAddress = 2147483646;
// client.Ping = 0;
// }
//#endif
StatusPlayers.Add(client); StatusPlayers.Add(client);
} }
} }
@ -231,5 +225,19 @@ namespace IW4MAdmin.Application.RconParsers
return StatusPlayers; return StatusPlayers;
} }
public string GetOverrideDvarName(string dvarName)
{
if (Configuration.OverrideDvarNameMapping.ContainsKey(dvarName))
{
return Configuration.OverrideDvarNameMapping[dvarName];
}
return dvarName;
}
public T GetDefaultDvarValue<T>(string dvarName) => Configuration.DefaultDvarValues.ContainsKey(dvarName) ?
(T)Convert.ChangeType(Configuration.DefaultDvarValues[dvarName], typeof(T)) :
default;
} }
} }

View File

@ -1,6 +1,6 @@
using IW4MAdmin.Application.Factories; using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Interfaces;
using SharedLibraryCore.RCon; using SharedLibraryCore.RCon;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
namespace IW4MAdmin.Application.RconParsers namespace IW4MAdmin.Application.RconParsers
@ -19,6 +19,8 @@ namespace IW4MAdmin.Application.RconParsers
public string ServerNotRunningResponse { get; set; } public string ServerNotRunningResponse { get; set; }
public bool WaitForResponse { get; set; } = true; public bool WaitForResponse { get; set; } = true;
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber; public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
public IDictionary<string, string> OverrideDvarNameMapping { get; set; } = new Dictionary<string, string>();
public IDictionary<string, string> DefaultDvarValues { get; set; } = new Dictionary<string, string>();
public DynamicRConParserConfiguration(IParserRegexFactory parserRegexFactory) public DynamicRConParserConfiguration(IParserRegexFactory parserRegexFactory)
{ {

View File

@ -3,7 +3,7 @@ var eventParser;
var plugin = { var plugin = {
author: 'RaidMax', author: 'RaidMax',
version: 0.1, version: 0.2,
name: 'Black Ops 3 Parser', name: 'Black Ops 3 Parser',
isParser: true, isParser: true,
@ -24,6 +24,14 @@ var plugin = {
rconParser.Configuration.CommandPrefixes.RConSetDvar = '\xff\xff\xff\xff\x00{0} set {1}'; rconParser.Configuration.CommandPrefixes.RConSetDvar = '\xff\xff\xff\xff\x00{0} set {1}';
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01'; rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01';
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7 rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7
rconParser.Configuration.ServerNotRunningResponse = 'this is here to prevent a hiberating server from being detected as not running';
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'live_steam_server_name');
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
rconParser.Configuration.DefaultDvarValues.Add('g_gametype', '');
rconParser.Configuration.DefaultDvarValues.Add('fs_basepath', '');
rconParser.Configuration.DefaultDvarValues.Add('fs_basegame', '');
rconParser.Configuration.DefaultDvarValues.Add('fs_game', '');
rconParser.Configuration.Status.AddMapping(105, 6); // ip address rconParser.Configuration.Status.AddMapping(105, 6); // ip address
rconParser.Version = '[local] ship win64 CODBUILD8-764 (3421987) Mon Dec 16 10:44:20 2019 10d27bef'; rconParser.Version = '[local] ship win64 CODBUILD8-764 (3421987) Mon Dec 16 10:44:20 2019 10d27bef';
@ -34,7 +42,6 @@ var plugin = {
eventParser.GameName = 8; // BO3 eventParser.GameName = 8; // BO3
eventParser.Configuration.GameDirectory = 'usermaps'; eventParser.Configuration.GameDirectory = 'usermaps';
eventParser.Configuration.Say.Pattern = '^(chat|chatteam);(?:[0-9]+);([0-9]+);([0-9]+);(.+);(.*)$'; eventParser.Configuration.Say.Pattern = '^(chat|chatteam);(?:[0-9]+);([0-9]+);([0-9]+);(.+);(.*)$';
}, },
onUnloadAsync: function () { onUnloadAsync: function () {

View File

@ -3,7 +3,7 @@ var eventParser;
var plugin = { var plugin = {
author: 'RaidMax', author: 'RaidMax',
version: 0.5, version: 0.6,
name: 'Tekno MW3 Parser', name: 'Tekno MW3 Parser',
isParser: true, isParser: true,
@ -27,6 +27,9 @@ var plugin = {
rconParser.Configuration.CommandPrefixes.TempBan = 'tempbanclient {0} "{1}"'; rconParser.Configuration.CommandPrefixes.TempBan = 'tempbanclient {0} "{1}"';
rconParser.Configuration.Dvar.AddMapping(107, 1); // RCon DvarValue rconParser.Configuration.Dvar.AddMapping(107, 1); // RCon DvarValue
rconParser.Configuration.Dvar.Pattern = '^(.*)$'; rconParser.Configuration.Dvar.Pattern = '^(.*)$';
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
rconParser.Version = 'IW5 MP 1.4 build 382 latest Thu Jan 19 2012 11:09:49AM win-x86'; rconParser.Version = 'IW5 MP 1.4 build 382 latest Thu Jan 19 2012 11:09:49AM win-x86';
rconParser.GameName = 3; // IW5 rconParser.GameName = 3; // IW5
rconParser.CanGenerateLogPath = false; rconParser.CanGenerateLogPath = false;

View File

@ -63,8 +63,24 @@ namespace SharedLibraryCore.Interfaces
bool CanGenerateLogPath { get; set; } bool CanGenerateLogPath { get; set; }
/// <summary> /// <summary>
/// Specifies the name of the parser /// specifies the name of the parser
/// </summary> /// </summary>
string Name { get; set; } string Name { get; set; }
/// <summary>
/// retrieves the value of given dvar key if it exists in the override dict
/// otherwise returns original
/// </summary>
/// <param name="dvarName">name of dvar key</param>
/// <returns></returns>
string GetOverrideDvarName(string dvarName);
/// <summary>
/// retrieves the configuration value of a dvar key for
/// games that do not support the given dvar
/// </summary>
/// <param name="dvarName">dvar key name</param>
/// <returns></returns>
T GetDefaultDvarValue<T>(string dvarName);
} }
} }

View File

@ -1,4 +1,5 @@
using SharedLibraryCore.RCon; using SharedLibraryCore.RCon;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
namespace SharedLibraryCore.Interfaces namespace SharedLibraryCore.Interfaces
@ -45,5 +46,16 @@ namespace SharedLibraryCore.Interfaces
/// indicates the format expected for parsed guids /// indicates the format expected for parsed guids
/// </summary> /// </summary>
NumberStyles GuidNumberStyle { get; set; } NumberStyles GuidNumberStyle { get; set; }
/// <summary>
/// specifies simple mappings for dvar names in scenarios where the needed
/// information is not stored in a traditional dvar name
/// </summary>
IDictionary<string, string> OverrideDvarNameMapping { get; set; }
/// <summary>
/// specifies the default dvar values for games that don't support certain dvars
/// </summary>
IDictionary<string, string> DefaultDvarValues { get; set; }
} }
} }

View File

@ -1,4 +1,5 @@
using SharedLibraryCore.Database.Models; 
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using System; using System;
@ -747,7 +748,27 @@ namespace SharedLibraryCore
public static Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName, T fallbackValue = default) public static Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName, T fallbackValue = default)
{ {
return server.RconParser.GetDvarAsync<T>(server.RemoteConnection, dvarName, fallbackValue); return server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName, fallbackValue);
}
public static async Task<Dvar<T>> GetMappedDvarValueOrDefaultAsync<T>(this Server server, string dvarName, string infoResponseName = null, IDictionary<string, string> infoResponse = null)
{
// todo: unit test this
string mappedKey = server.RconParser.GetOverrideDvarName(dvarName);
var defaultValue = server.RconParser.GetDefaultDvarValue<T>(mappedKey);
string foundKey = infoResponse?.Keys.Where(_key => new[] { mappedKey, dvarName, infoResponseName ?? dvarName }.Contains(_key)).FirstOrDefault();
if (!string.IsNullOrEmpty(foundKey))
{
return new Dvar<T>
{
Value = (T)Convert.ChangeType(infoResponse[foundKey], typeof(T)),
Name = foundKey
};
}
return await server.GetDvarAsync(mappedKey, defaultValue);
} }
public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue) public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
@ -944,6 +965,8 @@ namespace SharedLibraryCore
public static bool ShouldHideLevel(this Permission perm) => perm == Permission.Flagged; public static bool ShouldHideLevel(this Permission perm) => perm == Permission.Flagged;
/// <summary> /// <summary>
/// replaces any directory separator chars with the platform specific character /// replaces any directory separator chars with the platform specific character
/// </summary> /// </summary>