More stats polishing

fixed player specification for commands with multiple words
This commit is contained in:
RaidMax 2018-02-09 01:21:25 -06:00
parent f929e606f4
commit b9900707b5
17 changed files with 240 additions and 61 deletions

View File

@ -1,5 +1,4 @@
 
#define USINGMEMORY
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SharedLibrary; using SharedLibrary;

View File

@ -199,6 +199,12 @@ namespace IW4MAdmin
var Status = TaskStatuses[i]; var Status = TaskStatuses[i];
if (Status.RequestedTask == null || Status.RequestedTask.Status == TaskStatus.RanToCompletion) if (Status.RequestedTask == null || Status.RequestedTask.Status == TaskStatus.RanToCompletion)
{ {
if (Status.ElapsedMillisecondsTime() > 60000)
{
Logger.WriteWarning($"Task took longer than 60 seconds to complete, killing");
//Status.RequestedTask.
}
Status.Update(new Task<bool>(() => { return (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken()).Result; })); Status.Update(new Task<bool>(() => { return (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken()).Result; }));
if (Status.RunAverage > 1000 + UPDATE_FREQUENCY) if (Status.RunAverage > 1000 + UPDATE_FREQUENCY)
Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server)} [{Status.RunAverage}ms]"); Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server)} [{Status.RunAverage}ms]");

View File

@ -34,6 +34,7 @@ namespace IW4MAdmin
{ {
// update their ping // update their ping
Players[polledPlayer.ClientNumber].Ping = polledPlayer.Ping; Players[polledPlayer.ClientNumber].Ping = polledPlayer.Ping;
Players[polledPlayer.ClientNumber].Score = polledPlayer.Score;
return true; return true;
} }
@ -112,6 +113,7 @@ namespace IW4MAdmin
// NewPlayer.Level = Player.Permission.Flagged; // NewPlayer.Level = Player.Permission.Flagged;
// Do the player specific stuff // Do the player specific stuff
player.ClientNumber = polledPlayer.ClientNumber; player.ClientNumber = polledPlayer.ClientNumber;
player.Score = polledPlayer.Score;
Players[player.ClientNumber] = player; Players[player.ClientNumber] = player;
Logger.WriteInfo($"Client {player} connecting..."); Logger.WriteInfo($"Client {player} connecting...");
@ -210,7 +212,15 @@ namespace IW4MAdmin
if (C.RequiresTarget || Args.Length > 0) if (C.RequiresTarget || Args.Length > 0)
{ {
int cNum = -1; int cNum = -1;
int.TryParse(Args[0], out cNum); try
{
cNum = Convert.ToInt32(Args[0]);
}
catch(FormatException)
{
}
if (Args[0][0] == '@') // user specifying target by database ID if (Args[0][0] == '@') // user specifying target by database ID
{ {
@ -227,7 +237,7 @@ namespace IW4MAdmin
} }
} }
else if (Args[0].Length < 3 && cNum > -1 && cNum < 18) // user specifying target by client num else if (Args[0].Length < 3 && cNum > -1 && cNum < MaxClients) // user specifying target by client num
{ {
if (Players[cNum] != null) if (Players[cNum] != null)
{ {
@ -250,6 +260,13 @@ namespace IW4MAdmin
{ {
E.Target = matchingPlayers.First(); E.Target = matchingPlayers.First();
E.Data = Regex.Replace(E.Data, $"\"{E.Target.Name}\"", "", RegexOptions.IgnoreCase).Trim(); E.Data = Regex.Replace(E.Data, $"\"{E.Target.Name}\"", "", RegexOptions.IgnoreCase).Trim();
if (E.Data.ToLower().Trim() == E.Target.Name.ToLower().Trim())
{
await E.Origin.Tell($"Not enough arguments supplied!");
await E.Origin.Tell(C.Syntax);
throw new SharedLibrary.Exceptions.CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
}
} }
} }
@ -267,6 +284,13 @@ namespace IW4MAdmin
{ {
E.Target = matchingPlayers.First(); E.Target = matchingPlayers.First();
E.Data = Regex.Replace(E.Data, $"{E.Target.Name}", "", RegexOptions.IgnoreCase).Trim(); E.Data = Regex.Replace(E.Data, $"{E.Target.Name}", "", RegexOptions.IgnoreCase).Trim();
if (E.Data.Trim() == E.Target.Name.ToLower().Trim())
{
await E.Origin.Tell($"Not enough arguments supplied!");
await E.Origin.Tell(C.Syntax);
throw new SharedLibrary.Exceptions.CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
}
} }
} }

