updated portuguese translation

fixed issue with locale when no config present
changed kick color on webfront
aliased owner to iamgod (for b3 familiar users)
hopefully fixed stats issue
added T5M (V2 BO2) support
made dvar grab at beginning minimal to prevent throttling on older CODS
This commit is contained in:
RaidMax 2018-04-26 19:19:42 -05:00
parent b6c979beba
commit 2c2c442ba7
14 changed files with 124 additions and 71 deletions

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace IW4MAdmin.Application.EventParsers
{
class T5MEventParser : IW4EventParser
{
public override string GetGameDir() => "v2";
}
}

View File

@ -11,8 +11,8 @@ namespace IW4MAdmin.Application.Localization
{ {
public static void Initialize() public static void Initialize()
{ {
string currentLocale = Program.ServerManager.GetApplicationSettings().Configuration().CustomLocale ?? string currentLocale = Program.ServerManager.GetApplicationSettings().Configuration()?.CustomLocale ??
CultureInfo.CurrentCulture.Name?.Substring(0, 2); CultureInfo.CurrentCulture?.Name?.Substring(0, 2);
if (currentLocale == null) if (currentLocale == null)
throw new Exception("Computer CurrentCulture does not exist"); throw new Exception("Computer CurrentCulture does not exist");

View File

@ -1,9 +1,8 @@
// translated by Daniel aka Vou te comer {
{
"LocalizationName": "pt-BR", "LocalizationName": "pt-BR",
"LocalizationSet": { "LocalizationSet": {
"MANAGER_VERSION_FAIL": "Não foi possível obter a versão mais recente do IW4MAdmin", "MANAGER_VERSION_FAIL": "Não foi possível obter a versão mais recente do IW4MAdmin",
"MANAGER_VERSION_UPDATE": "Tem uma atualização. A versão mais recente é", "MANAGER_VERSION_UPDATE": "Há uma atualização disponível. A versão mais recente é",
"MANAGER_VERSION_CURRENT": "Está é a sua versão", "MANAGER_VERSION_CURRENT": "Está é a sua versão",
"MANAGER_VERSION_SUCCESS": "O IW4MAdmin está atualizado", "MANAGER_VERSION_SUCCESS": "O IW4MAdmin está atualizado",
"MANAGER_INIT_FAIL": "Erro fatal durante a inicialização", "MANAGER_INIT_FAIL": "Erro fatal durante a inicialização",
@ -12,7 +11,7 @@
"MANAGER_MONITORING_TEXT": "Agora monitorando", "MANAGER_MONITORING_TEXT": "Agora monitorando",
"MANAGER_CONNECTION_REST": "A conexão foi reestabelecida com", "MANAGER_CONNECTION_REST": "A conexão foi reestabelecida com",
"SETUP_ENABLE_WEBFRONT": "Habilitar o módulo da web do IW4MAdmin", "SETUP_ENABLE_WEBFRONT": "Habilitar o módulo da web do IW4MAdmin",
"SETUP_ENABLE_MULTIOWN": "Ativar vários propietários", "SETUP_ENABLE_MULTIOWN": "Ativar vários proprietários",
"SETUP_ENABLE_STEPPEDPRIV": "Ativar hierarquia de privilégios escalonada", "SETUP_ENABLE_STEPPEDPRIV": "Ativar hierarquia de privilégios escalonada",
"SETUP_ENABLE_CUSTOMSAY": "Habilitar a customização do nome do comando say", "SETUP_ENABLE_CUSTOMSAY": "Habilitar a customização do nome do comando say",
"SETUP_SAY_NAME": "Digite o nome customizado do comando say", "SETUP_SAY_NAME": "Digite o nome customizado do comando say",
@ -39,10 +38,10 @@
"SERVER_ERROR_PLUGIN": "Ocorreu um erro ao carregar o plug-in", "SERVER_ERROR_PLUGIN": "Ocorreu um erro ao carregar o plug-in",
"SERVER_ERROR_ADDPLAYER": "Não foi possível adicionar o jogador", "SERVER_ERROR_ADDPLAYER": "Não foi possível adicionar o jogador",
"SERVER_ERROR_POLLING": "reduzir a taxa de sondagem do server", "SERVER_ERROR_POLLING": "reduzir a taxa de sondagem do server",
"SERVER_ERROR_COMMUNICATION": "Não foi possivel fazer a comunicação com", "SERVER_ERROR_COMMUNICATION": "Não foi possível fazer a comunicação com",
"SERVER_ERROR_EXCEPTION": "Exceção inesperada em", "SERVER_ERROR_EXCEPTION": "Exceção inesperada em",
"SERVER_KICK_VPNS_NOTALLOWED": "VPNs não são permitidas neste servidor", "SERVER_KICK_VPNS_NOTALLOWED": "VPNs não são permitidas neste servidor",
"SERVER_KICK_TEXT": "Você foi expluso", "SERVER_KICK_TEXT": "Você foi expulso",
"SERVER_KICK_MINNAME": "Seu nome deve conter no mínimo três caracteres", "SERVER_KICK_MINNAME": "Seu nome deve conter no mínimo três caracteres",
"SERVER_KICK_NAME_INUSE": "Seu nome já está sendo usado por outra pessoa", "SERVER_KICK_NAME_INUSE": "Seu nome já está sendo usado por outra pessoa",
"SERVER_KICK_GENERICNAME": "Por favor, mude o seu nome usando o comando /name no console", "SERVER_KICK_GENERICNAME": "Por favor, mude o seu nome usando o comando /name no console",
@ -83,9 +82,9 @@
"COMMANDS_HELP_NOTFOUND": "Não foi possível encontrar esse comando", "COMMANDS_HELP_NOTFOUND": "Não foi possível encontrar esse comando",
"COMMANDS_HELP_MOREINFO": "Digite !help <comando> para saber como usar o comando", "COMMANDS_HELP_MOREINFO": "Digite !help <comando> para saber como usar o comando",
"COMMANDS_FASTRESTART_UNMASKED": "reiniciou rapidamente o mapa", "COMMANDS_FASTRESTART_UNMASKED": "reiniciou rapidamente o mapa",
"COMMANDS_FASTRESTART_MASKED": "O mapa foi reniciado rapidamente", "COMMANDS_FASTRESTART_MASKED": "O mapa foi reiniciado rapidamente",
"COMMANDS_MAPROTATE": "Rotacionando o mapa em ^55 ^7segundos", "COMMANDS_MAPROTATE": "Rotacionando o mapa em ^55 ^7segundos",
"COMMANDS_SETLEVEL_SELF": "Você não pode mudar seu própio nível", "COMMANDS_SETLEVEL_SELF": "Você não pode mudar seu próprio nível",
"COMMANDS_SETLEVEL_OWNER": "Só pode haver 1 dono. Modifique suas configurações se vários proprietários forem necessários", "COMMANDS_SETLEVEL_OWNER": "Só pode haver 1 dono. Modifique suas configurações se vários proprietários forem necessários",
"COMMANDS_SETLEVEL_STEPPEDDISABLED": "Este servidor não permite que você promova", "COMMANDS_SETLEVEL_STEPPEDDISABLED": "Este servidor não permite que você promova",
"COMMANDS_SETLEVEL_LEVELTOOHIGH": "Você só pode promover do ^5{0} ^7para ^5{1} ^7ou um nível menor", "COMMANDS_SETLEVEL_LEVELTOOHIGH": "Você só pode promover do ^5{0} ^7para ^5{1} ^7ou um nível menor",
@ -109,9 +108,9 @@
"COMMANDS_REPORTS_CLEAR_SUCCESS": "Lista de denúncias limpa com sucesso", "COMMANDS_REPORTS_CLEAR_SUCCESS": "Lista de denúncias limpa com sucesso",
"COMMANDS_REPORTS_NONE": "Ninguém foi denunciado ainda", "COMMANDS_REPORTS_NONE": "Ninguém foi denunciado ainda",
"COMMANDS_MASK_ON": "Você foi mascarado", "COMMANDS_MASK_ON": "Você foi mascarado",
"COMMANDS_MASK_OFF": "Você foi desmarcarado", "COMMANDS_MASK_OFF": "Você foi desmascarado",
"COMMANDS_BANINFO_NONE": "Nenhum banimento ativo foi encontrado para esse jogador", "COMMANDS_BANINFO_NONE": "Nenhum banimento ativo foi encontrado para esse jogador",
"COMMANDS_BANINO_SUCCESS": "foi bannido por ^5{0} ^7por:", "COMMANDS_BANINO_SUCCESS": "foi banido por ^5{0} ^7por:",
"COMMANDS_ALIAS_ALIASES": "Nomes registrados", "COMMANDS_ALIAS_ALIASES": "Nomes registrados",
"COMMANDS_ALIAS_IPS": "IPs", "COMMANDS_ALIAS_IPS": "IPs",
"COMMANDS_RCON_SUCCESS": "O comando para o RCon foi enviado com sucesso", "COMMANDS_RCON_SUCCESS": "O comando para o RCon foi enviado com sucesso",
@ -135,7 +134,7 @@
"COMMANDS_WHO_DESC": "dá informações sobre você", "COMMANDS_WHO_DESC": "dá informações sobre você",
"COMMANDS_LIST_DESC": "lista os jogadores ativos na partida", "COMMANDS_LIST_DESC": "lista os jogadores ativos na partida",
"COMMANDS_HELP_DESC": "lista todos os comandos disponíveis", "COMMANDS_HELP_DESC": "lista todos os comandos disponíveis",
"COMMANDS_FASTRESTART_DESC": "renincializa rapidamente o mapa, não recomendável o uso várias vezes seguidas", "COMMANDS_FASTRESTART_DESC": "reinicializa rapidamente o mapa, não recomendável o uso várias vezes seguidas",
"COMMANDS_MAPROTATE_DESC": "avança para o próximo mapa da rotação", "COMMANDS_MAPROTATE_DESC": "avança para o próximo mapa da rotação",
"COMMANDS_SETLEVEL_DESC": "define o jogador para o nível de privilégio especificado", "COMMANDS_SETLEVEL_DESC": "define o jogador para o nível de privilégio especificado",
"COMMANDS_USAGE_DESC": "vê quanto o aplicativo está usando de memória ram do seu computador", "COMMANDS_USAGE_DESC": "vê quanto o aplicativo está usando de memória ram do seu computador",
@ -164,7 +163,7 @@
"COMMANDS_ARGS_MESSAGE": "mensagem", "COMMANDS_ARGS_MESSAGE": "mensagem",
"COMMANDS_ARGS_DURATION": "duração (minutos|horas|dias|semanas|anos)", "COMMANDS_ARGS_DURATION": "duração (minutos|horas|dias|semanas|anos)",
"COMMANDS_ARGS_CLIENTID": "id do jogador", "COMMANDS_ARGS_CLIENTID": "id do jogador",
"COMMANDS_ARGS_COMMANDS": "commandos", "COMMANDS_ARGS_COMMANDS": "comandos",
"COMMANDS_ARGS_LEVEL": "nível", "COMMANDS_ARGS_LEVEL": "nível",
"COMMANDS_ARGS_MAP": "mapa", "COMMANDS_ARGS_MAP": "mapa",
"COMMANDS_ARGS_CLEAR": "limpar", "COMMANDS_ARGS_CLEAR": "limpar",
@ -175,7 +174,7 @@
"PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Sua senha está errada", "PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Sua senha está errada",
"PLUGINS_STATS_COMMANDS_RESET_DESC": "reinicia suas estatísticas para uma nova", "PLUGINS_STATS_COMMANDS_RESET_DESC": "reinicia suas estatísticas para uma nova",
"PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Suas estatísticas nesse servidor foram reiniciadas", "PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Suas estatísticas nesse servidor foram reiniciadas",
"PLUGINS_STATS_COMMANDS_RESET_FAIL": "Você deve estar connectado a um servidor para reiniciar as suas estatísticas", "PLUGINS_STATS_COMMANDS_RESET_FAIL": "Você deve estar conectado a um servidor para reiniciar as suas estatísticas",
"PLUGINS_STATS_COMMANDS_VIEW_DESC": "mostra suas estatísticas", "PLUGINS_STATS_COMMANDS_VIEW_DESC": "mostra suas estatísticas",
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "o jogador especificado deve estar jogando", "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "o jogador especificado deve estar jogando",
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Você deve estar no jogo para ver suas estatísticas", "PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Você deve estar no jogo para ver suas estatísticas",

View File

@ -41,7 +41,7 @@ namespace IW4MAdmin.Application
ServerManager = ApplicationManager.GetInstance(); ServerManager = ApplicationManager.GetInstance();
using (var db = new DatabaseContext(ServerManager.GetApplicationSettings().Configuration().ConnectionString)) using (var db = new DatabaseContext(ServerManager.GetApplicationSettings().Configuration()?.ConnectionString))
new ContextSeed(db).Seed().Wait(); new ContextSeed(db).Seed().Wait();
var api = API.Master.Endpoint.Get(); var api = API.Master.Endpoint.Get();

View File

@ -92,10 +92,14 @@ namespace IW4MAdmin.Application
public void UpdateStatus(object state) public void UpdateStatus(object state)
{ {
var taskList = new List<Task>();
foreach (var server in Servers) foreach (var server in Servers)
{ {
Task.Run(() => server.ProcessUpdatesAsync(new CancellationToken())); taskList.Add(Task.Run(() => server.ProcessUpdatesAsync(new CancellationToken())));
} }
Task.WaitAll(taskList.ToArray());
} }
public async Task Init() public async Task Init()

View File

@ -183,9 +183,10 @@ namespace IW4MAdmin
Logger.WriteInfo($"Client {player} connecting..."); Logger.WriteInfo($"Client {player} connecting...");
var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this);
Manager.GetEventHandler().AddEvent(e);
Manager.GetEventHandler().AddEvent(new GameEvent(GameEvent.EventType.Connect, "", player, null, this)); e.OnProcessed.Wait();
if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs && if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey)) await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey))
@ -212,7 +213,9 @@ namespace IW4MAdmin
Player Leaving = Players[cNum]; Player Leaving = Players[cNum];
Logger.WriteInfo($"Client {Leaving} disconnecting..."); Logger.WriteInfo($"Client {Leaving} disconnecting...");
Manager.GetEventHandler().AddEvent(new GameEvent(GameEvent.EventType.Disconnect, "", Leaving, null, this)); var e = new GameEvent(GameEvent.EventType.Disconnect, "", Leaving, null, this);
Manager.GetEventHandler().AddEvent(e);
e.OnProcessed.Wait();
Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds; Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds;
Leaving.LastConnection = DateTime.UtcNow; Leaving.LastConnection = DateTime.UtcNow;
@ -697,6 +700,7 @@ namespace IW4MAdmin
if (ServerConfig.UseIW5MParser) if (ServerConfig.UseIW5MParser)
RconParser = new IW5MRConParser(); RconParser = new IW5MRConParser();
var version = await this.GetDvarAsync<string>("version"); var version = await this.GetDvarAsync<string>("version");
GameName = Utilities.GetGame(version.Value); GameName = Utilities.GetGame(version.Value);
@ -704,26 +708,41 @@ namespace IW4MAdmin
EventParser = new IW4EventParser(); EventParser = new IW4EventParser();
else if (GameName == Game.IW5) else if (GameName == Game.IW5)
EventParser = new IW5EventParser(); EventParser = new IW5EventParser();
else if (GameName == Game.T5M)
EventParser = new T5MEventParser();
else if (GameName == Game.T6M) else if (GameName == Game.T6M)
EventParser = new T6MEventParser(); EventParser = new T6MEventParser();
else if (GameName == Game.UKN)
Logger.WriteWarning($"Game name not recognized: {version}");
else else
EventParser = new IW3EventParser(); // this uses the 'main' folder for log paths EventParser = new IW3EventParser(); // this uses the 'main' folder for log paths
var shortversion = await this.GetDvarAsync<string>("shortversion"); if (GameName == Game.UKN)
var hostname = await this.GetDvarAsync<string>("sv_hostname"); Logger.WriteWarning($"Game name not recognized: {version}");
var mapname = await this.GetDvarAsync<string>("mapname");
var maxplayers = (GameName == Game.IW4) ? // gotta love IW4 idiosyncrasies var infoResponse = await this.GetInfoAsync();
await this.GetDvarAsync<int>("party_maxplayers") : // this is normally slow, but I'm only doing it because different games have different prefixes
await this.GetDvarAsync<int>("sv_maxclients"); var hostname = infoResponse == null ?
var gametype = await this.GetDvarAsync<string>("g_gametype"); (await this.GetDvarAsync<string>("sv_hostname")).Value :
infoResponse.Where(kvp => kvp.Key.Contains("hostname")).Select(kvp => kvp.Value).First();
var mapname = infoResponse == null ?
(await this.GetDvarAsync<string>("mapname")).Value :
infoResponse["mapname"];
int maxplayers = (GameName == Game.IW4) ? // gotta love IW4 idiosyncrasies
(await this.GetDvarAsync<int>("party_maxplayers")).Value :
infoResponse == null ?
(await this.GetDvarAsync<int>("sv_maxclients")).Value :
Convert.ToInt32(infoResponse["sv_maxclients"]);
var gametype = infoResponse == null ?
(await this.GetDvarAsync<string>("g_gametype")).Value :
infoResponse.Where(kvp => kvp.Key.Contains("gametype")).Select(kvp => kvp.Value).First();
var basepath = await this.GetDvarAsync<string>("fs_basepath"); var basepath = await this.GetDvarAsync<string>("fs_basepath");
WorkingDirectory = basepath.Value; var game = infoResponse == null || !infoResponse.ContainsKey("fs_game") ?
var game = await this.GetDvarAsync<string>("fs_game"); (await this.GetDvarAsync<string>("fs_game")).Value :
infoResponse["fs_game"];
var logfile = await this.GetDvarAsync<string>("g_log"); var logfile = await this.GetDvarAsync<string>("g_log");
var logsync = await this.GetDvarAsync<int>("g_logsync"); var logsync = await this.GetDvarAsync<int>("g_logsync");
WorkingDirectory = basepath.Value;
try try
{ {
var website = await this.GetDvarAsync<string>("_website"); var website = await this.GetDvarAsync<string>("_website");
@ -737,11 +756,11 @@ namespace IW4MAdmin
InitializeMaps(); InitializeMaps();
this.Hostname = hostname.Value.StripColors(); this.Hostname = hostname.StripColors();
this.CurrentMap = Maps.Find(m => m.Name == mapname.Value) ?? new Map() { Alias = mapname.Value, Name = mapname.Value }; this.CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
this.MaxClients = maxplayers.Value; this.MaxClients = maxplayers;
this.FSGame = game.Value; this.FSGame = game;
this.Gametype = gametype.Value; this.Gametype = gametype;
//wait this.SetDvarAsync("sv_kickbantime", 60); //wait this.SetDvarAsync("sv_kickbantime", 60);
@ -759,7 +778,7 @@ namespace IW4MAdmin
CustomCallback = await ScriptLoaded(); CustomCallback = await ScriptLoaded();
string mainPath = EventParser.GetGameDir(); string mainPath = EventParser.GetGameDir();
#if DEBUG #if DEBUG
basepath.Value = @"\\192.168.88.253\mw2\"; basepath.Value = @"\\192.168.88.253\Call of Duty 4\";
#endif #endif
string logPath; string logPath;
if (GameName == Game.IW5) if (GameName == Game.IW5)
@ -768,9 +787,9 @@ namespace IW4MAdmin
} }
else else
{ {
logPath = game.Value == string.Empty ? logPath = game == string.Empty ?
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile.Value}" : $"{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}"; $"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}";
} }
@ -789,10 +808,9 @@ namespace IW4MAdmin
} }
else else
{ {
// LogFile = new IFile(logPath); LogEvent = new GameLogEvent(this, logPath, logfile.Value);
} }
LogEvent = new GameLogEvent(this, logPath, logfile.Value);
Logger.WriteInfo($"Log file is {logPath}"); Logger.WriteInfo($"Log file is {logPath}");
#if DEBUG #if DEBUG
// LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php"); // LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php");

