Compare commits
16 Commits
release/pr
...
2021.11.15
Author | SHA1 | Date | |
---|---|---|---|
|
d93bfc11d0 | ||
|
21f290ca58 | ||
|
d3df9623aa | ||
|
1b9ca676dc | ||
|
58616e18fe | ||
|
0dcbafd0f2 | ||
|
f8723e6a8c | ||
|
3ebdbde33d | ||
|
769faaa31b | ||
|
2734a3f138 | ||
|
914b37b20a | ||
|
755c149495 | ||
|
bbcbc4c042 | ||
|
f3bead8eb5 | ||
|
7eb45f2bc9 | ||
|
5837885653 |
@ -22,7 +22,7 @@ namespace IW4MAdmin.Application.API.Master
|
|||||||
public int Uptime { get; set; }
|
public int Uptime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifices the version of the instance
|
/// Specifies the version of the instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("version")]
|
[JsonProperty("version")]
|
||||||
[JsonConverter(typeof(BuildNumberJsonConverter))]
|
[JsonConverter(typeof(BuildNumberJsonConverter))]
|
||||||
@ -33,5 +33,11 @@ namespace IW4MAdmin.Application.API.Master
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("servers")]
|
[JsonProperty("servers")]
|
||||||
public List<ApiServer> Servers { get; set; }
|
public List<ApiServer> Servers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Url IW4MAdmin is listening on
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("webfront_url")]
|
||||||
|
public string WebfrontUrl { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,6 +605,11 @@ namespace IW4MAdmin.Application
|
|||||||
return _servers.SelectMany(s => s.Clients).ToList().Where(p => p != null).ToList();
|
return _servers.SelectMany(s => s.Clients).ToList().Where(p => p != null).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EFClient FindActiveClient(EFClient client) =>client.ClientNumber < 0 ?
|
||||||
|
GetActiveClients()
|
||||||
|
.FirstOrDefault(c => c.NetworkId == client.NetworkId) ?? client :
|
||||||
|
client;
|
||||||
|
|
||||||
public ClientService GetClientService()
|
public ClientService GetClientService()
|
||||||
{
|
{
|
||||||
return ClientSvc;
|
return ClientSvc;
|
||||||
|
@ -18,6 +18,13 @@
|
|||||||
"rollingInterval": "Day",
|
"rollingInterval": "Day",
|
||||||
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Server} {Level:u3}] {Message:lj}{NewLine}{Exception}"
|
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Server} {Level:u3}] {Message:lj}{NewLine}{Exception}"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Console",
|
||||||
|
"Args": {
|
||||||
|
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Server} {Level:u3}] {Message:lj}{NewLine}{Exception}",
|
||||||
|
"RestrictedToMinimumLevel": "Fatal"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Enrich": [
|
"Enrich": [
|
||||||
|
@ -703,6 +703,18 @@
|
|||||||
{
|
{
|
||||||
"Alias": "Highrise",
|
"Alias": "Highrise",
|
||||||
"Name": "mp_highrise"
|
"Name": "mp_highrise"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Favela",
|
||||||
|
"Name": "mp_favela"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Nuketown",
|
||||||
|
"Name": "mp_nuked"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Skidrow",
|
||||||
|
"Name": "mp_nightshift"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -242,11 +242,11 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await (plugin.OnEventAsync(gameEvent, this)).WithWaitCancellation(tokenSource.Token);
|
await plugin.OnEventAsync(gameEvent, this).WithWaitCancellation(tokenSource.Token);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(loc["SERVER_PLUGIN_ERROR"]);
|
Console.WriteLine(loc["SERVER_PLUGIN_ERROR"].FormatExt(plugin.Name), ex.GetType().Name);
|
||||||
ServerLogger.LogError(ex, "Could not execute {methodName} for plugin {plugin}",
|
ServerLogger.LogError(ex, "Could not execute {methodName} for plugin {plugin}",
|
||||||
nameof(plugin.OnEventAsync), plugin.Name);
|
nameof(plugin.OnEventAsync), plugin.Name);
|
||||||
}
|
}
|
||||||
@ -725,11 +725,11 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
private async Task OnClientUpdate(EFClient origin)
|
private async Task OnClientUpdate(EFClient origin)
|
||||||
{
|
{
|
||||||
var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(origin));
|
var client = Manager.GetActiveClients().FirstOrDefault(c => c.NetworkId == origin.NetworkId);
|
||||||
|
|
||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
ServerLogger.LogWarning("{origin} expected to exist in client list for update, but they do not", origin.ToString());
|
ServerLogger.LogWarning("{Origin} expected to exist in client list for update, but they do not", origin.ToString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,10 +755,10 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ((client.IPAddress != null && client.State == ClientState.Disconnecting) ||
|
else if (client.IPAddress != null && client.State == ClientState.Disconnecting ||
|
||||||
client.Level == Permission.Banned)
|
client.Level == Permission.Banned)
|
||||||
{
|
{
|
||||||
ServerLogger.LogWarning("{client} state is Unknown (probably kicked), but they are still connected. trying to kick again...", origin.ToString());
|
ServerLogger.LogWarning("{Client} state is Unknown (probably kicked), but they are still connected. trying to kick again...", origin.ToString());
|
||||||
await client.CanConnect(client.IPAddress, Manager.GetApplicationSettings().Configuration().EnableImplicitAccountLinking);
|
await client.CanConnect(client.IPAddress, Manager.GetApplicationSettings().Configuration().EnableImplicitAccountLinking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1321,12 +1321,9 @@ namespace IW4MAdmin
|
|||||||
public override async Task Warn(string reason, EFClient targetClient, EFClient targetOrigin)
|
public override async Task Warn(string reason, EFClient targetClient, EFClient targetOrigin)
|
||||||
{
|
{
|
||||||
// ensure player gets warned if command not performed on them in game
|
// ensure player gets warned if command not performed on them in game
|
||||||
targetClient = targetClient.ClientNumber < 0 ?
|
var activeClient = Manager.FindActiveClient(targetClient);
|
||||||
Manager.GetActiveClients()
|
|
||||||
.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) ?? targetClient :
|
|
||||||
targetClient;
|
|
||||||
|
|
||||||
var newPenalty = new EFPenalty()
|
var newPenalty = new EFPenalty
|
||||||
{
|
{
|
||||||
Type = EFPenalty.PenaltyType.Warning,
|
Type = EFPenalty.PenaltyType.Warning,
|
||||||
Expires = DateTime.UtcNow,
|
Expires = DateTime.UtcNow,
|
||||||
@ -1336,31 +1333,28 @@ namespace IW4MAdmin
|
|||||||
Link = targetClient.AliasLink
|
Link = targetClient.AliasLink
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerLogger.LogDebug("Creating warn penalty for {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Creating warn penalty for {TargetClient}", targetClient.ToString());
|
||||||
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
||||||
|
|
||||||
if (targetClient.IsIngame)
|
if (activeClient.IsIngame)
|
||||||
{
|
{
|
||||||
if (targetClient.Warnings >= 4)
|
if (activeClient.Warnings >= 4)
|
||||||
{
|
{
|
||||||
targetClient.Kick(loc["SERVER_WARNLIMT_REACHED"], Utilities.IW4MAdminClient(this));
|
activeClient.Kick(loc["SERVER_WARNLIMT_REACHED"], Utilities.IW4MAdminClient(this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: move to translation sheet
|
var message = loc["COMMANDS_WARNING_FORMAT"]
|
||||||
string message = $"^1{loc["SERVER_WARNING"]} ^7[^3{targetClient.Warnings}^7]: ^3{targetClient.Name}^7, {reason}";
|
.FormatExt(activeClient.Warnings, activeClient.Name, reason);
|
||||||
targetClient.CurrentServer.Broadcast(message);
|
activeClient.CurrentServer.Broadcast(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Kick(string reason, EFClient targetClient, EFClient originClient, EFPenalty previousPenalty)
|
public override async Task Kick(string reason, EFClient targetClient, EFClient originClient, EFPenalty previousPenalty)
|
||||||
{
|
{
|
||||||
targetClient = targetClient.ClientNumber < 0 ?
|
var activeClient = Manager.FindActiveClient(targetClient);
|
||||||
Manager.GetActiveClients()
|
|
||||||
.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) ?? targetClient :
|
|
||||||
targetClient;
|
|
||||||
|
|
||||||
var newPenalty = new EFPenalty()
|
var newPenalty = new EFPenalty
|
||||||
{
|
{
|
||||||
Type = EFPenalty.PenaltyType.Kick,
|
Type = EFPenalty.PenaltyType.Kick,
|
||||||
Expires = DateTime.UtcNow,
|
Expires = DateTime.UtcNow,
|
||||||
@ -1370,77 +1364,64 @@ namespace IW4MAdmin
|
|||||||
Link = targetClient.AliasLink
|
Link = targetClient.AliasLink
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerLogger.LogDebug("Creating kick penalty for {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Creating kick penalty for {TargetClient}", targetClient.ToString());
|
||||||
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
||||||
|
|
||||||
if (targetClient.IsIngame)
|
if (activeClient.IsIngame)
|
||||||
{
|
{
|
||||||
var e = new GameEvent()
|
var gameEvent = new GameEvent
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.PreDisconnect,
|
Type = GameEvent.EventType.PreDisconnect,
|
||||||
Origin = targetClient,
|
Origin = activeClient,
|
||||||
Owner = this
|
Owner = this
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.AddEvent(e);
|
Manager.AddEvent(gameEvent);
|
||||||
|
|
||||||
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
|
||||||
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
|
||||||
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
|
||||||
|
|
||||||
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
||||||
clientNumber,
|
activeClient.TemporalClientNumber,
|
||||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration,
|
_messageFormatter.BuildFormattedMessage(RconParser.Configuration,
|
||||||
newPenalty,
|
newPenalty,
|
||||||
previousPenalty));
|
previousPenalty));
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
ServerLogger.LogDebug("Executing tempban kick command for {ActiveClient}", activeClient.ToString());
|
||||||
|
await activeClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task TempBan(string Reason, TimeSpan length, EFClient targetClient, EFClient originClient)
|
public override async Task TempBan(string reason, TimeSpan length, EFClient targetClient, EFClient originClient)
|
||||||
{
|
{
|
||||||
// ensure player gets kicked if command not performed on them in the same server
|
// ensure player gets kicked if command not performed on them in the same server
|
||||||
targetClient = targetClient.ClientNumber < 0 ?
|
var activeClient = Manager.FindActiveClient(targetClient);
|
||||||
Manager.GetActiveClients()
|
|
||||||
.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) ?? targetClient :
|
|
||||||
targetClient;
|
|
||||||
|
|
||||||
var newPenalty = new EFPenalty()
|
var newPenalty = new EFPenalty
|
||||||
{
|
{
|
||||||
Type = EFPenalty.PenaltyType.TempBan,
|
Type = EFPenalty.PenaltyType.TempBan,
|
||||||
Expires = DateTime.UtcNow + length,
|
Expires = DateTime.UtcNow + length,
|
||||||
Offender = targetClient,
|
Offender = targetClient,
|
||||||
Offense = Reason,
|
Offense = reason,
|
||||||
Punisher = originClient,
|
Punisher = originClient,
|
||||||
Link = targetClient.AliasLink
|
Link = targetClient.AliasLink
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerLogger.LogDebug("Creating tempban penalty for {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Creating tempban penalty for {TargetClient}", targetClient.ToString());
|
||||||
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
||||||
|
|
||||||
if (targetClient.IsIngame)
|
if (activeClient.IsIngame)
|
||||||
{
|
{
|
||||||
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
|
||||||
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
|
||||||
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
|
||||||
|
|
||||||
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
||||||
clientNumber,
|
activeClient.TemporalClientNumber,
|
||||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
||||||
ServerLogger.LogDebug("Executing tempban kick command for {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Executing tempban kick command for {ActiveClient}", activeClient.ToString());
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
await activeClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Ban(string reason, EFClient targetClient, EFClient originClient, bool isEvade = false)
|
public override async Task Ban(string reason, EFClient targetClient, EFClient originClient, bool isEvade = false)
|
||||||
{
|
{
|
||||||
// ensure player gets kicked if command not performed on them in the same server
|
// ensure player gets kicked if command not performed on them in the same server
|
||||||
targetClient = targetClient.ClientNumber < 0 ?
|
var activeClient = Manager.FindActiveClient(targetClient);
|
||||||
Manager.GetActiveClients()
|
|
||||||
.FirstOrDefault(c => c.ClientId == targetClient?.ClientId) ?? targetClient :
|
|
||||||
targetClient;
|
|
||||||
|
|
||||||
EFPenalty newPenalty = new EFPenalty()
|
var newPenalty = new EFPenalty
|
||||||
{
|
{
|
||||||
Type = EFPenalty.PenaltyType.Ban,
|
Type = EFPenalty.PenaltyType.Ban,
|
||||||
Expires = null,
|
Expires = null,
|
||||||
@ -1451,46 +1432,42 @@ namespace IW4MAdmin
|
|||||||
IsEvadedOffense = isEvade
|
IsEvadedOffense = isEvade
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerLogger.LogDebug("Creating ban penalty for {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Creating ban penalty for {TargetClient}", targetClient.ToString());
|
||||||
targetClient.SetLevel(Permission.Banned, originClient);
|
activeClient.SetLevel(Permission.Banned, originClient);
|
||||||
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
await newPenalty.TryCreatePenalty(Manager.GetPenaltyService(), ServerLogger);
|
||||||
|
|
||||||
if (targetClient.IsIngame)
|
if (activeClient.IsIngame)
|
||||||
{
|
{
|
||||||
ServerLogger.LogDebug("Attempting to kicking newly banned client {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Attempting to kicking newly banned client {ActiveClient}", activeClient.ToString());
|
||||||
|
|
||||||
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
|
||||||
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
|
||||||
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
|
||||||
|
|
||||||
var formattedString = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
var formattedString = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
||||||
clientNumber,
|
activeClient.TemporalClientNumber,
|
||||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
await activeClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public async Task Unban(string reason, EFClient Target, EFClient Origin)
|
public override async Task Unban(string reason, EFClient targetClient, EFClient originClient)
|
||||||
{
|
{
|
||||||
var unbanPenalty = new EFPenalty()
|
var unbanPenalty = new EFPenalty
|
||||||
{
|
{
|
||||||
Type = EFPenalty.PenaltyType.Unban,
|
Type = EFPenalty.PenaltyType.Unban,
|
||||||
Expires = DateTime.Now,
|
Expires = DateTime.Now,
|
||||||
Offender = Target,
|
Offender = targetClient,
|
||||||
Offense = reason,
|
Offense = reason,
|
||||||
Punisher = Origin,
|
Punisher = originClient,
|
||||||
When = DateTime.UtcNow,
|
When = DateTime.UtcNow,
|
||||||
Active = true,
|
Active = true,
|
||||||
Link = Target.AliasLink
|
Link = targetClient.AliasLink
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerLogger.LogDebug("Creating unban penalty for {targetClient}", Target.ToString());
|
ServerLogger.LogDebug("Creating unban penalty for {targetClient}", targetClient.ToString());
|
||||||
Target.SetLevel(Permission.User, Origin);
|
targetClient.SetLevel(Permission.User, originClient);
|
||||||
await Manager.GetPenaltyService().RemoveActivePenalties(Target.AliasLink.AliasLinkId);
|
await Manager.GetPenaltyService().RemoveActivePenalties(targetClient.AliasLink.AliasLinkId);
|
||||||
await Manager.GetPenaltyService().Create(unbanPenalty);
|
await Manager.GetPenaltyService().Create(unbanPenalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void InitializeTokens()
|
public override void InitializeTokens()
|
||||||
{
|
{
|
||||||
Manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYERS", (Server s) => Task.Run(async () => (await Manager.GetClientService().GetTotalClientsAsync()).ToString())));
|
Manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYERS", (Server s) => Task.Run(async () => (await Manager.GetClientService().GetTotalClientsAsync()).ToString())));
|
||||||
Manager.GetMessageTokens().Add(new MessageToken("VERSION", (Server s) => Task.FromResult(Application.Program.Version.ToString())));
|
Manager.GetMessageTokens().Add(new MessageToken("VERSION", (Server s) => Task.FromResult(Application.Program.Version.ToString())));
|
||||||
|
@ -19,6 +19,7 @@ using SharedLibraryCore.Services;
|
|||||||
using Stats.Dtos;
|
using Stats.Dtos;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -342,7 +343,12 @@ namespace IW4MAdmin.Application
|
|||||||
var masterUri = Utilities.IsDevelopment
|
var masterUri = Utilities.IsDevelopment
|
||||||
? new Uri("http://127.0.0.1:8080")
|
? new Uri("http://127.0.0.1:8080")
|
||||||
: appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl;
|
: appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl;
|
||||||
var masterRestClient = RestClient.For<IMasterApi>(masterUri);
|
var httpClient = new HttpClient
|
||||||
|
{
|
||||||
|
BaseAddress = masterUri,
|
||||||
|
Timeout = TimeSpan.FromSeconds(15)
|
||||||
|
};
|
||||||
|
var masterRestClient = RestClient.For<IMasterApi>(httpClient);
|
||||||
var translationLookup = Configure.Initialize(Utilities.DefaultLogger, masterRestClient, appConfig);
|
var translationLookup = Configure.Initialize(Utilities.DefaultLogger, masterRestClient, appConfig);
|
||||||
|
|
||||||
if (appConfig == null)
|
if (appConfig == null)
|
||||||
|
@ -179,7 +179,8 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
Id = s.EndPoint,
|
Id = s.EndPoint,
|
||||||
Port = (short)s.Port,
|
Port = (short)s.Port,
|
||||||
IPAddress = s.IP
|
IPAddress = s.IP
|
||||||
}).ToList()
|
}).ToList(),
|
||||||
|
WebfrontUrl = _appConfig.WebfrontUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
Response<ResultMessage> response = null;
|
Response<ResultMessage> response = null;
|
||||||
|
@ -24,7 +24,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
private readonly IDataValueCache<EFServerSnapshot, List<ClientHistoryInfo>> _clientHistoryCache;
|
private readonly IDataValueCache<EFServerSnapshot, List<ClientHistoryInfo>> _clientHistoryCache;
|
||||||
|
|
||||||
private readonly TimeSpan? _cacheTimeSpan =
|
private readonly TimeSpan? _cacheTimeSpan =
|
||||||
Utilities.IsDevelopment ? TimeSpan.FromSeconds(1) : (TimeSpan?) TimeSpan.FromMinutes(1);
|
Utilities.IsDevelopment ? TimeSpan.FromSeconds(30) : (TimeSpan?) TimeSpan.FromMinutes(10);
|
||||||
|
|
||||||
public ServerDataViewer(ILogger<ServerDataViewer> logger, IDataValueCache<EFServerSnapshot, (int?, DateTime?)> snapshotCache,
|
public ServerDataViewer(ILogger<ServerDataViewer> logger, IDataValueCache<EFServerSnapshot, (int?, DateTime?)> snapshotCache,
|
||||||
IDataValueCache<EFClient, (int, int)> serverStatsCache,
|
IDataValueCache<EFClient, (int, int)> serverStatsCache,
|
||||||
@ -36,7 +36,8 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
_clientHistoryCache = clientHistoryCache;
|
_clientHistoryCache = clientHistoryCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(int?, DateTime?)> MaxConcurrentClientsAsync(long? serverId = null, TimeSpan? overPeriod = null,
|
public async Task<(int?, DateTime?)>
|
||||||
|
MaxConcurrentClientsAsync(long? serverId = null, TimeSpan? overPeriod = null,
|
||||||
CancellationToken token = default)
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
_snapshotCache.SetCacheItem(async (snapshots, cancellationToken) =>
|
_snapshotCache.SetCacheItem(async (snapshots, cancellationToken) =>
|
||||||
@ -83,7 +84,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
_logger.LogDebug("Max concurrent clients since {Start} is {Clients}", oldestEntry, maxClients);
|
_logger.LogDebug("Max concurrent clients since {Start} is {Clients}", oldestEntry, maxClients);
|
||||||
|
|
||||||
return (maxClients, maxClientsTime);
|
return (maxClients, maxClientsTime);
|
||||||
}, nameof(MaxConcurrentClientsAsync), _cacheTimeSpan);
|
}, nameof(MaxConcurrentClientsAsync), _cacheTimeSpan, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -107,7 +108,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
return (count, recentCount);
|
return (count, recentCount);
|
||||||
}, nameof(_serverStatsCache), _cacheTimeSpan);
|
}, nameof(_serverStatsCache), _cacheTimeSpan, true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,8 @@ namespace IW4MAdmin.Application.RConParsers
|
|||||||
public int NoticeMaximumLines { get; set; } = 8;
|
public int NoticeMaximumLines { get; set; } = 8;
|
||||||
public int NoticeMaxCharactersPerLine { get; set; } = 50;
|
public int NoticeMaxCharactersPerLine { get; set; } = 50;
|
||||||
public string NoticeLineSeparator { get; set; } = Environment.NewLine;
|
public string NoticeLineSeparator { get; set; } = Environment.NewLine;
|
||||||
|
public int? DefaultRConPort { get; set; }
|
||||||
|
public string DefaultInstallationDirectoryHint { get; set; }
|
||||||
|
|
||||||
public DynamicRConParserConfiguration(IParserRegexFactory parserRegexFactory)
|
public DynamicRConParserConfiguration(IParserRegexFactory parserRegexFactory)
|
||||||
{
|
{
|
||||||
|
@ -5,9 +5,10 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
|
|
||||||
namespace Data.Abstractions
|
namespace Data.Abstractions
|
||||||
{
|
{
|
||||||
public interface IDataValueCache<T, V> where T : class
|
public interface IDataValueCache<TEntityType, TReturnType> where TEntityType : class
|
||||||
{
|
{
|
||||||
void SetCacheItem(Func<DbSet<T>, CancellationToken, Task<V>> itemGetter, string keyName, TimeSpan? expirationTime = null);
|
void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> itemGetter, string keyName,
|
||||||
Task<V> GetCacheItem(string keyName, CancellationToken token = default);
|
TimeSpan? expirationTime = null, bool autoRefresh = false);
|
||||||
|
Task<TReturnType> GetCacheItem(string keyName, CancellationToken token = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,7 +8,7 @@
|
|||||||
<PackageId>RaidMax.IW4MAdmin.Data</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.Data</PackageId>
|
||||||
<Title>RaidMax.IW4MAdmin.Data</Title>
|
<Title>RaidMax.IW4MAdmin.Data</Title>
|
||||||
<Authors />
|
<Authors />
|
||||||
<PackageVersion>1.0.7</PackageVersion>
|
<PackageVersion>1.0.8</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,58 +1,83 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data.Abstractions;
|
using Data.Abstractions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
namespace Data.Helpers
|
namespace Data.Helpers
|
||||||
{
|
{
|
||||||
public class DataValueCache<T, V> : IDataValueCache<T, V> where T : class
|
public class DataValueCache<TEntityType, TReturnType> : IDataValueCache<TEntityType, TReturnType>
|
||||||
|
where TEntityType : class
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
private readonly Dictionary<string, CacheState> _cacheStates = new Dictionary<string, CacheState>();
|
|
||||||
|
private readonly ConcurrentDictionary<string, CacheState> _cacheStates =
|
||||||
|
new ConcurrentDictionary<string, CacheState>();
|
||||||
|
|
||||||
|
private bool _autoRefresh;
|
||||||
private const int DefaultExpireMinutes = 15;
|
private const int DefaultExpireMinutes = 15;
|
||||||
|
private Timer _timer;
|
||||||
|
|
||||||
private class CacheState
|
private class CacheState
|
||||||
{
|
{
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public DateTime LastRetrieval { get; set; }
|
public DateTime LastRetrieval { get; set; }
|
||||||
public TimeSpan ExpirationTime { get; set; }
|
public TimeSpan ExpirationTime { get; set; }
|
||||||
public Func<DbSet<T>, CancellationToken, Task<V>> Getter { get; set; }
|
public Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> Getter { get; set; }
|
||||||
public V Value { get; set; }
|
public TReturnType Value { get; set; }
|
||||||
|
|
||||||
public bool IsExpired => ExpirationTime != TimeSpan.MaxValue &&
|
public bool IsExpired => ExpirationTime != TimeSpan.MaxValue &&
|
||||||
(DateTime.Now - LastRetrieval.Add(ExpirationTime)).TotalSeconds > 0;
|
(DateTime.Now - LastRetrieval.Add(ExpirationTime)).TotalSeconds > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataValueCache(ILogger<DataValueCache<T, V>> logger, IDatabaseContextFactory contextFactory)
|
public DataValueCache(ILogger<DataValueCache<TEntityType, TReturnType>> logger,
|
||||||
|
IDatabaseContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCacheItem(Func<DbSet<T>, CancellationToken, Task<V>> getter, string key,
|
~DataValueCache()
|
||||||
TimeSpan? expirationTime = null)
|
{
|
||||||
|
_timer?.Stop();
|
||||||
|
_timer?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCacheItem(Func<DbSet<TEntityType>, CancellationToken, Task<TReturnType>> getter, string key,
|
||||||
|
TimeSpan? expirationTime = null, bool autoRefresh = false)
|
||||||
{
|
{
|
||||||
if (_cacheStates.ContainsKey(key))
|
if (_cacheStates.ContainsKey(key))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Cache key {key} is already added", key);
|
_logger.LogDebug("Cache key {Key} is already added", key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var state = new CacheState()
|
var state = new CacheState
|
||||||
{
|
{
|
||||||
Key = key,
|
Key = key,
|
||||||
Getter = getter,
|
Getter = getter,
|
||||||
ExpirationTime = expirationTime ?? TimeSpan.FromMinutes(DefaultExpireMinutes)
|
ExpirationTime = expirationTime ?? TimeSpan.FromMinutes(DefaultExpireMinutes)
|
||||||
};
|
};
|
||||||
|
|
||||||
_cacheStates.Add(key, state);
|
_autoRefresh = autoRefresh;
|
||||||
|
|
||||||
|
_cacheStates.TryAdd(key, state);
|
||||||
|
|
||||||
|
if (!_autoRefresh || expirationTime == TimeSpan.MaxValue)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_timer = new Timer(state.ExpirationTime.TotalMilliseconds);
|
||||||
|
_timer.Elapsed += async (sender, args) => await RunCacheUpdate(state, CancellationToken.None);
|
||||||
|
_timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<V> GetCacheItem(string keyName, CancellationToken cancellationToken = default)
|
public async Task<TReturnType> GetCacheItem(string keyName, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (!_cacheStates.ContainsKey(keyName))
|
if (!_cacheStates.ContainsKey(keyName))
|
||||||
{
|
{
|
||||||
@ -61,7 +86,9 @@ namespace Data.Helpers
|
|||||||
|
|
||||||
var state = _cacheStates[keyName];
|
var state = _cacheStates[keyName];
|
||||||
|
|
||||||
if (state.IsExpired || state.Value == null)
|
// when auto refresh is off we want to check the expiration and value
|
||||||
|
// when auto refresh is on, we want to only check the value, because it'll be refreshed automatically
|
||||||
|
if ((state.IsExpired || state.Value == null) && !_autoRefresh || _autoRefresh && state.Value == null)
|
||||||
{
|
{
|
||||||
await RunCacheUpdate(state, cancellationToken);
|
await RunCacheUpdate(state, cancellationToken);
|
||||||
}
|
}
|
||||||
@ -73,15 +100,16 @@ namespace Data.Helpers
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("Running update for {ClassName} {@State}", GetType().Name, state);
|
||||||
await using var context = _contextFactory.CreateContext(false);
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
var set = context.Set<T>();
|
var set = context.Set<TEntityType>();
|
||||||
var value = await state.Getter(set, token);
|
var value = await state.Getter(set, token);
|
||||||
state.Value = value;
|
state.Value = value;
|
||||||
state.LastRetrieval = DateTime.Now;
|
state.LastRetrieval = DateTime.Now;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Could not get cached value for {key}", state.Key);
|
_logger.LogError(ex, "Could not get cached value for {Key}", state.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,35 +139,35 @@ steps:
|
|||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/IW4MAdmin-$(Build.BuildNumber).zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/IW4MAdmin-$(Build.BuildNumber).zip'
|
||||||
replaceExistingArchive: true
|
replaceExistingArchive: true
|
||||||
|
|
||||||
- task: FtpUpload@2
|
#- task: FtpUpload@2
|
||||||
displayName: 'Upload zip file to website'
|
# displayName: 'Upload zip file to website'
|
||||||
inputs:
|
# inputs:
|
||||||
credentialsOption: 'inputs'
|
# credentialsOption: 'inputs'
|
||||||
serverUrl: '$(FTPUrl)'
|
# serverUrl: '$(FTPUrl)'
|
||||||
username: '$(FTPUsername)'
|
# username: '$(FTPUsername)'
|
||||||
password: '$(FTPPassword)'
|
# password: '$(FTPPassword)'
|
||||||
rootDirectory: '$(Build.ArtifactStagingDirectory)'
|
# rootDirectory: '$(Build.ArtifactStagingDirectory)'
|
||||||
filePatterns: '*.zip'
|
# filePatterns: '*.zip'
|
||||||
remoteDirectory: 'IW4MAdmin/Download'
|
# remoteDirectory: 'IW4MAdmin/Download'
|
||||||
clean: false
|
# clean: false
|
||||||
cleanContents: false
|
# cleanContents: false
|
||||||
preservePaths: false
|
# preservePaths: false
|
||||||
trustSSL: false
|
# trustSSL: false
|
||||||
|
|
||||||
- task: FtpUpload@2
|
#- task: FtpUpload@2
|
||||||
displayName: 'Upload version info to website'
|
# displayName: 'Upload version info to website'
|
||||||
inputs:
|
# inputs:
|
||||||
credentialsOption: 'inputs'
|
# credentialsOption: 'inputs'
|
||||||
serverUrl: '$(FTPUrl)'
|
# serverUrl: '$(FTPUrl)'
|
||||||
username: '$(FTPUsername)'
|
# username: '$(FTPUsername)'
|
||||||
password: '$(FTPPassword)'
|
# password: '$(FTPPassword)'
|
||||||
rootDirectory: '$(Build.ArtifactStagingDirectory)'
|
# rootDirectory: '$(Build.ArtifactStagingDirectory)'
|
||||||
filePatterns: 'version_$(releaseType).txt'
|
# filePatterns: 'version_$(releaseType).txt'
|
||||||
remoteDirectory: 'IW4MAdmin'
|
# remoteDirectory: 'IW4MAdmin'
|
||||||
clean: false
|
# clean: false
|
||||||
cleanContents: false
|
# cleanContents: false
|
||||||
preservePaths: false
|
# preservePaths: false
|
||||||
trustSSL: false
|
# trustSSL: false
|
||||||
|
|
||||||
- task: GitHubRelease@1
|
- task: GitHubRelease@1
|
||||||
displayName: 'Make GitHub release'
|
displayName: 'Make GitHub release'
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
|
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -3,7 +3,7 @@ let eventParser;
|
|||||||
|
|
||||||
const plugin = {
|
const plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.3,
|
version: 0.4,
|
||||||
name: 'CS:GO Parser',
|
name: 'CS:GO Parser',
|
||||||
engine: 'Source',
|
engine: 'Source',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
@ -58,6 +58,7 @@ const plugin = {
|
|||||||
rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password');
|
rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password');
|
||||||
|
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. ';
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.Configuration.DefaultRConPort = 27015;
|
||||||
rconParser.CanGenerateLogPath = false;
|
rconParser.CanGenerateLogPath = false;
|
||||||
|
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
@ -3,7 +3,7 @@ let eventParser;
|
|||||||
|
|
||||||
const plugin = {
|
const plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.3,
|
version: 0.4,
|
||||||
name: 'CS:GO (SourceMod) Parser',
|
name: 'CS:GO (SourceMod) Parser',
|
||||||
engine: 'Source',
|
engine: 'Source',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
@ -58,6 +58,7 @@ const plugin = {
|
|||||||
rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password');
|
rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password');
|
||||||
|
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. ';
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.Configuration.DefaultRConPort = 27015;
|
||||||
rconParser.CanGenerateLogPath = false;
|
rconParser.CanGenerateLogPath = false;
|
||||||
|
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'FrenchFry, RaidMax',
|
author: 'FrenchFry, RaidMax',
|
||||||
version: 0.7,
|
version: 0.8,
|
||||||
name: 'CoD4x Parser',
|
name: 'CoD4x Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.Dvar.AddMapping(110, 4); // dvar info
|
rconParser.Configuration.Dvar.AddMapping(110, 4); // dvar info
|
||||||
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. '; // CoD4x does not support \n in the client notice
|
rconParser.Configuration.NoticeLineSeparator = '. '; // CoD4x does not support \n in the client notice
|
||||||
|
rconParser.Configuration.DefaultRConPort = 28960;
|
||||||
rconParser.Version = 'CoD4 X - win_mingw-x86 build 1056 Dec 12 2020';
|
rconParser.Version = 'CoD4 X - win_mingw-x86 build 1056 Dec 12 2020';
|
||||||
rconParser.GameName = 1; // IW3
|
rconParser.GameName = 1; // IW3
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.4,
|
version: 0.5,
|
||||||
name: 'IW4x Parser',
|
name: 'IW4x Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -18,7 +18,11 @@ var plugin = {
|
|||||||
rconParser.Configuration.CommandPrefixes.Say = 'sayraw {0}';
|
rconParser.Configuration.CommandPrefixes.Say = 'sayraw {0}';
|
||||||
rconParser.Configuration.CommandPrefixes.Kick = 'clientkick {0} "{1}"';
|
rconParser.Configuration.CommandPrefixes.Kick = 'clientkick {0} "{1}"';
|
||||||
rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"';
|
rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"';
|
||||||
rconParser.Configuration.CommandPrefixes.TempBan = 'tempbanclient {0} "{1}"';
|
rconParser.Configuration.CommandPrefixes.TempBan = 'tempbanclient {0} "{1}"'
|
||||||
|
|
||||||
|
rconParser.Configuration.DefaultRConPort = 28960;
|
||||||
|
rconParser.Configuration.DefaultInstallationDirectoryHint = 'HKEY_CURRENT_USER\\Software\\Classes\\iw4x\\shell\\open\\command';
|
||||||
|
|
||||||
eventParser.Configuration.GameDirectory = 'userraw';
|
eventParser.Configuration.GameDirectory = 'userraw';
|
||||||
|
|
||||||
rconParser.Version = 'IW4x (v0.6.0)';
|
rconParser.Version = 'IW4x (v0.6.0)';
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'Xerxes, RaidMax, st0rm',
|
author: 'Xerxes, RaidMax, st0rm',
|
||||||
version: 0.3,
|
version: 0.4,
|
||||||
name: 'IW6x Parser',
|
name: 'IW6x Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -24,6 +24,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(Yes|No) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(Yes|No) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
||||||
rconParser.Configuration.WaitForResponse = false;
|
rconParser.Configuration.WaitForResponse = false;
|
||||||
|
rconParser.Configuration.DefaultRConPort = 28960;
|
||||||
rconParser.Configuration.Status.AddMapping(102, 4);
|
rconParser.Configuration.Status.AddMapping(102, 4);
|
||||||
rconParser.Configuration.Status.AddMapping(103, 5);
|
rconParser.Configuration.Status.AddMapping(103, 5);
|
||||||
rconParser.Configuration.Status.AddMapping(104, 6);
|
rconParser.Configuration.Status.AddMapping(104, 6);
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.9,
|
version: 1.0,
|
||||||
name: 'Plutonium IW5 Parser',
|
name: 'Plutonium IW5 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -28,6 +28,9 @@ var plugin = {
|
|||||||
rconParser.Configuration.WaitForResponse = true;
|
rconParser.Configuration.WaitForResponse = true;
|
||||||
rconParser.Configuration.CanGenerateLogPath = true;
|
rconParser.Configuration.CanGenerateLogPath = true;
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. ';
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.Configuration.DefaultRConPort = 27016;
|
||||||
|
|
||||||
|
rconParser.Configuration.DefaultInstallationDirectoryHint = '{LocalAppData}/Plutonium/storage/iw5';
|
||||||
|
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(0|1) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(0|1) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax, Xerxes',
|
author: 'RaidMax, Xerxes',
|
||||||
version: 1.0,
|
version: 1.1,
|
||||||
name: 'Plutonium T6 Parser',
|
name: 'Plutonium T6 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -27,6 +27,8 @@ var plugin = {
|
|||||||
rconParser.Configuration.Dvar.AddMapping(107, 2);
|
rconParser.Configuration.Dvar.AddMapping(107, 2);
|
||||||
rconParser.Configuration.WaitForResponse = false;
|
rconParser.Configuration.WaitForResponse = false;
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. ';
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.Configuration.DefaultRConPort = 4976;
|
||||||
|
rconParser.Configuration.DefaultInstallationDirectoryHint = '{LocalAppData}/Plutonium/storage/t6';
|
||||||
|
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(?:[0-1]{1}) +([0-9]+) +([A-F0-9]+|0) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(?:[0-1]{1}) +([0-9]+) +([A-F0-9]+|0) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax, Chase',
|
author: 'RaidMax, Chase',
|
||||||
version: 0.2,
|
version: 0.3,
|
||||||
name: 'Plutonium T4 Parser',
|
name: 'Plutonium T4 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -19,6 +19,9 @@ var plugin = {
|
|||||||
rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0}';
|
rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0}';
|
||||||
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
||||||
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
|
rconParser.Configuration.DefaultRConPort = 28960;
|
||||||
|
|
||||||
|
rconParser.Configuration.DefaultInstallationDirectoryHint = '{LocalAppData}/Plutonium/storage/t4';
|
||||||
|
|
||||||
rconParser.Version = 'Plutonium T4';
|
rconParser.Version = 'Plutonium T4';
|
||||||
rconParser.GameName = 5; // T4
|
rconParser.GameName = 5; // T4
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.3,
|
version: 0.4,
|
||||||
name: 'RektT5m Parser',
|
name: 'RektT5m Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01print\n';
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\x01print\n';
|
||||||
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
rconParser.Configuration.DefaultRConPort = 28960;
|
||||||
|
|
||||||
rconParser.Version = 'Call of Duty Multiplayer - Ship COD_T5_S MP build 7.0.189 CL(1022875) CODPCAB-V64 CEG Wed Nov 02 18:02:23 2011 win-x86';
|
rconParser.Version = 'Call of Duty Multiplayer - Ship COD_T5_S MP build 7.0.189 CL(1022875) CODPCAB-V64 CEG Wed Nov 02 18:02:23 2011 win-x86';
|
||||||
rconParser.GameName = 6; // T5
|
rconParser.GameName = 6; // T5
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'Diavolo, RaidMax',
|
author: 'Diavolo, RaidMax',
|
||||||
version: 0.1,
|
version: 0.2,
|
||||||
name: 'S1x Parser',
|
name: 'S1x Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -24,6 +24,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.Status.AddMapping(103, 5);
|
rconParser.Configuration.Status.AddMapping(103, 5);
|
||||||
rconParser.Configuration.Status.AddMapping(104, 6);
|
rconParser.Configuration.Status.AddMapping(104, 6);
|
||||||
rconParser.Configuration.WaitForResponse = false;
|
rconParser.Configuration.WaitForResponse = false;
|
||||||
|
rconParser.Configuration.DefaultRConPort = 27016;
|
||||||
|
|
||||||
eventParser.Configuration.GameDirectory = '';
|
eventParser.Configuration.GameDirectory = '';
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.1,
|
version: 0.2,
|
||||||
name: 'Call of Duty 5: World at War Parser',
|
name: 'Call of Duty 5: World at War Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ var plugin = {
|
|||||||
eventParser = manager.GenerateDynamicEventParser(this.name);
|
eventParser = manager.GenerateDynamicEventParser(this.name);
|
||||||
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
||||||
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
|
rconParser.Configuration.DefaultRConPort = 28960;
|
||||||
rconParser.Version = 'Call of Duty Multiplayer COD_WaW MP build 1.7.1263 CL(350073) JADAMS2 Thu Oct 29 15:43:55 2009 win-x86';
|
rconParser.Version = 'Call of Duty Multiplayer COD_WaW MP build 1.7.1263 CL(350073) JADAMS2 Thu Oct 29 15:43:55 2009 win-x86';
|
||||||
|
|
||||||
eventParser.Configuration.GuidNumberStyle = 7; // Integer
|
eventParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.3,
|
version: 0.4,
|
||||||
name: 'Black Ops 3 Parser',
|
name: 'Black Ops 3 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.MapStatus.Pattern = 'Map: (.+)';
|
rconParser.Configuration.MapStatus.Pattern = 'Map: (.+)';
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7
|
||||||
rconParser.Configuration.ServerNotRunningResponse = 'this is here to prevent a hibernating server from being detected as not running';
|
rconParser.Configuration.ServerNotRunningResponse = 'this is here to prevent a hibernating server from being detected as not running';
|
||||||
|
rconParser.Configuration.DefaultRConPort = 27016;
|
||||||
|
|
||||||
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'live_steam_server_name');
|
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'live_steam_server_name');
|
||||||
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.8,
|
version: 0.9,
|
||||||
name: 'Tekno MW3 Parser',
|
name: 'Tekno MW3 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.Dvar.AddMapping(107, 1); // RCon DvarValue
|
rconParser.Configuration.Dvar.AddMapping(107, 1); // RCon DvarValue
|
||||||
rconParser.Configuration.Dvar.Pattern = '^(.*)$';
|
rconParser.Configuration.Dvar.Pattern = '^(.*)$';
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. ';
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.Configuration.DefaultRConPort = 8766;
|
||||||
|
|
||||||
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
||||||
rconParser.Configuration.OverrideDvarNameMapping.Add('_website', 'sv_clanWebsite');
|
rconParser.Configuration.OverrideDvarNameMapping.Add('_website', 'sv_clanWebsite');
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -104,24 +104,22 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<string> GetCountryName(string ip)
|
private async Task<string> GetCountryName(string ip)
|
||||||
{
|
{
|
||||||
using (var wc = new WebClient())
|
using var wc = new WebClient();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
var response =
|
||||||
{
|
await wc.DownloadStringTaskAsync(new Uri($"http://extreme-ip-lookup.com/json/{ip}?key=demo"));
|
||||||
string response =
|
var responseObj = JObject.Parse(response);
|
||||||
await wc.DownloadStringTaskAsync(new Uri($"http://extreme-ip-lookup.com/json/{ip}"));
|
response = responseObj["country"]?.ToString();
|
||||||
var responseObj = JObject.Parse(response);
|
|
||||||
response = responseObj["country"].ToString();
|
|
||||||
|
|
||||||
return string.IsNullOrEmpty(response)
|
return string.IsNullOrEmpty(response)
|
||||||
? Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_COUNTRY"]
|
? Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_COUNTRY"]
|
||||||
: response;
|
: response;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_IP"];
|
return Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_IP"];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.8.31.1" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2021.11.15.1" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -83,9 +83,10 @@ namespace SharedLibraryCore.Commands
|
|||||||
var found = await Manager.GetClientService().Get(dbID);
|
var found = await Manager.GetClientService().Get(dbID);
|
||||||
if (found != null)
|
if (found != null)
|
||||||
{
|
{
|
||||||
|
found = Manager.FindActiveClient(found);
|
||||||
E.Target = found;
|
E.Target = found;
|
||||||
E.Target.CurrentServer = E.Owner;
|
E.Target.CurrentServer = found.CurrentServer ?? E.Owner;
|
||||||
E.Data = String.Join(" ", Args.Skip(1));
|
E.Data = string.Join(" ", Args.Skip(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Configuration.Extensions
|
||||||
|
{
|
||||||
|
public static class ConfigurationExtensions
|
||||||
|
{
|
||||||
|
public static void TrySetIpAddress(this ServerConfiguration config)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var interfaces = NetworkInterface.GetAllNetworkInterfaces().Where(nic =>
|
||||||
|
nic.OperationalStatus == OperationalStatus.Up &&
|
||||||
|
(nic.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
|
||||||
|
nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet && nic.GetIPProperties().UnicastAddresses
|
||||||
|
.Any(addr => addr.Address.AddressFamily == AddressFamily.InterNetwork))).ToList();
|
||||||
|
|
||||||
|
var publicInterfaces = interfaces.Where(nic =>
|
||||||
|
nic.GetIPProperties().UnicastAddresses.Any(info =>
|
||||||
|
info.Address.AddressFamily == AddressFamily.InterNetwork && !info.Address.IsInternal()))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
config.IPAddress = publicInterfaces.Any()
|
||||||
|
? publicInterfaces.First().GetIPProperties().UnicastAddresses.First().Address.ToString()
|
||||||
|
: IPAddress.Loopback.ToString();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
config.IPAddress = IPAddress.Loopback.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (string, string)[] TryGetRConPasswords(this IRConParser parser)
|
||||||
|
{
|
||||||
|
string searchPath = null;
|
||||||
|
var isRegistryKey = parser.Configuration.DefaultInstallationDirectoryHint.Contains("HKEY_");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isRegistryKey)
|
||||||
|
{
|
||||||
|
var result = Registry.GetValue(parser.Configuration.DefaultInstallationDirectoryHint, null, null);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return new (string, string)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPath = Path.Combine(result.ToString().Split(Path.DirectorySeparatorChar)
|
||||||
|
.Where(p => !p.Contains(".exe"))
|
||||||
|
.Select(p => p.Replace("\"", "")).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var path = parser.Configuration.DefaultInstallationDirectoryHint.Replace("{LocalAppData}",
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
|
||||||
|
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
{
|
||||||
|
searchPath = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(searchPath))
|
||||||
|
{
|
||||||
|
return new (string, string)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var possibleFiles = Directory.GetFiles(searchPath, "*.cfg", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
if (!possibleFiles.Any())
|
||||||
|
{
|
||||||
|
return new (string, string)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var possiblePasswords = possibleFiles.SelectMany(File.ReadAllLines)
|
||||||
|
.Select(line => Regex.Match(line, "^(\\/\\/)?.*rcon_password +\"?([^\\/\"\n]+)\"?"))
|
||||||
|
.Where(match => match.Success)
|
||||||
|
.Select(match =>
|
||||||
|
!string.IsNullOrEmpty(match.Groups[1].ToString())
|
||||||
|
? (match.Groups[2].ToString(),
|
||||||
|
Utilities.CurrentLocalization.LocalizationIndex["SETUP_RCON_PASSWORD_COMMENTED"])
|
||||||
|
: (match.Groups[2].ToString(), null));
|
||||||
|
|
||||||
|
return possiblePasswords.ToArray();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new (string, string)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using SharedLibraryCore.Configuration.Extensions;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Configuration
|
namespace SharedLibraryCore.Configuration
|
||||||
{
|
{
|
||||||
@ -10,96 +11,145 @@ namespace SharedLibraryCore.Configuration
|
|||||||
{
|
{
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_IP")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_IP")]
|
||||||
public string IPAddress { get; set; }
|
public string IPAddress { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PORT")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PORT")]
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PASSWORD")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PASSWORD")]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RULES")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RULES")]
|
||||||
public string[] Rules { get; set; } = new string[0];
|
public string[] Rules { get; set; } = new string[0];
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_AUTO_MESSAGES")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_AUTO_MESSAGES")]
|
||||||
public string[] AutoMessages { get; set; } = new string[0];
|
public string[] AutoMessages { get; set; } = new string[0];
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PATH")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_PATH")]
|
||||||
[ConfigurationOptional]
|
[ConfigurationOptional]
|
||||||
public string ManualLogPath { get; set; }
|
public string ManualLogPath { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RCON_PARSER")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RCON_PARSER")]
|
||||||
public string RConParserVersion { get; set; }
|
public string RConParserVersion { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_EVENT_PARSER")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_EVENT_PARSER")]
|
||||||
public string EventParserVersion { get; set; }
|
public string EventParserVersion { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RESERVED_SLOT")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_RESERVED_SLOT")]
|
||||||
public int ReservedSlotNumber { get; set; }
|
public int ReservedSlotNumber { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_GAME_LOG_SERVER")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_GAME_LOG_SERVER")]
|
||||||
[ConfigurationOptional]
|
[ConfigurationOptional]
|
||||||
public Uri GameLogServerUrl { get; set; }
|
public Uri GameLogServerUrl { get; set; }
|
||||||
|
|
||||||
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_CUSTOM_HOSTNAME")]
|
[LocalizedDisplayName("WEBFRONT_CONFIGURATION_SERVER_CUSTOM_HOSTNAME")]
|
||||||
[ConfigurationOptional]
|
[ConfigurationOptional]
|
||||||
public string CustomHostname { get; set; }
|
public string CustomHostname { get; set; }
|
||||||
|
|
||||||
private readonly IList<IRConParser> rconParsers;
|
private readonly IList<IRConParser> _rconParsers;
|
||||||
private readonly IList<IEventParser> eventParsers;
|
private IRConParser _selectedParser;
|
||||||
|
|
||||||
public ServerConfiguration()
|
public ServerConfiguration()
|
||||||
{
|
{
|
||||||
rconParsers = new List<IRConParser>();
|
_rconParsers = new List<IRConParser>();
|
||||||
eventParsers = new List<IEventParser>();
|
|
||||||
Rules = new string[0];
|
Rules = new string[0];
|
||||||
AutoMessages = new string[0];
|
AutoMessages = new string[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRConParser(IRConParser parser)
|
public void AddRConParser(IRConParser parser)
|
||||||
{
|
{
|
||||||
rconParsers.Add(parser);
|
_rconParsers.Add(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEventParser(IEventParser parser)
|
public void AddEventParser(IEventParser parser)
|
||||||
{
|
{
|
||||||
eventParsers.Add(parser);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ModifyParsers()
|
public void ModifyParsers()
|
||||||
{
|
{
|
||||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
var parserVersions = rconParsers.Select(_parser => _parser.Name).ToArray();
|
var parserVersions = _rconParsers.Select(p => p.Name).ToArray();
|
||||||
var selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_RCON_PARSER_VERSION"]} ({IPAddress}:{Port})", parserVersions[0], null, parserVersions);
|
var (index, parser) = loc["SETUP_SERVER_RCON_PARSER_VERSION"].PromptSelection(parserVersions[0],
|
||||||
|
null, parserVersions);
|
||||||
|
|
||||||
if (selection.Item1 >= 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
RConParserVersion = rconParsers.FirstOrDefault(_parser => _parser.Name == selection.Item2)?.Version;
|
return;
|
||||||
|
|
||||||
if (selection.Item1 > 0 && !rconParsers[selection.Item1].CanGenerateLogPath)
|
|
||||||
{
|
|
||||||
Console.WriteLine(loc["SETUP_SERVER_NO_LOG"]);
|
|
||||||
ManualLogPath = Utilities.PromptString(loc["SETUP_SERVER_LOG_PATH"]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parserVersions = eventParsers.Select(_parser => _parser.Name).ToArray();
|
_selectedParser = _rconParsers.FirstOrDefault(p => p.Name == parser);
|
||||||
selection = Utilities.PromptSelection($"{loc["SETUP_SERVER_EVENT_PARSER_VERSION"]} ({IPAddress}:{Port})", parserVersions[0], null, parserVersions);
|
RConParserVersion = _selectedParser?.Version;
|
||||||
|
EventParserVersion = _selectedParser?.Version;
|
||||||
|
|
||||||
if (selection.Item1 >= 0)
|
if (index <= 0 || _rconParsers[index].CanGenerateLogPath)
|
||||||
{
|
{
|
||||||
EventParserVersion = eventParsers.FirstOrDefault(_parser => _parser.Name == selection.Item2)?.Version;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(loc["SETUP_SERVER_NO_LOG"]);
|
||||||
|
ManualLogPath = loc["SETUP_SERVER_LOG_PATH"].PromptString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBaseConfiguration Generate()
|
public IBaseConfiguration Generate()
|
||||||
{
|
{
|
||||||
|
ModifyParsers();
|
||||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
|
var shouldTryFindIp = loc["SETUP_SERVER_IP_AUTO"].PromptBool(defaultValue: true);
|
||||||
|
|
||||||
while (string.IsNullOrEmpty(IPAddress))
|
if (shouldTryFindIp)
|
||||||
{
|
{
|
||||||
var input = Utilities.PromptString(loc["SETUP_SERVER_IP"]);
|
this.TrySetIpAddress();
|
||||||
IPAddress = input;
|
Console.WriteLine(loc["SETUP_SERVER_IP_AUTO_RESULT"].FormatExt(IPAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (string.IsNullOrEmpty(IPAddress))
|
||||||
|
{
|
||||||
|
var input = loc["SETUP_SERVER_IP"].PromptString();
|
||||||
|
IPAddress = input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultPort = _selectedParser.Configuration.DefaultRConPort;
|
||||||
|
Port = loc["SETUP_SERVER_PORT"].PromptInt(null, 1, ushort.MaxValue, defaultValue:defaultPort);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(_selectedParser.Configuration.DefaultInstallationDirectoryHint))
|
||||||
|
{
|
||||||
|
var shouldTryFindPassword = loc["SETUP_RCON_PASSWORD_AUTO"].PromptBool(defaultValue: true);
|
||||||
|
|
||||||
|
if (shouldTryFindPassword)
|
||||||
|
{
|
||||||
|
var passwords = _selectedParser.TryGetRConPasswords();
|
||||||
|
if (passwords.Length > 1)
|
||||||
|
{
|
||||||
|
var (index, value) =
|
||||||
|
loc["SETUP_RCON_PASSWORD_PROMPT"].PromptSelection(loc["SETUP_RCON_PASSWORD_MANUAL"], null,
|
||||||
|
passwords.Select(pw =>
|
||||||
|
$"{pw.Item1}{(string.IsNullOrEmpty(pw.Item2) ? "" : " " + pw.Item2)}").ToArray());
|
||||||
|
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
Password = passwords[index - 1].Item1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (passwords.Length > 0)
|
||||||
|
{
|
||||||
|
Password = passwords[0].Item1;
|
||||||
|
Console.WriteLine(loc["SETUP_RCON_PASSWORD_RESULT"].FormatExt(Password));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Password))
|
||||||
|
{
|
||||||
|
Password = loc["SETUP_SERVER_RCON"].PromptString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Port = Utilities.PromptInt(loc["SETUP_SERVER_PORT"], null, 1, ushort.MaxValue);
|
|
||||||
Password = Utilities.PromptString(loc["SETUP_SERVER_RCON"]);
|
|
||||||
AutoMessages = new string[0];
|
AutoMessages = new string[0];
|
||||||
Rules = new string[0];
|
Rules = new string[0];
|
||||||
ReservedSlotNumber = loc["SETUP_SERVER_RESERVEDSLOT"].PromptInt(null, 0, 32);
|
|
||||||
ManualLogPath = null;
|
ManualLogPath = null;
|
||||||
|
|
||||||
ModifyParsers();
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,4 +158,4 @@ namespace SharedLibraryCore.Configuration
|
|||||||
return "ServerConfiguration";
|
return "ServerConfiguration";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,6 @@ using System.Threading;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -23,6 +22,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
IList<IManagerCommand> GetCommands();
|
IList<IManagerCommand> GetCommands();
|
||||||
IList<Helpers.MessageToken> GetMessageTokens();
|
IList<Helpers.MessageToken> GetMessageTokens();
|
||||||
IList<EFClient> GetActiveClients();
|
IList<EFClient> GetActiveClients();
|
||||||
|
EFClient FindActiveClient(EFClient client);
|
||||||
IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings();
|
IConfigurationHandler<ApplicationConfiguration> GetApplicationSettings();
|
||||||
ClientService GetClientService();
|
ClientService GetClientService();
|
||||||
PenaltyService GetPenaltyService();
|
PenaltyService GetPenaltyService();
|
||||||
|
@ -87,5 +87,15 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// specifies the characters used to split a line
|
/// specifies the characters used to split a line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string NoticeLineSeparator { get; }
|
string NoticeLineSeparator { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default port the game listens to RCon requests on
|
||||||
|
/// </summary>
|
||||||
|
int? DefaultRConPort { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default Indicator of where the game is installed (ex file path or registry entry)
|
||||||
|
/// </summary>
|
||||||
|
string DefaultInstallationDirectoryHint { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -683,6 +683,17 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
set => SetAdditionalProperty(EFMeta.ClientTag, value);
|
set => SetAdditionalProperty(EFMeta.ClientTag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public int TemporalClientNumber
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var temporalClientId = GetAdditionalProperty<string>("ConnectionClientId");
|
||||||
|
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?) null : int.Parse(temporalClientId);
|
||||||
|
return parsedClientId ?? ClientNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
private readonly SemaphoreSlim _processingEvent;
|
private readonly SemaphoreSlim _processingEvent;
|
||||||
|
|
||||||
|
@ -218,9 +218,9 @@ namespace SharedLibraryCore
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Temporarily ban a player ( default 1 hour ) from the server
|
/// Temporarily ban a player ( default 1 hour ) from the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Reason">Reason for banning the player</param>
|
/// <param name="reason">Reason for banning the player</param>
|
||||||
/// <param name="Target">The player to ban</param>
|
/// <param name="Target">The player to ban</param>
|
||||||
abstract public Task TempBan(String Reason, TimeSpan length, EFClient Target, EFClient Origin);
|
abstract public Task TempBan(String reason, TimeSpan length, EFClient Target, EFClient Origin);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perm ban a player from the server
|
/// Perm ban a player from the server
|
||||||
@ -236,9 +236,9 @@ namespace SharedLibraryCore
|
|||||||
/// Unban a player by npID / GUID
|
/// Unban a player by npID / GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="npID">npID of the player</param>
|
/// <param name="npID">npID of the player</param>
|
||||||
/// <param name="Target">I don't remember what this is for</param>
|
/// <param name="targetClient">I don't remember what this is for</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
abstract public Task Unban(string reason, EFClient Target, EFClient Origin);
|
abstract public Task Unban(string reason, EFClient targetClient, EFClient originClient);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change the current searver map
|
/// Change the current searver map
|
||||||
|
@ -162,15 +162,29 @@ namespace SharedLibraryCore.Services
|
|||||||
.Where(p => p.LinkId == linkId)
|
.Where(p => p.LinkId == linkId)
|
||||||
.Where(filter);
|
.Where(filter);
|
||||||
|
|
||||||
var iqIpPenalties = _appConfig.EnableImplicitAccountLinking
|
IQueryable<EFPenalty> iqIpPenalties;
|
||||||
? context.Aliases
|
|
||||||
|
if (_appConfig.EnableImplicitAccountLinking)
|
||||||
|
{
|
||||||
|
iqIpPenalties = context.Aliases
|
||||||
.Where(a => a.IPAddress != null && a.IPAddress == ip)
|
.Where(a => a.IPAddress != null && a.IPAddress == ip)
|
||||||
.SelectMany(a => a.Link.ReceivedPenalties)
|
.SelectMany(a => a.Link.ReceivedPenalties)
|
||||||
.Where(filter)
|
|
||||||
: context.Penalties.Where(penalty =>
|
|
||||||
penalty.Offender.CurrentAlias.IPAddress != null &&
|
|
||||||
penalty.Offender.CurrentAlias.IPAddress == ip)
|
|
||||||
.Where(filter);
|
.Where(filter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var aliasIps = await context.Aliases.Where(alias => alias.LinkId == linkId && alias.IPAddress != null)
|
||||||
|
.Select(alias => alias.IPAddress)
|
||||||
|
.ToListAsync();
|
||||||
|
if (ip != null)
|
||||||
|
{
|
||||||
|
aliasIps.Add(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
iqIpPenalties = context.Penalties
|
||||||
|
.Where(penalty => aliasIps.Contains(penalty.Offender.CurrentAlias.IPAddress))
|
||||||
|
.Where(filter);
|
||||||
|
}
|
||||||
|
|
||||||
var activePenalties = (await iqLinkPenalties.ToListAsync())
|
var activePenalties = (await iqLinkPenalties.ToListAsync())
|
||||||
.Union(await iqIpPenalties.ToListAsync())
|
.Union(await iqIpPenalties.ToListAsync())
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||||
<Version>2021.8.31.1</Version>
|
<Version>2021.11.15.1</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<Description>Shared Library for IW4MAdmin</Description>
|
<Description>Shared Library for IW4MAdmin</Description>
|
||||||
<PackageVersion>2021.8.31.1</PackageVersion>
|
<PackageVersion>2021.11.15.1</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.10" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.10" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.10" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.Data" Version="1.0.7" />
|
<PackageReference Include="RaidMax.IW4MAdmin.Data" Version="1.0.8" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -546,7 +546,7 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="description">description of the question's value</param>
|
/// <param name="description">description of the question's value</param>
|
||||||
/// <param name="defaultValue">default value to set if no input is entered</param>
|
/// <param name="defaultValue">default value to set if no input is entered</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool PromptBool(string question, string description = null, bool defaultValue = true)
|
public static bool PromptBool(this string question, string description = null, bool defaultValue = true)
|
||||||
{
|
{
|
||||||
Console.Write($"{question}?{(string.IsNullOrEmpty(description) ? " " : $" ({description}) ")}[y/n]: ");
|
Console.Write($"{question}?{(string.IsNullOrEmpty(description) ? " " : $" ({description}) ")}[y/n]: ");
|
||||||
char response = Console.ReadLine().ToLower().FirstOrDefault();
|
char response = Console.ReadLine().ToLower().FirstOrDefault();
|
||||||
@ -562,7 +562,7 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="description">description of the question's value</param>
|
/// <param name="description">description of the question's value</param>
|
||||||
/// <param name="selections">array of possible selections (should be able to convert to string)</param>
|
/// <param name="selections">array of possible selections (should be able to convert to string)</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static Tuple<int, T> PromptSelection<T>(string question, T defaultValue, string description = null, params T[] selections)
|
public static Tuple<int, T> PromptSelection<T>(this string question, T defaultValue, string description = null, params T[] selections)
|
||||||
{
|
{
|
||||||
bool hasDefault = false;
|
bool hasDefault = false;
|
||||||
|
|
||||||
@ -634,7 +634,7 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="description">description of the question's value</param>
|
/// <param name="description">description of the question's value</param>
|
||||||
/// <param name="defaultValue">default value to set the return value to</param>
|
/// <param name="defaultValue">default value to set the return value to</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string PromptString(string question, string description = null, string defaultValue = null)
|
public static string PromptString(this string question, string description = null, string defaultValue = null)
|
||||||
{
|
{
|
||||||
string inputOrDefault()
|
string inputOrDefault()
|
||||||
{
|
{
|
||||||
|
@ -50,9 +50,15 @@
|
|||||||
{
|
{
|
||||||
<!-- I don't want to include the entire highlight js into the bundle for this 1 page -->
|
<!-- I don't want to include the entire highlight js into the bundle for this 1 page -->
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
|
||||||
|
<script>
|
||||||
|
if (hljs !== undefined) {
|
||||||
|
hljs.highlightAll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<environment include="Development">
|
<environment include="Development">
|
||||||
<script type="text/javascript" src="~/js/configuration.js"></script>
|
<script type="text/javascript" src="~/js/configuration.js"></script>
|
||||||
</environment>
|
</environment>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
@ -202,6 +202,6 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@await RenderSectionAsync("scripts", required: false)
|
@await RenderSectionAsync("scripts", required: false)
|
||||||
@Html.Raw(ViewBag.ScriptInjection);
|
@Html.Raw(ViewBag.ScriptInjection)
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -78,10 +78,6 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="Views\Plugins\**" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Remove="Views\Plugins\**" />
|
<EmbeddedResource Remove="Views\Plugins\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -96,7 +92,7 @@
|
|||||||
<Exec Command="if $(ConfigurationName) == Debug ( 
powershell -Command wget https://raw.githubusercontent.com/iconic/open-iconic/master/font/css/open-iconic-bootstrap.scss -o $(ProjectDir)wwwroot\lib\open-iconic\font\css\open-iconic-bootstrap.scss
echo d | xcopy /f /y $(ProjectDir)wwwroot\lib\open-iconic\font\fonts $(ProjectDir)wwwroot\font\
)" />
|
<Exec Command="if $(ConfigurationName) == Debug ( 
powershell -Command wget https://raw.githubusercontent.com/iconic/open-iconic/master/font/css/open-iconic-bootstrap.scss -o $(ProjectDir)wwwroot\lib\open-iconic\font\css\open-iconic-bootstrap.scss
echo d | xcopy /f /y $(ProjectDir)wwwroot\lib\open-iconic\font\fonts $(ProjectDir)wwwroot\font\
)" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="MyPreCompileTarget" BeforeTargets="Build">
|
<Target Name="MyPreCompileTarget" BeforeTargets="Build" Condition="'$(Configuration)'!='Debug'">
|
||||||
<Exec Command="dotnet bundle" />
|
<Exec Command="dotnet bundle" />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -99,7 +99,7 @@ $(document).ready(function () {
|
|||||||
$.get('https://ip2c.org/' + $(address).data('ip'), function (result) {
|
$.get('https://ip2c.org/' + $(address).data('ip'), function (result) {
|
||||||
const countryCode = result.split(';')[1].toLowerCase();
|
const countryCode = result.split(';')[1].toLowerCase();
|
||||||
if (countryCode !== 'zz') {
|
if (countryCode !== 'zz') {
|
||||||
$(address).css('background-image', `url(https://www.countryflags.io/${countryCode}/flat/64.png)`);
|
$(address).css('background-image', `url('https://flagcdn.com/w80/${countryCode}.png')`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -73,8 +73,7 @@
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
hljs.highlightAll();
|
|
||||||
$('.edit-file' ).on('keydown .editable', function(e){
|
$('.edit-file' ).on('keydown .editable', function(e){
|
||||||
if(e.keyCode === 9) {
|
if(e.keyCode === 9) {
|
||||||
document.execCommand ( 'styleWithCSS', true, null )
|
document.execCommand ( 'styleWithCSS', true, null )
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
$('#ip_lookup_country').text(country);
|
$('#ip_lookup_country').text(country);
|
||||||
if (countryCode !== 'zz' && countryCode !== '') {
|
if (countryCode !== 'zz' && countryCode !== '') {
|
||||||
$(address).css('background-image', `url(https://www.countryflags.io/${countryCode}/flat/64.png)`);
|
$(address).css('background-image', `url('https://flagcdn.com/w80/${countryCode}.png')`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -34,7 +34,6 @@
|
|||||||
/* set the end time for initial event query */
|
/* set the end time for initial event query */
|
||||||
startAt = $('.loader-data-time').last().data('time');
|
startAt = $('.loader-data-time').last().data('time');
|
||||||
|
|
||||||
|
|
||||||
$('#filter_meta_container_button').click(function () {
|
$('#filter_meta_container_button').click(function () {
|
||||||
$('#filter_meta_container').hide();
|
$('#filter_meta_container').hide();
|
||||||
$('#filter_meta_container').removeClass('d-none');
|
$('#filter_meta_container').removeClass('d-none');
|
||||||
@ -97,7 +96,7 @@
|
|||||||
$('.ip-locate-link').click(function (e) {
|
$('.ip-locate-link').click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const ip = $(this).data("ip");
|
const ip = $(this).data("ip");
|
||||||
$.getJSON('https://extreme-ip-lookup.com/json/' + ip)
|
$.getJSON('https://extreme-ip-lookup.com/json/' + ip + '?key=demo')
|
||||||
.done(function (response) {
|
.done(function (response) {
|
||||||
$('#mainModal .modal-title').text(ip);
|
$('#mainModal .modal-title').text(ip);
|
||||||
$('#mainModal .modal-body').text('');
|
$('#mainModal .modal-body').text('');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user