Binary file not shown.

View File

@ -11,11 +11,13 @@ namespace StatsPlugin.Helpers
public class ServerStats public class ServerStats
{ {
public Dictionary<int, EFClientStatistics> PlayerStats { get; set; } public Dictionary<int, EFClientStatistics> PlayerStats { get; set; }
public EFServerStatistics ServerStatistics { get; private set; }
public EFServer Server { get; private set; } public EFServer Server { get; private set; }
public ServerStats(EFServer sv) public ServerStats(EFServer sv, EFServerStatistics st)
{ {
PlayerStats = new Dictionary<int, EFClientStatistics>(); PlayerStats = new Dictionary<int, EFClientStatistics>();
ServerStatistics = st;
Server = sv; Server = sv;
} }
} }

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using SharedLibrary; using SharedLibrary;
using SharedLibrary.Helpers; using SharedLibrary.Helpers;
@ -19,7 +18,8 @@ namespace StatsPlugin.Helpers
private IManager Manager; private IManager Manager;
private GenericRepository<EFClientStatistics> ClientStatSvc; private GenericRepository<EFClientStatistics> ClientStatSvc;
private GenericRepository<EFServer> ServerSvc; private GenericRepository<EFServer> ServerSvc;
private GenericRepository<EFClientKill> KillSvc; private GenericRepository<EFClientKill> KillStatsSvc;
private GenericRepository<EFServerStatistics> ServerStatsSvc;
public StatManager(IManager mgr) public StatManager(IManager mgr)
{ {
@ -28,13 +28,13 @@ namespace StatsPlugin.Helpers
Manager = mgr; Manager = mgr;
ClientStatSvc = new GenericRepository<EFClientStatistics>(); ClientStatSvc = new GenericRepository<EFClientStatistics>();
ServerSvc = new GenericRepository<EFServer>(); ServerSvc = new GenericRepository<EFServer>();
KillSvc = new GenericRepository<EFClientKill>(); KillStatsSvc = new GenericRepository<EFClientKill>();
ServerStatsSvc = new GenericRepository<EFServerStatistics>();
} }
~StatManager() ~StatManager()
{ {
Servers.Clear(); Servers.Clear();
Log.WriteInfo("Cleared StatManager servers");
Log = null; Log = null;
Servers = null; Servers = null;
} }
@ -48,6 +48,7 @@ namespace StatsPlugin.Helpers
try try
{ {
int serverId = sv.GetHashCode(); int serverId = sv.GetHashCode();
// get the server from the database if it exists, otherwise create and insert a new one // get the server from the database if it exists, otherwise create and insert a new one
var server = ServerSvc.Find(c => c.ServerId == serverId).FirstOrDefault(); var server = ServerSvc.Find(c => c.ServerId == serverId).FirstOrDefault();
if (server == null) if (server == null)
@ -64,7 +65,13 @@ namespace StatsPlugin.Helpers
// this doesn't need to be async as it's during initialization // this doesn't need to be async as it's during initialization
ServerSvc.SaveChanges(); ServerSvc.SaveChanges();
Servers.Add(sv.GetHashCode(), new ServerStats(server)); InitializeServerStats(sv);
ServerStatsSvc.SaveChanges();
var serverStats = ServerStatsSvc.Find(c => c.ServerId == serverId).FirstOrDefault();
// check to see if the stats have ever been initialized
Servers.Add(serverId, new ServerStats(server, serverStats));
} }
catch (Exception e) catch (Exception e)
@ -102,6 +109,10 @@ namespace StatsPlugin.Helpers
clientStats = ClientStatSvc.Insert(clientStats); clientStats = ClientStatSvc.Insert(clientStats);
} }
// set these on connecting
clientStats.LastActive = DateTime.UtcNow;
clientStats.LastStatCalculation = DateTime.UtcNow;
lock (playerStats) lock (playerStats)
{ {
if (playerStats.ContainsKey(pl.ClientNumber)) if (playerStats.ContainsKey(pl.ClientNumber))
@ -123,17 +134,9 @@ namespace StatsPlugin.Helpers
// remove the client from the stats dictionary as they're leaving // remove the client from the stats dictionary as they're leaving
lock (playerStats) lock (playerStats)
playerStats.Remove(pl.ClientNumber); playerStats.Remove(pl.ClientNumber);
// allow accessing certain properties
//clientStats.Client = pl; var serverStats = ServerStatsSvc.Find(sv => sv.ServerId == serverId).FirstOrDefault();
// update skill serverStats.TotalPlayTime += (int)(DateTime.UtcNow - pl.LastConnection).TotalSeconds;
// clientStats = UpdateStats(clientStats);
// reset for EF cache
//clientStats.SessionDeaths = 0;
// clientStats.SessionKills = 0;
// prevent mismatched primary key
//clientStats.Client = null;
// update in database
//await ClientStatSvc.SaveChangesAsync();
} }
/// <summary> /// <summary>
@ -160,18 +163,29 @@ namespace StatsPlugin.Helpers
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName)) Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName))
}; };
KillSvc.Insert(kill); KillStatsSvc.Insert(kill);
await KillSvc.SaveChangesAsync(); await KillStatsSvc.SaveChangesAsync();
} }
public void AddStandardKill(Player attacker, Player victim) public void AddStandardKill(Player attacker, Player victim)
{ {
var attackerStats = Servers[attacker.CurrentServer.GetHashCode()].PlayerStats[attacker.ClientNumber]; int serverId = attacker.CurrentServer.GetHashCode();
// set to access total time var attackerStats = Servers[serverId].PlayerStats[attacker.ClientNumber];
// set to access total time played
attackerStats.Client = attacker; attackerStats.Client = attacker;
var victimStats = Servers[victim.CurrentServer.GetHashCode()].PlayerStats[victim.ClientNumber]; var victimStats = Servers[serverId].PlayerStats[victim.ClientNumber];
// update the total stats
Servers[serverId].ServerStatistics.TotalKills += 1;
// calculate for the clients
CalculateKill(attackerStats, victimStats); CalculateKill(attackerStats, victimStats);
// immediately write changes in debug
#if DEBUG
ClientStatSvc.SaveChanges();
ServerStatsSvc.SaveChanges();
#endif
} }
/// <summary> /// <summary>
@ -195,10 +209,9 @@ namespace StatsPlugin.Helpers
UpdateStats(attackerStats); UpdateStats(attackerStats);
attackerStats.Client = null; attackerStats.Client = null;
// immediately write changes in debug // update after calculation
#if DEBUG attackerStats.LastActive = DateTime.UtcNow;
ClientStatSvc.SaveChanges(); victimStats.LastActive = DateTime.UtcNow;
#endif
} }
/// <summary> /// <summary>
@ -208,44 +221,83 @@ namespace StatsPlugin.Helpers
/// <returns></returns> /// <returns></returns>
private EFClientStatistics UpdateStats(EFClientStatistics clientStats) private EFClientStatistics UpdateStats(EFClientStatistics clientStats)
{ {
// if it's their first kill we need to set the last kill as the time they joined
clientStats.LastStatCalculation = (clientStats.LastStatCalculation == DateTime.MinValue) ? DateTime.UtcNow : clientStats.LastStatCalculation;
double timeSinceLastCalc = (DateTime.UtcNow - clientStats.LastStatCalculation).TotalSeconds / 60.0; double timeSinceLastCalc = (DateTime.UtcNow - clientStats.LastStatCalculation).TotalSeconds / 60.0;
double timeSinceLastActive = (DateTime.UtcNow - clientStats.LastActive).TotalSeconds / 60.0;
// each 'session' is one minute // prevent NaN or inactive time lowering SPM
if (timeSinceLastCalc >= 1) if (timeSinceLastCalc == 0 || timeSinceLastActive > 3)
{ return clientStats;
Log.WriteDebug($"Updated stats for {clientStats.ClientId} ({clientStats.SessionKills})");
// calculate the players Score Per Minute for the current session
// todo: score should be based on gamemode
double killSPM = clientStats.SessionKills * 100.0;
// calculate how much the KDR should weigh // calculate the players Score Per Minute for the current session
// 1.637 is a Eddie-Generated number that weights the KDR nicely int currentScore = Manager.GetActiveClients()
double KDRWeight = Math.Round(Math.Pow(clientStats.KDR, 1.637 / Math.E), 3); .First(c => c.ClientId == clientStats.ClientId)
.Score;
double killSPM = currentScore / (timeSinceLastCalc * 60.0);
// if no SPM, weight is 1 else the weight ishe current session's spm / lifetime average score per minute // calculate how much the KDR should weigh
double SPMWeightAgainstAverage = (clientStats.SPM < 1) ? 1 : killSPM / clientStats.SPM; // 1.637 is a Eddie-Generated number that weights the KDR nicely
double KDRWeight = Math.Round(Math.Pow(clientStats.KDR, 1.637 / Math.E), 3);
// calculate the weight of the new play time against last 10 hours of gameplay // if no SPM, weight is 1 else the weight ishe current session's spm / lifetime average score per minute
int totalConnectionTime = (clientStats.Client.TotalConnectionTime == 0) ? double SPMWeightAgainstAverage = (clientStats.SPM < 1) ? 1 : killSPM / clientStats.SPM;
(int)(DateTime.UtcNow - clientStats.Client.FirstConnection).TotalSeconds :
clientStats.Client.TotalConnectionTime + (int)(DateTime.UtcNow - clientStats.Client.LastConnection).TotalSeconds;
double SPMAgainstPlayWeight = timeSinceLastCalc / Math.Min(600, (totalConnectionTime / 60.0)); // calculate the weight of the new play time against last 10 hours of gameplay
int totalConnectionTime = (clientStats.Client.TotalConnectionTime == 0) ?
(int)(DateTime.UtcNow - clientStats.Client.FirstConnection).TotalSeconds :
clientStats.Client.TotalConnectionTime + (int)(DateTime.UtcNow - clientStats.Client.LastConnection).TotalSeconds;
// calculate the new weight against average times the weight against play time double SPMAgainstPlayWeight = timeSinceLastCalc / Math.Min(600, (totalConnectionTime / 60.0));
clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight));
clientStats.SPM = Math.Round(clientStats.SPM, 3);
clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight) / 10.0, 3);
clientStats.SessionKills = 0; // calculate the new weight against average times the weight against play time
clientStats.SessionDeaths = 0; clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight));
clientStats.SPM = Math.Round(clientStats.SPM, 3);
clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3);
clientStats.LastStatCalculation = DateTime.UtcNow; clientStats.LastStatCalculation = DateTime.UtcNow;
} clientStats.LastScore = currentScore;
return clientStats; return clientStats;
} }
public void InitializeServerStats(Server sv)
{
int serverId = sv.GetHashCode();
var serverStats = ServerStatsSvc.Find(s => s.ServerId == serverId).FirstOrDefault();
if (serverStats == null)
{
Log.WriteDebug($"Initializing server stats for {sv}");
// server stats have never been generated before
serverStats = new EFServerStatistics()
{
Active = true,
ServerId = serverId,
TotalKills = 0,
TotalPlayTime = 0,
};
var ieClientStats = ClientStatSvc.Find(cs => cs.ServerId == serverId);
// set these incase they've we've imported settings
serverStats.TotalKills = ieClientStats.Sum(cs => cs.Kills);
serverStats.TotalPlayTime = Manager.GetClientService().GetTotalPlayTime().Result;
ServerStatsSvc.Insert(serverStats);
}
}
public async Task Sync()
{
Log.WriteDebug("Syncing server stats");
await ServerStatsSvc.SaveChangesAsync();
Log.WriteDebug("Syncing client stats");
await ClientStatSvc.SaveChangesAsync();
Log.WriteDebug("Syncing kill stats");
await KillStatsSvc.SaveChangesAsync();
Log.WriteDebug("Syncing servers");
await ServerSvc.SaveChangesAsync();
}
} }
} }

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StatsPlugin.Helpers
{
public class StreakMessage
{
public static string MessageOnStreak(int killStreak, int deathStreak)
{
String Message = "";
switch (killStreak)
{
case 5:
Message = "Great job! You're on a ^55 killstreak!";
break;
case 10:
Message = "Amazing! ^510 kills ^7without dying!";
break;
}
switch (deathStreak)
{
case 5:
Message = "Pick it up soldier, you've died ^55 times ^7in a row...";
break;
case 10:
Message = "Seriously? ^510 deaths ^7without getting a kill?";
break;
}
return Message;
}
}
}

