Compare commits
47 Commits
2.3-prerel
...
2.3-prerel
Author | SHA1 | Date | |
---|---|---|---|
02622ea7de | |||
03ae3b5822 | |||
0711249a46 | |||
18f4ffa9ff | |||
934fead5c2 | |||
02cad10d77 | |||
b134cd4728 | |||
b9c4a1b5f6 | |||
f0fd4c66e9 | |||
52fe8fc847 | |||
9f8c35dbed | |||
9d9be7f8af | |||
dd82a5e3fa | |||
8667532d24 | |||
863ba8b096 | |||
8ab89e113d | |||
00634780d4 | |||
6f80f1edbb | |||
9393b35c39 | |||
37d3f4f90d | |||
8521df85f5 | |||
7b8126d57e | |||
1e2e2218e3 | |||
11e3235d5d | |||
cae6d8389e | |||
1056c7c335 | |||
95e4ee672e | |||
bf0a0befc6 | |||
53c3ff6ce3 | |||
c8ec0eefa9 | |||
82bae772f0 | |||
af3aea77bc | |||
b3e5f468a1 | |||
c21bf2ebf1 | |||
d318a57830 | |||
61f1436faf | |||
0c527a5f65 | |||
1457b843e2 | |||
de69bed792 | |||
4b1f44cc2a | |||
74cdf8e885 | |||
5d41059641 | |||
2e6889d9bb | |||
9c4d23f0b4 | |||
b4e3e8526a | |||
e3944fb8c2 | |||
40f1697c97 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -223,7 +223,7 @@ global.min.js
|
|||||||
bootstrap-custom.min.css
|
bootstrap-custom.min.css
|
||||||
**/Master/static
|
**/Master/static
|
||||||
**/Master/dev_env
|
**/Master/dev_env
|
||||||
/WebfrontCore/Views/Plugins/Stats
|
/WebfrontCore/Views/Plugins/*
|
||||||
/WebfrontCore/wwwroot/**/dds
|
/WebfrontCore/wwwroot/**/dds
|
||||||
|
|
||||||
/DiscordWebhook/env
|
/DiscordWebhook/env
|
||||||
@ -232,4 +232,5 @@ bootstrap-custom.min.css
|
|||||||
launchSettings.json
|
launchSettings.json
|
||||||
/VpnDetectionPrivate.js
|
/VpnDetectionPrivate.js
|
||||||
/Plugins/ScriptPlugins/VpnDetectionPrivate.js
|
/Plugins/ScriptPlugins/VpnDetectionPrivate.js
|
||||||
**/Master/env_master
|
**/Master/env_master
|
||||||
|
/GameLogServer/log_env
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using RestEase;
|
using RestEase;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
@ -11,6 +12,7 @@ namespace IW4MAdmin.Application.API.Master
|
|||||||
public class HeartbeatState
|
public class HeartbeatState
|
||||||
{
|
{
|
||||||
public bool Connected { get; set; }
|
public bool Connected { get; set; }
|
||||||
|
public CancellationToken Token { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Heartbeat
|
public class Heartbeat
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
<RuntimeFrameworkVersion>2.2.2</RuntimeFrameworkVersion>
|
<RuntimeFrameworkVersion>2.2.2</RuntimeFrameworkVersion>
|
||||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
||||||
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
||||||
<Version>2.2.5.1</Version>
|
<Version>2.2.6.5</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Product>IW4MAdmin</Product>
|
<Product>IW4MAdmin</Product>
|
||||||
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated server</Description>
|
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated servers</Description>
|
||||||
<Copyright>2019</Copyright>
|
<Copyright>2019</Copyright>
|
||||||
<PackageLicenseUrl>https://github.com/RaidMax/IW4M-Admin/blob/master/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/RaidMax/IW4M-Admin/blob/master/LICENSE</PackageLicenseUrl>
|
||||||
<PackageProjectUrl>https://raidmax.org/IW4MAdmin</PackageProjectUrl>
|
<PackageProjectUrl>https://raidmax.org/IW4MAdmin</PackageProjectUrl>
|
||||||
@ -31,8 +31,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||||
<TieredCompilation>true</TieredCompilation>
|
<TieredCompilation>true</TieredCompilation>
|
||||||
<AssemblyVersion>2.2.5.1</AssemblyVersion>
|
<AssemblyVersion>2.2.6.5</AssemblyVersion>
|
||||||
<FileVersion>2.2.5.1</FileVersion>
|
<FileVersion>2.2.6.5</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -45,37 +45,10 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="Properties\IW4MAdmin.en-US.Designer.cs">
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
<DependentUpon>IW4MAdmin.en-US.resx</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Update="Properties\IW4MAdmin.en-US.resx">
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
<LastGenOutput>IW4MAdmin.en-US.Designer.cs</LastGenOutput>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="DefaultSettings.json">
|
<None Update="DefaultSettings.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="Localization\IW4MAdmin.en-US.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="Localization\IW4MAdmin.es-EC.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="Localization\IW4MAdmin.pt-BR.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="Localization\IW4MAdmin.ru-RU.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -7,10 +7,12 @@ using SharedLibraryCore.Commands;
|
|||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Database;
|
using SharedLibraryCore.Database;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Events;
|
using SharedLibraryCore.Events;
|
||||||
using SharedLibraryCore.Exceptions;
|
using SharedLibraryCore.Exceptions;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.Objects;
|
||||||
using SharedLibraryCore.Services;
|
using SharedLibraryCore.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -39,10 +41,9 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public IList<IRConParser> AdditionalRConParsers { get; }
|
public IList<IRConParser> AdditionalRConParsers { get; }
|
||||||
public IList<IEventParser> AdditionalEventParsers { get; }
|
public IList<IEventParser> AdditionalEventParsers { get; }
|
||||||
|
|
||||||
public ITokenAuthentication TokenAuthenticator => Authenticator;
|
public ITokenAuthentication TokenAuthenticator => Authenticator;
|
||||||
|
|
||||||
public ITokenAuthentication Authenticator => _authenticator;
|
public ITokenAuthentication Authenticator => _authenticator;
|
||||||
|
public string ExternalIPAddress { get; private set; }
|
||||||
|
|
||||||
static ApplicationManager Instance;
|
static ApplicationManager Instance;
|
||||||
readonly List<AsyncStatus> TaskStatuses;
|
readonly List<AsyncStatus> TaskStatuses;
|
||||||
@ -58,6 +59,8 @@ namespace IW4MAdmin.Application
|
|||||||
readonly SemaphoreSlim ProcessingEvent = new SemaphoreSlim(1, 1);
|
readonly SemaphoreSlim ProcessingEvent = new SemaphoreSlim(1, 1);
|
||||||
readonly Dictionary<long, ILogger> Loggers = new Dictionary<long, ILogger>();
|
readonly Dictionary<long, ILogger> Loggers = new Dictionary<long, ILogger>();
|
||||||
readonly ITokenAuthentication _authenticator;
|
readonly ITokenAuthentication _authenticator;
|
||||||
|
private readonly MetaService _metaService;
|
||||||
|
private readonly TimeSpan _throttleTimeout = new TimeSpan(0, 1, 0);
|
||||||
|
|
||||||
private ApplicationManager()
|
private ApplicationManager()
|
||||||
{
|
{
|
||||||
@ -77,6 +80,7 @@ namespace IW4MAdmin.Application
|
|||||||
OnServerEvent += OnGameEvent;
|
OnServerEvent += OnGameEvent;
|
||||||
OnServerEvent += EventApi.OnGameEvent;
|
OnServerEvent += EventApi.OnGameEvent;
|
||||||
_authenticator = new TokenAuthentication();
|
_authenticator = new TokenAuthentication();
|
||||||
|
_metaService = new MetaService();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnGameEvent(object sender, GameEventArgs args)
|
private async void OnGameEvent(object sender, GameEventArgs args)
|
||||||
@ -129,7 +133,7 @@ namespace IW4MAdmin.Application
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
newEvent.FailReason = GameEvent.EventFailReason.Exception;
|
newEvent.FailReason = GameEvent.EventFailReason.Exception;
|
||||||
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"]} {newEvent.Owner}");
|
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"].FormatExt(newEvent.Owner));
|
||||||
Logger.WriteDebug(ex.GetExceptionInfo());
|
Logger.WriteDebug(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +158,7 @@ namespace IW4MAdmin.Application
|
|||||||
return Instance ?? (Instance = new ApplicationManager());
|
return Instance ?? (Instance = new ApplicationManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateServerStates()
|
public async Task UpdateServerStates(CancellationToken token)
|
||||||
{
|
{
|
||||||
// store the server hash code and task for it
|
// store the server hash code and task for it
|
||||||
var runningUpdateTasks = new Dictionary<long, Task>();
|
var runningUpdateTasks = new Dictionary<long, Task>();
|
||||||
@ -190,7 +194,11 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await server.ProcessUpdatesAsync(new CancellationToken());
|
await server.ProcessUpdatesAsync(token);
|
||||||
|
if (server.Throttled)
|
||||||
|
{
|
||||||
|
await Task.Delay((int)_throttleTimeout.TotalMilliseconds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -198,6 +206,11 @@ namespace IW4MAdmin.Application
|
|||||||
Logger.WriteWarning($"Failed to update status for {server}");
|
Logger.WriteWarning($"Failed to update status for {server}");
|
||||||
Logger.WriteDebug(e.GetExceptionInfo());
|
Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
server.IsInitialized = true;
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@ -206,17 +219,19 @@ namespace IW4MAdmin.Application
|
|||||||
ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
|
ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
|
||||||
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
||||||
#endif
|
#endif
|
||||||
await Task.Delay(ConfigHandler.Configuration().RConPollRate);
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(ConfigHandler.Configuration().RConPollRate, token);
|
||||||
|
}
|
||||||
|
// if a cancellation is received, we want to return immediately
|
||||||
|
catch { break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger the event processing loop to end
|
|
||||||
SetHasEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
Running = true;
|
Running = true;
|
||||||
|
ExternalIPAddress = await Utilities.GetExternalIP();
|
||||||
|
|
||||||
#region PLUGINS
|
#region PLUGINS
|
||||||
SharedLibraryCore.Plugins.PluginImporter.Load(this);
|
SharedLibraryCore.Plugins.PluginImporter.Load(this);
|
||||||
@ -246,10 +261,11 @@ namespace IW4MAdmin.Application
|
|||||||
ConfigHandler.Set((ApplicationConfiguration)new ApplicationConfiguration().Generate());
|
ConfigHandler.Set((ApplicationConfiguration)new ApplicationConfiguration().Generate());
|
||||||
var newConfig = ConfigHandler.Configuration();
|
var newConfig = ConfigHandler.Configuration();
|
||||||
|
|
||||||
newConfig.AutoMessagePeriod = defaultConfig.AutoMessagePeriod;
|
|
||||||
newConfig.AutoMessages = defaultConfig.AutoMessages;
|
newConfig.AutoMessages = defaultConfig.AutoMessages;
|
||||||
newConfig.GlobalRules = defaultConfig.GlobalRules;
|
newConfig.GlobalRules = defaultConfig.GlobalRules;
|
||||||
newConfig.Maps = defaultConfig.Maps;
|
newConfig.Maps = defaultConfig.Maps;
|
||||||
|
newConfig.DisallowedClientNames = defaultConfig.DisallowedClientNames;
|
||||||
|
newConfig.QuickMessages = defaultConfig.QuickMessages;
|
||||||
|
|
||||||
if (newConfig.Servers == null)
|
if (newConfig.Servers == null)
|
||||||
{
|
{
|
||||||
@ -277,7 +293,7 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (config != null)
|
else
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(config.Id))
|
if (string.IsNullOrEmpty(config.Id))
|
||||||
{
|
{
|
||||||
@ -313,7 +329,7 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (config.Servers.Count == 0)
|
if (config.Servers.Count == 0)
|
||||||
{
|
{
|
||||||
throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
|
throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
|
||||||
}
|
}
|
||||||
@ -376,7 +392,7 @@ namespace IW4MAdmin.Application
|
|||||||
Commands.Add(new CPing());
|
Commands.Add(new CPing());
|
||||||
Commands.Add(new CSetGravatar());
|
Commands.Add(new CSetGravatar());
|
||||||
Commands.Add(new CNextMap());
|
Commands.Add(new CNextMap());
|
||||||
Commands.Add(new GenerateTokenCommand());
|
Commands.Add(new RequestTokenCommand());
|
||||||
|
|
||||||
foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands)
|
foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands)
|
||||||
{
|
{
|
||||||
@ -384,11 +400,139 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region META
|
||||||
|
async Task<List<ProfileMeta>> getProfileMeta(int clientId, int offset, int count, DateTime? startAt)
|
||||||
|
{
|
||||||
|
var metaList = new List<ProfileMeta>();
|
||||||
|
|
||||||
|
// we don't want to return anything because it means we're trying to retrieve paged meta data
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
return metaList;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastMapMeta = await _metaService.GetPersistentMeta("LastMapPlayed", new EFClient() { ClientId = clientId });
|
||||||
|
|
||||||
|
if (lastMapMeta != null)
|
||||||
|
{
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = lastMapMeta.MetaId,
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_MAP"],
|
||||||
|
Value = lastMapMeta.Value,
|
||||||
|
Show = true,
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastServerMeta = await _metaService.GetPersistentMeta("LastServerPlayed", new EFClient() { ClientId = clientId });
|
||||||
|
|
||||||
|
if (lastServerMeta != null)
|
||||||
|
{
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = lastServerMeta.MetaId,
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_SERVER"],
|
||||||
|
Value = lastServerMeta.Value,
|
||||||
|
Show = true,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = await GetClientService().Get(clientId);
|
||||||
|
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = client.ClientId,
|
||||||
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]} {Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_PLAYER"]}",
|
||||||
|
Value = Math.Round(client.TotalConnectionTime / 3600.0, 1).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Show = true,
|
||||||
|
Column = 1,
|
||||||
|
Order = 0,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
});
|
||||||
|
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = client.ClientId,
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_FSEEN"],
|
||||||
|
Value = Utilities.GetTimePassed(client.FirstConnection, false),
|
||||||
|
Show = true,
|
||||||
|
Column = 1,
|
||||||
|
Order = 1,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
});
|
||||||
|
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = client.ClientId,
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_LSEEN"],
|
||||||
|
Value = Utilities.GetTimePassed(client.LastConnection, false),
|
||||||
|
Show = true,
|
||||||
|
Column = 1,
|
||||||
|
Order = 2,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
});
|
||||||
|
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = client.ClientId,
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_CONNECTIONS"],
|
||||||
|
Value = client.Connections.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Show = true,
|
||||||
|
Column = 1,
|
||||||
|
Order = 3,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
});
|
||||||
|
|
||||||
|
metaList.Add(new ProfileMeta()
|
||||||
|
{
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_MASKED"],
|
||||||
|
Value = client.Masked ? Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_TRUE"] : Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_FALSE"],
|
||||||
|
Sensitive = true,
|
||||||
|
Column = 1,
|
||||||
|
Order = 4,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
});
|
||||||
|
|
||||||
|
return metaList;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<List<ProfileMeta>> getPenaltyMeta(int clientId, int offset, int count, DateTime? startAt)
|
||||||
|
{
|
||||||
|
if (count <= 1)
|
||||||
|
{
|
||||||
|
return new List<ProfileMeta>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var penalties = await GetPenaltyService().GetClientPenaltyForMetaAsync(clientId, count, offset, startAt);
|
||||||
|
|
||||||
|
return penalties.Select(_penalty => new ProfileMeta()
|
||||||
|
{
|
||||||
|
Id = _penalty.Id,
|
||||||
|
Type = _penalty.PunisherId == clientId ? ProfileMeta.MetaType.Penalized : ProfileMeta.MetaType.ReceivedPenalty,
|
||||||
|
Value = _penalty,
|
||||||
|
When = _penalty.TimePunished,
|
||||||
|
Sensitive = _penalty.Sensitive
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
MetaService.AddRuntimeMeta(getProfileMeta);
|
||||||
|
MetaService.AddRuntimeMeta(getPenaltyMeta);
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region INIT
|
#region INIT
|
||||||
|
int failedServers = 0;
|
||||||
|
int successServers = 0;
|
||||||
|
Exception lastException = null;
|
||||||
|
|
||||||
async Task Init(ServerConfiguration Conf)
|
async Task Init(ServerConfiguration Conf)
|
||||||
{
|
{
|
||||||
// setup the event handler after the class is initialized
|
// setup the event handler after the class is initialized
|
||||||
|
|
||||||
Handler = new GameEventHandler(this);
|
Handler = new GameEventHandler(this);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ServerInstance = new IW4MServer(this, Conf);
|
var ServerInstance = new IW4MServer(this, Conf);
|
||||||
@ -399,7 +543,7 @@ namespace IW4MAdmin.Application
|
|||||||
_servers.Add(ServerInstance);
|
_servers.Add(ServerInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.WriteVerbose($"{Utilities.CurrentLocalization.LocalizationIndex["MANAGER_MONITORING_TEXT"]} {ServerInstance.Hostname}");
|
Logger.WriteVerbose(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_MONITORING_TEXT"].FormatExt(ServerInstance.Hostname));
|
||||||
// add the start event for this server
|
// add the start event for this server
|
||||||
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
@ -410,26 +554,37 @@ namespace IW4MAdmin.Application
|
|||||||
};
|
};
|
||||||
|
|
||||||
Handler.AddEvent(e);
|
Handler.AddEvent(e);
|
||||||
|
successServers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (ServerException e)
|
catch (ServerException e)
|
||||||
{
|
{
|
||||||
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"]} [{Conf.IPAddress}:{Conf.Port}]");
|
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_UNFIXABLE"].FormatExt($"[{Conf.IPAddress}:{Conf.Port}]"));
|
||||||
|
|
||||||
if (e.GetType() == typeof(DvarException))
|
if (e.GetType() == typeof(DvarException))
|
||||||
{
|
{
|
||||||
Logger.WriteDebug($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR"]} {(e as DvarException).Data["dvar_name"]} ({Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR_HELP"]})");
|
Logger.WriteDebug($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR"].FormatExt((e as DvarException).Data["dvar_name"])} ({Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_DVAR_HELP"]})");
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (e.GetType() == typeof(NetworkException))
|
else if (e.GetType() == typeof(NetworkException))
|
||||||
{
|
{
|
||||||
Logger.WriteDebug(e.Message);
|
Logger.WriteDebug(e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw the exception to the main method to stop before instantly exiting
|
failedServers++;
|
||||||
throw e;
|
lastException = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(config.Servers.Select(c => Init(c)).ToArray());
|
await Task.WhenAll(config.Servers.Select(c => Init(c)).ToArray());
|
||||||
|
|
||||||
|
if (successServers - failedServers <= 0)
|
||||||
|
{
|
||||||
|
if (!Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_START_WITH_ERRORS"]))
|
||||||
|
{
|
||||||
|
throw lastException;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,27 +649,34 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
await Task.Delay(30000);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(30000, heartbeatState.Token);
|
||||||
|
}
|
||||||
|
catch { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
var tokenSource = new CancellationTokenSource();
|
||||||
// this needs to be run seperately from the main thread
|
// this needs to be run seperately from the main thread
|
||||||
var _ = Task.Run(() => SendHeartbeat(new HeartbeatState()));
|
_ = Task.Run(() => SendHeartbeat(new HeartbeatState() { Token = tokenSource.Token }));
|
||||||
_ = Task.Run(() => UpdateServerStates());
|
_ = Task.Run(() => UpdateServerStates(tokenSource.Token));
|
||||||
|
|
||||||
while (Running)
|
while (Running)
|
||||||
{
|
{
|
||||||
OnQuit.Wait();
|
OnQuit.Wait();
|
||||||
|
tokenSource.Cancel();
|
||||||
OnQuit.Reset();
|
OnQuit.Reset();
|
||||||
}
|
}
|
||||||
_servers.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
Running = false;
|
Running = false;
|
||||||
|
OnQuit.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILogger GetLogger(long serverId)
|
public ILogger GetLogger(long serverId)
|
||||||
@ -589,12 +751,12 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public void SetHasEvent()
|
public void SetHasEvent()
|
||||||
{
|
{
|
||||||
OnQuit.Set();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<Assembly> GetPluginAssemblies()
|
public IList<Assembly> GetPluginAssemblies()
|
||||||
{
|
{
|
||||||
return SharedLibraryCore.Plugins.PluginImporter.PluginAssemblies;
|
return SharedLibraryCore.Plugins.PluginImporter.PluginAssemblies.Union(SharedLibraryCore.Plugins.PluginImporter.Assemblies).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPageList GetPageList()
|
public IPageList GetPageList()
|
||||||
|
@ -97,11 +97,19 @@ if "%CurrentConfiguration%" == "Release" (
|
|||||||
if exist "%SolutionDir%Publish\Windows\refs" move "%SolutionDir%Publish\Windows\refs" "%SolutionDir%Publish\Windows\Lib\refs"
|
if exist "%SolutionDir%Publish\Windows\refs" move "%SolutionDir%Publish\Windows\refs" "%SolutionDir%Publish\Windows\Lib\refs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if "%CurrentConfiguration%" == "Prerelease" (
|
||||||
|
echo PR-LOC
|
||||||
|
if not exist "%SolutionDir%Publish\WindowsPrerelease\Localization" md "%SolutionDir%Publish\WindowsPrerelease\Localization"
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%CurrentConfiguration%" == "Release" (
|
||||||
|
echo R-LOC
|
||||||
|
if not exist "%SolutionDir%Publish\Windows\Localization" md "%SolutionDir%Publish\Windows\Localization"
|
||||||
|
)
|
||||||
|
|
||||||
echo making start scripts
|
echo making start scripts
|
||||||
@(echo dotnet Lib/IW4MAdmin.dll && echo pause) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.cmd"
|
@(echo @echo off && echo @title IW4MAdmin && echo dotnet Lib\IW4MAdmin.dll && echo pause) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.cmd"
|
||||||
@(echo dotnet Lib/IW4MAdmin.dll && echo pause) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.cmd"
|
@(echo @echo off && echo @title IW4MAdmin && echo dotnet Lib\IW4MAdmin.dll && echo pause) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.cmd"
|
||||||
|
|
||||||
@(echo #!/bin/bash && echo dotnet Lib\IW4MAdmin.dll) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.sh"
|
@(echo #!/bin/bash && echo dotnet Lib/IW4MAdmin.dll) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.sh"
|
||||||
@(echo #!/bin/bash && echo dotnet Lib\IW4MAdmin.dll) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.sh"
|
@(echo #!/bin/bash && echo dotnet Lib/IW4MAdmin.dll) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.sh"
|
||||||
|
|
||||||
eCHO "%CurrentConfiguration%"
|
|
||||||
|
@ -16,7 +16,231 @@
|
|||||||
"Keep grenade launcher use to a minimum",
|
"Keep grenade launcher use to a minimum",
|
||||||
"Balance teams at ALL times"
|
"Balance teams at ALL times"
|
||||||
],
|
],
|
||||||
|
"DisallowedClientNames": ["Unknown Soldier", "VickNet", "UnknownSoldier", "CHEATER"],
|
||||||
|
"QuickMessages": [
|
||||||
|
{
|
||||||
|
"Game": "IW4",
|
||||||
|
"Messages": {
|
||||||
|
"QUICKMESSAGE_AREA_SECURE": "Area secure!",
|
||||||
|
"QUICKMESSAGE_ARE_YOU_CRAZY": "Are you crazy?",
|
||||||
|
"QUICKMESSAGE_ATTACK_LEFT_FLANK": "Attack left flank!",
|
||||||
|
"QUICKMESSAGE_ATTACK_RIGHT_FLANK": "Attack right flank!",
|
||||||
|
"QUICKMESSAGE_COME_ON": "Come on.",
|
||||||
|
"QUICKMESSAGE_ENEMIES_SPOTTED": "Multiple contacts!",
|
||||||
|
"QUICKMESSAGE_ENEMY_DOWN": "Enemy down!",
|
||||||
|
"QUICKMESSAGE_ENEMY_GRENADE": "Enemy grenade!",
|
||||||
|
"QUICKMESSAGE_ENEMY_SPOTTED": "Contact!",
|
||||||
|
"QUICKMESSAGE_FALL_BACK": "Fall back!",
|
||||||
|
"QUICKMESSAGE_FOLLOW_ME": "On me!",
|
||||||
|
"QUICKMESSAGE_GREAT_SHOT": "Nice shot!",
|
||||||
|
"QUICKMESSAGE_GRENADE": "Grenade!",
|
||||||
|
"QUICKMESSAGE_HOLD_THIS_POSITION": "Hold this position!",
|
||||||
|
"QUICKMESSAGE_HOLD_YOUR_FIRE": "Hold your fire!",
|
||||||
|
"QUICKMESSAGE_IM_IN_POSITION": "In position.",
|
||||||
|
"QUICKMESSAGE_IM_ON_MY_WAY": "Moving.",
|
||||||
|
"QUICKMESSAGE_MOVE_IN": "Move in!",
|
||||||
|
"QUICKMESSAGE_NEED_REINFORCEMENTS": "Need reinforcements!",
|
||||||
|
"QUICKMESSAGE_NO_SIR": "Negative.",
|
||||||
|
"QUICKMESSAGE_ON_MY_WAY": "On my way.",
|
||||||
|
"QUICKMESSAGE_REGROUP": "Regroup!",
|
||||||
|
"QUICKMESSAGE_SNIPER": "Sniper!",
|
||||||
|
"QUICKMESSAGE_SORRY": "Sorry.",
|
||||||
|
"QUICKMESSAGE_SQUAD_ATTACK_LEFT_FLANK": "Squad, attack left flank!",
|
||||||
|
"QUICKMESSAGE_SQUAD_ATTACK_RIGHT_FLANK": "Squad, attack right flank!",
|
||||||
|
"QUICKMESSAGE_SQUAD_HOLD_THIS_POSITION": "Squad, hold this position!",
|
||||||
|
"QUICKMESSAGE_SQUAD_REGROUP": "Squad, regroup!",
|
||||||
|
"QUICKMESSAGE_SQUAD_STICK_TOGETHER": "Squad, stick together!",
|
||||||
|
"QUICKMESSAGE_STICK_TOGETHER": "Stick together!",
|
||||||
|
"QUICKMESSAGE_SUPPRESSING_FIRE": "Base of fire!",
|
||||||
|
"QUICKMESSAGE_TOOK_LONG_ENOUGH": "Took long enough!",
|
||||||
|
"QUICKMESSAGE_TOOK_YOU_LONG_ENOUGH": "Took you long enough!",
|
||||||
|
"QUICKMESSAGE_WATCH_SIX": "Watch your six!",
|
||||||
|
"QUICKMESSAGE_YES_SIR": "Roger.",
|
||||||
|
"QUICKMESSAGE_YOURE_CRAZY": "You're crazy!",
|
||||||
|
"QUICKMESSAGE_YOURE_NUTS": "You're nuts!",
|
||||||
|
"QUICKMESSAGE_YOU_OUTTA_YOUR_MIND": "You outta your mind?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"Maps": [
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Game": "IW3",
|
||||||
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Alias": "Ambush",
|
||||||
|
"Name": "mp_convoy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Backlot",
|
||||||
|
"Name": "mp_backlot"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Bloc",
|
||||||
|
"Name": "mp_bloc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Bog",
|
||||||
|
"Name": "mp_bog"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Countdown",
|
||||||
|
"Name": "mp_countdown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Crash",
|
||||||
|
"Name": "mp_crash"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Crossfire",
|
||||||
|
"Name": "mp_crossfire"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "District",
|
||||||
|
"Name": "mp_citystreets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Downpour",
|
||||||
|
"Name": "mp_farm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Overgrown",
|
||||||
|
"Name": "mp_overgrown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Pipeline",
|
||||||
|
"Name": "mp_pipeline"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Shipment",
|
||||||
|
"Name": "mp_shipment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Showdown",
|
||||||
|
"Name": "mp_showdown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Strike",
|
||||||
|
"Name": "mp_strike"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Vacant",
|
||||||
|
"Name": "mp_vacant"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Wet Work",
|
||||||
|
"Name": "mp_cargoship"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Winter Crash",
|
||||||
|
"Name": "mp_crash_snow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Broadcast",
|
||||||
|
"Name": "mp_broadcast"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Creek",
|
||||||
|
"Name": "mp_creek"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Chinatown",
|
||||||
|
"Name": "mp_carentan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Killhouse",
|
||||||
|
"Name": "mp_killhouse"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Game": "T4",
|
||||||
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Alias": "Airfield",
|
||||||
|
"Name": "mp_airfield"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Asylum",
|
||||||
|
"Name": "mp_asylum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Castle",
|
||||||
|
"Name": "mp_castle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Cliffside",
|
||||||
|
"Name": "mp_shrine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Courtyard",
|
||||||
|
"Name": "mp_courtyard"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Dome",
|
||||||
|
"Name": "mp_dome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Downfall",
|
||||||
|
"Name": "mp_downfall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Hanger",
|
||||||
|
"Name": "mp_hangar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Makin",
|
||||||
|
"Name": "mp_makin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Outskirts",
|
||||||
|
"Name": "mp_outskirts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Roundhouse",
|
||||||
|
"Name": "mp_roundhouse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Upheaval",
|
||||||
|
"Name": "mp_suburban"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Knee Deep",
|
||||||
|
"Name": "mp_kneedeep"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Nightfire",
|
||||||
|
"Name": "mp_nachtfeuer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Station",
|
||||||
|
"Name": "mp_subway"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Banzai",
|
||||||
|
"Name": "mp_kwai"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Corrosion",
|
||||||
|
"Name": "mp_stalingrad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Sub Pens",
|
||||||
|
"Name": "mp_docks"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Battery",
|
||||||
|
"Name": "mp_drum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Breach",
|
||||||
|
"Name": "mp_bgate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Revolution",
|
||||||
|
"Name": "mp_vodka"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Game": "IW4",
|
"Game": "IW4",
|
||||||
"Maps": [
|
"Maps": [
|
||||||
@ -246,6 +470,260 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Game": "T5",
|
||||||
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Alias": "Array",
|
||||||
|
"Name": "mp_array"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Berlin Wall",
|
||||||
|
"Name": "mp_berlinwall2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Convoy",
|
||||||
|
"Name": "mp_gridlock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Cracked",
|
||||||
|
"Name": "mp_cracked"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Crisis",
|
||||||
|
"Name": "mp_crisis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Discovery",
|
||||||
|
"Name": "mp_discovery"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Drive-In",
|
||||||
|
"Name": "mp_drivein"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Firing Range",
|
||||||
|
"Name": "mp_firingrange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Grid",
|
||||||
|
"Name": "mp_duga"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Hangar 18",
|
||||||
|
"Name": "mp_area51"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Hanoi",
|
||||||
|
"Name": "mp_hanoi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Hazard",
|
||||||
|
"Name": "mp_golfcourse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Hotel",
|
||||||
|
"Name": "mp_hotel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Jungle",
|
||||||
|
"Name": "mp_havoc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Kowloon",
|
||||||
|
"Name": "mp_kowloon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Launch",
|
||||||
|
"Name": "mp_cosmodrome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Nuketown",
|
||||||
|
"Name": "mp_nuked"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Radiation",
|
||||||
|
"Name": "mp_radiation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Silo",
|
||||||
|
"Name": "mp_silo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Stadium",
|
||||||
|
"Name": "mp_stadium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Stockpile",
|
||||||
|
"Name": "mp_outskirts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Summit",
|
||||||
|
"Name": "mp_mountain"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Villa",
|
||||||
|
"Name": "mp_villa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "WMD",
|
||||||
|
"Name": "mp_russianbase"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Zoo",
|
||||||
|
"Name": "mp_zoo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Game": "IW5",
|
||||||
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Alias": "Seatown",
|
||||||
|
"Name": "mp_seatown"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Lockdown",
|
||||||
|
"Name": "mp_alpha"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Mission",
|
||||||
|
"Name": "mp_bravo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Carbon",
|
||||||
|
"Name": "mp_carbon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Dome",
|
||||||
|
"Name": "mp_dome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Arkaden",
|
||||||
|
"Name": "mp_plaza2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Downturn",
|
||||||
|
"Name": "mp_exchange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Bootleg",
|
||||||
|
"Name": "mp_bootleg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Hardhat",
|
||||||
|
"Name": "mp_hardhat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Interchange",
|
||||||
|
"Name": "mp_interchange"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Fallen",
|
||||||
|
"Name": "mp_lambeth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Outpost",
|
||||||
|
"Name": "mp_radar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Bakaara",
|
||||||
|
"Name": "mp_mogadishu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Resistance",
|
||||||
|
"Name": "mp_paris"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Underground",
|
||||||
|
"Name": "mp_underground"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Village",
|
||||||
|
"Name": "mp_village"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Aground",
|
||||||
|
"Name": "mp_aground_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Boardwalk",
|
||||||
|
"Name": "mp_boardwalk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "U-turn",
|
||||||
|
"Name": "mp_burn_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Foundation",
|
||||||
|
"Name": "mp_cement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Erosion",
|
||||||
|
"Name": "mp_courtyard_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Intersection",
|
||||||
|
"Name": "mp_crosswalk_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Getaway",
|
||||||
|
"Name": "mp_hillside_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Piazza",
|
||||||
|
"Name": "mp_italy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Sanctuary",
|
||||||
|
"Name": "mp_meteora"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Gulch",
|
||||||
|
"Name": "mp_moab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Black Box",
|
||||||
|
"Name": "mp_morningwood"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Parish",
|
||||||
|
"Name": "mp_nola"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Overwatch",
|
||||||
|
"Name": "mp_overwatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Liberation",
|
||||||
|
"Name": "mp_park"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Oasis",
|
||||||
|
"Name": "mp_qadeem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Lookout",
|
||||||
|
"Name": "mp_restrepo_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Off Shore",
|
||||||
|
"Name": "mp_roughneck"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Decommission",
|
||||||
|
"Name": "mp_shipbreaker"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Vortex",
|
||||||
|
"Name": "mp_six_ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Terminal",
|
||||||
|
"Name": "mp_terminal_cls"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Game": "T6",
|
"Game": "T6",
|
||||||
"Maps": [
|
"Maps": [
|
||||||
@ -402,95 +880,6 @@
|
|||||||
"Name": "zm_transit"
|
"Name": "zm_transit"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"Game": "IW3",
|
|
||||||
"Maps": [
|
|
||||||
{
|
|
||||||
"Alias": "Ambush",
|
|
||||||
"Name": "mp_convoy"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Backlot",
|
|
||||||
"Name": "mp_backlot"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Bloc",
|
|
||||||
"Name": "mp_bloc"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Bog",
|
|
||||||
"Name": "mp_bog"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Countdown",
|
|
||||||
"Name": "mp_countdown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Crash",
|
|
||||||
"Name": "mp_crash"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Crossfire",
|
|
||||||
"Name": "mp_crossfire"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "District",
|
|
||||||
"Name": "mp_citystreets"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Downpour",
|
|
||||||
"Name": "mp_farm"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Overgrown",
|
|
||||||
"Name": "mp_overgrown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Pipeline",
|
|
||||||
"Name": "mp_pipeline"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Shipment",
|
|
||||||
"Name": "mp_shipment"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Showdown",
|
|
||||||
"Name": "mp_showdown"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Strike",
|
|
||||||
"Name": "mp_strike"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Vacant",
|
|
||||||
"Name": "mp_vacant"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Wet Work",
|
|
||||||
"Name": "mp_cargoship"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Winter Crash",
|
|
||||||
"Name": "mp_crash_snow"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Broadcast",
|
|
||||||
"Name": "mp_broadcast"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Creek",
|
|
||||||
"Name": "mp_creek"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Chinatown",
|
|
||||||
"Name": "mp_carentan"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Killhouse",
|
|
||||||
"Name": "mp_killhouse"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -17,26 +17,26 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
GameDirectory = "main",
|
GameDirectory = "main",
|
||||||
};
|
};
|
||||||
|
|
||||||
Configuration.Say.Pattern = @"^(say|sayteam);(-?[A-Fa-f0-9_]{8,32});([0-9]+);(.+);(.*)$";
|
Configuration.Say.Pattern = @"^(say|sayteam);(-?[A-Fa-f0-9_]{1,32});([0-9]+);(.+);(.*)$";
|
||||||
Configuration.Say.AddMapping(ParserRegex.GroupType.EventType, 1);
|
Configuration.Say.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||||
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
||||||
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||||
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
Configuration.Say.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||||
Configuration.Say.AddMapping(ParserRegex.GroupType.Message, 5);
|
Configuration.Say.AddMapping(ParserRegex.GroupType.Message, 5);
|
||||||
|
|
||||||
Configuration.Quit.Pattern = @"^(Q);(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+);([0-9]+);(.*)$";
|
Configuration.Quit.Pattern = @"^(Q);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);([0-9]+);(.*)$";
|
||||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.EventType, 1);
|
Configuration.Quit.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
||||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||||
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
Configuration.Quit.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||||
|
|
||||||
Configuration.Join.Pattern = @"^(J);(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+);([0-9]+);(.*)$";
|
Configuration.Join.Pattern = @"^(J);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);([0-9]+);(.*)$";
|
||||||
Configuration.Join.AddMapping(ParserRegex.GroupType.EventType, 1);
|
Configuration.Join.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
|
||||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
|
||||||
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4);
|
||||||
|
|
||||||
Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world);(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world);(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1);
|
Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
||||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
Configuration.Damage.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
||||||
@ -51,7 +51,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
Configuration.Damage.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
||||||
Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
Configuration.Damage.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
||||||
|
|
||||||
Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});(-?[A-Fa-f0-9_]{8,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world);(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
Configuration.Kill.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+);(-?[0-9]+);(axis|allies|world);(.{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+)?;-?([0-9]+);(axis|allies|world);(.{1,24})?;((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.EventType, 1);
|
||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetNetworkId, 2);
|
||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.TargetClientNumber, 3);
|
||||||
@ -73,6 +73,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
public Game GameName { get; set; } = Game.COD;
|
public Game GameName { get; set; } = Game.COD;
|
||||||
|
|
||||||
|
public string URLProtocolFormat { get; set; } = "CoD://{{ip}}:{{port}}";
|
||||||
|
|
||||||
public virtual GameEvent GetEvent(Server server, string logLine)
|
public virtual GameEvent GetEvent(Server server, string logLine)
|
||||||
{
|
{
|
||||||
logLine = Regex.Replace(logLine, @"([0-9]+:[0-9]+ |^[0-9]+ )", "").Trim();
|
logLine = Regex.Replace(logLine, @"([0-9]+:[0-9]+ |^[0-9]+ )", "").Trim();
|
||||||
@ -87,7 +89,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.JoinTeam,
|
Type = GameEvent.EventType.JoinTeam,
|
||||||
Data = eventType,
|
Data = logLine,
|
||||||
Origin = origin,
|
Origin = origin,
|
||||||
Owner = server
|
Owner = server
|
||||||
};
|
};
|
||||||
@ -139,11 +141,16 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
var origin = server.GetClientsAsList()
|
string originId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].Value.ToString();
|
||||||
.First(c => c.NetworkId == match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertLong());
|
string targetId = match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].Value.ToString();
|
||||||
var target = server.GetClientsAsList()
|
|
||||||
.First(c => c.NetworkId == match.Groups[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertLong());
|
|
||||||
|
|
||||||
|
var origin = !string.IsNullOrEmpty(originId) ? server.GetClientsAsList()
|
||||||
|
.First(c => c.NetworkId == originId.ConvertLong()) :
|
||||||
|
Utilities.IW4MAdminClient(server);
|
||||||
|
|
||||||
|
var target = !string.IsNullOrEmpty(targetId) ? server.GetClientsAsList()
|
||||||
|
.First(c => c.NetworkId == targetId.ConvertLong()) :
|
||||||
|
Utilities.IW4MAdminClient(server);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -159,8 +166,14 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "ScriptKill")
|
if (eventType == "ScriptKill")
|
||||||
{
|
{
|
||||||
var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
|
long originId = lineSplit[1].ConvertLong();
|
||||||
var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong());
|
long targetId = lineSplit[2].ConvertLong();
|
||||||
|
|
||||||
|
var origin = originId == long.MinValue ? Utilities.IW4MAdminClient(server) :
|
||||||
|
server.GetClientsAsList().First(c => c.NetworkId == originId);
|
||||||
|
var target = targetId == long.MinValue ? Utilities.IW4MAdminClient(server) :
|
||||||
|
server.GetClientsAsList().FirstOrDefault(c => c.NetworkId == targetId) ?? Utilities.IW4MAdminClient(server);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.ScriptKill,
|
Type = GameEvent.EventType.ScriptKill,
|
||||||
@ -173,8 +186,13 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "ScriptDamage")
|
if (eventType == "ScriptDamage")
|
||||||
{
|
{
|
||||||
var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
|
long originId = lineSplit[1].ConvertLong();
|
||||||
var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong());
|
long targetId = lineSplit[2].ConvertLong();
|
||||||
|
|
||||||
|
var origin = originId == long.MinValue ? Utilities.IW4MAdminClient(server) :
|
||||||
|
server.GetClientsAsList().First(c => c.NetworkId == originId);
|
||||||
|
var target = targetId == long.MinValue ? Utilities.IW4MAdminClient(server) :
|
||||||
|
server.GetClientsAsList().FirstOrDefault(c => c.NetworkId == targetId) ?? Utilities.IW4MAdminClient(server);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -195,15 +213,21 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (regexMatch.Success)
|
if (regexMatch.Success)
|
||||||
{
|
{
|
||||||
var origin = server.GetClientsAsList()
|
string originId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
||||||
.First(c => c.NetworkId == regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertLong());
|
string targetId = regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString();
|
||||||
var target = server.GetClientsAsList()
|
|
||||||
.First(c => c.NetworkId == regexMatch.Groups[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertLong());
|
var origin = !string.IsNullOrEmpty(originId) ? server.GetClientsAsList()
|
||||||
|
.First(c => c.NetworkId == originId.ConvertLong()) :
|
||||||
|
Utilities.IW4MAdminClient(server);
|
||||||
|
|
||||||
|
var target = !string.IsNullOrEmpty(targetId) ? server.GetClientsAsList()
|
||||||
|
.First(c => c.NetworkId == targetId.ConvertLong()) :
|
||||||
|
Utilities.IW4MAdminClient(server);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Damage,
|
Type = GameEvent.EventType.Damage,
|
||||||
Data = eventType,
|
Data = logLine,
|
||||||
Origin = origin,
|
Origin = origin,
|
||||||
Target = target,
|
Target = target,
|
||||||
Owner = server
|
Owner = server
|
||||||
@ -229,7 +253,6 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
Active = false,
|
|
||||||
Name = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().StripColors(),
|
Name = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().StripColors(),
|
||||||
},
|
},
|
||||||
NetworkId = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertLong(),
|
NetworkId = regexMatch.Groups[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertLong(),
|
||||||
@ -256,7 +279,6 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
Active = false,
|
|
||||||
Name = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().StripColors()
|
Name = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().StripColors()
|
||||||
},
|
},
|
||||||
NetworkId = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertLong(),
|
NetworkId = regexMatch.Groups[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertLong(),
|
||||||
|
@ -30,7 +30,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
{
|
{
|
||||||
while (!Server.Manager.ShutdownRequested())
|
while (!Server.Manager.ShutdownRequested())
|
||||||
{
|
{
|
||||||
if ((Server.Manager as ApplicationManager).IsInitialized)
|
if (Server.IsInitialized)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -34,9 +34,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
// todo: max async
|
// todo: max async
|
||||||
// take the old start position and go back the number of new characters
|
// take the old start position and go back the number of new characters
|
||||||
rd.BaseStream.Seek(-fileSizeDiff, SeekOrigin.End);
|
rd.BaseStream.Seek(-fileSizeDiff, SeekOrigin.End);
|
||||||
// the difference should be in the range of a int :P
|
|
||||||
string newLine;
|
string newLine;
|
||||||
while (!String.IsNullOrEmpty(newLine = rd.ReadLine()))
|
while (!string.IsNullOrEmpty(newLine = await rd.ReadLineAsync()))
|
||||||
{
|
{
|
||||||
logLines.Add(newLine);
|
logLines.Add(newLine);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using SharedLibraryCore.Exceptions;
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Localization;
|
using SharedLibraryCore.Localization;
|
||||||
using SharedLibraryCore.Objects;
|
using SharedLibraryCore.Objects;
|
||||||
|
using SharedLibraryCore.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -17,6 +18,7 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
|
||||||
namespace IW4MAdmin
|
namespace IW4MAdmin
|
||||||
{
|
{
|
||||||
@ -25,6 +27,7 @@ namespace IW4MAdmin
|
|||||||
private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex;
|
private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
private GameLogEventDetection LogEvent;
|
private GameLogEventDetection LogEvent;
|
||||||
private DateTime SessionStart;
|
private DateTime SessionStart;
|
||||||
|
|
||||||
public int Id { get; private set; }
|
public int Id { get; private set; }
|
||||||
|
|
||||||
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg)
|
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg)
|
||||||
@ -34,7 +37,6 @@ namespace IW4MAdmin
|
|||||||
override public async Task OnClientConnected(EFClient clientFromLog)
|
override public async Task OnClientConnected(EFClient clientFromLog)
|
||||||
{
|
{
|
||||||
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
|
Logger.WriteDebug($"Client slot #{clientFromLog.ClientNumber} now reserved");
|
||||||
Clients[clientFromLog.ClientNumber] = new EFClient();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -44,19 +46,16 @@ namespace IW4MAdmin
|
|||||||
if (client == null)
|
if (client == null)
|
||||||
{
|
{
|
||||||
Logger.WriteDebug($"Client {clientFromLog} first time connecting");
|
Logger.WriteDebug($"Client {clientFromLog} first time connecting");
|
||||||
|
clientFromLog.CurrentServer = this;
|
||||||
client = await Manager.GetClientService().Create(clientFromLog);
|
client = await Manager.GetClientService().Create(clientFromLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
// client has connected in the past
|
/// this is only a temporary version until the IPAddress is transmitted
|
||||||
else
|
client.CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
// this is only a temporary version until the IPAddress is transmitted
|
Name = clientFromLog.Name,
|
||||||
client.CurrentAlias = new EFAlias
|
IPAddress = clientFromLog.IPAddress
|
||||||
{
|
};
|
||||||
Name = clientFromLog.Name,
|
|
||||||
IPAddress = clientFromLog.IPAddress
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.WriteInfo($"Client {client} connected...");
|
Logger.WriteInfo($"Client {client} connected...");
|
||||||
|
|
||||||
@ -68,8 +67,6 @@ namespace IW4MAdmin
|
|||||||
client.CurrentServer = this;
|
client.CurrentServer = this;
|
||||||
|
|
||||||
Clients[client.ClientNumber] = client;
|
Clients[client.ClientNumber] = client;
|
||||||
|
|
||||||
client.State = EFClient.ClientState.Connected;
|
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Logger.WriteDebug($"End PreConnect for {client}");
|
Logger.WriteDebug($"End PreConnect for {client}");
|
||||||
#endif
|
#endif
|
||||||
@ -81,11 +78,8 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
await client.OnJoin(client.IPAddress);
|
||||||
if (client.IPAddress != null)
|
client.State = ClientState.Connected;
|
||||||
{
|
|
||||||
await client.OnJoin(client.IPAddress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -97,12 +91,14 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
override public async Task OnClientDisconnected(EFClient client)
|
override public async Task OnClientDisconnected(EFClient client)
|
||||||
{
|
{
|
||||||
Logger.WriteInfo($"Client {client} [{client.State.ToString().ToLower()}] disconnecting...");
|
|
||||||
await client.OnDisconnect();
|
|
||||||
Clients[client.ClientNumber] = null;
|
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Logger.WriteDebug($"End PreDisconnect for {client}");
|
if (client.ClientNumber >= 0)
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
Logger.WriteInfo($"Client {client} [{client.State.ToString().ToLower()}] disconnecting...");
|
||||||
|
Clients[client.ClientNumber] = null;
|
||||||
|
await client.OnDisconnect();
|
||||||
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
Origin = client,
|
Origin = client,
|
||||||
@ -111,6 +107,9 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
#if DEBUG == true
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task ExecuteEvent(GameEvent E)
|
public override async Task ExecuteEvent(GameEvent E)
|
||||||
@ -176,9 +175,33 @@ namespace IW4MAdmin
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
override protected async Task<bool> ProcessEvent(GameEvent E)
|
override protected async Task<bool> ProcessEvent(GameEvent E)
|
||||||
{
|
{
|
||||||
|
if (E.Type == GameEvent.EventType.ConnectionLost)
|
||||||
|
{
|
||||||
|
var exception = E.Extra as Exception;
|
||||||
|
Logger.WriteError(exception.Message);
|
||||||
|
if (exception.Data["internal_exception"] != null)
|
||||||
|
{
|
||||||
|
Logger.WriteDebug($"Internal Exception: {exception.Data["internal_exception"]}");
|
||||||
|
}
|
||||||
|
Logger.WriteInfo("Connection lost to server, so we are throttling the poll rate");
|
||||||
|
Throttled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (E.Type == GameEvent.EventType.ConnectionRestored)
|
||||||
|
{
|
||||||
|
if (Throttled)
|
||||||
|
{
|
||||||
|
Logger.WriteVerbose(loc["MANAGER_CONNECTION_REST"].FormatExt($"[{IP}:{Port}]"));
|
||||||
|
}
|
||||||
|
Logger.WriteInfo("Connection restored to server, so we are no longer throttling the poll rate");
|
||||||
|
Throttled = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.ChangePermission)
|
if (E.Type == GameEvent.EventType.ChangePermission)
|
||||||
{
|
{
|
||||||
if (!E.Target.IsPrivileged())
|
var newPermission = (Permission)E.Extra;
|
||||||
|
|
||||||
|
if (newPermission < Permission.Moderator)
|
||||||
{
|
{
|
||||||
// remove banned or demoted privileged user
|
// remove banned or demoted privileged user
|
||||||
Manager.GetPrivilegedClients().Remove(E.Target.ClientId);
|
Manager.GetPrivilegedClients().Remove(E.Target.ClientId);
|
||||||
@ -186,17 +209,46 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
|
if (Manager.GetPrivilegedClients().ContainsKey(E.Target.ClientId))
|
||||||
|
{
|
||||||
|
Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Manager.GetPrivilegedClients().Add(E.Target.ClientId, E.Target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.WriteInfo($"{E.Origin} is setting {E.Target} to permission level {newPermission}");
|
||||||
|
await Manager.GetClientService().UpdateLevel(newPermission, E.Target, E.Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.PreConnect)
|
else if (E.Type == GameEvent.EventType.PreConnect)
|
||||||
{
|
{
|
||||||
|
// we don't want to track bots in the database at all if ignore bots is requested
|
||||||
|
if (E.Origin.IsBot && Manager.GetApplicationSettings().Configuration().IgnoreBots)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existingClient = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin));
|
||||||
|
|
||||||
|
// they're already connected
|
||||||
|
if (existingClient != null)
|
||||||
|
{
|
||||||
|
Logger.WriteWarning($"detected preconnect for {E.Origin}, but they are already connected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONNECT:
|
||||||
if (Clients[E.Origin.ClientNumber] == null)
|
if (Clients[E.Origin.ClientNumber] == null)
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Logger.WriteDebug($"Begin PreConnect for {E.Origin}");
|
Logger.WriteDebug($"Begin PreConnect for {E.Origin}");
|
||||||
#endif
|
#endif
|
||||||
|
// we can go ahead and put them in so that they don't get re added
|
||||||
|
Clients[E.Origin.ClientNumber] = E.Origin;
|
||||||
await OnClientConnected(E.Origin);
|
await OnClientConnected(E.Origin);
|
||||||
|
|
||||||
ChatHistory.Add(new ChatInfo()
|
ChatHistory.Add(new ChatInfo()
|
||||||
@ -212,9 +264,12 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for some reason there's still a client in the spot
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
Logger.WriteWarning($"{E.Origin} is connecteding but {Clients[E.Origin.ClientNumber]} is currently in that client slot");
|
||||||
|
await OnClientDisconnected(Clients[E.Origin.ClientNumber]);
|
||||||
|
goto CONNECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,17 +288,29 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
var addedPenalty = await Manager.GetPenaltyService().Create(newPenalty);
|
var addedPenalty = await Manager.GetPenaltyService().Create(newPenalty);
|
||||||
await Manager.GetClientService().Update(E.Target);
|
E.Target.SetLevel(Permission.Flagged, E.Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.Unflag)
|
else if (E.Type == GameEvent.EventType.Unflag)
|
||||||
{
|
{
|
||||||
await Manager.GetClientService().Update(E.Target);
|
var unflagPenalty = new Penalty()
|
||||||
|
{
|
||||||
|
Type = Penalty.PenaltyType.Unflag,
|
||||||
|
Expires = DateTime.UtcNow,
|
||||||
|
Offender = E.Target,
|
||||||
|
Offense = E.Data,
|
||||||
|
Punisher = E.Origin,
|
||||||
|
When = DateTime.UtcNow,
|
||||||
|
Link = E.Target.AliasLink
|
||||||
|
};
|
||||||
|
|
||||||
|
await Manager.GetPenaltyService().Create(unflagPenalty);
|
||||||
|
E.Target.SetLevel(Permission.User, E.Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.Report)
|
else if (E.Type == GameEvent.EventType.Report)
|
||||||
{
|
{
|
||||||
this.Reports.Add(new Report()
|
Reports.Add(new Report()
|
||||||
{
|
{
|
||||||
Origin = E.Origin,
|
Origin = E.Origin,
|
||||||
Target = E.Target,
|
Target = E.Target,
|
||||||
@ -277,37 +344,21 @@ namespace IW4MAdmin
|
|||||||
await Warn(E.Data, E.Target, E.Origin);
|
await Warn(E.Data, E.Target, E.Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.Quit)
|
else if (E.Type == GameEvent.EventType.Disconnect)
|
||||||
{
|
{
|
||||||
var origin = GetClientsAsList().FirstOrDefault(_client => _client.NetworkId.Equals(E.Origin));
|
ChatHistory.Add(new ChatInfo()
|
||||||
|
|
||||||
if (origin != null)
|
|
||||||
{
|
{
|
||||||
var e = new GameEvent()
|
Name = E.Origin.Name,
|
||||||
{
|
Message = "DISCONNECTED",
|
||||||
Type = GameEvent.EventType.Disconnect,
|
Time = DateTime.UtcNow
|
||||||
Origin = origin,
|
});
|
||||||
Owner = this
|
|
||||||
};
|
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
await new MetaService().AddPersistentMeta("LastMapPlayed", CurrentMap.Alias, E.Origin);
|
||||||
}
|
await new MetaService().AddPersistentMeta("LastServerPlayed", E.Owner.Hostname, E.Origin);
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.PreDisconnect)
|
else if (E.Type == GameEvent.EventType.PreDisconnect)
|
||||||
{
|
{
|
||||||
if ((DateTime.UtcNow - SessionStart).TotalSeconds < 30)
|
|
||||||
{
|
|
||||||
Logger.WriteInfo($"Cancelling pre disconnect for {E.Origin} as it occured too close to map end");
|
|
||||||
E.FailReason = GameEvent.EventFailReason.Invalid;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// predisconnect comes from minimal rcon polled players and minimal log players
|
// predisconnect comes from minimal rcon polled players and minimal log players
|
||||||
// so we need to disconnect the "full" version of the client
|
// so we need to disconnect the "full" version of the client
|
||||||
var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin));
|
var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(E.Origin));
|
||||||
@ -317,18 +368,16 @@ namespace IW4MAdmin
|
|||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Logger.WriteDebug($"Begin PreDisconnect for {client}");
|
Logger.WriteDebug($"Begin PreDisconnect for {client}");
|
||||||
#endif
|
#endif
|
||||||
ChatHistory.Add(new ChatInfo()
|
|
||||||
{
|
|
||||||
Name = client.Name,
|
|
||||||
Message = "DISCONNECTED",
|
|
||||||
Time = DateTime.UtcNow
|
|
||||||
});
|
|
||||||
|
|
||||||
await OnClientDisconnected(client);
|
await OnClientDisconnected(client);
|
||||||
|
#if DEBUG == true
|
||||||
|
Logger.WriteDebug($"End PreDisconnect for {client}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else if (client?.State != ClientState.Disconnecting)
|
||||||
{
|
{
|
||||||
|
Logger.WriteWarning($"Client {E.Origin} detected as disconnecting, but could not find them in the player list");
|
||||||
|
Logger.WriteDebug($"Expected {E.Origin} but found {GetClientsAsList().FirstOrDefault(_client => _client.ClientNumber == E.Origin.ClientNumber)}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,18 +394,27 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
E.Data = E.Data.StripColors();
|
E.Data = E.Data.StripColors();
|
||||||
|
|
||||||
if (E.Data.Length > 0)
|
if (E.Data?.Length > 0)
|
||||||
{
|
{
|
||||||
// this may be a fix for a hard to reproduce null exception error
|
string message = E.Data;
|
||||||
lock (ChatHistory)
|
if (E.Data.IsQuickMessage())
|
||||||
{
|
{
|
||||||
ChatHistory.Add(new ChatInfo()
|
try
|
||||||
{
|
{
|
||||||
Name = E.Origin.Name,
|
message = Manager.GetApplicationSettings().Configuration()
|
||||||
Message = E.Data ?? "NULL",
|
.QuickMessages
|
||||||
Time = DateTime.UtcNow
|
.First(_qm => _qm.Game == GameName)
|
||||||
});
|
.Messages[E.Data.Substring(1)];
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatHistory.Add(new ChatInfo()
|
||||||
|
{
|
||||||
|
Name = E.Origin.Name,
|
||||||
|
Message = message,
|
||||||
|
Time = DateTime.UtcNow
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +447,7 @@ namespace IW4MAdmin
|
|||||||
var dict = (Dictionary<string, string>)E.Extra;
|
var dict = (Dictionary<string, string>)E.Extra;
|
||||||
Gametype = dict["g_gametype"].StripColors();
|
Gametype = dict["g_gametype"].StripColors();
|
||||||
Hostname = dict["sv_hostname"].StripColors();
|
Hostname = dict["sv_hostname"].StripColors();
|
||||||
MaxClients = Int32.Parse(dict["sv_maxclients"]);
|
MaxClients = int.Parse(dict["sv_maxclients"]);
|
||||||
|
|
||||||
string mapname = dict["mapname"].StripColors();
|
string mapname = dict["mapname"].StripColors();
|
||||||
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map()
|
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map()
|
||||||
@ -440,9 +498,9 @@ namespace IW4MAdmin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task OnClientUpdate(EFClient origin)
|
private async Task OnClientUpdate(EFClient origin)
|
||||||
{
|
{
|
||||||
var client = Clients[origin.ClientNumber];
|
var client = GetClientsAsList().FirstOrDefault(_client => _client.Equals(origin));
|
||||||
|
|
||||||
if (client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
@ -450,13 +508,22 @@ namespace IW4MAdmin
|
|||||||
client.Score = origin.Score;
|
client.Score = origin.Score;
|
||||||
|
|
||||||
// update their IP if it hasn't been set yet
|
// update their IP if it hasn't been set yet
|
||||||
if (client.IPAddress == null && !client.IsBot)
|
if (client.IPAddress == null &&
|
||||||
|
!client.IsBot &&
|
||||||
|
client.State == ClientState.Connected)
|
||||||
{
|
{
|
||||||
return client.OnJoin(origin.IPAddress);
|
try
|
||||||
|
{
|
||||||
|
await client.OnJoin(origin.IPAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
origin.CurrentServer.Logger.WriteWarning($"Could not execute on join for {origin}");
|
||||||
|
origin.CurrentServer.Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -472,6 +539,7 @@ namespace IW4MAdmin
|
|||||||
#endif
|
#endif
|
||||||
var currentClients = GetClientsAsList();
|
var currentClients = GetClientsAsList();
|
||||||
var polledClients = (await this.GetStatusAsync()).AsEnumerable();
|
var polledClients = (await this.GetStatusAsync()).AsEnumerable();
|
||||||
|
|
||||||
if (Manager.GetApplicationSettings().Configuration().IgnoreBots)
|
if (Manager.GetApplicationSettings().Configuration().IgnoreBots)
|
||||||
{
|
{
|
||||||
polledClients = polledClients.Where(c => !c.IsBot);
|
polledClients = polledClients.Where(c => !c.IsBot);
|
||||||
@ -479,8 +547,6 @@ namespace IW4MAdmin
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms");
|
Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms");
|
||||||
#endif
|
#endif
|
||||||
Throttled = false;
|
|
||||||
|
|
||||||
var disconnectingClients = currentClients.Except(polledClients);
|
var disconnectingClients = currentClients.Except(polledClients);
|
||||||
var connectingClients = polledClients.Except(currentClients);
|
var connectingClients = polledClients.Except(currentClients);
|
||||||
var updatedClients = polledClients.Except(connectingClients).Except(disconnectingClients);
|
var updatedClients = polledClients.Except(connectingClients).Except(disconnectingClients);
|
||||||
@ -533,7 +599,7 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
foreach (var disconnectingClient in polledClients[1])
|
foreach (var disconnectingClient in polledClients[1])
|
||||||
{
|
{
|
||||||
if (disconnectingClient.State == EFClient.ClientState.Disconnecting)
|
if (disconnectingClient.State == ClientState.Disconnecting)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -557,6 +623,12 @@ namespace IW4MAdmin
|
|||||||
// this are our new connecting clients
|
// this are our new connecting clients
|
||||||
foreach (var client in polledClients[0])
|
foreach (var client in polledClients[0])
|
||||||
{
|
{
|
||||||
|
// note: this prevents players in ZMBI state from being registered with no name
|
||||||
|
if (string.IsNullOrEmpty(client.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.PreConnect,
|
Type = GameEvent.EventType.PreConnect,
|
||||||
@ -590,8 +662,15 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
{
|
{
|
||||||
Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}");
|
var _event = new GameEvent()
|
||||||
Throttled = false;
|
{
|
||||||
|
Type = GameEvent.EventType.ConnectionRestored,
|
||||||
|
Owner = this,
|
||||||
|
Origin = Utilities.IW4MAdminClient(this),
|
||||||
|
Target = Utilities.IW4MAdminClient(this)
|
||||||
|
};
|
||||||
|
|
||||||
|
Manager.GetEventHandler().AddEvent(_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionErrors = 0;
|
ConnectionErrors = 0;
|
||||||
@ -603,9 +682,17 @@ namespace IW4MAdmin
|
|||||||
ConnectionErrors++;
|
ConnectionErrors++;
|
||||||
if (ConnectionErrors == 3)
|
if (ConnectionErrors == 3)
|
||||||
{
|
{
|
||||||
Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}");
|
var _event = new GameEvent()
|
||||||
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
|
{
|
||||||
Throttled = true;
|
Type = GameEvent.EventType.ConnectionLost,
|
||||||
|
Owner = this,
|
||||||
|
Origin = Utilities.IW4MAdminClient(this),
|
||||||
|
Target = Utilities.IW4MAdminClient(this),
|
||||||
|
Extra = e,
|
||||||
|
Data = ConnectionErrors.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
Manager.GetEventHandler().AddEvent(_event);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -630,7 +717,7 @@ namespace IW4MAdmin
|
|||||||
&& BroadcastMessages.Count > 0
|
&& BroadcastMessages.Count > 0
|
||||||
&& ClientNum > 0)
|
&& ClientNum > 0)
|
||||||
{
|
{
|
||||||
string[] messages = this.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage]).Split(Environment.NewLine);
|
string[] messages = (await this.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage])).Split(Environment.NewLine);
|
||||||
|
|
||||||
foreach (string message in messages)
|
foreach (string message in messages)
|
||||||
{
|
{
|
||||||
@ -647,9 +734,9 @@ namespace IW4MAdmin
|
|||||||
// this one is ok
|
// this one is ok
|
||||||
catch (ServerException e)
|
catch (ServerException e)
|
||||||
{
|
{
|
||||||
if (e is NetworkException)
|
if (e is NetworkException && !Throttled)
|
||||||
{
|
{
|
||||||
Logger.WriteError($"{loc["SERVER_ERROR_COMMUNICATION"]} {IP}:{Port}");
|
Logger.WriteError(loc["SERVER_ERROR_COMMUNICATION"].FormatExt($"{IP}:{Port}"));
|
||||||
Logger.WriteDebug(e.GetExceptionInfo());
|
Logger.WriteDebug(e.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,7 +745,7 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
Logger.WriteError($"{loc["SERVER_ERROR_EXCEPTION"]} {IP}:{Port}");
|
Logger.WriteError(loc["SERVER_ERROR_EXCEPTION"].FormatExt($"[{IP}:{Port}]"));
|
||||||
Logger.WriteDebug(E.GetExceptionInfo());
|
Logger.WriteDebug(E.GetExceptionInfo());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -751,7 +838,7 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomCallback = await ScriptLoaded();
|
CustomCallback = await ScriptLoaded();
|
||||||
|
|
||||||
// they've manually specified the log path
|
// they've manually specified the log path
|
||||||
if (!string.IsNullOrEmpty(ServerConfig.ManualLogPath))
|
if (!string.IsNullOrEmpty(ServerConfig.ManualLogPath))
|
||||||
{
|
{
|
||||||
@ -774,8 +861,8 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
if (!File.Exists(LogPath) && ServerConfig.GameLogServerUrl == null)
|
if (!File.Exists(LogPath) && ServerConfig.GameLogServerUrl == null)
|
||||||
{
|
{
|
||||||
Logger.WriteError($"{LogPath} {loc["SERVER_ERROR_DNE"]}");
|
Logger.WriteError(loc["SERVER_ERROR_DNE"].FormatExt(LogPath));
|
||||||
throw new ServerException($"{loc["SERVER_ERROR_LOG"]} {LogPath}");
|
throw new ServerException(loc["SERVER_ERROR_DNE"].FormatExt(LogPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,7 +932,7 @@ namespace IW4MAdmin
|
|||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string formattedKick = String.Format(RconParser.Configuration.CommandPrefixes.Kick, Target.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7");
|
string formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick, Target.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7");
|
||||||
await Target.CurrentServer.ExecuteCommandAsync(formattedKick);
|
await Target.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -925,11 +1012,9 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// this is set only because they're still in the server.
|
|
||||||
targetClient.Level = EFClient.Permission.Banned;
|
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
string formattedString = String.Format(RconParser.Configuration.CommandPrefixes.Kick, targetClient.ClientNumber, $"{loc["SERVER_BAN_TEXT"]} - ^5{reason} ^7({loc["SERVER_BAN_APPEAL"]} {Website})^7");
|
string formattedString = String.Format(RconParser.Configuration.CommandPrefixes.Kick, targetClient.ClientNumber, $"{loc["SERVER_BAN_TEXT"]} - ^5{reason} ^7{loc["SERVER_BAN_APPEAL"].FormatExt(Website)}^7");
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
await targetClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
||||||
#else
|
#else
|
||||||
await targetClient.CurrentServer.OnClientDisconnected(targetClient);
|
await targetClient.CurrentServer.OnClientDisconnected(targetClient);
|
||||||
@ -946,8 +1031,10 @@ namespace IW4MAdmin
|
|||||||
Link = targetClient.AliasLink,
|
Link = targetClient.AliasLink,
|
||||||
AutomatedOffense = originClient.AdministeredPenalties?.FirstOrDefault()?.AutomatedOffense,
|
AutomatedOffense = originClient.AdministeredPenalties?.FirstOrDefault()?.AutomatedOffense,
|
||||||
IsEvadedOffense = isEvade
|
IsEvadedOffense = isEvade
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
targetClient.SetLevel(Permission.Banned, originClient);
|
||||||
await Manager.GetPenaltyService().Create(newPenalty);
|
await Manager.GetPenaltyService().Create(newPenalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,16 +1052,17 @@ namespace IW4MAdmin
|
|||||||
Link = Target.AliasLink
|
Link = Target.AliasLink
|
||||||
};
|
};
|
||||||
|
|
||||||
await Manager.GetPenaltyService().RemoveActivePenalties(Target.AliasLink.AliasLinkId);
|
await Manager.GetPenaltyService().RemoveActivePenalties(Target.AliasLink.AliasLinkId, Origin);
|
||||||
await Manager.GetPenaltyService().Create(unbanPenalty);
|
await Manager.GetPenaltyService().Create(unbanPenalty);
|
||||||
|
Target.SetLevel(Permission.User, Origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
override public void InitializeTokens()
|
override public void InitializeTokens()
|
||||||
{
|
{
|
||||||
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("TOTALPLAYERS", (Server s) => Manager.GetClientService().GetTotalClientsAsync().Result.ToString()));
|
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("TOTALPLAYERS", (Server s) => Task.Run(async () => (await Manager.GetClientService().GetTotalClientsAsync()).ToString())));
|
||||||
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("VERSION", (Server s) => Application.Program.Version.ToString()));
|
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("VERSION", (Server s) => Task.FromResult(Application.Program.Version.ToString())));
|
||||||
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("NEXTMAP", (Server s) => SharedLibraryCore.Commands.CNextMap.GetNextMap(s).Result));
|
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("NEXTMAP", (Server s) => SharedLibraryCore.Commands.CNextMap.GetNextMap(s)));
|
||||||
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("ADMINS", (Server s) => SharedLibraryCore.Commands.CListAdmins.OnlineAdmins(s)));
|
Manager.GetMessageTokens().Add(new SharedLibraryCore.Helpers.MessageToken("ADMINS", (Server s) => Task.FromResult(SharedLibraryCore.Commands.CListAdmins.OnlineAdmins(s))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,20 @@ namespace IW4MAdmin.Application.Localization
|
|||||||
string currentLocale = string.IsNullOrEmpty(customLocale) ? CultureInfo.CurrentCulture.Name : customLocale;
|
string currentLocale = string.IsNullOrEmpty(customLocale) ? CultureInfo.CurrentCulture.Name : customLocale;
|
||||||
string[] localizationFiles = Directory.GetFiles(Path.Join(Utilities.OperatingDirectory, "Localization"), $"*.{currentLocale}.json");
|
string[] localizationFiles = Directory.GetFiles(Path.Join(Utilities.OperatingDirectory, "Localization"), $"*.{currentLocale}.json");
|
||||||
|
|
||||||
try
|
if (!Program.ServerManager.GetApplicationSettings()?.Configuration()?.UseLocalTranslations ?? false)
|
||||||
{
|
{
|
||||||
var api = Endpoint.Get();
|
try
|
||||||
var localization = api.GetLocalization(currentLocale).Result;
|
{
|
||||||
Utilities.CurrentLocalization = localization;
|
var api = Endpoint.Get();
|
||||||
return;
|
var localization = api.GetLocalization(currentLocale).Result;
|
||||||
}
|
Utilities.CurrentLocalization = localization;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// the online localization failed so will default to local files
|
// the online localization failed so will default to local files
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// culture doesn't exist so we just want language
|
// culture doesn't exist so we just want language
|
||||||
|
@ -1,269 +0,0 @@
|
|||||||
{
|
|
||||||
"LocalizationName": "en-US",
|
|
||||||
"LocalizationIndex": {
|
|
||||||
"Set": {
|
|
||||||
"BROADCAST_OFFLINE": "^5IW4MAdmin ^7is going ^1OFFLINE",
|
|
||||||
"BROADCAST_ONLINE": "^5IW4MADMIN ^7is now ^2ONLINE",
|
|
||||||
"COMMAND_HELP_OPTIONAL": "optional",
|
|
||||||
"COMMAND_HELP_SYNTAX": "syntax:",
|
|
||||||
"COMMAND_MISSINGARGS": "Not enough arguments supplied",
|
|
||||||
"COMMAND_NOACCESS": "You do not have access to that command",
|
|
||||||
"COMMAND_NOTAUTHORIZED": "You are not authorized to execute that command",
|
|
||||||
"COMMAND_TARGET_MULTI": "Multiple players match that name",
|
|
||||||
"COMMAND_TARGET_NOTFOUND": "Unable to find specified player",
|
|
||||||
"COMMAND_UNKNOWN": "You entered an unknown command",
|
|
||||||
"COMMANDS_ADMINS_DESC": "list currently connected privileged clients",
|
|
||||||
"COMMANDS_ADMINS_NONE": "No visible administrators online",
|
|
||||||
"COMMANDS_ALIAS_ALIASES": "Aliases",
|
|
||||||
"COMMANDS_ALIAS_DESC": "get past aliases and ips of a client",
|
|
||||||
"COMMANDS_ALIAS_IPS": "IPs",
|
|
||||||
"COMMANDS_ARGS_CLEAR": "clear",
|
|
||||||
"COMMANDS_ARGS_CLIENTID": "client id",
|
|
||||||
"COMMANDS_ARGS_COMMANDS": "commands",
|
|
||||||
"COMMANDS_ARGS_DURATION": "duration (m|h|d|w|y)",
|
|
||||||
"COMMANDS_ARGS_INACTIVE": "inactive days",
|
|
||||||
"COMMANDS_ARGS_LEVEL": "level",
|
|
||||||
"COMMANDS_ARGS_MAP": "map",
|
|
||||||
"COMMANDS_ARGS_MESSAGE": "message",
|
|
||||||
"COMMANDS_ARGS_PASSWORD": "password",
|
|
||||||
"COMMANDS_ARGS_PLAYER": "player",
|
|
||||||
"COMMANDS_ARGS_REASON": "reason",
|
|
||||||
"COMMANDS_BAN_DESC": "permanently ban a client from the server",
|
|
||||||
"COMMANDS_BAN_FAIL": "You cannot ban",
|
|
||||||
"COMMANDS_BAN_SUCCESS": "has been permanently banned",
|
|
||||||
"COMMANDS_BANINFO_DESC": "get information about a ban for a client",
|
|
||||||
"COMMANDS_BANINFO_NONE": "No active ban was found for that player",
|
|
||||||
"COMMANDS_BANINO_SUCCESS": "was banned by ^5{0} ^7for:",
|
|
||||||
"COMMANDS_FASTRESTART_DESC": "fast restart current map",
|
|
||||||
"COMMANDS_FASTRESTART_MASKED": "The map has been fast restarted",
|
|
||||||
"COMMANDS_FASTRESTART_UNMASKED": "fast restarted the map",
|
|
||||||
"COMMANDS_FIND_DESC": "find client in database",
|
|
||||||
"COMMANDS_FIND_EMPTY": "No players found",
|
|
||||||
"COMMANDS_FIND_MIN": "Please enter at least 3 characters",
|
|
||||||
"COMMANDS_FLAG_DESC": "flag a suspicious client and announce to admins on join",
|
|
||||||
"COMMANDS_FLAG_FAIL": "You cannot flag",
|
|
||||||
"COMMANDS_FLAG_SUCCESS": "You have flagged",
|
|
||||||
"COMMANDS_FLAG_UNFLAG": "You have unflagged",
|
|
||||||
"COMMANDS_HELP_DESC": "list all available commands",
|
|
||||||
"COMMANDS_HELP_MOREINFO": "Type !help <command name> to get command usage syntax",
|
|
||||||
"COMMANDS_HELP_NOTFOUND": "Could not find that command",
|
|
||||||
"COMMANDS_IP_DESC": "view your external IP address",
|
|
||||||
"COMMANDS_IP_SUCCESS": "Your external IP is",
|
|
||||||
"COMMANDS_KICK_DESC": "kick a client by name",
|
|
||||||
"COMMANDS_KICK_FAIL": "You do not have the required privileges to kick",
|
|
||||||
"COMMANDS_KICK_SUCCESS": "has been kicked",
|
|
||||||
"COMMANDS_LIST_DESC": "list active clients",
|
|
||||||
"COMMANDS_MAP_DESC": "change to specified map",
|
|
||||||
"COMMANDS_MAP_SUCCESS": "Changing to map",
|
|
||||||
"COMMANDS_MAP_UKN": "Attempting to change to unknown map",
|
|
||||||
"COMMANDS_MAPROTATE": "Map rotating in ^55 ^7seconds",
|
|
||||||
"COMMANDS_MAPROTATE_DESC": "cycle to the next map in rotation",
|
|
||||||
"COMMANDS_MASK_DESC": "hide your presence as a privileged client",
|
|
||||||
"COMMANDS_MASK_OFF": "You are now unmasked",
|
|
||||||
"COMMANDS_MASK_ON": "You are now masked",
|
|
||||||
"COMMANDS_OWNER_DESC": "claim ownership of the server",
|
|
||||||
"COMMANDS_OWNER_FAIL": "This server already has an owner",
|
|
||||||
"COMMANDS_OWNER_SUCCESS": "Congratulations, you have claimed ownership of this server!",
|
|
||||||
"COMMANDS_PASSWORD_FAIL": "Your password must be at least 5 characters long",
|
|
||||||
"COMMANDS_PASSWORD_SUCCESS": "Your password has been set successfully",
|
|
||||||
"COMMANDS_PING_DESC": "get client's latency",
|
|
||||||
"COMMANDS_PING_SELF": "Your latency is",
|
|
||||||
"COMMANDS_PING_TARGET": "latency is",
|
|
||||||
"COMMANDS_PLUGINS_DESC": "view all loaded plugins",
|
|
||||||
"COMMANDS_PLUGINS_LOADED": "Loaded Plugins",
|
|
||||||
"COMMANDS_PM_DESC": "send message to other client",
|
|
||||||
"COMMANDS_PRUNE_DESC": "demote any privileged clients that have not connected recently (defaults to 30 days)",
|
|
||||||
"COMMANDS_PRUNE_FAIL": "Invalid number of inactive days",
|
|
||||||
"COMMANDS_PRUNE_SUCCESS": "inactive privileged users were pruned",
|
|
||||||
"COMMANDS_QUIT_DESC": "quit IW4MAdmin",
|
|
||||||
"COMMANDS_RCON_DESC": "send rcon command to server",
|
|
||||||
"COMMANDS_RCON_SUCCESS": "Successfully sent RCon command",
|
|
||||||
"COMMANDS_REPORT_DESC": "report a client for suspicious behavior",
|
|
||||||
"COMMANDS_REPORT_FAIL": "You cannot report",
|
|
||||||
"COMMANDS_REPORT_FAIL_CAMP": "You cannot report an player for camping",
|
|
||||||
"COMMANDS_REPORT_FAIL_DUPLICATE": "You have already reported this player",
|
|
||||||
"COMMANDS_REPORT_FAIL_SELF": "You cannot report yourself",
|
|
||||||
"COMMANDS_REPORT_SUCCESS": "Thank you for your report, an administrator has been notified",
|
|
||||||
"COMMANDS_REPORTS_CLEAR_SUCCESS": "Reports successfully cleared",
|
|
||||||
"COMMANDS_REPORTS_DESC": "get or clear recent reports",
|
|
||||||
"COMMANDS_REPORTS_NONE": "No players reported yet",
|
|
||||||
"COMMANDS_RULES_DESC": "list server rules",
|
|
||||||
"COMMANDS_RULES_NONE": "The server owner has not set any rules",
|
|
||||||
"COMMANDS_SAY_DESC": "broadcast message to all clients",
|
|
||||||
"COMMANDS_SETLEVEL_DESC": "set client to specified privilege level",
|
|
||||||
"COMMANDS_SETLEVEL_FAIL": "Invalid group specified",
|
|
||||||
"COMMANDS_SETLEVEL_LEVELTOOHIGH": "You can only promote ^5{0} ^7to ^5{1} ^7or lower privilege",
|
|
||||||
"COMMANDS_SETLEVEL_OWNER": "There can only be 1 owner. Modify your settings if multiple owners are required",
|
|
||||||
"COMMANDS_SETLEVEL_SELF": "You cannot change your own level",
|
|
||||||
"COMMANDS_SETLEVEL_STEPPEDDISABLED": "This server does not allow you to promote",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS": "was successfully promoted",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS_TARGET": "Congratulations! You have been promoted to",
|
|
||||||
"COMMANDS_SETPASSWORD_DESC": "set your authentication password",
|
|
||||||
"COMMANDS_TEMPBAN_DESC": "temporarily ban a client for specified time (defaults to 1 hour)",
|
|
||||||
"COMMANDS_TEMPBAN_FAIL": "You cannot temporarily ban",
|
|
||||||
"COMMANDS_TEMPBAN_SUCCESS": "has been temporarily banned for",
|
|
||||||
"COMMANDS_UNBAN_DESC": "unban client by client id",
|
|
||||||
"COMMANDS_UNBAN_FAIL": "is not banned",
|
|
||||||
"COMMANDS_UNBAN_SUCCESS": "Successfully unbanned",
|
|
||||||
"COMMANDS_UPTIME_DESC": "get current application running time",
|
|
||||||
"COMMANDS_UPTIME_TEXT": "has been online for",
|
|
||||||
"COMMANDS_USAGE_DESC": "get application memory usage",
|
|
||||||
"COMMANDS_USAGE_TEXT": "is using",
|
|
||||||
"COMMANDS_WARN_DESC": "warn client for infringing rules",
|
|
||||||
"COMMANDS_WARN_FAIL": "You do not have the required privileges to warn",
|
|
||||||
"COMMANDS_WARNCLEAR_DESC": "remove all warnings for a client",
|
|
||||||
"COMMANDS_WARNCLEAR_SUCCESS": "All warning cleared for",
|
|
||||||
"COMMANDS_WHO_DESC": "give information about yourself",
|
|
||||||
"GLOBAL_TIME_DAYS": "days",
|
|
||||||
"GLOBAL_ERROR": "Error",
|
|
||||||
"GLOBAL_TIME_HOURS": "hours",
|
|
||||||
"GLOBAL_INFO": "Info",
|
|
||||||
"GLOBAL_TIME_MINUTES": "minutes",
|
|
||||||
"GLOBAL_REPORT": "If you suspect someone of ^5CHEATING ^7use the ^5!report ^7command",
|
|
||||||
"GLOBAL_VERBOSE": "Verbose",
|
|
||||||
"GLOBAL_WARNING": "Warning",
|
|
||||||
"MANAGER_CONNECTION_REST": "Connection has been reestablished with",
|
|
||||||
"MANAGER_CONSOLE_NOSERV": "No servers are currently being monitored",
|
|
||||||
"MANAGER_EXIT": "Press any key to exit...",
|
|
||||||
"MANAGER_INIT_FAIL": "Fatal error during initialization",
|
|
||||||
"MANAGER_MONITORING_TEXT": "Now monitoring",
|
|
||||||
"MANAGER_SHUTDOWN_SUCCESS": "Shutdown complete",
|
|
||||||
"MANAGER_VERSION_CURRENT": "Your version is",
|
|
||||||
"MANAGER_VERSION_FAIL": "Could not get latest IW4MAdmin version",
|
|
||||||
"MANAGER_VERSION_SUCCESS": "IW4MAdmin is up to date",
|
|
||||||
"MANAGER_VERSION_UPDATE": "has an update. Latest version is",
|
|
||||||
"PLUGIN_IMPORTER_NOTFOUND": "No plugins found to load",
|
|
||||||
"PLUGIN_IMPORTER_REGISTERCMD": "Registered command",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "login using password",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Your password is incorrect",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "You are now logged in",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_DESC": "reset your stats to factory-new",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_FAIL": "You must be connected to a server to reset your stats",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Your stats for this server have been reset",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_DESC": "view the top 5 players in this server",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_TEXT": "Top Players",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_DESC": "view your stats",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL": "Cannot find the player you specified",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "The specified player must be ingame",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "You must be ingame to view your stats",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Stats for",
|
|
||||||
"PLUGINS_STATS_TEXT_DEATHS": "DEATHS",
|
|
||||||
"PLUGINS_STATS_TEXT_KILLS": "KILLS",
|
|
||||||
"PLUGINS_STATS_TEXT_NOQUALIFY": "No players qualify for top stats yet",
|
|
||||||
"PLUGINS_STATS_TEXT_SKILL": "SKILL",
|
|
||||||
"SERVER_BAN_APPEAL": "appeal at",
|
|
||||||
"SERVER_BAN_PREV": "Previously banned for",
|
|
||||||
"SERVER_BAN_TEXT": "You're banned",
|
|
||||||
"SERVER_ERROR_ADDPLAYER": "Unable to add player",
|
|
||||||
"SERVER_ERROR_COMMAND_INGAME": "An internal error occured while processing your command",
|
|
||||||
"SERVER_ERROR_COMMAND_LOG": "command generated an error",
|
|
||||||
"SERVER_ERROR_COMMUNICATION": "Could not communicate with",
|
|
||||||
"SERVER_ERROR_DNE": "does not exist",
|
|
||||||
"SERVER_ERROR_DVAR": "Could not get the dvar value for",
|
|
||||||
"SERVER_ERROR_DVAR_HELP": "ensure the server has a map loaded",
|
|
||||||
"SERVER_ERROR_EXCEPTION": "Unexpected exception on",
|
|
||||||
"SERVER_ERROR_LOG": "Invalid game log file",
|
|
||||||
"SERVER_ERROR_PLUGIN": "An error occured loading plugin",
|
|
||||||
"SERVER_ERROR_POLLING": "reducing polling rate",
|
|
||||||
"SERVER_ERROR_UNFIXABLE": "Not monitoring server due to uncorrectable errors",
|
|
||||||
"SERVER_KICK_CONTROLCHARS": "Your name cannot contain control characters",
|
|
||||||
"SERVER_KICK_GENERICNAME": "Please change your name using /name",
|
|
||||||
"SERVER_KICK_MINNAME": "Your name must contain at least 3 characters",
|
|
||||||
"SERVER_KICK_NAME_INUSE": "Your name is being used by someone else",
|
|
||||||
"SERVER_KICK_TEXT": "You were kicked",
|
|
||||||
"SERVER_KICK_VPNS_NOTALLOWED": "VPNs are not allowed on this server",
|
|
||||||
"SERVER_PLUGIN_ERROR": "A plugin generated an error",
|
|
||||||
"SERVER_REPORT_COUNT": "There are ^5{0} ^7recent reports",
|
|
||||||
"SERVER_TB_REMAIN": "You are temporarily banned",
|
|
||||||
"SERVER_TB_TEXT": "You're temporarily banned",
|
|
||||||
"SERVER_WARNING": "WARNING",
|
|
||||||
"SERVER_WARNLIMT_REACHED": "Too many warnings",
|
|
||||||
"SERVER_WEBSITE_GENERIC": "this server's website",
|
|
||||||
"SETUP_DISPLAY_SOCIAL": "Display social media link on webfront (discord, website, VK, etc..)",
|
|
||||||
"SETUP_ENABLE_CUSTOMSAY": "Enable custom say name",
|
|
||||||
"SETUP_ENABLE_MULTIOWN": "Enable multiple owners",
|
|
||||||
"SETUP_ENABLE_STEPPEDPRIV": "Enable stepped privilege hierarchy",
|
|
||||||
"SETUP_ENABLE_VPNS": "Enable client VPNs",
|
|
||||||
"SETUP_ENABLE_WEBFRONT": "Enable webfront",
|
|
||||||
"SETUP_ENCODING_STRING": "Enter encoding string",
|
|
||||||
"SETUP_IPHUB_KEY": "Enter iphub.info api key",
|
|
||||||
"SETUP_SAY_NAME": "Enter custom say name",
|
|
||||||
"SETUP_SERVER_IP": "Enter server IP Address",
|
|
||||||
"SETUP_SERVER_MANUALLOG": "Enter manual log file path",
|
|
||||||
"SETUP_SERVER_PORT": "Enter server port",
|
|
||||||
"SETUP_SERVER_RCON": "Enter server RCon password",
|
|
||||||
"SETUP_SERVER_SAVE": "Configuration saved, add another",
|
|
||||||
"SETUP_SERVER_USEIW5M": "Use Pluto IW5 Parser",
|
|
||||||
"SETUP_SERVER_USET6M": "Use Pluto T6 parser",
|
|
||||||
"SETUP_SOCIAL_LINK": "Enter social media link",
|
|
||||||
"SETUP_SOCIAL_TITLE": "Enter social media name",
|
|
||||||
"SETUP_USE_CUSTOMENCODING": "Use custom encoding parser",
|
|
||||||
"WEBFRONT_ACTION_BAN_NAME": "Ban",
|
|
||||||
"WEBFRONT_ACTION_LABEL_ID": "Client ID",
|
|
||||||
"WEBFRONT_ACTION_LABEL_PASSWORD": "Password",
|
|
||||||
"WEBFRONT_ACTION_LABEL_REASON": "Reason",
|
|
||||||
"WEBFRONT_ACTION_LOGIN_NAME": "Login",
|
|
||||||
"WEBFRONT_ACTION_UNBAN_NAME": "Unban",
|
|
||||||
"WEBFRONT_CLIENT_META_FALSE": "Is not",
|
|
||||||
"WEBFRONT_CLIENT_META_JOINED": "Joined with alias",
|
|
||||||
"WEBFRONT_CLIENT_META_MASKED": "Masked",
|
|
||||||
"WEBFRONT_CLIENT_META_TRUE": "Is",
|
|
||||||
"WEBFRONT_CLIENT_PRIVILEGED_TITLE": "Privileged Clients",
|
|
||||||
"WEBFRONT_CLIENT_PROFILE_TITLE": "Profile",
|
|
||||||
"WEBFRONT_CLIENT_SEARCH_MATCHING": "Clients Matching",
|
|
||||||
"WEBFRONT_CONSOLE_EXECUTE": "Execute",
|
|
||||||
"WEBFRONT_CONSOLE_TITLE": "Web Console",
|
|
||||||
"WEBFRONT_ERROR_DESC": "IW4MAdmin encountered an error",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_DESC": "An error occurred while processing your request",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_TITLE": "Sorry!",
|
|
||||||
"WEBFRONT_ERROR_TITLE": "Error!",
|
|
||||||
"WEBFRONT_HOME_TITLE": "Server Overview",
|
|
||||||
"WEBFRONT_NAV_CONSOLE": "Console",
|
|
||||||
"WEBFRONT_NAV_DISCORD": "Discord",
|
|
||||||
"WEBFRONT_NAV_HOME": "Home",
|
|
||||||
"WEBFRONT_NAV_LOGOUT": "Logout",
|
|
||||||
"WEBFRONT_NAV_PENALTIES": "Penalties",
|
|
||||||
"WEBFRONT_NAV_PRIVILEGED": "Admins",
|
|
||||||
"WEBFRONT_NAV_PROFILE": "Client Profile",
|
|
||||||
"WEBFRONT_NAV_SEARCH": "Find Client",
|
|
||||||
"WEBFRONT_NAV_SOCIAL": "Social",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_ADMIN": "Admin",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_AGO": "ago",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_NAME": "Name",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_OFFENSE": "Offense",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_REMAINING": "left",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOW": "Show",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOWONLY": "Show only",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TIME": "Time/Left",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TYPE": "Type",
|
|
||||||
"WEBFRONT_PENALTY_TITLE": "Client Penalties",
|
|
||||||
"WEBFRONT_PROFILE_FSEEN": "First seen",
|
|
||||||
"WEBFRONT_PROFILE_LEVEL": "Level",
|
|
||||||
"WEBFRONT_PROFILE_LSEEN": "Last seen",
|
|
||||||
"WEBFRONT_PROFILE_PLAYER": "Played",
|
|
||||||
"PLUGIN_STATS_SETUP_ENABLEAC": "Enable server-side anti-cheat (IW4 only)",
|
|
||||||
"PLUGIN_STATS_ERROR_ADD": "Could not add server to server stats",
|
|
||||||
"PLUGIN_STATS_CHEAT_DETECTED": "You appear to be cheating",
|
|
||||||
"PLUGINS_STATS_TEXT_KDR": "KDR",
|
|
||||||
"PLUGINS_STATS_META_SPM": "Score per Minute",
|
|
||||||
"PLUGINS_WELCOME_USERANNOUNCE": "^5{{ClientName}} ^7hails from ^5{{ClientLocation}}",
|
|
||||||
"PLUGINS_WELCOME_USERWELCOME": "Welcome ^5{{ClientName}}^7, this is your ^5{{TimesConnected}} ^7time connecting!",
|
|
||||||
"PLUGINS_WELCOME_PRIVANNOUNCE": "{{ClientLevel}} {{ClientName}} has joined the server",
|
|
||||||
"PLUGINS_LOGIN_AUTH": "not logged in",
|
|
||||||
"PLUGINS_PROFANITY_SETUP_ENABLE": "Enable profanity deterring",
|
|
||||||
"PLUGINS_PROFANITY_WARNMSG": "Please do not use profanity on this server",
|
|
||||||
"PLUGINS_PROFANITY_KICKMSG": "Excessive use of profanity",
|
|
||||||
"GLOBAL_DEBUG": "Debug",
|
|
||||||
"COMMANDS_UNFLAG_DESC": "Remove flag for client",
|
|
||||||
"COMMANDS_UNFLAG_FAIL": "You cannot unflag",
|
|
||||||
"COMMANDS_UNFLAG_NOTFLAGGED": "Client is not flagged",
|
|
||||||
"COMMANDS_FLAG_ALREADYFLAGGED": "Client is already flagged",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT": "Most Played",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_DESC": "view the top 5 dedicated players on the server",
|
|
||||||
"WEBFRONT_PROFILE_MESSAGES": "Messages",
|
|
||||||
"WEBFRONT_CLIENT_META_CONNECTIONS": "Connections",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOPSTATS_RATING": "Rating",
|
|
||||||
"PLUGINS_STATS_COMMANDS_PERFORMANCE": "Performance"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,269 +0,0 @@
|
|||||||
{
|
|
||||||
"LocalizationName": "es-EC",
|
|
||||||
"LocalizationIndex": {
|
|
||||||
"Set": {
|
|
||||||
"BROADCAST_OFFLINE": "^5IW4MAdmin ^7está ^1DESCONECTANDOSE",
|
|
||||||
"BROADCAST_ONLINE": "^5IW4MADMIN ^7está ahora ^2en línea",
|
|
||||||
"COMMAND_HELP_OPTIONAL": "opcional",
|
|
||||||
"COMMAND_HELP_SYNTAX": "sintaxis:",
|
|
||||||
"COMMAND_MISSINGARGS": "No se han proporcionado suficientes argumentos",
|
|
||||||
"COMMAND_NOACCESS": "Tú no tienes acceso a ese comando",
|
|
||||||
"COMMAND_NOTAUTHORIZED": "Tú no estás autorizado para ejecutar ese comando",
|
|
||||||
"COMMAND_TARGET_MULTI": "Múltiples jugadores coinciden con ese nombre",
|
|
||||||
"COMMAND_TARGET_NOTFOUND": "No se puede encontrar el jugador especificado",
|
|
||||||
"COMMAND_UNKNOWN": "Has ingresado un comando desconocido",
|
|
||||||
"COMMANDS_ADMINS_DESC": "enlistar clientes privilegiados actualmente conectados",
|
|
||||||
"COMMANDS_ADMINS_NONE": "No hay administradores visibles en línea",
|
|
||||||
"COMMANDS_ALIAS_ALIASES": "Aliases",
|
|
||||||
"COMMANDS_ALIAS_DESC": "obtener alias e ips anteriores de un cliente",
|
|
||||||
"COMMANDS_ALIAS_IPS": "IPs",
|
|
||||||
"COMMANDS_ARGS_CLEAR": "borrar",
|
|
||||||
"COMMANDS_ARGS_CLIENTID": "id del cliente",
|
|
||||||
"COMMANDS_ARGS_COMMANDS": "comandos",
|
|
||||||
"COMMANDS_ARGS_DURATION": "duración (m|h|d|w|y)",
|
|
||||||
"COMMANDS_ARGS_INACTIVE": "días inactivo",
|
|
||||||
"COMMANDS_ARGS_LEVEL": "nivel",
|
|
||||||
"COMMANDS_ARGS_MAP": "mapa",
|
|
||||||
"COMMANDS_ARGS_MESSAGE": "mensaje",
|
|
||||||
"COMMANDS_ARGS_PASSWORD": "contraseña",
|
|
||||||
"COMMANDS_ARGS_PLAYER": "jugador",
|
|
||||||
"COMMANDS_ARGS_REASON": "razón",
|
|
||||||
"COMMANDS_BAN_DESC": "banear permanentemente un cliente del servidor",
|
|
||||||
"COMMANDS_BAN_FAIL": "Tú no puedes banear",
|
|
||||||
"COMMANDS_BAN_SUCCESS": "ha sido baneado permanentemente",
|
|
||||||
"COMMANDS_BANINFO_DESC": "obtener información sobre el ban de un cliente",
|
|
||||||
"COMMANDS_BANINFO_NONE": "No se encontró ban activo para ese jugador",
|
|
||||||
"COMMANDS_BANINO_SUCCESS": "fue baneado por ^5{0} ^7debido a:",
|
|
||||||
"COMMANDS_FASTRESTART_DESC": "dar reinicio rápido al mapa actial",
|
|
||||||
"COMMANDS_FASTRESTART_MASKED": "Al mapa se le ha dado un reinicio rápido",
|
|
||||||
"COMMANDS_FASTRESTART_UNMASKED": "ha dado rápido reinicio al mapa",
|
|
||||||
"COMMANDS_FIND_DESC": "encontrar cliente en la base de datos",
|
|
||||||
"COMMANDS_FIND_EMPTY": "No se encontraron jugadores",
|
|
||||||
"COMMANDS_FIND_MIN": "Por Favor introduzca al menos 3 caracteres",
|
|
||||||
"COMMANDS_FLAG_DESC": "marcar un cliente sospechoso y anunciar a los administradores al unirse",
|
|
||||||
"COMMANDS_FLAG_FAIL": "Tú no puedes marcar",
|
|
||||||
"COMMANDS_FLAG_SUCCESS": "Has marcado a",
|
|
||||||
"COMMANDS_FLAG_UNFLAG": "Has desmarcado a",
|
|
||||||
"COMMANDS_HELP_DESC": "enlistar todos los comandos disponibles",
|
|
||||||
"COMMANDS_HELP_MOREINFO": "Escribe !help <nombre del comando> para obtener la sintaxis de uso del comando",
|
|
||||||
"COMMANDS_HELP_NOTFOUND": "No se ha podido encontrar ese comando",
|
|
||||||
"COMMANDS_IP_DESC": "ver tu dirección IP externa",
|
|
||||||
"COMMANDS_IP_SUCCESS": "Tu IP externa es",
|
|
||||||
"COMMANDS_KICK_DESC": "expulsar a un cliente por su nombre",
|
|
||||||
"COMMANDS_KICK_FAIL": "No tienes los privilegios necesarios para expulsar a",
|
|
||||||
"COMMANDS_KICK_SUCCESS": "ha sido expulsado",
|
|
||||||
"COMMANDS_LIST_DESC": "enlistar clientes activos",
|
|
||||||
"COMMANDS_MAP_DESC": "cambiar al mapa especificado",
|
|
||||||
"COMMANDS_MAP_SUCCESS": "Cambiando al mapa",
|
|
||||||
"COMMANDS_MAP_UKN": "Intentando cambiar a un mapa desconocido",
|
|
||||||
"COMMANDS_MAPROTATE": "Rotación de mapa en ^55 ^7segundos",
|
|
||||||
"COMMANDS_MAPROTATE_DESC": "pasar al siguiente mapa en rotación",
|
|
||||||
"COMMANDS_MASK_DESC": "esconde tu presencia como un cliente privilegiado",
|
|
||||||
"COMMANDS_MASK_OFF": "Ahora estás desenmascarado",
|
|
||||||
"COMMANDS_MASK_ON": "Ahora estás enmascarado",
|
|
||||||
"COMMANDS_OWNER_DESC": "reclamar la propiedad del servidor",
|
|
||||||
"COMMANDS_OWNER_FAIL": "Este servidor ya tiene un propietario",
|
|
||||||
"COMMANDS_OWNER_SUCCESS": "¡Felicidades, has reclamado la propiedad de este servidor!",
|
|
||||||
"COMMANDS_PASSWORD_FAIL": "Tu contraseña debe tener al menos 5 caracteres de largo",
|
|
||||||
"COMMANDS_PASSWORD_SUCCESS": "Su contraseña ha sido establecida con éxito",
|
|
||||||
"COMMANDS_PING_DESC": "obtener ping del cliente",
|
|
||||||
"COMMANDS_PING_SELF": "Tu ping es",
|
|
||||||
"COMMANDS_PING_TARGET": "ping es",
|
|
||||||
"COMMANDS_PLUGINS_DESC": "ver todos los complementos cargados",
|
|
||||||
"COMMANDS_PLUGINS_LOADED": "Complementos cargados",
|
|
||||||
"COMMANDS_PM_DESC": "enviar mensaje a otro cliente",
|
|
||||||
"COMMANDS_PRUNE_DESC": "degradar a los clientes con privilegios que no se hayan conectado recientemente (el valor predeterminado es 30 días)",
|
|
||||||
"COMMANDS_PRUNE_FAIL": "Número inválido de días inactivos",
|
|
||||||
"COMMANDS_PRUNE_SUCCESS": "los usuarios privilegiados inactivos fueron podados",
|
|
||||||
"COMMANDS_QUIT_DESC": "salir de IW4MAdmin",
|
|
||||||
"COMMANDS_RCON_DESC": "enviar el comando rcon al servidor",
|
|
||||||
"COMMANDS_RCON_SUCCESS": "Exitosamente enviado el comando RCon",
|
|
||||||
"COMMANDS_REPORT_DESC": "reportar un cliente por comportamiento sospechoso",
|
|
||||||
"COMMANDS_REPORT_FAIL": "Tú no puedes reportar",
|
|
||||||
"COMMANDS_REPORT_FAIL_CAMP": "No puedes reportar a un jugador por campear",
|
|
||||||
"COMMANDS_REPORT_FAIL_DUPLICATE": "Ya has reportado a este jugador",
|
|
||||||
"COMMANDS_REPORT_FAIL_SELF": "No puedes reportarte a ti mismo",
|
|
||||||
"COMMANDS_REPORT_SUCCESS": "Gracias por su reporte, un administrador ha sido notificado",
|
|
||||||
"COMMANDS_REPORTS_CLEAR_SUCCESS": "Reportes borrados con éxito",
|
|
||||||
"COMMANDS_REPORTS_DESC": "obtener o borrar informes recientes",
|
|
||||||
"COMMANDS_REPORTS_NONE": "No hay jugadores reportados aun",
|
|
||||||
"COMMANDS_RULES_DESC": "enlistar reglas del servidor",
|
|
||||||
"COMMANDS_RULES_NONE": "El propietario del servidor no ha establecido ninguna regla",
|
|
||||||
"COMMANDS_SAY_DESC": "transmitir el mensaje a todos los clientes",
|
|
||||||
"COMMANDS_SETLEVEL_DESC": "establecer el cliente al nivel de privilegio especificado",
|
|
||||||
"COMMANDS_SETLEVEL_FAIL": "Grupo inválido especificado",
|
|
||||||
"COMMANDS_SETLEVEL_LEVELTOOHIGH": "Tú solo puedes promover ^5{0} ^7a ^5{1} ^7o menor privilegio",
|
|
||||||
"COMMANDS_SETLEVEL_OWNER": "Solo puede haber un propietario. Modifica tu configuración si múltiples propietarios son requeridos",
|
|
||||||
"COMMANDS_SETLEVEL_SELF": "No puedes cambiar tu propio nivel",
|
|
||||||
"COMMANDS_SETLEVEL_STEPPEDDISABLED": "Este servidor no te permite promover",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS": "fue promovido con éxito",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS_TARGET": "¡Felicitaciones! has ha sido promovido a",
|
|
||||||
"COMMANDS_SETPASSWORD_DESC": "configura tu contraseña de autenticación",
|
|
||||||
"COMMANDS_TEMPBAN_DESC": "banear temporalmente a un cliente por el tiempo especificado (predeterminado en 1 hora)",
|
|
||||||
"COMMANDS_TEMPBAN_FAIL": "Tú no puedes banear temporalmente",
|
|
||||||
"COMMANDS_TEMPBAN_SUCCESS": "ha sido baneado temporalmente por",
|
|
||||||
"COMMANDS_UNBAN_DESC": "desbanear al cliente por ID",
|
|
||||||
"COMMANDS_UNBAN_FAIL": "no está baneado",
|
|
||||||
"COMMANDS_UNBAN_SUCCESS": "Exitosamente desbaneado",
|
|
||||||
"COMMANDS_UPTIME_DESC": "obtener el tiempo de ejecución de la aplicación actual",
|
|
||||||
"COMMANDS_UPTIME_TEXT": "ha estado en línea por",
|
|
||||||
"COMMANDS_USAGE_DESC": "obtener uso de la memoria de la aplicación",
|
|
||||||
"COMMANDS_USAGE_TEXT": "está usando",
|
|
||||||
"COMMANDS_WARN_DESC": "advertir al cliente por infringir las reglas",
|
|
||||||
"COMMANDS_WARN_FAIL": "No tiene los privilegios necesarios para advertir a",
|
|
||||||
"COMMANDS_WARNCLEAR_DESC": "eliminar todas las advertencias de un cliente",
|
|
||||||
"COMMANDS_WARNCLEAR_SUCCESS": "Todas las advertencias borradas para",
|
|
||||||
"COMMANDS_WHO_DESC": "da información sobre ti",
|
|
||||||
"GLOBAL_TIME_DAYS": "días",
|
|
||||||
"GLOBAL_ERROR": "Error",
|
|
||||||
"GLOBAL_TIME_HOURS": "horas",
|
|
||||||
"GLOBAL_INFO": "Información",
|
|
||||||
"GLOBAL_TIME_MINUTES": "minutos",
|
|
||||||
"GLOBAL_REPORT": "Si sospechas que alguien ^5usa cheats ^7usa el comando ^5!report",
|
|
||||||
"GLOBAL_VERBOSE": "Detallado",
|
|
||||||
"GLOBAL_WARNING": "Advertencia",
|
|
||||||
"MANAGER_CONNECTION_REST": "La conexión ha sido restablecida con",
|
|
||||||
"MANAGER_CONSOLE_NOSERV": "No hay servidores que estén siendo monitoreados en este momento",
|
|
||||||
"MANAGER_EXIT": "Presione cualquier tecla para salir...",
|
|
||||||
"MANAGER_INIT_FAIL": "Error fatal durante la inicialización",
|
|
||||||
"MANAGER_MONITORING_TEXT": "Ahora monitoreando",
|
|
||||||
"MANAGER_SHUTDOWN_SUCCESS": "Apagado completo",
|
|
||||||
"MANAGER_VERSION_CURRENT": "Tu versión es",
|
|
||||||
"MANAGER_VERSION_FAIL": "No se ha podido conseguir la última versión de IW4MAdmin",
|
|
||||||
"MANAGER_VERSION_SUCCESS": "IW4MAdmin está actualizado",
|
|
||||||
"MANAGER_VERSION_UPDATE": "tiene una actualización. La última versión es",
|
|
||||||
"PLUGIN_IMPORTER_NOTFOUND": "No se encontraron complementos para cargar",
|
|
||||||
"PLUGIN_IMPORTER_REGISTERCMD": "Comando registrado",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "iniciar sesión usando la contraseña",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "tu contraseña es incorrecta",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "Ahora está conectado",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_DESC": "restablece tus estadísticas a las nuevas de fábrica",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_FAIL": "Debes estar conectado a un servidor para restablecer tus estadísticas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Tus estadísticas para este servidor se han restablecido",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_DESC": "ver los 5 mejores jugadores en este servidor",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_TEXT": "Mejores Jugadores",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_DESC": "ver tus estadísticas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL": "No se puede encontrar el jugador que especificó",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "El jugador especificado debe estar dentro del juego",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Debes estar dentro del juego para ver tus estadísticas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Estadísticas para",
|
|
||||||
"PLUGINS_STATS_TEXT_DEATHS": "Muertes",
|
|
||||||
"PLUGINS_STATS_TEXT_KILLS": "Asesinatos",
|
|
||||||
"PLUGINS_STATS_TEXT_NOQUALIFY": "No hay jugadores que califiquen para los primeros lugares aun",
|
|
||||||
"PLUGINS_STATS_TEXT_SKILL": "Habilidad",
|
|
||||||
"SERVER_BAN_APPEAL": "apela en",
|
|
||||||
"SERVER_BAN_PREV": "Baneado anteriormente por",
|
|
||||||
"SERVER_BAN_TEXT": "Estás baneado",
|
|
||||||
"SERVER_ERROR_ADDPLAYER": "Incapaz de añadir al jugador",
|
|
||||||
"SERVER_ERROR_COMMAND_INGAME": "Un error interno ocurrió mientras se procesaba tu comando",
|
|
||||||
"SERVER_ERROR_COMMAND_LOG": "Comando generó error",
|
|
||||||
"SERVER_ERROR_COMMUNICATION": "No se ha podido comunicar con",
|
|
||||||
"SERVER_ERROR_DNE": "No existe",
|
|
||||||
"SERVER_ERROR_DVAR": "No se pudo obtener el valor dvar",
|
|
||||||
"SERVER_ERROR_DVAR_HELP": "asegúrate de que el servidor tenga un mapa cargado",
|
|
||||||
"SERVER_ERROR_EXCEPTION": "Excepción inesperada en",
|
|
||||||
"SERVER_ERROR_LOG": "Archivo de registro del juego invalido",
|
|
||||||
"SERVER_ERROR_PLUGIN": "Un error ocurrió mientras se cargaba el complemente",
|
|
||||||
"SERVER_ERROR_POLLING": "reduciendo la tasa de sondeo",
|
|
||||||
"SERVER_ERROR_UNFIXABLE": "No se está supervisando el servidor debido a errores incorregibles",
|
|
||||||
"SERVER_KICK_CONTROLCHARS": "Tu nombre no puede contener caracteres de control",
|
|
||||||
"SERVER_KICK_GENERICNAME": "Por favor cambia tu nombre usando /name",
|
|
||||||
"SERVER_KICK_MINNAME": "Tu nombre debe contener al menos 3 caracteres",
|
|
||||||
"SERVER_KICK_NAME_INUSE": "Tu nombre está siendo usado por alguien más",
|
|
||||||
"SERVER_KICK_TEXT": "Fuiste expulsado",
|
|
||||||
"SERVER_KICK_VPNS_NOTALLOWED": "Las VPNs no están permitidas en este servidor",
|
|
||||||
"SERVER_PLUGIN_ERROR": "Un complemento generó un error",
|
|
||||||
"SERVER_REPORT_COUNT": "Hay ^5{0} ^7reportes recientes",
|
|
||||||
"SERVER_TB_REMAIN": "Tú estás temporalmente baneado",
|
|
||||||
"SERVER_TB_TEXT": "Estás temporalmente baneado",
|
|
||||||
"SERVER_WARNING": "ADVERTENCIA",
|
|
||||||
"SERVER_WARNLIMT_REACHED": "Muchas advertencias",
|
|
||||||
"SERVER_WEBSITE_GENERIC": "el sitio web de este servidor",
|
|
||||||
"SETUP_DISPLAY_SOCIAL": "Mostrar el link del medio de comunicación en la parte frontal de la web. (discord, website, VK, etc..)",
|
|
||||||
"SETUP_ENABLE_CUSTOMSAY": "Habilitar nombre a decir personalizado",
|
|
||||||
"SETUP_ENABLE_MULTIOWN": "Habilitar múltiples propietarios",
|
|
||||||
"SETUP_ENABLE_STEPPEDPRIV": "Habilitar jerarquía de privilegios por escalones",
|
|
||||||
"SETUP_ENABLE_VPNS": "Habilitar VPNs clientes",
|
|
||||||
"SETUP_ENABLE_WEBFRONT": "Habilitar frente de la web",
|
|
||||||
"SETUP_ENCODING_STRING": "Ingresar cadena de codificación",
|
|
||||||
"SETUP_IPHUB_KEY": "Ingresar clave api de iphub.info",
|
|
||||||
"SETUP_SAY_NAME": "Ingresar nombre a decir personalizado",
|
|
||||||
"SETUP_SERVER_IP": "Ingresar Dirección IP del servidor",
|
|
||||||
"SETUP_SERVER_MANUALLOG": "Ingresar manualmente la ruta del archivo de registro",
|
|
||||||
"SETUP_SERVER_PORT": "Ingresar puerto del servidor",
|
|
||||||
"SETUP_SERVER_RCON": "Ingresar contraseña RCon del servidor",
|
|
||||||
"SETUP_SERVER_SAVE": "Configuración guardada, añadir otra",
|
|
||||||
"SETUP_SERVER_USEIW5M": "Usar analizador Pluto IW5",
|
|
||||||
"SETUP_SERVER_USET6M": "Usar analizador Pluto T6",
|
|
||||||
"SETUP_SOCIAL_LINK": "Ingresar link del medio de comunicación",
|
|
||||||
"SETUP_SOCIAL_TITLE": "Ingresa el nombre de la red de comunicación",
|
|
||||||
"SETUP_USE_CUSTOMENCODING": "Usar analizador de codificación personalizado",
|
|
||||||
"WEBFRONT_ACTION_BAN_NAME": "Ban",
|
|
||||||
"WEBFRONT_ACTION_LABEL_ID": "ID del Cliente",
|
|
||||||
"WEBFRONT_ACTION_LABEL_PASSWORD": "Contraseña",
|
|
||||||
"WEBFRONT_ACTION_LABEL_REASON": "Razón",
|
|
||||||
"WEBFRONT_ACTION_LOGIN_NAME": "Inicio de sesión",
|
|
||||||
"WEBFRONT_ACTION_UNBAN_NAME": "Desban",
|
|
||||||
"WEBFRONT_CLIENT_META_FALSE": "No está",
|
|
||||||
"WEBFRONT_CLIENT_META_JOINED": "Se unió con el alias",
|
|
||||||
"WEBFRONT_CLIENT_META_MASKED": "Enmascarado",
|
|
||||||
"WEBFRONT_CLIENT_META_TRUE": "Está",
|
|
||||||
"WEBFRONT_CLIENT_PRIVILEGED_TITLE": "Clientes privilegiados",
|
|
||||||
"WEBFRONT_CLIENT_PROFILE_TITLE": "Perfil",
|
|
||||||
"WEBFRONT_CLIENT_SEARCH_MATCHING": "Clientes que concuerdan",
|
|
||||||
"WEBFRONT_CONSOLE_EXECUTE": "Ejecutar",
|
|
||||||
"WEBFRONT_CONSOLE_TITLE": "Consola Web",
|
|
||||||
"WEBFRONT_ERROR_DESC": "IW4MAdmin encontró un error",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_DESC": "Un error ha ocurrido mientras se procesaba tu solicitud",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_TITLE": "¡Lo lamento!",
|
|
||||||
"WEBFRONT_ERROR_TITLE": "¡Error!",
|
|
||||||
"WEBFRONT_HOME_TITLE": "Vista general del servidor",
|
|
||||||
"WEBFRONT_NAV_CONSOLE": "Consola",
|
|
||||||
"WEBFRONT_NAV_DISCORD": "Discord",
|
|
||||||
"WEBFRONT_NAV_HOME": "Inicio",
|
|
||||||
"WEBFRONT_NAV_LOGOUT": "Cerrar sesión",
|
|
||||||
"WEBFRONT_NAV_PENALTIES": "Sanciones",
|
|
||||||
"WEBFRONT_NAV_PRIVILEGED": "Administradores",
|
|
||||||
"WEBFRONT_NAV_PROFILE": "Perfil del cliente",
|
|
||||||
"WEBFRONT_NAV_SEARCH": "Encontrar cliente",
|
|
||||||
"WEBFRONT_NAV_SOCIAL": "Social",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_ADMIN": "Administrador",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_AGO": "atrás",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_NAME": "Nombre",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_OFFENSE": "Ofensa",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_REMAINING": "restante",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOW": "Mostrar",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOWONLY": "Mostrar solamente",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TIME": "Tiempo/Restante",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TYPE": "Tipo",
|
|
||||||
"WEBFRONT_PENALTY_TITLE": "Faltas del cliente",
|
|
||||||
"WEBFRONT_PROFILE_FSEEN": "Primera vez visto hace",
|
|
||||||
"WEBFRONT_PROFILE_LEVEL": "Nivel",
|
|
||||||
"WEBFRONT_PROFILE_LSEEN": "Última vez visto hace",
|
|
||||||
"WEBFRONT_PROFILE_PLAYER": "Jugadas",
|
|
||||||
"PLUGIN_STATS_SETUP_ENABLEAC": "Habilitar anti-trampas junto al servidor (solo IW4)",
|
|
||||||
"PLUGIN_STATS_ERROR_ADD": "No se puedo añadir servidor a los estados del servidor",
|
|
||||||
"PLUGIN_STATS_CHEAT_DETECTED": "Pareces estar haciendo trampa",
|
|
||||||
"PLUGINS_STATS_TEXT_KDR": "KDR",
|
|
||||||
"PLUGINS_STATS_META_SPM": "Puntaje por minuto",
|
|
||||||
"PLUGINS_WELCOME_USERANNOUNCE": "^5{{ClientName}} ^7llega desde ^5{{ClientLocation}}",
|
|
||||||
"PLUGINS_WELCOME_USERWELCOME": "¡Bienvenido ^5{{ClientName}}^7, esta es tu visita numero ^5{{TimesConnected}} ^7 en el servidor!",
|
|
||||||
"PLUGINS_WELCOME_PRIVANNOUNCE": "{{ClientLevel}} {{ClientName}} Se ha unido al servidor",
|
|
||||||
"PLUGINS_LOGIN_AUTH": "No registrado",
|
|
||||||
"PLUGINS_PROFANITY_SETUP_ENABLE": "Habilitar la disuasión de blasfemias",
|
|
||||||
"PLUGINS_PROFANITY_WARNMSG": "Por favor no uses blasfemias en este servidor",
|
|
||||||
"PLUGINS_PROFANITY_KICKMSG": "Excesivo uso de blasfemias",
|
|
||||||
"GLOBAL_DEBUG": "Depurar",
|
|
||||||
"COMMANDS_UNFLAG_DESC": "Remover marca del cliente",
|
|
||||||
"COMMANDS_UNFLAG_FAIL": "Tu no puedes desmarcar",
|
|
||||||
"COMMANDS_UNFLAG_NOTFLAGGED": "El cliente no está marcado",
|
|
||||||
"COMMANDS_FLAG_ALREADYFLAGGED": "El cliente yá se encuentra marcado",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT": "Más jugado",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_DESC": "ver el Top 5 de jugadores dedicados en el servidor",
|
|
||||||
"WEBFRONT_PROFILE_MESSAGES": "Mensajes",
|
|
||||||
"WEBFRONT_CLIENT_META_CONNECTIONS": "Conexiones",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOPSTATS_RATING": "Clasificación",
|
|
||||||
"PLUGINS_STATS_COMMANDS_PERFORMANCE": "Desempeño"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,269 +0,0 @@
|
|||||||
{
|
|
||||||
"LocalizationName": "pt-BR",
|
|
||||||
"LocalizationIndex": {
|
|
||||||
"Set": {
|
|
||||||
"BROADCAST_OFFLINE": "IW4MAdmin ficou offline",
|
|
||||||
"BROADCAST_ONLINE": "^5IW4MADMIN ^7agora está ^2ONLINE",
|
|
||||||
"COMMAND_HELP_OPTIONAL": "opcional",
|
|
||||||
"COMMAND_HELP_SYNTAX": "sintaxe:",
|
|
||||||
"COMMAND_MISSINGARGS": "Não foram oferecidos argumentos suficientes",
|
|
||||||
"COMMAND_NOACCESS": "Você não tem acesso a este comando",
|
|
||||||
"COMMAND_NOTAUTHORIZED": "Você não está autorizado a executar este comando",
|
|
||||||
"COMMAND_TARGET_MULTI": "Vários jogadores correspondem a esse nome",
|
|
||||||
"COMMAND_TARGET_NOTFOUND": "Não é possível encontrar o jogador especificado",
|
|
||||||
"COMMAND_UNKNOWN": "Você digitou um comando desconhecido",
|
|
||||||
"COMMANDS_ADMINS_DESC": "lista os clientes privilegiados conectados no momento",
|
|
||||||
"COMMANDS_ADMINS_NONE": "Não há administradores visíveis online",
|
|
||||||
"COMMANDS_ALIAS_ALIASES": "Nomes registrados",
|
|
||||||
"COMMANDS_ALIAS_DESC": "obtém a lista de histórico de nomes que o jogador usou no servidor",
|
|
||||||
"COMMANDS_ALIAS_IPS": "IPs",
|
|
||||||
"COMMANDS_ARGS_CLEAR": "apagar",
|
|
||||||
"COMMANDS_ARGS_CLIENTID": "id do jogador",
|
|
||||||
"COMMANDS_ARGS_COMMANDS": "comandos",
|
|
||||||
"COMMANDS_ARGS_DURATION": "duração (m|h|d|w|y)",
|
|
||||||
"COMMANDS_ARGS_INACTIVE": "dias inativos",
|
|
||||||
"COMMANDS_ARGS_LEVEL": "nível",
|
|
||||||
"COMMANDS_ARGS_MAP": "mapa",
|
|
||||||
"COMMANDS_ARGS_MESSAGE": "mensagem",
|
|
||||||
"COMMANDS_ARGS_PASSWORD": "senha",
|
|
||||||
"COMMANDS_ARGS_PLAYER": "jogador",
|
|
||||||
"COMMANDS_ARGS_REASON": "razão",
|
|
||||||
"COMMANDS_BAN_DESC": "banir permanentemente um cliente do servidor",
|
|
||||||
"COMMANDS_BAN_FAIL": "Você não pode banir permanentemente",
|
|
||||||
"COMMANDS_BAN_SUCCESS": "foi banido permanentemente",
|
|
||||||
"COMMANDS_BANINFO_DESC": "obtém informações sobre um banimento para um jogador",
|
|
||||||
"COMMANDS_BANINFO_NONE": "Nenhum banimento ativo foi encontrado para esse jogador",
|
|
||||||
"COMMANDS_BANINO_SUCCESS": "foi banido por ^5{0} ^7por:",
|
|
||||||
"COMMANDS_FASTRESTART_DESC": "reinicializa rapidamente o mapa atual, não recomendável o uso várias vezes seguidas",
|
|
||||||
"COMMANDS_FASTRESTART_MASKED": "O mapa foi reiniciado rapidamente",
|
|
||||||
"COMMANDS_FASTRESTART_UNMASKED": "reiniciou rapidamente o mapa",
|
|
||||||
"COMMANDS_FIND_DESC": "acha o jogador na base de dados",
|
|
||||||
"COMMANDS_FIND_EMPTY": "Nenhum jogador foi encontrado",
|
|
||||||
"COMMANDS_FIND_MIN": "Por favor, insira pelo menos 3 caracteres",
|
|
||||||
"COMMANDS_FLAG_DESC": "sinaliza um cliente suspeito e anuncia aos administradores ao entrar no servidor",
|
|
||||||
"COMMANDS_FLAG_FAIL": "Você não pode sinalizar",
|
|
||||||
"COMMANDS_FLAG_SUCCESS": "Você sinalizou",
|
|
||||||
"COMMANDS_FLAG_UNFLAG": "Você tirou a sinalização de",
|
|
||||||
"COMMANDS_HELP_DESC": "lista todos os comandos disponíveis",
|
|
||||||
"COMMANDS_HELP_MOREINFO": "Digite !help <comando> para saber como usar o comando",
|
|
||||||
"COMMANDS_HELP_NOTFOUND": "Não foi possível encontrar esse comando",
|
|
||||||
"COMMANDS_IP_DESC": "mostrar o seu endereço IP externo",
|
|
||||||
"COMMANDS_IP_SUCCESS": "Seu endereço IP externo é",
|
|
||||||
"COMMANDS_KICK_DESC": "expulsa o jogador pelo nome",
|
|
||||||
"COMMANDS_KICK_FAIL": "Você não tem os privilégios necessários para expulsar",
|
|
||||||
"COMMANDS_KICK_SUCCESS": "foi expulso",
|
|
||||||
"COMMANDS_LIST_DESC": "lista os jogadores ativos na partida",
|
|
||||||
"COMMANDS_MAP_DESC": "muda para o mapa especificado",
|
|
||||||
"COMMANDS_MAP_SUCCESS": "Mudando o mapa para",
|
|
||||||
"COMMANDS_MAP_UKN": "Tentando mudar para o mapa desconhecido",
|
|
||||||
"COMMANDS_MAPROTATE": "Rotacionando o mapa em ^55 ^7segundos",
|
|
||||||
"COMMANDS_MAPROTATE_DESC": "avança para o próximo mapa da rotação",
|
|
||||||
"COMMANDS_MASK_DESC": "esconde a sua presença como um jogador privilegiado",
|
|
||||||
"COMMANDS_MASK_OFF": "Você foi desmascarado",
|
|
||||||
"COMMANDS_MASK_ON": "Você agora está mascarado",
|
|
||||||
"COMMANDS_OWNER_DESC": "reivindica a propriedade do servidor",
|
|
||||||
"COMMANDS_OWNER_FAIL": "Este servidor já tem um dono",
|
|
||||||
"COMMANDS_OWNER_SUCCESS": "Parabéns, você reivindicou a propriedade deste servidor!",
|
|
||||||
"COMMANDS_PASSWORD_FAIL": "Sua senha deve ter pelo menos 5 caracteres",
|
|
||||||
"COMMANDS_PASSWORD_SUCCESS": "Sua senha foi configurada com sucesso",
|
|
||||||
"COMMANDS_PING_DESC": "mostra o quanto de latência tem o jogador",
|
|
||||||
"COMMANDS_PING_SELF": "Sua latência é",
|
|
||||||
"COMMANDS_PING_TARGET": "latência é",
|
|
||||||
"COMMANDS_PLUGINS_DESC": "mostra todos os plugins que estão carregados",
|
|
||||||
"COMMANDS_PLUGINS_LOADED": "Plugins carregados",
|
|
||||||
"COMMANDS_PM_DESC": "envia a mensagem para o outro jogador de maneira privada, use /!pm para ter efeito, se possível",
|
|
||||||
"COMMANDS_PRUNE_DESC": "rebaixa qualquer jogador privilegiado que não tenha se conectado recentemente (o padrão é 30 dias)",
|
|
||||||
"COMMANDS_PRUNE_FAIL": "Número inválido de dias ativo",
|
|
||||||
"COMMANDS_PRUNE_SUCCESS": "usuários privilegiados inativos foram removidos",
|
|
||||||
"COMMANDS_QUIT_DESC": "sair do IW4MAdmin",
|
|
||||||
"COMMANDS_RCON_DESC": "envia o comando Rcon para o servidor",
|
|
||||||
"COMMANDS_RCON_SUCCESS": "O comando para o RCon foi enviado com sucesso!",
|
|
||||||
"COMMANDS_REPORT_DESC": "denuncia o jogador por comportamento suspeito",
|
|
||||||
"COMMANDS_REPORT_FAIL": "Você não pode reportar",
|
|
||||||
"COMMANDS_REPORT_FAIL_CAMP": "Você não pode denunciar o jogador por camperar",
|
|
||||||
"COMMANDS_REPORT_FAIL_DUPLICATE": "Você já denunciou o jogador",
|
|
||||||
"COMMANDS_REPORT_FAIL_SELF": "Você não pode reportar a si mesmo",
|
|
||||||
"COMMANDS_REPORT_SUCCESS": "Obrigado pela sua denúncia, um administrador foi notificado",
|
|
||||||
"COMMANDS_REPORTS_CLEAR_SUCCESS": "Lista de denúncias limpa com sucesso",
|
|
||||||
"COMMANDS_REPORTS_DESC": "obtém ou limpa as denúncias recentes",
|
|
||||||
"COMMANDS_REPORTS_NONE": "Ninguém foi denunciado ainda",
|
|
||||||
"COMMANDS_RULES_DESC": "lista as regras do servidor",
|
|
||||||
"COMMANDS_RULES_NONE": "O proprietário do servidor não definiu nenhuma regra, sinta-se livre",
|
|
||||||
"COMMANDS_SAY_DESC": "transmite mensagem para todos os jogadores",
|
|
||||||
"COMMANDS_SETLEVEL_DESC": "define o jogador para o nível de privilégio especificado",
|
|
||||||
"COMMANDS_SETLEVEL_FAIL": "grupo especificado inválido",
|
|
||||||
"COMMANDS_SETLEVEL_LEVELTOOHIGH": "Você só pode promover do ^5{0} ^7para ^5{1} ^7ou um nível menor",
|
|
||||||
"COMMANDS_SETLEVEL_OWNER": "Só pode haver 1 dono. Modifique suas configurações se vários proprietários forem necessários",
|
|
||||||
"COMMANDS_SETLEVEL_SELF": "Você não pode mudar seu próprio nível",
|
|
||||||
"COMMANDS_SETLEVEL_STEPPEDDISABLED": "Este servidor não permite que você promova",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS": "foi promovido com sucesso",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS_TARGET": "Parabéns! Você foi promovido para",
|
|
||||||
"COMMANDS_SETPASSWORD_DESC": "define sua senha de autenticação",
|
|
||||||
"COMMANDS_TEMPBAN_DESC": "bane temporariamente um jogador por tempo especificado (o padrão é 1 hora)",
|
|
||||||
"COMMANDS_TEMPBAN_FAIL": "Você não pode banir temporariamente",
|
|
||||||
"COMMANDS_TEMPBAN_SUCCESS": "foi banido temporariamente por",
|
|
||||||
"COMMANDS_UNBAN_DESC": "retira o banimento de um jogador pelo seu ID",
|
|
||||||
"COMMANDS_UNBAN_FAIL": "não está banido",
|
|
||||||
"COMMANDS_UNBAN_SUCCESS": "Foi retirado o banimento com sucesso",
|
|
||||||
"COMMANDS_UPTIME_DESC": "obtém o tempo de execução do aplicativo a quando aberto",
|
|
||||||
"COMMANDS_UPTIME_TEXT": "está online por",
|
|
||||||
"COMMANDS_USAGE_DESC": "vê quanto o aplicativo está usando de memória RAM do seu computador",
|
|
||||||
"COMMANDS_USAGE_TEXT": "está usando",
|
|
||||||
"COMMANDS_WARN_DESC": "adverte o cliente por infringir as regras",
|
|
||||||
"COMMANDS_WARN_FAIL": "Você não tem os privilégios necessários para advertir",
|
|
||||||
"COMMANDS_WARNCLEAR_DESC": "remove todos os avisos para um cliente",
|
|
||||||
"COMMANDS_WARNCLEAR_SUCCESS": "Todos as advertências foram apagados para",
|
|
||||||
"COMMANDS_WHO_DESC": "dá informações sobre você",
|
|
||||||
"GLOBAL_TIME_DAYS": "dias",
|
|
||||||
"GLOBAL_ERROR": "Erro",
|
|
||||||
"GLOBAL_TIME_HOURS": "horas",
|
|
||||||
"GLOBAL_INFO": "Informação",
|
|
||||||
"GLOBAL_TIME_MINUTES": "minutos",
|
|
||||||
"GLOBAL_REPORT": "Se você está suspeitando alguém de alguma ^5TRAPAÇA ^7use o comando ^5!report",
|
|
||||||
"GLOBAL_VERBOSE": "Detalhe",
|
|
||||||
"GLOBAL_WARNING": "AVISO",
|
|
||||||
"MANAGER_CONNECTION_REST": "A conexão foi reestabelecida com",
|
|
||||||
"MANAGER_CONSOLE_NOSERV": "Não há servidores sendo monitorados neste momento",
|
|
||||||
"MANAGER_EXIT": "Pressione qualquer tecla para sair...",
|
|
||||||
"MANAGER_INIT_FAIL": "Erro fatal durante a inicialização",
|
|
||||||
"MANAGER_MONITORING_TEXT": "Agora monitorando",
|
|
||||||
"MANAGER_SHUTDOWN_SUCCESS": "Desligamento concluído",
|
|
||||||
"MANAGER_VERSION_CURRENT": "Está é a sua versão",
|
|
||||||
"MANAGER_VERSION_FAIL": "Não foi possível obter a versão mais recente do IW4MAdmin",
|
|
||||||
"MANAGER_VERSION_SUCCESS": "O IW4MAdmin está atualizado",
|
|
||||||
"MANAGER_VERSION_UPDATE": "Há uma atualização disponível. A versão mais recente é",
|
|
||||||
"PLUGIN_IMPORTER_NOTFOUND": "Não foram encontrados plugins para carregar",
|
|
||||||
"PLUGIN_IMPORTER_REGISTERCMD": "Comando registrado",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "Inicie a sua sessão usando a senha",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Sua senha está errada",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "Você agora está conectado",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_DESC": "reinicia suas estatísticas para uma nova",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_FAIL": "Você deve estar conectado a um servidor para reiniciar as suas estatísticas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Suas estatísticas nesse servidor foram reiniciadas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_DESC": "visualiza os 5 melhores jogadores do servidor",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_TEXT": "Top Jogadores",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_DESC": "mostra suas estatísticas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL": "Não foi encontrado o jogador que você especificou",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "o jogador especificado deve estar dentro do jogo",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Você deve estar no jogo para ver suas estatísticas",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Estatísticas para",
|
|
||||||
"PLUGINS_STATS_TEXT_DEATHS": "MORTES",
|
|
||||||
"PLUGINS_STATS_TEXT_KILLS": "BAIXAS",
|
|
||||||
"PLUGINS_STATS_TEXT_NOQUALIFY": "Não há ainda jogadores qualificados para os primeiros lugares",
|
|
||||||
"PLUGINS_STATS_TEXT_SKILL": "HABILIDADE",
|
|
||||||
"SERVER_BAN_APPEAL": "apele em",
|
|
||||||
"SERVER_BAN_PREV": "Banido preventivamente por",
|
|
||||||
"SERVER_BAN_TEXT": "Você está banido",
|
|
||||||
"SERVER_ERROR_ADDPLAYER": "Não foi possível adicionar o jogador",
|
|
||||||
"SERVER_ERROR_COMMAND_INGAME": "Ocorreu um erro interno ao processar seu comando",
|
|
||||||
"SERVER_ERROR_COMMAND_LOG": "o comando gerou um erro",
|
|
||||||
"SERVER_ERROR_COMMUNICATION": "Não foi possível fazer a comunicação com",
|
|
||||||
"SERVER_ERROR_DNE": "não existe",
|
|
||||||
"SERVER_ERROR_DVAR": "Não foi possível obter o valor de dvar para",
|
|
||||||
"SERVER_ERROR_DVAR_HELP": "garanta que o servidor tenha um mapa carregado",
|
|
||||||
"SERVER_ERROR_EXCEPTION": "Exceção inesperada em",
|
|
||||||
"SERVER_ERROR_LOG": "Log do jogo inválido",
|
|
||||||
"SERVER_ERROR_PLUGIN": "Ocorreu um erro ao carregar o plug-in",
|
|
||||||
"SERVER_ERROR_POLLING": "reduzir a taxa de sondagem do server",
|
|
||||||
"SERVER_ERROR_UNFIXABLE": "Não monitorando o servidor devido a erros incorrigíveis",
|
|
||||||
"SERVER_KICK_CONTROLCHARS": "Seu nome não pode conter caracteres de controle",
|
|
||||||
"SERVER_KICK_GENERICNAME": "Por favor, mude o seu nome usando o comando /name no console",
|
|
||||||
"SERVER_KICK_MINNAME": "Seu nome deve conter no mínimo três caracteres",
|
|
||||||
"SERVER_KICK_NAME_INUSE": "Seu nome já está sendo usado por outra pessoa",
|
|
||||||
"SERVER_KICK_TEXT": "Você foi expulso",
|
|
||||||
"SERVER_KICK_VPNS_NOTALLOWED": "VPNs não são permitidas neste servidor",
|
|
||||||
"SERVER_PLUGIN_ERROR": "Um plugin gerou erro",
|
|
||||||
"SERVER_REPORT_COUNT": "Você tem ^5{0} ^7denúncias recentes",
|
|
||||||
"SERVER_TB_REMAIN": "Você está banido temporariamente",
|
|
||||||
"SERVER_TB_TEXT": "Você está banido temporariamente",
|
|
||||||
"SERVER_WARNING": "AVISO",
|
|
||||||
"SERVER_WARNLIMT_REACHED": "Avisos demais! Leia o chat da próxima vez",
|
|
||||||
"SERVER_WEBSITE_GENERIC": "este é o site do servidor",
|
|
||||||
"SETUP_DISPLAY_SOCIAL": "Digitar link do convite do seu site no módulo da web (Discord, YouTube, etc.)",
|
|
||||||
"SETUP_ENABLE_CUSTOMSAY": "Habilitar a customização do nome do comando say",
|
|
||||||
"SETUP_ENABLE_MULTIOWN": "Habilitar vários proprietários",
|
|
||||||
"SETUP_ENABLE_STEPPEDPRIV": "Ativar hierarquia de privilégios escalonada",
|
|
||||||
"SETUP_ENABLE_VPNS": "Habilitar que os usuários usem VPN",
|
|
||||||
"SETUP_ENABLE_WEBFRONT": "Habilitar o módulo da web do IW4MAdmin",
|
|
||||||
"SETUP_ENCODING_STRING": "Digite sequência de codificação",
|
|
||||||
"SETUP_IPHUB_KEY": "Digite iphub.info api key",
|
|
||||||
"SETUP_SAY_NAME": "Habilitar a customização do nome do comando say",
|
|
||||||
"SETUP_SERVER_IP": "Digite o endereço IP do servidor",
|
|
||||||
"SETUP_SERVER_MANUALLOG": "Insira o caminho do arquivo de log manualmente",
|
|
||||||
"SETUP_SERVER_PORT": "Digite a porta do servidor",
|
|
||||||
"SETUP_SERVER_RCON": "Digite a senha do RCon do servidor",
|
|
||||||
"SETUP_SERVER_SAVE": "Configuração salva, adicionar outra",
|
|
||||||
"SETUP_SERVER_USEIW5M": "Usar analisador Pluto IW5 ",
|
|
||||||
"SETUP_SERVER_USET6M": "Usar analisador Pluto T6 ",
|
|
||||||
"SETUP_SOCIAL_LINK": "Digite o link da Rede Social",
|
|
||||||
"SETUP_SOCIAL_TITLE": "Digite o nome da rede social",
|
|
||||||
"SETUP_USE_CUSTOMENCODING": "Usar o analisador de codificação customizado",
|
|
||||||
"WEBFRONT_ACTION_BAN_NAME": "Banir",
|
|
||||||
"WEBFRONT_ACTION_LABEL_ID": "ID do cliente",
|
|
||||||
"WEBFRONT_ACTION_LABEL_PASSWORD": "Senha",
|
|
||||||
"WEBFRONT_ACTION_LABEL_REASON": "Razão",
|
|
||||||
"WEBFRONT_ACTION_LOGIN_NAME": "Iniciar a sessão",
|
|
||||||
"WEBFRONT_ACTION_UNBAN_NAME": "Retirar o banimento",
|
|
||||||
"WEBFRONT_CLIENT_META_FALSE": "Não está",
|
|
||||||
"WEBFRONT_CLIENT_META_JOINED": "Entrou com o nome",
|
|
||||||
"WEBFRONT_CLIENT_META_MASKED": "Mascarado",
|
|
||||||
"WEBFRONT_CLIENT_META_TRUE": "Está",
|
|
||||||
"WEBFRONT_CLIENT_PRIVILEGED_TITLE": "Jogadores Privilegiados",
|
|
||||||
"WEBFRONT_CLIENT_PROFILE_TITLE": "Pefil",
|
|
||||||
"WEBFRONT_CLIENT_SEARCH_MATCHING": "Jogadores correspondidos",
|
|
||||||
"WEBFRONT_CONSOLE_EXECUTE": "Executar",
|
|
||||||
"WEBFRONT_CONSOLE_TITLE": "Console da Web",
|
|
||||||
"WEBFRONT_ERROR_DESC": "O IW4MAdmin encontrou um erro",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_DESC": "Ocorreu um erro ao processar seu pedido",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_TITLE": "Desculpe!",
|
|
||||||
"WEBFRONT_ERROR_TITLE": "Erro!",
|
|
||||||
"WEBFRONT_HOME_TITLE": "Visão geral do servidor",
|
|
||||||
"WEBFRONT_NAV_CONSOLE": "Console",
|
|
||||||
"WEBFRONT_NAV_DISCORD": "Discord",
|
|
||||||
"WEBFRONT_NAV_HOME": "Início",
|
|
||||||
"WEBFRONT_NAV_LOGOUT": "Encerrar a sessão",
|
|
||||||
"WEBFRONT_NAV_PENALTIES": "Penalidades",
|
|
||||||
"WEBFRONT_NAV_PRIVILEGED": "Administradores",
|
|
||||||
"WEBFRONT_NAV_PROFILE": "Perfil do Jogador",
|
|
||||||
"WEBFRONT_NAV_SEARCH": "Achar jogador",
|
|
||||||
"WEBFRONT_NAV_SOCIAL": "Rede Social",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_ADMIN": "Administrador",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_AGO": "atrás",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_NAME": "Nome",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_OFFENSE": "Ofensa",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_REMAINING": "restantes",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOW": "Mostrar",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOWONLY": "Mostrar somente",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TIME": "Tempo/Restante",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TYPE": "Tipo",
|
|
||||||
"WEBFRONT_PENALTY_TITLE": "Penalidades dos jogadores",
|
|
||||||
"WEBFRONT_PROFILE_FSEEN": "Visto primeiro em",
|
|
||||||
"WEBFRONT_PROFILE_LEVEL": "Nível",
|
|
||||||
"WEBFRONT_PROFILE_LSEEN": "Visto por último em",
|
|
||||||
"WEBFRONT_PROFILE_PLAYER": "Jogou",
|
|
||||||
"PLUGIN_STATS_SETUP_ENABLEAC": "Habilitar a anti-trapaça no servidor (Somente IW4/MW2)",
|
|
||||||
"PLUGIN_STATS_ERROR_ADD": "Não foi possível adicionar o servidor para as estatísticas do servidor",
|
|
||||||
"PLUGIN_STATS_CHEAT_DETECTED": "Aparentemente você está trapaceando",
|
|
||||||
"PLUGINS_STATS_TEXT_KDR": "KDR",
|
|
||||||
"PLUGINS_STATS_META_SPM": "Pontuação por minuto",
|
|
||||||
"PLUGINS_WELCOME_USERANNOUNCE": "^5{{ClientName}} ^7 vem de ^5{{ClientLocation}}",
|
|
||||||
"PLUGINS_WELCOME_USERWELCOME": "Bem-vindo ^5{{ClientName}}^7, esta é a sua visita de número ^5{{TimesConnected}} ^7 no servidor!",
|
|
||||||
"PLUGINS_WELCOME_PRIVANNOUNCE": "{{ClientLevel}} {{ClientName}} entrou no servidor",
|
|
||||||
"PLUGINS_LOGIN_AUTH": "não está registrado",
|
|
||||||
"PLUGINS_PROFANITY_SETUP_ENABLE": "Habilitar o plugin de anti-palavrão",
|
|
||||||
"PLUGINS_PROFANITY_WARNMSG": "Por favor, não use palavras ofensivas neste servidor",
|
|
||||||
"PLUGINS_PROFANITY_KICKMSG": "Uso excessivo de palavrão, lave a boca da próxima vez",
|
|
||||||
"GLOBAL_DEBUG": "Depuração",
|
|
||||||
"COMMANDS_UNFLAG_DESC": "Remover a sinalização do jogador",
|
|
||||||
"COMMANDS_UNFLAG_FAIL": "Você não pode retirar a sinalização do jogador",
|
|
||||||
"COMMANDS_UNFLAG_NOTFLAGGED": "O jogador não está sinalizado",
|
|
||||||
"COMMANDS_FLAG_ALREADYFLAGGED": "O jogador já está sinalizado",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT": "Mais jogado",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_DESC": "ver o top 5 de jogadores mais dedicados no servidor",
|
|
||||||
"WEBFRONT_PROFILE_MESSAGES": "Mensagens",
|
|
||||||
"WEBFRONT_CLIENT_META_CONNECTIONS": "Conexões",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOPSTATS_RATING": "Classificação",
|
|
||||||
"PLUGINS_STATS_COMMANDS_PERFORMANCE": "Desempenho"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,269 +0,0 @@
|
|||||||
{
|
|
||||||
"LocalizationName": "ru-RU",
|
|
||||||
"LocalizationIndex": {
|
|
||||||
"Set": {
|
|
||||||
"BROADCAST_OFFLINE": "^5IW4MAdmin ^1ВЫКЛЮЧАЕТСЯ",
|
|
||||||
"BROADCAST_ONLINE": "^5IW4MADMIN ^7сейчас В СЕТИ",
|
|
||||||
"COMMAND_HELP_OPTIONAL": "опционально",
|
|
||||||
"COMMAND_HELP_SYNTAX": "Проблема с выражением мысли ( пересмотри слова)",
|
|
||||||
"COMMAND_MISSINGARGS": "Приведено недостаточно аргументов",
|
|
||||||
"COMMAND_NOACCESS": "У вас нет доступа к этой команде",
|
|
||||||
"COMMAND_NOTAUTHORIZED": "Вы не авторизованы для исполнения этой команды",
|
|
||||||
"COMMAND_TARGET_MULTI": "Несколько игроков соответствуют этому имени",
|
|
||||||
"COMMAND_TARGET_NOTFOUND": "Невозможно найти указанного игрока",
|
|
||||||
"COMMAND_UNKNOWN": "Вы ввели неизвестную команду",
|
|
||||||
"COMMANDS_ADMINS_DESC": "перечислить присоединенных на данный момент игроков с правами",
|
|
||||||
"COMMANDS_ADMINS_NONE": "Нет видимых администраторов в сети",
|
|
||||||
"COMMANDS_ALIAS_ALIASES": "Имена",
|
|
||||||
"COMMANDS_ALIAS_DESC": "получить прошлые имена и IP игрока",
|
|
||||||
"COMMANDS_ALIAS_IPS": "IP",
|
|
||||||
"COMMANDS_ARGS_CLEAR": "очистить",
|
|
||||||
"COMMANDS_ARGS_CLIENTID": "ID игрока",
|
|
||||||
"COMMANDS_ARGS_COMMANDS": "команды",
|
|
||||||
"COMMANDS_ARGS_DURATION": "длительность (m|h|d|w|y)",
|
|
||||||
"COMMANDS_ARGS_INACTIVE": "дни бездействия",
|
|
||||||
"COMMANDS_ARGS_LEVEL": "уровень",
|
|
||||||
"COMMANDS_ARGS_MAP": "карта",
|
|
||||||
"COMMANDS_ARGS_MESSAGE": "сообщение",
|
|
||||||
"COMMANDS_ARGS_PASSWORD": "пароль",
|
|
||||||
"COMMANDS_ARGS_PLAYER": "игрок",
|
|
||||||
"COMMANDS_ARGS_REASON": "причина",
|
|
||||||
"COMMANDS_BAN_DESC": "навсегда забанить игрока на сервере",
|
|
||||||
"COMMANDS_BAN_FAIL": "Вы не можете выдавать бан",
|
|
||||||
"COMMANDS_BAN_SUCCESS": "был забанен навсегда",
|
|
||||||
"COMMANDS_BANINFO_DESC": "получить информацию о бане игрока",
|
|
||||||
"COMMANDS_BANINFO_NONE": "Не найдено действующего бана для этого игрока",
|
|
||||||
"COMMANDS_BANINO_SUCCESS": "был забанен игроком ^5{0} ^7на:",
|
|
||||||
"COMMANDS_FASTRESTART_DESC": "перезапустить нынешнюю карту",
|
|
||||||
"COMMANDS_FASTRESTART_MASKED": "Карта была перезапущена",
|
|
||||||
"COMMANDS_FASTRESTART_UNMASKED": "перезапустил карту",
|
|
||||||
"COMMANDS_FIND_DESC": "найти игрока в базе данных",
|
|
||||||
"COMMANDS_FIND_EMPTY": "Не найдено игроков",
|
|
||||||
"COMMANDS_FIND_MIN": "Пожалуйста, введите хотя бы 3 символа",
|
|
||||||
"COMMANDS_FLAG_DESC": "отметить подозрительного игрока и сообщить администраторам, чтобы присоединились",
|
|
||||||
"COMMANDS_FLAG_FAIL": "Вы не можете ставить отметки",
|
|
||||||
"COMMANDS_FLAG_SUCCESS": "Вы отметили",
|
|
||||||
"COMMANDS_FLAG_UNFLAG": "Вы сняли отметку",
|
|
||||||
"COMMANDS_HELP_DESC": "перечислить все доступные команды",
|
|
||||||
"COMMANDS_HELP_MOREINFO": "Введите !help <имя команды>, чтобы узнать синтаксис для использования команды",
|
|
||||||
"COMMANDS_HELP_NOTFOUND": "Не удалось найти эту команду",
|
|
||||||
"COMMANDS_IP_DESC": "просмотреть ваш внешний IP-адрес",
|
|
||||||
"COMMANDS_IP_SUCCESS": "Ваш внешний IP:",
|
|
||||||
"COMMANDS_KICK_DESC": "исключить игрока по имени",
|
|
||||||
"COMMANDS_KICK_FAIL": "У вас нет достаточных прав, чтобы исключать",
|
|
||||||
"COMMANDS_KICK_SUCCESS": "был исключен",
|
|
||||||
"COMMANDS_LIST_DESC": "перечислить действующих игроков",
|
|
||||||
"COMMANDS_MAP_DESC": "сменить на определенную карту",
|
|
||||||
"COMMANDS_MAP_SUCCESS": "Смена карты на",
|
|
||||||
"COMMANDS_MAP_UKN": "Попытка сменить на неизвестную карту",
|
|
||||||
"COMMANDS_MAPROTATE": "Смена карты через ^55 ^7секунд",
|
|
||||||
"COMMANDS_MAPROTATE_DESC": "переключиться на следующую карту в ротации",
|
|
||||||
"COMMANDS_MASK_DESC": "скрыть свое присутствие как игрока с правами",
|
|
||||||
"COMMANDS_MASK_OFF": "Вы теперь демаскированы",
|
|
||||||
"COMMANDS_MASK_ON": "Вы теперь замаскированы",
|
|
||||||
"COMMANDS_OWNER_DESC": "утверить владение сервером",
|
|
||||||
"COMMANDS_OWNER_FAIL": "Этот сервер уже имеет владельца",
|
|
||||||
"COMMANDS_OWNER_SUCCESS": "Поздравляю, вы утвердили владение этим сервером!",
|
|
||||||
"COMMANDS_PASSWORD_FAIL": "Ваш пароль должен быть хотя бы 5 символов в длину",
|
|
||||||
"COMMANDS_PASSWORD_SUCCESS": "Ваш пароль был успешно установлен",
|
|
||||||
"COMMANDS_PING_DESC": "получить пинг игрока",
|
|
||||||
"COMMANDS_PING_SELF": "Ваш пинг:",
|
|
||||||
"COMMANDS_PING_TARGET": "пинг:",
|
|
||||||
"COMMANDS_PLUGINS_DESC": "просмотреть все загруженные плагины",
|
|
||||||
"COMMANDS_PLUGINS_LOADED": "Загруженные плагины",
|
|
||||||
"COMMANDS_PM_DESC": "отправить сообщение другому игроку",
|
|
||||||
"COMMANDS_PRUNE_DESC": "понизить любых игроков с правами, которые не подключались за последнее время (по умолчанию: 30 дней)",
|
|
||||||
"COMMANDS_PRUNE_FAIL": "Неверное количество дней бездействия",
|
|
||||||
"COMMANDS_PRUNE_SUCCESS": "бездействующих пользователей с правами было сокращено",
|
|
||||||
"COMMANDS_QUIT_DESC": "покинуть IW4MAdmin",
|
|
||||||
"COMMANDS_RCON_DESC": "отправить RCon команду на сервер",
|
|
||||||
"COMMANDS_RCON_SUCCESS": "Успешно отправлена команда RCon",
|
|
||||||
"COMMANDS_REPORT_DESC": "пожаловаться на игрока за подозрительное поведение",
|
|
||||||
"COMMANDS_REPORT_FAIL": "Вы не можете пожаловаться",
|
|
||||||
"COMMANDS_REPORT_FAIL_CAMP": "Вы не можете пожаловаться на игрока за кемперство",
|
|
||||||
"COMMANDS_REPORT_FAIL_DUPLICATE": "Вы уже пожаловались на этого игрока",
|
|
||||||
"COMMANDS_REPORT_FAIL_SELF": "Вы не можете пожаловаться на самого себя",
|
|
||||||
"COMMANDS_REPORT_SUCCESS": "Спасибо за вашу жалобу, администратор оповещен",
|
|
||||||
"COMMANDS_REPORTS_CLEAR_SUCCESS": "Жалобы успешно очищены",
|
|
||||||
"COMMANDS_REPORTS_DESC": "получить или очистить последние жалобы",
|
|
||||||
"COMMANDS_REPORTS_NONE": "Пока нет жалоб на игроков",
|
|
||||||
"COMMANDS_RULES_DESC": "перечислить правила сервера",
|
|
||||||
"COMMANDS_RULES_NONE": "Владелец сервера не установил никаких правил",
|
|
||||||
"COMMANDS_SAY_DESC": "транслировать сообщения всем игрокам",
|
|
||||||
"COMMANDS_SETLEVEL_DESC": "установить особый уровень прав игроку",
|
|
||||||
"COMMANDS_SETLEVEL_FAIL": "Указана неверная группа",
|
|
||||||
"COMMANDS_SETLEVEL_LEVELTOOHIGH": "Вы только можете повысить ^5{0} ^7до ^5{1} ^7или понизить в правах",
|
|
||||||
"COMMANDS_SETLEVEL_OWNER": "Может быть только 1 владелец. Измените настройки, если требуется несколько владельцов",
|
|
||||||
"COMMANDS_SETLEVEL_SELF": "Вы не можете изменить свой уровень",
|
|
||||||
"COMMANDS_SETLEVEL_STEPPEDDISABLED": "Этот сервер не разрешает вам повыситься",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS": "был успешно повышен",
|
|
||||||
"COMMANDS_SETLEVEL_SUCCESS_TARGET": "Поздравляю! Вы были повышены до",
|
|
||||||
"COMMANDS_SETPASSWORD_DESC": "установить свой пароль аутентификации",
|
|
||||||
"COMMANDS_TEMPBAN_DESC": "временно забанить игрока на определенное время (по умолчанию: 1 час)",
|
|
||||||
"COMMANDS_TEMPBAN_FAIL": "Вы не можете выдавать временный бан",
|
|
||||||
"COMMANDS_TEMPBAN_SUCCESS": "был временно забанен за",
|
|
||||||
"COMMANDS_UNBAN_DESC": "разбанить игрока по ID игрока",
|
|
||||||
"COMMANDS_UNBAN_FAIL": "не забанен",
|
|
||||||
"COMMANDS_UNBAN_SUCCESS": "Успешно разбанен",
|
|
||||||
"COMMANDS_UPTIME_DESC": "получить время с начала запуска текущего приложения",
|
|
||||||
"COMMANDS_UPTIME_TEXT": "был в сети",
|
|
||||||
"COMMANDS_USAGE_DESC": "узнать о потреблении памяти приложением",
|
|
||||||
"COMMANDS_USAGE_TEXT": "используется",
|
|
||||||
"COMMANDS_WARN_DESC": "предупредить игрока за нарушение правил",
|
|
||||||
"COMMANDS_WARN_FAIL": "У вас недостаточно прав, чтобы выносить предупреждения",
|
|
||||||
"COMMANDS_WARNCLEAR_DESC": "удалить все предупреждения у игрока",
|
|
||||||
"COMMANDS_WARNCLEAR_SUCCESS": "Все предупреждения очищены у",
|
|
||||||
"COMMANDS_WHO_DESC": "предоставить информацию о себе",
|
|
||||||
"GLOBAL_TIME_DAYS": "дней",
|
|
||||||
"GLOBAL_ERROR": "Ошибка",
|
|
||||||
"GLOBAL_TIME_HOURS": "часов",
|
|
||||||
"GLOBAL_INFO": "Информация",
|
|
||||||
"GLOBAL_TIME_MINUTES": "минут",
|
|
||||||
"GLOBAL_REPORT": "Если вы подозреваете кого-то в ^5ЧИТЕРСТВЕ^7, используйте команду ^5!report",
|
|
||||||
"GLOBAL_VERBOSE": "Подробно",
|
|
||||||
"GLOBAL_WARNING": "Предупреждение",
|
|
||||||
"MANAGER_CONNECTION_REST": "Соединение было восстановлено с помощью",
|
|
||||||
"MANAGER_CONSOLE_NOSERV": "На данный момент нет серверов под мониторингом",
|
|
||||||
"MANAGER_EXIT": "Нажмите любую клавишу, чтобы выйти...",
|
|
||||||
"MANAGER_INIT_FAIL": "Критическая ошибка во время инициализации",
|
|
||||||
"MANAGER_MONITORING_TEXT": "Идет мониторинг",
|
|
||||||
"MANAGER_SHUTDOWN_SUCCESS": "Выключение завершено",
|
|
||||||
"MANAGER_VERSION_CURRENT": "Ваша версия:",
|
|
||||||
"MANAGER_VERSION_FAIL": "Не удалось получить последнюю версию IW4MAdmin",
|
|
||||||
"MANAGER_VERSION_SUCCESS": "IW4MAdmin обновлен",
|
|
||||||
"MANAGER_VERSION_UPDATE": "- есть обновление. Последняя версия:",
|
|
||||||
"PLUGIN_IMPORTER_NOTFOUND": "Не найдено плагинов для загрузки",
|
|
||||||
"PLUGIN_IMPORTER_REGISTERCMD": "Зарегистрированная команда",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_DESC": "войти, используя пароль",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL": "Ваш пароль неверный",
|
|
||||||
"PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS": "Вы теперь вошли",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_DESC": "сбросить вашу статистику под ноль",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_FAIL": "Вы должны быть подключены к серверу, чтобы сбросить свою статистику",
|
|
||||||
"PLUGINS_STATS_COMMANDS_RESET_SUCCESS": "Ваша статистика на этом сервере была сброшена",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_DESC": "показать топ-5 лучших игроков на этом сервере",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOP_TEXT": "Лучшие игроки",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_DESC": "просмотреть свою статистику",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL": "Не удается найти игрока, которого вы указали.",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME": "Указанный игрок должен быть в игре",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF": "Вы должны быть в игре, чтобы просмотреть свою статистику",
|
|
||||||
"PLUGINS_STATS_COMMANDS_VIEW_SUCCESS": "Статистика",
|
|
||||||
"PLUGINS_STATS_TEXT_DEATHS": "СМЕРТЕЙ",
|
|
||||||
"PLUGINS_STATS_TEXT_KILLS": "УБИЙСТВ",
|
|
||||||
"PLUGINS_STATS_TEXT_NOQUALIFY": "Ещё нет совернующихся игроков за лучшую статистику",
|
|
||||||
"PLUGINS_STATS_TEXT_SKILL": "МАСТЕРСТВО",
|
|
||||||
"SERVER_BAN_APPEAL": "оспорить:",
|
|
||||||
"SERVER_BAN_PREV": "Ранее забанены за",
|
|
||||||
"SERVER_BAN_TEXT": "Вы забанены",
|
|
||||||
"SERVER_ERROR_ADDPLAYER": "Не удалось добавить игрока",
|
|
||||||
"SERVER_ERROR_COMMAND_INGAME": "Произошла внутренняя ошибка при обработке вашей команды",
|
|
||||||
"SERVER_ERROR_COMMAND_LOG": "команда сгенерировала ошибку",
|
|
||||||
"SERVER_ERROR_COMMUNICATION": "Не удалось связаться с",
|
|
||||||
"SERVER_ERROR_DNE": "не существует",
|
|
||||||
"SERVER_ERROR_DVAR": "Не удалось получить значение dvar:",
|
|
||||||
"SERVER_ERROR_DVAR_HELP": "убедитесь, что на сервере загружена карта",
|
|
||||||
"SERVER_ERROR_EXCEPTION": "Неожиданное исключение на",
|
|
||||||
"SERVER_ERROR_LOG": "Неверный игровой лог-файл",
|
|
||||||
"SERVER_ERROR_PLUGIN": "Произошла ошибка загрузки плагина",
|
|
||||||
"SERVER_ERROR_POLLING": "снижение частоты обновления данных",
|
|
||||||
"SERVER_ERROR_UNFIXABLE": "Мониторинг сервера выключен из-за неисправимых ошибок",
|
|
||||||
"SERVER_KICK_CONTROLCHARS": "Ваше имя не должно содержать спецсимволы",
|
|
||||||
"SERVER_KICK_GENERICNAME": "Пожалуйста, смените ваше имя, используя /name",
|
|
||||||
"SERVER_KICK_MINNAME": "Ваше имя должно содержать хотя бы 3 символа",
|
|
||||||
"SERVER_KICK_NAME_INUSE": "Ваше имя используется кем-то другим",
|
|
||||||
"SERVER_KICK_TEXT": "Вы были исключены",
|
|
||||||
"SERVER_KICK_VPNS_NOTALLOWED": "Использование VPN не разрешено на этом сервере",
|
|
||||||
"SERVER_PLUGIN_ERROR": "Плагин образовал ошибку",
|
|
||||||
"SERVER_REPORT_COUNT": "Имеется ^5{0} ^7жалоб за последнее время",
|
|
||||||
"SERVER_TB_REMAIN": "Вы временно забанены",
|
|
||||||
"SERVER_TB_TEXT": "Вы временно забанены",
|
|
||||||
"SERVER_WARNING": "ПРЕДУПРЕЖДЕНИЕ",
|
|
||||||
"SERVER_WARNLIMT_REACHED": "Слишком много предупреждений",
|
|
||||||
"SERVER_WEBSITE_GENERIC": "веб-сайт этого сервера",
|
|
||||||
"SETUP_DISPLAY_SOCIAL": "Отображать ссылку на социальную сеть в веб-интерфейсе (Discord, веб-сайт, ВК, и т.д.)",
|
|
||||||
"SETUP_ENABLE_CUSTOMSAY": "Включить кастомное имя для чата",
|
|
||||||
"SETUP_ENABLE_MULTIOWN": "Включить поддержку нескольких владельцев",
|
|
||||||
"SETUP_ENABLE_STEPPEDPRIV": "Включить последовательную иерархию прав",
|
|
||||||
"SETUP_ENABLE_VPNS": "Включить поддержку VPN у игроков",
|
|
||||||
"SETUP_ENABLE_WEBFRONT": "Включить веб-интерфейс",
|
|
||||||
"SETUP_ENCODING_STRING": "Введите кодировку",
|
|
||||||
"SETUP_IPHUB_KEY": "Введите iphub.info api-ключ",
|
|
||||||
"SETUP_SAY_NAME": "Введите кастомное имя для чата",
|
|
||||||
"SETUP_SERVER_IP": "Введите IP-адрес сервера",
|
|
||||||
"SETUP_SERVER_MANUALLOG": "Введите путь для лог-файла",
|
|
||||||
"SETUP_SERVER_PORT": "Введите порт сервера",
|
|
||||||
"SETUP_SERVER_RCON": "Введите RCon пароль сервера",
|
|
||||||
"SETUP_SERVER_SAVE": "Настройки сохранены, добавить",
|
|
||||||
"SETUP_SERVER_USEIW5M": "Использовать парсер Pluto IW5",
|
|
||||||
"SETUP_SERVER_USET6M": "Использовать парсер Pluto T6",
|
|
||||||
"SETUP_SOCIAL_LINK": "Ввести ссылку на социальную сеть",
|
|
||||||
"SETUP_SOCIAL_TITLE": "Ввести имя социальной сети",
|
|
||||||
"SETUP_USE_CUSTOMENCODING": "Использовать кастомную кодировку парсера",
|
|
||||||
"WEBFRONT_ACTION_BAN_NAME": "Забанить",
|
|
||||||
"WEBFRONT_ACTION_LABEL_ID": "ID игрока",
|
|
||||||
"WEBFRONT_ACTION_LABEL_PASSWORD": "Пароль",
|
|
||||||
"WEBFRONT_ACTION_LABEL_REASON": "Причина",
|
|
||||||
"WEBFRONT_ACTION_LOGIN_NAME": "Войти",
|
|
||||||
"WEBFRONT_ACTION_UNBAN_NAME": "Разбанить",
|
|
||||||
"WEBFRONT_CLIENT_META_FALSE": "не",
|
|
||||||
"WEBFRONT_CLIENT_META_JOINED": "Присоединился с именем",
|
|
||||||
"WEBFRONT_CLIENT_META_MASKED": "Замаскирован",
|
|
||||||
"WEBFRONT_CLIENT_META_TRUE": "Это",
|
|
||||||
"WEBFRONT_CLIENT_PRIVILEGED_TITLE": "Игроки с правами",
|
|
||||||
"WEBFRONT_CLIENT_PROFILE_TITLE": "Профиль",
|
|
||||||
"WEBFRONT_CLIENT_SEARCH_MATCHING": "Подходящие игроки",
|
|
||||||
"WEBFRONT_CONSOLE_EXECUTE": "Выполнить",
|
|
||||||
"WEBFRONT_CONSOLE_TITLE": "Веб-консоль",
|
|
||||||
"WEBFRONT_ERROR_DESC": "IW4MAdmin столкнулся с ошибкой",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_DESC": "Произошла ошибка во время обработки вашего запроса",
|
|
||||||
"WEBFRONT_ERROR_GENERIC_TITLE": "Извините!",
|
|
||||||
"WEBFRONT_ERROR_TITLE": "Ошибка!",
|
|
||||||
"WEBFRONT_HOME_TITLE": "Обзор сервера",
|
|
||||||
"WEBFRONT_NAV_CONSOLE": "Консоль",
|
|
||||||
"WEBFRONT_NAV_DISCORD": "Дискорд ",
|
|
||||||
"WEBFRONT_NAV_HOME": "Обзор Серверов ",
|
|
||||||
"WEBFRONT_NAV_LOGOUT": "Выйти",
|
|
||||||
"WEBFRONT_NAV_PENALTIES": "Наказания",
|
|
||||||
"WEBFRONT_NAV_PRIVILEGED": "Админы",
|
|
||||||
"WEBFRONT_NAV_PROFILE": "Профиль игрока",
|
|
||||||
"WEBFRONT_NAV_SEARCH": "Найти игрока",
|
|
||||||
"WEBFRONT_NAV_SOCIAL": "Соц. сети",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_ADMIN": "Админ",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_AGO": "назад",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_NAME": "Имя",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_OFFENSE": "Нарушение",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_REMAINING": "осталось",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOW": "Показывать",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_SHOWONLY": "Показывать только",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TIME": "Время/Осталось",
|
|
||||||
"WEBFRONT_PENALTY_TEMPLATE_TYPE": "Тип",
|
|
||||||
"WEBFRONT_PENALTY_TITLE": "Наказания игроков",
|
|
||||||
"WEBFRONT_PROFILE_FSEEN": "Впервые заходил",
|
|
||||||
"WEBFRONT_PROFILE_LEVEL": "Уровень",
|
|
||||||
"WEBFRONT_PROFILE_LSEEN": "Последний раз заходил",
|
|
||||||
"WEBFRONT_PROFILE_PLAYER": "Наиграл",
|
|
||||||
"PLUGIN_STATS_SETUP_ENABLEAC": "Включить серверный античит (только IW4)",
|
|
||||||
"PLUGIN_STATS_ERROR_ADD": "Не удалось добавить сервер в статистику серверов",
|
|
||||||
"PLUGIN_STATS_CHEAT_DETECTED": "Кажется, вы читерите",
|
|
||||||
"PLUGINS_STATS_TEXT_KDR": "Вот так ..",
|
|
||||||
"PLUGINS_STATS_META_SPM": "Счёт за минуту",
|
|
||||||
"PLUGINS_WELCOME_USERANNOUNCE": "^5{{ClientName}} ^7из ^5{{ClientLocation}}",
|
|
||||||
"PLUGINS_WELCOME_USERWELCOME": "Добро пожаловать, ^5{{ClientName}}^7. Это ваше ^5{{TimesConnected}} ^7подключение по счёту!",
|
|
||||||
"PLUGINS_WELCOME_PRIVANNOUNCE": "{{ClientLevel}} {{ClientName}} присоединился к серверу",
|
|
||||||
"PLUGINS_LOGIN_AUTH": "Сперва Подключись",
|
|
||||||
"PLUGINS_PROFANITY_SETUP_ENABLE": "Включить сдерживание ненормативной лексики",
|
|
||||||
"PLUGINS_PROFANITY_WARNMSG": "Пожалуйта, не ругайтесь на этом сервере",
|
|
||||||
"PLUGINS_PROFANITY_KICKMSG": "Чрезмерное употребление ненормативной лексики",
|
|
||||||
"GLOBAL_DEBUG": "Отлаживание ",
|
|
||||||
"COMMANDS_UNFLAG_DESC": "Снять все подозрение с игрока !",
|
|
||||||
"COMMANDS_UNFLAG_FAIL": "Вы не можете снять подозрения..",
|
|
||||||
"COMMANDS_UNFLAG_NOTFLAGGED": "Игрок без подозрения !",
|
|
||||||
"COMMANDS_FLAG_ALREADYFLAGGED": "Игрок помечен ! ",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_TEXT": "Самые популярные",
|
|
||||||
"PLUGINS_STATS_COMMANDS_MOSTPLAYED_DESC": "просмотр 5 лучших игроков на сервере",
|
|
||||||
"WEBFRONT_PROFILE_MESSAGES": "Сообщения",
|
|
||||||
"WEBFRONT_CLIENT_META_CONNECTIONS": "Подключения",
|
|
||||||
"PLUGINS_STATS_COMMANDS_TOPSTATS_RATING": "Рейтинг",
|
|
||||||
"PLUGINS_STATS_COMMANDS_PERFORMANCE": "Эффективность"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -34,10 +34,11 @@ namespace IW4MAdmin.Application
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ServerManager = ApplicationManager.GetInstance();
|
ServerManager = ApplicationManager.GetInstance();
|
||||||
|
var configuration = ServerManager.GetApplicationSettings().Configuration();
|
||||||
|
|
||||||
if (ServerManager.GetApplicationSettings().Configuration() != null)
|
if (configuration != null)
|
||||||
{
|
{
|
||||||
Localization.Configure.Initialize(ServerManager.GetApplicationSettings().Configuration().CustomLocale);
|
Localization.Configure.Initialize(configuration.EnableCustomLocale ? (configuration.CustomLocale ?? "windows-1252") : "windows-1252");
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -90,7 +91,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString("0.0")}]");
|
Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString("0.0")}]");
|
||||||
Console.WriteLine($"{loc["MANAGER_VERSION_CURRENT"]} [v{Version.ToString("0.0")}]");
|
Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString("0.0")}]"));
|
||||||
Console.ForegroundColor = ConsoleColor.Gray;
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -98,7 +99,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.ToString("0.0")}-pr]");
|
Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.ToString("0.0")}-pr]");
|
||||||
Console.WriteLine($"{loc["MANAGER_VERSION_CURRENT"]} [v{Version.ToString("0.0")}-pr]");
|
Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString("0.0")}-pr]"));
|
||||||
Console.ForegroundColor = ConsoleColor.Gray;
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Helpers;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
@ -10,16 +11,9 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<long, TokenState> _tokens;
|
private readonly ConcurrentDictionary<long, TokenState> _tokens;
|
||||||
private readonly RNGCryptoServiceProvider _random;
|
private readonly RNGCryptoServiceProvider _random;
|
||||||
private readonly static TimeSpan _timeoutPeriod = new TimeSpan(0, 0, 30);
|
private readonly static TimeSpan _timeoutPeriod = new TimeSpan(0, 0, 120);
|
||||||
private const short TOKEN_LENGTH = 4;
|
private const short TOKEN_LENGTH = 4;
|
||||||
|
|
||||||
private class TokenState
|
|
||||||
{
|
|
||||||
public long NetworkId { get; set; }
|
|
||||||
public DateTime RequestTime { get; set; } = DateTime.Now;
|
|
||||||
public string Token { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public TokenAuthentication()
|
public TokenAuthentication()
|
||||||
{
|
{
|
||||||
_tokens = new ConcurrentDictionary<long, TokenState>();
|
_tokens = new ConcurrentDictionary<long, TokenState>();
|
||||||
@ -38,32 +32,44 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
return authorizeSuccessful;
|
return authorizeSuccessful;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GenerateNextToken(long networkId)
|
public TokenState GenerateNextToken(long networkId)
|
||||||
{
|
{
|
||||||
TokenState state = null;
|
TokenState state = null;
|
||||||
|
|
||||||
if (_tokens.ContainsKey(networkId))
|
if (_tokens.ContainsKey(networkId))
|
||||||
{
|
{
|
||||||
state = _tokens[networkId];
|
state = _tokens[networkId];
|
||||||
|
|
||||||
if ((DateTime.Now - state.RequestTime) < _timeoutPeriod)
|
if ((DateTime.Now - state.RequestTime) > _timeoutPeriod)
|
||||||
{
|
{
|
||||||
return null;
|
_tokens.TryRemove(networkId, out TokenState _);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_tokens.TryRemove(networkId, out TokenState _);
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state = new TokenState()
|
state = new TokenState()
|
||||||
{
|
{
|
||||||
NetworkId = networkId,
|
NetworkId = networkId,
|
||||||
Token = _generateToken()
|
Token = _generateToken(),
|
||||||
|
TokenDuration = _timeoutPeriod
|
||||||
};
|
};
|
||||||
|
|
||||||
_tokens.TryAdd(networkId, state);
|
_tokens.TryAdd(networkId, state);
|
||||||
return state.Token;
|
|
||||||
|
// perform some housekeeping so we don't have built up tokens if they're not ever used
|
||||||
|
foreach (var (key, value) in _tokens)
|
||||||
|
{
|
||||||
|
if ((DateTime.Now - value.RequestTime) > _timeoutPeriod)
|
||||||
|
{
|
||||||
|
_tokens.TryRemove(key, out TokenState _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string _generateToken()
|
public string _generateToken()
|
||||||
|
@ -119,9 +119,9 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
}
|
}
|
||||||
|
|
||||||
int validMatches = 0;
|
int validMatches = 0;
|
||||||
foreach (string S in Status)
|
foreach (string statusLine in Status)
|
||||||
{
|
{
|
||||||
string responseLine = S.Trim();
|
string responseLine = statusLine.Trim();
|
||||||
|
|
||||||
var regex = Regex.Match(responseLine, Configuration.Status.Pattern, RegexOptions.IgnoreCase);
|
var regex = Regex.Match(responseLine, Configuration.Status.Pattern, RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
@ -158,11 +158,11 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
State = EFClient.ClientState.Connecting
|
State = EFClient.ClientState.Connecting
|
||||||
};
|
};
|
||||||
|
|
||||||
// they've not fully connected yet
|
//// they've not fully connected yet
|
||||||
if (!client.IsBot && ping == 999)
|
//if (!client.IsBot && ping == 999)
|
||||||
{
|
//{
|
||||||
continue;
|
// continue;
|
||||||
}
|
//}
|
||||||
|
|
||||||
StatusPlayers.Add(client);
|
StatusPlayers.Add(client);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<SuppressCollectPythonCloudServiceFiles>true</SuppressCollectPythonCloudServiceFiles>
|
<SuppressCollectPythonCloudServiceFiles>true</SuppressCollectPythonCloudServiceFiles>
|
||||||
<Name>GameLogServer</Name>
|
<Name>GameLogServer</Name>
|
||||||
<RootNamespace>GameLogServer</RootNamespace>
|
<RootNamespace>GameLogServer</RootNamespace>
|
||||||
<InterpreterId>MSBuild|env|$(MSBuildProjectFullPath)</InterpreterId>
|
<InterpreterId>MSBuild|log_env|$(MSBuildProjectFullPath)</InterpreterId>
|
||||||
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
|
<EnableNativeCodeDebugging>False</EnableNativeCodeDebugging>
|
||||||
<Environment>DEBUG=True</Environment>
|
<Environment>DEBUG=True</Environment>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@ -50,7 +50,6 @@
|
|||||||
<Folder Include="GameLogServer\" />
|
<Folder Include="GameLogServer\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="requirements.txt" />
|
|
||||||
<None Include="Stable.pubxml" />
|
<None Include="Stable.pubxml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -63,6 +62,18 @@
|
|||||||
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
|
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
|
||||||
<Architecture>X64</Architecture>
|
<Architecture>X64</Architecture>
|
||||||
</Interpreter>
|
</Interpreter>
|
||||||
|
<Interpreter Include="log_env\">
|
||||||
|
<Id>log_env</Id>
|
||||||
|
<Version>3.6</Version>
|
||||||
|
<Description>log_env (Python 3.6 (64-bit))</Description>
|
||||||
|
<InterpreterPath>Scripts\python.exe</InterpreterPath>
|
||||||
|
<WindowsInterpreterPath>Scripts\pythonw.exe</WindowsInterpreterPath>
|
||||||
|
<PathEnvironmentVariable>PYTHONPATH</PathEnvironmentVariable>
|
||||||
|
<Architecture>X64</Architecture>
|
||||||
|
</Interpreter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="requirements.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.Web.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.Web.targets" />
|
||||||
<!-- Specify pre- and post-build commands in the BeforeBuild and
|
<!-- Specify pre- and post-build commands in the BeforeBuild and
|
||||||
|
@ -5,55 +5,53 @@ import time
|
|||||||
class LogReader(object):
|
class LogReader(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.log_file_sizes = {}
|
self.log_file_sizes = {}
|
||||||
# (if the file changes more than this, ignore ) - 0.125 MB
|
# (if the time between checks is greater, ignore ) - in seconds
|
||||||
self.max_file_size_change = 125000
|
self.max_file_time_change = 30
|
||||||
# (if the time between checks is greater, ignore ) - 5 minutes
|
|
||||||
self.max_file_time_change = 60
|
|
||||||
|
|
||||||
def read_file(self, path):
|
def read_file(self, path):
|
||||||
|
# this removes old entries that are no longer valid
|
||||||
|
try:
|
||||||
|
self._clear_old_logs()
|
||||||
|
except Exception as e:
|
||||||
|
print('could not clear old logs')
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
if os.name != 'nt':
|
||||||
|
path = re.sub(r'^[A-Z]\:', '', path)
|
||||||
|
path = re.sub(r'\\+', '/', path)
|
||||||
|
|
||||||
# prevent traversing directories
|
# prevent traversing directories
|
||||||
if re.search('r^.+\.\.\\.+$', path):
|
if re.search('r^.+\.\.\\.+$', path):
|
||||||
return False
|
return False
|
||||||
# must be a valid log path and log file
|
# must be a valid log path and log file
|
||||||
if not re.search(r'^.+[\\|\/](.+)[\\|\/].+.log$', path):
|
if not re.search(r'^.+[\\|\/](.+)[\\|\/].+.log$', path):
|
||||||
return False
|
return False
|
||||||
# set the initialze size to the current file size
|
|
||||||
file_size = 0
|
|
||||||
|
|
||||||
if path not in self.log_file_sizes:
|
# get the new file size
|
||||||
self.log_file_sizes[path] = {
|
|
||||||
'length' : self.file_length(path),
|
|
||||||
'read': time.time()
|
|
||||||
}
|
|
||||||
return True
|
|
||||||
|
|
||||||
# grab the previous values
|
|
||||||
last_length = self.log_file_sizes[path]['length']
|
|
||||||
last_read = self.log_file_sizes[path]['read']
|
|
||||||
|
|
||||||
# the file is being tracked already
|
|
||||||
new_file_size = self.file_length(path)
|
new_file_size = self.file_length(path)
|
||||||
|
|
||||||
# the log size was unable to be read (probably the wrong path)
|
# the log size was unable to be read (probably the wrong path)
|
||||||
if new_file_size < 0:
|
if new_file_size < 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
now = time.time()
|
# this is the first time the log has been requested
|
||||||
|
if path not in self.log_file_sizes:
|
||||||
|
self.log_file_sizes[path] = {
|
||||||
|
'length' : new_file_size,
|
||||||
|
'read': time.time()
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
|
||||||
|
# grab the previous values
|
||||||
|
last_length = self.log_file_sizes[path]['length']
|
||||||
file_size_difference = new_file_size - last_length
|
file_size_difference = new_file_size - last_length
|
||||||
time_difference = now - last_read
|
|
||||||
|
|
||||||
# update the new size and actually read the data
|
# update the new size and actually read the data
|
||||||
self.log_file_sizes[path] = {
|
self.log_file_sizes[path] = {
|
||||||
'length': new_file_size,
|
'length': new_file_size,
|
||||||
'read': now
|
'read': time.time()
|
||||||
}
|
}
|
||||||
|
|
||||||
# if it's been too long since we read and the amount changed is too great, discard it
|
|
||||||
# todo: do we really want old events? maybe make this an "or"
|
|
||||||
if file_size_difference > self.max_file_size_change or time_difference > self.max_file_time_change:
|
|
||||||
return True
|
|
||||||
|
|
||||||
new_log_info = self.get_file_lines(path, file_size_difference)
|
new_log_info = self.get_file_lines(path, file_size_difference)
|
||||||
return new_log_info
|
return new_log_info
|
||||||
|
|
||||||
@ -63,14 +61,25 @@ class LogReader(object):
|
|||||||
file_handle.seek(-length, 2)
|
file_handle.seek(-length, 2)
|
||||||
file_data = file_handle.read(length)
|
file_data = file_handle.read(length)
|
||||||
file_handle.close()
|
file_handle.close()
|
||||||
return file_data.decode('utf-8')
|
# using ignore errors omits the pesky 0xb2 bytes we're reading in for some reason
|
||||||
except:
|
return file_data.decode('utf-8', errors='ignore')
|
||||||
|
except Exception as e:
|
||||||
|
print('could not read the log file at {0}, wanted to read {1} bytes'.format(path, length))
|
||||||
|
print(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _clear_old_logs(self):
|
||||||
|
expired_logs = [path for path in self.log_file_sizes if int(time.time() - self.log_file_sizes[path]['read']) > self.max_file_time_change]
|
||||||
|
for log in expired_logs:
|
||||||
|
print('removing expired log {0}'.format(log))
|
||||||
|
del self.log_file_sizes[log]
|
||||||
|
|
||||||
def file_length(self, path):
|
def file_length(self, path):
|
||||||
try:
|
try:
|
||||||
return os.stat(path).st_size
|
return os.stat(path).st_size
|
||||||
except:
|
except Exception as e:
|
||||||
|
print('could not get the size of the log file at {0}'.format(path))
|
||||||
|
print(e)
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
reader = LogReader()
|
reader = LogReader()
|
||||||
|
@ -7,13 +7,8 @@ class LogResource(Resource):
|
|||||||
path = urlsafe_b64decode(path).decode('utf-8')
|
path = urlsafe_b64decode(path).decode('utf-8')
|
||||||
log_info = reader.read_file(path)
|
log_info = reader.read_file(path)
|
||||||
|
|
||||||
if log_info is False:
|
|
||||||
print('could not read log file ' + path)
|
|
||||||
|
|
||||||
empty_read = (log_info == False) or (log_info == True)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'success' : log_info is not False,
|
'success' : log_info is not False,
|
||||||
'length': -1 if empty_read else len(log_info),
|
'length': 0 if log_info is False else len(log_info),
|
||||||
'data': log_info
|
'data': log_info
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
from flask_restful import Resource
|
#from flask_restful import Resource
|
||||||
from flask import request
|
#from flask import request
|
||||||
import requests
|
#import requests
|
||||||
import os
|
#import os
|
||||||
import subprocess
|
#import subprocess
|
||||||
import re
|
#import re
|
||||||
|
|
||||||
def get_pid_of_server_windows(port):
|
#def get_pid_of_server_windows(port):
|
||||||
process = subprocess.Popen('netstat -aon', shell=True, stdout=subprocess.PIPE)
|
# process = subprocess.Popen('netstat -aon', shell=True, stdout=subprocess.PIPE)
|
||||||
output = process.communicate()[0]
|
# output = process.communicate()[0]
|
||||||
matches = re.search(' *(UDP) +([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):'+ str(port) + ' +[^\w]*([0-9]+)', output.decode('utf-8'))
|
# matches = re.search(' *(UDP) +([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):'+ str(port) + ' +[^\w]*([0-9]+)', output.decode('utf-8'))
|
||||||
if matches is not None:
|
# if matches is not None:
|
||||||
return matches.group(3)
|
# return matches.group(3)
|
||||||
else:
|
# else:
|
||||||
return 0
|
# return 0
|
||||||
|
|
||||||
class RestartResource(Resource):
|
#class RestartResource(Resource):
|
||||||
def get(self):
|
# def get(self):
|
||||||
try:
|
# try:
|
||||||
response = requests.get('http://' + request.remote_addr + ':1624/api/restartapproved')
|
# response = requests.get('http://' + request.remote_addr + ':1624/api/restartapproved')
|
||||||
if response.status_code == 200:
|
# if response.status_code == 200:
|
||||||
pid = get_pid_of_server_windows(response.json()['port'])
|
# pid = get_pid_of_server_windows(response.json()['port'])
|
||||||
subprocess.check_output("Taskkill /PID %s /F" % pid)
|
# subprocess.check_output("Taskkill /PID %s /F" % pid)
|
||||||
else:
|
# else:
|
||||||
return {}, 400
|
# return {}, 400
|
||||||
except Exception as e:
|
# except Exception as e:
|
||||||
print(e)
|
# print(e)
|
||||||
return {}, 500
|
# return {}, 500
|
||||||
return {}, 200
|
# return {}, 200
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_restful import Api
|
from flask_restful import Api
|
||||||
from .log_resource import LogResource
|
from .log_resource import LogResource
|
||||||
from .restart_resource import RestartResource
|
#from .restart_resource import RestartResource
|
||||||
|
import logging
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
|
log = logging.getLogger('werkzeug')
|
||||||
|
log.setLevel(logging.ERROR)
|
||||||
api = Api(app)
|
api = Api(app)
|
||||||
api.add_resource(LogResource, '/log/<string:path>')
|
api.add_resource(LogResource, '/log/<string:path>')
|
||||||
api.add_resource(RestartResource, '/restart')
|
#api.add_resource(RestartResource, '/restart')
|
||||||
|
@ -1,26 +1,12 @@
|
|||||||
aniso8601==3.0.2
|
aniso8601==6.0.0
|
||||||
APScheduler==3.5.3
|
Click==7.0
|
||||||
certifi==2018.10.15
|
|
||||||
chardet==3.0.4
|
|
||||||
click==6.7
|
|
||||||
Flask==1.0.2
|
Flask==1.0.2
|
||||||
Flask-JWT==0.3.2
|
Flask-RESTful==0.3.7
|
||||||
Flask-JWT-Extended==3.8.1
|
itsdangerous==1.1.0
|
||||||
Flask-RESTful==0.3.6
|
|
||||||
idna==2.7
|
|
||||||
itsdangerous==0.24
|
|
||||||
Jinja2==2.10
|
Jinja2==2.10
|
||||||
MarkupSafe==1.0
|
MarkupSafe==1.1.1
|
||||||
marshmallow==3.0.0b8
|
pip==10.0.1
|
||||||
pip==9.0.3
|
pytz==2018.9
|
||||||
psutil==5.4.8
|
setuptools==39.0.1
|
||||||
pygal==2.4.0
|
six==1.12.0
|
||||||
PyJWT==1.4.2
|
Werkzeug==0.15.2
|
||||||
pytz==2018.7
|
|
||||||
requests==2.20.0
|
|
||||||
setuptools==40.5.0
|
|
||||||
six==1.11.0
|
|
||||||
timeago==1.0.8
|
|
||||||
tzlocal==1.5.1
|
|
||||||
urllib3==1.24
|
|
||||||
Werkzeug==0.14.1
|
|
||||||
|
@ -41,6 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug
|
|||||||
Plugins\ScriptPlugins\ParserCoD4x.js = Plugins\ScriptPlugins\ParserCoD4x.js
|
Plugins\ScriptPlugins\ParserCoD4x.js = Plugins\ScriptPlugins\ParserCoD4x.js
|
||||||
Plugins\ScriptPlugins\ParserIW4x.js = Plugins\ScriptPlugins\ParserIW4x.js
|
Plugins\ScriptPlugins\ParserIW4x.js = Plugins\ScriptPlugins\ParserIW4x.js
|
||||||
Plugins\ScriptPlugins\ParserPT6.js = Plugins\ScriptPlugins\ParserPT6.js
|
Plugins\ScriptPlugins\ParserPT6.js = Plugins\ScriptPlugins\ParserPT6.js
|
||||||
|
Plugins\ScriptPlugins\ParserRektT5M.js = Plugins\ScriptPlugins\ParserRektT5M.js
|
||||||
Plugins\ScriptPlugins\ParserTeknoMW3.js = Plugins\ScriptPlugins\ParserTeknoMW3.js
|
Plugins\ScriptPlugins\ParserTeknoMW3.js = Plugins\ScriptPlugins\ParserTeknoMW3.js
|
||||||
Plugins\ScriptPlugins\SharedGUIDKick.js = Plugins\ScriptPlugins\SharedGUIDKick.js
|
Plugins\ScriptPlugins\SharedGUIDKick.js = Plugins\ScriptPlugins\SharedGUIDKick.js
|
||||||
Plugins\ScriptPlugins\VPNDetection.js = Plugins\ScriptPlugins\VPNDetection.js
|
Plugins\ScriptPlugins\VPNDetection.js = Plugins\ScriptPlugins\VPNDetection.js
|
||||||
@ -48,6 +49,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "GameLogServer", "GameLogServer\GameLogServer.pyproj", "{42EFDA12-10D3-4C40-A210-9483520116BC}"
|
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "GameLogServer", "GameLogServer\GameLogServer.pyproj", "{42EFDA12-10D3-4C40-A210-9483520116BC}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{A848FCF1-8527-4AA8-A1AA-50D29695C678}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatsWeb", "Plugins\Web\StatsWeb\StatsWeb.csproj", "{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutomessageFeed", "Plugins\AutomessageFeed\AutomessageFeed.csproj", "{F5815359-CFC7-44B4-9A3B-C04BACAD5836}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -286,8 +293,8 @@ Global
|
|||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Debug|x64.Build.0 = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Debug|x86.ActiveCfg = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Debug|x86.Build.0 = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Any CPU.Build.0 = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
{6C706CE5-A206-4E46-8712-F8C48D526091}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
||||||
@ -306,7 +313,7 @@ Global
|
|||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|Mixed Platforms.ActiveCfg = Release|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|x64.ActiveCfg = Release|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|x64.ActiveCfg = Release|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|x86.ActiveCfg = Release|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Prerelease|x86.ActiveCfg = Release|Any CPU
|
||||||
@ -315,15 +322,13 @@ Global
|
|||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x64.ActiveCfg = Release|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x86.ActiveCfg = Release|Any CPU
|
{15A81D6E-7502-46CE-8530-0647A380B5F4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x64.Build.0 = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x86.Build.0 = Debug|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Mixed Platforms.ActiveCfg = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Mixed Platforms.Build.0 = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|x64.ActiveCfg = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Prerelease|x64.ActiveCfg = Release|Any CPU
|
||||||
@ -338,6 +343,54 @@ Global
|
|||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x64.Build.0 = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x86.ActiveCfg = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x86.Build.0 = Release|Any CPU
|
{42EFDA12-10D3-4C40-A210-9483520116BC}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|x64.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Prerelease|x86.Build.0 = Debug|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|x64.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Prerelease|x86.Build.0 = Debug|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -350,6 +403,9 @@ Global
|
|||||||
{B72DEBFB-9D48-4076-8FF5-1FD72A830845} = {26E8B310-269E-46D4-A612-24601F16065F}
|
{B72DEBFB-9D48-4076-8FF5-1FD72A830845} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
{6C706CE5-A206-4E46-8712-F8C48D526091} = {26E8B310-269E-46D4-A612-24601F16065F}
|
{6C706CE5-A206-4E46-8712-F8C48D526091} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
{3F9ACC27-26DB-49FA-BCD2-50C54A49C9FA} = {26E8B310-269E-46D4-A612-24601F16065F}
|
{3F9ACC27-26DB-49FA-BCD2-50C54A49C9FA} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
|
{A848FCF1-8527-4AA8-A1AA-50D29695C678} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
|
{776B348B-F818-4A0F-A625-D0AF8BAD3E9B} = {A848FCF1-8527-4AA8-A1AA-50D29695C678}
|
||||||
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87}
|
SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87}
|
||||||
|
21
Plugins/AutomessageFeed/AutomessageFeed.csproj
Normal file
21
Plugins/AutomessageFeed/AutomessageFeed.csproj
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
<Exec Command="copy "$(TargetPath)" "$(SolutionDir)BUILD\Plugins""/>
|
||||||
|
<Exec Command="copy "$(TargetDir)Microsoft.SyndicationFeed.ReaderWriter.dll" "$(SolutionDir)BUILD\Plugins""/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
29
Plugins/AutomessageFeed/Configuration.cs
Normal file
29
Plugins/AutomessageFeed/Configuration.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace AutomessageFeed
|
||||||
|
{
|
||||||
|
class Configuration : IBaseConfiguration
|
||||||
|
{
|
||||||
|
public bool EnableFeed { get; set; }
|
||||||
|
public string FeedUrl { get; set; }
|
||||||
|
public int MaxFeedItems { get; set; }
|
||||||
|
|
||||||
|
public IBaseConfiguration Generate()
|
||||||
|
{
|
||||||
|
EnableFeed = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_PROMPT_ENABLE"]);
|
||||||
|
|
||||||
|
if (EnableFeed)
|
||||||
|
{
|
||||||
|
FeedUrl = Utilities.PromptString(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_URL"]);
|
||||||
|
MaxFeedItems = Utilities.PromptInt(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_PROMPT_MAXITEMS"],
|
||||||
|
Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_PROMPT_MAXITEMS_DESC"],
|
||||||
|
0, int.MaxValue, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name() => "AutomessageFeedConfiguration";
|
||||||
|
}
|
||||||
|
}
|
85
Plugins/AutomessageFeed/Plugin.cs
Normal file
85
Plugins/AutomessageFeed/Plugin.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.SyndicationFeed.Rss;
|
||||||
|
using SharedLibraryCore.Configuration;
|
||||||
|
using System.Xml;
|
||||||
|
using Microsoft.SyndicationFeed;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using SharedLibraryCore.Helpers;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace AutomessageFeed
|
||||||
|
{
|
||||||
|
public class Plugin : IPlugin
|
||||||
|
{
|
||||||
|
public string Name => "Automessage Feed";
|
||||||
|
|
||||||
|
public float Version => (float)Utilities.GetVersionAsDouble();
|
||||||
|
|
||||||
|
public string Author => "RaidMax";
|
||||||
|
|
||||||
|
private Configuration _configuration;
|
||||||
|
private int _currentFeedItem;
|
||||||
|
|
||||||
|
private async Task<string> GetNextFeedItem(Server server)
|
||||||
|
{
|
||||||
|
var items = new List<string>();
|
||||||
|
|
||||||
|
using (var reader = XmlReader.Create(_configuration.FeedUrl, new XmlReaderSettings() { Async = true }))
|
||||||
|
{
|
||||||
|
var feedReader = new RssFeedReader(reader);
|
||||||
|
|
||||||
|
while (await feedReader.Read())
|
||||||
|
{
|
||||||
|
switch (feedReader.ElementType)
|
||||||
|
{
|
||||||
|
case SyndicationElementType.Item:
|
||||||
|
var item = await feedReader.ReadItem();
|
||||||
|
items.Add(Regex.Replace(item.Title, @"\<.+\>.*\</.+\>", ""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentFeedItem < items.Count && (_configuration.MaxFeedItems == 0 || _currentFeedItem < _configuration.MaxFeedItems))
|
||||||
|
{
|
||||||
|
_currentFeedItem++;
|
||||||
|
return items[_currentFeedItem - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentFeedItem = 0;
|
||||||
|
return Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_AUTOMESSAGEFEED_NO_ITEMS"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task OnEventAsync(GameEvent E, Server S)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnLoadAsync(IManager manager)
|
||||||
|
{
|
||||||
|
var cfg = new BaseConfigurationHandler<Configuration>("AutomessageFeedPluginSettings");
|
||||||
|
if (cfg.Configuration() == null)
|
||||||
|
{
|
||||||
|
cfg.Set((Configuration)new Configuration().Generate());
|
||||||
|
await cfg.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
_configuration = cfg.Configuration();
|
||||||
|
|
||||||
|
manager.GetMessageTokens().Add(new MessageToken("FEED", GetNextFeedItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task OnTickAsync(Server S)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task OnUnloadAsync()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,5 @@
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Objects;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Login.Commands
|
namespace IW4MAdmin.Plugins.Login.Commands
|
||||||
@ -22,18 +19,22 @@ namespace IW4MAdmin.Plugins.Login.Commands
|
|||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
var client = E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId];
|
var client = E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId];
|
||||||
string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(E.Data, client.PasswordSalt));
|
bool success = E.Owner.Manager.TokenAuthenticator.AuthorizeToken(E.Origin.NetworkId, E.Data);
|
||||||
|
|
||||||
if (hashedPassword[0] == client.Password)
|
if (!success)
|
||||||
|
{
|
||||||
|
string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(E.Data, client.PasswordSalt));
|
||||||
|
success = hashedPassword[0] == client.Password;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
{
|
{
|
||||||
Plugin.AuthorizedClients[E.Origin.ClientId] = true;
|
Plugin.AuthorizedClients[E.Origin.ClientId] = true;
|
||||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
_ = success ?
|
||||||
{
|
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]) :
|
||||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL"]);
|
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL"]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using SharedLibraryCore;
|
|||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Objects;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.ProfanityDeterment
|
namespace IW4MAdmin.Plugins.ProfanityDeterment
|
||||||
{
|
{
|
||||||
@ -49,11 +48,7 @@ namespace IW4MAdmin.Plugins.ProfanityDeterment
|
|||||||
|
|
||||||
if (containsObjectionalWord)
|
if (containsObjectionalWord)
|
||||||
{
|
{
|
||||||
E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, new EFClient()
|
E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, Utilities.IW4MAdminClient(E.Owner));
|
||||||
{
|
|
||||||
ClientId = 1,
|
|
||||||
CurrentServer = E.Owner
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'FrenchFry, RaidMax',
|
author: 'FrenchFry, RaidMax',
|
||||||
version: 0.2,
|
version: 0.3,
|
||||||
name: 'CoD4x Parser',
|
name: 'CoD4x Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ var plugin = {
|
|||||||
eventParser.Configuration.GameDirectory = 'main';
|
eventParser.Configuration.GameDirectory = 'main';
|
||||||
eventParser.Version = 'CoD4 X 1.8 win_mingw-x86 build 2055 May 2 2017';
|
eventParser.Version = 'CoD4 X 1.8 win_mingw-x86 build 2055 May 2 2017';
|
||||||
eventParser.GameName = 1; // IW3
|
eventParser.GameName = 1; // IW3
|
||||||
|
eventParser.URLProtocolFormat = 'cod4://{{ip}}:{{port}}';
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync: function () {
|
onUnloadAsync: function () {
|
||||||
|
@ -3,8 +3,8 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.2,
|
version: 0.3,
|
||||||
name: 'IW3 Parser',
|
name: 'IW4 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
onEventAsync: function (gameEvent, server) {
|
onEventAsync: function (gameEvent, server) {
|
||||||
@ -25,6 +25,7 @@ var plugin = {
|
|||||||
rconParser.GameName = 2; // IW4x
|
rconParser.GameName = 2; // IW4x
|
||||||
eventParser.Version = 'IW4x (v0.6.0)';
|
eventParser.Version = 'IW4x (v0.6.0)';
|
||||||
eventParser.GameName = 2; // IW4x
|
eventParser.GameName = 2; // IW4x
|
||||||
|
eventParser.URLProtocolFormat = 'iw4x://{{ip}}:{{port}}';
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync: function () {
|
onUnloadAsync: function () {
|
||||||
|
@ -4,7 +4,7 @@ var eventParser;
|
|||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.2,
|
version: 0.2,
|
||||||
name: 'Plutoniun T6 Parser',
|
name: 'Plutonium T6 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
onEventAsync: function (gameEvent, server) {
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
34
Plugins/ScriptPlugins/ParserRektT5M.js
Normal file
34
Plugins/ScriptPlugins/ParserRektT5M.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
var rconParser;
|
||||||
|
var eventParser;
|
||||||
|
|
||||||
|
var plugin = {
|
||||||
|
author: 'RaidMax',
|
||||||
|
version: 0.1,
|
||||||
|
name: 'RektT5m Parser',
|
||||||
|
isParser: true,
|
||||||
|
|
||||||
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadAsync: function (manager) {
|
||||||
|
rconParser = manager.GenerateDynamicRConParser();
|
||||||
|
eventParser = manager.GenerateDynamicEventParser();
|
||||||
|
|
||||||
|
eventParser.Configuration.GameDirectory = 'data';
|
||||||
|
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff\1print';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
|
||||||
|
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
|
||||||
|
eventParser.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';
|
||||||
|
eventParser.GameName = 6; // T5
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 1.0,
|
version: 1.1,
|
||||||
name: 'VPN Detection Plugin',
|
name: 'VPN Detection Plugin',
|
||||||
|
|
||||||
manager: null,
|
manager: null,
|
||||||
@ -33,7 +33,7 @@ var plugin = {
|
|||||||
cl.Dispose();
|
cl.Dispose();
|
||||||
usingVPN = parsedJSON.success && parsedJSON.proxy;
|
usingVPN = parsedJSON.success && parsedJSON.proxy;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.WriteError(e.message);
|
this.logger.WriteWarning('There was a problem checking client IP for VPN ' + e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usingVPN) {
|
if (usingVPN) {
|
||||||
|
@ -39,7 +39,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands
|
|||||||
where stats.ServerId == serverId
|
where stats.ServerId == serverId
|
||||||
where client.Level != EFClient.Permission.Banned
|
where client.Level != EFClient.Permission.Banned
|
||||||
where client.LastConnection >= thirtyDaysAgo
|
where client.LastConnection >= thirtyDaysAgo
|
||||||
orderby stats.Kills descending
|
orderby stats.TimePlayed descending
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
alias.Name,
|
alias.Name,
|
||||||
|
@ -69,7 +69,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands
|
|||||||
if (E.Message.IsBroadcastCommand())
|
if (E.Message.IsBroadcastCommand())
|
||||||
{
|
{
|
||||||
string name = E.Target == null ? E.Origin.Name : E.Target.Name;
|
string name = E.Target == null ? E.Origin.Name : E.Target.Name;
|
||||||
E.Owner.Broadcast($"{loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"]} ^5{name}^7");
|
E.Owner.Broadcast(loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(name));
|
||||||
E.Owner.Broadcast(statLine);
|
E.Owner.Broadcast(statLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands
|
|||||||
{
|
{
|
||||||
if (E.Target != null)
|
if (E.Target != null)
|
||||||
{
|
{
|
||||||
E.Origin.Tell($"{loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"]} ^5{E.Target.Name}^7");
|
E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(E.Target.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
E.Origin.Tell(statLine);
|
E.Origin.Tell(statLine);
|
||||||
|
138
Plugins/Stats/Controllers/StatsController.cs
Normal file
138
Plugins/Stats/Controllers/StatsController.cs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Dtos;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using WebfrontCore.Controllers;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Plugins.Stats.Web.Controllers
|
||||||
|
{
|
||||||
|
public class StatsController : BaseController
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult TopPlayersAsync()
|
||||||
|
{
|
||||||
|
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_STATS_INDEX_TITLE"];
|
||||||
|
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_STATS_INDEX_DESC"];
|
||||||
|
ViewBag.Servers = Manager.GetServers().Select(_server => new ServerInfo() { Name = _server.Hostname, ID = _server.EndPoint });
|
||||||
|
|
||||||
|
return View("Index");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetTopPlayersAsync(int count, int offset, long? serverId = null)
|
||||||
|
{
|
||||||
|
// this prevents empty results when we really want aggregate
|
||||||
|
if (serverId == 0)
|
||||||
|
{
|
||||||
|
serverId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = Manager.GetServers().FirstOrDefault(_server => _server.EndPoint == serverId);
|
||||||
|
|
||||||
|
if (server != null)
|
||||||
|
{
|
||||||
|
serverId = await StatManager.GetIdForServer(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = await Plugin.Manager.GetTopStats(offset, count, serverId);
|
||||||
|
|
||||||
|
// this returns an empty result so we know to stale the loader
|
||||||
|
if (results.Count == 0 && offset > 0)
|
||||||
|
{
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return View("Components/TopPlayers/_List", results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetMessageAsync(int serverId, long when)
|
||||||
|
{
|
||||||
|
var whenTime = DateTime.FromFileTimeUtc(when);
|
||||||
|
var whenUpper = whenTime.AddMinutes(5);
|
||||||
|
var whenLower = whenTime.AddMinutes(-5);
|
||||||
|
|
||||||
|
using (var ctx = new SharedLibraryCore.Database.DatabaseContext(true))
|
||||||
|
{
|
||||||
|
var iqMessages = from message in ctx.Set<Models.EFClientMessage>()
|
||||||
|
where message.ServerId == serverId
|
||||||
|
where message.TimeSent >= whenLower
|
||||||
|
where message.TimeSent <= whenUpper
|
||||||
|
select new ChatInfo()
|
||||||
|
{
|
||||||
|
ClientId = message.ClientId,
|
||||||
|
Message = message.Message,
|
||||||
|
Name = message.Client.CurrentAlias.Name,
|
||||||
|
Time = message.TimeSent,
|
||||||
|
ServerGame = message.Server.GameName ?? Server.Game.IW4
|
||||||
|
};
|
||||||
|
|
||||||
|
#if DEBUG == true
|
||||||
|
var messagesSql = iqMessages.ToSql();
|
||||||
|
#endif
|
||||||
|
var messages = await iqMessages.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var message in messages)
|
||||||
|
{
|
||||||
|
if (message.Message.IsQuickMessage())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var quickMessages = Manager.GetApplicationSettings().Configuration()
|
||||||
|
.QuickMessages
|
||||||
|
.First(_qm => _qm.Game == message.ServerGame);
|
||||||
|
message.Message = quickMessages.Messages[message.Message.Substring(1)];
|
||||||
|
message.IsQuickMessage = true;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return View("_MessageContext", messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> GetAutomatedPenaltyInfoAsync(int clientId)
|
||||||
|
{
|
||||||
|
using (var ctx = new SharedLibraryCore.Database.DatabaseContext(true))
|
||||||
|
{
|
||||||
|
int linkId = await ctx.Clients
|
||||||
|
.Where(_client => _client.ClientId == clientId)
|
||||||
|
.Select(_client => _client.AliasLinkId)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
var clientIds = await ctx.Clients.Where(_client => _client.AliasLinkId == linkId)
|
||||||
|
.Select(_client => _client.ClientId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var iqPenaltyInfo = ctx.Set<Models.EFACSnapshot>()
|
||||||
|
.Where(s => clientIds.Contains(s.ClientId))
|
||||||
|
.Include(s => s.LastStrainAngle)
|
||||||
|
.Include(s => s.HitOrigin)
|
||||||
|
.Include(s => s.HitDestination)
|
||||||
|
.Include(s => s.CurrentViewAngle)
|
||||||
|
.Include(s => s.PredictedViewAngles)
|
||||||
|
.OrderBy(s => s.When)
|
||||||
|
.ThenBy(s => s.Hits);
|
||||||
|
|
||||||
|
#if DEBUG == true
|
||||||
|
var sql = iqPenaltyInfo.ToSql();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var penaltyInfo = await iqPenaltyInfo.ToListAsync();
|
||||||
|
|
||||||
|
return View("_PenaltyInfo", penaltyInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,6 @@ using System.Collections.Concurrent;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -82,13 +81,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<TopStatsInfo>> GetTopStats(int start, int count)
|
public async Task<List<TopStatsInfo>> GetTopStats(int start, int count, long? serverId = null)
|
||||||
{
|
{
|
||||||
using (var context = new DatabaseContext(true))
|
using (var context = new DatabaseContext(true))
|
||||||
{
|
{
|
||||||
// setup the query for the clients within the given rating range
|
// setup the query for the clients within the given rating range
|
||||||
var iqClientRatings = (from rating in context.Set<EFRating>()
|
var iqClientRatings = (from rating in context.Set<EFRating>()
|
||||||
.Where(GetRankingFunc())
|
.Where(GetRankingFunc(serverId))
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
rating.RatingHistory.ClientId,
|
rating.RatingHistory.ClientId,
|
||||||
@ -113,7 +112,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
var iqRatingInfo = from rating in context.Set<EFRating>()
|
var iqRatingInfo = from rating in context.Set<EFRating>()
|
||||||
where clientIds.Contains(rating.RatingHistory.ClientId)
|
where clientIds.Contains(rating.RatingHistory.ClientId)
|
||||||
where rating.ServerId == null
|
where rating.ServerId == serverId
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
rating.Ranking,
|
rating.Ranking,
|
||||||
@ -155,6 +154,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
var finished = topPlayers.Select(s => new TopStatsInfo()
|
var finished = topPlayers.Select(s => new TopStatsInfo()
|
||||||
{
|
{
|
||||||
ClientId = s.ClientId,
|
ClientId = s.ClientId,
|
||||||
|
Id = (int?)serverId ?? 0,
|
||||||
Deaths = s.Deaths,
|
Deaths = s.Deaths,
|
||||||
Kills = s.Kills,
|
Kills = s.Kills,
|
||||||
KDR = Math.Round(s.KDR, 2),
|
KDR = Math.Round(s.KDR, 2),
|
||||||
@ -221,13 +221,22 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
Port = sv.GetPort(),
|
Port = sv.GetPort(),
|
||||||
EndPoint = sv.ToString(),
|
EndPoint = sv.ToString(),
|
||||||
ServerId = serverId
|
ServerId = serverId,
|
||||||
|
GameName = sv.GameName
|
||||||
};
|
};
|
||||||
|
|
||||||
server = serverSet.Add(server).Entity;
|
server = serverSet.Add(server).Entity;
|
||||||
// this doesn't need to be async as it's during initialization
|
// this doesn't need to be async as it's during initialization
|
||||||
ctx.SaveChanges();
|
ctx.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we want to set the gamename up if it's never been set, or it changed
|
||||||
|
else if (!server.GameName.HasValue || server.GameName.HasValue && server.GameName.Value != sv.GameName)
|
||||||
|
{
|
||||||
|
server.GameName = sv.GameName;
|
||||||
|
ctx.Entry(server).Property(_prop => _prop.GameName).IsModified = true;
|
||||||
|
ctx.SaveChanges();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if the stats have ever been initialized
|
// check to see if the stats have ever been initialized
|
||||||
@ -427,19 +436,20 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
public void AddDamageEvent(string eventLine, int attackerClientId, int victimClientId, long serverId)
|
public void AddDamageEvent(string eventLine, int attackerClientId, int victimClientId, long serverId)
|
||||||
{
|
{
|
||||||
string regex = @"^(D);(.+);([0-9]+);(allies|axis);(.+);([0-9]+);(allies|axis);(.+);(.+);([0-9]+);(.+);(.+)$";
|
// todo: maybe do something with this
|
||||||
var match = Regex.Match(eventLine, regex, RegexOptions.IgnoreCase);
|
//string regex = @"^(D);(.+);([0-9]+);(allies|axis);(.+);([0-9]+);(allies|axis);(.+);(.+);([0-9]+);(.+);(.+)$";
|
||||||
|
//var match = Regex.Match(eventLine, regex, RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
if (match.Success)
|
//if (match.Success)
|
||||||
{
|
//{
|
||||||
// this gives us what team the player is on
|
// // this gives us what team the player is on
|
||||||
var attackerStats = Servers[serverId].PlayerStats[attackerClientId];
|
// var attackerStats = Servers[serverId].PlayerStats[attackerClientId];
|
||||||
var victimStats = Servers[serverId].PlayerStats[victimClientId];
|
// var victimStats = Servers[serverId].PlayerStats[victimClientId];
|
||||||
IW4Info.Team victimTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[4].ToString());
|
// IW4Info.Team victimTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[4].ToString(), true);
|
||||||
IW4Info.Team attackerTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[7].ToString());
|
// IW4Info.Team attackerTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[7].ToString(), true);
|
||||||
attackerStats.Team = attackerTeam;
|
// attackerStats.Team = attackerTeam;
|
||||||
victimStats.Team = victimTeam;
|
// victimStats.Team = victimTeam;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -526,7 +536,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// incase the add palyer event get delayed
|
// incase the add player event get delayed
|
||||||
if (!Servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
|
if (!Servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
|
||||||
{
|
{
|
||||||
await AddPlayer(attacker);
|
await AddPlayer(attacker);
|
||||||
@ -560,7 +570,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
ctx.Set<EFClientKill>().Add(hit);
|
ctx.Set<EFClientKill>().Add(hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Plugin.Config.Configuration().EnableAntiCheat)
|
if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot)
|
||||||
{
|
{
|
||||||
if (clientDetection.QueuedHits.Count > Detection.QUEUE_COUNT)
|
if (clientDetection.QueuedHits.Count > Detection.QUEUE_COUNT)
|
||||||
{
|
{
|
||||||
@ -569,7 +579,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
clientDetection.QueuedHits = clientDetection.QueuedHits.OrderBy(_hits => _hits.TimeOffset).ToList();
|
clientDetection.QueuedHits = clientDetection.QueuedHits.OrderBy(_hits => _hits.TimeOffset).ToList();
|
||||||
var oldestHit = clientDetection.QueuedHits.First();
|
var oldestHit = clientDetection.QueuedHits.First();
|
||||||
clientDetection.QueuedHits.RemoveAt(0);
|
clientDetection.QueuedHits.RemoveAt(0);
|
||||||
ApplyPenalty(clientDetection.ProcessHit(oldestHit, isDamage), clientDetection, attacker, ctx);
|
await ApplyPenalty(clientDetection.ProcessHit(oldestHit, isDamage), clientDetection, attacker, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +588,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
clientDetection.QueuedHits.Add(hit);
|
clientDetection.QueuedHits.Add(hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx);
|
await ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Set<EFHitLocationCount>().UpdateRange(clientStats.HitLocations);
|
ctx.Set<EFHitLocationCount>().UpdateRange(clientStats.HitLocations);
|
||||||
@ -596,8 +606,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyPenalty(DetectionPenaltyResult penalty, Detection clientDetection, EFClient attacker, DatabaseContext ctx)
|
async Task ApplyPenalty(DetectionPenaltyResult penalty, Detection clientDetection, EFClient attacker, DatabaseContext ctx)
|
||||||
{
|
{
|
||||||
|
var penaltyClient = Utilities.IW4MAdminClient(attacker.CurrentServer);
|
||||||
switch (penalty.ClientPenalty)
|
switch (penalty.ClientPenalty)
|
||||||
{
|
{
|
||||||
case Penalty.PenaltyType.Ban:
|
case Penalty.PenaltyType.Ban:
|
||||||
@ -605,22 +616,19 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new EFClient()
|
|
||||||
{
|
|
||||||
ClientId = 1,
|
|
||||||
AdministeredPenalties = new List<EFPenalty>()
|
|
||||||
{
|
|
||||||
new EFPenalty()
|
|
||||||
{
|
|
||||||
AutomatedOffense = penalty.Type == Cheat.Detection.DetectionType.Bone ?
|
|
||||||
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
|
||||||
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Level = EFClient.Permission.Console,
|
|
||||||
CurrentServer = attacker.CurrentServer,
|
|
||||||
|
|
||||||
}, false);
|
penaltyClient.AdministeredPenalties = new List<EFPenalty>()
|
||||||
|
{
|
||||||
|
new EFPenalty()
|
||||||
|
{
|
||||||
|
AutomatedOffense = penalty.Type == Detection.DetectionType.Bone ?
|
||||||
|
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
||||||
|
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], penaltyClient, false).WaitAsync();
|
||||||
|
|
||||||
if (clientDetection.Tracker.HasChanges)
|
if (clientDetection.Tracker.HasChanges)
|
||||||
{
|
{
|
||||||
SaveTrackedSnapshots(clientDetection, ctx);
|
SaveTrackedSnapshots(clientDetection, ctx);
|
||||||
@ -636,23 +644,17 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
||||||
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}";
|
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}";
|
||||||
|
|
||||||
attacker.Flag(flagReason, new EFClient()
|
await attacker.Flag(flagReason, penaltyClient).WaitAsync();
|
||||||
{
|
|
||||||
ClientId = 1,
|
|
||||||
Level = EFClient.Permission.Console,
|
|
||||||
CurrentServer = attacker.CurrentServer,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (clientDetection.Tracker.HasChanges)
|
if (clientDetection.Tracker.HasChanges)
|
||||||
{
|
{
|
||||||
SaveTrackedSnapshots(clientDetection, ctx);
|
SaveTrackedSnapshots(clientDetection, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTrackedSnapshots(Cheat.Detection clientDetection, DatabaseContext ctx)
|
void SaveTrackedSnapshots(Detection clientDetection, DatabaseContext ctx)
|
||||||
{
|
{
|
||||||
// todo: why does this cause duplicate primary key
|
// todo: why does this cause duplicate primary key
|
||||||
var change = clientDetection.Tracker.GetNextChange();
|
var change = clientDetection.Tracker.GetNextChange();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Models
|
namespace IW4MAdmin.Plugins.Stats.Models
|
||||||
{
|
{
|
||||||
@ -13,5 +14,6 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
[Required]
|
[Required]
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
public string EndPoint { get; set; }
|
public string EndPoint { get; set; }
|
||||||
|
public Game? GameName { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
using SharedLibraryCore.Database;
|
using SharedLibraryCore.Database;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Dtos;
|
using SharedLibraryCore.Dtos;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
@ -26,7 +27,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
public string Author => "RaidMax";
|
public string Author => "RaidMax";
|
||||||
|
|
||||||
public static StatManager Manager { get; private set; }
|
public static StatManager Manager { get; private set; }
|
||||||
private IManager ServerManager;
|
public static IManager ServerManager;
|
||||||
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
||||||
|
|
||||||
public async Task OnEventAsync(GameEvent E, Server S)
|
public async Task OnEventAsync(GameEvent E, Server S)
|
||||||
@ -51,7 +52,6 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
{
|
{
|
||||||
await Manager.AddMessageAsync(E.Origin.ClientId, await StatManager.GetIdForServer(E.Owner), E.Data);
|
await Manager.AddMessageAsync(E.Origin.ClientId, await StatManager.GetIdForServer(E.Owner), E.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.MapChange:
|
case GameEvent.EventType.MapChange:
|
||||||
Manager.SetTeamBased(await StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm");
|
Manager.SetTeamBased(await StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm");
|
||||||
@ -77,28 +77,72 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
break;
|
break;
|
||||||
case GameEvent.EventType.ScriptKill:
|
case GameEvent.EventType.ScriptKill:
|
||||||
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
||||||
if (killInfo.Length >= 14)
|
if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||||
{
|
{
|
||||||
|
// this treats "world" damage as self damage
|
||||||
|
if (E.Origin.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Origin = E.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (E.Target.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Target = E.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Kill:
|
case GameEvent.EventType.Kill:
|
||||||
if (!E.Owner.CustomCallback)
|
if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||||
{
|
{
|
||||||
|
// this treats "world" damage as self damage
|
||||||
|
if (E.Origin.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Origin = E.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (E.Target.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Target = E.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
await Manager.AddStandardKill(E.Origin, E.Target);
|
await Manager.AddStandardKill(E.Origin, E.Target);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Damage:
|
case GameEvent.EventType.Damage:
|
||||||
if (!E.Owner.CustomCallback)
|
if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||||
{
|
{
|
||||||
|
// this treats "world" damage as self damage
|
||||||
|
if (E.Origin.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Origin = E.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (E.Target.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Target = E.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, await StatManager.GetIdForServer(E.Owner));
|
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Target.ClientId, await StatManager.GetIdForServer(E.Owner));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.ScriptDamage:
|
case GameEvent.EventType.ScriptDamage:
|
||||||
killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
||||||
if (killInfo.Length >= 14)
|
if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target))
|
||||||
{
|
{
|
||||||
|
// this treats "world" damage as self damage
|
||||||
|
if (E.Origin.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Origin = E.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (E.Target.ClientId <= 1)
|
||||||
|
{
|
||||||
|
E.Target = E.Origin;
|
||||||
|
}
|
||||||
|
|
||||||
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, await StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
||||||
}
|
}
|
||||||
@ -124,8 +168,13 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
"/Stats/TopPlayersAsync");
|
"/Stats/TopPlayersAsync");
|
||||||
|
|
||||||
// meta data info
|
// meta data info
|
||||||
async Task<List<ProfileMeta>> getStats(int clientId)
|
async Task<List<ProfileMeta>> getStats(int clientId, int offset, int count, DateTime? startAt)
|
||||||
{
|
{
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
return new List<ProfileMeta>();
|
||||||
|
}
|
||||||
|
|
||||||
IList<EFClientStatistics> clientStats;
|
IList<EFClientStatistics> clientStats;
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
using (var ctx = new DatabaseContext(disableTracking: true))
|
||||||
{
|
{
|
||||||
@ -145,39 +194,63 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_RANKING"],
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_RANKING"],
|
||||||
Value = "#" + await StatManager.GetClientOverallRanking(clientId),
|
Value = "#" + (await StatManager.GetClientOverallRanking(clientId)).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 0,
|
||||||
|
Order = 0,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KILLS"],
|
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KILLS"],
|
||||||
Value = kills
|
Value = kills.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 0,
|
||||||
|
Order = 1,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_DEATHS"],
|
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_DEATHS"],
|
||||||
Value = deaths
|
Value = deaths.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 0,
|
||||||
|
Order = 2,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"],
|
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"],
|
||||||
Value = kdr
|
Value = kdr.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 0,
|
||||||
|
Order = 3,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"],
|
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"],
|
||||||
Value = performance
|
Value = performance.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 0,
|
||||||
|
Order = 4,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_META_SPM"],
|
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_META_SPM"],
|
||||||
Value = spm
|
Value = spm.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 0,
|
||||||
|
Order = 5,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<List<ProfileMeta>> getAnticheatInfo(int clientId)
|
async Task<List<ProfileMeta>> getAnticheatInfo(int clientId, int offset, int count, DateTime? startAt)
|
||||||
{
|
{
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
return new List<ProfileMeta>();
|
||||||
|
}
|
||||||
|
|
||||||
IList<EFClientStatistics> clientStats;
|
IList<EFClientStatistics> clientStats;
|
||||||
|
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
using (var ctx = new DatabaseContext(disableTracking: true))
|
||||||
{
|
{
|
||||||
clientStats = await ctx.Set<EFClientStatistics>()
|
clientStats = await ctx.Set<EFClientStatistics>()
|
||||||
@ -195,21 +268,21 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
|
|
||||||
if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
|
if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
|
||||||
{
|
{
|
||||||
chestRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
|
chestRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
|
||||||
c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
|
c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
|
||||||
(double)clientStats.Where(c => c.HitLocations.Count > 0)
|
(double)clientStats.Where(c => c.HitLocations.Count > 0)
|
||||||
.Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount)), 2);
|
.Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0);
|
||||||
|
|
||||||
abdomenRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
|
abdomenRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
|
||||||
c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount) /
|
c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount) /
|
||||||
(double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount)), 2);
|
(double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0);
|
||||||
|
|
||||||
chestAbdomenRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
|
chestAbdomenRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
|
||||||
(double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount), 2);
|
(double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount)) * 100.0, 0);
|
||||||
|
|
||||||
headRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.head).HitCount) /
|
headRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.head).HitCount) /
|
||||||
(double)clientStats.Where(c => c.HitLocations.Count > 0)
|
(double)clientStats.Where(c => c.HitLocations.Count > 0)
|
||||||
.Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount)), 2);
|
.Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0);
|
||||||
|
|
||||||
var validOffsets = clientStats.Where(c => c.HitLocations.Count(hl => hl.HitCount > 0) > 0).SelectMany(hl => hl.HitLocations);
|
var validOffsets = clientStats.Where(c => c.HitLocations.Count(hl => hl.HitCount > 0) > 0).SelectMany(hl => hl.HitLocations);
|
||||||
hitOffsetAverage = validOffsets.Sum(o => o.HitCount * o.HitOffsetAverage) / (double)validOffsets.Sum(o => o.HitCount);
|
hitOffsetAverage = validOffsets.Sum(o => o.HitCount * o.HitOffsetAverage) / (double)validOffsets.Sum(o => o.HitCount);
|
||||||
@ -219,104 +292,172 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
{
|
{
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Chest Ratio",
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 1",
|
||||||
Value = chestRatio,
|
Value = chestRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 0,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM1"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Abdomen Ratio",
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 2",
|
||||||
Value = abdomenRatio,
|
Value = abdomenRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 1,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM2"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Chest To Abdomen Ratio",
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 3",
|
||||||
Value = chestAbdomenRatio,
|
Value = chestAbdomenRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 2,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM3"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Headshot Ratio",
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 4",
|
||||||
Value = headRatio,
|
Value = headRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 3,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM4"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Hit Offset Average",
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 5",
|
||||||
// todo: make sure this is wrapped somewhere else
|
// todo: make sure this is wrapped somewhere else
|
||||||
Value = $"{Math.Round(((float)hitOffsetAverage), 4).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))}°",
|
Value = $"{Math.Round(((float)hitOffsetAverage), 4).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))}°",
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 4,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM5"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Max Strain",
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 6",
|
||||||
Value = Math.Round(maxStrain, 3),
|
Value = Math.Round(maxStrain, 3).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 5,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM6"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<List<ProfileMeta>> getMessages(int clientId)
|
async Task<List<ProfileMeta>> getMessages(int clientId, int offset, int count, DateTime? startAt)
|
||||||
{
|
{
|
||||||
|
if (count <= 1)
|
||||||
|
{
|
||||||
|
using (var ctx = new DatabaseContext(true))
|
||||||
|
{
|
||||||
|
return new List<ProfileMeta>
|
||||||
|
{
|
||||||
|
new ProfileMeta()
|
||||||
|
{
|
||||||
|
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
|
||||||
|
Value = (await ctx.Set<EFClientMessage>()
|
||||||
|
.CountAsync(_message => _message.ClientId == clientId))
|
||||||
|
.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Column = 1,
|
||||||
|
Order= 4,
|
||||||
|
Type = ProfileMeta.MetaType.Information
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<ProfileMeta> messageMeta;
|
List<ProfileMeta> messageMeta;
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
using (var ctx = new DatabaseContext(disableTracking: true))
|
||||||
{
|
{
|
||||||
var messages = ctx.Set<EFClientMessage>().Where(m => m.ClientId == clientId);
|
var messages = ctx.Set<EFClientMessage>()
|
||||||
|
.Where(m => m.ClientId == clientId)
|
||||||
|
.Where(_message => _message.TimeSent < startAt)
|
||||||
|
.OrderByDescending(_message => _message.TimeSent)
|
||||||
|
.Skip(offset)
|
||||||
|
.Take(count);
|
||||||
|
|
||||||
messageMeta = await messages.Select(m => new ProfileMeta()
|
messageMeta = await messages.Select(m => new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "EventMessage",
|
Key = null,
|
||||||
Value = m.Message,
|
Value = new { m.Message, m.Server.GameName },
|
||||||
When = m.TimeSent,
|
When = m.TimeSent,
|
||||||
Extra = m.ServerId.ToString()
|
Extra = m.ServerId.ToString(),
|
||||||
|
Type = ProfileMeta.MetaType.ChatMessage
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
}
|
|
||||||
|
|
||||||
messageMeta.Add(new ProfileMeta()
|
foreach (var message in messageMeta)
|
||||||
{
|
{
|
||||||
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
|
if ((message.Value.Message as string).IsQuickMessage())
|
||||||
Value = messageMeta.Count
|
{
|
||||||
});
|
try
|
||||||
|
{
|
||||||
|
var quickMessages = ServerManager.GetApplicationSettings().Configuration()
|
||||||
|
.QuickMessages
|
||||||
|
.First(_qm => _qm.Game == message.Value.GameName);
|
||||||
|
message.Value = quickMessages.Messages[(message.Value.Message as string).Substring(1)];
|
||||||
|
message.Type = ProfileMeta.MetaType.QuickMessage;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
message.Value = message.Value.Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message.Value = message.Value.Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return messageMeta;
|
return messageMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaService.AddMeta(getStats);
|
|
||||||
|
|
||||||
if (Config.Configuration().EnableAntiCheat)
|
if (Config.Configuration().EnableAntiCheat)
|
||||||
{
|
{
|
||||||
MetaService.AddMeta(getAnticheatInfo);
|
MetaService.AddRuntimeMeta(getAnticheatInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaService.AddMeta(getMessages);
|
MetaService.AddRuntimeMeta(getStats);
|
||||||
|
MetaService.AddRuntimeMeta(getMessages);
|
||||||
|
|
||||||
string totalKills(Server server)
|
async Task<string> totalKills(Server server)
|
||||||
{
|
{
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
using (var ctx = new DatabaseContext(disableTracking: true))
|
||||||
{
|
{
|
||||||
long kills = ctx.Set<EFServerStatistics>().Where(s => s.Active).Sum(s => s.TotalKills);
|
long kills = await ctx.Set<EFServerStatistics>().Where(s => s.Active).SumAsync(s => s.TotalKills);
|
||||||
return kills.ToString("#,##0");
|
return kills.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string totalPlayTime(Server server)
|
async Task<string> totalPlayTime(Server server)
|
||||||
{
|
{
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
using (var ctx = new DatabaseContext(disableTracking: true))
|
||||||
{
|
{
|
||||||
long playTime = ctx.Set<EFServerStatistics>().Where(s => s.Active).Sum(s => s.TotalPlayTime);
|
long playTime = await ctx.Set<EFServerStatistics>().Where(s => s.Active).SumAsync(s => s.TotalPlayTime);
|
||||||
return (playTime / 3600.0).ToString("#,##0");
|
return (playTime / 3600.0).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string topStats(Server s)
|
async Task<string> topStats(Server s)
|
||||||
{
|
{
|
||||||
return String.Join(Environment.NewLine, Commands.TopStats.GetTopStats(s).Result);
|
return string.Join(Environment.NewLine, await Commands.TopStats.GetTopStats(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
string mostPlayed(Server s)
|
async Task<string> mostPlayed(Server s)
|
||||||
{
|
{
|
||||||
return String.Join(Environment.NewLine, Commands.MostPlayed.GetMostPlayed(s).Result);
|
return string.Join(Environment.NewLine, await Commands.MostPlayed.GetMostPlayed(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills));
|
manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills));
|
||||||
@ -325,7 +466,6 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
manager.GetMessageTokens().Add(new MessageToken("MOSTPLAYED", mostPlayed));
|
manager.GetMessageTokens().Add(new MessageToken("MOSTPLAYED", mostPlayed));
|
||||||
|
|
||||||
ServerManager = manager;
|
ServerManager = manager;
|
||||||
|
|
||||||
Manager = new StatManager(manager);
|
Manager = new StatManager(manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,5 +481,17 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
await Manager.Sync(sv);
|
await Manager.Sync(sv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the event should be ignored
|
||||||
|
/// (If the client id or target id is not a real client or the target/origin is a bot and ignore bots is turned on)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="origin"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool ShouldIgnoreEvent(EFClient origin, EFClient target)
|
||||||
|
{
|
||||||
|
return ((origin.ClientId <= 1 && target.ClientId <= 1) || (target.IsBot || origin.IsBot) && ServerManager.GetApplicationSettings().Configuration().IgnoreBots);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,6 @@
|
|||||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="Web\Views\Stats\_MessageContext.cshtml">
|
|
||||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
||||||
<ProjectReference Include="..\..\WebfrontCore\WebfrontCore.csproj" />
|
<ProjectReference Include="..\..\WebfrontCore\WebfrontCore.csproj" />
|
||||||
@ -33,9 +27,4 @@
|
|||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
<Exec Command="copy "$(TargetPath)" "$(SolutionDir)BUILD\Plugins"" />
|
<Exec Command="copy "$(TargetPath)" "$(SolutionDir)BUILD\Plugins"" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
|
||||||
<Exec Command="xcopy /E /K /Y /C /I "$(ProjectDir)Web\Views" "$(SolutionDir)WebfrontCore\Views\Plugins"
xcopy /E /K /Y /C /I "$(ProjectDir)Web\wwwroot\images" "$(SolutionDir)WebfrontCore\wwwroot\images"" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
28
Plugins/Stats/ViewComponents/TopPlayersViewComponent.cs
Normal file
28
Plugins/Stats/ViewComponents/TopPlayersViewComponent.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using IW4MAdmin.Plugins.Stats;
|
||||||
|
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Stats.ViewComponents
|
||||||
|
{
|
||||||
|
public class TopPlayersViewComponent : ViewComponent
|
||||||
|
{
|
||||||
|
public async Task<IViewComponentResult> InvokeAsync(int count, int offset, long? serverId = null)
|
||||||
|
{
|
||||||
|
if (serverId == 0)
|
||||||
|
{
|
||||||
|
serverId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = Plugin.ServerManager.GetServers().FirstOrDefault(_server => _server.EndPoint == serverId);
|
||||||
|
|
||||||
|
if (server != null)
|
||||||
|
{
|
||||||
|
serverId = await StatManager.GetIdForServer(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
return View("_List", await Plugin.Manager.GetTopStats(offset, count, serverId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,80 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using SharedLibraryCore;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using WebfrontCore.Controllers;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Web.Controllers
|
|
||||||
{
|
|
||||||
public class StatsController : BaseController
|
|
||||||
{
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<IActionResult> TopPlayersAsync()
|
|
||||||
{
|
|
||||||
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_TITLE"];
|
|
||||||
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_DESC"];
|
|
||||||
|
|
||||||
return View("Index", await Plugin.Manager.GetTopStats(0, 50));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<IActionResult> GetTopPlayersAsync(int count, int offset)
|
|
||||||
{
|
|
||||||
return View("_List", await Plugin.Manager.GetTopStats(offset, count));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
public async Task<IActionResult> GetMessageAsync(int serverId, DateTime when)
|
|
||||||
{
|
|
||||||
var whenUpper = when.AddMinutes(5);
|
|
||||||
var whenLower = when.AddMinutes(-5);
|
|
||||||
|
|
||||||
using (var ctx = new SharedLibraryCore.Database.DatabaseContext(true))
|
|
||||||
{
|
|
||||||
var iqMessages = from message in ctx.Set<Models.EFClientMessage>()
|
|
||||||
where message.ServerId == serverId
|
|
||||||
where message.TimeSent >= whenLower
|
|
||||||
where message.TimeSent <= whenUpper
|
|
||||||
select new SharedLibraryCore.Dtos.ChatInfo()
|
|
||||||
{
|
|
||||||
ClientId = message.ClientId,
|
|
||||||
Message = message.Message,
|
|
||||||
Name = message.Client.CurrentAlias.Name,
|
|
||||||
Time = message.TimeSent
|
|
||||||
};
|
|
||||||
|
|
||||||
#if DEBUG == true
|
|
||||||
var messagesSql = iqMessages.ToSql();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var messages = await iqMessages.ToListAsync();
|
|
||||||
|
|
||||||
return View("_MessageContext", messages);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize]
|
|
||||||
public async Task<IActionResult> GetAutomatedPenaltyInfoAsync(int clientId)
|
|
||||||
{
|
|
||||||
using (var ctx = new SharedLibraryCore.Database.DatabaseContext(true))
|
|
||||||
{
|
|
||||||
var penaltyInfo = await ctx.Set<Models.EFACSnapshot>()
|
|
||||||
.Where(s => s.ClientId == clientId)
|
|
||||||
.Include(s => s.LastStrainAngle)
|
|
||||||
.Include(s => s.HitOrigin)
|
|
||||||
.Include(s => s.HitDestination)
|
|
||||||
.Include(s => s.CurrentViewAngle)
|
|
||||||
.Include(s => s.PredictedViewAngles)
|
|
||||||
.OrderBy(s => s.When)
|
|
||||||
.ThenBy(s => s.Hits)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
return View("_PenaltyInfo", penaltyInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
@model List<dynamic>
|
|
||||||
<h4 class="pb-2 text-center ">@ViewBag.Title</h4>
|
|
||||||
|
|
||||||
<div id="stats_top_players" class="striped border-top border-bottom">
|
|
||||||
@await Html.PartialAsync("_List", Model)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@section scripts {
|
|
||||||
<environment include="Development">
|
|
||||||
<script type="text/javascript" src="~/js/loader.js"></script>
|
|
||||||
<script type="text/javascript" src="~/js/stats.js"></script>
|
|
||||||
</environment>
|
|
||||||
<script>initLoader('/Stats/GetTopPlayersAsync', '#stats_top_players', 50);</script>
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
@model IEnumerable<SharedLibraryCore.Dtos.ChatInfo>
|
|
||||||
@{
|
|
||||||
Layout = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="client-message-context bg-dark p-2 mt-2 mb-2 border-top border-bottom">
|
|
||||||
<h5>@Model.First().Time.ToString()</h5>
|
|
||||||
@foreach (var message in Model)
|
|
||||||
{
|
|
||||||
<span class="text-white">@Html.ActionLink(@message.Name, "ProfileAsync", "Client", new { id = message.ClientId})</span><span> — @message.Message</span><br />
|
|
||||||
}
|
|
||||||
</div>
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user