View File

@ -84,7 +84,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
/// <returns>EFClientStatistic of specified player</returns> /// <returns>EFClientStatistic of specified player</returns>
public async Task<EFClientStatistics> AddPlayer(Player pl) public async Task<EFClientStatistics> AddPlayer(Player pl)
{ {
Log.WriteInfo($"Adding {pl} to stats");
int serverId = pl.CurrentServer.GetHashCode(); int serverId = pl.CurrentServer.GetHashCode();
if (!Servers.ContainsKey(serverId)) if (!Servers.ContainsKey(serverId))
@ -95,6 +94,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
var playerStats = Servers[serverId].PlayerStats; var playerStats = Servers[serverId].PlayerStats;
var statsSvc = ContextThreads[serverId]; var statsSvc = ContextThreads[serverId];
var detectionStats = Servers[serverId].PlayerDetections;
if (playerStats.ContainsKey(pl.ClientId))
{
Log.WriteWarning($"Duplicate ClientId in stats {pl.ClientId}");
return null;
}
// get the client's stats from the database if it exists, otherwise create and attach a new one // get the client's stats from the database if it exists, otherwise create and attach a new one
// if this fails we want to throw an exception // if this fails we want to throw an exception
@ -142,19 +148,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
clientStats.LastStatCalculation = DateTime.UtcNow; clientStats.LastStatCalculation = DateTime.UtcNow;
clientStats.SessionScore = pl.Score; clientStats.SessionScore = pl.Score;
if (playerStats.ContainsKey(pl.ClientId)) Log.WriteInfo($"Adding {pl} to stats");
{
Log.WriteWarning($"Duplicate ClientId in stats {pl.ClientId} vs {playerStats[pl.ClientId].ClientId}");
playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue);
}
playerStats.TryAdd(pl.ClientId, clientStats);
var detectionStats = Servers[serverId].PlayerDetections; if (!playerStats.TryAdd(pl.ClientId, clientStats))
Log.WriteDebug($"Could not add client to stats {pl}");
if (detectionStats.ContainsKey(pl.ClientId)) if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)))
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue); Log.WriteDebug("Could not add client to detection");
detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats));
// todo: look at this more // todo: look at this more
statsSvc.ClientStatSvc.Update(clientStats); statsSvc.ClientStatSvc.Update(clientStats);
@ -181,6 +182,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
if (!playerStats.ContainsKey(pl.ClientId)) if (!playerStats.ContainsKey(pl.ClientId))
{ {
Log.WriteWarning($"Client disconnecting not in stats {pl}"); Log.WriteWarning($"Client disconnecting not in stats {pl}");
// remove the client from the stats dictionary as they're leaving
playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue1);
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue2);
return; return;
} }
@ -188,9 +192,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
var clientStats = playerStats[pl.ClientId]; var clientStats = playerStats[pl.ClientId];
// sync their score // sync their score
clientStats.SessionScore += (pl.Score - clientStats.LastScore); clientStats.SessionScore += (pl.Score - clientStats.LastScore);
// remove the client from the stats dictionary as they're leaving // remove the client from the stats dictionary as they're leaving
playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue); playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue3);
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue2); detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue4);
// sync their stats before they leave // sync their stats before they leave
clientStats = UpdateStats(clientStats); clientStats = UpdateStats(clientStats);

