Player search not showing duplicates anymore

removed extra information on player search
fixed kdr innaccuracy on profile page
shortened cache-length
This commit is contained in:
RaidMax 2018-02-16 22:24:03 -06:00
parent 2842d77948
commit c41949588c
19 changed files with 10840 additions and 253 deletions

View File

@ -367,6 +367,9 @@ xcopy /Y /I /E "$(SolutionDir)SharedLibrary\$(OutDir)*" "$(SolutionDir)Admin\Li
xcopy /Y /I /E "$(ProjectDir)webfront\*" "$(SolutionDir)BUILD\Webfront"
xcopy /Y /I /E "$(SolutionDir)Admin\Config\*" "$(SolutionDir)BUILD\Config"
if $(ConfigurationName) == Release-Nightly powershell.exe -file "$(SolutionDir)DEPLOY\publish_nightly.ps1" 1.6
if $(ConfigurationName) == Release-Stable powershell.exe -file "$(SolutionDir)DEPLOY\publish_stable.ps1" 1.6
</PostBuildEvent>
</PropertyGroup>

View File

@ -66,7 +66,7 @@ namespace IW4MAdmin
requestedPage.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedPage.content, Newtonsoft.Json.Formatting.Indented);
#endif
string maxAge = requestedPage.contentType == "application/json" ? "0" : "31536000";
string maxAge = requestedPage.contentType == "application/json" ? "0" : "21600";
var headers = new HttpResponseHead()
{
Status = "200 OK",

10760
Admin/Lib/Newtonsoft.Json.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -231,9 +231,6 @@ namespace IW4MAdmin
public void Stop()
{
// tell threads it's time to stop
// foreach (var status in TaskStatuses)
// status.TokenSrc.Cancel();
Running = false;
}

View File

@ -132,6 +132,7 @@ namespace IW4MAdmin
{
Player Leaving = Players[cNum];
Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds;
Leaving.LastConnection = DateTime.UtcNow;
await Manager.GetClientService().Update(Leaving);
Logger.WriteInfo($"Client {Leaving} disconnecting...");
@ -333,9 +334,6 @@ namespace IW4MAdmin
async Task<int> PollPlayersAsync()
{
#if DEBUG
// return Players.Where(p => p != null).Count();
#endif
var CurrentPlayers = await this.GetStatusAsync();
for (int i = 0; i < Players.Count; i++)
@ -344,7 +342,6 @@ namespace IW4MAdmin
await RemovePlayer(i);
}
//polledPlayer.ClientNumber < 0 || polledPlayer.ClientNumber > (Players.Count - 1) || polledPlayer.Ping < 1 || polledPlayer.Ping == 999
for (int i = 0; i < CurrentPlayers.Count; i++)
{
await AddPlayer(CurrentPlayers[i]);
@ -586,7 +583,7 @@ namespace IW4MAdmin
}
LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php");
#endif
Logger.WriteInfo("Log file is " + logPath);
Logger.WriteInfo($"Log file is {logPath}");
#if !DEBUG
Broadcast("IW4M Admin is now ^2ONLINE");
}
@ -623,13 +620,7 @@ namespace IW4MAdmin
else if (E.Type == Event.GType.Script)
{
/* if (E.Origin == E.Target)// suicide/falling
await ExecuteEvent(new Event(Event.GType.Death, E.Data, E.Target, E.Target, this));
else
{*/
await ExecuteEvent(new Event(Event.GType.Kill, E.Data, E.Origin, E.Target, this));
//await ExecuteEvent(new Event(Event.GType.Death, E.Data, E.Target, E.Origin, this));
// }
}
if (E.Type == Event.GType.Say && E.Data.Length >= 2)

View File

@ -215,7 +215,7 @@ namespace IW4MAdmin
return "/_servers";
}
public async Task<HttpResponse> GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
public async Task<HttpResponse> GetPage(NameValueCollection querySet, IDictionary<string, string> headers)
{
var info = new List<ServerInfo>();
foreach (Server S in ApplicationManager.GetInstance().Servers)
@ -234,8 +234,8 @@ namespace IW4MAdmin
};
int ip = querySet["ip"].ConvertToIP();
//var admins = (await (ApplicationManager.GetInstance().GetClientService() as ClientService).GetPrivilegedClients());
bool authed = true; //admins.FirstOrDefault(a => a.IPAddress == ip) != null;
// var admins = (await (ApplicationManager.GetInstance().GetClientService() as ClientService).GetPrivilegedClients());
bool authed = (await (ApplicationManager.GetInstance().GetClientService() as ClientService).IsAuthenticated(ip));//admins.FirstOrDefault(a => a.IPAddress == ip) != null;
// if (ip == 16777343)
// authed = true;
@ -759,7 +759,7 @@ namespace IW4MAdmin
};
// int ip = querySet["IP"].ConvertToIP();
//var admins = (await (ApplicationManager.GetInstance().GetClientService() as ClientService).GetPrivilegedClients());
var admins = (await (ApplicationManager.GetInstance().GetClientService() as ClientService).GetPrivilegedClients());
// bool authed = admins.FirstOrDefault(c => c.IPAddress == ip) != null || ip == 16777343;
bool authed = true;
bool recent = false;
@ -840,9 +840,6 @@ namespace IW4MAdmin
.ToList();
}
//eachPlayer.playerAliases = eachPlayer.playerAliases.Distinct().ToList();
// eachPlayer.playerIPs = eachPlayer.playerIPs.Distinct().ToList();
eachPlayer.playerConnections = pp.Connections;
pInfo.Add(eachPlayer);

