fix remote commands

user clientkick_for_reason for T6 parsers
small bug fixes
This commit is contained in:
RaidMax 2018-12-01 12:17:53 -06:00
parent 9d6cbee69c
commit 4522992c0e
10 changed files with 85 additions and 73 deletions

View File

@ -24,39 +24,13 @@ namespace IW4MAdmin
{ {
private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex; private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex;
private GameLogEventDetection LogEvent; private GameLogEventDetection LogEvent;
private DateTime SessionStart;
public int Id { get; private set; } public int Id { get; private set; }
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg) public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg)
{ {
} }
//public override int EndPoint
//{
// // hack: my laziness
// if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28965")
// {
// return 886229536;
// }
// if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28960")
// {
// return 1645744423;
// }
// if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28970")
// {
// return 1645809959;
// }
// if (Id == 0)
// {
// Id = HashCode.Combine(IP, Port);
// Id = Id < 0 ? Math.Abs(Id) : Id;
// }
// return Id;
//}
override public async Task OnClientConnected(EFClient clientFromLog) override public async Task OnClientConnected(EFClient clientFromLog)
{ {
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved"); Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
@ -327,6 +301,13 @@ namespace IW4MAdmin
else if (E.Type == GameEvent.EventType.PreDisconnect) else if (E.Type == GameEvent.EventType.PreDisconnect)
{ {
if ((DateTime.UtcNow - SessionStart).TotalSeconds < 5)
{
Logger.WriteInfo($"Cancelling pre disconnect for {E.Origin} as it occured too close to map end");
E.FailReason = GameEvent.EventFailReason.Invalid;
return false;
}
// predisconnect comes from minimal rcon polled players and minimal log players // predisconnect comes from minimal rcon polled players and minimal log players
// so we need to disconnect the "full" version of the client // so we need to disconnect the "full" version of the client
var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin)); var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin));
@ -421,6 +402,7 @@ namespace IW4MAdmin
if (E.Type == GameEvent.EventType.MapEnd) if (E.Type == GameEvent.EventType.MapEnd)
{ {
Logger.WriteInfo("Game ending..."); Logger.WriteInfo("Game ending...");
SessionStart = DateTime.UtcNow;
} }
if (E.Type == GameEvent.EventType.Tell) if (E.Type == GameEvent.EventType.Tell)
@ -439,9 +421,12 @@ namespace IW4MAdmin
#endif #endif
} }
while (ChatHistory.Count > Math.Ceiling((double)ClientNum / 2)) lock (ChatHistory)
{ {
ChatHistory.RemoveAt(0); while (ChatHistory.Count > Math.Ceiling(ClientNum / 2.0))
{
ChatHistory.RemoveAt(0);
}
} }
// the last client hasn't fully disconnected yet // the last client hasn't fully disconnected yet
@ -954,7 +939,7 @@ namespace IW4MAdmin
ingameClient = Manager.GetServers() ingameClient = Manager.GetServers()
.Select(s => s.GetClientsAsList()) .Select(s => s.GetClientsAsList())
.FirstOrDefault(l => l.FirstOrDefault(c => c.ClientId == Target.ClientId) != null) .FirstOrDefault(l => l.FirstOrDefault(c => c.ClientId == Target?.ClientId) != null)
?.First(c => c.ClientId == Target.ClientId); ?.First(c => c.ClientId == Target.ClientId);
if (ingameClient != null) if (ingameClient != null)
@ -987,7 +972,7 @@ namespace IW4MAdmin
Active = true, Active = true,
When = DateTime.UtcNow, When = DateTime.UtcNow,
Link = Target.AliasLink, Link = Target.AliasLink,
AutomatedOffense = Origin.AdministeredPenalties.FirstOrDefault()?.AutomatedOffense AutomatedOffense = Origin.AdministeredPenalties?.FirstOrDefault()?.AutomatedOffense
}; };
await Manager.GetPenaltyService().Create(newPenalty); await Manager.GetPenaltyService().Create(newPenalty);

View File

@ -19,9 +19,9 @@ namespace IW4MAdmin.Application.RconParsers
{ {
Tell = "tell {0} {1}", Tell = "tell {0} {1}",
Say = "say {0}", Say = "say {0}",
Kick = "clientKick {0}", Kick = "clientkick_for_reason {0} \"{1}\"",
Ban = "clientKick {0}", Ban = "clientkick_for_reason {0} \"{1}\"",
TempBan = "clientKick {0}" TempBan = "clientkick_for_reason {0} \"{1}\""
}; };
public CommandPrefix GetCommandPrefixes() => Prefixes; public CommandPrefix GetCommandPrefixes() => Prefixes;

View File

