adding Cod4 support (for steam GUID is truncated to 16 characters)
exit properly whoops add all linked accounts to drop down consolidate linked admin accounts to the most recently seen one limited some waits to 5s to hopefully prevent a rare thread lock
This commit is contained in:
parent
6e5501b32d
commit
699c19cd4b
@ -27,9 +27,9 @@
|
|||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<!--<PropertyGroup>
|
||||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||||
</PropertyGroup>
|
</PropertyGroup>-->
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj">
|
<ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj">
|
||||||
|
@ -82,14 +82,17 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (cleanedEventLine[0] == 'D')
|
if (cleanedEventLine[0] == 'D')
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
if (Regex.Match(cleanedEventLine, @"^(D);((?:bot[0-9]+)|(?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$").Success)
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Damage,
|
return new GameEvent()
|
||||||
Data = Regex.Replace(logLine, @"[0-9]+:[0-9]+\ ", "").Trim(),
|
{
|
||||||
Origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong()),
|
Type = GameEvent.EventType.Damage,
|
||||||
Target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong()),
|
Data = cleanedEventLine,
|
||||||
Owner = server
|
Origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong()),
|
||||||
};
|
Target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong()),
|
||||||
|
Owner = server
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cleanedEventLine.Contains("ExitLevel"))
|
if (cleanedEventLine.Contains("ExitLevel"))
|
||||||
|
@ -49,8 +49,11 @@ namespace IW4MAdmin.Application.IO
|
|||||||
events.Add(Parser.GetEvent(server, eventLine));
|
events.Add(Parser.GetEvent(server, eventLine));
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
Program.ServerManager.GetLogger().WriteWarning("Could not properly parse event line");
|
||||||
|
Program.ServerManager.GetLogger().WriteDebug(e.Message);
|
||||||
|
Program.ServerManager.GetLogger().WriteDebug(eventLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ namespace IW4MAdmin.Application
|
|||||||
};
|
};
|
||||||
|
|
||||||
ServerManager.GetEventHandler().AddEvent(E);
|
ServerManager.GetEventHandler().AddEvent(E);
|
||||||
E.OnProcessed.Wait();
|
E.OnProcessed.Wait(5000);
|
||||||
}
|
}
|
||||||
Console.Write('>');
|
Console.Write('>');
|
||||||
|
|
||||||
@ -155,6 +155,7 @@ namespace IW4MAdmin.Application
|
|||||||
Console.WriteLine($"Exception: {e.Message}");
|
Console.WriteLine($"Exception: {e.Message}");
|
||||||
Console.WriteLine(loc["MANAGER_EXIT"]);
|
Console.WriteLine(loc["MANAGER_EXIT"]);
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ServerManager.GetApplicationSettings().Configuration().EnableWebFront)
|
if (ServerManager.GetApplicationSettings().Configuration().EnableWebFront)
|
||||||
@ -171,7 +172,7 @@ namespace IW4MAdmin.Application
|
|||||||
private static void OnCancelKey(object sender, ConsoleCancelEventArgs e)
|
private static void OnCancelKey(object sender, ConsoleCancelEventArgs e)
|
||||||
{
|
{
|
||||||
ServerManager.Stop();
|
ServerManager.Stop();
|
||||||
OnShutdownComplete.Wait();
|
OnShutdownComplete.Wait(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckDirectories()
|
static void CheckDirectories()
|
||||||
|
@ -341,7 +341,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Heartbeat.Send(this, true).Wait();
|
Heartbeat.Send(this, true).Wait(5000);
|
||||||
heartbeatState.Connected = true;
|
heartbeatState.Connected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Heartbeat.Send(this).Wait();
|
Heartbeat.Send(this).Wait(5000);
|
||||||
}
|
}
|
||||||
catch (System.Net.Http.HttpRequestException e)
|
catch (System.Net.Http.HttpRequestException e)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ namespace Application.RconParsers
|
|||||||
TempBan = "tempbanclient {0} \"{1}\""
|
TempBan = "tempbanclient {0} \"{1}\""
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|bot[0-9]+|(?:[0-9]+)) +(.{0,20}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$";
|
private static string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|(?:[a-z]|[0-9]){32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$";
|
||||||
|
|
||||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||||
{
|
{
|
||||||
|
@ -51,7 +51,6 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
override public async Task<bool> AddPlayer(Player polledPlayer)
|
override public async Task<bool> AddPlayer(Player polledPlayer)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
|
if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
|
||||||
polledPlayer.Ping < 1 ||
|
polledPlayer.Ping < 1 ||
|
||||||
polledPlayer.ClientNumber < 0)
|
polledPlayer.ClientNumber < 0)
|
||||||
@ -451,12 +450,16 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
if (E.Type == GameEvent.EventType.Connect)
|
if (E.Type == GameEvent.EventType.Connect)
|
||||||
{
|
{
|
||||||
ChatHistory.Add(new ChatInfo()
|
// this may be a fix for a hard to reproduce null exception error
|
||||||
|
lock (ChatHistory)
|
||||||
{
|
{
|
||||||
Name = E.Origin.Name,
|
ChatHistory.Add(new ChatInfo()
|
||||||
Message = "CONNECTED",
|
{
|
||||||
Time = DateTime.UtcNow
|
Name = E.Origin?.Name ?? "ERROR!",
|
||||||
});
|
Message = "CONNECTED",
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (E.Origin.Level > Player.Permission.Moderator)
|
if (E.Origin.Level > Player.Permission.Moderator)
|
||||||
await E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
|
await E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
|
||||||
@ -479,24 +482,35 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.Disconnect)
|
else if (E.Type == GameEvent.EventType.Disconnect)
|
||||||
{
|
{
|
||||||
ChatHistory.Add(new ChatInfo()
|
// this may be a fix for a hard to reproduce null exception error
|
||||||
|
lock (ChatHistory)
|
||||||
{
|
{
|
||||||
Name = E.Origin.Name,
|
ChatHistory.Add(new ChatInfo()
|
||||||
Message = "DISCONNECTED",
|
{
|
||||||
Time = DateTime.UtcNow
|
Name = E.Origin?.Name ?? "ERROR!",
|
||||||
});
|
Message = "DISCONNECTED",
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.Say && E.Data?.Length >= 2)
|
if (E.Type == GameEvent.EventType.Say)
|
||||||
{
|
{
|
||||||
E.Data = E.Data.StripColors();
|
E.Data = E.Data.StripColors();
|
||||||
|
|
||||||
ChatHistory.Add(new ChatInfo()
|
if (E.Data.Length > 0)
|
||||||
{
|
{
|
||||||
Name = E.Origin.Name,
|
// this may be a fix for a hard to reproduce null exception error
|
||||||
Message = E.Data,
|
lock (ChatHistory)
|
||||||
Time = DateTime.UtcNow
|
{
|
||||||
});
|
ChatHistory.Add(new ChatInfo()
|
||||||
|
{
|
||||||
|
Name = E.Origin?.Name ?? "ERROR!",
|
||||||
|
Message = E.Data,
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.MapChange)
|
if (E.Type == GameEvent.EventType.MapChange)
|
||||||
@ -731,7 +745,10 @@ namespace IW4MAdmin
|
|||||||
GameName = Utilities.GetGame(version.Value);
|
GameName = Utilities.GetGame(version.Value);
|
||||||
|
|
||||||
if (GameName == Game.IW4)
|
if (GameName == Game.IW4)
|
||||||
|
{
|
||||||
EventParser = new IW4EventParser();
|
EventParser = new IW4EventParser();
|
||||||
|
RconParser = new IW4RConParser();
|
||||||
|
}
|
||||||
else if (GameName == Game.IW5)
|
else if (GameName == Game.IW5)
|
||||||
EventParser = new IW5EventParser();
|
EventParser = new IW5EventParser();
|
||||||
else if (GameName == Game.T5M)
|
else if (GameName == Game.T5M)
|
||||||
|
@ -81,8 +81,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
||||||
hitLoc.HitOffsetAverage = (float)newAverage;
|
hitLoc.HitOffsetAverage = (float)newAverage;
|
||||||
|
|
||||||
|
if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset &&
|
||||||
if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset)
|
hitLoc.HitCount > 15)
|
||||||
{
|
{
|
||||||
Log.WriteDebug("*** Reached Max Lifetime Average for Angle Difference ***");
|
Log.WriteDebug("*** Reached Max Lifetime Average for Angle Difference ***");
|
||||||
Log.WriteDebug($"Lifetime Average = {newAverage}");
|
Log.WriteDebug($"Lifetime Average = {newAverage}");
|
||||||
@ -92,9 +92,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
return new DetectionPenaltyResult()
|
return new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = hitLoc.HitOffsetAverage,
|
Value = hitLoc.HitOffsetAverage,
|
||||||
HitCount = hitLoc.HitCount,
|
HitCount = hitLoc.HitCount,
|
||||||
|
Type = DetectionType.Offset
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +103,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
double sessAverage = (AngleDifferenceAverage * (HitCount - 1) + realAgainstPredict) / HitCount;
|
double sessAverage = (AngleDifferenceAverage * (HitCount - 1) + realAgainstPredict) / HitCount;
|
||||||
AngleDifferenceAverage = sessAverage;
|
AngleDifferenceAverage = sessAverage;
|
||||||
|
|
||||||
if (sessAverage > Thresholds.MaxOffset)
|
if (sessAverage > Thresholds.MaxOffset &&
|
||||||
|
HitCount > 15)
|
||||||
{
|
{
|
||||||
Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
|
Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
|
||||||
Log.WriteDebug($"Session Average = {sessAverage}");
|
Log.WriteDebug($"Session Average = {sessAverage}");
|
||||||
@ -124,7 +126,6 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
var currentStrain = Strain.GetStrain(kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset));
|
var currentStrain = Strain.GetStrain(kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset));
|
||||||
|
|
||||||
LastOffset = kill.TimeOffset;
|
LastOffset = kill.TimeOffset;
|
||||||
|
|
||||||
if (currentStrain > ClientStats.MaxStrain)
|
if (currentStrain > ClientStats.MaxStrain)
|
||||||
|
@ -28,8 +28,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
public const double KillTimeThreshold = 0.2;
|
public const double KillTimeThreshold = 0.2;
|
||||||
|
|
||||||
public const double MaxStrainBan = 0.4399;
|
public const double MaxStrainBan = 0.4399;
|
||||||
public const double MaxOffset = 4.789;
|
public const double MaxOffset = 1.2;
|
||||||
public const double MaxStrainFlag = 0.2;
|
public const double MaxStrainFlag = 1;
|
||||||
|
|
||||||
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using SharedLibraryCore.Services;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Helpers
|
namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||||
{
|
{
|
||||||
|
@ -104,7 +104,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
// 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
|
||||||
var clientStats = statsSvc.ClientStatSvc.Find(c => c.ClientId == pl.ClientId && c.ServerId == serverId).FirstOrDefault();
|
var clientStatsSvc = statsSvc.ClientStatSvc;
|
||||||
|
var clientStats = clientStatsSvc.Find(c => c.ClientId == pl.ClientId && c.ServerId == serverId).FirstOrDefault();
|
||||||
|
|
||||||
if (clientStats == null)
|
if (clientStats == null)
|
||||||
{
|
{
|
||||||
@ -127,7 +128,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
};
|
};
|
||||||
|
|
||||||
// insert if they've not been added
|
// insert if they've not been added
|
||||||
var clientStatsSvc = statsSvc.ClientStatSvc;
|
|
||||||
clientStats = clientStatsSvc.Insert(clientStats);
|
clientStats = clientStatsSvc.Insert(clientStats);
|
||||||
await clientStatsSvc.SaveChangesAsync();
|
await clientStatsSvc.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
@ -193,10 +193,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue4);
|
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue4);
|
||||||
|
|
||||||
// sync their stats before they leave
|
// sync their stats before they leave
|
||||||
// clientStats = UpdateStats(clientStats);
|
var clientStatsSvc = statsSvc.ClientStatSvc;
|
||||||
// var clientStatsSvc = statsSvc.ClientStatSvc;
|
clientStats = UpdateStats(clientStats);
|
||||||
// clientStatsSvc.Update(clientStats);
|
clientStatsSvc.Update(clientStats);
|
||||||
// await clientStatsSvc.SaveChangesAsync();
|
await clientStatsSvc.SaveChangesAsync();
|
||||||
|
|
||||||
// increment the total play time
|
// increment the total play time
|
||||||
serverStats.TotalPlayTime += (int)(DateTime.UtcNow - pl.LastConnection).TotalSeconds;
|
serverStats.TotalPlayTime += (int)(DateTime.UtcNow - pl.LastConnection).TotalSeconds;
|
||||||
@ -305,6 +305,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
var clientDetection = Servers[serverId].PlayerDetections[attacker.ClientId];
|
var clientDetection = Servers[serverId].PlayerDetections[attacker.ClientId];
|
||||||
var clientStats = Servers[serverId].PlayerStats[attacker.ClientId];
|
var clientStats = Servers[serverId].PlayerStats[attacker.ClientId];
|
||||||
|
var clientStatsSvc = statsSvc.ClientStatSvc;
|
||||||
|
clientStatsSvc.Update(clientStats);
|
||||||
|
|
||||||
// increment their hit count
|
// increment their hit count
|
||||||
if (kill.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
if (kill.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
||||||
@ -313,7 +315,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
clientStats.HitLocations.Single(hl => hl.Location == kill.HitLoc).HitCount += 1;
|
clientStats.HitLocations.Single(hl => hl.Location == kill.HitLoc).HitCount += 1;
|
||||||
|
|
||||||
statsSvc.ClientStatSvc.Update(clientStats);
|
//statsSvc.ClientStatSvc.Update(clientStats);
|
||||||
// await statsSvc.ClientStatSvc.SaveChangesAsync();
|
// await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +347,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
Data = penalty.Type == Cheat.Detection.DetectionType.Bone ?
|
Data = penalty.Type == Cheat.Detection.DetectionType.Bone ?
|
||||||
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
||||||
$"{penalty.Type} -{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
|
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
|
||||||
Origin = new Player()
|
Origin = new Player()
|
||||||
{
|
{
|
||||||
ClientId = 1,
|
ClientId = 1,
|
||||||
@ -365,10 +367,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
await executePenalty(clientDetection.ProcessKill(kill, isDamage));
|
await executePenalty(clientDetection.ProcessKill(kill, isDamage));
|
||||||
await executePenalty(clientDetection.ProcessTotalRatio(clientStats));
|
await executePenalty(clientDetection.ProcessTotalRatio(clientStats));
|
||||||
|
|
||||||
#if DEBUG
|
await clientStatsSvc.SaveChangesAsync();
|
||||||
statsSvc.ClientStatSvc.Update(clientStats);
|
|
||||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,10 +447,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo: do we want to save this immediately?
|
// todo: do we want to save this immediately?
|
||||||
var statsSvc = ContextThreads[serverId].ClientStatSvc;
|
var clientStatsSvc = ContextThreads[serverId].ClientStatSvc;
|
||||||
statsSvc.Update(attackerStats);
|
clientStatsSvc.Update(attackerStats);
|
||||||
statsSvc.Update(victimStats);
|
clientStatsSvc.Update(victimStats);
|
||||||
await statsSvc.SaveChangesAsync();
|
await clientStatsSvc.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -478,7 +477,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
victimStats.KillStreak = 0;
|
victimStats.KillStreak = 0;
|
||||||
|
|
||||||
// process the attacker's stats after the kills
|
// process the attacker's stats after the kills
|
||||||
//attackerStats = UpdateStats(attackerStats);
|
attackerStats = UpdateStats(attackerStats);
|
||||||
|
|
||||||
// update after calculation
|
// update after calculation
|
||||||
attackerStats.TimePlayed += (int)(DateTime.UtcNow - attackerStats.LastActive).TotalSeconds;
|
attackerStats.TimePlayed += (int)(DateTime.UtcNow - attackerStats.LastActive).TotalSeconds;
|
||||||
@ -630,7 +629,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
Log.WriteDebug("Syncing stats contexts");
|
Log.WriteDebug("Syncing stats contexts");
|
||||||
await statsSvc.ServerStatsSvc.SaveChangesAsync();
|
await statsSvc.ServerStatsSvc.SaveChangesAsync();
|
||||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
//await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||||
await statsSvc.KillStatsSvc.SaveChangesAsync();
|
await statsSvc.KillStatsSvc.SaveChangesAsync();
|
||||||
await statsSvc.ServerSvc.SaveChangesAsync();
|
await statsSvc.ServerSvc.SaveChangesAsync();
|
||||||
|
|
||||||
|
@ -20,7 +20,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
public GenericRepository<EFServer> ServerSvc { get; private set; }
|
public GenericRepository<EFServer> ServerSvc { get; private set; }
|
||||||
public GenericRepository<EFClientKill> KillStatsSvc { get; private set; }
|
public GenericRepository<EFClientKill> KillStatsSvc { get; private set; }
|
||||||
public GenericRepository<EFServerStatistics> ServerStatsSvc { get; private set; }
|
public GenericRepository<EFServerStatistics> ServerStatsSvc { get; private set; }
|
||||||
public GenericRepository<EFClientMessage> MessageSvc { get; private set; }
|
public GenericRepository<EFClientMessage> MessageSvc
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new GenericRepository<EFClientMessage>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ThreadSafeStatsService()
|
public ThreadSafeStatsService()
|
||||||
{
|
{
|
||||||
@ -28,7 +34,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
ServerSvc = new GenericRepository<EFServer>();
|
ServerSvc = new GenericRepository<EFServer>();
|
||||||
KillStatsSvc = new GenericRepository<EFClientKill>();
|
KillStatsSvc = new GenericRepository<EFClientKill>();
|
||||||
ServerStatsSvc = new GenericRepository<EFServerStatistics>();
|
ServerStatsSvc = new GenericRepository<EFServerStatistics>();
|
||||||
MessageSvc = new GenericRepository<EFClientMessage>();
|
//MessageSvc = new GenericRepository<EFClientMessage>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,7 +387,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]");
|
await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]");
|
||||||
else
|
else
|
||||||
await E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAPROTATE"]);
|
await E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAPROTATE"]);
|
||||||
Task.Delay(5000).Wait();
|
await Task.Delay(5000);
|
||||||
await E.Owner.ExecuteCommandAsync("map_rotate");
|
await E.Owner.ExecuteCommandAsync("map_rotate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -553,14 +553,14 @@ namespace SharedLibraryCore.Commands
|
|||||||
if (m.Name.ToLower() == newMap || m.Alias.ToLower() == newMap)
|
if (m.Name.ToLower() == newMap || m.Alias.ToLower() == newMap)
|
||||||
{
|
{
|
||||||
await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAP_SUCCESS"]} ^5{m.Alias}");
|
await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAP_SUCCESS"]} ^5{m.Alias}");
|
||||||
Task.Delay(5000).Wait();
|
await Task.Delay(5000);
|
||||||
await E.Owner.LoadMap(m.Name);
|
await E.Owner.LoadMap(m.Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAP_UKN"]} ^5{newMap}");
|
await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAP_UKN"]} ^5{newMap}");
|
||||||
Task.Delay(5000).Wait();
|
await Task.Delay(5000);
|
||||||
await E.Owner.LoadMap(newMap);
|
await E.Owner.LoadMap(newMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,8 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string IPAddressString => new System.Net.IPAddress(BitConverter.GetBytes(IPAddress)).ToString();
|
public string IPAddressString => new System.Net.IPAddress(BitConverter.GetBytes(IPAddress)).ToString();
|
||||||
|
[NotMapped]
|
||||||
|
public virtual IDictionary<int, long> LinkedAccounts { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<EFPenalty> ReceivedPenalties { get; set; }
|
public virtual ICollection<EFPenalty> ReceivedPenalties { get; set; }
|
||||||
public virtual ICollection<EFPenalty> AdministeredPenalties { get; set; }
|
public virtual ICollection<EFPenalty> AdministeredPenalties { get; set; }
|
||||||
|
@ -24,5 +24,6 @@ namespace SharedLibraryCore.Dtos
|
|||||||
public List<ProfileMeta> Meta { get; set; }
|
public List<ProfileMeta> Meta { get; set; }
|
||||||
public bool Online { get; set; }
|
public bool Online { get; set; }
|
||||||
public string TimeOnline { get; set; }
|
public string TimeOnline { get; set; }
|
||||||
|
public IDictionary<int, long> LinkedAccounts { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace SharedLibraryCore.Dtos
|
|||||||
public string GameType { get; set; }
|
public string GameType { get; set; }
|
||||||
public int ClientCount { get; set; }
|
public int ClientCount { get; set; }
|
||||||
public int MaxClients { get; set; }
|
public int MaxClients { get; set; }
|
||||||
public ChatInfo[] ChatHistory { get; set; }
|
public List<ChatInfo> ChatHistory { get; set; }
|
||||||
public List<PlayerInfo> Players { get; set; }
|
public List<PlayerInfo> Players { get; set; }
|
||||||
public Helpers.PlayerHistory[] PlayerHistory { get; set; }
|
public Helpers.PlayerHistory[] PlayerHistory { get; set; }
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
@ -33,25 +33,6 @@ namespace SharedLibraryCore.RCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResponseEvent
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string[] Response { get; set; }
|
|
||||||
public Task Awaiter
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Task.Run(() => FinishedEvent.Wait());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private ManualResetEventSlim FinishedEvent;
|
|
||||||
|
|
||||||
public ResponseEvent()
|
|
||||||
{
|
|
||||||
FinishedEvent = new ManualResetEventSlim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Connection
|
public class Connection
|
||||||
{
|
{
|
||||||
public IPEndPoint Endpoint { get; private set; }
|
public IPEndPoint Endpoint { get; private set; }
|
||||||
@ -110,7 +91,7 @@ namespace SharedLibraryCore.RCon
|
|||||||
OnSent.Set();
|
OnSent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (SocketException)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,9 +148,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 < 250)
|
if ((DateTime.Now - LastQuery).TotalMilliseconds < 350)
|
||||||
{
|
{
|
||||||
await Task.Delay(250);
|
await Task.Delay(350);
|
||||||
}
|
}
|
||||||
|
|
||||||
LastQuery = DateTime.Now;
|
LastQuery = DateTime.Now;
|
||||||
|
@ -107,11 +107,33 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
using (var context = new DatabaseContext())
|
using (var context = new DatabaseContext())
|
||||||
{
|
{
|
||||||
return await context.Clients
|
context.ChangeTracker.AutoDetectChangesEnabled = false;
|
||||||
.AsNoTracking()
|
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
.Include(c => c.CurrentAlias)
|
|
||||||
.Include(c => c.AliasLink.Children)
|
var iqClient = from client in context.Clients
|
||||||
.SingleOrDefaultAsync(e => e.ClientId == entityID);
|
.Include(c => c.CurrentAlias)
|
||||||
|
.Include(c => c.AliasLink.Children)
|
||||||
|
where client.ClientId == entityID
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
Client = client,
|
||||||
|
LinkedAccounts = (from linkedClient in context.Clients
|
||||||
|
where client.AliasLinkId == linkedClient.AliasLinkId
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
linkedClient.ClientId,
|
||||||
|
linkedClient.NetworkId
|
||||||
|
})
|
||||||
|
};
|
||||||
|
var foundClient = await iqClient.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
foundClient.Client.LinkedAccounts = new Dictionary<int, long>();
|
||||||
|
// todo: find out the best way to do this
|
||||||
|
// I'm doing this here because I don't know the best way to have multiple awaits in the query
|
||||||
|
foreach (var linked in foundClient.LinkedAccounts)
|
||||||
|
foundClient.Client.LinkedAccounts.Add(linked.ClientId, linked.NetworkId);
|
||||||
|
|
||||||
|
return foundClient.Client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,11 +238,15 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
using (var context = new DatabaseContext())
|
using (var context = new DatabaseContext())
|
||||||
{
|
{
|
||||||
return await context.Clients
|
context.ChangeTracker.AutoDetectChangesEnabled = false;
|
||||||
.AsNoTracking()
|
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
.Include(c => c.CurrentAlias)
|
|
||||||
.Where(c => c.Level >= Player.Permission.Trusted)
|
var iqClients = from client in context.Clients
|
||||||
.ToListAsync();
|
.Include(c => c.CurrentAlias)
|
||||||
|
where client.Level >= Player.Permission.Trusted
|
||||||
|
select client;
|
||||||
|
|
||||||
|
return await iqClients.ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,14 +259,14 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
var iqClients = (from alias in context.Aliases
|
var iqClients = (from alias in context.Aliases
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
where alias.Name.ToLower()
|
where alias.Name.ToLower()
|
||||||
.Contains(name.ToLower())
|
.Contains(name.ToLower())
|
||||||
join link in context.AliasLinks
|
join link in context.AliasLinks
|
||||||
on alias.LinkId equals link.AliasLinkId
|
on alias.LinkId equals link.AliasLinkId
|
||||||
join client in context.Clients
|
join client in context.Clients
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
on alias.LinkId equals client.AliasLinkId
|
on alias.LinkId equals client.AliasLinkId
|
||||||
select client)
|
select client)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.Include(c => c.CurrentAlias)
|
.Include(c => c.CurrentAlias)
|
||||||
.Include(c => c.AliasLink.Children);
|
.Include(c => c.AliasLink.Children);
|
||||||
@ -255,13 +281,13 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
var iqClients = (from alias in context.Aliases
|
var iqClients = (from alias in context.Aliases
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
where alias.IPAddress == ipAddress
|
where alias.IPAddress == ipAddress
|
||||||
join link in context.AliasLinks
|
join link in context.AliasLinks
|
||||||
on alias.LinkId equals link.AliasLinkId
|
on alias.LinkId equals link.AliasLinkId
|
||||||
join client in context.Clients
|
join client in context.Clients
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
on alias.LinkId equals client.AliasLinkId
|
on alias.LinkId equals client.AliasLinkId
|
||||||
select client)
|
select client)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.Include(c => c.CurrentAlias)
|
.Include(c => c.CurrentAlias)
|
||||||
.Include(c => c.AliasLink.Children);
|
.Include(c => c.AliasLink.Children);
|
||||||
|
@ -12,7 +12,7 @@ namespace SharedLibraryCore.Services
|
|||||||
// https://stackoverflow.com/questions/43677906/crud-operations-with-entityframework-using-generic-type
|
// https://stackoverflow.com/questions/43677906/crud-operations-with-entityframework-using-generic-type
|
||||||
public class GenericRepository<TEntity> where TEntity : class
|
public class GenericRepository<TEntity> where TEntity : class
|
||||||
{
|
{
|
||||||
private dynamic _context;
|
private DatabaseContext _context;
|
||||||
private DbSet<TEntity> _dbSet;
|
private DbSet<TEntity> _dbSet;
|
||||||
|
|
||||||
protected DbContext Context
|
protected DbContext Context
|
||||||
@ -101,7 +101,6 @@ namespace SharedLibraryCore.Services
|
|||||||
dbSet.Attach(entity);
|
dbSet.Attach(entity);
|
||||||
|
|
||||||
dbSet.Remove(entity);
|
dbSet.Remove(entity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Delete(TEntity entity)
|
public virtual void Delete(TEntity entity)
|
||||||
@ -119,7 +118,6 @@ namespace SharedLibraryCore.Services
|
|||||||
T entity = dbSet.Find(id);
|
T entity = dbSet.Find(id);
|
||||||
dbSet.Attach(entity);
|
dbSet.Attach(entity);
|
||||||
dbSet.Remove(entity);
|
dbSet.Remove(entity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Delete(object id)
|
public virtual void Delete(object id)
|
||||||
|
@ -208,7 +208,8 @@ namespace SharedLibraryCore.Services
|
|||||||
Offense = penalty.Offense,
|
Offense = penalty.Offense,
|
||||||
Type = penalty.Type.ToString()
|
Type = penalty.Type.ToString()
|
||||||
},
|
},
|
||||||
When = penalty.When
|
When = penalty.When,
|
||||||
|
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
||||||
};
|
};
|
||||||
// fixme: is this good and fast?
|
// fixme: is this good and fast?
|
||||||
var list = await iqPenalties.ToListAsync();
|
var list = await iqPenalties.ToListAsync();
|
||||||
|
@ -182,6 +182,7 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
public static long ConvertLong(this string str)
|
public static long ConvertLong(this string str)
|
||||||
{
|
{
|
||||||
|
str = str.Substring(0, Math.Min(str.Length, 16));
|
||||||
if (Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id))
|
if (Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id))
|
||||||
return id;
|
return id;
|
||||||
var bot = Regex.Match(str, @"bot[0-9]+").Value;
|
var bot = Regex.Match(str, @"bot[0-9]+").Value;
|
||||||
|
@ -71,7 +71,7 @@ namespace WebfrontCore.Controllers
|
|||||||
catch (System.Collections.Generic.KeyNotFoundException)
|
catch (System.Collections.Generic.KeyNotFoundException)
|
||||||
{
|
{
|
||||||
// force the "banned" client to be signed out
|
// force the "banned" client to be signed out
|
||||||
HttpContext.SignOutAsync().Wait();
|
HttpContext.SignOutAsync().Wait(5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ namespace WebfrontCore.Controllers
|
|||||||
.OrderBy(i => i)
|
.OrderBy(i => i)
|
||||||
.ToList(),
|
.ToList(),
|
||||||
Online = Manager.GetActiveClients().FirstOrDefault(c => c.ClientId == client.ClientId) != null,
|
Online = Manager.GetActiveClients().FirstOrDefault(c => c.ClientId == client.ClientId) != null,
|
||||||
TimeOnline = (DateTime.UtcNow - client.LastConnection).TimeSpanText()
|
TimeOnline = (DateTime.UtcNow - client.LastConnection).TimeSpanText(),
|
||||||
|
LinkedAccounts = client.LinkedAccounts
|
||||||
};
|
};
|
||||||
|
|
||||||
var meta = await MetaService.GetMeta(client.ClientId);
|
var meta = await MetaService.GetMeta(client.ClientId);
|
||||||
@ -54,7 +55,7 @@ namespace WebfrontCore.Controllers
|
|||||||
clientDto.Meta.Add(new ProfileMeta()
|
clientDto.Meta.Add(new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Localization["WEBFRONT_CLIENT_META_MASKED"],
|
Key = Localization["WEBFRONT_CLIENT_META_MASKED"],
|
||||||
Value = client.Masked ? Localization["WEBFRONT_CLIENT_META_TRUE"]: Localization["WEBFRONT_CLIENT_META_FALSE"],
|
Value = client.Masked ? Localization["WEBFRONT_CLIENT_META_TRUE"] : Localization["WEBFRONT_CLIENT_META_FALSE"],
|
||||||
Sensitive = true,
|
Sensitive = true,
|
||||||
When = DateTime.MinValue
|
When = DateTime.MinValue
|
||||||
});
|
});
|
||||||
@ -94,7 +95,9 @@ namespace WebfrontCore.Controllers
|
|||||||
{
|
{
|
||||||
var admins = (await Manager.GetClientService().GetPrivilegedClients())
|
var admins = (await Manager.GetClientService().GetPrivilegedClients())
|
||||||
.Where(a => a.Active)
|
.Where(a => a.Active)
|
||||||
.OrderByDescending(a => a.Level);
|
.OrderByDescending(a => a.Level).ThenByDescending(a => a.LastConnection)
|
||||||
|
.GroupBy(a => a.AliasLinkId).Select(a => a.First());
|
||||||
|
|
||||||
var adminsDict = new Dictionary<SharedLibraryCore.Objects.Player.Permission, IList<ClientInfo>>();
|
var adminsDict = new Dictionary<SharedLibraryCore.Objects.Player.Permission, IList<ClientInfo>>();
|
||||||
|
|
||||||
foreach (var admin in admins)
|
foreach (var admin in admins)
|
||||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
|
|
||||||
@ -21,6 +22,11 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
public IActionResult Error()
|
public IActionResult Error()
|
||||||
{
|
{
|
||||||
|
var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
|
||||||
|
Manager.GetLogger().WriteError($"[Webfront] {exceptionFeature.Error.Message}");
|
||||||
|
Manager.GetLogger().WriteDebug(exceptionFeature.Path);
|
||||||
|
Manager.GetLogger().WriteDebug(exceptionFeature.Error.StackTrace);
|
||||||
|
|
||||||
ViewBag.Description = Localization["WEBFRONT_ERROR_DESC"];
|
ViewBag.Description = Localization["WEBFRONT_ERROR_DESC"];
|
||||||
ViewBag.Title = Localization["WEBFRONT_ERROR_TITLE"];
|
ViewBag.Title = Localization["WEBFRONT_ERROR_TITLE"];
|
||||||
return View();
|
return View();
|
||||||
|
@ -13,7 +13,6 @@ namespace WebfrontCore.Controllers
|
|||||||
[ResponseCache(NoStore = true, Duration = 0)]
|
[ResponseCache(NoStore = true, Duration = 0)]
|
||||||
public IActionResult ClientActivity(int id)
|
public IActionResult ClientActivity(int id)
|
||||||
{
|
{
|
||||||
|
|
||||||
var s = Manager.GetServers().FirstOrDefault(s2 => s2.GetHashCode() == id);
|
var s = Manager.GetServers().FirstOrDefault(s2 => s2.GetHashCode() == id);
|
||||||
if (s == null)
|
if (s == null)
|
||||||
return View("Error", "Invalid server!");
|
return View("Error", "Invalid server!");
|
||||||
@ -27,14 +26,15 @@ namespace WebfrontCore.Controllers
|
|||||||
ClientCount = s.ClientNum,
|
ClientCount = s.ClientNum,
|
||||||
MaxClients = s.MaxClients,
|
MaxClients = s.MaxClients,
|
||||||
GameType = s.Gametype,
|
GameType = s.Gametype,
|
||||||
Players = s.Players.Where(p => p != null).Select(p => new PlayerInfo
|
Players = s.GetPlayersAsList()
|
||||||
|
.Select(p => new PlayerInfo
|
||||||
{
|
{
|
||||||
Name = p.Name,
|
Name = p.Name,
|
||||||
ClientId = p.ClientId,
|
ClientId = p.ClientId,
|
||||||
Level = p.Level.ToString(),
|
Level = p.Level.ToString(),
|
||||||
LevelInt = (int)p.Level
|
LevelInt = (int)p.Level
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
ChatHistory = s.ChatHistory.OrderBy(c => c.Time).Take((int)Math.Ceiling(s.ClientNum / 2.0)).ToArray(),
|
ChatHistory = s.ChatHistory,
|
||||||
PlayerHistory = s.PlayerHistory.ToArray(),
|
PlayerHistory = s.PlayerHistory.ToArray(),
|
||||||
};
|
};
|
||||||
return PartialView("_ClientActivity", serverInfo);
|
return PartialView("_ClientActivity", serverInfo);
|
||||||
|
@ -19,7 +19,7 @@ namespace WebfrontCore.ViewComponents
|
|||||||
MaxClients = s.MaxClients,
|
MaxClients = s.MaxClients,
|
||||||
GameType = s.Gametype,
|
GameType = s.Gametype,
|
||||||
PlayerHistory = s.PlayerHistory.ToArray(),
|
PlayerHistory = s.PlayerHistory.ToArray(),
|
||||||
Players = s.Players.Where(p => p != null)
|
Players = s.GetPlayersAsList()
|
||||||
.Select(p => new PlayerInfo()
|
.Select(p => new PlayerInfo()
|
||||||
{
|
{
|
||||||
Name = p.Name,
|
Name = p.Name,
|
||||||
@ -27,7 +27,7 @@ namespace WebfrontCore.ViewComponents
|
|||||||
Level = p.Level.ToString(),
|
Level = p.Level.ToString(),
|
||||||
LevelInt = (int)p.Level
|
LevelInt = (int)p.Level
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
ChatHistory = s.ChatHistory.ToArray(),
|
ChatHistory = s.ChatHistory,
|
||||||
Online = !s.Throttled
|
Online = !s.Throttled
|
||||||
}).ToList();
|
}).ToList();
|
||||||
return View("_List", serverInfo);
|
return View("_List", serverInfo);
|
||||||
|
@ -31,13 +31,13 @@
|
|||||||
<div id="profile_aliases_btn" class="oi oi-caret-bottom h3 ml-0 ml-md-2"></div>
|
<div id="profile_aliases_btn" class="oi oi-caret-bottom h3 ml-0 ml-md-2"></div>
|
||||||
|
|
||||||
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
||||||
(SharedLibraryCore.Objects.Player.Permission)Model.LevelInt != SharedLibraryCore.Objects.Player.Permission.Banned)
|
(SharedLibraryCore.Objects.Player.Permission)Model.LevelInt != SharedLibraryCore.Objects.Player.Permission.Banned)
|
||||||
{
|
{
|
||||||
<div id="profile_action_ban_btn" class="profile-action oi oi-lock-unlocked text-success h3 ml-2" title="Ban Client" data-action="ban" aria-hidden="true"></div>
|
<div id="profile_action_ban_btn" class="profile-action oi oi-lock-unlocked text-success h3 ml-2" title="Ban Client" data-action="ban" aria-hidden="true"></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
||||||
(SharedLibraryCore.Objects.Player.Permission)Model.LevelInt == SharedLibraryCore.Objects.Player.Permission.Banned)
|
(SharedLibraryCore.Objects.Player.Permission)Model.LevelInt == SharedLibraryCore.Objects.Player.Permission.Banned)
|
||||||
{
|
{
|
||||||
<div id="profile_action_unban_btn" class="profile-action oi oi-lock-locked text-danger h3 ml-2" title="Unban Client" data-action="unban" aria-hidden="true"></div>
|
<div id="profile_action_unban_btn" class="profile-action oi oi-lock-locked text-danger h3 ml-2" title="Unban Client" data-action="unban" aria-hidden="true"></div>
|
||||||
}
|
}
|
||||||
@ -45,10 +45,13 @@
|
|||||||
|
|
||||||
<div id="profile_aliases" class="pr-0 pr-sm-4 pb-2 mb-2 text-muted order-0">
|
<div id="profile_aliases" class="pr-0 pr-sm-4 pb-2 mb-2 text-muted order-0">
|
||||||
@{
|
@{
|
||||||
<span class="text-secondary">@Model.NetworkId.ToString("X")</span> <br />
|
foreach (var linked in Model.LinkedAccounts)
|
||||||
|
{
|
||||||
|
@Html.ActionLink(linked.Value.ToString("X"), "ProfileAsync", "Client", new { id = linked.Key}, new { @class = "link-inverse" })<br/>
|
||||||
|
}
|
||||||
foreach (string alias in Model.Aliases)
|
foreach (string alias in Model.Aliases)
|
||||||
{
|
{
|
||||||
@alias <br />
|
@alias<br />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ViewBag.Authorized)
|
if (ViewBag.Authorized)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
}
|
}
|
||||||
<div class="col-12 col-md-8 d-none d-md-block">
|
<div class="col-12 col-md-8 d-none d-md-block">
|
||||||
@{
|
@{
|
||||||
for (int i = 0; i < Model.ChatHistory.Length; i++)
|
for (int i = 0; i < Model.ChatHistory.Count; i++)
|
||||||
{
|
{
|
||||||
string message = @Model.ChatHistory[i].Message;
|
string message = @Model.ChatHistory[i].Message;
|
||||||
if (Model.ChatHistory[i].Message == "CONNECTED")
|
if (Model.ChatHistory[i].Message == "CONNECTED")
|
||||||
@ -47,13 +47,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (Model.ChatHistory.Length > 0)
|
@if (Model.ChatHistory.Count > 0)
|
||||||
{
|
{
|
||||||
<div class="w-100 border-bottom d-md-none d-block mt-1 mb-1"></div>
|
<div class="w-100 border-bottom d-md-none d-block mt-1 mb-1"></div>
|
||||||
}
|
}
|
||||||
<div class="col-12 col-md-8 d-md-none d-block text-left">
|
<div class="col-12 col-md-8 d-md-none d-block text-left">
|
||||||
@{
|
@{
|
||||||
for (int i = 0; i < Model.ChatHistory.Length; i++)
|
for (int i = 0; i < Model.ChatHistory.Count; i++)
|
||||||
{
|
{
|
||||||
string message = @Model.ChatHistory[i].Message;
|
string message = @Model.ChatHistory[i].Message;
|
||||||
if (Model.ChatHistory[i].Message == "CONNECTED")
|
if (Model.ChatHistory[i].Message == "CONNECTED")
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
@{
|
@{
|
||||||
Layout = null;
|
Layout = null;
|
||||||
ViewBag.Description += Model.Name + ", ";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="row server-header" id="server_header_@Model.ID">
|
<div class="row server-header" id="server_header_@Model.ID">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
<!--<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>-->
|
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
<TypeScriptToolsVersion>2.6</TypeScriptToolsVersion>
|
<TypeScriptToolsVersion>2.6</TypeScriptToolsVersion>
|
||||||
<PackageId>RaidMax.IW4MAdmin.WebfrontCore</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.WebfrontCore</PackageId>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user