View File

@ -27,7 +27,7 @@ namespace SharedLibraryCore.Commands
public class COwner : Command public class COwner : Command
{ {
public COwner() : public COwner() :
base("owner", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_DESC"], "o", Player.Permission.User, false) base("owner", Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_DESC"], "iamgod", Player.Permission.User, false)
{ } { }
public override async Task ExecuteAsync(GameEvent E) public override async Task ExecuteAsync(GameEvent E)

View File

@ -163,9 +163,9 @@ namespace SharedLibraryCore.RCon
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", bool waitForResponse = true) public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", bool waitForResponse = true)
{ {
// will this really prevent flooding? // will this really prevent flooding?
if ((DateTime.Now - LastQuery).TotalMilliseconds < 35) if ((DateTime.Now - LastQuery).TotalMilliseconds < 150)
{ {
await Task.Delay(35); await Task.Delay(150);
} }
LastQuery = DateTime.Now; LastQuery = DateTime.Now;

View File

@ -13,6 +13,6 @@ namespace SharedLibraryCore.RCon
} }
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier); public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 10); public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 2);
} }
} }

View File

@ -109,10 +109,7 @@ namespace SharedLibraryCore
/// <returns></returns> /// <returns></returns>
abstract public Task<Command> ValidateCommand(GameEvent E); abstract public Task<Command> ValidateCommand(GameEvent E);
virtual public Task<bool> ProcessUpdatesAsync(CancellationToken cts) virtual public Task<bool> ProcessUpdatesAsync(CancellationToken cts) => (Task<bool>)Task.CompletedTask;
{
return null;
}
/// <summary> /// <summary>
/// Process any server event /// Process any server event

