update project to .net core 2.1.5

got rid of "threadsafe" stats service in stats plugin
This commit is contained in:
RaidMax 2018-10-07 21:34:30 -05:00
parent c8366a22e5
commit b289917319
24 changed files with 364 additions and 455 deletions

View File

@ -3,9 +3,10 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish> <MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
<PackageId>RaidMax.IW4MAdmin.Application</PackageId> <PackageId>RaidMax.IW4MAdmin.Application</PackageId>
<Version>2.1.9.4</Version> <Version>2.1.9.5</Version>
<Authors>RaidMax</Authors> <Authors>RaidMax</Authors>
<Company>Forever None</Company> <Company>Forever None</Company>
<Product>IW4MAdmin</Product> <Product>IW4MAdmin</Product>
@ -30,8 +31,8 @@
<PropertyGroup> <PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection> <ServerGarbageCollection>true</ServerGarbageCollection>
<TieredCompilation>true</TieredCompilation> <TieredCompilation>true</TieredCompilation>
<AssemblyVersion>2.1.9.4</AssemblyVersion> <AssemblyVersion>2.1.9.5</AssemblyVersion>
<FileVersion>2.1.9.4</FileVersion> <FileVersion>2.1.9.5</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -78,7 +79,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" /> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent"> <Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View File

@ -20,11 +20,37 @@ namespace IW4MAdmin.Application
readonly string FileName; readonly string FileName;
readonly SemaphoreSlim OnLogWriting; readonly SemaphoreSlim OnLogWriting;
static readonly short MAX_LOG_FILES = 10;
public Logger(string fn) public Logger(string fn)
{ {
FileName = Path.Join("Log", $"{fn}-{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.log"); FileName = Path.Join("Log", $"{fn}.log");
OnLogWriting = new SemaphoreSlim(1,1); OnLogWriting = new SemaphoreSlim(1, 1);
RotateLogs();
}
/// <summary>
/// rotates logs when log is initialized
/// </summary>
private void RotateLogs()
{
string maxLog = FileName + MAX_LOG_FILES;
if (File.Exists(maxLog))
{
File.Delete(maxLog);
}
for (int i = MAX_LOG_FILES - 1; i >= 0; i--)
{
string logToMove = i == 0 ? FileName : FileName + i;
string movedLogName = FileName + (i + 1);
if (File.Exists(logToMove))
{
File.Move(logToMove, movedLogName);
}
}
} }
void Write(string msg, LogType type) void Write(string msg, LogType type)
@ -41,17 +67,25 @@ namespace IW4MAdmin.Application
catch (Exception) { } catch (Exception) { }
string LogLine = $"[{DateTime.Now.ToString("MM.dd.yyy HH:mm:ss.fff")}] - {stringType}: {msg}"; string LogLine = $"[{DateTime.Now.ToString("MM.dd.yyy HH:mm:ss.fff")}] - {stringType}: {msg}";
try
{
#if DEBUG #if DEBUG
// lets keep it simple and dispose of everything quickly as logging wont be that much (relatively) // lets keep it simple and dispose of everything quickly as logging wont be that much (relatively)
Console.WriteLine(LogLine);
Console.WriteLine(LogLine); File.AppendAllText(FileName, LogLine + Environment.NewLine);
File.AppendAllText(FileName, LogLine + Environment.NewLine);
#else #else
if (type == LogType.Error || type == LogType.Verbose) if (type == LogType.Error || type == LogType.Verbose)
Console.WriteLine(LogLine); Console.WriteLine(LogLine);
//if (type != LogType.Debug) //if (type != LogType.Debug)
File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}"); File.AppendAllText(FileName, $"{LogLine}{Environment.NewLine}");
#endif #endif
}
catch (Exception ex)
{
Console.WriteLine("Well.. It looks like your machine can't event write to the log file. That's something else...");
Console.WriteLine(ex.GetExceptionInfo());
}
OnLogWriting.Release(1); OnLogWriting.Release(1);
} }

View File