View File

@ -157,6 +157,9 @@
}
#profile_aliases_btn {
position: absolute;
top: auto;
margin-top: 0.7em;
font-size: 0.5em;
color: rgb(0, 122, 204);
cursor: pointer;
@ -171,6 +174,8 @@
position: relative;
display: none;
top: 0.2em;
font-size: 0.5em;
line-height: 1.2em;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1">
@ -296,7 +301,7 @@
<div id="profile_info" class="text-center text-sm-left pr-4 pl-4">
<div id="profile_name">
<span class="client-name"><span id="profile_aliases_btn" class="oi oi-caret-bottom pl-2"></span></span>
<div id="profile_aliases" class="pr-4 pb-2 mb-2 text-muted"></div>
<div id="profile_aliases" class="pr-0 pr-sm-4 pb-2 mb-2 text-muted"></div>
</div>
<div id="profile_level" class="text-muted">
<span>_</span>

Binary file not shown.

View File

@ -2,11 +2,11 @@
<script>
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
var curFrom = 0;
@ -27,45 +27,18 @@
}
}
function formatHidden(data, authed) {
var p = "<div class=\"hiddenWrapper\"><span>Expand</span><div class=\"hiddenElements\">";
if (authed) {
if (data == undefined || data.length == 0)
p += "Not Loaded"
$.each(data, function (i, dat) {
p += "<span>" + escapeHtml(dat) + "</span><br/>"
})
}
else
p += "Hidden";
p += "</div></div>"
return p;
}
function printPlayer(player, i) {
var p = "";
p +=
"<div class=\"playerInfo table alternate_" + i % 2 + "\"> \
"<div class=\"playerInfo table alternate_" + i % 2 + "\"> \
<div class=\"tableCell\"><a href=\"/profile?id=" + player['playerID'] + "\">" + escapeHtml(player['playerName']) + "</a></div> \
<div class=\"tableCell\">" + formatHidden(player['playerAliases'], player.authed) + "</div> \
<div class=\"tableCell\">" + formatHidden(player['playerIPs'], player.authed) + "</div> \
<div class=\"tableCell\">" + getColorForLevel(player['playerLevel'], player['playerLevel']) + "</div> \
<div class=\"tableCell\">" + player['playerConnections'] + "</div>";
<div class=\"tableCell\">" + getColorForLevel(player['playerLevel'], player['playerLevel']) + "</div>";
p +=
"<div class=\"tableCell\" style='width: 2em;'><a href=\"/chat?clientid=" + player.playerID + "\"><i class=\"fa fa-comments\" aria-hidden=\"true\"></i></a></div>"
p +=
"<div class=\"tableCell alignRight\">" + checkJustNow(player['LastSeen']) + "</div> \
"<div class=\"tableCell alignRight\">" + checkJustNow(player['LastSeen']) + " ago</div> \
</div>";
$("#playersTable").append(p);
}
function getPlayer(ident, identValue) {
@ -76,7 +49,11 @@
$.each(result, function (i, player) {
printPlayer(player, i);
});
}).done(function (data) { $(".loader").fadeOut(); });
}).done(function (data) {
$(".loader").fadeOut();
}).fail(function () {
$(".loader").fadeOut();
});
}
function getRecentPlayers(offset) {
@ -88,7 +65,7 @@
printPlayer(player, i);
});
}).done(function (data) { $(".loader").fadeOut(); })
.error(function (data) { $(".loader").fadeOut(); })
.error(function (data) { $(".loader").fadeOut(); })
}
$(document).ready(function () {
@ -114,11 +91,7 @@
<div class="contentHeader table">
<div class="contentColumn tableCell">Name</div>
<div class="contentColumn tableCell">Aliases</div>
<div class="contentColumn tableCell">IP</div>
<div class="contentColumn tableCell">Level</div>
<div class="contentColumn tableCell">Connections</div>
<div class="contentColumn tableCell" style="width: 1em;">Chat</div>
<div class="contentColumn tableCell alignRight">Last Seen</div>
</div>
<div id="playersTable">

View File

@ -90,7 +90,7 @@ namespace StatsPlugin
int kills = clientStats.Sum(c => c.Kills);
int deaths = clientStats.Sum(c => c.Deaths);
double kdr = Math.Round(clientStats.Sum(c => c.KDR) / clientStats.Count, 2);
double kdr = Math.Round(kills / (double)deaths, 2);
double skill = Math.Round(clientStats.Sum(c => c.Skill) / clientStats.Count, 2);
return new List<ProfileMeta>()

View File

@ -87,7 +87,6 @@
<Compile Include="Pages\LiveStatsJson.cs" />
<Compile Include="Pages\WordCloudJson.cs" />
<Compile Include="Plugin.cs" />
<None Include="_Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -1,178 +0,0 @@
using SharedLibrary;
using SharedLibrary.Helpers;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using SharedLibrary.Objects;
using System.Linq;
using StatsPlugin.Models;
namespace StatsPlugin
{
/// <summary>
/// Each server runs from the same plugin ( for easier reloading and reduced memory usage ).
/// So, to have multiple stat tracking, we must store a stat struct for each server
/// </summary>
public class Stats : SharedLibrary.Interfaces.IPlugin
{
public static SharedLibrary.Interfaces.IManager ManagerInstance;
public static int MAX_KILLEVENTS = 1000;
public static Dictionary<int, ServerStatInfo> ServerStats { get; private set; }
public static SharedLibrary.Services.GenericService<Models.EFClientStatistics> ClientStatsSvc;
public static SharedLibrary.Services.GenericService<Models.EFServer> ServerSvc;
public class ServerStatInfo
{
public ServerStatInfo()
{
KillQueue = new Queue<KillInfo>();
ServerStartTime = DateTime.Now;
}
public DateTime ServerStartTime { get; private set; }
public DateTime RoundStartTime { get; set; }
public string Uptime => Utilities.GetTimePassed(ServerStartTime, false);
public string ElapsedRoundTime => Utilities.GetTimePassed(RoundStartTime);
private Queue<KillInfo> KillQueue { get; set; }
public Queue<KillInfo> GetKillQueue() { return KillQueue; }
}
public string Name => "Basic Stats";
public float Version => 1.1f;
public string Author => "RaidMax";
public async Task OnLoadAsync(SharedLibrary.Interfaces.IManager manager)
{
statLists = new List<StatTracking>();
ServerStats = new Dictionary<int, ServerStatInfo>();
ManagerInstance = manager;
WebService.PageList.Add(new StatsPage());
WebService.PageList.Add(new KillStatsJSON());
WebService.PageList.Add(new Chat.WordCloudJSON());
WebService.PageList.Add(new Chat.ClientChatJSON());
WebService.PageList.Add(new Chat.ChatPage());
ManagerInstance.GetMessageTokens().Add(new MessageToken("TOTALKILLS", GetTotalKills));
ManagerInstance.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", GetTotalPlaytime));
ClientStatsSvc = new SharedLibrary.Services.GenericService<Models.EFClientStatistics>();
ServerSvc = new SharedLibrary.Services.GenericService<Models.EFServer>();
ChatDB = new ChatDatabase("Database/ChatHistory.rm", ManagerInstance.GetLogger());
try
{
var minimapConfig = MinimapConfig.Read("Config/minimaps.cfg");
}
catch (SharedLibrary.Exceptions.SerializeException e)
{
MinimapConfig.Write("Config/minimaps.cfg", MinimapConfig.IW4Minimaps());
}
}
public async Task OnUnloadAsync()
{
statLists.Clear();
}
public async Task OnTickAsync(Server S)
{
return;
}
public async Task OnEventAsync(Event E, Server S)
{
try
{
if (E.Type == Event.GType.Start)
{
statLists.Add(new StatTracking(S.GetPort()));
ServerStats.Add(S.GetPort(), new ServerStatInfo());
var config = new ConfigurationManager(S);
if (config.GetProperty("EnableTrusted") == null)
config.AddProperty(new KeyValuePair<string, object>("EnableTrusted", true));
}
if (E.Type == Event.GType.Stop)
{
statLists.RemoveAll(s => s.Port == S.GetPort());
ServerStats.Remove(S.GetPort());
}
if (E.Type == Event.GType.Connect)
{
ResetCounters(E.Origin.ClientNumber, S.GetPort());
var serverStats = statLists.First(s => s.Port == E.Owner.GetPort());
var clientStats = await ClientStatsSvc.Get(new int[] { E.Origin.ClientNumber });
var server = (await ServerSvc.Find(s => s.Port == E.Owner.GetPort())).First();
// create stats if not exist already
serverStats.clientStats[E.Origin.ClientNumber] = clientStats ?? await ClientStatsSvc.Create(new Models.EFClientStatistics()
{
Active = false,
Client = E.Target,
ClientId = E.Target.ClientId,
Deaths = 0,
KDR = 0,
Kills = 0,
Server = (await ServerSvc.Find(s => s.Port == E.Owner.GetPort())).First(),
ServerId = server.ServerId,
Skill = 0,
SPM = 0,
});
/* var config = new ConfigurationManager(E.Owner);
if (!(bool)config.GetProperty("EnableTrusted"))
return;
PlayerStats checkForTrusted = statLists.Find(x => x.Port == S.GetPort()).playerStats.GetStats(E.Origin);
//todo: move this out of here!!
if (checkForTrusted.TotalPlayTime >= 4320 && E.Origin.Level < Player.Permission.Trusted && E.Origin.Level != Player.Permission.Flagged)
{
E.Origin.Level = Player.Permission.Trusted;
await E.Owner.Manager.GetDatabase().UpdateClient(E.Origin);
await E.Origin.Tell("Congratulations, you are now a ^5trusted ^7player! Type ^5!help ^7to view new commands.");
await E.Origin.Tell("You earned this by playing for ^53 ^7full days!");
}*/
}
if (E.Type == Event.GType.MapEnd || E.Type == Event.GType.Stop)
{
foreach (Player P in S.GetPlayersAsList())
{
if (P == null)
continue;
CalculateAndSaveSkill(P, statLists.Find(x => x.Port == S.GetPort()));
ResetCounters(P.ClientNumber, S.GetPort());
E.Owner.Logger.WriteInfo($"Updated skill for {P}");
//E.Owner.Log.Write(String.Format("\r\nJoin: {0}\r\nInactive Minutes: {1}\r\nnewPlayTime: {2}\r\nnewSPM: {3}\r\nkdrWeight: {4}\r\nMultiplier: {5}\r\nscoreWeight: {6}\r\nnewSkillFactor: {7}\r\nprojectedNewSkill: {8}\r\nKills: {9}\r\nDeaths: {10}", connectionTime[P.ClientNumber].ToShortTimeString(), inactiveMinutes[P.ClientNumber], newPlayTime, newSPM, kdrWeight, Multiplier, scoreWeight, newSkillFactor, disconnectStats.Skill, disconnectStats.Kills, disconnectStats.Deaths));
}
}
if (E.Type == Event.GType.MapChange)
{
ServerStats[S.GetPort()].GetKillQueue().Clear();
ServerStats[S.GetPort()].RoundStartTime = DateTime.Now;
}
}
}

View File

@ -942,7 +942,7 @@ namespace SharedLibrary.Commands
inactiveUsers.ForEach(c => c.Level = Player.Permission.User);
await context.SaveChangesAsync();
}
await E.Origin.Tell($"Pruned inactive {inactiveUsers.Count} privileged users");
await E.Origin.Tell($"Pruned {inactiveUsers.Count} inactive privileged users");
}
}

View File

@ -46,7 +46,6 @@ namespace SharedLibrary.Database
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
// todo: custom load DBSets from plugins
// https://aleemkhan.wordpress.com/2013/02/28/dynamically-adding-dbset-properties-in-dbcontext-for-entity-framework-code-first/
foreach (string dllPath in System.IO.Directory.GetFiles($"{Environment.CurrentDirectory}{System.IO.Path.DirectorySeparatorChar}Plugins"))
{

View File

@ -10,7 +10,7 @@ namespace SharedLibrary
public class RemoteFile : IFile
{
string Location;
string[] FileCache;
string[] FileCache = new string[0];
public RemoteFile(string location) : base(string.Empty)
{
@ -25,7 +25,7 @@ namespace SharedLibrary
public override string[] Tail(int lineCount)
{
Retrieve();
// Retrieve();
return FileCache;
}

View File

@ -194,6 +194,25 @@ namespace SharedLibrary.Services
.ToListAsync();
}
public async Task<bool> IsAuthenticated(int clientIP)
{
using (var context = new DatabaseContext())
{
context.Configuration.LazyLoadingEnabled = false;
context.Configuration.ProxyCreationEnabled = false;
context.Configuration.AutoDetectChangesEnabled = false;
var iqMatching = from alias in context.Aliases
where alias.IPAddress == clientIP
join client in context.Clients
on alias.LinkId equals client.AliasLinkId
where client.Level > Player.Permission.Trusted
select client;
return (await iqMatching.CountAsync()) > 0;
}
}
public async Task<IList<EFClient>> GetPrivilegedClients()
{
using (var context = new DatabaseContext())
@ -228,6 +247,7 @@ namespace SharedLibrary.Services
.AsNoTracking()
on alias.LinkId equals client.AliasLinkId
select client)
.Distinct()
.Include(c => c.CurrentAlias)
.Include(c => c.AliasLink.Children);

View File

@ -77,7 +77,7 @@
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
@ -152,6 +152,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>move "$(TargetDir)Newtonsoft.Json.dll" "$(TargetDir)lib\Newtonsoft.Json.dll"
move "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)BUILD\Lib\Newtonsoft.Json.dll"
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\lib"
copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\lib"
copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)BUILD\lib"
@ -159,7 +160,10 @@ copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)Admin\lib"
if not exist "$(TargetDir)x86" md "$(TargetDir)x86"
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\x86\*.*" "$(TargetDir)x86"
if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64"
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64"</PostBuildEvent>
xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64"
xcopy /Y /I /E "$(TargetDir)*" "$(SolutionDir)BUILD\Lib"</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PreBuildEvent>if exist "$(SolutionDir)BUILD\Plugins" rmdir /Q /S "$(SolutionDir)BUILD\Plugins"

View File

@ -199,12 +199,29 @@ namespace SharedLibrary
public static long ConvertLong(this string str)
{
return Int64.Parse(str, System.Globalization.NumberStyles.HexNumber);
try
{
return Int64.Parse(str, System.Globalization.NumberStyles.HexNumber);
}
catch (FormatException)
{
return -1;
}
}
public static int ConvertToIP(this string str)
{
return BitConverter.ToInt32(System.Net.IPAddress.Parse(str).GetAddressBytes(), 0);
try
{
return BitConverter.ToInt32(System.Net.IPAddress.Parse(str).GetAddressBytes(), 0);
}
catch (FormatException)
{
return 0;
}
}
public static string ConvertIPtoString(this int ip)

View File

@ -14,7 +14,7 @@ Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vD
{
victim = self;
_attacker = attacker;
if (!isDefined(attacker) || !isPlayer(attacker))
if (!isDefined(attacker))
_attacker = victim;
logPrint("ScriptKill;" + _attacker.guid + ";" + victim.guid + ";" + _attacker.origin + ";" + victim.origin + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + "\n");