adding IW5m parsers
reduce status polling rate adding preliminary russian localization small rcon tweak to attempt to send custom encoded messages removed exception handling in ConvertLong throttled servers will still attempt to execute events
This commit is contained in:
parent
96d6b03cc5
commit
02ef5a0bf8
@ -58,6 +58,9 @@
|
||||
<None Update="Localization\IW4MAdmin.en-US.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Localization\IW4MAdmin.ru-RU.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||
|
@ -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<string, string>();
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<string, string>();
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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<SharedLibraryCore.Localization.Layout>(localizationContents);
|
||||
|
109
Application/Localization/IW4MAdmin.ru-RU.json
Normal file
109
Application/Localization/IW4MAdmin.ru-RU.json
Normal file
@ -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": "Ваш пинг"
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
166
Application/RconParsers/IW5MRConParser.cs
Normal file
166
Application/RconParsers/IW5MRConParser.cs
Normal file
@ -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<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||
{
|
||||
await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command, false);
|
||||
return new string[] { "Command Executed" };
|
||||
}
|
||||
|
||||
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)
|
||||
{
|
||||
// why can't this be real :(
|
||||
if (dvarName == "version")
|
||||
return new Dvar<T>(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<T>(dvarName)
|
||||
{
|
||||
Value = (T)Convert.ChangeType("1.9", typeof(T))
|
||||
};
|
||||
|
||||
if (dvarName == "mapname")
|
||||
return new Dvar<T>(dvarName)
|
||||
{
|
||||
Value = (T)Convert.ChangeType("Unknown", typeof(T))
|
||||
};
|
||||
|
||||
if (dvarName == "g_gametype")
|
||||
return new Dvar<T>(dvarName)
|
||||
{
|
||||
Value = (T)Convert.ChangeType("Unknown", typeof(T))
|
||||
};
|
||||
|
||||
if (dvarName == "fs_game")
|
||||
return new Dvar<T>(dvarName)
|
||||
{
|
||||
Value = (T)Convert.ChangeType("", typeof(T))
|
||||
};
|
||||
|
||||
if (dvarName == "g_logsync")
|
||||
return new Dvar<T>(dvarName)
|
||||
{
|
||||
Value = (T)Convert.ChangeType(1, typeof(T))
|
||||
};
|
||||
|
||||
if (dvarName == "fs_basepath")
|
||||
return new Dvar<T>(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<T>(DvarName)
|
||||
{
|
||||
Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T))
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<List<Player>> GetStatusAsync(Connection connection)
|
||||
{
|
||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
|
||||
return ClientsFromStatus(response);
|
||||
}
|
||||
|
||||
public async Task<bool> 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<Player> ClientsFromStatus(string[] status)
|
||||
{
|
||||
List<Player> StatusPlayers = new List<Player>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -149,7 +149,6 @@ namespace Application.RconParsers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<Player> ClientsFromStatus(string[] status)
|
||||
{
|
||||
List<Player> StatusPlayers = new List<Player>();
|
||||
|
@ -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,6 +422,8 @@ namespace IW4MAdmin
|
||||
|
||||
for (int i = 0; i < CurrentPlayers.Count; i++)
|
||||
{
|
||||
// todo: wait til GUID is included in status to fix this
|
||||
if (GameName != Game.IW5)
|
||||
await AddPlayer(CurrentPlayers[i]);
|
||||
}
|
||||
|
||||
@ -456,6 +458,9 @@ namespace IW4MAdmin
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
// trying to reduce the polling rate as every 450ms is unnecessary
|
||||
if ((DateTime.Now - LastPoll).TotalSeconds >= 10)
|
||||
{
|
||||
int polledPlayerCount = await PollPlayersAsync();
|
||||
|
||||
@ -467,6 +472,7 @@ namespace IW4MAdmin
|
||||
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<string>("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<string>("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 ?
|
||||
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))
|
||||
@ -686,6 +702,23 @@ namespace IW4MAdmin
|
||||
override protected async Task ProcessEvent(GameEvent E)
|
||||
{
|
||||
if (E.Type == GameEvent.EventType.Connect)
|
||||
{
|
||||
// special case for IW5 when connect is from the log
|
||||
if (E.Extra != null)
|
||||
{
|
||||
var logClient = (Player)E.Extra;
|
||||
var client = (await this.GetStatusAsync())
|
||||
.Single(c => c.ClientNumber == logClient.ClientNumber &&
|
||||
c.Name == logClient.Name);
|
||||
client.NetworkId = logClient.NetworkId;
|
||||
|
||||
await AddPlayer(client);
|
||||
|
||||
// hack: to prevent plugins from registering it as a real connect
|
||||
E.Type = GameEvent.EventType.Unknown;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ChatHistory.Add(new ChatInfo()
|
||||
{
|
||||
@ -697,6 +730,7 @@ namespace IW4MAdmin
|
||||
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<string>("g_gametype")).Value.StripColors();
|
||||
Hostname = (await this.GetDvarAsync<string>("sv_hostname")).Value.StripColors();
|
||||
FSGame = (await this.GetDvarAsync<string>("fs_game")).Value.StripColors();
|
||||
var dict = (Dictionary<string, string>)E.Extra;
|
||||
Gametype = dict["g_gametype"].StripColors();
|
||||
Hostname = dict["sv_hostname"].StripColors();
|
||||
|
||||
string mapname = this.GetDvarAsync<string>("mapname").Result.Value;
|
||||
string mapname = dict["mapname"].StripColors();
|
||||
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,17 @@ namespace SharedLibraryCore.Configuration
|
||||
public List<string> Rules { get; set; }
|
||||
public List<string> 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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user