@ -47,7 +47,6 @@
</Interpreter> </Interpreter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="config.dev.json" />
<Content Include="config.json"> <Content Include="config.json">
<Publish>True</Publish> <Publish>True</Publish>
</Content> </Content>

View File

@ -802,8 +802,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
var clientStatsSet = ctx.Set<EFClientStatistics>(); var clientStatsSet = ctx.Set<EFClientStatistics>();
clientStatsSet.Update(attackerStats); clientStatsSet.Attach(attackerStats).State = EntityState.Modified;
clientStatsSet.Update(victimStats); clientStatsSet.Attach(victimStats).State = EntityState.Modified;
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
} }

View File

@ -1,8 +1,9 @@
dotnet publish WebfrontCore/WebfrontCore.csproj -c Prerelease -o X:\IW4MAdmin\Publish\WindowsPrerelease dotnet publish WebfrontCore/WebfrontCore.csproj -c Prerelease -o X:\IW4MAdmin\Publish\WindowsPrerelease /p:PublishProfile=Prerelease
dotnet publish Application/Application.csproj -c Prerelease -o X:\IW4MAdmin\Publish\WindowsPrerelease dotnet publish Application/Application.csproj -c Prerelease -o X:\IW4MAdmin\Publish\WindowsPrerelease /p:PublishProfile=Prerelease
dotnet publish GameLogServer/GameLogServer.pyproj -c Release -o X:\IW4MAdmin\Publish\WindowsPrerelease\GameLogServer dotnet publish GameLogServer/GameLogServer.pyproj -c Release -o X:\IW4MAdmin\Publish\WindowsPrerelease\GameLogServer
dotnet publish GameLogServer/DiscordWebhook.pyproj -c Release -o X:\IW4MAdmin\Publish\WindowsPrerelease\DiscordWebhook
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat"
msbuild GameLogServer/GameLogServer.pyproj /p:PublishProfile=FolderProfile /p:DeployOnBuild=true /p:PublishProfileRootFolder=X:\IW4MAdmin\GameLogServer\ msbuild GameLogServer/GameLogServer.pyproj /p:PublishProfile=PreRelease /p:DeployOnBuild=true /p:PublishProfileRootFolder=X:\IW4MAdmin\GameLogServer\
msbuild DiscordWebhook/DiscordWebhook.pyproj /p:PublishProfile=FolderProfile /p:DeployOnBuild=true /p:PublishProfileRootFolder=X:\IW4MAdmin\DiscordWebhook\ msbuild DiscordWebhook/DiscordWebhook.pyproj /p:PublishProfile=PreRelease /p:DeployOnBuild=true /p:PublishProfileRootFolder=X:\IW4MAdmin\DiscordWebhook\
cd "X:\IW4MAdmin\DEPLOY\" cd "X:\IW4MAdmin\DEPLOY\"
PowerShell ".\upload_prerelease.ps1" PowerShell ".\upload_prerelease.ps1"

View File

