diff --git a/.gitignore b/.gitignore
index 890f16a1b..28797a3e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -229,4 +229,6 @@ bootstrap-custom.min.css
/DiscordWebhook/env
/DiscordWebhook/config.dev.json
/GameLogServer/env
-launchSettings.json
\ No newline at end of file
+launchSettings.json
+/VpnDetectionPrivate.js
+/Plugins/ScriptPlugins/VpnDetectionPrivate.js
diff --git a/Application/Application.csproj b/Application/Application.csproj
index 80fd79210..a1fc11b2f 100644
--- a/Application/Application.csproj
+++ b/Application/Application.csproj
@@ -6,7 +6,7 @@
2.1.5
false
RaidMax.IW4MAdmin.Application
- 2.2.1.0
+ 2.2.2.0
RaidMax
Forever None
IW4MAdmin
@@ -31,8 +31,8 @@
true
true
- 2.2.1.0
- 2.2.1.0
+ 2.2.2.0
+ 2.2.2.0
diff --git a/Application/Core/ClientAuthentication.cs b/Application/Core/ClientAuthentication.cs
index db3640f9e..fa064493c 100644
--- a/Application/Core/ClientAuthentication.cs
+++ b/Application/Core/ClientAuthentication.cs
@@ -1,4 +1,5 @@
-using SharedLibraryCore.Interfaces;
+using SharedLibraryCore.Database.Models;
+using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Objects;
using System;
using System.Collections.Generic;
@@ -9,16 +10,16 @@ namespace IW4MAdmin.Application.Core
{
class ClientAuthentication : IClientAuthentication
{
- private Queue ClientAuthenticationQueue;
- private Dictionary AuthenticatedClients;
+ private Queue ClientAuthenticationQueue;
+ private Dictionary AuthenticatedClients;
public ClientAuthentication()
{
- ClientAuthenticationQueue = new Queue();
- AuthenticatedClients = new Dictionary();
+ ClientAuthenticationQueue = new Queue();
+ AuthenticatedClients = new Dictionary();
}
- public void AuthenticateClients(IList clients)
+ public void AuthenticateClients(IList clients)
{
// we need to un-auth all the clients that have disconnected
var clientNetworkIds = clients.Select(c => c.NetworkId);
@@ -33,10 +34,10 @@ namespace IW4MAdmin.Application.Core
foreach (var client in clients)
{
// they've not been authenticated
- if (!AuthenticatedClients.TryGetValue(client.NetworkId, out Player value))
+ if (!AuthenticatedClients.TryGetValue(client.NetworkId, out EFClient value))
{
// authenticate them
- client.State = Player.ClientState.Authenticated;
+ client.State = EFClient.ClientState.Authenticated;
AuthenticatedClients.Add(client.NetworkId, client);
}
else
@@ -54,16 +55,16 @@ namespace IW4MAdmin.Application.Core
// grab each client that's connected via log
var clientToAuthenticate = ClientAuthenticationQueue.Dequeue();
// if they're not already authed, auth them
- if (!AuthenticatedClients.TryGetValue(clientToAuthenticate.NetworkId, out Player value))
+ if (!AuthenticatedClients.TryGetValue(clientToAuthenticate.NetworkId, out EFClient value))
{
// authenticate them
- clientToAuthenticate.State = Player.ClientState.Authenticated;
+ clientToAuthenticate.State = EFClient.ClientState.Authenticated;
AuthenticatedClients.Add(clientToAuthenticate.NetworkId, clientToAuthenticate);
}
}
}
- public IList GetAuthenticatedClients()
+ public IList GetAuthenticatedClients()
{
if (AuthenticatedClients.Values.Count > 18)
{
@@ -74,7 +75,7 @@ namespace IW4MAdmin.Application.Core
return AuthenticatedClients.Values.ToList();
}
- public void RequestClientAuthentication(Player client)
+ public void RequestClientAuthentication(EFClient client)
{
ClientAuthenticationQueue.Enqueue(client);
}
diff --git a/Application/EventParsers/IW4EventParser.cs b/Application/EventParsers/IW4EventParser.cs
index d0f80fdd5..cdbb5fd79 100644
--- a/Application/EventParsers/IW4EventParser.cs
+++ b/Application/EventParsers/IW4EventParser.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using SharedLibraryCore;
+using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Objects;
@@ -20,7 +21,7 @@ namespace IW4MAdmin.Application.EventParsers
if (eventType == "JoinTeam")
{
- var origin = server.GetPlayersAsList().FirstOrDefault(c => c.NetworkId == lineSplit[1].ConvertLong());
+ var origin = server.GetClientsAsList().FirstOrDefault(c => c.NetworkId == lineSplit[1].ConvertLong());
return new GameEvent()
{
@@ -41,7 +42,7 @@ namespace IW4MAdmin.Application.EventParsers
.Replace("\x15", "")
.Trim();
- var origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2));
+ var origin = server.GetClientsAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2));
if (message[0] == '!' || message[0] == '@')
{
@@ -70,8 +71,8 @@ namespace IW4MAdmin.Application.EventParsers
{
if (!server.CustomCallback)
{
- var origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6));
- var target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2));
+ var origin = server.GetClientsAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6));
+ var target = server.GetClientsAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2));
return new GameEvent()
{
@@ -86,8 +87,8 @@ namespace IW4MAdmin.Application.EventParsers
if (eventType == "ScriptKill")
{
- var origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
- var target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong());
+ var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
+ var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong());
return new GameEvent()
{
Type = GameEvent.EventType.ScriptKill,
@@ -100,8 +101,8 @@ namespace IW4MAdmin.Application.EventParsers
if (eventType == "ScriptDamage")
{
- var origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
- var target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong());
+ var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
+ var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong());
return new GameEvent()
{
@@ -120,8 +121,8 @@ namespace IW4MAdmin.Application.EventParsers
{
if (Regex.Match(eventType, @"^(D);((?:bot[0-9]+)|(?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$").Success)
{
- var origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong());
- var target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
+ var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong());
+ var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
return new GameEvent()
{
@@ -146,12 +147,12 @@ namespace IW4MAdmin.Application.EventParsers
Type = GameEvent.EventType.Join,
Data = logLine,
Owner = server,
- Origin = new Player()
+ Origin = new EFClient()
{
Name = regexMatch.Groups[4].ToString().StripColors(),
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
- State = Player.ClientState.Connecting,
+ State = EFClient.ClientState.Connecting,
CurrentServer = server
}
};
@@ -185,11 +186,11 @@ namespace IW4MAdmin.Application.EventParsers
{
Type = GameEvent.EventType.MapEnd,
Data = lineSplit[0],
- Origin = new Player()
+ Origin = new EFClient()
{
ClientId = 1
},
- Target = new Player()
+ Target = new EFClient()
{
ClientId = 1
},
@@ -205,14 +206,8 @@ namespace IW4MAdmin.Application.EventParsers
{
Type = GameEvent.EventType.MapChange,
Data = lineSplit[0],
- Origin = new Player()
- {
- ClientId = 1
- },
- Target = new Player()
- {
- ClientId = 1
- },
+ Origin = Utilities.IW4MAdminClient(server),
+ Target = Utilities.IW4MAdminClient(server),
Owner = server,
Extra = dump.DictionaryFromKeyValue()
};
@@ -221,14 +216,8 @@ namespace IW4MAdmin.Application.EventParsers
return new GameEvent()
{
Type = GameEvent.EventType.Unknown,
- Origin = new Player()
- {
- ClientId = 1
- },
- Target = new Player()
- {
- ClientId = 1
- },
+ Origin = Utilities.IW4MAdminClient(server),
+ Target = Utilities.IW4MAdminClient(server),
Owner = server
};
}
diff --git a/Application/EventParsers/IW5EventParser.cs b/Application/EventParsers/IW5EventParser.cs
index e452bdaa7..429b1bc32 100644
--- a/Application/EventParsers/IW5EventParser.cs
+++ b/Application/EventParsers/IW5EventParser.cs
@@ -1,4 +1,5 @@
using SharedLibraryCore;
+using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Objects;
using System;
@@ -23,7 +24,7 @@ namespace IW4MAdmin.Application.EventParsers
int clientNum = Int32.Parse(lineSplit[2]);
- var player = new Player()
+ var player = new EFClient()
{
NetworkId = lineSplit[1].ConvertLong(),
ClientNumber = clientNum,
@@ -33,11 +34,11 @@ namespace IW4MAdmin.Application.EventParsers
return new GameEvent()
{
Type = GameEvent.EventType.Join,
- Origin = new Player()
+ Origin = new EFClient()
{
ClientId = 1
},
- Target = new Player()
+ Target = new EFClient()
{
ClientId = 1
},
diff --git a/Application/Main.cs b/Application/Main.cs
index 6ea5b2164..8f19df87a 100644
--- a/Application/Main.cs
+++ b/Application/Main.cs
@@ -110,7 +110,7 @@ namespace IW4MAdmin.Application
var consoleTask = Task.Run(async () =>
{
String userInput;
- Player Origin = Utilities.IW4MAdminClient(ServerManager.Servers[0]);
+ var Origin = Utilities.IW4MAdminClient(ServerManager.Servers[0]);
do
{
diff --git a/Application/Manager.cs b/Application/Manager.cs
index be9aeb84c..b9b3bf8f2 100644
--- a/Application/Manager.cs
+++ b/Application/Manager.cs
@@ -19,6 +19,7 @@ using SharedLibraryCore.Events;
using IW4MAdmin.Application.API.Master;
using IW4MAdmin.Application.Migration;
+using SharedLibraryCore.Database.Models;
namespace IW4MAdmin.Application
{
@@ -26,7 +27,7 @@ namespace IW4MAdmin.Application
{
private List _servers;
public List Servers => _servers.OrderByDescending(s => s.ClientNum).ToList();
- public Dictionary PrivilegedClients { get; set; }
+ public Dictionary PrivilegedClients { get; set; }
public ILogger Logger => GetLogger(0);
public bool Running { get; private set; }
public bool IsInitialized { get; private set; }
@@ -60,7 +61,7 @@ namespace IW4MAdmin.Application
ClientSvc = new ClientService();
AliasSvc = new AliasService();
PenaltySvc = new PenaltyService();
- PrivilegedClients = new Dictionary();
+ PrivilegedClients = new Dictionary();
ConfigHandler = new BaseConfigurationHandler("IW4MAdminSettings");
StartTime = DateTime.UtcNow;
OnQuit = new ManualResetEventSlim();
@@ -144,7 +145,7 @@ namespace IW4MAdmin.Application
if (e.Target != null)
{
// update the target incase they left or have newer info
- e.Target = newEvent.Owner.GetPlayersAsList()
+ e.Target = newEvent.Owner.GetClientsAsList()
.FirstOrDefault(p => p.NetworkId == e.Target.NetworkId);
// we have to throw out the event because they left
if (e.Target == null)
@@ -285,7 +286,7 @@ namespace IW4MAdmin.Application
}
// todo: optimize this (or replace it)
- var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
+ var ipList = (await ClientSvc.Find(c => c.Level > EFClient.Permission.Trusted))
.Select(c => new
{
c.Password,
@@ -299,7 +300,7 @@ namespace IW4MAdmin.Application
{
try
{
- PrivilegedClients.Add(a.ClientId, new Player()
+ PrivilegedClients.Add(a.ClientId, new EFClient()
{
Name = a.Name,
ClientId = a.ClientId,
@@ -593,13 +594,13 @@ namespace IW4MAdmin.Application
return MessageTokens;
}
- public IList GetActiveClients() => _servers.SelectMany(s => s.Players).Where(p => p != null).ToList();
+ public IList GetActiveClients() => _servers.SelectMany(s => s.Clients).Where(p => p != null).ToList();
public ClientService GetClientService() => ClientSvc;
public AliasService GetAliasService() => AliasSvc;
public PenaltyService GetPenaltyService() => PenaltySvc;
public IConfigurationHandler GetApplicationSettings() => ConfigHandler;
- public IDictionary GetPrivilegedClients() => PrivilegedClients;
+ public IDictionary GetPrivilegedClients() => PrivilegedClients;
public bool ShutdownRequested() => !Running;
public IEventHandler GetEventHandler() => Handler;
diff --git a/Application/RconParsers/IW4RConParser.cs b/Application/RconParsers/IW4RConParser.cs
index 0348808f4..d04046a5b 100644
--- a/Application/RconParsers/IW4RConParser.cs
+++ b/Application/RconParsers/IW4RConParser.cs
@@ -9,6 +9,7 @@ using SharedLibraryCore.Objects;
using SharedLibraryCore;
using SharedLibraryCore.RCon;
using SharedLibraryCore.Exceptions;
+using SharedLibraryCore.Database.Models;
namespace IW4MAdmin.Application.RconParsers
{
@@ -61,7 +62,7 @@ namespace IW4MAdmin.Application.RconParsers
};
}
- public async Task> GetStatusAsync(Connection connection)
+ public async Task> GetStatusAsync(Connection connection)
{
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
return ClientsFromStatus(response);
@@ -74,9 +75,9 @@ namespace IW4MAdmin.Application.RconParsers
public virtual CommandPrefix GetCommandPrefixes() => Prefixes;
- private List ClientsFromStatus(string[] Status)
+ private List ClientsFromStatus(string[] Status)
{
- List StatusPlayers = new List();
+ List StatusPlayers = new List();
if (Status.Length < 4)
throw new ServerException("Unexpected status response received");
@@ -106,7 +107,7 @@ namespace IW4MAdmin.Application.RconParsers
string name = regex.Groups[5].Value.StripColors().Trim();
int ip = regex.Groups[7].Value.Split(':')[0].ConvertToIP();
- Player P = new Player()
+ var P = new EFClient()
{
Name = name,
NetworkId = networkId,
@@ -115,7 +116,7 @@ namespace IW4MAdmin.Application.RconParsers
Ping = ping,
Score = score,
IsBot = ip == 0,
- State = Player.ClientState.Connecting
+ State = EFClient.ClientState.Connecting
};
StatusPlayers.Add(P);
}
diff --git a/Application/RconParsers/IW5MRConParser.cs b/Application/RconParsers/IW5MRConParser.cs
index b0948610e..a2d5f49c6 100644
--- a/Application/RconParsers/IW5MRConParser.cs
+++ b/Application/RconParsers/IW5MRConParser.cs
@@ -9,6 +9,7 @@ using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Objects;
using SharedLibraryCore.RCon;
using SharedLibraryCore.Exceptions;
+using SharedLibraryCore.Database.Models;
namespace IW4MAdmin.Application.RconParsers
{
@@ -105,7 +106,7 @@ namespace IW4MAdmin.Application.RconParsers
};
}
- public async Task> GetStatusAsync(Connection connection)
+ public async Task> GetStatusAsync(Connection connection)
{
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
return ClientsFromStatus(response);
@@ -118,9 +119,9 @@ namespace IW4MAdmin.Application.RconParsers
return true;
}
- private List ClientsFromStatus(string[] status)
+ private List ClientsFromStatus(string[] status)
{
- List StatusPlayers = new List();
+ List StatusPlayers = new List();
foreach (string statusLine in status)
{
@@ -145,7 +146,7 @@ namespace IW4MAdmin.Application.RconParsers
regex = Regex.Match(responseLine, @" +(\d+ +){3}");
int score = Int32.Parse(regex.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0]);
- var p = new Player()
+ var p = new EFClient()
{
Name = name,
NetworkId = networkId,
@@ -154,7 +155,7 @@ namespace IW4MAdmin.Application.RconParsers
Ping = Ping,
Score = score,
IsBot = false,
- State = Player.ClientState.Connecting
+ State = EFClient.ClientState.Connecting
};
StatusPlayers.Add(p);
diff --git a/Application/RconParsers/T6MRConParser.cs b/Application/RconParsers/T6MRConParser.cs
index 6a26d599d..9f38ae7fd 100644
--- a/Application/RconParsers/T6MRConParser.cs
+++ b/Application/RconParsers/T6MRConParser.cs
@@ -9,6 +9,7 @@ using SharedLibraryCore.Objects;
using SharedLibraryCore.RCon;
using SharedLibraryCore.Exceptions;
using System.Text;
+using SharedLibraryCore.Database.Models;
namespace IW4MAdmin.Application.RconParsers
{
@@ -60,7 +61,7 @@ namespace IW4MAdmin.Application.RconParsers
};
}
- public async Task> GetStatusAsync(Connection connection)
+ public async Task> GetStatusAsync(Connection connection)
{
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
return ClientsFromStatus(response);
@@ -73,9 +74,9 @@ namespace IW4MAdmin.Application.RconParsers
return true;
}
- private List ClientsFromStatus(string[] status)
+ private List ClientsFromStatus(string[] status)
{
- List StatusPlayers = new List();
+ List StatusPlayers = new List();
foreach (string statusLine in status)
{
@@ -98,7 +99,7 @@ namespace IW4MAdmin.Application.RconParsers
#endif
int ipAddress = regex.Value.Split(':')[0].ConvertToIP();
regex = Regex.Match(responseLine, @"[0-9]{1,2}\s+[0-9]+\s+");
- var p = new Player()
+ var p = new EFClient()
{
Name = name,
NetworkId = networkId,
@@ -106,7 +107,7 @@ namespace IW4MAdmin.Application.RconParsers
IPAddress = ipAddress,
Ping = Ping,
Score = 0,
- State = Player.ClientState.Connecting,
+ State = EFClient.ClientState.Connecting,
IsBot = networkId == 0
};
diff --git a/Application/Server.cs b/Application/Server.cs
index 3d8fa41f6..3b61d5767 100644
--- a/Application/Server.cs
+++ b/Application/Server.cs
@@ -1,24 +1,22 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Text.RegularExpressions;
-using System.Runtime.InteropServices;
-
+using IW4MAdmin.Application.EventParsers;
+using IW4MAdmin.Application.IO;
+using IW4MAdmin.Application.RconParsers;
using SharedLibraryCore;
-using SharedLibraryCore.Interfaces;
-using SharedLibraryCore.Objects;
+using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos;
-using SharedLibraryCore.Configuration;
using SharedLibraryCore.Exceptions;
+using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Localization;
-
-using IW4MAdmin.Application.RconParsers;
-using IW4MAdmin.Application.EventParsers;
-using IW4MAdmin.Application.IO;
+using SharedLibraryCore.Objects;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
namespace IW4MAdmin
{
@@ -58,234 +56,101 @@ namespace IW4MAdmin
return Id;
}
- public async Task OnPlayerJoined(Player logClient)
+ public async Task OnClientJoined(EFClient polledClient)
{
- var existingClient = Players[logClient.ClientNumber];
+ var existingClient = Clients[polledClient.ClientNumber];
- if (existingClient == null ||
- (existingClient.NetworkId != logClient.NetworkId &&
- existingClient.State != Player.ClientState.Connected))
+ if (existingClient != null)
{
- Logger.WriteDebug($"Log detected {logClient} joining");
- Players[logClient.ClientNumber] = logClient;
+ await existingClient.OnJoin(polledClient.IPAddress);
}
-
- await Task.CompletedTask;
}
- override public async Task AddPlayer(Player polledPlayer)
+ override public async Task OnClientConnected(EFClient clientFromLog)
{
- if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
- polledPlayer.Ping < 1 ||
- polledPlayer.ClientNumber < 0)
- {
- return false;
- }
-
- // set this when they are waiting for authentication
- if (Players[polledPlayer.ClientNumber] == null &&
- polledPlayer.State == Player.ClientState.Connecting)
- {
- Players[polledPlayer.ClientNumber] = polledPlayer;
- return false;
- }
-
-#if !DEBUG
- if (polledPlayer.Name.Length < 3)
- {
- Logger.WriteDebug($"Kicking {polledPlayer} because their name is too short");
- string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_MINNAME"]);
- await this.ExecuteCommandAsync(formattedKick);
- return false;
- }
-
- if (Players.FirstOrDefault(p => p != null && p.Name == polledPlayer.Name && p.NetworkId != polledPlayer.NetworkId) != null)
- {
- Logger.WriteDebug($"Kicking {polledPlayer} because their name is already in use");
- string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_NAME_INUSE"]);
- await this.ExecuteCommandAsync(formattedKick);
- return false;
- }
-
- if (polledPlayer.Name == "Unknown Soldier" ||
- polledPlayer.Name == "UnknownSoldier" ||
- polledPlayer.Name == "CHEATER")
- {
- Logger.WriteDebug($"Kicking {polledPlayer} because their name is generic");
- string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_GENERICNAME"]);
- await this.ExecuteCommandAsync(formattedKick);
- return false;
- }
-
- if (polledPlayer.Name.Where(c => Char.IsControl(c)).Count() > 0)
- {
- Logger.WriteDebug($"Kicking {polledPlayer} because their name contains control characters");
- string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_CONTROLCHARS"]);
- await this.ExecuteCommandAsync(formattedKick);
- return false;
- }
-
-#endif
- Logger.WriteDebug($"Client slot #{polledPlayer.ClientNumber} now reserved");
+ Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
try
{
- Player player = null;
- var client = await Manager.GetClientService().GetUnique(polledPlayer.NetworkId);
+ EFClient client = await Manager.GetClientService().GetUnique(clientFromLog.NetworkId);
// first time client is connecting to server
if (client == null)
{
- Logger.WriteDebug($"Client {polledPlayer} first time connecting");
- player = (await Manager.GetClientService().Create(polledPlayer)).AsPlayer();
+ Logger.WriteDebug($"Client {clientFromLog} first time connecting");
+ client = await Manager.GetClientService().Create(clientFromLog);
}
// client has connected in the past
else
{
- client.LastConnection = DateTime.UtcNow;
- client.Connections += 1;
-
var existingAlias = client.AliasLink.Children
- .FirstOrDefault(a => a.Name == polledPlayer.Name && a.IPAddress == polledPlayer.IPAddress);
+ .FirstOrDefault(a => a.Name == clientFromLog.Name);
if (existingAlias == null)
{
- Logger.WriteDebug($"Client {polledPlayer} has connected previously under a different ip/name");
+ Logger.WriteDebug($"Client {clientFromLog} has connected previously under a different ip/name");
client.CurrentAlias = new EFAlias()
{
- IPAddress = polledPlayer.IPAddress,
- Name = polledPlayer.Name,
+ // this gets updated on client join
+ IPAddress = clientFromLog.IPAddress,
+ Name = clientFromLog.Name,
};
- // we need to update their new ip and name to the virtual property
- client.Name = polledPlayer.Name;
- client.IPAddress = polledPlayer.IPAddress;
}
else
{
client.CurrentAlias = existingAlias;
client.CurrentAliasId = existingAlias.AliasId;
- client.Name = existingAlias.Name;
- client.IPAddress = existingAlias.IPAddress;
}
await Manager.GetClientService().Update(client);
- player = client.AsPlayer();
}
- // reserved slots stuff
- if ((MaxClients - ClientNum) < ServerConfig.ReservedSlotNumber &&
- !player.IsPrivileged())
- {
- Logger.WriteDebug($"Kicking {polledPlayer} their spot is reserved");
- string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_SLOT_IS_RESERVED"]);
- await this.ExecuteCommandAsync(formattedKick);
- return false;
- }
-
- Logger.WriteInfo($"Client {player} connected...");
+ Logger.WriteInfo($"Client {client} connected...");
// Do the player specific stuff
- player.ClientNumber = polledPlayer.ClientNumber;
- player.IsBot = polledPlayer.IsBot;
- player.Score = polledPlayer.Score;
- player.CurrentServer = this;
+ client.ClientNumber = clientFromLog.ClientNumber;
+ client.IsBot = clientFromLog.IsBot;
+ client.Score = clientFromLog.Score;
+ client.Ping = clientFromLog.Ping;
+ client.CurrentServer = this;
- player.DelayedEvents = (Players[player.ClientNumber]?.DelayedEvents) ?? new Queue();
- Players[player.ClientNumber] = player;
+ Clients[client.ClientNumber] = client;
+ client.OnConnect();
- var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(player.AliasLinkId, player.IPAddress);
- var currentBan = activePenalties.FirstOrDefault(p => p.Type == Penalty.PenaltyType.Ban || p.Type == Penalty.PenaltyType.TempBan);
-
- var currentAutoFlag = activePenalties.Where(p => p.Type == Penalty.PenaltyType.Flag && p.PunisherId == 1)
- .Where(p => p.Active)
- .OrderByDescending(p => p.When)
- .FirstOrDefault();
-
- // remove their auto flag status after a week
- if (player.Level == Player.Permission.Flagged &&
- currentAutoFlag != null &&
- (DateTime.Now - currentAutoFlag.When).TotalDays > 7)
- {
- player.Level = Player.Permission.User;
- }
-
- if (currentBan != null)
- {
- Logger.WriteInfo($"Banned client {player} trying to connect...");
- var autoKickClient = Utilities.IW4MAdminClient(this);
-
- // the player is permanently banned
- if (currentBan.Type == Penalty.PenaltyType.Ban)
- {
- // don't store the kick message
- string formattedKick = String.Format(
- RconParser.GetCommandPrefixes().Kick,
- polledPlayer.ClientNumber,
- $"{loc["SERVER_BAN_PREV"]} {currentBan.Offense} ({loc["SERVER_BAN_APPEAL"]} {Website})");
- await this.ExecuteCommandAsync(formattedKick);
- }
-
- else
- {
- string formattedKick = String.Format(
- RconParser.GetCommandPrefixes().Kick,
- polledPlayer.ClientNumber,
- $"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})");
- await this.ExecuteCommandAsync(formattedKick);
- }
-
- // reban the "evading" guid
- if (player.Level != Player.Permission.Banned && currentBan.Type == Penalty.PenaltyType.Ban)
- {
- // hack: re apply the automated offense to the reban
- if (currentBan.AutomatedOffense != null)
- {
- autoKickClient.AdministeredPenalties.Add(new EFPenalty() { AutomatedOffense = currentBan.AutomatedOffense });
- }
- player.Ban($"{currentBan.Offense}", autoKickClient);
- }
-
- // they didn't fully connect so empty their slot
- Players[player.ClientNumber] = null;
- return false;
- }
-
- player.State = Player.ClientState.Connected;
- return true;
+ client.State = EFClient.ClientState.Connected;
}
catch (Exception ex)
{
- Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {polledPlayer.Name}::{polledPlayer.NetworkId}");
+ Logger.WriteError($"{loc["SERVER_ERROR_ADDPLAYER"]} {clientFromLog.Name}::{clientFromLog.NetworkId}");
Logger.WriteDebug(ex.Message);
Logger.WriteDebug(ex.StackTrace);
- return false;
}
}
//Remove player by CLIENT NUMBER
- override public async Task RemovePlayer(int cNum)
+ override public async Task RemoveClient(int cNum)
{
- if (cNum >= 0 && Players[cNum] != null)
+ if (cNum >= 0 && Clients[cNum] != null)
{
- Player Leaving = Players[cNum];
+ EFClient Leaving = Clients[cNum];
// occurs when the player disconnects via log before being authenticated by RCon
- if (Leaving.State != Player.ClientState.Connected)
+ if (Leaving.State != EFClient.ClientState.Connected)
{
- Players[cNum] = null;
+ Clients[cNum] = null;
}
else
{
Logger.WriteInfo($"Client {Leaving} [{Leaving.State.ToString().ToLower()}] disconnecting...");
- Leaving.State = Player.ClientState.Disconnecting;
+ Leaving.State = EFClient.ClientState.Disconnecting;
Leaving.TotalConnectionTime += Leaving.ConnectionLength;
Leaving.LastConnection = DateTime.UtcNow;
await Manager.GetClientService().Update(Leaving);
- Players[cNum] = null;
+ Clients[cNum] = null;
}
}
}
@@ -340,7 +205,7 @@ namespace IW4MAdmin
if (E.Type == GameEvent.EventType.Command &&
E.Extra != null &&
(canExecuteCommand ||
- E.Origin?.Level == Player.Permission.Console))
+ E.Origin?.Level == EFClient.Permission.Console))
{
await (((Command)E.Extra).ExecuteAsync(E));
}
@@ -355,25 +220,17 @@ namespace IW4MAdmin
{
if (E.Type == GameEvent.EventType.Connect)
{
- E.Origin.State = Player.ClientState.Authenticated;
- // add them to the server
- if (!await AddPlayer(E.Origin))
- {
- E.Origin.State = Player.ClientState.Connecting;
- Logger.WriteDebug("client didn't pass authentication, so we are discontinuing event");
- return false;
- }
- // hack: makes the event propgate with the correct info
- E.Origin = Players[E.Origin.ClientNumber];
+ E.Origin.State = EFClient.ClientState.Authenticated;
+ await OnClientConnected(E.Origin);
ChatHistory.Add(new ChatInfo()
{
- Name = E.Origin?.Name ?? "ERROR!",
+ Name = E.Origin.Name,
Message = "CONNECTED",
Time = DateTime.UtcNow
});
- if (E.Origin.Level > Player.Permission.Moderator)
+ if (E.Origin.Level > EFClient.Permission.Moderator)
{
E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count));
}
@@ -381,7 +238,7 @@ namespace IW4MAdmin
else if (E.Type == GameEvent.EventType.Join)
{
- await OnPlayerJoined(E.Origin);
+ await OnClientJoined(E.Origin);
}
else if (E.Type == GameEvent.EventType.Flag)
@@ -446,11 +303,11 @@ namespace IW4MAdmin
else if (E.Type == GameEvent.EventType.Quit)
{
- var origin = Players.FirstOrDefault(p => p != null && p.NetworkId == E.Origin.NetworkId);
+ var origin = Clients.FirstOrDefault(p => p != null && p.NetworkId == E.Origin.NetworkId);
if (origin != null &&
// we only want to forward the event if they are connected.
- origin.State == Player.ClientState.Connected &&
+ origin.State == EFClient.ClientState.Connected &&
// make sure we don't get the disconnect event from every time the game ends
origin.ConnectionLength < Manager.GetApplicationSettings().Configuration().RConPollRate)
{
@@ -465,9 +322,9 @@ namespace IW4MAdmin
}
else if (origin != null &&
- origin.State != Player.ClientState.Connected)
+ origin.State != EFClient.ClientState.Connected)
{
- await RemovePlayer(origin.ClientNumber);
+ await RemoveClient(origin.ClientNumber);
}
}
@@ -481,9 +338,9 @@ namespace IW4MAdmin
});
var currentState = E.Origin.State;
- await RemovePlayer(E.Origin.ClientNumber);
+ await RemoveClient(E.Origin.ClientNumber);
- if (currentState != Player.ClientState.Connected)
+ if (currentState != EFClient.ClientState.Connected)
{
throw new ServerException("Disconnecting player was not in a connected state");
}
@@ -569,12 +426,16 @@ namespace IW4MAdmin
}
while (ChatHistory.Count > Math.Ceiling((double)ClientNum / 2))
+ {
ChatHistory.RemoveAt(0);
+ }
// the last client hasn't fully disconnected yet
// so there will still be at least 1 client left
if (ClientNum < 2)
+ {
ChatHistory.Clear();
+ }
return true;
}
@@ -585,12 +446,12 @@ namespace IW4MAdmin
/// array index 1 = disconnecting clients
///
///
- async Task[]> PollPlayersAsync()
+ async Task[]> PollPlayersAsync()
{
#if DEBUG
var now = DateTime.Now;
#endif
- var currentClients = GetPlayersAsList();
+ var currentClients = GetClientsAsList();
var polledClients = (await this.GetStatusAsync()).AsEnumerable();
if (this.Manager.GetApplicationSettings().Configuration().IgnoreBots)
{
@@ -604,15 +465,15 @@ namespace IW4MAdmin
foreach (var client in polledClients)
{
// todo: move out somehwere
- var existingClient = Players[client.ClientNumber] ?? client;
+ var existingClient = Clients[client.ClientNumber] ?? client;
existingClient.Ping = client.Ping;
existingClient.Score = client.Score;
}
var disconnectingClients = currentClients.Except(polledClients);
- var connectingClients = polledClients.Except(currentClients.Where(c => c.State == Player.ClientState.Connected));
+ var connectingClients = polledClients.Except(currentClients.Where(c => c.State == EFClient.ClientState.Connected));
- return new List[] { connectingClients.ToList(), disconnectingClients.ToList() };
+ return new List[] { connectingClients.ToList(), disconnectingClients.ToList() };
}
DateTime start = DateTime.Now;
@@ -626,11 +487,13 @@ namespace IW4MAdmin
if (Manager.ShutdownRequested())
{
// todo: fix up disconnect
- //for (int i = 0; i < Players.Count; i++)
- // await RemovePlayer(i);
+ //for (int i = 0; i < EFClients.Count; i++)
+ // await RemoveClient(i);
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
+ {
await plugin.OnUnloadAsync();
+ }
}
// only check every 2 minutes if the server doesn't seem to be responding
@@ -644,7 +507,7 @@ namespace IW4MAdmin
foreach (var disconnectingClient in polledClients[1])
{
- if (disconnectingClient.State == Player.ClientState.Disconnecting)
+ if (disconnectingClient.State == EFClient.ClientState.Disconnecting)
{
continue;
}
@@ -669,8 +532,8 @@ namespace IW4MAdmin
foreach (var client in polledClients[0])
{
// this prevents duplicate events from being sent to the event api
- if (GetPlayersAsList().Count(c => c.NetworkId == client.NetworkId &&
- c.State == Player.ClientState.Connected) != 0)
+ if (GetClientsAsList().Count(c => c.NetworkId == client.NetworkId &&
+ c.State == EFClient.ClientState.Connected) != 0)
{
continue;
}
@@ -730,9 +593,12 @@ namespace IW4MAdmin
// update the player history
if ((lastCount - playerCountStart).TotalMinutes >= SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval)
{
- while (PlayerHistory.Count > ((60 / SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval) * 12)) // 12 times a hour for 12 hours
- PlayerHistory.Dequeue();
- PlayerHistory.Enqueue(new SharedLibraryCore.Helpers.PlayerHistory(ClientNum));
+ while (ClientHistory.Count > ((60 / SharedLibraryCore.Helpers.PlayerHistory.UpdateInterval) * 12)) // 12 times a hour for 12 hours
+ {
+ ClientHistory.Dequeue();
+ }
+
+ ClientHistory.Enqueue(new SharedLibraryCore.Helpers.PlayerHistory(ClientNum));
playerCountStart = DateTime.Now;
}
@@ -782,7 +648,9 @@ namespace IW4MAdmin
new IW3RConParser();
if (ServerConfig.UseIW5MParser)
+ {
RconParser = new IW5MRConParser();
+ }
var version = await this.GetDvarAsync("version");
GameName = Utilities.GetGame(version.Value);
@@ -793,16 +661,26 @@ namespace IW4MAdmin
RconParser = new IW4RConParser();
}
else if (GameName == Game.IW5)
+ {
EventParser = new IW5EventParser();
+ }
else if (GameName == Game.T5M)
+ {
EventParser = new T5MEventParser();
+ }
else if (GameName == Game.T6M)
+ {
EventParser = new T6MEventParser();
+ }
else
+ {
EventParser = new IW3EventParser(); // this uses the 'main' folder for log paths
+ }
if (GameName == Game.UKN)
+ {
Logger.WriteWarning($"Game name not recognized: {version}");
+ }
var infoResponse = await this.GetInfoAsync();
// this is normally slow, but I'm only doing it because different games have different prefixes
@@ -906,7 +784,7 @@ namespace IW4MAdmin
#endif
}
- protected override async Task Warn(String Reason, Player Target, Player Origin)
+ protected override async Task Warn(String Reason, EFClient Target, EFClient Origin)
{
// ensure player gets warned if command not performed on them in game
if (Target.ClientNumber < 0)
@@ -948,7 +826,7 @@ namespace IW4MAdmin
await Manager.GetPenaltyService().Create(newPenalty);
}
- protected override async Task Kick(String Reason, Player Target, Player Origin)
+ protected override async Task Kick(String Reason, EFClient Target, EFClient Origin)
{
// ensure player gets kicked if command not performed on them in game
if (Target.ClientNumber < 0)
@@ -971,7 +849,7 @@ namespace IW4MAdmin
#endif
#if DEBUG
- await Target.CurrentServer.RemovePlayer(Target.ClientNumber);
+ await Target.CurrentServer.RemoveClient(Target.ClientNumber);
#endif
var newPenalty = new Penalty()
@@ -988,7 +866,7 @@ namespace IW4MAdmin
await Manager.GetPenaltyService().Create(newPenalty);
}
- protected override async Task TempBan(String Reason, TimeSpan length, Player Target, Player Origin)
+ protected override async Task TempBan(String Reason, TimeSpan length, EFClient Target, EFClient Origin)
{
// ensure player gets banned if command not performed on them in game
if (Target.ClientNumber < 0)
@@ -1009,7 +887,7 @@ namespace IW4MAdmin
await Target.CurrentServer.ExecuteCommandAsync(formattedKick);
}
#else
- await Target.CurrentServer.RemovePlayer(Target.ClientNumber);
+ await Target.CurrentServer.RemoveClient(Target.ClientNumber);
#endif
Penalty newPenalty = new Penalty()
@@ -1027,15 +905,15 @@ namespace IW4MAdmin
await Manager.GetPenaltyService().Create(newPenalty);
}
- override protected async Task Ban(String Message, Player Target, Player Origin)
+ override protected async Task Ban(String Message, EFClient Target, EFClient Origin)
{
// ensure player gets banned if command not performed on them in game
if (Target.ClientNumber < 0)
{
- Player ingameClient = null;
+ EFClient ingameClient = null;
ingameClient = Manager.GetServers()
- .Select(s => s.GetPlayersAsList())
+ .Select(s => s.GetClientsAsList())
.FirstOrDefault(l => l.FirstOrDefault(c => c.ClientId == Target.ClientId) != null)
?.First(c => c.ClientId == Target.ClientId);
@@ -1049,13 +927,13 @@ namespace IW4MAdmin
else
{
// this is set only because they're still in the server.
- Target.Level = Player.Permission.Banned;
+ Target.Level = EFClient.Permission.Banned;
#if !DEBUG
string formattedString = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"{loc["SERVER_BAN_TEXT"]} - ^5{Message} ^7({loc["SERVER_BAN_APPEAL"]} {Website})^7");
await Target.CurrentServer.ExecuteCommandAsync(formattedString);
#else
- await Target.CurrentServer.RemovePlayer(Target.ClientNumber);
+ await Target.CurrentServer.RemoveClient(Target.ClientNumber);
#endif
}
@@ -1077,7 +955,7 @@ namespace IW4MAdmin
Manager.GetPrivilegedClients().Remove(Target.ClientId);
}
- override public async Task Unban(string reason, Player Target, Player Origin)
+ override public async Task Unban(string reason, EFClient Target, EFClient Origin)
{
var unbanPenalty = new Penalty()
{
diff --git a/DiscordWebhook/DiscordWebhook.pyproj b/DiscordWebhook/DiscordWebhook.pyproj
index c3ed35f4f..786fe607c 100644
--- a/DiscordWebhook/DiscordWebhook.pyproj
+++ b/DiscordWebhook/DiscordWebhook.pyproj
@@ -27,6 +27,11 @@
true
false
+
+ true
+ false
+ bin\Prerelease\
+
@@ -50,7 +55,7 @@
True
-
+
@@ -59,7 +64,7 @@
-
+
diff --git a/GameLogServer/GameLogServer.pyproj b/GameLogServer/GameLogServer.pyproj
index 249fa7af5..d07c347c9 100644
--- a/GameLogServer/GameLogServer.pyproj
+++ b/GameLogServer/GameLogServer.pyproj
@@ -27,10 +27,16 @@
true
false
+
+ true
+ false
+ bin\Prerelease\
+
Code
+
Code
diff --git a/GameLogServer/GameLogServer/restart_resource.py b/GameLogServer/GameLogServer/restart_resource.py
new file mode 100644
index 000000000..762b2d0d1
--- /dev/null
+++ b/GameLogServer/GameLogServer/restart_resource.py
@@ -0,0 +1,29 @@
+from flask_restful import Resource
+from flask import request
+import requests
+import os
+import subprocess
+import re
+
+def get_pid_of_server_windows(port):
+ process = subprocess.Popen('netstat -aon', shell=True, stdout=subprocess.PIPE)
+ output = process.communicate()[0]
+ matches = re.search(' *(UDP) +([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):'+ str(port) + ' +[^\w]*([0-9]+)', output.decode('utf-8'))
+ if matches is not None:
+ return matches.group(3)
+ else:
+ return 0
+
+class RestartResource(Resource):
+ def get(self):
+ try:
+ response = requests.get('http://' + request.remote_addr + ':1624/api/restartapproved')
+ if response.status_code == 200:
+ pid = get_pid_of_server_windows(response.json()['port'])
+ subprocess.check_output("Taskkill /PID %s /F" % pid)
+ else:
+ return {}, 400
+ except Exception as e:
+ print(e)
+ return {}, 500
+ return {}, 200
diff --git a/GameLogServer/GameLogServer/server.py b/GameLogServer/GameLogServer/server.py
index 3ec49269e..ba4f1d0fe 100644
--- a/GameLogServer/GameLogServer/server.py
+++ b/GameLogServer/GameLogServer/server.py
@@ -1,9 +1,11 @@
from flask import Flask
from flask_restful import Api
from .log_resource import LogResource
+from .restart_resource import RestartResource
app = Flask(__name__)
def init():
api = Api(app)
api.add_resource(LogResource, '/log/')
+ api.add_resource(RestartResource, '/restart')
diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln
index dbb34eeb0..679c734e5 100644
--- a/IW4MAdmin.sln
+++ b/IW4MAdmin.sln
@@ -1,4 +1,3 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.16
@@ -41,6 +40,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug
ProjectSection(SolutionItems) = preProject
Plugins\ScriptPlugins\SharedGUIDKick.js = Plugins\ScriptPlugins\SharedGUIDKick.js
Plugins\ScriptPlugins\VPNDetection.js = Plugins\ScriptPlugins\VPNDetection.js
+ Plugins\ScriptPlugins\VpnDetectionPrivate.js = Plugins\ScriptPlugins\VpnDetectionPrivate.js
EndProjectSection
EndProject
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "GameLogServer", "GameLogServer\GameLogServer.pyproj", "{42EFDA12-10D3-4C40-A210-9483520116BC}"
diff --git a/Master/Master.pyproj b/Master/Master.pyproj
index 271fede2d..aba301767 100644
--- a/Master/Master.pyproj
+++ b/Master/Master.pyproj
@@ -17,7 +17,7 @@
true
Master
Master
- MSBuild|dev_env|$(MSBuildProjectFullPath)
+ MSBuild|env|X:\IW4MAdmin\GameLogServer\GameLogServer.pyproj
False
@@ -111,23 +111,15 @@
-
+
-
- dev_env
- 3.6
- dev_env (Python 3.6 (64-bit))
- Scripts\python.exe
- Scripts\pythonw.exe
- PYTHONPATH
- X64
-
+