View File

@ -1333,7 +1333,8 @@ namespace StatsPlugin
ak74u_silencer_thermal_mp, ak74u_silencer_thermal_mp,
ak74u_silencer_xmags_mp, ak74u_silencer_xmags_mp,
ak74u_thermal_xmags_mp, ak74u_thermal_xmags_mp,
m40a3_mp = 1194, m16_reflex_silencer_mp,
m40a3_mp,
peacekeeper_mp, peacekeeper_mp,
dragunov_mp, dragunov_mp,
cobra_player_minigun_mp cobra_player_minigun_mp

View File

@ -45,5 +45,9 @@ namespace StatsPlugin.Models
public int DeathStreak { get; set; } public int DeathStreak { get; set; }
[NotMapped] [NotMapped]
public DateTime LastStatCalculation { get; set; } public DateTime LastStatCalculation { get; set; }
[NotMapped]
public int LastScore { get; set; }
[NotMapped]
public DateTime LastActive { get; set; }
} }
} }

View File

@ -0,0 +1,17 @@
using SharedLibrary.Database.Models;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace StatsPlugin.Models
{
public class EFServerStatistics : SharedEntity
{
[Key]
public int StatisticId { get; set; }
public int ServerId { get; set; }
[ForeignKey("ServerId")]
public virtual EFServer Server { get; set; }
public long TotalKills { get; set; }
public long TotalPlayTime { get; set; }
}
}