@ -75,11 +75,11 @@ namespace SharedLibraryCore.Database.Models
{ {
ConnectionTime = DateTime.UtcNow; ConnectionTime = DateTime.UtcNow;
ClientNumber = -1; ClientNumber = -1;
DelayedEvents = new Queue<GameEvent>();
_additionalProperties = new Dictionary<string, object> _additionalProperties = new Dictionary<string, object>
{ {
{ "_reportCount", 0 } { "_reportCount", 0 }
}; };
CurrentAlias = new EFAlias();
} }
public override string ToString() public override string ToString()
@ -481,6 +481,7 @@ namespace SharedLibraryCore.Database.Models
if (Level != Permission.Banned && if (Level != Permission.Banned &&
currentBan.Type == Penalty.PenaltyType.Ban) currentBan.Type == Penalty.PenaltyType.Ban)
{ {
CurrentServer.Logger.WriteInfo($"Banned client {this} connected using a new GUID");
// hack: re apply the automated offense to the reban // hack: re apply the automated offense to the reban
if (currentBan.AutomatedOffense != null) if (currentBan.AutomatedOffense != null)
{ {
@ -557,8 +558,7 @@ namespace SharedLibraryCore.Database.Models
[NotMapped] [NotMapped]
public ClientState State { get; set; } public ClientState State { get; set; }
[NotMapped]
public Queue<GameEvent> DelayedEvents { get; set; }
[NotMapped] [NotMapped]
// this is kinda dirty, but I need localizable level names // this is kinda dirty, but I need localizable level names
public ClientPermission ClientPermission => new ClientPermission() public ClientPermission ClientPermission => new ClientPermission()

View File

@ -79,6 +79,8 @@ namespace SharedLibraryCore.Services
if (hasExistingAlias && !entity.AliasLink.Active) if (hasExistingAlias && !entity.AliasLink.Active)
{ {
entity.CurrentServer.Logger.WriteDebug($"Removing temporary alias for ${entity}");
// we want to delete the temporary alias // we want to delete the temporary alias
context.Entry(entity.CurrentAlias).State = EntityState.Deleted; context.Entry(entity.CurrentAlias).State = EntityState.Deleted;
entity.CurrentAlias = null; entity.CurrentAlias = null;
@ -97,6 +99,8 @@ namespace SharedLibraryCore.Services
// update the temporary alias to permanent one // update the temporary alias to permanent one
else if (!entity.AliasLink.Active) else if (!entity.AliasLink.Active)
{ {
entity.CurrentServer.Logger.WriteDebug($"Linking permanent alias for ${entity}");
// we want to track the current alias and link // we want to track the current alias and link
var alias = context.Update(entity.CurrentAlias).Entity; var alias = context.Update(entity.CurrentAlias).Entity;
var _aliasLink = context.Update(entity.AliasLink).Entity; var _aliasLink = context.Update(entity.AliasLink).Entity;
@ -119,16 +123,15 @@ namespace SharedLibraryCore.Services
Name = name, Name = name,
}; };
var iqExistingPermission = context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId) if (!hasExistingAlias)
.OrderByDescending(client => client.Level) {
.Select(c => new EFClient() { Level = c.Level }); entity.CurrentServer.Logger.WriteDebug($"Connecting player does not have an existing alias {entity}");
}
entity.Level = hasExistingAlias ? entity.Level = hasExistingAlias ?
(await iqExistingPermission.FirstOrDefaultAsync())?.Level ?? Permission.User : await context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId)
.MaxAsync(c => c.Level) :
Permission.User; Permission.User;
#if DEBUG
string sql = iqExistingPermission.AsQueryable().ToSql();
#endif
if (entity.CurrentAlias != existingAlias || if (entity.CurrentAlias != existingAlias ||
entity.AliasLink != aliasLink) entity.AliasLink != aliasLink)

View File

@ -1,13 +1,13 @@
using System; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using SharedLibraryCore.Database; using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos;
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Objects; using SharedLibraryCore.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using static SharedLibraryCore.Database.Models.EFClient; using static SharedLibraryCore.Database.Models.EFClient;
namespace SharedLibraryCore.Services namespace SharedLibraryCore.Services
@ -87,6 +87,7 @@ namespace SharedLibraryCore.Services
public async Task<IList<EFPenalty>> GetRecentPenalties(int count, int offset, Penalty.PenaltyType showOnly = Penalty.PenaltyType.Any) public async Task<IList<EFPenalty>> GetRecentPenalties(int count, int offset, Penalty.PenaltyType showOnly = Penalty.PenaltyType.Any)
{ {
using (var context = new DatabaseContext(true)) using (var context = new DatabaseContext(true))
{
return await context.Penalties return await context.Penalties
.Include(p => p.Offender.CurrentAlias) .Include(p => p.Offender.CurrentAlias)
.Include(p => p.Punisher.CurrentAlias) .Include(p => p.Punisher.CurrentAlias)
@ -96,17 +97,20 @@ namespace SharedLibraryCore.Services
.Skip(offset) .Skip(offset)
.Take(count) .Take(count)
.ToListAsync(); .ToListAsync();
}
} }
public async Task<IList<EFPenalty>> GetClientPenaltiesAsync(int clientId) public async Task<IList<EFPenalty>> GetClientPenaltiesAsync(int clientId)
{ {
using (var context = new DatabaseContext(true)) using (var context = new DatabaseContext(true))
{
return await context.Penalties return await context.Penalties
.Where(p => p.OffenderId == clientId) .Where(p => p.OffenderId == clientId)
.Where(p => p.Active) .Where(p => p.Active)
.Include(p => p.Offender.CurrentAlias) .Include(p => p.Offender.CurrentAlias)
.Include(p => p.Punisher.CurrentAlias) .Include(p => p.Punisher.CurrentAlias)
.ToListAsync(); .ToListAsync();
}
} }
/// <summary> /// <summary>
@ -146,7 +150,7 @@ namespace SharedLibraryCore.Services
PunisherId = penalty.PunisherId, PunisherId = penalty.PunisherId,
Offense = penalty.Offense, Offense = penalty.Offense,
Type = penalty.Type.ToString(), Type = penalty.Type.ToString(),
TimeRemaining = penalty.Expires.HasValue ? (now > penalty.Expires ? "" : penalty.Expires.ToString()) : DateTime.MaxValue.ToString(), TimeRemaining = penalty.Expires.HasValue ? (now > penalty.Expires ? "" : penalty.Expires.ToString()) : DateTime.MaxValue.ToString(),
AutomatedOffense = penalty.AutomatedOffense AutomatedOffense = penalty.AutomatedOffense
}, },
When = penalty.When, When = penalty.When,
@ -158,12 +162,15 @@ namespace SharedLibraryCore.Services
{ {
// todo: why does this have to be done? // todo: why does this have to be done?
if (((PenaltyInfo)p.Value).Type.Length < 2) if (((PenaltyInfo)p.Value).Type.Length < 2)
{
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString(); ((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
}
var pi = ((PenaltyInfo)p.Value); var pi = ((PenaltyInfo)p.Value);
if (pi.TimeRemaining?.Length > 0) if (pi.TimeRemaining?.Length > 0)
{
pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText(); pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText();
}
}); });
return list; return list;
} }
@ -205,7 +212,9 @@ namespace SharedLibraryCore.Services
{ {
// todo: why does this have to be done? // todo: why does this have to be done?
if (((PenaltyInfo)p.Value).Type.Length < 2) if (((PenaltyInfo)p.Value).Type.Length < 2)
{
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString(); ((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
}
}); });
return list; return list;
@ -217,24 +226,33 @@ namespace SharedLibraryCore.Services
{ {
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
Expression<Func<EFPenalty, bool>> filter = (p) => new Penalty.PenaltyType[]
{
Penalty.PenaltyType.TempBan,
Penalty.PenaltyType.Ban, Penalty.PenaltyType.Flag
}.Contains(p.Type) &&
p.Active &&
(p.Expires == null || p.Expires > now);
using (var context = new DatabaseContext(true)) using (var context = new DatabaseContext(true))
{ {
var iqPenalties = context.Penalties var iqLinkPenalties = context.Penalties
.Where(p => p.LinkId == linkId || .Where(p => p.LinkId == linkId)
ip.HasValue ? p.Link.Children.Any(a => a.IPAddress == ip) : false) .Where(filter);
.Where(p => p.Type == Penalty.PenaltyType.TempBan ||
p.Type == Penalty.PenaltyType.Ban || var iqIPPenalties = context.Aliases
p.Type == Penalty.PenaltyType.Flag) .Where(a => a.IPAddress == ip)
.Where(p => p.Active) .SelectMany(a => a.Link.ReceivedPenalties)
.Where(p => p.Expires == null || p.Expires > now); .Where(filter);
#if DEBUG == true #if DEBUG == true
var penaltiesSql = iqPenalties.ToSql(); var penaltiesSql = iqLinkPenalties.ToSql();
var ipPenaltiesSql = iqIPPenalties.ToSql();
#endif #endif
var activePenalties = await iqPenalties.ToListAsync(); var activePenalties = (await iqLinkPenalties.ToListAsync()).Union(await iqIPPenalties.ToListAsync());
// this is a bit more performant in memory (ordering) // this is a bit more performant in memory (ordering)
return activePenalties.OrderByDescending(p =>p.When).ToList(); return activePenalties.OrderByDescending(p => p.When).ToList();
} }
} }

