mirror of
https://github.com/RaidMax/IW4M-Admin.git
synced 2025-06-10 07:13:58 -05:00
implement new eventing system
This commit is contained in:
@ -9,7 +9,7 @@ using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@ -31,6 +31,9 @@ using IW4MAdmin.Application.Plugin.Script;
|
||||
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedLibraryCore.Alerts;
|
||||
using SharedLibraryCore.Events.Management;
|
||||
using SharedLibraryCore.Events.Server;
|
||||
using SharedLibraryCore.Interfaces.Events;
|
||||
using static Data.Models.Client.EFClient;
|
||||
|
||||
namespace IW4MAdmin
|
||||
@ -44,11 +47,12 @@ namespace IW4MAdmin
|
||||
private const int REPORT_FLAG_COUNT = 4;
|
||||
private long lastGameTime = 0;
|
||||
|
||||
public int Id { get; private set; }
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IClientNoticeMessageFormatter _messageFormatter;
|
||||
private readonly ILookupCache<EFServer> _serverCache;
|
||||
private readonly CommandConfiguration _commandConfiguration;
|
||||
private EFServer _cachedDatabaseServer;
|
||||
private readonly StatManager _statManager;
|
||||
|
||||
public IW4MServer(
|
||||
ServerConfiguration serverConfiguration,
|
||||
@ -72,6 +76,18 @@ namespace IW4MAdmin
|
||||
_messageFormatter = messageFormatter;
|
||||
_serverCache = serverCache;
|
||||
_commandConfiguration = commandConfiguration;
|
||||
_statManager = serviceProvider.GetRequiredService<StatManager>();
|
||||
|
||||
IGameServerEventSubscriptions.MonitoringStarted += async (gameEvent, token) =>
|
||||
{
|
||||
if (gameEvent.Server.Id != Id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await EnsureServerAdded();
|
||||
await _statManager.EnsureServerAdded(gameEvent.Server, token);
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<EFClient> OnClientConnected(EFClient clientFromLog)
|
||||
@ -108,7 +124,7 @@ namespace IW4MAdmin
|
||||
|
||||
Clients[client.ClientNumber] = client;
|
||||
ServerLogger.LogDebug("End PreConnect for {client}", client.ToString());
|
||||
var e = new GameEvent()
|
||||
var e = new GameEvent
|
||||
{
|
||||
Origin = client,
|
||||
Owner = this,
|
||||
@ -116,6 +132,11 @@ namespace IW4MAdmin
|
||||
};
|
||||
|
||||
Manager.AddEvent(e);
|
||||
Manager.QueueEvent(new ClientStateInitializeEvent
|
||||
{
|
||||
Client = client,
|
||||
Source = this,
|
||||
});
|
||||
return client;
|
||||
}
|
||||
|
||||
@ -210,10 +231,17 @@ namespace IW4MAdmin
|
||||
ServerLogger.LogInformation("Executing command {Command} for {Client}", cmd.Name,
|
||||
E.Origin.ToString());
|
||||
await cmd.ExecuteAsync(E);
|
||||
Manager.QueueEvent(new ClientExecuteCommandEvent
|
||||
{
|
||||
Command = cmd,
|
||||
Client = E.Origin,
|
||||
Source = this,
|
||||
CommandText = E.Data
|
||||
});
|
||||
}
|
||||
|
||||
var pluginTasks = Manager.Plugins
|
||||
.Select(async plugin => await CreatePluginTask(plugin, E));
|
||||
var pluginTasks = Manager.Plugins.Where(plugin => !plugin.IsParser)
|
||||
.Select(plugin => CreatePluginTask(plugin, E));
|
||||
|
||||
await Task.WhenAll(pluginTasks);
|
||||
}
|
||||
@ -250,7 +278,7 @@ namespace IW4MAdmin
|
||||
|
||||
try
|
||||
{
|
||||
await plugin.OnEventAsync(gameEvent, this).WithWaitCancellation(tokenSource.Token);
|
||||
await plugin.OnEventAsync(gameEvent, this);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
@ -277,29 +305,7 @@ namespace IW4MAdmin
|
||||
{
|
||||
ServerLogger.LogDebug("processing event of type {type}", E.Type);
|
||||
|
||||
if (E.Type == GameEvent.EventType.Start)
|
||||
{
|
||||
var existingServer = (await _serverCache
|
||||
.FirstAsync(server => server.Id == EndPoint));
|
||||
|
||||
var serverId = await GetIdForServer(E.Owner);
|
||||
|
||||
if (existingServer == null)
|
||||
{
|
||||
var server = new EFServer()
|
||||
{
|
||||
Port = Port,
|
||||
EndPoint = ToString(),
|
||||
ServerId = serverId,
|
||||
GameName = (Reference.Game?)GameName,
|
||||
HostName = Hostname
|
||||
};
|
||||
|
||||
await _serverCache.AddAsync(server);
|
||||
}
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.ConnectionLost)
|
||||
if (E.Type == GameEvent.EventType.ConnectionLost)
|
||||
{
|
||||
var exception = E.Extra as Exception;
|
||||
ServerLogger.LogError(exception,
|
||||
@ -350,9 +356,18 @@ namespace IW4MAdmin
|
||||
else if (E.Type == GameEvent.EventType.ChangePermission)
|
||||
{
|
||||
var newPermission = (Permission) E.Extra;
|
||||
var oldPermission = E.Target.Level;
|
||||
ServerLogger.LogInformation("{origin} is setting {target} to permission level {newPermission}",
|
||||
E.Origin.ToString(), E.Target.ToString(), newPermission);
|
||||
await Manager.GetClientService().UpdateLevel(newPermission, E.Target, E.Origin);
|
||||
|
||||
Manager.QueueEvent(new ClientPermissionChangeEvent
|
||||
{
|
||||
Client = E.Origin,
|
||||
Source = this,
|
||||
OldPermission = oldPermission,
|
||||
NewPermission = newPermission
|
||||
});
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Connect)
|
||||
@ -500,6 +515,12 @@ namespace IW4MAdmin
|
||||
|
||||
await Manager.GetPenaltyService().Create(newPenalty);
|
||||
E.Target.SetLevel(Permission.Flagged, E.Origin);
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyEvent
|
||||
{
|
||||
Client = E.Target,
|
||||
Penalty = newPenalty
|
||||
});
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Unflag)
|
||||
@ -519,6 +540,12 @@ namespace IW4MAdmin
|
||||
await Manager.GetPenaltyService().RemoveActivePenalties(E.Target.AliasLinkId, E.Target.NetworkId,
|
||||
E.Target.GameName, E.Target.CurrentAlias?.IPAddress);
|
||||
await Manager.GetPenaltyService().Create(unflagPenalty);
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyRevokeEvent
|
||||
{
|
||||
Client = E.Target,
|
||||
Penalty = unflagPenalty
|
||||
});
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Report)
|
||||
@ -554,6 +581,13 @@ namespace IW4MAdmin
|
||||
Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTO_FLAG_REPORT"]
|
||||
.FormatExt(reportNum), Utilities.IW4MAdminClient(E.Owner));
|
||||
}
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyEvent
|
||||
{
|
||||
Client = E.Target,
|
||||
Penalty = newReport,
|
||||
Source = this
|
||||
});
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.TempBan)
|
||||
@ -728,6 +762,11 @@ namespace IW4MAdmin
|
||||
{
|
||||
MaxClients = int.Parse(dict["com_maxclients"]);
|
||||
}
|
||||
|
||||
else if (dict.ContainsKey("com_maxplayers"))
|
||||
{
|
||||
MaxClients = int.Parse(dict["com_maxplayers"]);
|
||||
}
|
||||
|
||||
if (dict.ContainsKey("mapname"))
|
||||
{
|
||||
@ -772,34 +811,6 @@ namespace IW4MAdmin
|
||||
{
|
||||
E.Origin.UpdateTeam(E.Extra as string);
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.MetaUpdated)
|
||||
{
|
||||
if (E.Extra is "PersistentClientGuid")
|
||||
{
|
||||
var parts = E.Data.Split(",");
|
||||
|
||||
if (parts.Length == 2 && int.TryParse(parts[0], out var high) &&
|
||||
int.TryParse(parts[1], out var low))
|
||||
{
|
||||
var guid = long.Parse(high.ToString("X") + low.ToString("X"), NumberStyles.HexNumber);
|
||||
|
||||
var penalties = await Manager.GetPenaltyService()
|
||||
.GetActivePenaltiesByIdentifier(null, guid, (Reference.Game)GameName);
|
||||
var banPenalty =
|
||||
penalties.FirstOrDefault(penalty => penalty.Type == EFPenalty.PenaltyType.Ban);
|
||||
|
||||
if (banPenalty is not null && E.Origin.Level != Permission.Banned)
|
||||
{
|
||||
ServerLogger.LogInformation(
|
||||
"Banning {Client} as they have have provided a persistent clientId of {PersistentClientId}, which is banned",
|
||||
E.Origin.ToString(), guid);
|
||||
E.Origin.Ban(loc["SERVER_BAN_EVADE"].FormatExt(guid),
|
||||
Utilities.IW4MAdminClient(this), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lock (ChatHistory)
|
||||
{
|
||||
@ -820,6 +831,53 @@ namespace IW4MAdmin
|
||||
}
|
||||
}
|
||||
|
||||
public async Task EnsureServerAdded()
|
||||
{
|
||||
var gameServer = await _serverCache
|
||||
.FirstAsync(server => server.EndPoint == base.Id);
|
||||
|
||||
if (gameServer == null)
|
||||
{
|
||||
gameServer = new EFServer
|
||||
{
|
||||
Port = ListenPort,
|
||||
EndPoint = base.Id,
|
||||
ServerId = BuildLegacyDatabaseId(),
|
||||
GameName = (Reference.Game?)GameName,
|
||||
HostName = ServerName
|
||||
};
|
||||
|
||||
await _serverCache.AddAsync(gameServer);
|
||||
}
|
||||
|
||||
await using var context = _serviceProvider.GetRequiredService<IDatabaseContextFactory>()
|
||||
.CreateContext(enableTracking: false);
|
||||
|
||||
context.Servers.Attach(gameServer);
|
||||
|
||||
// we want to set the gamename up if it's never been set, or it changed
|
||||
if (!gameServer.GameName.HasValue || gameServer.GameName.Value != GameCode)
|
||||
{
|
||||
gameServer.GameName = GameCode;
|
||||
context.Entry(gameServer).Property(property => property.GameName).IsModified = true;
|
||||
}
|
||||
|
||||
if (gameServer.HostName == null || gameServer.HostName != ServerName)
|
||||
{
|
||||
gameServer.HostName = ServerName;
|
||||
context.Entry(gameServer).Property(property => property.HostName).IsModified = true;
|
||||
}
|
||||
|
||||
if (gameServer.IsPasswordProtected != !string.IsNullOrEmpty(GamePassword))
|
||||
{
|
||||
gameServer.IsPasswordProtected = !string.IsNullOrEmpty(GamePassword);
|
||||
context.Entry(gameServer).Property(property => property.IsPasswordProtected).IsModified = true;
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
_cachedDatabaseServer = gameServer;
|
||||
}
|
||||
|
||||
private async Task OnClientUpdate(EFClient origin)
|
||||
{
|
||||
var client = GetClientsAsList().FirstOrDefault(c => c.NetworkId == origin.NetworkId);
|
||||
@ -909,22 +967,15 @@ namespace IW4MAdmin
|
||||
public override async Task<long> GetIdForServer(Server server = null)
|
||||
{
|
||||
server ??= this;
|
||||
|
||||
if ($"{server.IP}:{server.Port.ToString()}" == "66.150.121.184:28965")
|
||||
{
|
||||
return 886229536;
|
||||
}
|
||||
|
||||
// todo: this is not stable and will need to be migrated again...
|
||||
long id = HashCode.Combine(server.IP, server.Port);
|
||||
id = id < 0 ? Math.Abs(id) : id;
|
||||
return (await _serverCache.FirstAsync(cachedServer =>
|
||||
cachedServer.EndPoint == server.Id || cachedServer.ServerId == server.EndPoint)).ServerId;
|
||||
}
|
||||
|
||||
var serverId = (await _serverCache
|
||||
.FirstAsync(_server => _server.ServerId == server.EndPoint ||
|
||||
_server.EndPoint == server.ToString() ||
|
||||
_server.ServerId == id))?.ServerId;
|
||||
|
||||
return !serverId.HasValue ? id : serverId.Value;
|
||||
private long BuildLegacyDatabaseId()
|
||||
{
|
||||
long id = HashCode.Combine(ListenAddress, ListenPort);
|
||||
return id < 0 ? Math.Abs(id) : id;
|
||||
}
|
||||
|
||||
private void UpdateMap(string mapname)
|
||||
@ -983,7 +1034,7 @@ namespace IW4MAdmin
|
||||
{
|
||||
await client.OnDisconnect();
|
||||
|
||||
var e = new GameEvent()
|
||||
var e = new GameEvent
|
||||
{
|
||||
Type = GameEvent.EventType.Disconnect,
|
||||
Owner = this,
|
||||
@ -994,6 +1045,14 @@ namespace IW4MAdmin
|
||||
|
||||
await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token);
|
||||
}
|
||||
|
||||
using var tokenSource = new CancellationTokenSource();
|
||||
tokenSource.CancelAfter(Utilities.DefaultCommandTimeout);
|
||||
|
||||
Manager.QueueEvent(new MonitorStopEvent
|
||||
{
|
||||
Server = this
|
||||
});
|
||||
}
|
||||
|
||||
private DateTime _lastMessageSent = DateTime.Now;
|
||||
@ -1075,6 +1134,16 @@ namespace IW4MAdmin
|
||||
Manager.AddEvent(gameEvent);
|
||||
}
|
||||
|
||||
if (polledClients[2].Any())
|
||||
{
|
||||
Manager.QueueEvent(new ClientDataUpdateEvent
|
||||
{
|
||||
Clients = new ReadOnlyCollection<EFClient>(polledClients[2]),
|
||||
Server = this,
|
||||
Source = this,
|
||||
});
|
||||
}
|
||||
|
||||
if (Throttled)
|
||||
{
|
||||
var gameEvent = new GameEvent
|
||||
@ -1086,6 +1155,12 @@ namespace IW4MAdmin
|
||||
};
|
||||
|
||||
Manager.AddEvent(gameEvent);
|
||||
|
||||
Manager.QueueEvent(new ConnectionRestoreEvent
|
||||
{
|
||||
Server = this,
|
||||
Source = this
|
||||
});
|
||||
}
|
||||
|
||||
LastPoll = DateTime.Now;
|
||||
@ -1109,6 +1184,12 @@ namespace IW4MAdmin
|
||||
};
|
||||
|
||||
Manager.AddEvent(gameEvent);
|
||||
Manager.QueueEvent(new ConnectionInterruptEvent
|
||||
{
|
||||
Server = this,
|
||||
Source = this
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
@ -1469,6 +1550,12 @@ namespace IW4MAdmin
|
||||
.FormatExt(activeClient.Warnings, activeClient.Name, reason);
|
||||
activeClient.CurrentServer.Broadcast(message);
|
||||
}
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyEvent
|
||||
{
|
||||
Client = targetClient,
|
||||
Penalty = newPenalty
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task Kick(string reason, EFClient targetClient, EFClient originClient, EFPenalty previousPenalty)
|
||||
@ -1507,6 +1594,12 @@ namespace IW4MAdmin
|
||||
ServerLogger.LogDebug("Executing tempban kick command for {ActiveClient}", activeClient.ToString());
|
||||
await activeClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||
}
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyEvent
|
||||
{
|
||||
Client = targetClient,
|
||||
Penalty = newPenalty
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task TempBan(string reason, TimeSpan length, EFClient targetClient, EFClient originClient)
|
||||
@ -1540,6 +1633,12 @@ namespace IW4MAdmin
|
||||
ServerLogger.LogDebug("Executing tempban kick command for {ActiveClient}", activeClient.ToString());
|
||||
await activeClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||
}
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyEvent
|
||||
{
|
||||
Client = targetClient,
|
||||
Penalty = newPenalty
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task Ban(string reason, EFClient targetClient, EFClient originClient, bool isEvade = false)
|
||||
@ -1575,6 +1674,12 @@ namespace IW4MAdmin
|
||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
||||
await activeClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
||||
}
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyEvent
|
||||
{
|
||||
Client = targetClient,
|
||||
Penalty = newPenalty
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task Unban(string reason, EFClient targetClient, EFClient originClient)
|
||||
@ -1596,6 +1701,12 @@ namespace IW4MAdmin
|
||||
await Manager.GetPenaltyService().RemoveActivePenalties(targetClient.AliasLink.AliasLinkId,
|
||||
targetClient.NetworkId, targetClient.GameName, targetClient.CurrentAlias?.IPAddress);
|
||||
await Manager.GetPenaltyService().Create(unbanPenalty);
|
||||
|
||||
Manager.QueueEvent(new ClientPenaltyRevokeEvent
|
||||
{
|
||||
Client = targetClient,
|
||||
Penalty = unbanPenalty
|
||||
});
|
||||
}
|
||||
|
||||
public override void InitializeTokens()
|
||||
@ -1605,5 +1716,7 @@ namespace IW4MAdmin
|
||||
Manager.GetMessageTokens().Add(new MessageToken("NEXTMAP", (Server s) => SharedLibraryCore.Commands.NextMapCommand.GetNextMap(s, _translationLookup)));
|
||||
Manager.GetMessageTokens().Add(new MessageToken("ADMINS", (Server s) => Task.FromResult(ListAdminsCommand.OnlineAdmins(s, _translationLookup))));
|
||||
}
|
||||
|
||||
public override long LegacyDatabaseId => _cachedDatabaseServer.ServerId;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user