View File

@ -5,8 +5,11 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using SharedLibrary; using SharedLibrary;
using SharedLibrary.Helpers;
using SharedLibrary.Interfaces; using SharedLibrary.Interfaces;
using SharedLibrary.Services;
using StatsPlugin.Helpers; using StatsPlugin.Helpers;
using StatsPlugin.Models;
namespace StatsPlugin namespace StatsPlugin
{ {
@ -40,6 +43,7 @@ namespace StatsPlugin
case Event.GType.MapChange: case Event.GType.MapChange:
break; break;
case Event.GType.MapEnd: case Event.GType.MapEnd:
await Manager.Sync();
break; break;
case Event.GType.Broadcast: case Event.GType.Broadcast:
break; break;
@ -71,6 +75,27 @@ namespace StatsPlugin
public Task OnLoadAsync(IManager manager) public Task OnLoadAsync(IManager manager)
{ {
/*
*
ManagerInstance.GetMessageTokens().Add(new MessageToken("TOTALKILLS", GetTotalKills));
ManagerInstance.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", GetTotalPlaytime));
*/
string totalKills()
{
var serverStats = new GenericRepository<EFServerStatistics>();
return serverStats.GetQuery(s => s.Active)
.Sum(c => c.TotalKills).ToString();
}
string totalPlayTime()
{
var serverStats = new GenericRepository<EFServerStatistics>();
return serverStats.GetQuery(s => s.Active)
.Sum(c => c.TotalPlayTime).ToString();
}
manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills));
manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", totalPlayTime));
return Task.FromResult( return Task.FromResult(
Manager = new StatManager(manager) Manager = new StatManager(manager)
); );

View File

@ -72,11 +72,13 @@
<None Include="Chat\ChatHistoryPage.cs" /> <None Include="Chat\ChatHistoryPage.cs" />
<Compile Include="Helpers\ServerStats.cs" /> <Compile Include="Helpers\ServerStats.cs" />
<Compile Include="Helpers\StatManager.cs" /> <Compile Include="Helpers\StatManager.cs" />
<Compile Include="Helpers\StreakMessage.cs" />
<Compile Include="IW4Info.cs" /> <Compile Include="IW4Info.cs" />
<Compile Include="MinimapConfig.cs" /> <Compile Include="MinimapConfig.cs" />
<Compile Include="Models\EFClientKill.cs" /> <Compile Include="Models\EFClientKill.cs" />
<Compile Include="Models\EFServer.cs" /> <Compile Include="Models\EFServer.cs" />
<Compile Include="Models\EFClientStatistics.cs" /> <Compile Include="Models\EFClientStatistics.cs" />
<Compile Include="Models\EFServerStatistics.cs" />
<Compile Include="Plugin.cs" /> <Compile Include="Plugin.cs" />
<None Include="_Plugin.cs" /> <None Include="_Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -744,7 +744,7 @@ namespace SharedLibrary.Commands
E.Data = E.Data.RemoveWords(1); E.Data = E.Data.RemoveWords(1);
E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data)); E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data));
await E.Origin.Tell($"Thank you for your report, and administrator has been notified"); await E.Origin.Tell($"Thank you for your report, an administrator has been notified");
await E.Owner.ExecuteEvent(new Event(Event.GType.Report, E.Data, E.Origin, E.Target, E.Owner)); await E.Owner.ExecuteEvent(new Event(Event.GType.Report, E.Data, E.Origin, E.Target, E.Owner));
await E.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", E.Origin.Name, E.Target.Name, E.Data)); await E.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", E.Origin.Name, E.Target.Name, E.Data));
} }