@ -106,7 +106,7 @@ namespace IW4MAdmin.Application
var consoleTask = Task.Run(async () => var consoleTask = Task.Run(async () =>
{ {
String userInput; String userInput;
Player Origin = Utilities.IW4MAdminClient; Player Origin = Utilities.IW4MAdminClient(ServerManager.Servers[0]);
do do
{ {
@ -123,7 +123,6 @@ namespace IW4MAdmin.Application
if (userInput?.Length > 0) if (userInput?.Length > 0)
{ {
Origin.CurrentServer = ServerManager.Servers[0];
GameEvent E = new GameEvent() GameEvent E = new GameEvent()
{ {
Type = GameEvent.EventType.Command, Type = GameEvent.EventType.Command,

View File

@ -205,8 +205,7 @@ namespace IW4MAdmin
if (currentBan != null) if (currentBan != null)
{ {
Logger.WriteInfo($"Banned client {player} trying to connect..."); Logger.WriteInfo($"Banned client {player} trying to connect...");
var autoKickClient = Utilities.IW4MAdminClient; var autoKickClient = Utilities.IW4MAdminClient(this);
autoKickClient.CurrentServer = this;
// the player is permanently banned // the player is permanently banned
if (currentBan.Type == Penalty.PenaltyType.Ban) if (currentBan.Type == Penalty.PenaltyType.Ban)
@ -911,7 +910,7 @@ namespace IW4MAdmin
{ {
if (Target.Warnings >= 4) if (Target.Warnings >= 4)
{ {
Target.Kick(loc["SERVER_WARNLIMT_REACHED"], Utilities.IW4MAdminClient); Target.Kick(loc["SERVER_WARNLIMT_REACHED"], Utilities.IW4MAdminClient(this));
return; return;
} }

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
</PropertyGroup> </PropertyGroup>
@ -17,7 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App"/> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.Login</PackageId> <PackageId>RaidMax.IW4MAdmin.Plugins.Login</PackageId>
@ -21,7 +22,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App"/> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.ProfanityDeterment</PackageId> <PackageId>RaidMax.IW4MAdmin.Plugins.ProfanityDeterment</PackageId>
@ -19,7 +20,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App"/> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -28,7 +28,6 @@ var plugin = {
var re = cl.GetAsync('https://api.xdefcon.com/proxy/check/?ip=' + origin.IPAddressString).Result; var re = cl.GetAsync('https://api.xdefcon.com/proxy/check/?ip=' + origin.IPAddressString).Result;
var co = re.Content; var co = re.Content;
var parsedJSON = JSON.parse(co.ReadAsStringAsync().Result); var parsedJSON = JSON.parse(co.ReadAsStringAsync().Result);
// todo: does this work as expected now?
co.Dispose(); co.Dispose();
re.Dispose(); re.Dispose();
cl.Dispose(); cl.Dispose();
@ -39,11 +38,7 @@ var plugin = {
if (usingVPN) { if (usingVPN) {
this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')'); this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')');
var library = importNamespace('SharedLibraryCore'); origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], _IW4MAdminClient);
var kickOrigin = new library.Objects.Player();
kickOrigin.ClientId = 1;
kickOrigin.CurrentServer = origin.CurrentServer;
origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], kickOrigin);
} }
}, },

View File

@ -6,6 +6,8 @@ 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.Database;
using Microsoft.EntityFrameworkCore;
namespace IW4MAdmin.Plugins.Stats.Commands namespace IW4MAdmin.Plugins.Stats.Commands
{ {
@ -17,23 +19,30 @@ namespace IW4MAdmin.Plugins.Stats.Commands
{ {
if (E.Origin.ClientNumber >= 0) if (E.Origin.ClientNumber >= 0)
{ {
var svc = new SharedLibraryCore.Services.GenericRepository<EFClientStatistics>();
int serverId = E.Owner.GetHashCode(); int serverId = E.Owner.GetHashCode();
var stats = svc.Find(s => s.ClientId == E.Origin.ClientId && s.ServerId == serverId).First();
stats.Deaths = 0; EFClientStatistics clientStats;
stats.Kills = 0; using (var ctx = new DatabaseContext(disableTracking: true))
stats.SPM = 0.0; {
stats.Skill = 0.0; clientStats = await ctx.Set<EFClientStatistics>()
stats.TimePlayed = 0; .Where(s => s.ClientId == E.Origin.ClientId && s.ServerId == serverId)
// todo: make this more dynamic .FirstAsync();
stats.EloRating = 200.0;
// reset the cached version clientStats.Deaths = 0;
Plugin.Manager.ResetStats(E.Origin.ClientId, E.Owner.GetHashCode()); clientStats.Kills = 0;
clientStats.SPM = 0.0;
clientStats.Skill = 0.0;
clientStats.TimePlayed = 0;
// todo: make this more dynamic
clientStats.EloRating = 200.0;
// fixme: this doesn't work properly when another context exists // reset the cached version
await svc.SaveChangesAsync(); Plugin.Manager.ResetStats(E.Origin.ClientId, E.Owner.GetHashCode());
// fixme: this doesn't work properly when another context exists
await ctx.SaveChangesAsync();
}
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]); E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]);
} }

View File

@ -7,6 +7,8 @@ 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.Database;
using Microsoft.EntityFrameworkCore;
namespace IW4MAdmin.Plugins.Stats.Commands namespace IW4MAdmin.Plugins.Stats.Commands
{ {
@ -39,19 +41,21 @@ namespace IW4MAdmin.Plugins.Stats.Commands
} }
} }
var clientStats = new GenericRepository<EFClientStatistics>();
int serverId = E.Owner.GetHashCode(); int serverId = E.Owner.GetHashCode();
if (E.Target != null) using (var ctx = new DatabaseContext(disableTracking: true))
{ {
pStats = (await clientStats.FindAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId)).First(); if (E.Target != null)
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}"; {
} pStats = (await ctx.Set<EFClientStatistics>().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId));
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}";
}
else else
{ {
pStats = (await clientStats.FindAsync(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId)).First(); pStats = (await ctx.Set<EFClientStatistics>().FirstAsync((c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId)));
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}"; statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}";
}
} }
if (E.Message.IsBroadcastCommand()) if (E.Message.IsBroadcastCommand())

