diff --git a/Application/Application.csproj b/Application/Application.csproj
index 8a9554a8b..1b867d24c 100644
--- a/Application/Application.csproj
+++ b/Application/Application.csproj
@@ -58,6 +58,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/Application/EventParsers/IW4EventParser.cs b/Application/EventParsers/IW4EventParser.cs
index 3225514fe..d9cccdfa2 100644
--- a/Application/EventParsers/IW4EventParser.cs
+++ b/Application/EventParsers/IW4EventParser.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using SharedLibraryCore;
@@ -9,7 +10,7 @@ namespace Application.EventParsers
{
class IW4EventParser : IEventParser
{
- public GameEvent GetEvent(Server server, string logLine)
+ public virtual GameEvent GetEvent(Server server, string logLine)
{
string[] lineSplit = logLine.Split(';');
string cleanedEventLine = Regex.Replace(lineSplit[0], @"[0-9]+:[0-9]+\ ", "").Trim();
@@ -73,6 +74,13 @@ namespace Application.EventParsers
if (cleanedEventLine.Contains("InitGame"))
{
+ string dump = cleanedEventLine.Replace("InitGame: ", "");
+ string[] values = dump.Split('\\', StringSplitOptions.RemoveEmptyEntries);
+ var dict = new Dictionary();
+
+ for (int i = 0; i < values.Length; i += 2)
+ dict.Add(values[i], values[i + 1]);
+
return new GameEvent()
{
Type = GameEvent.EventType.MapChange,
@@ -85,7 +93,8 @@ namespace Application.EventParsers
{
ClientId = 1
},
- Owner = server
+ Owner = server,
+ Extra = dict
};
}
diff --git a/Application/EventParsers/IW5EventParser.cs b/Application/EventParsers/IW5EventParser.cs
index da25779ba..de5e97110 100644
--- a/Application/EventParsers/IW5EventParser.cs
+++ b/Application/EventParsers/IW5EventParser.cs
@@ -1,12 +1,53 @@
-using SharedLibraryCore.Interfaces;
+using SharedLibraryCore;
+using SharedLibraryCore.Interfaces;
+using SharedLibraryCore.Objects;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
+using System.Text.RegularExpressions;
namespace Application.EventParsers
{
class IW5EventParser : IW4EventParser
{
- public override string GetGameDir() => "rzodemo";
+ public override string GetGameDir() => "logs";
+
+ public override GameEvent GetEvent(Server server, string logLine)
+ {
+ string cleanedEventLine = Regex.Replace(logLine, @"[0-9]+:[0-9]+\ ", "").Trim();
+
+ if (cleanedEventLine.Contains("J;"))
+ {
+ string[] lineSplit = cleanedEventLine.Split(';');
+
+ int clientNum = Int32.Parse(lineSplit[2]);
+
+ var player = new Player()
+ {
+ NetworkId = lineSplit[1].ConvertLong(),
+ ClientNumber = clientNum,
+ Name = lineSplit[3]
+ };
+
+ return new GameEvent()
+ {
+ Type = GameEvent.EventType.Connect,
+ Origin = new Player()
+ {
+ ClientId = 1
+ },
+ Target = new Player()
+ {
+ ClientId = 1
+ },
+ Owner = server,
+ Extra = player
+ };
+ }
+
+ else
+ return base.GetEvent(server, logLine);
+ }
}
}
diff --git a/Application/EventParsers/T6MEventParser.cs b/Application/EventParsers/T6MEventParser.cs
index 050cf87ca..07b6a4ceb 100644
--- a/Application/EventParsers/T6MEventParser.cs
+++ b/Application/EventParsers/T6MEventParser.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -12,15 +13,15 @@ namespace Application.EventParsers
{
public GameEvent GetEvent(Server server, string logLine)
{
- string cleanedLogLine = Regex.Replace(logLine, @"^ *[0-9]+:[0-9]+ *", "");
- string[] lineSplit = cleanedLogLine.Split(';');
+ string cleanedEventLine = Regex.Replace(logLine, @"^ *[0-9]+:[0-9]+ *", "").Trim();
+ string[] lineSplit = cleanedEventLine.Split(';');
if (lineSplit[0][0] == 'K')
{
return new GameEvent()
{
Type = GameEvent.EventType.Script,
- Data = cleanedLogLine,
+ Data = cleanedEventLine,
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)),
Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
Owner = server
@@ -32,7 +33,7 @@ namespace Application.EventParsers
return new GameEvent()
{
Type = GameEvent.EventType.Damage,
- Data = cleanedLogLine,
+ Data = cleanedEventLine,
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)),
Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
Owner = server
@@ -69,13 +70,15 @@ namespace Application.EventParsers
};
}
- /*if (lineSplit[0].Contains("ShutdownGame"))
- {
-
- }*/
-
if (lineSplit[0].Contains("InitGame"))
{
+ string dump = cleanedEventLine.Replace("InitGame: ", "");
+ string[] values = dump.Split('\\', StringSplitOptions.RemoveEmptyEntries);
+ var dict = new Dictionary();
+
+ for (int i = 0; i < values.Length; i += 2)
+ dict.Add(values[i], values[i + 1]);
+
return new GameEvent()
{
Type = GameEvent.EventType.MapChange,
@@ -88,7 +91,8 @@ namespace Application.EventParsers
{
ClientId = 1
},
- Owner = server
+ Owner = server,
+ Extra = dict
};
}
diff --git a/Application/Localization/Configure.cs b/Application/Localization/Configure.cs
index 3933b8ba3..2badf5bc2 100644
--- a/Application/Localization/Configure.cs
+++ b/Application/Localization/Configure.cs
@@ -12,19 +12,21 @@ namespace IW4MAdmin.Application.Localization
public static void Initialize()
{
string currentLocal = CultureInfo.CurrentCulture.Name;
+#if DEBUG
+ currentLocal = "ru-RU";
+#endif
string localizationFile = $"Localization{Path.DirectorySeparatorChar}IW4MAdmin.{currentLocal}.json";
string localizationContents;
if (File.Exists(localizationFile))
{
- localizationContents = File.ReadAllText(localizationFile);
-
+ localizationContents = File.ReadAllText(localizationFile, Encoding.UTF8);
}
else
{
localizationFile = $"Localization{Path.DirectorySeparatorChar}IW4MAdmin.en-US.json";
- localizationContents = File.ReadAllText(localizationFile);
+ localizationContents = File.ReadAllText(localizationFile, Encoding.UTF8);
}
Utilities.CurrentLocalization = Newtonsoft.Json.JsonConvert.DeserializeObject(localizationContents);
diff --git a/Application/Localization/IW4MAdmin.ru-RU.json b/Application/Localization/IW4MAdmin.ru-RU.json
new file mode 100644
index 000000000..01b5f9663
--- /dev/null
+++ b/Application/Localization/IW4MAdmin.ru-RU.json
@@ -0,0 +1,109 @@
+{
+ "LocalizationName": "ru-RU",
+ "LocalizationSet": {
+ "MANAGER_VERSION_FAIL": "Не удалось получить последнюю версию IW4MAdmin",
+ "MANAGER_VERSION_UPDATE": "имеет обновление. Последняя версия",
+ "MANAGER_VERSION_CURRENT": "Ваша версия",
+ "MANAGER_VERSION_SUCCESS": "IW4MAdmin обновлен",
+ "MANAGER_INIT_FAIL": "Неустранимая ошибка при инициализации",
+ "MANAGER_EXIT": "Нажмите любую клавишу чтобы выйти ...",
+ "SETUP_ENABLE_WEBFRONT": "Включить веб-интерфейс",
+ "SETUP_ENABLE_MULTIOWN": "Включить поддержку нескольких владельцев",
+ "SETUP_ENABLE_STEPPEDPRIV": "Включить последовательную иерархию прав",
+ "SETUP_ENABLE_CUSTOMSAY": "Включить серверное имя для чата",
+ "SETUP_SAY_NAME": "Введите серверное имя для чата",
+ "SETUP_USE_CUSTOMENCODING": "Использовать иную кодировку текста",
+ "SETUP_ENCODING_STRING": "Введите желаемую кодировку",
+ "SETUP_ENABLE_VPNS": "Разрешить игрокам подключаться с VPN",
+ "SETUP_IPHUB_KEY": "Введите iphub.info api-ключ",
+ "SETUP_DISPLAY_DISCORD": "Отображать ссылку на Discord в веб-интерфейсе",
+ "SETUP_DISCORD_INVITE": "Введите ссылку-приглашение в Discord",
+ "SETUP_SERVER_USET6M": "Использовать T6M парсер для Black Ops 2",
+ "SETUP_SERVER_IP": "Введите IP-адрес сервера",
+ "SETUP_SERVER_PORT": "введите порт сервера",
+ "SETUP_SERVER_RCON": "Введите RCon пароль сервера",
+ "SETUP_SERVER_SAVE": "Конфигурация сохранена, добавить еще?",
+ "SERVER_KICK_VPNS_NOTALLOWED": "Использование VPN не разрешено на этом сервере",
+ "SERVER_KICK_TEXT": "Вы исключены",
+ "SERVER_KICK_MINNAME": "Ваше имя должно содержать хотя бы 3 символа",
+ "SERVER_KICK_NAME_INUSE": "Ваше имя используется кем-то другим",
+ "SERVER_KICK_GENERICNAME": "Пожалуйста, смените ваше имя, используя /name",
+ "SERVER_KICK_CONTROLCHARS": "Ваше имя не должно содержать спецсимволы",
+ "SERVER_TB_TEXT": "Вы временно забанены",
+ "SERVER_TB_REMAIN": "Вы временно забанены",
+ "SERVER_BAN_TEXT": "Вы забанены",
+ "SERVER_BAN_PREV": "Ранее забанены за",
+ "SERVER_BAN_APPEAL": "оспорить:",
+ "SERVER_REPORT_COUNT": "Имеется ^5{0} ^7жалоб за последнее время",
+ "SERVER_WARNLIMT_REACHED": "Слишком много предупреждений",
+ "SERVER_WARNING": "предупреждение",
+ "SERVER_WEBSITE_GENERIC": "веб-сайт этого сервера",
+ "BROADCAST_ONLINE": "^5IW4MADMIN ^7сейчас ^2ОНЛАЙН",
+ "BROADCAST_OFFLINE": "IW4MAdmin отключается",
+ "COMMAND_HELP_SYNTAX": "синтаксис:",
+ "COMMAND_HELP_OPTIONAL": "опционально",
+ "COMMAND_UNKNOWN": "Вы ввели неизвестную команду",
+ "COMMAND_NOACCESS": "У вас нет доступа к этой команде",
+ "COMMAND_NOTAUTHORIZED": "У вас нет разрешения выполнить эту команду",
+ "COMMAND_MISSINGARGS": "Приведено недостаточно аргументов",
+ "COMMAND_TARGET_MULTI": "Это имя использует не один игрок",
+ "COMMAND_TARGET_NOTFOUND": "Невозможно найти указанного игрока",
+ "PLUGIN_IMPORTER_NOTFOUND": "Нет загружаемых плагинов",
+ "PLUGIN_IMPORTER_REGISTERCMD": "Зарегистрированная команда",
+ "COMMANDS_OWNER_SUCCESS": "Поздравляем, Вы стали владельцем этого сервера!",
+ "COMMANDS_OWNER_FAIL": "Этот сервер уже имеет владельца",
+ "COMMANDS_WARN_FAIL": "У вас недостаточно прав чтобы предупреждать!",
+ "COMMANDS_WARNCLEAR_SUCCESS": "Все предупреждения очищены за",
+ "COMMANDS_KICK_SUCCESS": "был исключен",
+ "COMMANDS_KICK_FAIL": "У вас недостаточно прав чтобы исключать!",
+ "COMMANDS_TEMPBAN_SUCCESS": "был временно забанен за",
+ "COMMANDS_TEMPBAN_FAIL": "Вы не можете временно банить!",
+ "COMMANDS_BAN_SUCCESS": "был забанен навсегда",
+ "COMMANDS_BAN_FAIL": "Вы не можете банить!",
+ "COMMANDS_UNBAN_SUCCESS": "Успешно разбанен",
+ "COMMANDS_UNBAN_FAIL": "не забанен",
+ "COMMANDS_HELP_NOTFOUND": "Не удалось найти эту команду",
+ "COMMANDS_HELP_MOREINFO": "Введите !help <имя команды>, чтобы узнать синтаксис команды",
+ "COMMANDS_FASTRESTART_UNMASKED": "перезапуск карты",
+ "COMMANDS_FASTRESTART_MASKED": "Карта перезапущена",
+ "COMMANDS_MAPROTATE": "Смена карты через ^55 ^7секунд",
+ "COMMANDS_SETLEVEL_SELF": "Вы не можете изменить свой уровень",
+ "COMMANDS_SETLEVEL_OWNER": "Возможен только 1 владелец. Включите возможность нескольких владельцев!",
+ "COMMANDS_SETLEVEL_STEPPEDDISABLED": "Этот сервер не разрешает вам повыситься",
+ "COMMANDS_SETLEVEL_LEVELTOOHIGH": "Вы только можете повысить ^5{0} ^7до ^5{1} ^7или понизиться в правах",
+ "COMMANDS_SETLEVEL_SUCCESS_TARGET": "Поздравляем! Вы были повышены до",
+ "COMMANDS_SETLEVEL_SUCCESS": "был успешно повышен",
+ "COMMANDS_SETLEVEL_FAIL": "Указана неверная группа",
+ "COMMANDS_ADMINS_NONE": "Нет администраторов в сети",
+ "COMMANDS_MAP_SUCCESS": "Смена карты на",
+ "COMMANDS_MAP_UKN": "Попытка сменить на неизвестную карту",
+ "COMMANDS_FIND_MIN": "Пожалуйста, введите хотя бы 3 символа",
+ "COMMANDS_FIND_EMPTY": "Не найдено игроков",
+ "COMMANDS_RULES_NONE": "Владелец сервера не установил никаких правил",
+ "COMMANDS_FLAG_SUCCESS": "Вы были отмечены",
+ "COMMANDS_FLAG_UNFLAG": "С вас сняли отметку",
+ "COMMANDS_FLAG_FAIL": "Вы не можете ставить отметки",
+ "COMMANDS_REPORT_FAIL_CAMP": "Вы не можете пожаловаться на игрока за кемперство",
+ "COMMANDS_REPORT_FAIL_DUPLICATE": "Вы уже пожаловались на этого игрока",
+ "COMMANDS_REPORT_FAIL_SELF": "Вы не можете пожаловаться на самого себя",
+ "COMMANDS_REPORT_FAIL": "Вы не можете пожаловаться",
+ "COMMANDS_REPORT_SUCCESS": "Спасибо за вашу жалобу, администратор оповещен",
+ "COMMANDS_REPORTS_CLEAR_SUCCESS": "Жалобы полностью очищены",
+ "COMMANDS_REPORTS_NONE": "Пока нет жалоб на игроков",
+ "COMMANDS_MASK_ON": "Вы замаскированы",
+ "COMMANDS_MASK_OFF": "Маскировка снята",
+ "COMMANDS_BANINFO_NONE": "Нет активного запрета для этого игрока",
+ "COMMANDS_BANINO_SUCCESS": "был забанен ^5{0} ^7на:",
+ "COMMANDS_ALIAS_ALIASES": "Псевдонимы",
+ "COMMANDS_ALIAS_IPS": "IP",
+ "COMMANDS_RCON_SUCCESS": " RCon команда успешно отправлена",
+ "COMMANDS_PLUGINS_LOADED": "Загруженные плагины",
+ "COMMANDS_IP_SUCCESS": "Ваш внешний IP-адрес",
+ "COMMANDS_PRUNE_FAIL": "Недопустимое количество неактивных дней",
+ "COMMANDS_PRUNE_SUCCESS": "неактивные привилегированные пользователи были разжалованы",
+ "COMMANDS_PASSWORD_FAIL": "Ваш пароль должен содержать не менее 5 символов",
+ "COMMANDS_PASSWORD_SUCCESS": "Ваш пароль успешно установлен",
+ "COMMANDS_PING_TARGET": "пинг",
+ "COMMANDS_PING_SELF": "Ваш пинг"
+ }
+}
\ No newline at end of file
diff --git a/Application/Main.cs b/Application/Main.cs
index 3e3d3650e..a4209269b 100644
--- a/Application/Main.cs
+++ b/Application/Main.cs
@@ -6,6 +6,8 @@ using System.Reflection;
using SharedLibraryCore;
using SharedLibraryCore.Objects;
using SharedLibraryCore.Database;
+using System.Text;
+using System.Threading;
namespace IW4MAdmin.Application
{
@@ -21,8 +23,10 @@ namespace IW4MAdmin.Application
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal;
Localization.Configure.Initialize();
var loc = Utilities.CurrentLocalization.LocalizationSet;
+ Console.OutputEncoding = Encoding.UTF8;
Version = Assembly.GetExecutingAssembly().GetName().Version.Major + Assembly.GetExecutingAssembly().GetName().Version.Minor / 10.0f;
+ Version = Math.Round(Version, 2);
Console.WriteLine("=====================================================");
Console.WriteLine(" IW4M ADMIN");
diff --git a/Application/RconParsers/IW5MRConParser.cs b/Application/RconParsers/IW5MRConParser.cs
new file mode 100644
index 000000000..31a88fc61
--- /dev/null
+++ b/Application/RconParsers/IW5MRConParser.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+using SharedLibraryCore;
+using SharedLibraryCore.Interfaces;
+using SharedLibraryCore.Objects;
+using SharedLibraryCore.RCon;
+using SharedLibraryCore.Exceptions;
+using System.Text;
+using System.Linq;
+using System.Net.Http;
+
+namespace Application.RconParsers
+{
+ public class IW5MRConParser : IRConParser
+ {
+ private static CommandPrefix Prefixes = new CommandPrefix()
+ {
+ Tell = "tell {0} {1}",
+ Say = "say {0}",
+ Kick = "dropClient {0} \"{1}\"",
+ Ban = "dropClient {0} \"{1}\"",
+ TempBan = "dropClient {0} \"{1}\""
+ };
+
+ public CommandPrefix GetCommandPrefixes() => Prefixes;
+
+ public async Task ExecuteCommandAsync(Connection connection, string command)
+ {
+ await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command, false);
+ return new string[] { "Command Executed" };
+ }
+
+ public async Task> GetDvarAsync(Connection connection, string dvarName)
+ {
+ // why can't this be real :(
+ if (dvarName == "version")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType("IW5 MP 1.9 build 461 Fri Sep 14 00:04:28 2012 win-x86", typeof(T))
+ };
+
+ if (dvarName == "shortversion")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType("1.9", typeof(T))
+ };
+
+ if (dvarName == "mapname")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType("Unknown", typeof(T))
+ };
+
+ if (dvarName == "g_gametype")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType("Unknown", typeof(T))
+ };
+
+ if (dvarName == "fs_game")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType("", typeof(T))
+ };
+
+ if (dvarName == "g_logsync")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType(1, typeof(T))
+ };
+
+ if (dvarName == "fs_basepath")
+ return new Dvar(dvarName)
+ {
+ Value = (T)Convert.ChangeType("", typeof(T))
+ };
+
+
+
+ string[] LineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.DVAR, dvarName);
+
+ if (LineSplit.Length < 4)
+ {
+ var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
+ e.Data["dvar_name"] = dvarName;
+ throw e;
+ }
+
+ string[] ValueSplit = LineSplit[1].Split(new char[] { '"' });
+
+ if (ValueSplit.Length == 0)
+ {
+ var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
+ e.Data["dvar_name"] = dvarName;
+ throw e;
+ }
+
+ string DvarName = dvarName;
+ string DvarCurrentValue = Regex.Replace(ValueSplit[3].StripColors(), @"\^[0-9]", "");
+
+ return new Dvar(DvarName)
+ {
+ Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T))
+ };
+ }
+
+ public async Task> GetStatusAsync(Connection connection)
+ {
+ string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
+ return ClientsFromStatus(response);
+ }
+
+ public async Task SetDvarAsync(Connection connection, string dvarName, object dvarValue)
+ {
+ // T6M doesn't respond with anything when a value is set, so we can only hope for the best :c
+ await connection.SendQueryAsync(StaticHelpers.QueryType.DVAR, $"set {dvarName} {dvarValue}", false);
+ return true;
+ }
+
+ private List ClientsFromStatus(string[] status)
+ {
+ List StatusPlayers = new List();
+
+ foreach (string statusLine in status)
+ {
+ String responseLine = statusLine;
+
+ if (Regex.Matches(responseLine, @"^ *\d+", RegexOptions.IgnoreCase).Count > 0) // its a client line!
+ {
+ String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+
+ // this happens when the client is in a zombie state
+ if (playerInfo.Length < 5)
+ continue;
+ int clientId = -1;
+ int Ping = -1;
+
+ Int32.TryParse(playerInfo[2], out Ping);
+ string name = Encoding.UTF8.GetString(Encoding.Convert(Utilities.EncodingType, Encoding.UTF8, Utilities.EncodingType.GetBytes(responseLine.Substring(23, 15).StripColors().Trim())));
+ long networkId = playerInfo[4].ConvertLong();
+ int.TryParse(playerInfo[0], out clientId);
+ var regex = Regex.Match(responseLine, @"\d+\.\d+\.\d+.\d+\:\d{1,5}");
+ int ipAddress = regex.Value.Split(':')[0].ConvertToIP();
+ regex = Regex.Match(responseLine, @" +(\d+ +){3}");
+ int score = Int32.Parse(regex.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0]);
+
+ StatusPlayers.Add(new Player()
+ {
+ Name = name,
+ NetworkId = networkId,
+ ClientNumber = clientId,
+ IPAddress = ipAddress,
+ Ping = Ping,
+ Score = score,
+ IsBot = networkId < 1
+ });
+ }
+ }
+
+ return StatusPlayers;
+ }
+ }
+}
diff --git a/Application/RconParsers/T6MRConParser.cs b/Application/RconParsers/T6MRConParser.cs
index 0bbdb58b4..54204830f 100644
--- a/Application/RconParsers/T6MRConParser.cs
+++ b/Application/RconParsers/T6MRConParser.cs
@@ -149,7 +149,6 @@ namespace Application.RconParsers
}
}
-
private List ClientsFromStatus(string[] status)
{
List StatusPlayers = new List();
diff --git a/Application/Server.cs b/Application/Server.cs
index bb3dd07cc..7eca0373b 100644
--- a/Application/Server.cs
+++ b/Application/Server.cs
@@ -51,8 +51,8 @@ namespace IW4MAdmin
override public async Task AddPlayer(Player polledPlayer)
{
- if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot)||
- polledPlayer.Ping < 1 || polledPlayer.ClientNumber > (MaxClients) ||
+ if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
+ polledPlayer.Ping < 1 || polledPlayer.ClientNumber > (MaxClients) ||
polledPlayer.ClientNumber < 0)
{
//Logger.WriteDebug($"Skipping client not in connected state {P}");
@@ -360,8 +360,8 @@ namespace IW4MAdmin
public override async Task ExecuteEvent(GameEvent E)
{
- if (Throttled)
- return;
+ //if (Throttled)
+ // return;
await ProcessEvent(E);
Manager.GetEventApi().OnServerEvent(this, E);
@@ -422,7 +422,9 @@ namespace IW4MAdmin
for (int i = 0; i < CurrentPlayers.Count; i++)
{
- await AddPlayer(CurrentPlayers[i]);
+ // todo: wait til GUID is included in status to fix this
+ if (GameName != Game.IW5)
+ await AddPlayer(CurrentPlayers[i]);
}
return CurrentPlayers.Count;
@@ -457,15 +459,19 @@ namespace IW4MAdmin
try
{
- int polledPlayerCount = await PollPlayersAsync();
-
- if (ConnectionErrors > 0)
+ // trying to reduce the polling rate as every 450ms is unnecessary
+ if ((DateTime.Now - LastPoll).TotalSeconds >= 10)
{
- Logger.WriteVerbose($"Connection has been reestablished with {IP}:{Port}");
- Throttled = false;
+ int polledPlayerCount = await PollPlayersAsync();
+
+ if (ConnectionErrors > 0)
+ {
+ Logger.WriteVerbose($"Connection has been reestablished with {IP}:{Port}");
+ Throttled = false;
+ }
+ ConnectionErrors = 0;
+ LastPoll = DateTime.Now;
}
- ConnectionErrors = 0;
- LastPoll = DateTime.Now;
}
catch (NetworkException e)
@@ -587,6 +593,8 @@ namespace IW4MAdmin
public async Task Initialize()
{
RconParser = ServerConfig.UseT6MParser ? (IRConParser)new T6MRConParser() : new IW4RConParser();
+ if (ServerConfig.UseIW5MParser)
+ RconParser = new IW5MRConParser();
var version = await this.GetDvarAsync("version");
GameName = Utilities.GetGame(version.Value);
@@ -632,9 +640,9 @@ namespace IW4MAdmin
this.CurrentMap = Maps.Find(m => m.Name == mapname.Value) ?? new Map() { Alias = mapname.Value, Name = mapname.Value };
this.MaxClients = maxplayers.Value;
this.FSGame = game.Value;
- this.Gametype = (await this.GetDvarAsync("g_gametype")).Value;
+ this.Gametype = gametype.Value;
- await this.SetDvarAsync("sv_kickbantime", 60);
+ //wait this.SetDvarAsync("sv_kickbantime", 60);
if (logsync.Value == 0 || logfile.Value == string.Empty)
{
@@ -650,11 +658,19 @@ namespace IW4MAdmin
CustomCallback = await ScriptLoaded();
string mainPath = EventParser.GetGameDir();
#if DEBUG
- basepath.Value = @"\\192.168.88.253\Call of Duty Black Ops II";
+ // basepath.Value = @"\\192.168.88.253\Call of Duty Black Ops II";
#endif
- string logPath = game.Value == string.Empty ?
- $"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile.Value}" :
- $"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Value.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}";
+ string logPath;
+ if (GameName == Game.IW5)
+ {
+ logPath = ServerConfig.ManualLogPath;
+ }
+ else
+ {
+ logPath = game.Value == string.Empty ?
+ $"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile.Value}" :
+ $"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Value.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}";
+ }
// hopefully fix wine drive name mangling
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -676,7 +692,7 @@ namespace IW4MAdmin
Logger.WriteInfo($"Log file is {logPath}");
#if DEBUG
- // LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php");
+ // LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php");
#else
await Broadcast(loc["BROADCAST_ONLINE"]);
#endif
@@ -687,15 +703,33 @@ namespace IW4MAdmin
{
if (E.Type == GameEvent.EventType.Connect)
{
- ChatHistory.Add(new ChatInfo()
+ // special case for IW5 when connect is from the log
+ if (E.Extra != null)
{
- Name = E.Origin.Name,
- Message = "CONNECTED",
- Time = DateTime.UtcNow
- });
+ var logClient = (Player)E.Extra;
+ var client = (await this.GetStatusAsync())
+ .Single(c => c.ClientNumber == logClient.ClientNumber &&
+ c.Name == logClient.Name);
+ client.NetworkId = logClient.NetworkId;
- if (E.Origin.Level > Player.Permission.Moderator)
- await E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
+ await AddPlayer(client);
+
+ // hack: to prevent plugins from registering it as a real connect
+ E.Type = GameEvent.EventType.Unknown;
+ }
+
+ else
+ {
+ ChatHistory.Add(new ChatInfo()
+ {
+ Name = E.Origin.Name,
+ Message = "CONNECTED",
+ Time = DateTime.UtcNow
+ });
+
+ if (E.Origin.Level > Player.Permission.Moderator)
+ await E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
+ }
}
else if (E.Type == GameEvent.EventType.Disconnect)
@@ -790,11 +824,11 @@ namespace IW4MAdmin
{
Logger.WriteInfo($"New map loaded - {ClientNum} active players");
- Gametype = (await this.GetDvarAsync("g_gametype")).Value.StripColors();
- Hostname = (await this.GetDvarAsync("sv_hostname")).Value.StripColors();
- FSGame = (await this.GetDvarAsync("fs_game")).Value.StripColors();
+ var dict = (Dictionary)E.Extra;
+ Gametype = dict["g_gametype"].StripColors();
+ Hostname = dict["sv_hostname"].StripColors();
- string mapname = this.GetDvarAsync("mapname").Result.Value;
+ string mapname = dict["mapname"].StripColors();
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
}
diff --git a/SharedLibraryCore/Configuration/ServerConfiguration.cs b/SharedLibraryCore/Configuration/ServerConfiguration.cs
index f8d456fd7..4edd1c5c2 100644
--- a/SharedLibraryCore/Configuration/ServerConfiguration.cs
+++ b/SharedLibraryCore/Configuration/ServerConfiguration.cs
@@ -11,10 +11,17 @@ namespace SharedLibraryCore.Configuration
public List Rules { get; set; }
public List AutoMessages { get; set; }
public bool UseT6MParser { get; set; }
+ public bool UseIW5MParser { get; set; }
+ public string ManualLogPath { get; set; }
public IBaseConfiguration Generate()
{
UseT6MParser = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationSet["SETUP_SERVER_USET6M"]);
+ if (!UseT6MParser)
+ UseIW5MParser = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationSet["SETUP_SERVER_USEIW5M"]);
+ if (UseIW5MParser)
+ ManualLogPath = Utilities.PromptString(Utilities.CurrentLocalization.LocalizationSet["SETUP_SERVER_MANUALLOG"]);
+
return this;
}
diff --git a/SharedLibraryCore/RCon/Connection.cs b/SharedLibraryCore/RCon/Connection.cs
index 9d1e8c6fb..1644d387b 100644
--- a/SharedLibraryCore/RCon/Connection.cs
+++ b/SharedLibraryCore/RCon/Connection.cs
@@ -172,19 +172,23 @@ namespace SharedLibraryCore.RCon
OnSent.Reset();
OnReceived.Reset();
string queryString = "";
+ byte[] payload = null;
switch (type)
{
case StaticHelpers.QueryType.DVAR:
case StaticHelpers.QueryType.COMMAND:
- queryString = $"ÿÿÿÿrcon {RConPassword} {parameters}";
+ var header = "ÿÿÿÿrcon ".Select(Convert.ToByte).ToList();
+ byte[] p = Utilities.EncodingType.GetBytes($"{RConPassword} {parameters}");
+ header.AddRange(p);
+ payload = header.ToArray();
break;
case StaticHelpers.QueryType.GET_STATUS:
- queryString = "ÿÿÿÿgetstatus";
+ payload = "ÿÿÿÿgetstatus".Select(Convert.ToByte).ToArray();
break;
}
- byte[] payload = queryString.Select(Convert.ToByte).ToArray();
+ // byte[] payload = Utilities.EncodingType.GetBytes(queryString); // queryString.Select(Convert.ToByte).ToArray();
retrySend:
try
diff --git a/SharedLibraryCore/Server.cs b/SharedLibraryCore/Server.cs
index 9df932c8b..ede04b296 100644
--- a/SharedLibraryCore/Server.cs
+++ b/SharedLibraryCore/Server.cs
@@ -290,8 +290,8 @@ namespace SharedLibraryCore
// Info
public string Hostname { get; protected set; }
public string Website { get; protected set; }
- public string Gametype { get; protected set; }
- public Map CurrentMap { get; protected set; }
+ public string Gametype { get; set; }
+ public Map CurrentMap { get; set; }
public int ClientNum
{
get
diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs
index d2d113799..f051c02c9 100644
--- a/SharedLibraryCore/Utilities.cs
+++ b/SharedLibraryCore/Utilities.cs
@@ -9,6 +9,7 @@ using static SharedLibraryCore.Server;
using System.Reflection;
using System.IO;
using System.Threading.Tasks;
+using System.Globalization;
namespace SharedLibraryCore
{
@@ -181,16 +182,8 @@ namespace SharedLibraryCore
public static long ConvertLong(this string str)
{
- try
- {
- return Int64.Parse(str, System.Globalization.NumberStyles.HexNumber);
- }
-
-
- catch (FormatException)
- {
- return -1;
- }
+ Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id);
+ return id;
}
public static int ConvertToIP(this string str)