fix reading PT6 having signed decimal GUID in log
fix alternative encoding character converting allow more paths for game log server add localization for unknown ips in welcome plugin add gamelog server uri to support game log server on games that must supply manual log path misc fixes
This commit is contained in:
parent
7c6419a16a
commit
dea5b3f954
@ -6,7 +6,7 @@
|
||||
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
|
||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
||||
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
||||
<Version>2.2.4.6</Version>
|
||||
<Version>2.2.4.7</Version>
|
||||
<Authors>RaidMax</Authors>
|
||||
<Company>Forever None</Company>
|
||||
<Product>IW4MAdmin</Product>
|
||||
@ -31,8 +31,8 @@
|
||||
<PropertyGroup>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<AssemblyVersion>2.2.4.6</AssemblyVersion>
|
||||
<FileVersion>2.2.4.6</FileVersion>
|
||||
<AssemblyVersion>2.2.4.7</AssemblyVersion>
|
||||
<FileVersion>2.2.4.7</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -286,6 +286,8 @@ namespace IW4MAdmin.Application
|
||||
|
||||
foreach (var serverConfig in config.Servers)
|
||||
{
|
||||
Migration.ConfigurationMigration.ModifyLogPath020919(serverConfig);
|
||||
|
||||
if (serverConfig.RConParserVersion == null || serverConfig.EventParserVersion == null)
|
||||
{
|
||||
foreach (var parser in AdditionalRConParsers)
|
||||
@ -299,8 +301,8 @@ namespace IW4MAdmin.Application
|
||||
}
|
||||
|
||||
serverConfig.ModifyParsers();
|
||||
await ConfigHandler.Save();
|
||||
}
|
||||
await ConfigHandler.Save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,26 +17,26 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
GameDirectory = "main",
|
||||
};
|
||||
|
||||
Configuration.Say.Pattern = @"^(say|sayteam);(.{8,32});([0-9]+);(.+);(.*)$";
|
||||
Configuration.Say.Pattern = @"^(say|sayteam);(-?[A-Fa-f0-9_]{8,32});([0-9]+);(.+);(.*)$";
|
||||
Configuration.Say.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
||||
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||
Configuration.Say.AddMapping(ParserRegex.GroupType.Message, 5);
|
||||
|
||||
Configuration.Quit.Pattern = @"^(Q);(.{8,32}|bot[0-9]+);([0-9]+);(.*)$";
|
||||
Configuration.Quit.Pattern = @"^(Q);(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+);([0-9]+);(.*)$";
|
||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||
|
||||
Configuration.Join.Pattern = @"^(J);(.{8,32}|bot[0-9]+);([0-9]+);(.*)$";
|
||||
Configuration.Join.Pattern = @"^(J);(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+);([0-9]+);(.*)$";
|
||||
Configuration.Join.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||
|
||||
Configuration.Damage.Pattern = @"^(D);([A-Fa-f0-9_]{8,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});([A-Fa-f0-9_]{8,32}|bot[0-9]+)?;-?([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_]{8,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world);(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
||||
@ -51,7 +51,7 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
||||
|
||||
Configuration.Kill.Pattern = @"^(K);([A-Fa-f0-9_]{8,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});([A-Fa-f0-9_]{8,32}|bot[0-9]+)?;-?([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_]{8,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world);(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
||||
|
@ -19,19 +19,10 @@ namespace IW4MAdmin.Application.IO
|
||||
public string ServerId { get; set; }
|
||||
}
|
||||
|
||||
public GameLogEventDetection(Server server, string gameLogPath, string gameLogName)
|
||||
public GameLogEventDetection(Server server, string gameLogPath, Uri gameLogServerUri)
|
||||
{
|
||||
GameLogFile = gameLogPath;
|
||||
// todo: abtract this more
|
||||
if (gameLogPath.StartsWith("http"))
|
||||
{
|
||||
Reader = new GameLogReaderHttp(gameLogPath, server.EventParser);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reader = new GameLogReader(gameLogPath, server.EventParser);
|
||||
}
|
||||
|
||||
Reader = gameLogServerUri != null ? new GameLogReaderHttp(gameLogServerUri, gameLogPath, server.EventParser) : Reader = new GameLogReader(gameLogPath, server.EventParser);
|
||||
Server = server;
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,13 @@ namespace IW4MAdmin.Application.IO
|
||||
{
|
||||
readonly IEventParser Parser;
|
||||
readonly IGameLogServer Api;
|
||||
readonly string LogFile;
|
||||
readonly string logPath;
|
||||
|
||||
public GameLogReaderHttp(string logFile, IEventParser parser)
|
||||
public GameLogReaderHttp(Uri gameLogServerUri, string logPath, IEventParser parser)
|
||||
{
|
||||
LogFile = logFile;
|
||||
this.logPath = logPath.ToBase64UrlSafeString(); ;
|
||||
Parser = parser;
|
||||
Api = RestClient.For<IGameLogServer>(logFile);
|
||||
Api = RestClient.For<IGameLogServer>(gameLogServerUri);
|
||||
}
|
||||
|
||||
public long Length => -1;
|
||||
@ -36,12 +36,12 @@ namespace IW4MAdmin.Application.IO
|
||||
server.Logger.WriteDebug($"Begin reading from http log");
|
||||
#endif
|
||||
var events = new List<GameEvent>();
|
||||
string b64Path = server.LogPath.ToBase64UrlSafeString();
|
||||
string b64Path = logPath;
|
||||
var response = await Api.Log(b64Path);
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
server.Logger.WriteError($"Could not get log server info of {LogFile}/{b64Path} ({server.LogPath})");
|
||||
server.Logger.WriteError($"Could not get log server info of {logPath}/{b64Path} ({server.LogPath})");
|
||||
return events;
|
||||
}
|
||||
|
||||
|
@ -750,47 +750,36 @@ namespace IW4MAdmin
|
||||
}
|
||||
|
||||
CustomCallback = await ScriptLoaded();
|
||||
string mainPath = EventParser.Configuration.GameDirectory;
|
||||
string logPath = string.Empty;
|
||||
|
||||
LogPath = string.IsNullOrEmpty(game) ?
|
||||
$"{basepath?.Value?.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile?.Value}" :
|
||||
$"{basepath?.Value?.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game?.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile?.Value}";
|
||||
|
||||
bool remoteLog = false;
|
||||
if (GameName == Game.IW5 || ServerConfig.ManualLogPath?.Length > 0)
|
||||
|
||||
// they've manually specified the log path
|
||||
if (!string.IsNullOrEmpty(ServerConfig.ManualLogPath))
|
||||
{
|
||||
logPath = ServerConfig.ManualLogPath;
|
||||
remoteLog = logPath.StartsWith("http");
|
||||
}
|
||||
else
|
||||
{
|
||||
logPath = LogPath;
|
||||
}
|
||||
|
||||
if (remoteLog)
|
||||
{
|
||||
LogEvent = new GameLogEventDetection(this, logPath, logfile.Value);
|
||||
LogPath = ServerConfig.ManualLogPath;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
string mainPath = EventParser.Configuration.GameDirectory;
|
||||
|
||||
LogPath = string.IsNullOrEmpty(game) ?
|
||||
$"{basepath?.Value?.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile?.Value}" :
|
||||
$"{basepath?.Value?.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game?.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile?.Value}";
|
||||
|
||||
// fix wine drive name mangling
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
logPath = Regex.Replace($"{Path.DirectorySeparatorChar}{LogPath}", @"[A-Z]:/", "");
|
||||
LogPath = Regex.Replace($"{Path.DirectorySeparatorChar}{LogPath}", @"[A-Z]:/", "");
|
||||
}
|
||||
|
||||
if (!File.Exists(logPath))
|
||||
if (!File.Exists(LogPath))
|
||||
{
|
||||
Logger.WriteError($"{logPath} {loc["SERVER_ERROR_DNE"]}");
|
||||
throw new ServerException($"{loc["SERVER_ERROR_LOG"]} {logPath}");
|
||||
Logger.WriteError($"{LogPath} {loc["SERVER_ERROR_DNE"]}");
|
||||
throw new ServerException($"{loc["SERVER_ERROR_LOG"]} {LogPath}");
|
||||
}
|
||||
|
||||
LogEvent = new GameLogEventDetection(this, logPath, logfile.Value);
|
||||
}
|
||||
|
||||
Logger.WriteInfo($"Log file is {logPath}");
|
||||
LogEvent = new GameLogEventDetection(this, LogPath, ServerConfig.GameLogServerUrl);
|
||||
Logger.WriteInfo($"Log file is {LogPath}");
|
||||
|
||||
_ = Task.Run(() => LogEvent.PollForChanges());
|
||||
#if !DEBUG
|
||||
|
@ -56,5 +56,14 @@ namespace IW4MAdmin.Application.Migration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ModifyLogPath020919(SharedLibraryCore.Configuration.ServerConfiguration config)
|
||||
{
|
||||
if (config.ManualLogPath.IsRemoteLog())
|
||||
{
|
||||
config.GameLogServerUrl = new Uri(config.ManualLogPath);
|
||||
config.ManualLogPath = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
|
||||
public async Task<List<EFClient>> GetStatusAsync(Connection connection)
|
||||
{
|
||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
|
||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
||||
return ClientsFromStatus(response);
|
||||
}
|
||||
|
||||
|
@ -11,13 +11,15 @@
|
||||
<SearchPath>
|
||||
</SearchPath>
|
||||
<WorkingDirectory>.</WorkingDirectory>
|
||||
<LaunchProvider>Web launcher</LaunchProvider>
|
||||
<LaunchProvider>Standard Python launcher</LaunchProvider>
|
||||
<WebBrowserUrl>http://localhost</WebBrowserUrl>
|
||||
<OutputPath>.</OutputPath>
|
||||
<SuppressCollectPythonCloudServiceFiles>true</SuppressCollectPythonCloudServiceFiles>
|
||||
<Name>GameLogServer</Name>
|
||||
<RootNamespace>GameLogServer</RootNamespace>
|
||||
<InterpreterId>MSBuild|env|$(MSBuildProjectFullPath)</InterpreterId>
|
||||
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
|
||||
<Environment>DEBUG=True</Environment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -15,7 +15,7 @@ class LogReader(object):
|
||||
if re.search('r^.+\.\.\\.+$', path):
|
||||
return False
|
||||
# must be a valid log path and log file
|
||||
if not re.search(r'^.+[\\|\/](userraw|mods|main)[\\|\/].+.log$', path):
|
||||
if not re.search(r'^.+[\\|\/](.+)[\\|\/].+.log$', path):
|
||||
return False
|
||||
# set the initialze size to the current file size
|
||||
file_size = 0
|
||||
|
@ -139,13 +139,14 @@ namespace IW4MAdmin.Plugins.Welcome
|
||||
{
|
||||
string response = await wc.DownloadStringTaskAsync(new Uri($"http://extreme-ip-lookup.com/json/{ip}"));
|
||||
var responseObj = JObject.Parse(response);
|
||||
response = responseObj["country"].ToString();
|
||||
|
||||
return responseObj["country"].ToString();
|
||||
return string.IsNullOrEmpty(response) ? Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_COUNTRY"] : response;
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
return "a third world country";
|
||||
return Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_IP"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ namespace SharedLibraryCore.Configuration
|
||||
public string RConParserVersion { get; set; }
|
||||
public string EventParserVersion { get; set; }
|
||||
public int ReservedSlotNumber { get; set; }
|
||||
public Uri GameLogServerUrl { get; set; }
|
||||
|
||||
private readonly IList<IRConParser> rconParsers;
|
||||
private readonly IList<IEventParser> eventParsers;
|
||||
|
@ -78,16 +78,14 @@ namespace SharedLibraryCore.RCon
|
||||
byte[] payload = null;
|
||||
bool waitForResponse = Config.WaitForResponse;
|
||||
|
||||
string converterEncoding(string text)
|
||||
{
|
||||
var destinationEncoding = Encoding.GetEncoding("windows-1252");
|
||||
byte[] originalEncodedBytes = Utilities.EncodingType.GetBytes(text);
|
||||
byte[] convertedBytes = Encoding.Convert(Utilities.EncodingType, destinationEncoding, originalEncodedBytes);
|
||||
return destinationEncoding.GetString(convertedBytes);
|
||||
string convertEncoding(string text)
|
||||
{
|
||||
byte[] convertedBytes = Utilities.EncodingType.GetBytes(text);
|
||||
return Utilities.EncodingType.GetString(convertedBytes);
|
||||
}
|
||||
|
||||
string convertedRConPassword = converterEncoding(RConPassword);
|
||||
string convertedParameters = converterEncoding(parameters);
|
||||
string convertedRConPassword = convertEncoding(RConPassword);
|
||||
string convertedParameters = convertEncoding(parameters);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -109,6 +107,10 @@ namespace SharedLibraryCore.RCon
|
||||
waitForResponse |= true;
|
||||
payload = (Config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.COMMAND_STATUS:
|
||||
waitForResponse |= true;
|
||||
payload = string.Format(Config.CommandPrefixes.RConCommand, convertedRConPassword, "status\0").Select(Convert.ToByte).ToArray();
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] response = null;
|
||||
|
@ -35,6 +35,11 @@ namespace SharedLibraryCore.RCon
|
||||
/// RCon password is required
|
||||
/// </summary>
|
||||
COMMAND,
|
||||
/// <summary>
|
||||
/// get the full server command information
|
||||
/// RCon password is required
|
||||
/// </summary>
|
||||
COMMAND_STATUS
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -266,11 +266,16 @@ namespace SharedLibraryCore
|
||||
public static long ConvertLong(this string str)
|
||||
{
|
||||
str = str.Substring(0, Math.Min(str.Length, 16));
|
||||
if (Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id))
|
||||
if (long.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
if (long.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
|
||||
{
|
||||
return (uint)id;
|
||||
}
|
||||
|
||||
var bot = Regex.Match(str, @"bot[0-9]+").Value;
|
||||
if (!string.IsNullOrEmpty(bot))
|
||||
{
|
||||
@ -640,6 +645,13 @@ namespace SharedLibraryCore
|
||||
return cmdLine.Length > 1 ? cmdLine[1] : cmdLine[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// indicates if the given log path is a remote (http) uri
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsRemoteLog(this string log) => (log ?? "").StartsWith("http");
|
||||
|
||||
public static string ToBase64UrlSafeString(this string src)
|
||||
{
|
||||
return Convert.ToBase64String(src.Select(c => Convert.ToByte(c)).ToArray()).Replace('+', '-').Replace('/', '_');
|
||||
|
Loading…
Reference in New Issue
Block a user