View File

@ -24,20 +24,20 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
public class StatManager public class StatManager
{ {
private ConcurrentDictionary<int, ServerStats> Servers; private ConcurrentDictionary<int, ServerStats> Servers;
private ConcurrentDictionary<int, ThreadSafeStatsService> ContextThreads;
private ILogger Log; private ILogger Log;
private IManager Manager; private readonly IManager Manager;
private readonly SemaphoreSlim OnProcessingPenalty; private readonly SemaphoreSlim OnProcessingPenalty;
private readonly SemaphoreSlim OnProcessingSensitive;
public StatManager(IManager mgr) public StatManager(IManager mgr)
{ {
Servers = new ConcurrentDictionary<int, ServerStats>(); Servers = new ConcurrentDictionary<int, ServerStats>();
ContextThreads = new ConcurrentDictionary<int, ThreadSafeStatsService>();
Log = mgr.GetLogger(0); Log = mgr.GetLogger(0);
Manager = mgr; Manager = mgr;
OnProcessingPenalty = new SemaphoreSlim(1, 1); OnProcessingPenalty = new SemaphoreSlim(1, 1);
OnProcessingSensitive = new SemaphoreSlim(1, 1);
} }
public EFClientStatistics GetClientStats(int clientId, int serverId) => Servers[serverId].PlayerStats[clientId]; public EFClientStatistics GetClientStats(int clientId, int serverId) => Servers[serverId].PlayerStats[clientId];
@ -188,36 +188,36 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
/// <param name="sv"></param> /// <param name="sv"></param>
public void AddServer(Server sv) public void AddServer(Server sv)
{ {
// insert the server if it does not exist
try try
{ {
int serverId = sv.GetHashCode(); int serverId = sv.GetHashCode();
var statsSvc = new ThreadSafeStatsService(); EFServer server;
ContextThreads.TryAdd(serverId, statsSvc);
var serverSvc = statsSvc.ServerSvc; using (var ctx = new DatabaseContext(disableTracking: true))
// get the server from the database if it exists, otherwise create and insert a new one
var server = statsSvc.ServerSvc.Find(c => c.ServerId == serverId).FirstOrDefault();
if (server == null)
{ {
server = new EFServer() var serverSet = ctx.Set<EFServer>();
{ // get the server from the database if it exists, otherwise create and insert a new one
Port = sv.GetPort(), server = serverSet.FirstOrDefault(c => c.ServerId == serverId);
Active = true,
ServerId = serverId
};
serverSvc.Insert(server); if (server == null)
{
server = new EFServer()
{
Port = sv.GetPort(),
Active = true,
ServerId = serverId
};
server = serverSet.Add(server).Entity;
// this doesn't need to be async as it's during initialization
ctx.SaveChanges();
}
} }
// this doesn't need to be async as it's during initialization
serverSvc.SaveChanges();
// check to see if the stats have ever been initialized // check to see if the stats have ever been initialized
InitializeServerStats(sv); var serverStats = InitializeServerStats(sv);
statsSvc.ServerStatsSvc.SaveChanges();
var serverStats = statsSvc.ServerStatsSvc.Find(c => c.ServerId == serverId).FirstOrDefault();
Servers.TryAdd(serverId, new ServerStats(server, serverStats) Servers.TryAdd(serverId, new ServerStats(server, serverStats)
{ {
IsTeamBased = sv.Gametype != "dm" IsTeamBased = sv.Gametype != "dm"
@ -237,106 +237,134 @@ 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)
{ {
int serverId = pl.CurrentServer.GetHashCode(); await OnProcessingSensitive.WaitAsync();
if (!Servers.ContainsKey(serverId)) try
{ {
Log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found"); int serverId = pl.CurrentServer.GetHashCode();
return null;
}
var playerStats = Servers[serverId].PlayerStats;
var detectionStats = Servers[serverId].PlayerDetections;
var statsSvc = ContextThreads[serverId];
if (playerStats.ContainsKey(pl.ClientId)) if (!Servers.ContainsKey(serverId))
{
Log.WriteWarning($"Duplicate ClientId in stats {pl.ClientId}");
return playerStats[pl.ClientId];
}
// 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
var clientStatsSvc = statsSvc.ClientStatSvc;
var clientStats = clientStatsSvc.Find(c => c.ClientId == pl.ClientId && c.ServerId == serverId).FirstOrDefault();
if (clientStats == null)
{
clientStats = new EFClientStatistics()
{ {
Active = true, Log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found");
ClientId = pl.ClientId, return null;
Deaths = 0,
Kills = 0,
ServerId = serverId,
Skill = 0.0,
SPM = 0.0,
EloRating = 200.0,
HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType<IW4Info.HitLocation>().Select(hl => new EFHitLocationCount()
{
Active = true,
HitCount = 0,
Location = hl
}).ToList()
};
// insert if they've not been added
clientStats = clientStatsSvc.Insert(clientStats);
if (!playerStats.TryAdd(clientStats.ClientId, clientStats))
{
Log.WriteWarning("Adding new client to stats failed");
} }
await clientStatsSvc.SaveChangesAsync(); var playerStats = Servers[serverId].PlayerStats;
} var detectionStats = Servers[serverId].PlayerDetections;
else if (playerStats.ContainsKey(pl.ClientId))
{
if (!playerStats.TryAdd(clientStats.ClientId, clientStats))
{ {
Log.WriteWarning("Adding pre-existing client to stats failed"); Log.WriteWarning($"Duplicate ClientId in stats {pl.ClientId}");
return playerStats[pl.ClientId];
} }
}
// migration for previous existing stats // get the client's stats from the database if it exists, otherwise create and attach a new one
if (clientStats.HitLocations.Count == 0) // if this fails we want to throw an exception
{
clientStats.HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType<IW4Info.HitLocation>() EFClientStatistics clientStats;
.Select(hl => new EFHitLocationCount()
using (var ctx = new DatabaseContext(disableTracking: true))
{
var clientStatsSet = ctx.Set<EFClientStatistics>();
clientStats = clientStatsSet
.Include(cl => cl.HitLocations)
.FirstOrDefault(c => c.ClientId == pl.ClientId && c.ServerId == serverId);
if (clientStats == null)
{ {
Active = true, clientStats = new EFClientStatistics()
HitCount = 0, {
Location = hl Active = true,
}) ClientId = pl.ClientId,
.ToList(); Deaths = 0,
await statsSvc.ClientStatSvc.SaveChangesAsync(); Kills = 0,
ServerId = serverId,
Skill = 0.0,
SPM = 0.0,
EloRating = 200.0,
HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType<IW4Info.HitLocation>().Select(hl => new EFHitLocationCount()
{
Active = true,
HitCount = 0,
Location = hl
}).ToList()
};
// insert if they've not been added
clientStats = clientStatsSet.Add(clientStats).Entity;
await ctx.SaveChangesAsync();
if (!playerStats.TryAdd(clientStats.ClientId, clientStats))
{
Log.WriteWarning("Adding new client to stats failed");
}
}
else
{
if (!playerStats.TryAdd(clientStats.ClientId, clientStats))
{
Log.WriteWarning("Adding pre-existing client to stats failed");
}
}
// migration for previous existing stats
if (clientStats.HitLocations.Count == 0)
{
clientStats.HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType<IW4Info.HitLocation>()
.Select(hl => new EFHitLocationCount()
{
Active = true,
HitCount = 0,
Location = hl
})
.ToList();
ctx.Update(clientStats);
await ctx.SaveChangesAsync();
}
// for stats before rating
if (clientStats.EloRating == 0.0)
{
clientStats.EloRating = clientStats.Skill;
}
if (clientStats.RollingWeightedKDR == 0)
{
clientStats.RollingWeightedKDR = clientStats.KDR;
}
// set these on connecting
clientStats.LastActive = DateTime.UtcNow;
clientStats.LastStatCalculation = DateTime.UtcNow;
clientStats.SessionScore = pl.Score;
clientStats.LastScore = pl.Score;
if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)))
{
Log.WriteWarning("Could not add client to detection");
}
Log.WriteInfo($"Adding {pl} to stats");
}
return clientStats;
} }
// for stats before rating catch (Exception ex)
if (clientStats.EloRating == 0.0)
{ {
clientStats.EloRating = clientStats.Skill;
} }
if (clientStats.RollingWeightedKDR == 0) finally
{ {
clientStats.RollingWeightedKDR = clientStats.KDR; OnProcessingSensitive.Release(1);
} }
// set these on connecting return null;
clientStats.LastActive = DateTime.UtcNow;
clientStats.LastStatCalculation = DateTime.UtcNow;
clientStats.SessionScore = pl.Score;
clientStats.LastScore = pl.Score;
if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)))
{
Log.WriteWarning("Could not add client to detection");
}
Log.WriteInfo($"Adding {pl} to stats");
return clientStats;
} }
/// <summary> /// <summary>
@ -352,7 +380,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
var playerStats = Servers[serverId].PlayerStats; var playerStats = Servers[serverId].PlayerStats;
var detectionStats = Servers[serverId].PlayerDetections; var detectionStats = Servers[serverId].PlayerDetections;
var serverStats = Servers[serverId].ServerStatistics; var serverStats = Servers[serverId].ServerStatistics;
var statsSvc = ContextThreads[serverId];
if (!playerStats.ContainsKey(pl.ClientId)) if (!playerStats.ContainsKey(pl.ClientId))
{ {
@ -371,10 +398,13 @@ 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
var clientStatsSvc = statsSvc.ClientStatSvc;
clientStats = UpdateStats(clientStats); clientStats = UpdateStats(clientStats);
clientStatsSvc.Update(clientStats);
await clientStatsSvc.SaveChangesAsync(); using (var ctx = new DatabaseContext(disableTracking: true))
{
ctx.Update(clientStats);
await ctx.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;
@ -405,15 +435,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads, string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads,
string fraction, string visibilityPercentage, string snapAngles) string fraction, string visibilityPercentage, string snapAngles)
{ {
var statsSvc = ContextThreads[serverId];
// incase the add palyer event get delayed
if (!Servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
{
await AddPlayer(attacker);
}
Vector3 vDeathOrigin = null; Vector3 vDeathOrigin = null;
Vector3 vKillOrigin = null; Vector3 vKillOrigin = null;
Vector3 vViewAngles = null; Vector3 vViewAngles = null;
@ -490,10 +511,20 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
return; return;
} }
// incase the add palyer event get delayed
if (!Servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
{
await AddPlayer(attacker);
}
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); using (var ctx = new DatabaseContext(disableTracking: true))
{
ctx.Set<EFClientStatistics>().Update(clientStats);
await ctx.SaveChangesAsync();
}
// increment their hit count // increment their hit count
if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET || if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
@ -531,17 +562,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
Log.WriteDebug(ex.GetExceptionInfo()); Log.WriteDebug(ex.GetExceptionInfo());
} }
try
{
await clientStatsSvc.SaveChangesAsync();
}
catch (Exception ex)
{
Log.WriteError("Could save save client stats");
Log.WriteDebug(ex.GetExceptionInfo());
}
OnProcessingPenalty.Release(1); OnProcessingPenalty.Release(1);
} }
} }
@ -743,10 +763,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
} }
// todo: do we want to save this immediately? // todo: do we want to save this immediately?
var clientStatsSvc = ContextThreads[serverId].ClientStatSvc; using (var ctx = new DatabaseContext(disableTracking: true))
clientStatsSvc.Update(attackerStats); {
clientStatsSvc.Update(victimStats); var clientStatsSet = ctx.Set<EFClientStatistics>();
await clientStatsSvc.SaveChangesAsync();
clientStatsSet.Update(attackerStats);
clientStatsSet.Update(victimStats);
await ctx.SaveChangesAsync();
}
} }
/// <summary> /// <summary>
@ -1079,39 +1103,43 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
return clientStats; return clientStats;
} }
public void InitializeServerStats(Server sv) public EFServerStatistics InitializeServerStats(Server sv)
{ {
int serverId = sv.GetHashCode(); int serverId = sv.GetHashCode();
var statsSvc = ContextThreads[serverId]; EFServerStatistics serverStats;
var serverStats = statsSvc.ServerStatsSvc.Find(s => s.ServerId == serverId).FirstOrDefault(); using (var ctx = new DatabaseContext(disableTracking: true))
if (serverStats == null)
{ {
Log.WriteDebug($"Initializing server stats for {sv}"); var serverStatsSet = ctx.Set<EFServerStatistics>();
// server stats have never been generated before serverStats = serverStatsSet.FirstOrDefault(s => s.ServerId == serverId);
serverStats = new EFServerStatistics()
if (serverStats == null)
{ {
Active = true, Log.WriteDebug($"Initializing server stats for {sv}");
ServerId = serverId, // server stats have never been generated before
TotalKills = 0, serverStats = new EFServerStatistics()
TotalPlayTime = 0, {
}; ServerId = serverId,
TotalKills = 0,
TotalPlayTime = 0,
};
var ieClientStats = statsSvc.ClientStatSvc.Find(cs => cs.ServerId == serverId); serverStats = serverStatsSet.Add(serverStats).Entity;
ctx.SaveChanges();
// set these incase we've imported settings }
serverStats.TotalKills = ieClientStats.Sum(cs => cs.Kills);
serverStats.TotalPlayTime = Manager.GetClientService().GetTotalPlayTime().Result;
statsSvc.ServerStatsSvc.Insert(serverStats);
} }
return serverStats;
} }
public void ResetKillstreaks(int serverId) public void ResetKillstreaks(int serverId)
{ {
var serverStats = Servers[serverId]; var serverStats = Servers[serverId];
foreach (var stat in serverStats.PlayerStats.Values) foreach (var stat in serverStats.PlayerStats.Values)
{
stat.StartNewSession(); stat.StartNewSession();
}
} }
public void ResetStats(int clientId, int serverId) public void ResetStats(int clientId, int serverId)
@ -1131,33 +1159,30 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
if (clientId < 1) if (clientId < 1)
return; return;
var messageSvc = ContextThreads[serverId].MessageSvc; using (var ctx = new DatabaseContext(disableTracking: true))
messageSvc.Insert(new EFClientMessage()
{ {
Active = true, ctx.Set<EFClientMessage>().Add(new EFClientMessage()
ClientId = clientId, {
Message = message, ClientId = clientId,
ServerId = serverId, Message = message,
TimeSent = DateTime.UtcNow ServerId = serverId,
}); TimeSent = DateTime.UtcNow
await messageSvc.SaveChangesAsync(); });
await ctx.SaveChangesAsync();
}
} }
public async Task Sync(Server sv) public async Task Sync(Server sv)
{ {
int serverId = sv.GetHashCode(); int serverId = sv.GetHashCode();
var statsSvc = ContextThreads[serverId];
var serverSvc = statsSvc.ServerSvc;
serverSvc.Update(Servers[serverId].Server); using (var ctx = new DatabaseContext(disableTracking: true))
await serverSvc.SaveChangesAsync(); {
var serverSet = ctx.Set<EFServer>();
await statsSvc.KillStatsSvc.SaveChangesAsync(); serverSet.Update(Servers[serverId].Server);
await statsSvc.ServerSvc.SaveChangesAsync(); await ctx.SaveChangesAsync();
}
statsSvc = null;
// this should prevent the gunk from having a long lasting context.
ContextThreads[serverId] = new ThreadSafeStatsService();
} }
public void SetTeamBased(int serverId, bool isTeamBased) public void SetTeamBased(int serverId, bool isTeamBased)

View File

@ -1,43 +0,0 @@
using SharedLibraryCore.Services;
using IW4MAdmin.Plugins.Stats.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IW4MAdmin.Plugins.Stats.Helpers
{
public class ThreadSafeStatsService
{
public GenericRepository<EFClientStatistics> ClientStatSvc
{
get
{
return new GenericRepository<EFClientStatistics>(false);
}
}
public GenericRepository<EFServer> ServerSvc
{
get
{
return new GenericRepository<EFServer>(false);
}
}
public GenericRepository<EFClientKill> KillStatsSvc { get; private set; }
public GenericRepository<EFServerStatistics> ServerStatsSvc { get; private set; }
public GenericRepository<EFClientMessage> MessageSvc
{
get
{
return new GenericRepository<EFClientMessage>();
}
}
public ThreadSafeStatsService()
{
KillStatsSvc = new GenericRepository<EFClientKill>();
ServerStatsSvc = new GenericRepository<EFServerStatistics>();
}
}
}

View File

@ -13,6 +13,8 @@ using SharedLibraryCore.Services;
using IW4MAdmin.Plugins.Stats.Config; using IW4MAdmin.Plugins.Stats.Config;
using IW4MAdmin.Plugins.Stats.Helpers; using IW4MAdmin.Plugins.Stats.Helpers;
using IW4MAdmin.Plugins.Stats.Models; using IW4MAdmin.Plugins.Stats.Models;
using SharedLibraryCore.Database;
using Microsoft.EntityFrameworkCore;
namespace IW4MAdmin.Plugins.Stats namespace IW4MAdmin.Plugins.Stats
{ {
@ -122,8 +124,11 @@ namespace IW4MAdmin.Plugins.Stats
// meta data info // meta data info
async Task<List<ProfileMeta>> getStats(int clientId) async Task<List<ProfileMeta>> getStats(int clientId)
{ {
var statsSvc = new GenericRepository<EFClientStatistics>(); IList<EFClientStatistics> clientStats;
var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId); using (var ctx = new DatabaseContext(disableTracking: true))
{
clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == clientId).ToListAsync();
}
int kills = clientStats.Sum(c => c.Kills); int kills = clientStats.Sum(c => c.Kills);
int deaths = clientStats.Sum(c => c.Deaths); int deaths = clientStats.Sum(c => c.Deaths);
@ -170,8 +175,14 @@ namespace IW4MAdmin.Plugins.Stats
async Task<List<ProfileMeta>> getAnticheatInfo(int clientId) async Task<List<ProfileMeta>> getAnticheatInfo(int clientId)
{ {
var statsSvc = new GenericRepository<EFClientStatistics>(); IList<EFClientStatistics> clientStats;
var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId); using (var ctx = new DatabaseContext(disableTracking: true))
{
clientStats = await ctx.Set<EFClientStatistics>()
.Include(c => c.HitLocations)
.Where(c => c.ClientId == clientId)
.ToListAsync();
}
double headRatio = 0; double headRatio = 0;
double chestRatio = 0; double chestRatio = 0;
@ -246,19 +257,24 @@ namespace IW4MAdmin.Plugins.Stats
async Task<List<ProfileMeta>> getMessages(int clientId) async Task<List<ProfileMeta>> getMessages(int clientId)
{ {
var messageSvc = new GenericRepository<EFClientMessage>(); List<ProfileMeta> messageMeta;
var messages = await messageSvc.FindAsync(m => m.ClientId == clientId); using (var ctx = new DatabaseContext(disableTracking: true))
var messageMeta = messages.Select(m => new ProfileMeta()
{ {
Key = "EventMessage", var messages = ctx.Set<EFClientMessage>().Where(m => m.ClientId == clientId);
Value = m.Message,
When = m.TimeSent, messageMeta = await messages.Select(m => new ProfileMeta()
Extra = m.ServerId.ToString() {
}).ToList(); Key = "EventMessage",
Value = m.Message,
When = m.TimeSent,
Extra = m.ServerId.ToString()
}).ToListAsync();
}
messageMeta.Add(new ProfileMeta() messageMeta.Add(new ProfileMeta()
{ {
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"], Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
Value = messages.Count Value = messageMeta.Count
}); });
return messageMeta; return messageMeta;
@ -275,16 +291,20 @@ namespace IW4MAdmin.Plugins.Stats
string totalKills(Server server) string totalKills(Server server)
{ {
var serverStats = new GenericRepository<EFServerStatistics>(); using (var ctx = new DatabaseContext(disableTracking: true))
return serverStats.Find(s => s.Active) {
.Sum(c => c.TotalKills).ToString("#,##0"); long kills = ctx.Set<EFServerStatistics>().Where(s => s.Active).Sum(s => s.TotalKills);
return kills.ToString("#,##0");
}
} }
string totalPlayTime(Server server) string totalPlayTime(Server server)
{ {
var serverStats = new GenericRepository<EFServerStatistics>(); using (var ctx = new DatabaseContext(disableTracking: true))
return Math.Ceiling((serverStats.GetQuery(s => s.Active) {
.Sum(c => c.TotalPlayTime) / 3600.0)).ToString("#,##0"); long playTime = ctx.Set<EFServerStatistics>().Where(s => s.Active).Sum(s => s.TotalPlayTime);
return (playTime / 3600.0).ToString("#,##0");
}
} }
string topStats(Server s) string topStats(Server s)

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.Stats</PackageId> <PackageId>RaidMax.IW4MAdmin.Plugins.Stats</PackageId>
@ -26,7 +27,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" /> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
</PropertyGroup> </PropertyGroup>
@ -22,7 +23,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" /> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,6 +8,8 @@ using SharedLibraryCore.Configuration;
using SharedLibraryCore.Services; using SharedLibraryCore.Services;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using System.Linq; using System.Linq;
using SharedLibraryCore.Database;
using Microsoft.EntityFrameworkCore;
namespace IW4MAdmin.Plugins.Welcome namespace IW4MAdmin.Plugins.Welcome
{ {
@ -88,8 +90,18 @@ namespace IW4MAdmin.Plugins.Welcome
if (newPlayer.Level == Player.Permission.Flagged) if (newPlayer.Level == Player.Permission.Flagged)
{ {
var penalty = await new GenericRepository<EFPenalty>().FindAsync(p => p.OffenderId == newPlayer.ClientId && p.Type == Penalty.PenaltyType.Flag); string penaltyReason;
E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penalty.FirstOrDefault()?.Offense}) has joined!");
using (var ctx = new DatabaseContext(disableTracking: true))
{
penaltyReason = await ctx.Penalties
.Where(p => p.OffenderId == newPlayer.ClientId && p.Type == Penalty.PenaltyType.Flag)
.OrderByDescending(p => p.When)
.Select(p => p.AutomatedOffense ?? p.Offense)
.FirstOrDefaultAsync();
}
E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!");
} }
else else
E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer)); E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer));

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<PackageId>RaidMax.IW4MAdmin.Plugins.Welcome</PackageId> <PackageId>RaidMax.IW4MAdmin.Plugins.Welcome</PackageId>
@ -25,7 +26,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" /> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -68,7 +68,6 @@ namespace SharedLibraryCore
ScriptEngine.Execute(script); ScriptEngine.Execute(script);
ScriptEngine.SetValue("_localization", Utilities.CurrentLocalization); ScriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
ScriptEngine.SetValue("_IW4MAdminClient", Utilities.IW4MAdminClient);
dynamic pluginObject = ScriptEngine.GetValue("plugin").ToObject(); dynamic pluginObject = ScriptEngine.GetValue("plugin").ToObject();
this.Author = pluginObject.author; this.Author = pluginObject.author;
@ -87,6 +86,7 @@ namespace SharedLibraryCore
{ {
ScriptEngine.SetValue("_gameEvent", E); ScriptEngine.SetValue("_gameEvent", E);
ScriptEngine.SetValue("_server", S); ScriptEngine.SetValue("_server", S);
ScriptEngine.SetValue("_IW4MAdminClient", Utilities.IW4MAdminClient(S));
return Task.FromResult(ScriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue()); return Task.FromResult(ScriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue());
} }
} }

View File

@ -33,6 +33,7 @@ namespace SharedLibraryCore
Port = config.Port; Port = config.Port;
Manager = mgr; Manager = mgr;
Logger = Manager.GetLogger(this.GetHashCode()); Logger = Manager.GetLogger(this.GetHashCode());
Logger.WriteInfo(this.ToString());
ServerConfig = config; ServerConfig = config;
RemoteConnection = new RCon.Connection(IP, Port, Password, Logger); RemoteConnection = new RCon.Connection(IP, Port, Password, Logger);
@ -263,7 +264,7 @@ namespace SharedLibraryCore
public override string ToString() public override string ToString()
{ {
return $"{IP}_{Port}"; return $"{IP}-{Port}";
} }
protected async Task<bool> ScriptLoaded() protected async Task<bool> ScriptLoaded()

View File

@ -1,154 +0,0 @@
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
namespace SharedLibraryCore.Services
{
// https://stackoverflow.com/questions/43677906/crud-operations-with-entityframework-using-generic-type
public class GenericRepository<TEntity> where TEntity : class
{
private DatabaseContext _context;
private DbSet<TEntity> _dbSet;
private readonly bool ShouldTrack;
public GenericRepository(bool shouldTrack)
{
this.ShouldTrack = shouldTrack;
}
public GenericRepository() { }
protected DbContext Context
{
get
{
if (_context == null)
{
_context = new DatabaseContext(!ShouldTrack);
}
return _context;
}
}
protected DbSet<TEntity> DBSet
{
get
{
if (_dbSet == null)
{
_dbSet = this.Context.Set<TEntity>();
}
return _dbSet;
}
}
public virtual async Task<IList<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
{
return await this.GetQuery(predicate, orderExpression).ToListAsync();
}
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
{
return this.GetQuery(predicate, orderExpression).AsEnumerable();
}
public virtual IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
{
IQueryable<TEntity> qry = this.DBSet;
foreach (var property in this.Context.Model.FindEntityType(typeof(TEntity)).GetNavigations())
qry = qry.Include(property.Name);
if (predicate != null)
qry = qry.Where(predicate);
if (orderExpression != null)
return orderExpression(qry);
return qry;
}
public virtual void Insert<T>(T entity) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
dbSet.Add(entity);
}
public virtual TEntity Insert(TEntity entity)
{
return DBSet.Add(entity).Entity;
}
public virtual void Update<T>(T entity) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
dbSet.Attach(entity);
this.Context.Entry(entity).State = EntityState.Modified;
}
public virtual void Update(TEntity entity)
{
this.Attach(entity);
this.Context.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete<T>(T entity) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
if (this.Context.Entry(entity).State == EntityState.Detached)
dbSet.Attach(entity);
dbSet.Remove(entity);
}
public virtual void Delete(TEntity entity)
{
if (this.Context.Entry(entity).State == EntityState.Detached)
this.Attach(entity);
this.DBSet.Remove(entity);
}
public virtual void Delete<T>(object[] id) where T : class
{
DbSet<T> dbSet = this.Context.Set<T>();
T entity = dbSet.Find(id);
dbSet.Attach(entity);
dbSet.Remove(entity);
}
public virtual void Delete(object id)
{
TEntity entity = this.DBSet.Find(id);
this.Delete(entity);
}
public virtual void Attach(TEntity entity)
{
if (this.Context.Entry(entity).State == EntityState.Detached)
this.DBSet.Attach(entity);
}
public virtual void SaveChanges()
{
this.Context.SaveChanges();
}
public virtual Task SaveChangesAsync()
{
return this.Context.SaveChangesAsync();
}
}
}

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId> <PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
@ -12,15 +13,6 @@
<Configurations>Debug;Release;Prerelease</Configurations> <Configurations>Debug;Release;Prerelease</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Migrations\20180502195240_Update.cs" />
<Compile Remove="Migrations\20180923025324_FixForPostgreSQL.cs" />
<Compile Remove="Migrations\20180923025702_FixForPostgreSQL.cs" />
<Compile Remove="Migrations\20180923030248_FixForPostgreSQL.cs" />
<Compile Remove="Migrations\20180923030426_FixForPostgreSQL.cs" />
<Compile Remove="Migrations\20180923030528_FixForPostgreSQL.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Jint" Version="2.11.58" /> <PackageReference Include="Jint" Version="2.11.58" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.4" />
@ -39,7 +31,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Update="Microsoft.NETCore.App" /> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
</ItemGroup> </ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent"> <Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View File