View File

@ -7,6 +7,7 @@ using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Objects;
namespace SharedLibraryCore.Services namespace SharedLibraryCore.Services
{ {
@ -135,16 +136,17 @@ namespace SharedLibraryCore.Services
{ {
if (victim) if (victim)
{ {
context.ChangeTracker.AutoDetectChangesEnabled = false;
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var iqPenalties = from penalty in context.Penalties.AsNoTracking() var iqPenalties = from penalty in context.Penalties.AsNoTracking()
where penalty.OffenderId == clientId where penalty.OffenderId == clientId
join victimClient in context.Clients.AsNoTracking() join victimClient in context.Clients.AsNoTracking()
on penalty.OffenderId equals victimClient.ClientId on penalty.OffenderId equals victimClient.ClientId
join victimAlias in context.Aliases join victimAlias in context.Aliases.AsNoTracking()
on victimClient.CurrentAliasId equals victimAlias.AliasId on victimClient.CurrentAliasId equals victimAlias.AliasId
join punisherClient in context.Clients join punisherClient in context.Clients.AsNoTracking()
on penalty.PunisherId equals punisherClient.ClientId on penalty.PunisherId equals punisherClient.ClientId
join punisherAlias in context.Aliases join punisherAlias in context.Aliases.AsNoTracking()
on punisherClient.CurrentAliasId equals punisherAlias.AliasId on punisherClient.CurrentAliasId equals punisherAlias.AliasId
//orderby penalty.When descending //orderby penalty.When descending
select new ProfileMeta() select new ProfileMeta()
@ -170,6 +172,9 @@ namespace SharedLibraryCore.Services
var pi = ((PenaltyInfo)p.Value); var pi = ((PenaltyInfo)p.Value);
if (pi.TimeRemaining.Length > 0) if (pi.TimeRemaining.Length > 0)
pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText(); pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText();
// todo: why does this have to be done?
if (pi.Type.Length > 2)
pi.Type = ((Penalty.PenaltyType)Convert.ToInt32(pi.Type)).ToString();
} }
); );
return list; return list;
@ -203,7 +208,16 @@ namespace SharedLibraryCore.Services
When = penalty.When When = penalty.When
}; };
// fixme: is this good and fast? // fixme: is this good and fast?
return await iqPenalties.ToListAsync(); var list = await iqPenalties.ToListAsync();
list.ForEach(p =>
{
// todo: why does this have to be done?
if (((PenaltyInfo)p.Value).Type.Length < 2)
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
});
return list;
} }

View File

@ -84,7 +84,10 @@
color: white; color: white;
} }
.penalties-color-kick, .penalties-color-kick {
color: rgb(182, 129, 43);
}
.penalties-color-unban { .penalties-color-unban {
color: #749363; color: #749363;
color: rgba(116, 147, 99, 1); color: rgba(116, 147, 99, 1);

View File

@ -2,6 +2,8 @@ Version 2.1:
CHANGELOG: CHANGELOG:
-add support for localization -add support for localization
-upgraded projects to .NET Core 2.0.7 -upgraded projects to .NET Core 2.0.7
-redid the event system to haev a single line of execution
-added support for MySQL provider via "ConnectrionString"
Version 2.0: Version 2.0:
CHANGELOG: CHANGELOG: