fix bug with player not getting updated on disconnect (related to issue #24)
jint version downgraded for better stability (also locked the engine instance as it's not thread safe) updated readme remove vpn detection from application configuration as it's now in a seperate plugin defaulted webfront bind URl to all interfaces readd the custom say name added visibility percentage to AC
This commit is contained in:
parent
672d45df7c
commit
cfbacabb4a
@ -21,4 +21,11 @@ xcopy /Y "%SolutionDir%BUILD\Plugins" "%SolutionDir%Publish\WindowsPrerelease\Pl
|
|||||||
|
|
||||||
echo Copying script plugins for publish
|
echo Copying script plugins for publish
|
||||||
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\Windows\Plugins\"
|
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\Windows\Plugins\"
|
||||||
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\WindowsPrerelease\Plugins\"
|
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\WindowsPrerelease\Plugins\"
|
||||||
|
|
||||||
|
echo Copying GSC files for publish
|
||||||
|
xcopy /Y "%SolutionDir%_customcallbacks.gsc" "%SolutionDir%Publish\Windows\userraw\scripts\"
|
||||||
|
xcopy /Y "%SolutionDir%_customcallbacks.gsc" "%SolutionDir%Publish\WindowsPrerelease\userraw\scripts\"
|
||||||
|
|
||||||
|
xcopy /Y "%SolutionDir%_commands.gsc" "%SolutionDir%Publish\Windows\userraw\scripts\"
|
||||||
|
xcopy /Y "%SolutionDir%_commands.gsc" "%SolutionDir%Publish\WindowsPrerelease\userraw\scripts\"
|
@ -1,12 +1,9 @@
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Events;
|
using SharedLibraryCore.Events;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
@ -22,59 +19,57 @@ namespace IW4MAdmin.Application
|
|||||||
OutOfOrderEvents = new SortedList<long, GameEvent>();
|
OutOfOrderEvents = new SortedList<long, GameEvent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddEvent(GameEvent gameEvent)
|
public void AddEvent(GameEvent gameEvent)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Manager.GetLogger().WriteDebug($"Got new event of type {gameEvent.Type} for {gameEvent.Owner} with id {gameEvent.Id}");
|
Manager.GetLogger().WriteDebug($"Got new event of type {gameEvent.Type} for {gameEvent.Owner} with id {gameEvent.Id}");
|
||||||
#endif
|
#endif
|
||||||
// GameEvent sortedEvent = null;
|
GameEvent sortedEvent = null;
|
||||||
// lock (OutOfOrderEvents)
|
lock (OutOfOrderEvents)
|
||||||
// {
|
{
|
||||||
// sortedEvent = OutOfOrderEvents.Values.FirstOrDefault();
|
sortedEvent = OutOfOrderEvents.Values.FirstOrDefault();
|
||||||
|
|
||||||
// while (sortedEvent?.Id == Interlocked.Read(ref NextEventId))
|
while (sortedEvent?.Id == Interlocked.Read(ref NextEventId))
|
||||||
// {
|
{
|
||||||
// if (OutOfOrderEvents.Count > 0)
|
if (OutOfOrderEvents.Count > 0)
|
||||||
// {
|
{
|
||||||
// OutOfOrderEvents.RemoveAt(0);
|
OutOfOrderEvents.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// AddEvent(sortedEvent);
|
AddEvent(sortedEvent);
|
||||||
// sortedEvent = OutOfOrderEvents.Values.FirstOrDefault();
|
sortedEvent = OutOfOrderEvents.Values.FirstOrDefault();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// // both the gameEvent Id and the LastEventId are thread safe because we want to synchronize when the
|
// both the gameEvent Id and the LastEventId are thread safe because we want to synchronize when the
|
||||||
// // event occurs
|
// event occurs
|
||||||
// if (gameEvent.Id == Interlocked.Read(ref NextEventId))
|
if (gameEvent.Id == Interlocked.Read(ref NextEventId))
|
||||||
// {
|
{
|
||||||
//#if DEBUG == true
|
#if DEBUG == true
|
||||||
// Manager.GetLogger().WriteDebug($"sent event with id {gameEvent.Id} to be processed");
|
Manager.GetLogger().WriteDebug($"sent event with id {gameEvent.Id} to be processed");
|
||||||
//#endif
|
#endif
|
||||||
((Manager as ApplicationManager).OnServerEvent)(this, new GameEventArgs(null, false, gameEvent));
|
((Manager as ApplicationManager).OnServerEvent)(this, new GameEventArgs(null, false, gameEvent));
|
||||||
return true;
|
Interlocked.Increment(ref NextEventId);
|
||||||
// Interlocked.Increment(ref NextEventId);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// // a "newer" event has been added before and "older" one has been added (due to threads and context switching)
|
// a "newer" event has been added before and "older" one has been added (due to threads and context switching)
|
||||||
// // so me must wait until the next expected one arrives
|
// so me must wait until the next expected one arrives
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
//#if DEBUG == true
|
#if DEBUG == true
|
||||||
// Manager.GetLogger().WriteWarning("Incoming event is out of order");
|
Manager.GetLogger().WriteWarning("Incoming event is out of order");
|
||||||
// Manager.GetLogger().WriteDebug($"Expected event Id is {Interlocked.Read(ref NextEventId)}, but got {gameEvent.Id} instead");
|
Manager.GetLogger().WriteDebug($"Expected event Id is {Interlocked.Read(ref NextEventId)}, but got {gameEvent.Id} instead");
|
||||||
//#endif
|
#endif
|
||||||
|
|
||||||
// // this prevents multiple threads from adding simultaneously
|
// this prevents multiple threads from adding simultaneously
|
||||||
// lock (OutOfOrderEvents)
|
lock (OutOfOrderEvents)
|
||||||
// {
|
{
|
||||||
// if (!OutOfOrderEvents.TryGetValue(gameEvent.Id, out GameEvent discard))
|
if (!OutOfOrderEvents.TryGetValue(gameEvent.Id, out GameEvent discard))
|
||||||
// {
|
{
|
||||||
// OutOfOrderEvents.Add(gameEvent.Id, gameEvent);
|
OutOfOrderEvents.Add(gameEvent.Id, gameEvent);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,6 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
Player Leaving = Players[cNum];
|
Player Leaving = Players[cNum];
|
||||||
Logger.WriteInfo($"Client {Leaving}, state {Leaving.State.ToString()} disconnecting...");
|
Logger.WriteInfo($"Client {Leaving}, state {Leaving.State.ToString()} disconnecting...");
|
||||||
Leaving.State = Player.ClientState.Disconnecting;
|
|
||||||
|
|
||||||
// occurs when the player disconnects via log before being authenticated by RCon
|
// occurs when the player disconnects via log before being authenticated by RCon
|
||||||
if (Leaving.State != Player.ClientState.Connected)
|
if (Leaving.State != Player.ClientState.Connected)
|
||||||
@ -268,6 +267,7 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Leaving.State = Player.ClientState.Disconnecting;
|
||||||
Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds;
|
Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds;
|
||||||
Leaving.LastConnection = DateTime.UtcNow;
|
Leaving.LastConnection = DateTime.UtcNow;
|
||||||
await Manager.GetClientService().Update(Leaving);
|
await Manager.GetClientService().Update(Leaving);
|
||||||
@ -822,7 +822,7 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
Logger.WriteInfo($"Log file is {logPath}");
|
Logger.WriteInfo($"Log file is {logPath}");
|
||||||
|
|
||||||
Task.Run(() => LogEvent.PollForChanges());
|
_ = Task.Run(() => LogEvent.PollForChanges());
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
await Broadcast(loc["BROADCAST_ONLINE"]);
|
await Broadcast(loc["BROADCAST_ONLINE"]);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,197 +1,197 @@
|
|||||||
//using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
//using SharedLibraryCore.Objects;
|
using SharedLibraryCore.Objects;
|
||||||
//using System;
|
using System;
|
||||||
//using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
//using System.Linq;
|
using System.Linq;
|
||||||
//using System.Text;
|
using System.Text;
|
||||||
//using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
//namespace IW4ScriptCommands.Commands
|
namespace IW4ScriptCommands.Commands
|
||||||
//{
|
{
|
||||||
// class Balance : Command
|
class Balance : Command
|
||||||
// {
|
{
|
||||||
// private class TeamAssignment
|
private class TeamAssignment
|
||||||
// {
|
{
|
||||||
// public IW4MAdmin.Plugins.Stats.IW4Info.Team CurrentTeam { get; set; }
|
public IW4MAdmin.Plugins.Stats.IW4Info.Team CurrentTeam { get; set; }
|
||||||
// public int Num { get; set; }
|
public int Num { get; set; }
|
||||||
// public IW4MAdmin.Plugins.Stats.Models.EFClientStatistics Stats { get; set; }
|
public IW4MAdmin.Plugins.Stats.Models.EFClientStatistics Stats { get; set; }
|
||||||
// }
|
}
|
||||||
// public Balance() : base("balance", "balance teams", "bal", Player.Permission.Trusted, false, null)
|
public Balance() : base("balance", "balance teams", "bal", Player.Permission.Trusted, false, null)
|
||||||
// {
|
{
|
||||||
// }
|
}
|
||||||
|
|
||||||
// public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
// {
|
{
|
||||||
// string teamsString = (await E.Owner.GetDvarAsync<string>("sv_iw4madmin_teams")).Value;
|
string teamsString = (await E.Owner.GetDvarAsync<string>("sv_iw4madmin_teams")).Value;
|
||||||
|
|
||||||
// var scriptClientTeams = teamsString.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
var scriptClientTeams = teamsString.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
||||||
// .Select(c => c.Split(','))
|
.Select(c => c.Split(','))
|
||||||
// .Select(c => new TeamAssignment()
|
.Select(c => new TeamAssignment()
|
||||||
// {
|
{
|
||||||
// CurrentTeam = (IW4MAdmin.Plugins.Stats.IW4Info.Team)Enum.Parse(typeof(IW4MAdmin.Plugins.Stats.IW4Info.Team), c[1]),
|
CurrentTeam = (IW4MAdmin.Plugins.Stats.IW4Info.Team)Enum.Parse(typeof(IW4MAdmin.Plugins.Stats.IW4Info.Team), c[1]),
|
||||||
// Num = E.Owner.Players.FirstOrDefault(p => p?.NetworkId == c[0].ConvertLong())?.ClientNumber ?? -1,
|
Num = E.Owner.Players.FirstOrDefault(p => p?.NetworkId == c[0].ConvertLong())?.ClientNumber ?? -1,
|
||||||
// Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(E.Owner.Players.FirstOrDefault(p => p?.NetworkId == c[0].ConvertLong()).ClientId, E.Owner.GetHashCode())
|
Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(E.Owner.Players.FirstOrDefault(p => p?.NetworkId == c[0].ConvertLong()).ClientId, E.Owner.GetHashCode())
|
||||||
// })
|
})
|
||||||
// .ToList();
|
.ToList();
|
||||||
|
|
||||||
// // at least one team is full so we can't balance
|
// at least one team is full so we can't balance
|
||||||
// if (scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) >= Math.Floor(E.Owner.MaxClients / 2.0)
|
if (scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) >= Math.Floor(E.Owner.MaxClients / 2.0)
|
||||||
// || scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) >= Math.Floor(E.Owner.MaxClients / 2.0))
|
|| scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) >= Math.Floor(E.Owner.MaxClients / 2.0))
|
||||||
// {
|
{
|
||||||
// await E.Origin?.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL"]);
|
await E.Origin?.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL"]);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// List<string> teamAssignments = new List<string>();
|
List<string> teamAssignments = new List<string>();
|
||||||
|
|
||||||
// var activeClients = E.Owner.GetPlayersAsList().Select(c => new TeamAssignment()
|
var activeClients = E.Owner.GetPlayersAsList().Select(c => new TeamAssignment()
|
||||||
// {
|
{
|
||||||
// Num = c.ClientNumber,
|
Num = c.ClientNumber,
|
||||||
// Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, E.Owner.GetHashCode()),
|
Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, E.Owner.GetHashCode()),
|
||||||
// CurrentTeam = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, E.Owner.GetHashCode()).Team
|
CurrentTeam = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, E.Owner.GetHashCode()).Team
|
||||||
// })
|
})
|
||||||
// .Where(c => scriptClientTeams.FirstOrDefault(sc => sc.Num == c.Num)?.CurrentTeam != IW4MAdmin.Plugins.Stats.IW4Info.Team.Spectator)
|
.Where(c => scriptClientTeams.FirstOrDefault(sc => sc.Num == c.Num)?.CurrentTeam != IW4MAdmin.Plugins.Stats.IW4Info.Team.Spectator)
|
||||||
// .Where(c => c.CurrentTeam != scriptClientTeams.FirstOrDefault(p => p.Num == c.Num)?.CurrentTeam)
|
.Where(c => c.CurrentTeam != scriptClientTeams.FirstOrDefault(p => p.Num == c.Num)?.CurrentTeam)
|
||||||
// .OrderByDescending(c => c.Stats.Performance)
|
.OrderByDescending(c => c.Stats.Performance)
|
||||||
// .ToList();
|
.ToList();
|
||||||
|
|
||||||
// var alliesTeam = scriptClientTeams
|
var alliesTeam = scriptClientTeams
|
||||||
// .Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies)
|
.Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies)
|
||||||
// .Where(c => activeClients.Count(t => t.Num == c.Num) == 0)
|
.Where(c => activeClients.Count(t => t.Num == c.Num) == 0)
|
||||||
// .ToList();
|
.ToList();
|
||||||
|
|
||||||
// var axisTeam = scriptClientTeams
|
var axisTeam = scriptClientTeams
|
||||||
// .Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis)
|
.Where(c => c.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis)
|
||||||
// .Where(c => activeClients.Count(t => t.Num == c.Num) == 0)
|
.Where(c => activeClients.Count(t => t.Num == c.Num) == 0)
|
||||||
// .ToList();
|
.ToList();
|
||||||
|
|
||||||
// while (activeClients.Count() > 0)
|
while (activeClients.Count() > 0)
|
||||||
// {
|
{
|
||||||
// int teamSizeDifference = alliesTeam.Count - axisTeam.Count;
|
int teamSizeDifference = alliesTeam.Count - axisTeam.Count;
|
||||||
// double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 -
|
double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 -
|
||||||
// axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0;
|
axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0;
|
||||||
|
|
||||||
// if (teamSizeDifference == 0)
|
if (teamSizeDifference == 0)
|
||||||
// {
|
{
|
||||||
// if (performanceDisparity == 0)
|
if (performanceDisparity == 0)
|
||||||
// {
|
{
|
||||||
// alliesTeam.Add(activeClients.First());
|
alliesTeam.Add(activeClients.First());
|
||||||
// activeClients.RemoveAt(0);
|
activeClients.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// if (performanceDisparity > 0)
|
if (performanceDisparity > 0)
|
||||||
// {
|
{
|
||||||
// axisTeam.Add(activeClients.First());
|
axisTeam.Add(activeClients.First());
|
||||||
// activeClients.RemoveAt(0);
|
activeClients.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// alliesTeam.Add(activeClients.First());
|
alliesTeam.Add(activeClients.First());
|
||||||
// activeClients.RemoveAt(0);
|
activeClients.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// else if (teamSizeDifference > 0)
|
else if (teamSizeDifference > 0)
|
||||||
// {
|
{
|
||||||
// if (performanceDisparity > 0)
|
if (performanceDisparity > 0)
|
||||||
// {
|
{
|
||||||
// axisTeam.Add(activeClients.First());
|
axisTeam.Add(activeClients.First());
|
||||||
// activeClients.RemoveAt(0);
|
activeClients.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// axisTeam.Add(activeClients.Last());
|
axisTeam.Add(activeClients.Last());
|
||||||
// activeClients.RemoveAt(activeClients.Count - 1);
|
activeClients.RemoveAt(activeClients.Count - 1);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// if (performanceDisparity > 0)
|
if (performanceDisparity > 0)
|
||||||
// {
|
{
|
||||||
// alliesTeam.Add(activeClients.First());
|
alliesTeam.Add(activeClients.First());
|
||||||
// activeClients.RemoveAt(0);
|
activeClients.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// alliesTeam.Add(activeClients.Last());
|
alliesTeam.Add(activeClients.Last());
|
||||||
// activeClients.RemoveAt(activeClients.Count - 1);
|
activeClients.RemoveAt(activeClients.Count - 1);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// alliesTeam = alliesTeam.OrderByDescending(t => t.Stats.Performance)
|
alliesTeam = alliesTeam.OrderByDescending(t => t.Stats.Performance)
|
||||||
// .ToList();
|
.ToList();
|
||||||
|
|
||||||
// axisTeam = axisTeam.OrderByDescending(t => t.Stats.Performance)
|
axisTeam = axisTeam.OrderByDescending(t => t.Stats.Performance)
|
||||||
// .ToList();
|
.ToList();
|
||||||
|
|
||||||
// while (Math.Abs(alliesTeam.Count - axisTeam.Count) > 1)
|
while (Math.Abs(alliesTeam.Count - axisTeam.Count) > 1)
|
||||||
// {
|
{
|
||||||
// int teamSizeDifference = alliesTeam.Count - axisTeam.Count;
|
int teamSizeDifference = alliesTeam.Count - axisTeam.Count;
|
||||||
// double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 -
|
double performanceDisparity = alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0 -
|
||||||
// axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0;
|
axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0;
|
||||||
|
|
||||||
// if (teamSizeDifference > 0)
|
if (teamSizeDifference > 0)
|
||||||
// {
|
{
|
||||||
// if (performanceDisparity > 0)
|
if (performanceDisparity > 0)
|
||||||
// {
|
{
|
||||||
// axisTeam.Add(alliesTeam.First());
|
axisTeam.Add(alliesTeam.First());
|
||||||
// alliesTeam.RemoveAt(0);
|
alliesTeam.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// axisTeam.Add(alliesTeam.Last());
|
axisTeam.Add(alliesTeam.Last());
|
||||||
// alliesTeam.RemoveAt(axisTeam.Count - 1);
|
alliesTeam.RemoveAt(axisTeam.Count - 1);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// if (performanceDisparity > 0)
|
if (performanceDisparity > 0)
|
||||||
// {
|
{
|
||||||
// alliesTeam.Add(axisTeam.Last());
|
alliesTeam.Add(axisTeam.Last());
|
||||||
// axisTeam.RemoveAt(axisTeam.Count - 1);
|
axisTeam.RemoveAt(axisTeam.Count - 1);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// else
|
else
|
||||||
// {
|
{
|
||||||
// alliesTeam.Add(axisTeam.First());
|
alliesTeam.Add(axisTeam.First());
|
||||||
// axisTeam.RemoveAt(0);
|
axisTeam.RemoveAt(0);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// foreach (var assignment in alliesTeam)
|
foreach (var assignment in alliesTeam)
|
||||||
// {
|
{
|
||||||
// teamAssignments.Add($"{assignment.Num},2");
|
teamAssignments.Add($"{assignment.Num},2");
|
||||||
// assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies;
|
assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies;
|
||||||
// }
|
}
|
||||||
// foreach (var assignment in axisTeam)
|
foreach (var assignment in axisTeam)
|
||||||
// {
|
{
|
||||||
// teamAssignments.Add($"{assignment.Num},3");
|
teamAssignments.Add($"{assignment.Num},3");
|
||||||
// assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis;
|
assignment.Stats.Team = IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (alliesTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0 &&
|
if (alliesTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0 &&
|
||||||
// axisTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0)
|
axisTeam.Count(ac => scriptClientTeams.First(sc => sc.Num == ac.Num).CurrentTeam != ac.CurrentTeam) == 0)
|
||||||
// {
|
{
|
||||||
// await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL_BALANCED"]);
|
await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL_BALANCED"]);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// if (E.Origin?.Level > Player.Permission.Administrator)
|
if (E.Origin?.Level > Player.Permission.Administrator)
|
||||||
// {
|
{
|
||||||
// await E.Origin.Tell($"Allies Elo: {(alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0)}");
|
await E.Origin.Tell($"Allies Elo: {(alliesTeam.Count > 0 ? alliesTeam.Average(t => t.Stats.Performance) : 0)}");
|
||||||
// await E.Origin.Tell($"Axis Elo: {(axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0)}");
|
await E.Origin.Tell($"Axis Elo: {(axisTeam.Count > 0 ? axisTeam.Average(t => t.Stats.Performance) : 0)}");
|
||||||
// }
|
}
|
||||||
|
|
||||||
// string args = string.Join(",", teamAssignments);
|
string args = string.Join(",", teamAssignments);
|
||||||
// await E.Owner.ExecuteCommandAsync($"sv_iw4madmin_command \"balance:{args}\"");
|
await E.Owner.ExecuteCommandAsync($"sv_iw4madmin_command \"balance:{args}\"");
|
||||||
// await E.Origin.Tell("Balance command sent");
|
await E.Origin.Tell("Balance command sent");
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
@ -36,6 +37,15 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
|||||||
var objectionalWords = Settings.Configuration().OffensiveWords;
|
var objectionalWords = Settings.Configuration().OffensiveWords;
|
||||||
bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Origin.Name.ToLower().Contains(w)) != null;
|
bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Origin.Name.ToLower().Contains(w)) != null;
|
||||||
|
|
||||||
|
// we want to run regex against it just incase
|
||||||
|
if (!containsObjectionalWord)
|
||||||
|
{
|
||||||
|
foreach (string word in objectionalWords)
|
||||||
|
{
|
||||||
|
containsObjectionalWord |= Regex.IsMatch(E.Origin.Name.ToLower(), word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (containsObjectionalWord)
|
if (containsObjectionalWord)
|
||||||
{
|
{
|
||||||
await E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, new Player()
|
await E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, new Player()
|
||||||
@ -56,7 +66,18 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
|||||||
if (E.Type == GameEvent.EventType.Say)
|
if (E.Type == GameEvent.EventType.Say)
|
||||||
{
|
{
|
||||||
var objectionalWords = Settings.Configuration().OffensiveWords;
|
var objectionalWords = Settings.Configuration().OffensiveWords;
|
||||||
bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Data.ToLower().Contains(w)) != null;
|
bool containsObjectionalWord = false;
|
||||||
|
|
||||||
|
foreach (string word in objectionalWords)
|
||||||
|
{
|
||||||
|
containsObjectionalWord |= Regex.IsMatch(E.Origin.Name.ToLower(), word);
|
||||||
|
|
||||||
|
// break out early because there's at least one objectional word
|
||||||
|
if (containsObjectionalWord)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (containsObjectionalWord)
|
if (containsObjectionalWord)
|
||||||
{
|
{
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
const plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 1.0,
|
version: 1.0,
|
||||||
name: 'VPN Kick Plugin',
|
name: 'VPN Detection Plugin',
|
||||||
|
|
||||||
manager: null,
|
manager: null,
|
||||||
logger: null,
|
logger: null,
|
||||||
vpnExceptionIds: [],
|
vpnExceptionIds: [],
|
||||||
|
|
||||||
checkForVpn(origin) {
|
checkForVpn: function (origin) {
|
||||||
let exempt = false;
|
var exempt = false;
|
||||||
// prevent players that are exempt from being kicked
|
// prevent players that are exempt from being kicked
|
||||||
this.vpnExceptionIds.forEach(function (id) {
|
this.vpnExceptionIds.forEach(function (id) {
|
||||||
if (id === origin.ClientId) {
|
if (id === origin.ClientId) {
|
||||||
@ -21,43 +21,46 @@ const plugin = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let usingVPN = false;
|
var usingVPN = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let cl = new System.Net.Http.HttpClient();
|
var cl = new System.Net.Http.HttpClient();
|
||||||
let 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;
|
||||||
let co = re.Content;
|
var co = re.Content;
|
||||||
let parsedJSON = JSON.parse(co.ReadAsStringAsync().Result);
|
var parsedJSON = JSON.parse(co.ReadAsStringAsync().Result);
|
||||||
//co.Dispose();
|
// todo: does this work as expected now?
|
||||||
//re.Dispose();
|
co.Dispose();
|
||||||
//cl.Dispose();
|
re.Dispose();
|
||||||
usingVPN = parsedJSON['success'] && parsedJSON['proxy'];
|
cl.Dispose();
|
||||||
|
usingVPN = parsedJSON.success && parsedJSON.proxy;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.WriteError(e.message);
|
this.logger.WriteError(e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usingVPN) {
|
if (usingVPN) {
|
||||||
this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')');
|
this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')');
|
||||||
let library = importNamespace('SharedLibraryCore');
|
var library = importNamespace('SharedLibraryCore');
|
||||||
let kickOrigin = new library.Objects.Player();
|
var kickOrigin = new library.Objects.Player();
|
||||||
kickOrigin.ClientId = 1;
|
kickOrigin.ClientId = 1;
|
||||||
origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], kickOrigin);
|
origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], kickOrigin);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onEventAsync(gameEvent, server) {
|
onEventAsync: function (gameEvent, server) {
|
||||||
// connect event
|
// connect event
|
||||||
if (gameEvent.Type === 3) {
|
if (gameEvent.Type === 3) {
|
||||||
this.checkForVpn(gameEvent.Origin);
|
this.checkForVpn(gameEvent.Origin);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoadAsync(manager) {
|
onLoadAsync: function (manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.logger = manager.GetLogger();
|
this.logger = manager.GetLogger();
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync() { },
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
onTickAsync(server) { }
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
};
|
};
|
@ -43,15 +43,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
context.ChangeTracker.AutoDetectChangesEnabled = false;
|
context.ChangeTracker.AutoDetectChangesEnabled = false;
|
||||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
|
|
||||||
var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1);
|
var fifteenDaysAgo = DateTime.UtcNow.AddDays(-15);
|
||||||
var iqClientRatings = (from rating in context.Set<EFRating>()
|
var iqClientRatings = (from rating in context.Set<EFRating>()
|
||||||
#if DEBUG == false
|
|
||||||
where rating.ActivityAmount >= Plugin.Config.Configuration().TopPlayersMinPlayTime
|
|
||||||
#endif
|
|
||||||
where rating.RatingHistory.Client.Level != Player.Permission.Banned
|
|
||||||
where rating.RatingHistory.Client.LastConnection > thirtyDaysAgo
|
|
||||||
where rating.Newest
|
|
||||||
where rating.ServerId == null
|
where rating.ServerId == null
|
||||||
|
where rating.RatingHistory.Client.LastConnection > fifteenDaysAgo
|
||||||
|
where rating.RatingHistory.Client.Level != Player.Permission.Banned
|
||||||
|
where rating.Newest
|
||||||
|
where rating.ActivityAmount >= Plugin.Config.Configuration().TopPlayersMinPlayTime
|
||||||
orderby rating.Performance descending
|
orderby rating.Performance descending
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
@ -67,7 +65,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
var clientRatings = await iqClientRatings.ToListAsync();
|
var clientRatings = await iqClientRatings.ToListAsync();
|
||||||
|
|
||||||
var clientIds = clientRatings.GroupBy(r => r.ClientId).Select(r => r.First().ClientId).ToList();
|
var clientIds = clientRatings
|
||||||
|
.GroupBy(r => r.ClientId)
|
||||||
|
.Select(r => r.First().ClientId)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var iqStatsInfo = (from stat in context.Set<EFClientStatistics>()
|
var iqStatsInfo = (from stat in context.Set<EFClientStatistics>()
|
||||||
where clientIds.Contains(stat.ClientId)
|
where clientIds.Contains(stat.ClientId)
|
||||||
@ -101,8 +102,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
Performance = Math.Round(clientRatingsDict[s.ClientId].Performance, 2),
|
Performance = Math.Round(clientRatingsDict[s.ClientId].Performance, 2),
|
||||||
RatingChange = clientRatingsDict[s.ClientId].Ratings.First().Ranking - clientRatingsDict[s.ClientId].Ratings.Last().Ranking,
|
RatingChange = clientRatingsDict[s.ClientId].Ratings.First().Ranking - clientRatingsDict[s.ClientId].Ratings.Last().Ranking,
|
||||||
PerformanceHistory = clientRatingsDict[s.ClientId].Ratings.Count() > 1 ?
|
PerformanceHistory = clientRatingsDict[s.ClientId].Ratings.Count() > 1 ?
|
||||||
clientRatingsDict[s.ClientId].Ratings.Select(r => r.Performance).ToList() :
|
clientRatingsDict[s.ClientId].Ratings.Select(r => r.Performance).ToList() :
|
||||||
new List<double>() { clientRatingsDict[s.ClientId].Performance, clientRatingsDict[s.ClientId].Performance },
|
new List<double>() { clientRatingsDict[s.ClientId].Performance, clientRatingsDict[s.ClientId].Performance },
|
||||||
TimePlayed = Math.Round(clientRatingsDict[s.ClientId].TotalConnectionTime / 3600.0, 1).ToString("#,##0"),
|
TimePlayed = Math.Round(clientRatingsDict[s.ClientId].TotalConnectionTime / 3600.0, 1).ToString("#,##0"),
|
||||||
})
|
})
|
||||||
.OrderByDescending(r => r.Performance)
|
.OrderByDescending(r => r.Performance)
|
||||||
@ -324,7 +325,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task AddScriptHit(bool isDamage, DateTime time, Player attacker, Player victim, int serverId, string map, string hitLoc, string type,
|
public async Task AddScriptHit(bool isDamage, DateTime time, Player attacker, Player victim, int serverId, string map, string hitLoc, string type,
|
||||||
string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads, string fraction, string snapAngles)
|
string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads,
|
||||||
|
string fraction, string visibilityPercentage, string snapAngles)
|
||||||
{
|
{
|
||||||
var statsSvc = ContextThreads[serverId];
|
var statsSvc = ContextThreads[serverId];
|
||||||
Vector3 vDeathOrigin = null;
|
Vector3 vDeathOrigin = null;
|
||||||
@ -381,6 +383,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
IsKillstreakKill = isKillstreakKill[0] != '0',
|
IsKillstreakKill = isKillstreakKill[0] != '0',
|
||||||
AdsPercent = float.Parse(Ads),
|
AdsPercent = float.Parse(Ads),
|
||||||
Fraction = double.Parse(fraction),
|
Fraction = double.Parse(fraction),
|
||||||
|
VisibilityPercentage = double.Parse(visibilityPercentage),
|
||||||
IsKill = !isDamage,
|
IsKill = !isDamage,
|
||||||
AnglesList = snapshotAngles
|
AnglesList = snapshotAngles
|
||||||
};
|
};
|
||||||
@ -569,9 +572,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update their performance
|
// update their performance
|
||||||
//#if !DEBUG
|
#if !DEBUG
|
||||||
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >= 2.5)
|
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >= 2.5)
|
||||||
//#endif
|
#endif
|
||||||
{
|
{
|
||||||
await UpdateStatHistory(attacker, attackerStats);
|
await UpdateStatHistory(attacker, attackerStats);
|
||||||
attackerStats.LastStatHistoryUpdate = DateTime.UtcNow;
|
attackerStats.LastStatHistoryUpdate = DateTime.UtcNow;
|
||||||
@ -631,13 +634,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
ctx.Update(clientHistory);
|
ctx.Update(clientHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1);
|
var fifteenDaysAgo = DateTime.UtcNow.AddDays(-15);
|
||||||
// get the client ranking for the current server
|
// get the client ranking for the current server
|
||||||
int individualClientRanking = await ctx.Set<EFRating>()
|
int individualClientRanking = await ctx.Set<EFRating>()
|
||||||
.Where(c => c.ServerId == clientStats.ServerId)
|
.Where(c => c.ServerId == clientStats.ServerId)
|
||||||
|
.Where(r => r.RatingHistory.Client.LastConnection > fifteenDaysAgo)
|
||||||
.Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned)
|
.Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned)
|
||||||
.Where(r => r.ActivityAmount > Plugin.Config.Configuration().TopPlayersMinPlayTime)
|
.Where(r => r.ActivityAmount > Plugin.Config.Configuration().TopPlayersMinPlayTime)
|
||||||
.Where(r => r.RatingHistory.Client.LastConnection > thirtyDaysAgo)
|
|
||||||
.Where(c => c.RatingHistory.ClientId != client.ClientId)
|
.Where(c => c.RatingHistory.ClientId != client.ClientId)
|
||||||
.Where(r => r.Newest)
|
.Where(r => r.Newest)
|
||||||
.Where(c => c.Performance > clientStats.Performance)
|
.Where(c => c.Performance > clientStats.Performance)
|
||||||
@ -689,11 +692,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
int overallClientRanking = await ctx.Set<EFRating>()
|
int overallClientRanking = await ctx.Set<EFRating>()
|
||||||
.Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned)
|
.Where(r => r.ServerId == null)
|
||||||
|
.Where(r => r.RatingHistory.ClientId != client.ClientId)
|
||||||
|
.Where(r => r.RatingHistory.Client.LastConnection > fifteenDaysAgo)
|
||||||
|
.Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned)
|
||||||
.Where(r => r.ActivityAmount > Plugin.Config.Configuration().TopPlayersMinPlayTime)
|
.Where(r => r.ActivityAmount > Plugin.Config.Configuration().TopPlayersMinPlayTime)
|
||||||
.Where(r => r.RatingHistory.Client.LastConnection > thirtyDaysAgo)
|
|
||||||
.Where(r => r.RatingHistory.ClientId != client.ClientId)
|
|
||||||
.Where(r => r.ServerId == null)
|
|
||||||
.Where(r => r.Newest)
|
.Where(r => r.Newest)
|
||||||
.Where(r => r.Performance > performanceAverage)
|
.Where(r => r.Performance > performanceAverage)
|
||||||
.CountAsync() + 1;
|
.CountAsync() + 1;
|
||||||
@ -730,9 +733,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
catch (DbUpdateConcurrencyException e)
|
// this can happen when the client disconnects without any stat changes
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
public DateTime When { get; set; }
|
public DateTime When { get; set; }
|
||||||
public double Fraction { get; set; }
|
public double Fraction { get; set; }
|
||||||
public bool IsKill { get; set; }
|
public bool IsKill { get; set; }
|
||||||
|
public double VisibilityPercentage { get; set; }
|
||||||
// http://wiki.modsrepository.com/index.php?title=Call_of_Duty_5:_Gameplay_standards for conversion to meters
|
// http://wiki.modsrepository.com/index.php?title=Call_of_Duty_5:_Gameplay_standards for conversion to meters
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public double Distance => Vector3.Distance(KillOrigin, DeathOrigin) * 0.0254;
|
public double Distance => Vector3.Distance(KillOrigin, DeathOrigin) * 0.0254;
|
||||||
|
@ -76,7 +76,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
if (killInfo.Length >= 14)
|
if (killInfo.Length >= 14)
|
||||||
{
|
{
|
||||||
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Kill:
|
case GameEvent.EventType.Kill:
|
||||||
@ -92,7 +92,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
if (killInfo.Length >= 14)
|
if (killInfo.Length >= 14)
|
||||||
{
|
{
|
||||||
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
55
Plugins/Tests/PluginTests.cs
Normal file
55
Plugins/Tests/PluginTests.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using IW4MAdmin.Application;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Objects;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Tests
|
||||||
|
{
|
||||||
|
[Collection("ManagerCollection")]
|
||||||
|
public class PluginTests
|
||||||
|
{
|
||||||
|
readonly ApplicationManager Manager;
|
||||||
|
|
||||||
|
public PluginTests(ManagerFixture fixture)
|
||||||
|
{
|
||||||
|
Manager = fixture.Manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ClientSayObjectionalWordShouldWarn()
|
||||||
|
{
|
||||||
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Connect,
|
||||||
|
Origin = new Player()
|
||||||
|
{
|
||||||
|
Name = $"Player1",
|
||||||
|
NetworkId = 1,
|
||||||
|
ClientNumber = 1
|
||||||
|
},
|
||||||
|
Owner = Manager.GetServers()[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
e.OnProcessed.Wait();
|
||||||
|
|
||||||
|
var client = Manager.GetServers()[0].Players[0];
|
||||||
|
|
||||||
|
e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Say,
|
||||||
|
Origin = client,
|
||||||
|
Data = "nigger",
|
||||||
|
Owner = client.CurrentServer
|
||||||
|
};
|
||||||
|
|
||||||
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
e.OnProcessed.Wait();
|
||||||
|
|
||||||
|
Assert.True(client.Warnings == 1, "client wasn't warned for objectional language");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
README.md
46
README.md
@ -11,6 +11,9 @@ Latest binary builds are always available at https://raidmax.org/IW4MAdmin
|
|||||||
* [.NET Core 2.1 Runtime](https://www.microsoft.com/net/download) *or newer*
|
* [.NET Core 2.1 Runtime](https://www.microsoft.com/net/download) *or newer*
|
||||||
1. Extract `IW4MAdmin-<version>.zip`
|
1. Extract `IW4MAdmin-<version>.zip`
|
||||||
2. Run `StartIW4MAdmin.cmd`
|
2. Run `StartIW4MAdmin.cmd`
|
||||||
|
### Help
|
||||||
|
Feel free to join the **IW4MAdmin** [Discord](https://discord.gg/ZZFK5p3)
|
||||||
|
If you come across an issue, bug, or feature request please post an [issue](https://github.com/RaidMax/IW4M-Admin/issues)
|
||||||
___
|
___
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
@ -30,10 +33,6 @@ When **IW4MAdmin** is launched for the _first time_, you will be prompted to set
|
|||||||
* Shows a prefix to every message send by **IW4MAdmin** -- `[Admin] message`
|
* Shows a prefix to every message send by **IW4MAdmin** -- `[Admin] message`
|
||||||
* _This feature requires you specify a custom say name_
|
* _This feature requires you specify a custom say name_
|
||||||
|
|
||||||
`Enable client VPNs`
|
|
||||||
* Allow clients to use a [VPN](https://en.wikipedia.org/wiki/Virtual_private_network)
|
|
||||||
* _This feature requires an active api key on [iphub.info](https://iphub.info/)_
|
|
||||||
|
|
||||||
`Enable social link`
|
`Enable social link`
|
||||||
* Shows a link to your community's social media/website on the webfront
|
* Shows a link to your community's social media/website on the webfront
|
||||||
|
|
||||||
@ -82,9 +81,6 @@ If you wish to further customize your experience of **IW4MAdmin**, the following
|
|||||||
`RConPollRate`
|
`RConPollRate`
|
||||||
* Specifies (in milliseconds) how often to poll each server for updates
|
* Specifies (in milliseconds) how often to poll each server for updates
|
||||||
|
|
||||||
`VpnExceptionIds`
|
|
||||||
* Specifies the list of `Client IDs` exempt from the VPN check (if enabled)
|
|
||||||
|
|
||||||
`Servers`
|
`Servers`
|
||||||
* Specifies the list of servers **IW4MAdmin** will monitor
|
* Specifies the list of servers **IW4MAdmin** will monitor
|
||||||
* `IPAddress`
|
* `IPAddress`
|
||||||
@ -228,6 +224,9 @@ ___
|
|||||||
|
|
||||||
#### Stats
|
#### Stats
|
||||||
- This plugin calculates basic player performance, skill approximation, and kill/death ratio
|
- This plugin calculates basic player performance, skill approximation, and kill/death ratio
|
||||||
|
- Skill is an number derived from an algorithmic processing of a player's Kill Death Ratio (KDR) and Score per Minute (SPM).
|
||||||
|
- Elo Rating is based off of the number of encounters a player wins.
|
||||||
|
- Performance is the average of Skill + Elo Rating
|
||||||
|
|
||||||
**Commands added by this plugin**
|
**Commands added by this plugin**
|
||||||
|
|
||||||
@ -238,7 +237,7 @@ ___
|
|||||||
|topstats|ts|view the top 5 players on this server|False|!ts |User|
|
|topstats|ts|view the top 5 players on this server|False|!ts |User|
|
||||||
|mostplayed|mp|view the top 5 dedicated players on the server|False|!mp |User|
|
|mostplayed|mp|view the top 5 dedicated players on the server|False|!mp |User|
|
||||||
|
|
||||||
- To qualify for top stats, a client must have played for at least `1 hour` and connected within the past `30 days`.
|
- To qualify for top stats, a client must have played for at least `3 hours` and connected within the past `15 days`.
|
||||||
|
|
||||||
#### Login
|
#### Login
|
||||||
- This plugin deters GUID spoofing by requiring privileged users to login with their password before executing commands
|
- This plugin deters GUID spoofing by requiring privileged users to login with their password before executing commands
|
||||||
@ -254,6 +253,14 @@ ___
|
|||||||
- This plugin warns and kicks players for using profanity
|
- This plugin warns and kicks players for using profanity
|
||||||
- Profane words and warning message can be specified in `ProfanityDetermentSettings.json`
|
- Profane words and warning message can be specified in `ProfanityDetermentSettings.json`
|
||||||
- If a client's name contains a word listed in the settings, they will immediately be kicked
|
- If a client's name contains a word listed in the settings, they will immediately be kicked
|
||||||
|
|
||||||
|
####IW4 Script Commands
|
||||||
|
- This plugin provides additional integration to IW4x
|
||||||
|
- In order to take advantage of it, copy the `userraw` folder into your IW4x server directory
|
||||||
|
|
||||||
|
####VPN Detection [Script Plugin]
|
||||||
|
- This plugin detects if a client is using a VPN and kicks them if they are
|
||||||
|
- To disable this plugin, delete `Plugins\VPNDetection.js`
|
||||||
___
|
___
|
||||||
### Webfront
|
### Webfront
|
||||||
`Home`
|
`Home`
|
||||||
@ -274,34 +281,35 @@ ___
|
|||||||
|
|
||||||
`Web Console`
|
`Web Console`
|
||||||
* Allows logged in privileged users to execute commands as if they are in-game
|
* Allows logged in privileged users to execute commands as if they are in-game
|
||||||
|
|
||||||
---
|
---
|
||||||
### Extending Plugins
|
### Extending Plugins
|
||||||
#### Code
|
#### Code
|
||||||
IW4Madmin functionality can be extended by writing additional plugins in C#.
|
IW4Madmin functionality can be extended by writing additional plugins in C#.
|
||||||
|
Each class library must implement the `IPlugin` interface.
|
||||||
|
See the existing plugins for examples.
|
||||||
#### JavaScript
|
#### JavaScript
|
||||||
IW4MAdmin functionality can be extended using JavaScript.
|
IW4MAdmin functionality can be extended using JavaScript.
|
||||||
The JavaScript parser supports [some](https://github.com/sebastienros/jint/issues/343) of ECMAScript 6's new features.
|
The JavaScript parser supports [ECMA 5.1](https://ecma-international.org/ecma-262/5.1/) standards.
|
||||||
#### Plugin Object Template
|
#### Plugin Object Template
|
||||||
In order to be properly parsed by the JavaScript engine, every plugin must conform to the following template.
|
In order to be properly parsed by the JavaScript engine, every plugin must conform to the following template.
|
||||||
```js
|
```js
|
||||||
const plugin = {
|
var plugin = {
|
||||||
author: 'YourHandle',
|
author: 'YourHandle',
|
||||||
version: 1.0,
|
version: 1.0,
|
||||||
name: 'Sample JavaScript Plugin',
|
name: 'Sample JavaScript Plugin',
|
||||||
|
|
||||||
onEventAsync(gameEvent, server) {
|
onEventAsync: function (gameEvent, server) {
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoadAsync(manager) {
|
onLoadAsync: function (manager) {
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync() {
|
onUnloadAsync: function () {
|
||||||
},
|
},
|
||||||
|
|
||||||
onTickAsync(server) {
|
onTickAsync: function (server) {
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
#### Required Properties
|
#### Required Properties
|
||||||
- `author` — [string] Author of the plugin (usually your name or online name/alias)
|
- `author` — [string] Author of the plugin (usually your name or online name/alias)
|
||||||
@ -333,9 +341,9 @@ setuptools>=39.0.1
|
|||||||
urllib3>=1.23
|
urllib3>=1.23
|
||||||
```
|
```
|
||||||
#### Configuration Options
|
#### Configuration Options
|
||||||
- `IW4MAdminUrl` — Base url corresponding to your IW4MAdmin `WebfrontBindUrl`.
|
- `IW4MAdminUrl` — Base url corresponding to your IW4MAdmin `WebfrontBindUrl`.
|
||||||
Example http://127.0.0.1
|
Example http://127.0.0.1
|
||||||
- `DiscordWebhookNotificationUrl` — [required] Discord generated URL to send notifications/alerts to; this includes **Reports** and **Bans**
|
- `DiscordWebhookNotificationUrl` — [required] Discord generated URL to send notifications/alerts to; this includes **Reports** and **Bans**
|
||||||
Example https://discordapp.com/api/webhooks/id/token
|
Example https://discordapp.com/api/webhooks/id/token
|
||||||
- `DiscordWebhookInformationUrl` — [optional] Discord generated URL to send information to; this includes information such as player messages
|
- `DiscordWebhookInformationUrl` — [optional] Discord generated URL to send information to; this includes information such as player messages
|
||||||
- `NotifyRoleIds` — [optional] List of [discord role ids](https://discordhelp.net/role-id) to mention when notification hook is sent
|
- `NotifyRoleIds` — [optional] List of [discord role ids](https://discordhelp.net/role-id) to mention when notification hook is sent
|
||||||
|
@ -10,19 +10,16 @@ namespace SharedLibraryCore.Configuration
|
|||||||
public bool EnableWebFront { get; set; }
|
public bool EnableWebFront { get; set; }
|
||||||
public bool EnableMultipleOwners { get; set; }
|
public bool EnableMultipleOwners { get; set; }
|
||||||
public bool EnableSteppedHierarchy { get; set; }
|
public bool EnableSteppedHierarchy { get; set; }
|
||||||
public bool EnableClientVPNs { get; set; }
|
|
||||||
public bool EnableSocialLink { get; set; }
|
public bool EnableSocialLink { get; set; }
|
||||||
public bool EnableCustomSayName { get; set; }
|
public bool EnableCustomSayName { get; set; }
|
||||||
public string CustomSayName { get; set; }
|
public string CustomSayName { get; set; }
|
||||||
public string SocialLinkAddress { get; set; }
|
public string SocialLinkAddress { get; set; }
|
||||||
public string SocialLinkTitle { get; set; }
|
public string SocialLinkTitle { get; set; }
|
||||||
public string IPHubAPIKey { get; set; }
|
|
||||||
public string WebfrontBindUrl { get; set; }
|
public string WebfrontBindUrl { get; set; }
|
||||||
public string CustomParserEncoding { get; set; }
|
public string CustomParserEncoding { get; set; }
|
||||||
public string CustomLocale { get; set; }
|
public string CustomLocale { get; set; }
|
||||||
public string ConnectionString { get; set; }
|
public string ConnectionString { get; set; }
|
||||||
public int RConPollRate { get; set; } = 5000;
|
public int RConPollRate { get; set; } = 5000;
|
||||||
public List<int> VpnExceptionIds { get; set; }
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public List<ServerConfiguration> Servers { get; set; }
|
public List<ServerConfiguration> Servers { get; set; }
|
||||||
public int AutoMessagePeriod { get; set; }
|
public int AutoMessagePeriod { get; set; }
|
||||||
@ -43,16 +40,11 @@ namespace SharedLibraryCore.Configuration
|
|||||||
bool useCustomParserEncoding = Utilities.PromptBool(loc["SETUP_USE_CUSTOMENCODING"]);
|
bool useCustomParserEncoding = Utilities.PromptBool(loc["SETUP_USE_CUSTOMENCODING"]);
|
||||||
CustomParserEncoding = useCustomParserEncoding ? Utilities.PromptString(loc["SETUP_ENCODING_STRING"]) : "windows-1252";
|
CustomParserEncoding = useCustomParserEncoding ? Utilities.PromptString(loc["SETUP_ENCODING_STRING"]) : "windows-1252";
|
||||||
|
|
||||||
WebfrontBindUrl = "http://127.0.0.1:1624";
|
WebfrontBindUrl = "http://0.0.0.0:1624";
|
||||||
|
|
||||||
if (EnableCustomSayName)
|
if (EnableCustomSayName)
|
||||||
CustomSayName = Utilities.PromptString(loc["SETUP_SAY_NAME"]);
|
CustomSayName = Utilities.PromptString(loc["SETUP_SAY_NAME"]);
|
||||||
|
|
||||||
EnableClientVPNs = Utilities.PromptBool(loc["SETUP_ENABLE_VPNS"]);
|
|
||||||
|
|
||||||
if (!EnableClientVPNs)
|
|
||||||
IPHubAPIKey = Utilities.PromptString(loc["SETUP_IPHUB_KEY"]);
|
|
||||||
|
|
||||||
EnableSocialLink = Utilities.PromptBool(loc["SETUP_DISPLAY_SOCIAL"]);
|
EnableSocialLink = Utilities.PromptBool(loc["SETUP_DISPLAY_SOCIAL"]);
|
||||||
|
|
||||||
if (EnableSocialLink)
|
if (EnableSocialLink)
|
||||||
@ -60,7 +52,7 @@ namespace SharedLibraryCore.Configuration
|
|||||||
SocialLinkTitle = Utilities.PromptString(loc["SETUP_SOCIAL_TITLE"]);
|
SocialLinkTitle = Utilities.PromptString(loc["SETUP_SOCIAL_TITLE"]);
|
||||||
SocialLinkAddress = Utilities.PromptString(loc["SETUP_SOCIAL_LINK"]);
|
SocialLinkAddress = Utilities.PromptString(loc["SETUP_SOCIAL_LINK"]);
|
||||||
}
|
}
|
||||||
VpnExceptionIds = new List<int>();
|
|
||||||
RConPollRate = 5000;
|
RConPollRate = 5000;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -13,6 +13,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// Add a game event event to the queue to be processed
|
/// Add a game event event to the queue to be processed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameEvent">Game event</param>
|
/// <param name="gameEvent">Game event</param>
|
||||||
bool AddEvent(GameEvent gameEvent);
|
void AddEvent(GameEvent gameEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
665
SharedLibraryCore/Migrations/20180904154622_AddVisibilityPercentage.Designer.cs
generated
Normal file
665
SharedLibraryCore/Migrations/20180904154622_AddVisibilityPercentage.Designer.cs
generated
Normal file
@ -0,0 +1,665 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20180904154622_AddVisibilityPercentage")]
|
||||||
|
partial class AddVisibilityPercentage
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.1.2-rtm-30932");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SnapshotId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentSessionLength");
|
||||||
|
|
||||||
|
b.Property<double>("CurrentStrain");
|
||||||
|
|
||||||
|
b.Property<int?>("CurrentViewAngleVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("Distance");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int?>("HitDestinationVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("HitLocation");
|
||||||
|
|
||||||
|
b.Property<int?>("HitOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("HitType");
|
||||||
|
|
||||||
|
b.Property<int>("Hits");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<int?>("LastStrainAngleVector3Id");
|
||||||
|
|
||||||
|
b.Property<double>("SessionAngleOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionSPM");
|
||||||
|
|
||||||
|
b.Property<int>("SessionScore");
|
||||||
|
|
||||||
|
b.Property<double>("StrainAngleBetween");
|
||||||
|
|
||||||
|
b.Property<int>("TimeSinceLastEvent");
|
||||||
|
|
||||||
|
b.Property<int>("WeaponId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentViewAngleVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("HitDestinationVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("HitOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("LastStrainAngleVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshot");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("KillId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AttackerId");
|
||||||
|
|
||||||
|
b.Property<int>("Damage");
|
||||||
|
|
||||||
|
b.Property<int?>("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("DeathType");
|
||||||
|
|
||||||
|
b.Property<double>("Fraction");
|
||||||
|
|
||||||
|
b.Property<int>("HitLoc");
|
||||||
|
|
||||||
|
b.Property<bool>("IsKill");
|
||||||
|
|
||||||
|
b.Property<int?>("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Map");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<int>("VictimId");
|
||||||
|
|
||||||
|
b.Property<int?>("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.Property<double>("VisibilityPercentage");
|
||||||
|
|
||||||
|
b.Property<int>("Weapon");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("KillId");
|
||||||
|
|
||||||
|
b.HasIndex("AttackerId");
|
||||||
|
|
||||||
|
b.HasIndex("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("VictimId");
|
||||||
|
|
||||||
|
b.HasIndex("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFClientKills");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("MessageId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeSent");
|
||||||
|
|
||||||
|
b.HasKey("MessageId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.HasKey("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientRatingHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<double>("MaxStrain");
|
||||||
|
|
||||||
|
b.Property<double>("RollingWeightedKDR");
|
||||||
|
|
||||||
|
b.Property<double>("SPM");
|
||||||
|
|
||||||
|
b.Property<double>("Skill");
|
||||||
|
|
||||||
|
b.Property<int>("TimePlayed");
|
||||||
|
|
||||||
|
b.HasKey("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("HitLocationCountId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnName("EFClientStatistics_ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("HitCount");
|
||||||
|
|
||||||
|
b.Property<float>("HitOffsetAverage");
|
||||||
|
|
||||||
|
b.Property<int>("Location");
|
||||||
|
|
||||||
|
b.Property<float>("MaxAngleDistance");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId")
|
||||||
|
.HasColumnName("EFClientStatistics_ServerId");
|
||||||
|
|
||||||
|
b.HasKey("HitLocationCountId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFHitLocationCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityAmount");
|
||||||
|
|
||||||
|
b.Property<bool>("Newest");
|
||||||
|
|
||||||
|
b.Property<double>("Performance");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking");
|
||||||
|
|
||||||
|
b.Property<int>("RatingHistoryId");
|
||||||
|
|
||||||
|
b.Property<int?>("ServerId");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("Port");
|
||||||
|
|
||||||
|
b.HasKey("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatisticId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<long>("TotalKills");
|
||||||
|
|
||||||
|
b.Property<long>("TotalPlayTime");
|
||||||
|
|
||||||
|
b.HasKey("StatisticId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServerStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int>("IPAddress");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAlias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("AliasLinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAliasLinks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ChangeHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasMaxLength(128);
|
||||||
|
|
||||||
|
b.Property<int>("OriginEntityId");
|
||||||
|
|
||||||
|
b.Property<int>("TargetEntityId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeChanged");
|
||||||
|
|
||||||
|
b.Property<int>("TypeOfChange");
|
||||||
|
|
||||||
|
b.HasKey("ChangeHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFChangeHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AliasLinkId");
|
||||||
|
|
||||||
|
b.Property<int>("Connections");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentAliasId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstConnection");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastConnection");
|
||||||
|
|
||||||
|
b.Property<int>("Level");
|
||||||
|
|
||||||
|
b.Property<bool>("Masked");
|
||||||
|
|
||||||
|
b.Property<long>("NetworkId");
|
||||||
|
|
||||||
|
b.Property<string>("Password");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt");
|
||||||
|
|
||||||
|
b.Property<int>("TotalConnectionTime");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("AliasLinkId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentAliasId");
|
||||||
|
|
||||||
|
b.HasIndex("NetworkId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFClients");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MetaId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created");
|
||||||
|
|
||||||
|
b.Property<string>("Extra");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<DateTime>("Updated");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("MetaId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFMeta");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PenaltyId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<int>("OffenderId");
|
||||||
|
|
||||||
|
b.Property<string>("Offense")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("PunisherId");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("PenaltyId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("OffenderId");
|
||||||
|
|
||||||
|
b.HasIndex("PunisherId");
|
||||||
|
|
||||||
|
b.ToTable("EFPenalties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int?>("EFACSnapshotSnapshotId");
|
||||||
|
|
||||||
|
b.Property<float>("X");
|
||||||
|
|
||||||
|
b.Property<float>("Y");
|
||||||
|
|
||||||
|
b.Property<float>("Z");
|
||||||
|
|
||||||
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
|
b.ToTable("Vector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentViewAngleVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitDestinationVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LastStrainAngleVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AttackerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("VictimId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ViewAnglesVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
|
||||||
|
.WithMany("HitLocations")
|
||||||
|
.HasForeignKey("ClientId", "ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||||
|
.WithMany("Ratings")
|
||||||
|
.HasForeignKey("RatingHistoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AliasLinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentAliasId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany("Meta")
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("OffenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||||
|
.WithMany("AdministeredPenalties")
|
||||||
|
.HasForeignKey("PunisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
|
||||||
|
.WithMany("PredictedViewAngles")
|
||||||
|
.HasForeignKey("EFACSnapshotSnapshotId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddVisibilityPercentage : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "VisibilityPercentage",
|
||||||
|
table: "EFClientKills",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "VisibilityPercentage",
|
||||||
|
table: "EFClientKills");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -111,6 +111,8 @@ namespace SharedLibraryCore.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("ViewAnglesVector3Id");
|
b.Property<int?>("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.Property<double>("VisibilityPercentage");
|
||||||
|
|
||||||
b.Property<int>("Weapon");
|
b.Property<int>("Weapon");
|
||||||
|
|
||||||
b.Property<DateTime>("When");
|
b.Property<DateTime>("When");
|
||||||
|
@ -17,19 +17,14 @@ namespace SharedLibraryCore.RCon
|
|||||||
public int BufferSize { get; private set; }
|
public int BufferSize { get; private set; }
|
||||||
public byte[] Buffer { get; private set; }
|
public byte[] Buffer { get; private set; }
|
||||||
|
|
||||||
private readonly StringBuilder sb;
|
public StringBuilder ResponseString { get; }
|
||||||
|
|
||||||
public StringBuilder ResponseString
|
|
||||||
{
|
|
||||||
get => sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConnectionState(Socket cl)
|
public ConnectionState(Socket cl)
|
||||||
{
|
{
|
||||||
BufferSize = 8192;
|
BufferSize = 8192;
|
||||||
Buffer = new byte[BufferSize];
|
Buffer = new byte[BufferSize];
|
||||||
Client = cl;
|
Client = cl;
|
||||||
sb = new StringBuilder();
|
ResponseString = new StringBuilder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,6 @@ namespace SharedLibraryCore.RCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||||
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 5);
|
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
Manager = mgr;
|
Manager = mgr;
|
||||||
string script = File.ReadAllText(FileName);
|
string script = File.ReadAllText(FileName);
|
||||||
ScriptEngine = new Jint.Engine(cfg =>
|
ScriptEngine = new Jint.Engine(cfg =>
|
||||||
cfg.AllowClr(new[]
|
cfg.AllowClr(new[]
|
||||||
{
|
{
|
||||||
typeof(System.Net.Http.HttpClient).Assembly,
|
typeof(System.Net.Http.HttpClient).Assembly,
|
||||||
typeof(Objects.Player).Assembly,
|
typeof(Objects.Player).Assembly,
|
||||||
@ -82,9 +82,12 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
public Task OnEventAsync(GameEvent E, Server S)
|
public Task OnEventAsync(GameEvent E, Server S)
|
||||||
{
|
{
|
||||||
ScriptEngine.SetValue("_gameEvent", E);
|
lock (ScriptEngine)
|
||||||
ScriptEngine.SetValue("_server", S);
|
{
|
||||||
return Task.FromResult(ScriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue());
|
ScriptEngine.SetValue("_gameEvent", E);
|
||||||
|
ScriptEngine.SetValue("_server", S);
|
||||||
|
return Task.FromResult(ScriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnLoadAsync(IManager manager)
|
public Task OnLoadAsync(IManager manager)
|
||||||
|
@ -117,7 +117,7 @@ namespace SharedLibraryCore
|
|||||||
public async Task Broadcast(String Message)
|
public async Task Broadcast(String Message)
|
||||||
{
|
{
|
||||||
#if DEBUG == false
|
#if DEBUG == false
|
||||||
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, Message);
|
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{Message}");
|
||||||
#else
|
#else
|
||||||
Logger.WriteVerbose(Message.StripColors());
|
Logger.WriteVerbose(Message.StripColors());
|
||||||
#endif
|
#endif
|
||||||
@ -145,7 +145,7 @@ namespace SharedLibraryCore
|
|||||||
public async Task Tell(String Message, Player Target)
|
public async Task Tell(String Message, Player Target)
|
||||||
{
|
{
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Tell, Target.ClientNumber, Message);
|
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Tell, Target.ClientNumber, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{Message}");
|
||||||
if (Target.ClientNumber > -1 && Message.Length > 0 && Target.Level != Player.Permission.Console)
|
if (Target.ClientNumber > -1 && Message.Length > 0 && Target.Level != Player.Permission.Console)
|
||||||
await this.ExecuteCommandAsync(formattedMessage);
|
await this.ExecuteCommandAsync(formattedMessage);
|
||||||
#else
|
#else
|
||||||
@ -160,9 +160,11 @@ namespace SharedLibraryCore
|
|||||||
Console.ForegroundColor = ConsoleColor.Gray;
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prevent this from queueing up too many command responses
|
||||||
if (CommandResult.Count > 15)
|
if (CommandResult.Count > 15)
|
||||||
CommandResult.RemoveAt(0);
|
CommandResult.RemoveAt(0);
|
||||||
|
|
||||||
|
// it was a remote command so we need to add it to the command result queue
|
||||||
if (Target.ClientNumber < 0)
|
if (Target.ClientNumber < 0)
|
||||||
{
|
{
|
||||||
CommandResult.Add(new CommandResponseInfo()
|
CommandResult.Add(new CommandResponseInfo()
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Jint" Version="3.0.0-beta-1249" />
|
<PackageReference Include="Jint" Version="2.11.58" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.2" />
|
||||||
|
@ -12,6 +12,26 @@ init()
|
|||||||
level waittill("prematch_over");
|
level waittill("prematch_over");
|
||||||
level.callbackPlayerKilled = ::Callback_PlayerKilled;
|
level.callbackPlayerKilled = ::Callback_PlayerKilled;
|
||||||
level.callbackPlayerDamage = ::Callback_PlayerDamage;
|
level.callbackPlayerDamage = ::Callback_PlayerDamage;
|
||||||
|
level.playerTags = [];
|
||||||
|
level.playerTags[0] = "j_head";
|
||||||
|
level.playerTags[1] = "j_neck";
|
||||||
|
level.playerTags[2] = "j_spineupper";
|
||||||
|
level.playerTags[3] = "j_spinelower";
|
||||||
|
level.playerTags[4] = "j_shoulder_ri";
|
||||||
|
level.playerTags[5] = "j_shoulder_le";
|
||||||
|
level.playerTags[6] = "j_elbow_ri";
|
||||||
|
level.playerTags[7] = "j_spineupper";
|
||||||
|
level.playerTags[8] = "j_spineupper";
|
||||||
|
level.playerTags[9] = "j_elbow_le";
|
||||||
|
level.playerTags[10] = "j_wrist_ri";
|
||||||
|
level.playerTags[11] = "j_wrist_le";
|
||||||
|
level.playerTags[12] = "j_hip_ri";
|
||||||
|
level.playerTags[13] = "j_hip_le";
|
||||||
|
level.playerTags[14] = "j_knee_ri";
|
||||||
|
level.playerTags[15] = "j_knee_le";
|
||||||
|
level.playerTags[16] = "j_ankle_ri";
|
||||||
|
level.playerTags[17] = "j_ankle_le";
|
||||||
|
level.playerTags[18] = "j_helmet";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -112,6 +132,21 @@ waitForAdditionalAngles(logString)
|
|||||||
logPrint(logString + ";" + anglesStr + "\n");
|
logPrint(logString + ";" + anglesStr + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runVisibilityCheck(attacker, victim)
|
||||||
|
{
|
||||||
|
start = attacker getTagOrigin("tag_eye");
|
||||||
|
traceSucceedCount = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 19; i++)
|
||||||
|
{
|
||||||
|
if (sightTracePassed(start, victim getTagOrigin(level.playerTags[i]), false, attacker))
|
||||||
|
{
|
||||||
|
traceSucceedCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return traceSucceedCount / 20;
|
||||||
|
}
|
||||||
|
|
||||||
vectorScale(vector, scale)
|
vectorScale(vector, scale)
|
||||||
{
|
{
|
||||||
return (vector[0] * scale, vector[1] * scale, vector[2] * scale);
|
return (vector[0] * scale, vector[1] * scale, vector[2] * scale);
|
||||||
@ -134,7 +169,9 @@ Process_Hit(type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon)
|
|||||||
end = location;
|
end = location;
|
||||||
trace = bulletTrace(start, end, true, _attacker);
|
trace = bulletTrace(start, end, true, _attacker);
|
||||||
|
|
||||||
logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";" + trace["fraction"];
|
playerVisibilityPercentage = runVisibilityCheck(_attacker, victim);
|
||||||
|
|
||||||
|
logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";" + trace["fraction"] + ";" + playerVisibilityPercentage;
|
||||||
attacker thread waitForAdditionalAngles(logLine);
|
attacker thread waitForAdditionalAngles(logLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user