@ -27,7 +27,7 @@ namespace SharedLibraryCore
#endif #endif
public static Encoding EncodingType; public static Encoding EncodingType;
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>()); public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
public static Player IW4MAdminClient = new Player() { ClientId = 1, Level = Player.Permission.Console }; public static Player IW4MAdminClient(Server server = null) => new Player() { ClientId = 1, Level = Player.Permission.Console, CurrentServer = server };
public static string HttpRequest(string location, string header, string headerValue) public static string HttpRequest(string location, string header, string headerValue)
{ {

View File

@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos;
using SharedLibraryCore.Services; using SharedLibraryCore.Services;
@ -33,8 +35,14 @@ namespace WebfrontCore.Controllers
public async Task<IActionResult> PublicAsync() public async Task<IActionResult> PublicAsync()
{ {
var penalties = await (new GenericRepository<EFPenalty>()) IList<EFPenalty> penalties;
.FindAsync(p => p.Type == SharedLibraryCore.Objects.Penalty.PenaltyType.Ban && p.Active);
using (var ctx = new DatabaseContext(disableTracking: true))
{
penalties = await ctx.Penalties
.Where(p => p.Type == SharedLibraryCore.Objects.Penalty.PenaltyType.Ban && p.Active)
.ToListAsync();
}
var penaltiesDto = penalties.Select(p => new PenaltyInfo() var penaltiesDto = penalties.Select(p => new PenaltyInfo()
{ {

View File

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
<RazorCompileOnBuild>false</RazorCompileOnBuild> <RazorCompileOnBuild>false</RazorCompileOnBuild>
<RazorCompileOnPublish>false</RazorCompileOnPublish> <RazorCompileOnPublish>false</RazorCompileOnPublish>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
@ -63,7 +64,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.1" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.2" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" />
<PackageReference Update="Microsoft.NETCore.App" /> <PackageReference Update="Microsoft.NETCore.App" Version="2.1.5" />
<PackageReference Update="Microsoft.AspNetCore" Version="2.1.2" /> <PackageReference Update="Microsoft.AspNetCore" Version="2.1.2" />
</ItemGroup> </ItemGroup>