View File

@ -73,6 +73,8 @@ namespace SharedLibrary.Objects
public DateTime ConnectionTime { get; set; } public DateTime ConnectionTime { get; set; }
[NotMapped] [NotMapped]
public Server CurrentServer { get; set; } public Server CurrentServer { get; set; }
[NotMapped]
public int Score { get; set; }
private string _ipaddress; private string _ipaddress;
public override string IPAddress public override string IPAddress

View File

@ -26,8 +26,8 @@ namespace SharedLibrary.Network
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "") static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
{ {
if ((DateTime.Now - LastQuery).TotalMilliseconds < 100) if ((DateTime.Now - LastQuery).TotalMilliseconds < 300)
Task.Delay(100).Wait(); Task.Delay(300).Wait();
LastQuery = DateTime.Now; LastQuery = DateTime.Now;
var ServerOOBConnection = new UdpClient(); var ServerOOBConnection = new UdpClient();
ServerOOBConnection.Client.SendTimeout = 1000; ServerOOBConnection.Client.SendTimeout = 1000;

View File

@ -233,6 +233,12 @@ namespace SharedLibrary.Services
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public async Task<int> GetTotalPlayTime()
{
using (var context = new DatabaseContext())
return await context.Clients.SumAsync(c => c.TotalConnectionTime);
}
#endregion #endregion
} }
} }

View File

@ -62,7 +62,9 @@ namespace SharedLibrary
int.TryParse(playerInfo[0], out cID); int.TryParse(playerInfo[0], out cID);
var regex = Regex.Match(responseLine, @"\d+\.\d+\.\d+.\d+\:\d{1,5}"); var regex = Regex.Match(responseLine, @"\d+\.\d+\.\d+.\d+\:\d{1,5}");
string cIP = regex.Value.Split(':')[0]; string cIP = regex.Value.Split(':')[0];
Player P = new Player() { Name = cName, NetworkId = npID, ClientNumber = cID, IPAddress = cIP, Ping = Ping }; regex = Regex.Match(responseLine, @"[0-9]{1,2}\s+[0-9]+\s+");
int score = Int32.Parse(regex.Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[1]);
Player P = new Player() { Name = cName, NetworkId = npID, ClientNumber = cID, IPAddress = cIP, Ping = Ping, Score = score};
StatusPlayers.Add(P); StatusPlayers.Add(P);
} }
} }