Fix bug with webfront spamming issues when running
Remove IW5 parser Begin implementation of dynamic parsers
This commit is contained in:
parent
08c883e0ff
commit
7a6dccc26a
@ -6,7 +6,7 @@
|
|||||||
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
|
<RuntimeFrameworkVersion>2.1.5</RuntimeFrameworkVersion>
|
||||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
||||||
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
||||||
<Version>2.2.3.2</Version>
|
<Version>2.2.3.3</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Product>IW4MAdmin</Product>
|
<Product>IW4MAdmin</Product>
|
||||||
@ -31,8 +31,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||||
<TieredCompilation>true</TieredCompilation>
|
<TieredCompilation>true</TieredCompilation>
|
||||||
<AssemblyVersion>2.2.3.2</AssemblyVersion>
|
<AssemblyVersion>2.2.3.3</AssemblyVersion>
|
||||||
<FileVersion>2.2.3.2</FileVersion>
|
<FileVersion>2.2.3.3</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using IW4MAdmin.Application.API.Master;
|
using IW4MAdmin.Application.API.Master;
|
||||||
|
using IW4MAdmin.Application.EventParsers;
|
||||||
|
using IW4MAdmin.Application.RconParsers;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Commands;
|
using SharedLibraryCore.Commands;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
@ -34,6 +36,13 @@ namespace IW4MAdmin.Application
|
|||||||
public DateTime StartTime { get; private set; }
|
public DateTime StartTime { get; private set; }
|
||||||
public string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
public string Version => Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
|
public IList<IRConParser> AdditionalRConParsers => _additionalRConParsers.ToList<IRConParser>();
|
||||||
|
|
||||||
|
public IList<IEventParser> AdditionalEventParsers => _additionalEventParsers.ToList<IEventParser>();
|
||||||
|
|
||||||
|
private readonly IList<DynamicRConParser> _additionalRConParsers;
|
||||||
|
private readonly IList<DynamicEventParser> _additionalEventParsers;
|
||||||
|
|
||||||
static ApplicationManager Instance;
|
static ApplicationManager Instance;
|
||||||
readonly List<AsyncStatus> TaskStatuses;
|
readonly List<AsyncStatus> TaskStatuses;
|
||||||
List<Command> Commands;
|
List<Command> Commands;
|
||||||
@ -61,6 +70,8 @@ namespace IW4MAdmin.Application
|
|||||||
StartTime = DateTime.UtcNow;
|
StartTime = DateTime.UtcNow;
|
||||||
OnQuit = new ManualResetEventSlim();
|
OnQuit = new ManualResetEventSlim();
|
||||||
PageList = new PageList();
|
PageList = new PageList();
|
||||||
|
_additionalEventParsers = new List<DynamicEventParser>();
|
||||||
|
_additionalRConParsers = new List<DynamicRConParser>();
|
||||||
OnServerEvent += OnGameEvent;
|
OnServerEvent += OnGameEvent;
|
||||||
OnServerEvent += EventApi.OnGameEvent;
|
OnServerEvent += EventApi.OnGameEvent;
|
||||||
}
|
}
|
||||||
@ -552,5 +563,9 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
return PageList;
|
return PageList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IRConParser GenerateDynamicRConParser() => new DynamicRConParser();
|
||||||
|
|
||||||
|
public IEventParser GenerateDynamicEventParser() => new DynamicEventParser();
|
||||||
}
|
}
|
||||||
}
|
}
|
12
Application/EventParsers/DynamicEventParser.cs
Normal file
12
Application/EventParsers/DynamicEventParser.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
|
{
|
||||||
|
sealed internal class DynamicEventParser : IW4EventParser
|
||||||
|
{
|
||||||
|
public string Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
14
Application/EventParsers/DynamicEventParserConfiguration.cs
Normal file
14
Application/EventParsers/DynamicEventParserConfiguration.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
|
{
|
||||||
|
class DynamicEventParserConfiguration : IEventParserConfiguration
|
||||||
|
{
|
||||||
|
public string GameDirectory { get; set; }
|
||||||
|
public string SayRegex { get; set; }
|
||||||
|
public string JoinRegex { get; set; }
|
||||||
|
public string QuitRegex { get; set; }
|
||||||
|
public string KillRegex { get; set; }
|
||||||
|
public string DamageRegex { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,9 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
class IW3EventParser : IW4EventParser
|
class IW3EventParser : IW4EventParser
|
||||||
{
|
{
|
||||||
public override string GetGameDir() => "main";
|
public IW3EventParser() : base()
|
||||||
|
{
|
||||||
|
Configuration.GameDirectory = "main";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,21 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
class IW4EventParser : IEventParser
|
class IW4EventParser : IEventParser
|
||||||
{
|
{
|
||||||
private const string SayRegex = @"(say|sayteam);(.{1,32});([0-9]+)(.*);(.*)";
|
private IEventParserConfiguration _configuration;
|
||||||
|
|
||||||
|
public IW4EventParser()
|
||||||
|
{
|
||||||
|
_configuration = new DynamicEventParserConfiguration()
|
||||||
|
{
|
||||||
|
GameDirectory = "userraw",
|
||||||
|
SayRegex = "(say|sayteam);(.{1,32});([0-9]+)(.*);(.*)",
|
||||||
|
QuitRegex = @"^(Q;)(.{1,32});([0-9]+);(.*)$",
|
||||||
|
JoinRegex = @"^(J;)(.{1,32});([0-9]+);(.*)$",
|
||||||
|
DamageRegex = @"^(D);((?:bot[0-9]+)|(?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEventParserConfiguration Configuration { get => _configuration; set => _configuration = value; }
|
||||||
|
|
||||||
public virtual GameEvent GetEvent(Server server, string logLine)
|
public virtual GameEvent GetEvent(Server server, string logLine)
|
||||||
{
|
{
|
||||||
@ -32,7 +46,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "say" || eventType == "sayteam")
|
if (eventType == "say" || eventType == "sayteam")
|
||||||
{
|
{
|
||||||
var matchResult = Regex.Match(logLine, SayRegex);
|
var matchResult = Regex.Match(logLine, _configuration.SayRegex);
|
||||||
|
|
||||||
if (matchResult.Success)
|
if (matchResult.Success)
|
||||||
{
|
{
|
||||||
@ -117,7 +131,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
if (!server.CustomCallback)
|
if (!server.CustomCallback)
|
||||||
{
|
{
|
||||||
if (Regex.Match(eventType, @"^(D);((?:bot[0-9]+)|(?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$").Success)
|
if (Regex.Match(eventType, _configuration.DamageRegex).Success)
|
||||||
{
|
{
|
||||||
var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong());
|
var origin = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong());
|
||||||
var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
|
var target = server.GetClientsAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong());
|
||||||
@ -137,7 +151,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
// join
|
// join
|
||||||
if (eventType == "J")
|
if (eventType == "J")
|
||||||
{
|
{
|
||||||
var regexMatch = Regex.Match(logLine, @"^(J;)(.{1,32});([0-9]+);(.*)$");
|
var regexMatch = Regex.Match(logLine, _configuration.JoinRegex);
|
||||||
if (regexMatch.Success)
|
if (regexMatch.Success)
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
@ -163,7 +177,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (eventType == "Q")
|
if (eventType == "Q")
|
||||||
{
|
{
|
||||||
var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$");
|
var regexMatch = Regex.Match(logLine, _configuration.QuitRegex);
|
||||||
if (regexMatch.Success)
|
if (regexMatch.Success)
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
@ -221,11 +235,5 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Owner = server
|
Owner = server
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// other parsers can derive from this parser so we make it virtual
|
|
||||||
public virtual string GetGameDir()
|
|
||||||
{
|
|
||||||
return "userraw";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Database.Models;
|
|
||||||
using System;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
|
||||||
{
|
|
||||||
class IW5EventParser : IW4EventParser
|
|
||||||
{
|
|
||||||
public override string GetGameDir()
|
|
||||||
{
|
|
||||||
return "logs";
|
|
||||||
}
|
|
||||||
|
|
||||||
public override GameEvent GetEvent(Server server, string logLine)
|
|
||||||
{
|
|
||||||
string cleanedEventLine = Regex.Replace(logLine, @"[0-9]+:[0-9]+\ ", "").Trim();
|
|
||||||
|
|
||||||
if (cleanedEventLine.Contains("J;"))
|
|
||||||
{
|
|
||||||
string[] lineSplit = cleanedEventLine.Split(';');
|
|
||||||
|
|
||||||
int clientNum = Int32.Parse(lineSplit[2]);
|
|
||||||
|
|
||||||
var player = new EFClient()
|
|
||||||
{
|
|
||||||
NetworkId = lineSplit[1].ConvertLong(),
|
|
||||||
ClientNumber = clientNum,
|
|
||||||
CurrentAlias = new EFAlias()
|
|
||||||
{
|
|
||||||
Active = false,
|
|
||||||
Name = lineSplit[3]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.PreConnect,
|
|
||||||
Origin = new EFClient()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Target = new EFClient()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Owner = server,
|
|
||||||
Extra = player
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return base.GetEvent(server, logLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,9 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
class T5MEventParser : IW4EventParser
|
class T5MEventParser : IW4EventParser
|
||||||
{
|
{
|
||||||
public override string GetGameDir() => "v2";
|
public T5MEventParser() : base()
|
||||||
|
{
|
||||||
|
Configuration.GameDirectory = "v2";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
using System;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using SharedLibraryCore.Objects;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
{
|
{
|
||||||
class T6MEventParser : IW4EventParser
|
class T6MEventParser : IW4EventParser
|
||||||
{
|
{
|
||||||
public override string GetGameDir() => $"t6r{Path.DirectorySeparatorChar}data";
|
public T6MEventParser() : base()
|
||||||
|
{
|
||||||
|
Configuration.GameDirectory = $"t6r{Path.DirectorySeparatorChar}data";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -669,32 +669,26 @@ namespace IW4MAdmin
|
|||||||
(IRConParser)new T6MRConParser() :
|
(IRConParser)new T6MRConParser() :
|
||||||
new IW3RConParser();
|
new IW3RConParser();
|
||||||
|
|
||||||
if (ServerConfig.UseIW5MParser)
|
|
||||||
{
|
|
||||||
RconParser = new IW5MRConParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
var version = await this.GetDvarAsync<string>("version");
|
var version = await this.GetDvarAsync<string>("version");
|
||||||
Version = version.Value;
|
Version = version.Value;
|
||||||
GameName = Utilities.GetGame(version.Value);
|
//GameName = Utilities.GetGame(version.Value);
|
||||||
|
|
||||||
if (GameName == Game.IW4)
|
if (GameName == Game.IW4)
|
||||||
{
|
{
|
||||||
EventParser = new IW4EventParser();
|
EventParser = new IW4EventParser();
|
||||||
RconParser = new IW4RConParser();
|
RconParser = new IW4RConParser();
|
||||||
}
|
}
|
||||||
else if (GameName == Game.IW5)
|
|
||||||
{
|
|
||||||
EventParser = new IW5EventParser();
|
|
||||||
}
|
|
||||||
else if (GameName == Game.T5M)
|
else if (GameName == Game.T5M)
|
||||||
{
|
{
|
||||||
EventParser = new T5MEventParser();
|
EventParser = new T5MEventParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (GameName == Game.T6M)
|
else if (GameName == Game.T6M)
|
||||||
{
|
{
|
||||||
EventParser = new T6MEventParser();
|
EventParser = new T6MEventParser();
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EventParser = new IW3EventParser(); // this uses the 'main' folder for log paths
|
EventParser = new IW3EventParser(); // this uses the 'main' folder for log paths
|
||||||
@ -703,6 +697,9 @@ namespace IW4MAdmin
|
|||||||
if (GameName == Game.UKN)
|
if (GameName == Game.UKN)
|
||||||
{
|
{
|
||||||
Logger.WriteWarning($"Game name not recognized: {version}");
|
Logger.WriteWarning($"Game name not recognized: {version}");
|
||||||
|
|
||||||
|
EventParser = Manager.AdditionalEventParsers.FirstOrDefault(_parser => (_parser as DynamicEventParser).Version == version.Value) ?? EventParser;
|
||||||
|
RconParser = Manager.AdditionalRConParsers.FirstOrDefault(_parser => (_parser as DynamicRConParser).Version == version.Value) ?? RconParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
var infoResponse = await this.GetInfoAsync();
|
var infoResponse = await this.GetInfoAsync();
|
||||||
@ -763,7 +760,7 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomCallback = await ScriptLoaded();
|
CustomCallback = await ScriptLoaded();
|
||||||
string mainPath = EventParser.GetGameDir();
|
string mainPath = EventParser.Configuration.GameDirectory;
|
||||||
string logPath = string.Empty;
|
string logPath = string.Empty;
|
||||||
|
|
||||||
LogPath = game == string.Empty ?
|
LogPath = game == string.Empty ?
|
||||||
|
12
Application/RconParsers/DynamicRConParser.cs
Normal file
12
Application/RconParsers/DynamicRConParser.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.RCon;
|
||||||
|
using System;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
|
{
|
||||||
|
sealed internal class DynamicRConParser : IW4RConParser
|
||||||
|
{
|
||||||
|
public string Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
13
Application/RconParsers/DynamicRConParserConfiguration.cs
Normal file
13
Application/RconParsers/DynamicRConParserConfiguration.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.RCon;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
|
{
|
||||||
|
class DynamicRConParserConfiguration : IRConParserConfiguration
|
||||||
|
{
|
||||||
|
public CommandPrefix CommandPrefixes { get; set; }
|
||||||
|
public Server.Game GameName { get; set; }
|
||||||
|
public string StatusRegex { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using SharedLibraryCore.RCon;
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.RCon;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -7,15 +8,18 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
{
|
{
|
||||||
class IW3RConParser : IW4RConParser
|
class IW3RConParser : IW4RConParser
|
||||||
{
|
{
|
||||||
private static readonly CommandPrefix Prefixes = new CommandPrefix()
|
public IW3RConParser() : base()
|
||||||
{
|
{
|
||||||
Tell = "tell {0} {1}",
|
Configuration.CommandPrefixes = new CommandPrefix()
|
||||||
Say = "say {0}",
|
{
|
||||||
Kick = "clientkick {0} \"{1}\"",
|
Tell = "tell {0} {1}",
|
||||||
Ban = "clientkick {0} \"{1}\"",
|
Say = "say {0}",
|
||||||
TempBan = "tempbanclient {0} \"{1}\""
|
Kick = "clientkick {0} \"{1}\"",
|
||||||
};
|
Ban = "clientkick {0} \"{1}\"",
|
||||||
|
TempBan = "tempbanclient {0} \"{1}\""
|
||||||
|
};
|
||||||
|
|
||||||
public override CommandPrefix GetCommandPrefixes() => Prefixes;
|
Configuration.GameName = Server.Game.IW3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,16 +13,24 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
{
|
{
|
||||||
class IW4RConParser : IRConParser
|
class IW4RConParser : IRConParser
|
||||||
{
|
{
|
||||||
private static readonly CommandPrefix Prefixes = new CommandPrefix()
|
public IW4RConParser()
|
||||||
{
|
{
|
||||||
Tell = "tellraw {0} {1}",
|
Configuration = new DynamicRConParserConfiguration()
|
||||||
Say = "sayraw {0}",
|
{
|
||||||
Kick = "clientkick {0} \"{1}\"",
|
CommandPrefixes = new CommandPrefix()
|
||||||
Ban = "clientkick {0} \"{1}\"",
|
{
|
||||||
TempBan = "tempbanclient {0} \"{1}\""
|
Tell = "tellraw {0} {1}",
|
||||||
};
|
Say = "sayraw {0}",
|
||||||
|
Kick = "clientkick {0} \"{1}\"",
|
||||||
|
Ban = "clientkick {0} \"{1}\"",
|
||||||
|
TempBan = "tempbanclient {0} \"{1}\""
|
||||||
|
},
|
||||||
|
StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|(?:[a-z]|[0-9]){32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$",
|
||||||
|
GameName = Server.Game.IW4
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|(?:[a-z]|[0-9]){32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}|loopback) +(-*[0-9]+) +([0-9]+) *$";
|
public IRConParserConfiguration Configuration { get; set; }
|
||||||
|
|
||||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||||
{
|
{
|
||||||
@ -71,11 +79,6 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, $"set {dvarName} {dvarValue}")).Length > 0;
|
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, $"set {dvarName} {dvarValue}")).Length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual CommandPrefix GetCommandPrefixes()
|
|
||||||
{
|
|
||||||
return Prefixes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<EFClient> ClientsFromStatus(string[] Status)
|
private List<EFClient> ClientsFromStatus(string[] Status)
|
||||||
{
|
{
|
||||||
List<EFClient> StatusPlayers = new List<EFClient>();
|
List<EFClient> StatusPlayers = new List<EFClient>();
|
||||||
@ -90,7 +93,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
{
|
{
|
||||||
String responseLine = S.Trim();
|
String responseLine = S.Trim();
|
||||||
|
|
||||||
var regex = Regex.Match(responseLine, StatusRegex, RegexOptions.IgnoreCase);
|
var regex = Regex.Match(responseLine, Configuration.StatusRegex, RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
if (regex.Success)
|
if (regex.Success)
|
||||||
{
|
{
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using SharedLibraryCore.Objects;
|
|
||||||
using SharedLibraryCore.RCon;
|
|
||||||
using SharedLibraryCore.Exceptions;
|
|
||||||
using SharedLibraryCore.Database.Models;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
|
||||||
{
|
|
||||||
public class IW5MRConParser : IRConParser
|
|
||||||
{
|
|
||||||
private static readonly CommandPrefix Prefixes = new CommandPrefix()
|
|
||||||
{
|
|
||||||
Tell = "tell {0} {1}",
|
|
||||||
Say = "say {0}",
|
|
||||||
Kick = "dropClient {0} \"{1}\"",
|
|
||||||
Ban = "dropClient {0} \"{1}\"",
|
|
||||||
TempBan = "dropClient {0} \"{1}\""
|
|
||||||
};
|
|
||||||
|
|
||||||
public CommandPrefix GetCommandPrefixes() => Prefixes;
|
|
||||||
|
|
||||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
|
||||||
{
|
|
||||||
await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command, false);
|
|
||||||
return new string[] { "Command Executed" };
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)
|
|
||||||
{
|
|
||||||
// why can't this be real :(
|
|
||||||
if (dvarName == "version")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType("IW5 MP 1.9 build 461 Fri Sep 14 00:04:28 2012 win-x86", typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dvarName == "shortversion")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType("1.9", typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dvarName == "mapname")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType("Unknown", typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dvarName == "g_gametype")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType("Unknown", typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dvarName == "fs_game")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType("", typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dvarName == "g_logsync")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType(1, typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dvarName == "fs_basepath")
|
|
||||||
return new Dvar<T>(dvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType("", typeof(T))
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
string[] LineSplit = await connection.SendQueryAsync(StaticHelpers.QueryType.DVAR, dvarName);
|
|
||||||
|
|
||||||
if (LineSplit.Length < 4)
|
|
||||||
{
|
|
||||||
var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
|
|
||||||
e.Data["dvar_name"] = dvarName;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] ValueSplit = LineSplit[1].Split(new char[] { '"' });
|
|
||||||
|
|
||||||
if (ValueSplit.Length == 0)
|
|
||||||
{
|
|
||||||
var e = new DvarException($"DVAR \"{dvarName}\" does not exist");
|
|
||||||
e.Data["dvar_name"] = dvarName;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
string DvarName = dvarName;
|
|
||||||
string DvarCurrentValue = Regex.Replace(ValueSplit[3].StripColors(), @"\^[0-9]", "");
|
|
||||||
|
|
||||||
return new Dvar<T>(DvarName)
|
|
||||||
{
|
|
||||||
Value = (T)Convert.ChangeType(DvarCurrentValue, typeof(T))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<EFClient>> GetStatusAsync(Connection connection)
|
|
||||||
{
|
|
||||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, "status");
|
|
||||||
return ClientsFromStatus(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> SetDvarAsync(Connection connection, string dvarName, object dvarValue)
|
|
||||||
{
|
|
||||||
// T6M doesn't respond with anything when a value is set, so we can only hope for the best :c
|
|
||||||
await connection.SendQueryAsync(StaticHelpers.QueryType.DVAR, $"set {dvarName} {dvarValue}", false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<EFClient> ClientsFromStatus(string[] status)
|
|
||||||
{
|
|
||||||
List<EFClient> StatusPlayers = new List<EFClient>();
|
|
||||||
|
|
||||||
foreach (string statusLine in status)
|
|
||||||
{
|
|
||||||
String responseLine = statusLine;
|
|
||||||
|
|
||||||
if (Regex.Matches(responseLine, @"^ *\d+", RegexOptions.IgnoreCase).Count > 0) // its a client line!
|
|
||||||
{
|
|
||||||
String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
// this happens when the client is in a zombie state
|
|
||||||
if (playerInfo.Length < 5)
|
|
||||||
continue;
|
|
||||||
int clientId = -1;
|
|
||||||
int Ping = -1;
|
|
||||||
|
|
||||||
Int32.TryParse(playerInfo[2], out Ping);
|
|
||||||
string name = Encoding.UTF8.GetString(Encoding.Convert(Utilities.EncodingType, Encoding.UTF8, Utilities.EncodingType.GetBytes(responseLine.Substring(23, 15).StripColors().Trim())));
|
|
||||||
long networkId = 0;//playerInfo[4].ConvertLong();
|
|
||||||
int.TryParse(playerInfo[0], out clientId);
|
|
||||||
var regex = Regex.Match(responseLine, @"\d+\.\d+\.\d+.\d+\:\d{1,5}");
|
|
||||||
int? ipAddress = regex.Value.Split(':')[0].ConvertToIP();
|
|
||||||
regex = Regex.Match(responseLine, @" +(\d+ +){3}");
|
|
||||||
int score = Int32.Parse(regex.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0]);
|
|
||||||
|
|
||||||
var p = new EFClient()
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
NetworkId = networkId,
|
|
||||||
ClientNumber = clientId,
|
|
||||||
IPAddress = ipAddress,
|
|
||||||
Ping = Ping,
|
|
||||||
Score = score,
|
|
||||||
IsBot = false,
|
|
||||||
State = EFClient.ClientState.Connecting
|
|
||||||
};
|
|
||||||
|
|
||||||
StatusPlayers.Add(p);
|
|
||||||
|
|
||||||
if (p.IsBot)
|
|
||||||
p.NetworkId = -p.ClientNumber;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return StatusPlayers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +1,35 @@
|
|||||||
using System;
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Exceptions;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.RCon;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using SharedLibraryCore;
|
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using SharedLibraryCore.Objects;
|
|
||||||
using SharedLibraryCore.RCon;
|
|
||||||
using SharedLibraryCore.Exceptions;
|
|
||||||
using System.Text;
|
|
||||||
using SharedLibraryCore.Database.Models;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RconParsers
|
||||||
{
|
{
|
||||||
public class T6MRConParser : IRConParser
|
public class T6MRConParser : IRConParser
|
||||||
{
|
{
|
||||||
private static readonly CommandPrefix Prefixes = new CommandPrefix()
|
public IRConParserConfiguration Configuration { get; set; }
|
||||||
{
|
|
||||||
Tell = "tell {0} {1}",
|
|
||||||
Say = "say {0}",
|
|
||||||
Kick = "clientkick_for_reason {0} \"{1}\"",
|
|
||||||
Ban = "clientkick_for_reason {0} \"{1}\"",
|
|
||||||
TempBan = "clientkick_for_reason {0} \"{1}\""
|
|
||||||
};
|
|
||||||
|
|
||||||
public CommandPrefix GetCommandPrefixes() => Prefixes;
|
public T6MRConParser()
|
||||||
|
{
|
||||||
|
Configuration = new DynamicRConParserConfiguration()
|
||||||
|
{
|
||||||
|
CommandPrefixes = new CommandPrefix()
|
||||||
|
{
|
||||||
|
Tell = "tell {0} {1}",
|
||||||
|
Say = "say {0}",
|
||||||
|
Kick = "clientkick_for_reason {0} \"{1}\"",
|
||||||
|
Ban = "clientkick_for_reason {0} \"{1}\"",
|
||||||
|
TempBan = "clientkick_for_reason {0} \"{1}\""
|
||||||
|
},
|
||||||
|
GameName = Server.Game.T6M
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
|
||||||
{
|
{
|
||||||
@ -112,7 +117,9 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (p.IsBot)
|
if (p.IsBot)
|
||||||
|
{
|
||||||
p.NetworkId = -p.ClientNumber;
|
p.NetworkId = -p.ClientNumber;
|
||||||
|
}
|
||||||
|
|
||||||
StatusPlayers.Add(p);
|
StatusPlayers.Add(p);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ namespace SharedLibraryCore.Configuration
|
|||||||
public IList<string> Rules { get; set; }
|
public IList<string> Rules { get; set; }
|
||||||
public IList<string> AutoMessages { get; set; }
|
public IList<string> AutoMessages { get; set; }
|
||||||
public bool UseT6MParser { get; set; }
|
public bool UseT6MParser { get; set; }
|
||||||
public bool UseIW5MParser { get; set; }
|
|
||||||
public string ManualLogPath { get; set; }
|
public string ManualLogPath { get; set; }
|
||||||
public int ReservedSlotNumber { get; set; }
|
public int ReservedSlotNumber { get; set; }
|
||||||
|
|
||||||
@ -36,17 +35,9 @@ namespace SharedLibraryCore.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
Password = Utilities.PromptString(loc["SETUP_SERVER_RCON"]);
|
Password = Utilities.PromptString(loc["SETUP_SERVER_RCON"]);
|
||||||
|
|
||||||
AutoMessages = new List<string>();
|
AutoMessages = new List<string>();
|
||||||
Rules = new List<string>();
|
Rules = new List<string>();
|
||||||
|
|
||||||
|
|
||||||
UseT6MParser = Utilities.PromptBool(loc["SETUP_SERVER_USET6M"]);
|
UseT6MParser = Utilities.PromptBool(loc["SETUP_SERVER_USET6M"]);
|
||||||
if (!UseT6MParser)
|
|
||||||
UseIW5MParser = Utilities.PromptBool(loc["SETUP_SERVER_USEIW5M"]);
|
|
||||||
if (UseIW5MParser)
|
|
||||||
ManualLogPath = Utilities.PromptString(loc["SETUP_SERVER_MANUALLOG"]);
|
|
||||||
|
|
||||||
ReservedSlotNumber = loc["SETUP_SERVER_RESERVEDSLOT"].PromptInt(null, 0, 32);
|
ReservedSlotNumber = loc["SETUP_SERVER_RESERVEDSLOT"].PromptInt(null, 0, 32);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -18,6 +18,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// Get game specific folder prefix for log files
|
/// Get game specific folder prefix for log files
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Game directory prefix</returns>
|
/// <returns>Game directory prefix</returns>
|
||||||
string GetGameDir();
|
IEventParserConfiguration Configuration { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
SharedLibraryCore/Interfaces/IEventParserConfiguration.cs
Normal file
16
SharedLibraryCore/Interfaces/IEventParserConfiguration.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
public interface IEventParserConfiguration
|
||||||
|
{
|
||||||
|
string GameDirectory { get; set; }
|
||||||
|
string SayRegex { get; set; }
|
||||||
|
string JoinRegex { get; set; }
|
||||||
|
string QuitRegex { get; set; }
|
||||||
|
string KillRegex { get; set; }
|
||||||
|
string DamageRegex { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,10 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
IPageList GetPageList();
|
IPageList GetPageList();
|
||||||
|
IList<IRConParser> AdditionalRConParsers { get; }
|
||||||
|
IList<IEventParser> AdditionalEventParsers { get; }
|
||||||
|
IRConParser GenerateDynamicRConParser();
|
||||||
|
IEventParser GenerateDynamicEventParser();
|
||||||
string Version { get;}
|
string Version { get;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
|||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Objects;
|
using SharedLibraryCore.Objects;
|
||||||
using SharedLibraryCore.RCon;
|
using SharedLibraryCore.RCon;
|
||||||
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -12,6 +13,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
Task<bool> SetDvarAsync(Connection connection, string dvarName, object dvarValue);
|
Task<bool> SetDvarAsync(Connection connection, string dvarName, object dvarValue);
|
||||||
Task<string[]> ExecuteCommandAsync(Connection connection, string command);
|
Task<string[]> ExecuteCommandAsync(Connection connection, string command);
|
||||||
Task<List<EFClient>> GetStatusAsync(Connection connection);
|
Task<List<EFClient>> GetStatusAsync(Connection connection);
|
||||||
CommandPrefix GetCommandPrefixes();
|
IRConParserConfiguration Configuration { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
SharedLibraryCore/Interfaces/IRConParserConfiguration.cs
Normal file
11
SharedLibraryCore/Interfaces/IRConParserConfiguration.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using SharedLibraryCore.RCon;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
public interface IRConParserConfiguration
|
||||||
|
{
|
||||||
|
CommandPrefix CommandPrefixes { get; set; }
|
||||||
|
Server.Game GameName { get; set; }
|
||||||
|
string StatusRegex { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -461,6 +461,11 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
if (ipAddress != null)
|
if (ipAddress != null)
|
||||||
{
|
{
|
||||||
|
if (IPAddressString == "66.150.121.184")
|
||||||
|
{
|
||||||
|
Kick("Your favorite servers are outdated. Please re-add the server.", autoKickClient);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,10 @@ namespace SharedLibraryCore.RCon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// interval in milliseconds to wait before sending the next RCon request
|
/// interval in milliseconds to wait before sending the next RCon request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly int FloodProtectionInterval = 635;
|
public static readonly int FloodProtectionInterval = 650;
|
||||||
|
/// <summary>
|
||||||
|
/// how mant failed connection attempts before aborting connection
|
||||||
|
/// </summary>
|
||||||
public static readonly int AllowedConnectionFails = 3;
|
public static readonly int AllowedConnectionFails = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,17 @@ namespace SharedLibraryCore
|
|||||||
this.Name = pluginObject.name;
|
this.Name = pluginObject.name;
|
||||||
this.Version = (float)pluginObject.version;
|
this.Version = (float)pluginObject.version;
|
||||||
|
|
||||||
|
|
||||||
|
if (pluginObject.isParser)
|
||||||
|
{
|
||||||
|
await OnLoadAsync(mgr);
|
||||||
|
IEventParser eventParser = (IEventParser)ScriptEngine.GetValue("eventParser").ToObject();
|
||||||
|
IRConParser rconParser = (IRConParser)ScriptEngine.GetValue("rconParser").ToObject();
|
||||||
|
Manager.AdditionalEventParsers.Add(eventParser);
|
||||||
|
Manager.AdditionalRConParsers.Add(rconParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!firstRun)
|
if (!firstRun)
|
||||||
{
|
{
|
||||||
await OnLoadAsync(mgr);
|
await OnLoadAsync(mgr);
|
||||||
|
@ -120,7 +120,7 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="message">Message to be sent to all players</param>
|
/// <param name="message">Message to be sent to all players</param>
|
||||||
public GameEvent Broadcast(string message, EFClient sender = null)
|
public GameEvent Broadcast(string message, EFClient sender = null)
|
||||||
{
|
{
|
||||||
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}");
|
string formattedMessage = String.Format(RconParser.Configuration.CommandPrefixes.Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}");
|
||||||
|
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Logger.WriteVerbose(message.StripColors());
|
Logger.WriteVerbose(message.StripColors());
|
||||||
|
@ -35,7 +35,7 @@ namespace WebfrontCore.Controllers
|
|||||||
Level = p.Level.ToLocalizedLevelName(),
|
Level = p.Level.ToLocalizedLevelName(),
|
||||||
LevelInt = (int)p.Level
|
LevelInt = (int)p.Level
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
ChatHistory = s.ChatHistory,
|
ChatHistory = s.ChatHistory.ToList(),
|
||||||
PlayerHistory = s.ClientHistory.ToArray(),
|
PlayerHistory = s.ClientHistory.ToArray(),
|
||||||
};
|
};
|
||||||
return PartialView("_ClientActivity", serverInfo);
|
return PartialView("_ClientActivity", serverInfo);
|
||||||
|
@ -6,9 +6,6 @@ using Microsoft.Extensions.Configuration;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using SharedLibraryCore.Database;
|
using SharedLibraryCore.Database;
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace WebfrontCore
|
namespace WebfrontCore
|
||||||
{
|
{
|
||||||
@ -62,6 +59,7 @@ namespace WebfrontCore
|
|||||||
loggerFactory.AddDebug();
|
loggerFactory.AddDebug();
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
app.UseExceptionHandler("/Home/Error");
|
app.UseExceptionHandler("/Home/Error");
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
@{
|
@{
|
||||||
Layout = null;
|
Layout = null;
|
||||||
int half = (int)Math.Ceiling(Model.ClientCount / 2.0);
|
int half = Model.ClientCount == 0 || Model.Players.Count == 0 ? 0 : (int)Math.Ceiling(Model.ClientCount / 2.0);
|
||||||
}
|
}
|
||||||
<div class="col-12 col-md-8 d-none d-md-block">
|
<div class="col-12 col-md-8 d-none d-md-block">
|
||||||
@{
|
@{
|
||||||
@ -43,7 +43,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-6 text-right">
|
<div class="col-6 text-right">
|
||||||
@{
|
@{
|
||||||
for (int i = half; i < Model.ClientCount; i++)
|
for (int i = half; i < Math.Min(Model.ClientCount, Model.Players.Count); i++)
|
||||||
{
|
{
|
||||||
string levelColorClass = !ViewBag.Authorized ? "" : $"level-color-{Model.Players[i].LevelInt}";
|
string levelColorClass = !ViewBag.Authorized ? "" : $"level-color-{Model.Players[i].LevelInt}";
|
||||||
<span>@Html.ActionLink(Model.Players[i].Name, "ProfileAsync", "Client", new { id = Model.Players[i].ClientId }, new { @class = levelColorClass })</span><br />
|
<span>@Html.ActionLink(Model.Players[i].Name, "ProfileAsync", "Client", new { id = Model.Players[i].ClientId }, new { @class = levelColorClass })</span><br />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user