View File

@ -120,7 +120,8 @@ namespace WebfrontCore.Controllers
public async Task<IActionResult> PrivilegedAsync() public async Task<IActionResult> PrivilegedAsync()
{ {
var admins = (await Manager.GetClientService().GetPrivilegedClients()) var admins = (await Manager.GetClientService().GetPrivilegedClients())
.GroupBy(a => a.AliasLinkId).Select(_clients => _clients.OrderBy(_client => _client.LastConnection).LastOrDefault()) .GroupBy(a => a.AliasLinkId).Where(_clients => _clients.FirstOrDefault(_client => _client.LastConnection == _clients.Max(c => c.LastConnection)) != null)
.Select(_client => _client.First())
.OrderByDescending(_client => _client.Level); .OrderByDescending(_client => _client.Level);
var adminsDict = new Dictionary<EFClient.Permission, IList<ClientInfo>>(); var adminsDict = new Dictionary<EFClient.Permission, IList<ClientInfo>>();

View File

@ -34,7 +34,10 @@ namespace WebfrontCore.Controllers
ClientId = Client.ClientId, ClientId = Client.ClientId,
Level = Client.Level, Level = Client.Level,
CurrentServer = server, CurrentServer = server,
Name = Client.Name CurrentAlias = new EFAlias()
{
Name = Client.Name
}
}; };
var remoteEvent = new GameEvent() var remoteEvent = new GameEvent()
@ -55,7 +58,9 @@ namespace WebfrontCore.Controllers
// remove the added command response // remove the added command response
for (int i = 0; i < response.Count; i++) for (int i = 0; i < response.Count; i++)
{
server.CommandResult.Remove(response[i]); server.CommandResult.Remove(response[i]);
}
} }
else else