[tweaks and fixes]
reenable tekno support address vagrant thread issue refactor game log reader creation to follow better practices fix bot issues/address how guids are generated for bots/none provided
This commit is contained in:
parent
b49592d666
commit
267e0b8cbe
1
.gitignore
vendored
1
.gitignore
vendored
@ -242,3 +242,4 @@ launchSettings.json
|
|||||||
/WebfrontCore/wwwroot/font
|
/WebfrontCore/wwwroot/font
|
||||||
/Plugins/Tests/TestSourceFiles
|
/Plugins/Tests/TestSourceFiles
|
||||||
/Tests/ApplicationTests/Files/GameEvents.json
|
/Tests/ApplicationTests/Files/GameEvents.json
|
||||||
|
/Tests/ApplicationTests/Files/replay.json
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<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 servers</Description>
|
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated servers</Description>
|
||||||
<Copyright>2019</Copyright>
|
<Copyright>2020</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>
|
||||||
<RepositoryUrl>https://github.com/RaidMax/IW4M-Admin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/RaidMax/IW4M-Admin</RepositoryUrl>
|
||||||
|
@ -31,7 +31,7 @@ namespace IW4MAdmin.Application
|
|||||||
private readonly ConcurrentBag<Server> _servers;
|
private readonly ConcurrentBag<Server> _servers;
|
||||||
public List<Server> Servers => _servers.OrderByDescending(s => s.ClientNum).ToList();
|
public List<Server> Servers => _servers.OrderByDescending(s => s.ClientNum).ToList();
|
||||||
public ILogger Logger => GetLogger(0);
|
public ILogger Logger => GetLogger(0);
|
||||||
public bool Running { get; private set; }
|
public bool IsRunning { get; private set; }
|
||||||
public bool IsInitialized { get; private set; }
|
public bool IsInitialized { get; private set; }
|
||||||
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();
|
||||||
@ -50,7 +50,6 @@ namespace IW4MAdmin.Application
|
|||||||
readonly AliasService AliasSvc;
|
readonly AliasService AliasSvc;
|
||||||
readonly PenaltyService PenaltySvc;
|
readonly PenaltyService PenaltySvc;
|
||||||
public IConfigurationHandler<ApplicationConfiguration> ConfigHandler;
|
public IConfigurationHandler<ApplicationConfiguration> ConfigHandler;
|
||||||
GameEventHandler Handler;
|
|
||||||
readonly IPageList PageList;
|
readonly IPageList PageList;
|
||||||
private readonly Dictionary<long, ILogger> _loggers = new Dictionary<long, ILogger>();
|
private readonly Dictionary<long, ILogger> _loggers = new Dictionary<long, ILogger>();
|
||||||
private readonly MetaService _metaService;
|
private readonly MetaService _metaService;
|
||||||
@ -62,11 +61,13 @@ namespace IW4MAdmin.Application
|
|||||||
private readonly IGameServerInstanceFactory _serverInstanceFactory;
|
private readonly IGameServerInstanceFactory _serverInstanceFactory;
|
||||||
private readonly IParserRegexFactory _parserRegexFactory;
|
private readonly IParserRegexFactory _parserRegexFactory;
|
||||||
private readonly IEnumerable<IRegisterEvent> _customParserEvents;
|
private readonly IEnumerable<IRegisterEvent> _customParserEvents;
|
||||||
|
private readonly IEventHandler _eventHandler;
|
||||||
|
|
||||||
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
public ApplicationManager(ILogger logger, IMiddlewareActionHandler actionHandler, IEnumerable<IManagerCommand> commands,
|
||||||
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
ITranslationLookup translationLookup, IConfigurationHandler<CommandConfiguration> commandConfiguration,
|
||||||
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
IConfigurationHandler<ApplicationConfiguration> appConfigHandler, IGameServerInstanceFactory serverInstanceFactory,
|
||||||
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents)
|
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
||||||
|
IEventHandler eventHandler)
|
||||||
{
|
{
|
||||||
MiddlewareActionHandler = actionHandler;
|
MiddlewareActionHandler = actionHandler;
|
||||||
_servers = new ConcurrentBag<Server>();
|
_servers = new ConcurrentBag<Server>();
|
||||||
@ -90,6 +91,7 @@ namespace IW4MAdmin.Application
|
|||||||
_serverInstanceFactory = serverInstanceFactory;
|
_serverInstanceFactory = serverInstanceFactory;
|
||||||
_parserRegexFactory = parserRegexFactory;
|
_parserRegexFactory = parserRegexFactory;
|
||||||
_customParserEvents = customParserEvents;
|
_customParserEvents = customParserEvents;
|
||||||
|
_eventHandler = eventHandler;
|
||||||
Plugins = plugins;
|
Plugins = plugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +257,7 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
Running = true;
|
IsRunning = true;
|
||||||
ExternalIPAddress = await Utilities.GetExternalIP();
|
ExternalIPAddress = await Utilities.GetExternalIP();
|
||||||
|
|
||||||
#region PLUGINS
|
#region PLUGINS
|
||||||
@ -589,9 +591,6 @@ namespace IW4MAdmin.Application
|
|||||||
|
|
||||||
async Task Init(ServerConfiguration Conf)
|
async Task Init(ServerConfiguration Conf)
|
||||||
{
|
{
|
||||||
// setup the event handler after the class is initialized
|
|
||||||
Handler = new GameEventHandler(this);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// todo: this might not always be an IW4MServer
|
// todo: this might not always be an IW4MServer
|
||||||
@ -610,7 +609,7 @@ namespace IW4MAdmin.Application
|
|||||||
Owner = ServerInstance
|
Owner = ServerInstance
|
||||||
};
|
};
|
||||||
|
|
||||||
Handler.AddEvent(e);
|
AddEvent(e);
|
||||||
successServers++;
|
successServers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -726,7 +725,7 @@ namespace IW4MAdmin.Application
|
|||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
_tokenSource.Cancel();
|
_tokenSource.Cancel();
|
||||||
Running = false;
|
IsRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Restart()
|
public void Restart()
|
||||||
@ -782,9 +781,9 @@ namespace IW4MAdmin.Application
|
|||||||
return ConfigHandler;
|
return ConfigHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEventHandler GetEventHandler()
|
public void AddEvent(GameEvent gameEvent)
|
||||||
{
|
{
|
||||||
return Handler;
|
_eventHandler.HandleEvent(this, gameEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPageList GetPageList()
|
public IPageList GetPageList()
|
||||||
|
@ -23,26 +23,26 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
GameDirectory = "main",
|
GameDirectory = "main",
|
||||||
};
|
};
|
||||||
|
|
||||||
Configuration.Say.Pattern = @"^(say|sayteam);(-?[A-Fa-f0-9_]{1,32});([0-9]+);(.+);(.*)$";
|
Configuration.Say.Pattern = @"^(say|sayteam);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);([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_]{1,32}|bot[0-9]+);([0-9]+);(.*)$";
|
Configuration.Quit.Pattern = @"^(Q);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);([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_]{1,32}|bot[0-9]+);([0-9]+);(.*)$";
|
Configuration.Join.Pattern = @"^(J);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);([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_]{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.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[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);
|
||||||
@ -57,7 +57,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_]{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.Pattern = @"^(K);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world)?;([^;]{1,24});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[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);
|
||||||
@ -118,7 +118,13 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (message.Length > 0)
|
if (message.Length > 0)
|
||||||
{
|
{
|
||||||
long originId = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle);
|
string originIdString = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
||||||
|
string originName = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
||||||
|
|
||||||
|
long originId = originIdString.IsBotGuid() ?
|
||||||
|
originName.GenerateGuidFromString() :
|
||||||
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
|
||||||
int clientNumber = int.Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
int clientNumber = int.Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
|
|
||||||
// todo: these need to defined outside of here
|
// todo: these need to defined outside of here
|
||||||
@ -132,7 +138,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Message = message,
|
Message = message,
|
||||||
Extra = logLine,
|
Extra = logLine,
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +151,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Message = message,
|
Message = message,
|
||||||
Extra = logLine,
|
Extra = logLine,
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,8 +164,18 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
long originId = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
string originIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
||||||
long targetId = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
string targetIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString();
|
||||||
|
string originName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
||||||
|
string targetName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetName]].ToString();
|
||||||
|
|
||||||
|
long originId = originIdString.IsBotGuid() ?
|
||||||
|
originName.GenerateGuidFromString() :
|
||||||
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
|
long targetId = targetIdString.IsBotGuid() ?
|
||||||
|
targetName.GenerateGuidFromString() :
|
||||||
|
targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
|
|
||||||
int originClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
int originClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
int targetClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
int targetClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
||||||
|
|
||||||
@ -168,7 +186,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber },
|
Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber },
|
||||||
Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber },
|
Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber },
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,8 +198,18 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
long originId = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
string originIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
||||||
long targetId = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle, 1);
|
string targetIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString();
|
||||||
|
string originName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
||||||
|
string targetName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetName]].ToString();
|
||||||
|
|
||||||
|
long originId = originIdString.IsBotGuid() ?
|
||||||
|
originName.GenerateGuidFromString() :
|
||||||
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
|
long targetId = targetIdString.IsBotGuid() ?
|
||||||
|
targetName.GenerateGuidFromString() :
|
||||||
|
targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
|
|
||||||
int originClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
int originClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
int targetClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
int targetClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
||||||
|
|
||||||
@ -191,7 +220,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber },
|
Origin = new EFClient() { NetworkId = originId, ClientNumber = originClientNumber },
|
||||||
Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber },
|
Target = new EFClient() { NetworkId = targetId, ClientNumber = targetClientNumber },
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
RequiredEntity = GameEvent.EventRequiredEntity.Origin | GameEvent.EventRequiredEntity.Target,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,6 +232,13 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
|
string originIdString = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
||||||
|
string originName = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
||||||
|
|
||||||
|
long networkId = originIdString.IsBotGuid() ?
|
||||||
|
originName.GenerateGuidFromString() :
|
||||||
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.PreConnect,
|
Type = GameEvent.EventType.PreConnect,
|
||||||
@ -212,13 +249,14 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
Name = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine(),
|
Name = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine(),
|
||||||
},
|
},
|
||||||
NetworkId = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle),
|
NetworkId = networkId,
|
||||||
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
||||||
State = EFClient.ClientState.Connecting,
|
State = EFClient.ClientState.Connecting,
|
||||||
},
|
},
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
IsBlocking = true,
|
IsBlocking = true,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,6 +267,13 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
|
string originIdString = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
||||||
|
string originName = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
||||||
|
|
||||||
|
long networkId = originIdString.IsBotGuid() ?
|
||||||
|
originName.GenerateGuidFromString() :
|
||||||
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.PreDisconnect,
|
Type = GameEvent.EventType.PreDisconnect,
|
||||||
@ -239,13 +284,14 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
Name = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine()
|
Name = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine()
|
||||||
},
|
},
|
||||||
NetworkId = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString().ConvertGuidToLong(Configuration.GuidNumberStyle),
|
NetworkId = networkId,
|
||||||
ClientNumber = Convert.ToInt32(match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
||||||
State = EFClient.ClientState.Disconnecting
|
State = EFClient.ClientState.Disconnecting
|
||||||
},
|
},
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
IsBlocking = true,
|
IsBlocking = true,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,7 +305,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Origin = Utilities.IW4MAdminClient(),
|
Origin = Utilities.IW4MAdminClient(),
|
||||||
Target = Utilities.IW4MAdminClient(),
|
Target = Utilities.IW4MAdminClient(),
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +322,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Target = Utilities.IW4MAdminClient(),
|
Target = Utilities.IW4MAdminClient(),
|
||||||
Extra = dump.DictionaryFromKeyValue(),
|
Extra = dump.DictionaryFromKeyValue(),
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +338,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Type = GameEvent.EventType.Other,
|
Type = GameEvent.EventType.Other,
|
||||||
Data = logLine,
|
Data = logLine,
|
||||||
Subtype = eventModifier.Item1,
|
Subtype = eventModifier.Item1,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +356,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Origin = Utilities.IW4MAdminClient(),
|
Origin = Utilities.IW4MAdminClient(),
|
||||||
Target = Utilities.IW4MAdminClient(),
|
Target = Utilities.IW4MAdminClient(),
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
GameTime = gameTime
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
Application/Factories/GameLogReaderFactory.cs
Normal file
33
Application/Factories/GameLogReaderFactory.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using IW4MAdmin.Application.IO;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Factories
|
||||||
|
{
|
||||||
|
public class GameLogReaderFactory : IGameLogReaderFactory
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public GameLogReaderFactory(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IGameLogReader CreateGameLogReader(Uri[] logUris, IEventParser eventParser)
|
||||||
|
{
|
||||||
|
var baseUri = logUris[0];
|
||||||
|
if (baseUri.Scheme == Uri.UriSchemeHttp)
|
||||||
|
{
|
||||||
|
return new GameLogReaderHttp(logUris, eventParser, _serviceProvider.GetRequiredService<ILogger>());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (baseUri.Scheme == Uri.UriSchemeFile)
|
||||||
|
{
|
||||||
|
return new GameLogReader(baseUri.LocalPath, eventParser, _serviceProvider.GetRequiredService<ILogger>());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException($"No log reader implemented for Uri scheme \"{baseUri.Scheme}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,16 +12,18 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
{
|
{
|
||||||
private readonly ITranslationLookup _translationLookup;
|
private readonly ITranslationLookup _translationLookup;
|
||||||
private readonly IRConConnectionFactory _rconConnectionFactory;
|
private readonly IRConConnectionFactory _rconConnectionFactory;
|
||||||
|
private readonly IGameLogReaderFactory _gameLogReaderFactory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// base constructor
|
/// base constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="translationLookup"></param>
|
/// <param name="translationLookup"></param>
|
||||||
/// <param name="rconConnectionFactory"></param>
|
/// <param name="rconConnectionFactory"></param>
|
||||||
public GameServerInstanceFactory(ITranslationLookup translationLookup, IRConConnectionFactory rconConnectionFactory)
|
public GameServerInstanceFactory(ITranslationLookup translationLookup, IRConConnectionFactory rconConnectionFactory, IGameLogReaderFactory gameLogReaderFactory)
|
||||||
{
|
{
|
||||||
_translationLookup = translationLookup;
|
_translationLookup = translationLookup;
|
||||||
_rconConnectionFactory = rconConnectionFactory;
|
_rconConnectionFactory = rconConnectionFactory;
|
||||||
|
_gameLogReaderFactory = gameLogReaderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -32,7 +34,7 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Server CreateServer(ServerConfiguration config, IManager manager)
|
public Server CreateServer(ServerConfiguration config, IManager manager)
|
||||||
{
|
{
|
||||||
return new IW4MServer(manager, config, _translationLookup, _rconConnectionFactory);
|
return new IW4MServer(manager, config, _translationLookup, _rconConnectionFactory, _gameLogReaderFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Events;
|
using SharedLibraryCore.Events;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application
|
namespace IW4MAdmin.Application
|
||||||
{
|
{
|
||||||
class GameEventHandler : IEventHandler
|
public class GameEventHandler : IEventHandler
|
||||||
{
|
{
|
||||||
private const int MAX_CONCURRENT_EVENTS = 10;
|
private readonly EventLog _eventLog;
|
||||||
private readonly ApplicationManager _manager;
|
|
||||||
private readonly SemaphoreSlim _processingEvents;
|
|
||||||
private static readonly GameEvent.EventType[] overrideEvents = new[]
|
private static readonly GameEvent.EventType[] overrideEvents = new[]
|
||||||
{
|
{
|
||||||
GameEvent.EventType.Connect,
|
GameEvent.EventType.Connect,
|
||||||
@ -22,39 +22,12 @@ namespace IW4MAdmin.Application
|
|||||||
GameEvent.EventType.Stop
|
GameEvent.EventType.Stop
|
||||||
};
|
};
|
||||||
|
|
||||||
public GameEventHandler(IManager mgr)
|
public GameEventHandler()
|
||||||
{
|
{
|
||||||
_manager = (ApplicationManager)mgr;
|
_eventLog = new EventLog();
|
||||||
_processingEvents = new SemaphoreSlim(MAX_CONCURRENT_EVENTS, MAX_CONCURRENT_EVENTS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task GameEventHandler_GameEventAdded(object sender, GameEventArgs args)
|
public void HandleEvent(IManager manager, GameEvent gameEvent)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// this is not elegant and there's probably a much better way to do it, but it works for now
|
|
||||||
_processingEvents.Wait();
|
|
||||||
EventApi.OnGameEvent(sender, args);
|
|
||||||
return _manager.ExecuteEvent(args.Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (_processingEvents.CurrentCount < MAX_CONCURRENT_EVENTS)
|
|
||||||
{
|
|
||||||
_processingEvents.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(GameEvent gameEvent)
|
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ThreadPool.GetMaxThreads(out int workerThreads, out int n);
|
ThreadPool.GetMaxThreads(out int workerThreads, out int n);
|
||||||
@ -62,12 +35,23 @@ namespace IW4MAdmin.Application
|
|||||||
gameEvent.Owner.Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
gameEvent.Owner.Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
if (_manager.Running || overrideEvents.Contains(gameEvent.Type))
|
if (manager.IsRunning || overrideEvents.Contains(gameEvent.Type))
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
gameEvent.Owner.Logger.WriteDebug($"Adding event with id {gameEvent.Id}");
|
gameEvent.Owner.Logger.WriteDebug($"Adding event with id {gameEvent.Id}");
|
||||||
#endif
|
#endif
|
||||||
Task.Run(() => GameEventHandler_GameEventAdded(this, new GameEventArgs(null, false, gameEvent)));
|
|
||||||
|
EventApi.OnGameEvent(gameEvent);
|
||||||
|
Task.Factory.StartNew(() => manager.ExecuteEvent(gameEvent));
|
||||||
|
|
||||||
|
/*if (!_eventLog.ContainsKey(gameEvent.Owner.EndPoint))
|
||||||
|
{
|
||||||
|
_eventLog.Add(gameEvent.Owner.EndPoint,new List<GameEvent>());
|
||||||
|
}
|
||||||
|
_eventLog[gameEvent.Owner.EndPoint].Add(gameEvent);
|
||||||
|
string serializedEvents = JsonConvert.SerializeObject(_eventLog, EventLog.BuildVcrSerializationSettings());
|
||||||
|
System.IO.File.WriteAllText("output.json", serializedEvents);*/
|
||||||
|
//Task.Run(() => GameEventHandler_GameEventAdded(this, new GameEventArgs(null, false, gameEvent)));
|
||||||
}
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
else
|
else
|
||||||
|
@ -13,17 +13,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
private readonly IGameLogReader _reader;
|
private readonly IGameLogReader _reader;
|
||||||
private readonly bool _ignoreBots;
|
private readonly bool _ignoreBots;
|
||||||
|
|
||||||
class EventState
|
public GameLogEventDetection(Server server, Uri[] gameLogUris, IGameLogReaderFactory gameLogReaderFactory)
|
||||||
{
|
{
|
||||||
public ILogger Log { get; set; }
|
_reader = gameLogReaderFactory.CreateGameLogReader(gameLogUris, server.EventParser);
|
||||||
public string ServerId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameLogEventDetection(Server server, string gameLogPath, Uri gameLogServerUri, IGameLogReader reader = null)
|
|
||||||
{
|
|
||||||
_reader = gameLogServerUri != null
|
|
||||||
? reader ?? new GameLogReaderHttp(gameLogServerUri, gameLogPath, server.EventParser)
|
|
||||||
: reader ?? new GameLogReader(gameLogPath, server.EventParser);
|
|
||||||
_server = server;
|
_server = server;
|
||||||
_ignoreBots = server?.Manager.GetApplicationSettings().Configuration().IgnoreBots ?? false;
|
_ignoreBots = server?.Manager.GetApplicationSettings().Configuration().IgnoreBots ?? false;
|
||||||
}
|
}
|
||||||
@ -70,7 +62,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var events = await _reader.ReadEventsFromLog(_server, fileDiff, previousFileSize);
|
var events = await _reader.ReadEventsFromLog(fileDiff, previousFileSize);
|
||||||
|
|
||||||
foreach (var gameEvent in events)
|
foreach (var gameEvent in events)
|
||||||
{
|
{
|
||||||
@ -84,9 +76,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
// we don't want to add the event if ignoreBots is on and the event comes from a bot
|
// we don't want to add the event if ignoreBots is on and the event comes from a bot
|
||||||
if (!_ignoreBots || (_ignoreBots && !((gameEvent.Origin?.IsBot ?? false) || (gameEvent.Target?.IsBot ?? false))))
|
if (!_ignoreBots || (_ignoreBots && !((gameEvent.Origin?.IsBot ?? false) || (gameEvent.Target?.IsBot ?? false))))
|
||||||
{
|
{
|
||||||
if ((gameEvent.RequiredEntity & GameEvent.EventRequiredEntity.Origin) == GameEvent.EventRequiredEntity.Origin && gameEvent.Origin.NetworkId != 1)
|
if ((gameEvent.RequiredEntity & GameEvent.EventRequiredEntity.Origin) == GameEvent.EventRequiredEntity.Origin && gameEvent.Origin.NetworkId != Utilities.WORLD_ID)
|
||||||
{
|
{
|
||||||
gameEvent.Origin = _server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Origin?.NetworkId);
|
gameEvent.Origin = _server.GetClientsAsList().First(_client => _client.NetworkId == gameEvent.Origin?.NetworkId);;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((gameEvent.RequiredEntity & GameEvent.EventRequiredEntity.Target) == GameEvent.EventRequiredEntity.Target)
|
if ((gameEvent.RequiredEntity & GameEvent.EventRequiredEntity.Target) == GameEvent.EventRequiredEntity.Target)
|
||||||
@ -104,7 +96,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
gameEvent.Target.CurrentServer = _server;
|
gameEvent.Target.CurrentServer = _server;
|
||||||
}
|
}
|
||||||
|
|
||||||
_server.Manager.GetEventHandler().AddEvent(gameEvent);
|
_server.Manager.AddEvent(gameEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,18 +13,20 @@ namespace IW4MAdmin.Application.IO
|
|||||||
{
|
{
|
||||||
private readonly IEventParser _parser;
|
private readonly IEventParser _parser;
|
||||||
private readonly string _logFile;
|
private readonly string _logFile;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public long Length => new FileInfo(_logFile).Length;
|
public long Length => new FileInfo(_logFile).Length;
|
||||||
|
|
||||||
public int UpdateInterval => 300;
|
public int UpdateInterval => 300;
|
||||||
|
|
||||||
public GameLogReader(string logFile, IEventParser parser)
|
public GameLogReader(string logFile, IEventParser parser, ILogger logger)
|
||||||
{
|
{
|
||||||
_logFile = logFile;
|
_logFile = logFile;
|
||||||
_parser = parser;
|
_parser = parser;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
public async Task<IEnumerable<GameEvent>> ReadEventsFromLog(long fileSizeDiff, long startPosition)
|
||||||
{
|
{
|
||||||
// allocate the bytes for the new log lines
|
// allocate the bytes for the new log lines
|
||||||
List<string> logLines = new List<string>();
|
List<string> logLines = new List<string>();
|
||||||
@ -34,7 +36,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
{
|
{
|
||||||
byte[] buff = new byte[fileSizeDiff];
|
byte[] buff = new byte[fileSizeDiff];
|
||||||
fs.Seek(startPosition, SeekOrigin.Begin);
|
fs.Seek(startPosition, SeekOrigin.Begin);
|
||||||
await fs.ReadAsync(buff, 0, (int)fileSizeDiff, server.Manager.CancellationToken);
|
await fs.ReadAsync(buff, 0, (int)fileSizeDiff);
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
char[] charBuff = Utilities.EncodingType.GetChars(buff);
|
char[] charBuff = Utilities.EncodingType.GetChars(buff);
|
||||||
|
|
||||||
@ -71,9 +73,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
server.Logger.WriteWarning("Could not properly parse event line");
|
_logger.WriteWarning("Could not properly parse event line");
|
||||||
server.Logger.WriteDebug(e.Message);
|
_logger.WriteDebug(e.Message);
|
||||||
server.Logger.WriteDebug(eventLine);
|
_logger.WriteDebug(eventLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,43 +5,42 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static SharedLibraryCore.Utilities;
|
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// provides capibility of reading log files over HTTP
|
/// provides capability of reading log files over HTTP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class GameLogReaderHttp : IGameLogReader
|
class GameLogReaderHttp : IGameLogReader
|
||||||
{
|
{
|
||||||
private readonly IEventParser _eventParser;
|
private readonly IEventParser _eventParser;
|
||||||
private readonly IGameLogServer _logServerApi;
|
private readonly IGameLogServer _logServerApi;
|
||||||
readonly string logPath;
|
private readonly ILogger _logger;
|
||||||
|
private readonly string _safeLogPath;
|
||||||
private string lastKey = "next";
|
private string lastKey = "next";
|
||||||
|
|
||||||
public GameLogReaderHttp(Uri gameLogServerUri, string logPath, IEventParser parser)
|
public GameLogReaderHttp(Uri[] gameLogServerUris, IEventParser parser, ILogger logger)
|
||||||
{
|
{
|
||||||
this.logPath = logPath.ToBase64UrlSafeString();
|
|
||||||
_eventParser = parser;
|
_eventParser = parser;
|
||||||
_logServerApi = RestClient.For<IGameLogServer>(gameLogServerUri);
|
_logServerApi = RestClient.For<IGameLogServer>(gameLogServerUris[0].ToString());
|
||||||
|
_safeLogPath = gameLogServerUris[1].LocalPath.ToBase64UrlSafeString();
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Length => -1;
|
public long Length => -1;
|
||||||
|
|
||||||
public int UpdateInterval => 500;
|
public int UpdateInterval => 500;
|
||||||
|
|
||||||
public async Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
public async Task<IEnumerable<GameEvent>> ReadEventsFromLog(long fileSizeDiff, long startPosition)
|
||||||
{
|
{
|
||||||
var events = new List<GameEvent>();
|
var events = new List<GameEvent>();
|
||||||
string b64Path = logPath;
|
var response = await _logServerApi.Log(_safeLogPath, lastKey);
|
||||||
var response = await _logServerApi.Log(b64Path, lastKey);
|
|
||||||
lastKey = response.NextKey;
|
lastKey = response.NextKey;
|
||||||
|
|
||||||
if (!response.Success && string.IsNullOrEmpty(lastKey))
|
if (!response.Success && string.IsNullOrEmpty(lastKey))
|
||||||
{
|
{
|
||||||
server.Logger.WriteError($"Could not get log server info of {logPath}/{b64Path} ({server.LogPath})");
|
_logger.WriteError($"Could not get log server info of {_safeLogPath}");
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +62,9 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
server.Logger.WriteError("Could not properly parse event line from http");
|
_logger.WriteError("Could not properly parse event line from http");
|
||||||
server.Logger.WriteDebug(e.Message);
|
_logger.WriteDebug(e.Message);
|
||||||
server.Logger.WriteDebug(eventLine);
|
_logger.WriteDebug(eventLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -31,7 +32,7 @@ namespace IW4MAdmin
|
|||||||
public int Id { get; private set; }
|
public int Id { get; private set; }
|
||||||
|
|
||||||
public IW4MServer(IManager mgr, ServerConfiguration cfg, ITranslationLookup lookup,
|
public IW4MServer(IManager mgr, ServerConfiguration cfg, ITranslationLookup lookup,
|
||||||
IRConConnectionFactory connectionFactory) : base(mgr, connectionFactory, cfg)
|
IRConConnectionFactory connectionFactory, IGameLogReaderFactory gameLogReaderFactory) : base(cfg, mgr, connectionFactory, gameLogReaderFactory)
|
||||||
{
|
{
|
||||||
_translationLookup = lookup;
|
_translationLookup = lookup;
|
||||||
}
|
}
|
||||||
@ -77,7 +78,7 @@ namespace IW4MAdmin
|
|||||||
Type = GameEvent.EventType.Connect
|
Type = GameEvent.EventType.Connect
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ namespace IW4MAdmin
|
|||||||
Type = GameEvent.EventType.Disconnect
|
Type = GameEvent.EventType.Disconnect
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -176,6 +177,8 @@ namespace IW4MAdmin
|
|||||||
await command.ExecuteAsync(E);
|
await command.ExecuteAsync(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var pluginTasks = Manager.Plugins.Where(_plugin => _plugin.Name != "Login").Select(async _plugin =>
|
var pluginTasks = Manager.Plugins.Where(_plugin => _plugin.Name != "Login").Select(async _plugin =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -186,7 +189,11 @@ namespace IW4MAdmin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _plugin.OnEventAsync(E, this);
|
using (var tokenSource = new CancellationTokenSource())
|
||||||
|
{
|
||||||
|
tokenSource.CancelAfter(Utilities.DefaultCommandTimeout);
|
||||||
|
await (_plugin.OnEventAsync(E, this)).WithWaitCancellation(tokenSource.Token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception Except)
|
catch (Exception Except)
|
||||||
{
|
{
|
||||||
@ -195,7 +202,7 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Parallel.ForEach(pluginTasks, async (_task) => await _task);
|
await Task.WhenAny(pluginTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -314,7 +321,8 @@ namespace IW4MAdmin
|
|||||||
// this happens for some reason rarely where the client spots get out of order
|
// this happens for some reason rarely where the client spots get out of order
|
||||||
// possible a connect/reconnect game event before we get to process it here
|
// possible a connect/reconnect game event before we get to process it here
|
||||||
// it appears that new games decide to switch client slots between maps (even if the clients aren't disconnecting)
|
// it appears that new games decide to switch client slots between maps (even if the clients aren't disconnecting)
|
||||||
else if (existingClient != null && existingClient.ClientNumber != E.Origin.ClientNumber)
|
// bots can have duplicate names which causes conflicting GUIDs
|
||||||
|
else if (existingClient != null && existingClient.ClientNumber != E.Origin.ClientNumber && !E.Origin.IsBot)
|
||||||
{
|
{
|
||||||
Logger.WriteWarning($"client {E.Origin} is trying to connect in client slot {E.Origin.ClientNumber}, but they are already registed in client slot {existingClient.ClientNumber}, swapping...");
|
Logger.WriteWarning($"client {E.Origin} is trying to connect in client slot {E.Origin.ClientNumber}, but they are already registed in client slot {existingClient.ClientNumber}, swapping...");
|
||||||
// we need to remove them so the client spots can swap
|
// we need to remove them so the client spots can swap
|
||||||
@ -727,7 +735,7 @@ namespace IW4MAdmin
|
|||||||
Origin = client
|
Origin = client
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
|
|
||||||
await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token);
|
await e.WaitAsync(Utilities.DefaultCommandTimeout, new CancellationTokenRegistration().Token);
|
||||||
}
|
}
|
||||||
@ -771,10 +779,11 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
Type = GameEvent.EventType.PreDisconnect,
|
Type = GameEvent.EventType.PreDisconnect,
|
||||||
Origin = disconnectingClient,
|
Origin = disconnectingClient,
|
||||||
Owner = this
|
Owner = this,
|
||||||
|
Source = GameEvent.EventSource.Status
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
await e.WaitAsync(Utilities.DefaultCommandTimeout, Manager.CancellationToken);
|
await e.WaitAsync(Utilities.DefaultCommandTimeout, Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,10 +802,11 @@ namespace IW4MAdmin
|
|||||||
Type = GameEvent.EventType.PreConnect,
|
Type = GameEvent.EventType.PreConnect,
|
||||||
Origin = client,
|
Origin = client,
|
||||||
Owner = this,
|
Owner = this,
|
||||||
IsBlocking = true
|
IsBlocking = true,
|
||||||
|
Source = GameEvent.EventSource.Status
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
await e.WaitAsync(Utilities.DefaultCommandTimeout, Manager.CancellationToken);
|
await e.WaitAsync(Utilities.DefaultCommandTimeout, Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,7 +821,7 @@ namespace IW4MAdmin
|
|||||||
Owner = this
|
Owner = this
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
@ -824,7 +834,7 @@ namespace IW4MAdmin
|
|||||||
Target = Utilities.IW4MAdminClient(this)
|
Target = Utilities.IW4MAdminClient(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(_event);
|
Manager.AddEvent(_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionErrors = 0;
|
ConnectionErrors = 0;
|
||||||
@ -846,7 +856,7 @@ namespace IW4MAdmin
|
|||||||
Data = ConnectionErrors.ToString()
|
Data = ConnectionErrors.ToString()
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(_event);
|
Manager.AddEvent(_event);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1071,7 +1081,7 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogEvent = new GameLogEventDetection(this, LogPath, ServerConfig.GameLogServerUrl);
|
LogEvent = new GameLogEventDetection(this, GenerateUriForLog(LogPath, ServerConfig.GameLogServerUrl?.AbsoluteUri), gameLogReaderFactory);
|
||||||
Logger.WriteInfo($"Log file is {LogPath}");
|
Logger.WriteInfo($"Log file is {LogPath}");
|
||||||
|
|
||||||
_ = Task.Run(() => LogEvent.PollForChanges());
|
_ = Task.Run(() => LogEvent.PollForChanges());
|
||||||
@ -1080,6 +1090,21 @@ namespace IW4MAdmin
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uri[] GenerateUriForLog(string logPath, string gameLogServerUrl)
|
||||||
|
{
|
||||||
|
var logUri = new Uri(logPath);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(gameLogServerUrl))
|
||||||
|
{
|
||||||
|
return new[] { logUri };
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new[] { new Uri(gameLogServerUrl), logUri };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string GenerateLogPath(LogPathGeneratorInfo logInfo)
|
public static string GenerateLogPath(LogPathGeneratorInfo logInfo)
|
||||||
{
|
{
|
||||||
string logPath;
|
string logPath;
|
||||||
@ -1179,7 +1204,7 @@ namespace IW4MAdmin
|
|||||||
Owner = this
|
Owner = this
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
|
|
||||||
string formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick, targetClient.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7");
|
string formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick, targetClient.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7");
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
await targetClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||||
|
@ -30,7 +30,7 @@ namespace IW4MAdmin.Application
|
|||||||
/// entrypoint of the application
|
/// entrypoint of the application
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task Main()
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
AppDomain.CurrentDomain.SetData("DataDirectory", Utilities.OperatingDirectory);
|
AppDomain.CurrentDomain.SetData("DataDirectory", Utilities.OperatingDirectory);
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ namespace IW4MAdmin.Application
|
|||||||
Console.WriteLine($" Version {Utilities.GetVersionAsString()}");
|
Console.WriteLine($" Version {Utilities.GetVersionAsString()}");
|
||||||
Console.WriteLine("=====================================================");
|
Console.WriteLine("=====================================================");
|
||||||
|
|
||||||
await LaunchAsync();
|
await LaunchAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -64,7 +64,7 @@ namespace IW4MAdmin.Application
|
|||||||
/// task that initializes application and starts the application monitoring and runtime tasks
|
/// task that initializes application and starts the application monitoring and runtime tasks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static async Task LaunchAsync()
|
private static async Task LaunchAsync(string[] args)
|
||||||
{
|
{
|
||||||
restart:
|
restart:
|
||||||
ITranslationLookup translationLookup = null;
|
ITranslationLookup translationLookup = null;
|
||||||
@ -74,7 +74,7 @@ namespace IW4MAdmin.Application
|
|||||||
ConfigurationMigration.MoveConfigFolder10518(null);
|
ConfigurationMigration.MoveConfigFolder10518(null);
|
||||||
ConfigurationMigration.CheckDirectories();
|
ConfigurationMigration.CheckDirectories();
|
||||||
|
|
||||||
var services = ConfigureServices();
|
var services = ConfigureServices(args);
|
||||||
serviceProvider = services.BuildServiceProvider();
|
serviceProvider = services.BuildServiceProvider();
|
||||||
ServerManager = (ApplicationManager)serviceProvider.GetRequiredService<IManager>();
|
ServerManager = (ApplicationManager)serviceProvider.GetRequiredService<IManager>();
|
||||||
translationLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
translationLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
||||||
@ -252,7 +252,7 @@ namespace IW4MAdmin.Application
|
|||||||
Owner = ServerManager.Servers[0]
|
Owner = ServerManager.Servers[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
ServerManager.GetEventHandler().AddEvent(E);
|
ServerManager.AddEvent(E);
|
||||||
await E.WaitAsync(Utilities.DefaultCommandTimeout, ServerManager.CancellationToken);
|
await E.WaitAsync(Utilities.DefaultCommandTimeout, ServerManager.CancellationToken);
|
||||||
Console.Write('>');
|
Console.Write('>');
|
||||||
}
|
}
|
||||||
@ -266,7 +266,7 @@ namespace IW4MAdmin.Application
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configures the dependency injection services
|
/// Configures the dependency injection services
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static IServiceCollection ConfigureServices()
|
private static IServiceCollection ConfigureServices(string[] args)
|
||||||
{
|
{
|
||||||
var defaultLogger = new Logger("IW4MAdmin-Manager");
|
var defaultLogger = new Logger("IW4MAdmin-Manager");
|
||||||
var pluginImporter = new PluginImporter(defaultLogger);
|
var pluginImporter = new PluginImporter(defaultLogger);
|
||||||
@ -285,6 +285,7 @@ namespace IW4MAdmin.Application
|
|||||||
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
.AddSingleton<IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
|
||||||
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
.AddSingleton<IParserRegexFactory, ParserRegexFactory>()
|
||||||
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>()
|
.AddSingleton<IDatabaseContextFactory, DatabaseContextFactory>()
|
||||||
|
.AddSingleton<IGameLogReaderFactory, GameLogReaderFactory>()
|
||||||
.AddSingleton<IAuditInformationRepository, AuditInformationRepository>()
|
.AddSingleton<IAuditInformationRepository, AuditInformationRepository>()
|
||||||
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
|
||||||
.AddSingleton(_serviceProvider =>
|
.AddSingleton(_serviceProvider =>
|
||||||
@ -295,6 +296,15 @@ namespace IW4MAdmin.Application
|
|||||||
})
|
})
|
||||||
.AddSingleton<IManager, ApplicationManager>();
|
.AddSingleton<IManager, ApplicationManager>();
|
||||||
|
|
||||||
|
if (args.Contains("serialevents"))
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<IEventHandler, SerialGameEventHandler>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton<IEventHandler, GameEventHandler>();
|
||||||
|
}
|
||||||
|
|
||||||
// register the native commands
|
// register the native commands
|
||||||
foreach (var commandType in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
|
foreach (var commandType in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
|
||||||
.Where(_command => _command.BaseType == typeof(Command)))
|
.Where(_command => _command.BaseType == typeof(Command)))
|
||||||
|
27
Application/Misc/EventLog.cs
Normal file
27
Application/Misc/EventLog.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
public class EventLog : Dictionary<long, IList<GameEvent>>
|
||||||
|
{
|
||||||
|
private static JsonSerializerSettings serializationSettings;
|
||||||
|
|
||||||
|
public static JsonSerializerSettings BuildVcrSerializationSettings()
|
||||||
|
{
|
||||||
|
if (serializationSettings == null)
|
||||||
|
{
|
||||||
|
serializationSettings = new JsonSerializerSettings() { Formatting = Formatting.Indented, ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
|
||||||
|
serializationSettings.Converters.Add(new IPAddressConverter());
|
||||||
|
serializationSettings.Converters.Add(new IPEndPointConverter());
|
||||||
|
serializationSettings.Converters.Add(new GameEventConverter());
|
||||||
|
serializationSettings.Converters.Add(new ClientEntityConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
return serializationSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
149
Application/Misc/SerializationHelpers.cs
Normal file
149
Application/Misc/SerializationHelpers.cs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
|
using static SharedLibraryCore.GameEvent;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
class IPAddressConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return (objectType == typeof(IPAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
writer.WriteValue(value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
return IPAddress.Parse((string)reader.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IPEndPointConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return (objectType == typeof(IPEndPoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
IPEndPoint ep = (IPEndPoint)value;
|
||||||
|
JObject jo = new JObject();
|
||||||
|
jo.Add("Address", JToken.FromObject(ep.Address, serializer));
|
||||||
|
jo.Add("Port", ep.Port);
|
||||||
|
jo.WriteTo(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
JObject jo = JObject.Load(reader);
|
||||||
|
IPAddress address = jo["Address"].ToObject<IPAddress>(serializer);
|
||||||
|
int port = (int)jo["Port"];
|
||||||
|
return new IPEndPoint(address, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClientEntityConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvert(Type objectType) => objectType == typeof(EFClient);
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType,object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.Value == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonObject = JObject.Load(reader);
|
||||||
|
|
||||||
|
return new EFClient
|
||||||
|
{
|
||||||
|
NetworkId = (long)jsonObject["NetworkId"],
|
||||||
|
ClientNumber = (int)jsonObject["ClientNumber"],
|
||||||
|
State = Enum.Parse<ClientState>(jsonObject["state"].ToString()),
|
||||||
|
CurrentAlias = new EFAlias()
|
||||||
|
{
|
||||||
|
IPAddress = (int?)jsonObject["IPAddress"],
|
||||||
|
Name = jsonObject["Name"].ToString()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var client = value as EFClient;
|
||||||
|
var jsonObject = new JObject
|
||||||
|
{
|
||||||
|
{ "NetworkId", client.NetworkId },
|
||||||
|
{ "ClientNumber", client.ClientNumber },
|
||||||
|
{ "IPAddress", client.CurrentAlias?.IPAddress },
|
||||||
|
{ "Name", client.CurrentAlias?.Name },
|
||||||
|
{ "State", (int)client.State }
|
||||||
|
};
|
||||||
|
|
||||||
|
jsonObject.WriteTo(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameEventConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvert(Type objectType) =>objectType == typeof(GameEvent);
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var jsonObject = JObject.Load(reader);
|
||||||
|
|
||||||
|
return new GameEvent
|
||||||
|
{
|
||||||
|
Type = Enum.Parse<EventType>(jsonObject["Type"].ToString()),
|
||||||
|
Subtype = jsonObject["Subtype"]?.ToString(),
|
||||||
|
Source = Enum.Parse<EventSource>(jsonObject["Source"].ToString()),
|
||||||
|
RequiredEntity = Enum.Parse<EventRequiredEntity>(jsonObject["RequiredEntity"].ToString()),
|
||||||
|
Data = jsonObject["Data"].ToString(),
|
||||||
|
Message = jsonObject["Message"].ToString(),
|
||||||
|
GameTime = (int?)jsonObject["GameTime"],
|
||||||
|
Origin = jsonObject["Origin"]?.ToObject<EFClient>(serializer),
|
||||||
|
Target = jsonObject["Target"]?.ToObject<EFClient>(serializer),
|
||||||
|
ImpersonationOrigin = jsonObject["ImpersonationOrigin"]?.ToObject<EFClient>(serializer),
|
||||||
|
IsRemote = (bool)jsonObject["IsRemote"],
|
||||||
|
Extra = null, // fix
|
||||||
|
Time = (DateTime)jsonObject["Time"],
|
||||||
|
IsBlocking = (bool)jsonObject["IsBlocking"]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var gameEvent = value as GameEvent;
|
||||||
|
|
||||||
|
var jsonObject = new JObject
|
||||||
|
{
|
||||||
|
{ "Type", (int)gameEvent.Type },
|
||||||
|
{ "Subtype", gameEvent.Subtype },
|
||||||
|
{ "Source", (int)gameEvent.Source },
|
||||||
|
{ "RequiredEntity", (int)gameEvent.RequiredEntity },
|
||||||
|
{ "Data", gameEvent.Data },
|
||||||
|
{ "Message", gameEvent.Message },
|
||||||
|
{ "GameTime", gameEvent.GameTime },
|
||||||
|
{ "Origin", gameEvent.Origin != null ? JToken.FromObject(gameEvent.Origin, serializer) : null },
|
||||||
|
{ "Target", gameEvent.Target != null ? JToken.FromObject(gameEvent.Target, serializer) : null },
|
||||||
|
{ "ImpersonationOrigin", gameEvent.ImpersonationOrigin != null ? JToken.FromObject(gameEvent.ImpersonationOrigin, serializer) : null},
|
||||||
|
{ "IsRemote", gameEvent.IsRemote },
|
||||||
|
{ "Extra", gameEvent.Extra?.ToString() },
|
||||||
|
{ "Time", gameEvent.Time },
|
||||||
|
{ "IsBlocking", gameEvent.IsBlocking }
|
||||||
|
};
|
||||||
|
|
||||||
|
jsonObject.WriteTo(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RCon
|
namespace IW4MAdmin.Application.RCon
|
||||||
@ -193,7 +194,8 @@ namespace IW4MAdmin.Application.RCon
|
|||||||
throw new ServerException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_NOT_RUNNING"].FormatExt(Endpoint.ToString()));
|
throw new ServerException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_NOT_RUNNING"].FormatExt(Endpoint.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] headerSplit = responseString.Split(type == StaticHelpers.QueryType.GET_INFO ? config.CommandPrefixes.RconGetInfoResponseHeader : config.CommandPrefixes.RConResponse);
|
string responseHeaderMatch = Regex.Match(responseString, config.CommandPrefixes.RConResponse).Value;
|
||||||
|
string[] headerSplit = responseString.Split(type == StaticHelpers.QueryType.GET_INFO ? config.CommandPrefixes.RconGetInfoResponseHeader : responseHeaderMatch);
|
||||||
|
|
||||||
if (headerSplit.Length != 2)
|
if (headerSplit.Length != 2)
|
||||||
{
|
{
|
||||||
|
@ -179,9 +179,15 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
}
|
}
|
||||||
|
|
||||||
long networkId;
|
long networkId;
|
||||||
|
string name = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].TrimNewLine();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
networkId = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]].ConvertGuidToLong(Configuration.GuidNumberStyle);
|
string networkIdString = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConNetworkId]];
|
||||||
|
|
||||||
|
networkId = networkIdString.IsBotGuid() ?
|
||||||
|
name.GenerateGuidFromString() :
|
||||||
|
networkIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
@ -189,7 +195,6 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string name = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConName]].TrimNewLine();
|
|
||||||
int? ip = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConIpAddress]].Split(':')[0].ConvertToIP();
|
int? ip = match.Values[Configuration.Status.GroupMapping[ParserRegex.GroupType.RConIpAddress]].Split(':')[0].ConvertToIP();
|
||||||
|
|
||||||
var client = new EFClient()
|
var client = new EFClient()
|
||||||
@ -206,13 +211,13 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
State = EFClient.ClientState.Connecting
|
State = EFClient.ClientState.Connecting
|
||||||
};
|
};
|
||||||
|
|
||||||
#if DEBUG
|
//#if DEBUG
|
||||||
if (client.NetworkId < 1000 && client.NetworkId > 0)
|
// if (client.NetworkId < 1000 && client.NetworkId > 0)
|
||||||
{
|
// {
|
||||||
client.IPAddress = 2147483646;
|
// client.IPAddress = 2147483646;
|
||||||
client.Ping = 0;
|
// client.Ping = 0;
|
||||||
}
|
// }
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
StatusPlayers.Add(client);
|
StatusPlayers.Add(client);
|
||||||
}
|
}
|
||||||
|
41
Application/SerialGameEventHandler.cs
Normal file
41
Application/SerialGameEventHandler.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Events;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application
|
||||||
|
{
|
||||||
|
class SerialGameEventHandler : IEventHandler
|
||||||
|
{
|
||||||
|
private delegate void GameEventAddedEventHandler(object sender, GameEventArgs args);
|
||||||
|
private event GameEventAddedEventHandler GameEventAdded;
|
||||||
|
|
||||||
|
private static readonly GameEvent.EventType[] overrideEvents = new[]
|
||||||
|
{
|
||||||
|
GameEvent.EventType.Connect,
|
||||||
|
GameEvent.EventType.Disconnect,
|
||||||
|
GameEvent.EventType.Quit,
|
||||||
|
GameEvent.EventType.Stop
|
||||||
|
};
|
||||||
|
|
||||||
|
public SerialGameEventHandler()
|
||||||
|
{
|
||||||
|
GameEventAdded += GameEventHandler_GameEventAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void GameEventHandler_GameEventAdded(object sender, GameEventArgs args)
|
||||||
|
{
|
||||||
|
await (sender as IManager).ExecuteEvent(args.Event);
|
||||||
|
EventApi.OnGameEvent(args.Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleEvent(IManager manager, GameEvent gameEvent)
|
||||||
|
{
|
||||||
|
if (manager.IsRunning || overrideEvents.Contains(gameEvent.Type))
|
||||||
|
{
|
||||||
|
GameEventAdded?.Invoke(manager, new GameEventArgs(null, false, gameEvent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.2,
|
version: 0.3,
|
||||||
name: 'Plutonium IW5 Parser',
|
name: 'Plutonium IW5 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.CanGenerateLogPath = true;
|
rconParser.Configuration.CanGenerateLogPath = true;
|
||||||
|
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(?:[0-1]{1}) +([0-9]+) +([A-F0-9]+) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(?:[0-1]{1}) +([0-9]+) +([A-F0-9]+|0) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
||||||
rconParser.Configuration.Status.AddMapping(100, 1);
|
rconParser.Configuration.Status.AddMapping(100, 1);
|
||||||
rconParser.Configuration.Status.AddMapping(101, 2);
|
rconParser.Configuration.Status.AddMapping(101, 2);
|
||||||
rconParser.Configuration.Status.AddMapping(102, 3);
|
rconParser.Configuration.Status.AddMapping(102, 3);
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax, Xerxes',
|
author: 'RaidMax, Xerxes',
|
||||||
version: 0.7,
|
version: 0.8,
|
||||||
name: 'Plutonium T6 Parser',
|
name: 'Plutonium T6 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.WaitForResponse = false;
|
rconParser.Configuration.WaitForResponse = false;
|
||||||
|
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(?:[0-1]{1}) +([0-9]+) +([A-F0-9]+) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +(?:[0-1]{1}) +([0-9]+) +([A-F0-9]+|0) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
||||||
rconParser.Configuration.Status.AddMapping(100, 1);
|
rconParser.Configuration.Status.AddMapping(100, 1);
|
||||||
rconParser.Configuration.Status.AddMapping(101, 2);
|
rconParser.Configuration.Status.AddMapping(101, 2);
|
||||||
rconParser.Configuration.Status.AddMapping(102, 3);
|
rconParser.Configuration.Status.AddMapping(102, 3);
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.3,
|
version: 0.4,
|
||||||
name: 'Tekno MW3 Parser',
|
name: 'Tekno MW3 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -14,11 +14,11 @@ var plugin = {
|
|||||||
rconParser = manager.GenerateDynamicRConParser(this.name);
|
rconParser = manager.GenerateDynamicRConParser(this.name);
|
||||||
eventParser = manager.GenerateDynamicEventParser(this.name);
|
eventParser = manager.GenerateDynamicEventParser(this.name);
|
||||||
|
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[A-Z]|[0-9]){16,32})\t +(.{0,16}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+\\:-?\\d{1,5}|loopback) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[A-Z]|[0-9]){16,32}|0)\t +(.{0,16}) +([0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+\\:-?\\d{1,5}|loopback) *$';
|
||||||
rconParser.Configuration.Status.AddMapping(104, 5); // RConName
|
rconParser.Configuration.Status.AddMapping(104, 5); // RConName
|
||||||
rconParser.Configuration.Status.AddMapping(103, 4); // RConNetworkId
|
rconParser.Configuration.Status.AddMapping(103, 4); // RConNetworkId
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff';
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xff(print)?';
|
||||||
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
rconParser.Configuration.CommandPrefixes.Tell = 'tell {0} {1}';
|
||||||
rconParser.Configuration.CommandPrefixes.Say = 'say {0}';
|
rconParser.Configuration.CommandPrefixes.Say = 'say {0}';
|
||||||
rconParser.Configuration.CommandPrefixes.Kick = 'dropclient {0} "{1}"';
|
rconParser.Configuration.CommandPrefixes.Kick = 'dropclient {0} "{1}"';
|
||||||
|
@ -24,6 +24,12 @@ namespace IW4MAdmin.Plugins.Stats.Events
|
|||||||
return (EVENT_SCRIPTKILL, EVENT_SCRIPTKILL, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
return (EVENT_SCRIPTKILL, EVENT_SCRIPTKILL, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
||||||
{
|
{
|
||||||
string[] lineSplit = eventLine.Split(";");
|
string[] lineSplit = eventLine.Split(";");
|
||||||
|
|
||||||
|
if (lineSplit[1].IsBotGuid() || lineSplit[2].IsBotGuid())
|
||||||
|
{
|
||||||
|
return autoEvent;
|
||||||
|
}
|
||||||
|
|
||||||
long originId = lineSplit[1].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
long originId = lineSplit[1].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
||||||
long targetId = lineSplit[2].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
long targetId = lineSplit[2].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
||||||
|
|
||||||
@ -48,6 +54,12 @@ namespace IW4MAdmin.Plugins.Stats.Events
|
|||||||
return (EVENT_SCRIPTDAMAGE, EVENT_SCRIPTDAMAGE, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
return (EVENT_SCRIPTDAMAGE, EVENT_SCRIPTDAMAGE, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
||||||
{
|
{
|
||||||
string[] lineSplit = eventLine.Split(";");
|
string[] lineSplit = eventLine.Split(";");
|
||||||
|
|
||||||
|
if (lineSplit[1].IsBotGuid() || lineSplit[2].IsBotGuid())
|
||||||
|
{
|
||||||
|
return autoEvent;
|
||||||
|
}
|
||||||
|
|
||||||
long originId = lineSplit[1].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
long originId = lineSplit[1].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
||||||
long targetId = lineSplit[2].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
long targetId = lineSplit[2].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
||||||
|
|
||||||
@ -71,6 +83,12 @@ namespace IW4MAdmin.Plugins.Stats.Events
|
|||||||
return (EVENT_JOINTEAM, EVENT_JOINTEAM, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
return (EVENT_JOINTEAM, EVENT_JOINTEAM, (string eventLine, IEventParserConfiguration config, GameEvent autoEvent) =>
|
||||||
{
|
{
|
||||||
string[] lineSplit = eventLine.Split(";");
|
string[] lineSplit = eventLine.Split(";");
|
||||||
|
|
||||||
|
if (lineSplit[1].IsBotGuid() || lineSplit[2].IsBotGuid())
|
||||||
|
{
|
||||||
|
return autoEvent;
|
||||||
|
}
|
||||||
|
|
||||||
long originId = lineSplit[1].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
long originId = lineSplit[1].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
||||||
long targetId = lineSplit[2].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
long targetId = lineSplit[2].ConvertGuidToLong(config.GuidNumberStyle, 1);
|
||||||
|
|
||||||
|
@ -530,7 +530,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="origin"></param>
|
/// <param name="origin"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool IsWorldDamage(EFClient origin) => origin?.NetworkId == 1;
|
private bool IsWorldDamage(EFClient origin) => origin?.NetworkId == Utilities.WORLD_ID || origin?.ClientId == Utilities.WORLD_ID;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if we should try to use anticheat even if sv_customcallbacks is not defined
|
/// Indicates if we should try to use anticheat even if sv_customcallbacks is not defined
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.11" PrivateAssets="All" />
|
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.2.12" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
@ -72,7 +72,7 @@ namespace Tests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_manager.GetEventHandler().AddEvent(e);
|
_manager.AddEvent(e);
|
||||||
e.Complete();
|
e.Complete();
|
||||||
|
|
||||||
e = new GameEvent()
|
e = new GameEvent()
|
||||||
@ -91,7 +91,7 @@ namespace Tests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_manager.GetEventHandler().AddEvent(e);
|
_manager.AddEvent(e);
|
||||||
e.Complete();
|
e.Complete();
|
||||||
|
|
||||||
e = new GameEvent()
|
e = new GameEvent()
|
||||||
@ -110,7 +110,7 @@ namespace Tests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_manager.GetEventHandler().AddEvent(e);
|
_manager.AddEvent(e);
|
||||||
e.Complete();
|
e.Complete();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace Tests
|
|||||||
Owner = Manager.GetServers()[0]
|
Owner = Manager.GetServers()[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
e.Complete();
|
e.Complete();
|
||||||
|
|
||||||
var client = Manager.GetServers()[0].Clients[0];
|
var client = Manager.GetServers()[0].Clients[0];
|
||||||
@ -43,7 +43,7 @@ namespace Tests
|
|||||||
Owner = e.Owner
|
Owner = e.Owner
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
e.Complete();
|
e.Complete();
|
||||||
|
|
||||||
Assert.True(client.Warnings == 1, "client wasn't warned for objectional language");
|
Assert.True(client.Warnings == 1, "client wasn't warned for objectional language");
|
||||||
|
@ -49,7 +49,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
Data = cmd,
|
Data = cmd,
|
||||||
Owner = E.Owner
|
Owner = E.Owner
|
||||||
};
|
};
|
||||||
E.Owner.Manager.GetEventHandler().AddEvent(impersonatedCommandEvent);
|
E.Owner.Manager.AddEvent(impersonatedCommandEvent);
|
||||||
|
|
||||||
var result = await impersonatedCommandEvent.WaitAsync(Utilities.DefaultCommandTimeout, E.Owner.Manager.CancellationToken);
|
var result = await impersonatedCommandEvent.WaitAsync(Utilities.DefaultCommandTimeout, E.Owner.Manager.CancellationToken);
|
||||||
var response = E.Owner.CommandResult.Where(c => c.ClientId == E.Target.ClientId).ToList();
|
var response = E.Owner.CommandResult.Where(c => c.ClientId == E.Target.ClientId).ToList();
|
||||||
|
@ -23,9 +23,9 @@ namespace SharedLibraryCore.Events
|
|||||||
return eventList;
|
return eventList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnGameEvent(object sender, GameEventArgs eventState)
|
public static void OnGameEvent(GameEvent gameEvent)
|
||||||
{
|
{
|
||||||
var E = eventState.Event;
|
var E = gameEvent;
|
||||||
// don't want to clog up the api with unknown events
|
// don't want to clog up the api with unknown events
|
||||||
if (E.Type == GameEvent.EventType.Unknown)
|
if (E.Type == GameEvent.EventType.Unknown)
|
||||||
return;
|
return;
|
||||||
|
@ -194,6 +194,14 @@ namespace SharedLibraryCore
|
|||||||
Target = 4
|
Target = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum EventSource
|
||||||
|
{
|
||||||
|
Unspecified,
|
||||||
|
Log,
|
||||||
|
Status,
|
||||||
|
Internal
|
||||||
|
}
|
||||||
|
|
||||||
static long NextEventId;
|
static long NextEventId;
|
||||||
static long GetNextEventId()
|
static long GetNextEventId()
|
||||||
{
|
{
|
||||||
@ -214,6 +222,7 @@ namespace SharedLibraryCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EventType Type;
|
public EventType Type;
|
||||||
|
public EventSource Source { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// suptype of the event for more detailed classification
|
/// suptype of the event for more detailed classification
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -229,7 +238,7 @@ namespace SharedLibraryCore
|
|||||||
public EFClient Target;
|
public EFClient Target;
|
||||||
public EFClient ImpersonationOrigin { get; set; }
|
public EFClient ImpersonationOrigin { get; set; }
|
||||||
public Server Owner;
|
public Server Owner;
|
||||||
public bool IsRemote { get; set; } = false;
|
public bool IsRemote { get; set; }
|
||||||
public object Extra { get; set; }
|
public object Extra { get; set; }
|
||||||
private readonly ManualResetEvent _eventFinishedWaiter;
|
private readonly ManualResetEvent _eventFinishedWaiter;
|
||||||
public DateTime Time { get; set; }
|
public DateTime Time { get; set; }
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
using System;
|
namespace SharedLibraryCore.Interfaces
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class handle games events (from log, manual events, etc)
|
/// handles games events (from log, manual events, etc)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEventHandler
|
public interface IEventHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a game event event to the queue to be processed
|
/// Add a game event event to the queue to be processed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameEvent">Game event</param>
|
/// <param name="manager">application manager instance</param>
|
||||||
void AddEvent(GameEvent gameEvent);
|
/// <param name="gameEvent">game event</param>
|
||||||
|
void HandleEvent(IManager manager, GameEvent gameEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,17 @@ using System.Threading.Tasks;
|
|||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// represents the abtraction of game log reading
|
/// represents the abstraction of game log reading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IGameLogReader
|
public interface IGameLogReader
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// get new events that have occured since the last poll
|
/// get new events that have occured since the last poll
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server"></param>
|
|
||||||
/// <param name="fileSizeDiff"></param>
|
/// <param name="fileSizeDiff"></param>
|
||||||
/// <param name="startPosition"></param>
|
/// <param name="startPosition"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
Task<IEnumerable<GameEvent>> ReadEventsFromLog(long fileSizeDiff, long startPosition);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how long the log file is
|
/// how long the log file is
|
||||||
|
18
SharedLibraryCore/Interfaces/IGameLogReaderFactory.cs
Normal file
18
SharedLibraryCore/Interfaces/IGameLogReaderFactory.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// factory interface to create game log readers based on the log file uri
|
||||||
|
/// </summary>
|
||||||
|
public interface IGameLogReaderFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// generates a new game log reader based on the provided Uri
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logUris">collection of log uri used to generate the log reader</param>
|
||||||
|
/// <param name="eventParser">event parser for the log reader</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IGameLogReader CreateGameLogReader(Uri[] logUris, IEventParser eventParser);
|
||||||
|
}
|
||||||
|
}
|
@ -24,11 +24,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
AliasService GetAliasService();
|
AliasService GetAliasService();
|
||||||
PenaltyService GetPenaltyService();
|
PenaltyService GetPenaltyService();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the event handlers
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>EventHandler for the manager</returns>
|
|
||||||
IEventHandler GetEventHandler();
|
|
||||||
/// <summary>
|
|
||||||
/// enumerates the registered plugin instances
|
/// enumerates the registered plugin instances
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IEnumerable<IPlugin> Plugins { get; }
|
IEnumerable<IPlugin> Plugins { get; }
|
||||||
@ -68,7 +63,12 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
string ExternalIPAddress { get; }
|
string ExternalIPAddress { get; }
|
||||||
CancellationToken CancellationToken { get; }
|
CancellationToken CancellationToken { get; }
|
||||||
bool IsRestartRequested { get; }
|
bool IsRestartRequested { get; }
|
||||||
//OnServerEventEventHandler OnServerEvent { get; set; }
|
bool IsRunning { get; }
|
||||||
Task ExecuteEvent(GameEvent gameEvent);
|
Task ExecuteEvent(GameEvent gameEvent);
|
||||||
|
/// <summary>
|
||||||
|
/// queues an event for processing
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameEvent">event to be processed</param>
|
||||||
|
void AddEvent(GameEvent gameEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
Data = message
|
Data = message
|
||||||
};
|
};
|
||||||
|
|
||||||
CurrentServer?.Manager.GetEventHandler().AddEvent(e);
|
CurrentServer?.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
Warnings++;
|
Warnings++;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
Warnings = 0;
|
Warnings = 0;
|
||||||
|
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +243,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
sender.SetAdditionalProperty("_reportCount", reportCount + 1);
|
sender.SetAdditionalProperty("_reportCount", reportCount + 1);
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +276,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
e.FailReason = GameEvent.EventFailReason.Invalid;
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
e.FailReason = GameEvent.EventFailReason.Invalid;
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
State = ClientState.Disconnecting;
|
State = ClientState.Disconnecting;
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
State = ClientState.Disconnecting;
|
State = ClientState.Disconnecting;
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +400,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
State = ClientState.Disconnecting;
|
State = ClientState.Disconnecting;
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,7 +428,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
e.FailReason = GameEvent.EventFailReason.Permission;
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,7 +464,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
Level = newPermission;
|
Level = newPermission;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
sender.CurrentServer.Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,7 +565,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
Owner = CurrentServer,
|
Owner = CurrentServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
CurrentServer.Manager.AddEvent(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,7 +655,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int Score { get; set; }
|
public int Score { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsBot => NetworkId == -1;
|
public bool IsBot => NetworkId == Name.GenerateGuidFromString();
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public ClientState State { get; set; }
|
public ClientState State { get; set; }
|
||||||
@ -694,7 +694,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return ((EFClient)obj).NetworkId == this.NetworkId;
|
return obj.GetType() == typeof(EFClient) && ((EFClient)obj).NetworkId == this.NetworkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
@ -28,7 +28,7 @@ namespace SharedLibraryCore
|
|||||||
T7 = 8
|
T7 = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server(IManager mgr, IRConConnectionFactory rconConnectionFactory, ServerConfiguration config)
|
public Server(ServerConfiguration config, IManager mgr, IRConConnectionFactory rconConnectionFactory, IGameLogReaderFactory gameLogReaderFactory)
|
||||||
{
|
{
|
||||||
Password = config.Password;
|
Password = config.Password;
|
||||||
IP = config.IPAddress;
|
IP = config.IPAddress;
|
||||||
@ -46,6 +46,7 @@ namespace SharedLibraryCore
|
|||||||
NextMessage = 0;
|
NextMessage = 0;
|
||||||
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
||||||
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
||||||
|
this.gameLogReaderFactory = gameLogReaderFactory;
|
||||||
InitializeTokens();
|
InitializeTokens();
|
||||||
InitializeAutoMessages();
|
InitializeAutoMessages();
|
||||||
}
|
}
|
||||||
@ -134,7 +135,7 @@ namespace SharedLibraryCore
|
|||||||
Origin = sender,
|
Origin = sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +297,7 @@ namespace SharedLibraryCore
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Clients.Where(p => p != null && !p.IsBot).Count();
|
return Clients.Where(p => p != null/* && !p.IsBot*/).Count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public int MaxClients { get; protected set; }
|
public int MaxClients { get; protected set; }
|
||||||
@ -325,6 +326,7 @@ namespace SharedLibraryCore
|
|||||||
protected TimeSpan LastMessage;
|
protected TimeSpan LastMessage;
|
||||||
protected DateTime LastPoll;
|
protected DateTime LastPoll;
|
||||||
protected ManualResetEventSlim OnRemoteCommandResponse;
|
protected ManualResetEventSlim OnRemoteCommandResponse;
|
||||||
|
protected IGameLogReaderFactory gameLogReaderFactory;
|
||||||
|
|
||||||
// only here for performance
|
// only here for performance
|
||||||
private readonly bool CustomSayEnabled;
|
private readonly bool CustomSayEnabled;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<ApplicationIcon />
|
<ApplicationIcon />
|
||||||
<StartupObject />
|
<StartupObject />
|
||||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||||
<Version>2.2.11</Version>
|
<Version>2.2.12</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||||
@ -20,8 +20,8 @@
|
|||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<Description>Shared Library for IW4MAdmin</Description>
|
<Description>Shared Library for IW4MAdmin</Description>
|
||||||
<AssemblyVersion>2.2.11.0</AssemblyVersion>
|
<AssemblyVersion>2.2.12.0</AssemblyVersion>
|
||||||
<FileVersion>2.2.11.0</FileVersion>
|
<FileVersion>2.2.12.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||||
|
@ -16,6 +16,7 @@ using System.Net;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static SharedLibraryCore.Database.Models.EFClient;
|
using static SharedLibraryCore.Database.Models.EFClient;
|
||||||
using static SharedLibraryCore.Database.Models.EFPenalty;
|
using static SharedLibraryCore.Database.Models.EFPenalty;
|
||||||
@ -50,6 +51,10 @@ namespace SharedLibraryCore
|
|||||||
AdministeredPenalties = new List<EFPenalty>()
|
AdministeredPenalties = new List<EFPenalty>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// fallback id for world events
|
||||||
|
/// </summary>
|
||||||
|
public const long WORLD_ID = -1;
|
||||||
|
|
||||||
public static string HttpRequest(string location, string header, string headerValue)
|
public static string HttpRequest(string location, string header, string headerValue)
|
||||||
{
|
{
|
||||||
@ -295,39 +300,46 @@ namespace SharedLibraryCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// converts a string to numerical guid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">source string for guid</param>
|
||||||
|
/// <param name="numberStyle">how to parse the guid</param>
|
||||||
|
/// <param name="fallback">value to use if string is empty</param>
|
||||||
|
/// <returns></returns>
|
||||||
public static long ConvertGuidToLong(this string str, NumberStyles numberStyle, long? fallback = null)
|
public static long ConvertGuidToLong(this string str, NumberStyles numberStyle, long? fallback = null)
|
||||||
{
|
{
|
||||||
str = str.Substring(0, Math.Min(str.Length, 19));
|
str = str.Substring(0, Math.Min(str.Length, 19));
|
||||||
var bot = Regex.Match(str, @"bot[0-9]+").Value;
|
var parsableAsNumber = Regex.Match(str, @"([A-F]|[a-f]|[0-9])+").Value;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(str) && fallback.HasValue)
|
if (string.IsNullOrWhiteSpace(str) && fallback.HasValue)
|
||||||
{
|
{
|
||||||
return fallback.Value;
|
return fallback.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
long id = 0;
|
long id;
|
||||||
|
if (!string.IsNullOrEmpty(parsableAsNumber))
|
||||||
if (numberStyle == NumberStyles.Integer)
|
|
||||||
{
|
{
|
||||||
long.TryParse(str, numberStyle, CultureInfo.InvariantCulture, out id);
|
if (numberStyle == NumberStyles.Integer)
|
||||||
|
|
||||||
if (id < 0)
|
|
||||||
{
|
{
|
||||||
id = (uint)id;
|
long.TryParse(str, numberStyle, CultureInfo.InvariantCulture, out id);
|
||||||
|
|
||||||
|
if (id < 0)
|
||||||
|
{
|
||||||
|
id = (uint)id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long.TryParse(str.Length > 16 ? str.Substring(0, 16) : str, numberStyle, CultureInfo.InvariantCulture, out id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
long.TryParse(str.Length > 16 ? str.Substring(0, 16) : str, numberStyle, CultureInfo.InvariantCulture, out id);
|
// this is a special case for when a real guid is not provided, so we generated it from another source
|
||||||
}
|
id = str.GenerateGuidFromString();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(bot))
|
|
||||||
{
|
|
||||||
id = -1;
|
|
||||||
#if DEBUG
|
|
||||||
id = str.Sum(_c => _c);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
@ -338,6 +350,23 @@ namespace SharedLibraryCore
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// determines if the guid provided appears to be a bot guid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="guid">value of the guid</param>
|
||||||
|
/// <returns>true if is bot guid, otherwise false</returns>
|
||||||
|
public static bool IsBotGuid(this string guid)
|
||||||
|
{
|
||||||
|
return guid.Contains("bot") || guid == "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// generates a numerical hashcode from a string value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">value string</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static long GenerateGuidFromString(this string value) => string.IsNullOrEmpty(value) ? -1 : HashCode.Combine(value.StripColors());
|
||||||
|
|
||||||
public static int? ConvertToIP(this string str)
|
public static int? ConvertToIP(this string str)
|
||||||
{
|
{
|
||||||
bool success = IPAddress.TryParse(str, out IPAddress ip);
|
bool success = IPAddress.TryParse(str, out IPAddress ip);
|
||||||
@ -900,6 +929,24 @@ namespace SharedLibraryCore
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// https://www.planetgeek.ch/2016/12/08/async-method-without-cancellation-support-do-it-my-way/
|
||||||
|
/// </summary>
|
||||||
|
public static async Task WithWaitCancellation(this Task task,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Task completedTask = await Task.WhenAny(task, Task.Delay(Timeout.Infinite, cancellationToken));
|
||||||
|
if (completedTask == task)
|
||||||
|
{
|
||||||
|
await task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
throw new InvalidOperationException("Infinite delay task completed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ShouldHideLevel(this Permission perm) => perm == Permission.Flagged;
|
public static bool ShouldHideLevel(this Permission perm) => perm == Permission.Flagged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
<None Update="Files\GameEvents.json">
|
<None Update="Files\GameEvents.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="Files\replay.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update="Files\T6Game.log">
|
<None Update="Files\T6Game.log">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
@ -37,12 +37,10 @@ namespace ApplicationTests
|
|||||||
cmdConfig = new CommandConfiguration();
|
cmdConfig = new CommandConfiguration();
|
||||||
|
|
||||||
serviceProvider = new ServiceCollection()
|
serviceProvider = new ServiceCollection()
|
||||||
.BuildBase()
|
.BuildBase(new MockEventHandler(true))
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
|
|
||||||
mockEventHandler = new MockEventHandler(true);
|
mockEventHandler = serviceProvider.GetRequiredService<MockEventHandler>();
|
||||||
A.CallTo(() => serviceProvider.GetRequiredService<IManager>().GetEventHandler())
|
|
||||||
.Returns(mockEventHandler);
|
|
||||||
|
|
||||||
var mgr = serviceProvider.GetRequiredService<IManager>();
|
var mgr = serviceProvider.GetRequiredService<IManager>();
|
||||||
transLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
transLookup = serviceProvider.GetRequiredService<ITranslationLookup>();
|
||||||
@ -54,7 +52,9 @@ namespace ApplicationTests
|
|||||||
new NonImpersonatableCommand(cmdConfig, transLookup)
|
new NonImpersonatableCommand(cmdConfig, transLookup)
|
||||||
});
|
});
|
||||||
|
|
||||||
//Utilities.DefaultCommandTimeout = new TimeSpan(0, 0, 2);
|
A.CallTo(() => mgr.AddEvent(A<GameEvent>.Ignored))
|
||||||
|
.Invokes((fakeCall) => mockEventHandler.HandleEvent(mgr, fakeCall.Arguments[0] as GameEvent));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region RUNAS
|
#region RUNAS
|
||||||
|
@ -9,10 +9,22 @@ using SharedLibraryCore.Services;
|
|||||||
|
|
||||||
namespace ApplicationTests
|
namespace ApplicationTests
|
||||||
{
|
{
|
||||||
static class DepedencyInjectionExtensions
|
static class DependencyInjectionExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection BuildBase(this IServiceCollection serviceCollection)
|
public static IServiceCollection BuildBase(this IServiceCollection serviceCollection, IEventHandler eventHandler = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (eventHandler == null)
|
||||||
|
{
|
||||||
|
eventHandler = new MockEventHandler();
|
||||||
|
serviceCollection.AddSingleton(eventHandler as MockEventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (eventHandler is MockEventHandler mockEventHandler)
|
||||||
|
{
|
||||||
|
serviceCollection.AddSingleton(mockEventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
var manager = A.Fake<IManager>();
|
var manager = A.Fake<IManager>();
|
||||||
var logger = A.Fake<ILogger>();
|
var logger = A.Fake<ILogger>();
|
||||||
|
|
||||||
@ -27,10 +39,13 @@ namespace ApplicationTests
|
|||||||
.AddSingleton(A.Fake<ITranslationLookup>())
|
.AddSingleton(A.Fake<ITranslationLookup>())
|
||||||
.AddSingleton(A.Fake<IRConParser>())
|
.AddSingleton(A.Fake<IRConParser>())
|
||||||
.AddSingleton(A.Fake<IParserRegexFactory>())
|
.AddSingleton(A.Fake<IParserRegexFactory>())
|
||||||
.AddSingleton(A.Fake<ClientService>());
|
.AddSingleton<DataFileLoader>()
|
||||||
|
.AddSingleton(A.Fake<ClientService>())
|
||||||
|
.AddSingleton(A.Fake<IGameLogReaderFactory>())
|
||||||
|
.AddSingleton(eventHandler);
|
||||||
|
|
||||||
serviceCollection.AddSingleton(_sp => new IW4MServer(_sp.GetRequiredService<IManager>(), ConfigurationGenerators.CreateServerConfiguration(),
|
serviceCollection.AddSingleton(_sp => new IW4MServer(_sp.GetRequiredService<IManager>(), ConfigurationGenerators.CreateServerConfiguration(),
|
||||||
_sp.GetRequiredService<ITranslationLookup>(), _sp.GetRequiredService<IRConConnectionFactory>())
|
_sp.GetRequiredService<ITranslationLookup>(), _sp.GetRequiredService<IRConConnectionFactory>(), _sp.GetRequiredService<IGameLogReaderFactory>())
|
||||||
{
|
{
|
||||||
RconParser = _sp.GetRequiredService<IRConParser>()
|
RconParser = _sp.GetRequiredService<IRConParser>()
|
||||||
});
|
});
|
16
Tests/ApplicationTests/Fixtures/DataFileLoader.cs
Normal file
16
Tests/ApplicationTests/Fixtures/DataFileLoader.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using IW4MAdmin.Application.Misc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ApplicationTests.Fixtures
|
||||||
|
{
|
||||||
|
class DataFileLoader
|
||||||
|
{
|
||||||
|
public async Task<T> Load<T>(string fileName)
|
||||||
|
{
|
||||||
|
string data = await File.ReadAllTextAsync($"{fileName}.json");
|
||||||
|
return JsonConvert.DeserializeObject<T>(data, EventLog.BuildVcrSerializationSettings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Tests/ApplicationTests/GameEventHandlerTests.cs
Normal file
17
Tests/ApplicationTests/GameEventHandlerTests.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using IW4MAdmin;
|
||||||
|
using IW4MAdmin.Application;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ApplicationTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class GameEventHandlerTests
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
using FakeItEasy;
|
using FakeItEasy;
|
||||||
|
using IW4MAdmin;
|
||||||
using IW4MAdmin.Application.IO;
|
using IW4MAdmin.Application.IO;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
@ -12,11 +14,24 @@ namespace ApplicationTests
|
|||||||
public class IOTests
|
public class IOTests
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private IServiceProvider serviceProvider;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
serviceProvider = new ServiceCollection().BuildBase().BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task GameLogEventDetection_WorksAfterFileSizeReset()
|
public async Task GameLogEventDetection_WorksAfterFileSizeReset()
|
||||||
{
|
{
|
||||||
var reader = A.Fake<IGameLogReader>();
|
var reader = A.Fake<IGameLogReader>();
|
||||||
var detect = new GameLogEventDetection(null, "", A.Fake<Uri>(), reader);
|
var factory = A.Fake<IGameLogReaderFactory>();
|
||||||
|
|
||||||
|
A.CallTo(() => factory.CreateGameLogReader(A<Uri[]>.Ignored, A<IEventParser>.Ignored))
|
||||||
|
.Returns(reader);
|
||||||
|
|
||||||
|
var detect = new GameLogEventDetection(serviceProvider.GetService<IW4MServer>(), new Uri[] { new Uri("C:\\test.log") }, factory);
|
||||||
|
|
||||||
A.CallTo(() => reader.Length)
|
A.CallTo(() => reader.Length)
|
||||||
.Returns(100)
|
.Returns(100)
|
||||||
@ -35,7 +50,7 @@ namespace ApplicationTests
|
|||||||
await detect.UpdateLogEvents();
|
await detect.UpdateLogEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
A.CallTo(() => reader.ReadEventsFromLog(A<Server>.Ignored, A<long>.Ignored, A<long>.Ignored))
|
A.CallTo(() => reader.ReadEventsFromLog(A<long>.Ignored, A<long>.Ignored))
|
||||||
.MustHaveHappenedTwiceExactly();
|
.MustHaveHappenedTwiceExactly();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ namespace ApplicationTests
|
|||||||
fakeManager = serviceProvider.GetRequiredService<IManager>();
|
fakeManager = serviceProvider.GetRequiredService<IManager>();
|
||||||
fakeRConConnection = serviceProvider.GetRequiredService<IRConConnection>();
|
fakeRConConnection = serviceProvider.GetRequiredService<IRConConnection>();
|
||||||
fakeRConParser = serviceProvider.GetRequiredService<IRConParser>();
|
fakeRConParser = serviceProvider.GetRequiredService<IRConParser>();
|
||||||
|
mockEventHandler = serviceProvider.GetRequiredService<MockEventHandler>();
|
||||||
|
|
||||||
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
||||||
|
|
||||||
@ -45,10 +46,9 @@ namespace ApplicationTests
|
|||||||
A.CallTo(() => fakeRConParser.Configuration)
|
A.CallTo(() => fakeRConParser.Configuration)
|
||||||
.Returns(ConfigurationGenerators.CreateRConParserConfiguration(serviceProvider.GetRequiredService<IParserRegexFactory>()));
|
.Returns(ConfigurationGenerators.CreateRConParserConfiguration(serviceProvider.GetRequiredService<IParserRegexFactory>()));
|
||||||
|
|
||||||
|
A.CallTo(() => fakeManager.AddEvent(A<GameEvent>.Ignored))
|
||||||
mockEventHandler = new MockEventHandler();
|
.Invokes((fakeCall) => mockEventHandler.HandleEvent(fakeManager, fakeCall.Arguments[0] as GameEvent));
|
||||||
A.CallTo(() => fakeManager.GetEventHandler())
|
|
||||||
.Returns(mockEventHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region LOG
|
#region LOG
|
||||||
|
@ -14,7 +14,7 @@ namespace ApplicationTests.Mocks
|
|||||||
_autoExecute = autoExecute;
|
_autoExecute = autoExecute;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEvent(GameEvent gameEvent)
|
public void HandleEvent(IManager manager, GameEvent gameEvent)
|
||||||
{
|
{
|
||||||
Events.Add(gameEvent);
|
Events.Add(gameEvent);
|
||||||
|
|
||||||
|
21
Tests/ApplicationTests/Mocks/VcrEventReader.cs
Normal file
21
Tests/ApplicationTests/Mocks/VcrEventReader.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ApplicationTests.Mocks
|
||||||
|
{
|
||||||
|
class VcrEventReader : IGameLogReader
|
||||||
|
{
|
||||||
|
public long Length => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public int UpdateInterval => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<IEnumerable<GameEvent>> ReadEventsFromLog(long fileSizeDiff, long startPosition)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,9 +31,7 @@ namespace ApplicationTests
|
|||||||
{
|
{
|
||||||
serviceProvider = new ServiceCollection().BuildBase().BuildServiceProvider();
|
serviceProvider = new ServiceCollection().BuildBase().BuildServiceProvider();
|
||||||
fakeManager = serviceProvider.GetRequiredService<IManager>();
|
fakeManager = serviceProvider.GetRequiredService<IManager>();
|
||||||
mockEventHandler = new MockEventHandler();
|
mockEventHandler = serviceProvider.GetRequiredService<MockEventHandler>();
|
||||||
A.CallTo(() => fakeManager.GetEventHandler())
|
|
||||||
.Returns(mockEventHandler);
|
|
||||||
|
|
||||||
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
var rconConnectionFactory = serviceProvider.GetRequiredService<IRConConnectionFactory>();
|
||||||
|
|
||||||
@ -42,6 +40,9 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
A.CallTo(() => serviceProvider.GetRequiredService<IRConParser>().Configuration)
|
A.CallTo(() => serviceProvider.GetRequiredService<IRConParser>().Configuration)
|
||||||
.Returns(ConfigurationGenerators.CreateRConParserConfiguration(serviceProvider.GetRequiredService<IParserRegexFactory>()));
|
.Returns(ConfigurationGenerators.CreateRConParserConfiguration(serviceProvider.GetRequiredService<IParserRegexFactory>()));
|
||||||
|
|
||||||
|
A.CallTo(() => fakeManager.AddEvent(A<GameEvent>.Ignored))
|
||||||
|
.Invokes((fakeCall) => mockEventHandler.HandleEvent(fakeManager, fakeCall.Arguments[0] as GameEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -33,7 +33,7 @@ namespace ApplicationTests
|
|||||||
var mgr = A.Fake<IManager>();
|
var mgr = A.Fake<IManager>();
|
||||||
var server = new IW4MServer(mgr,
|
var server = new IW4MServer(mgr,
|
||||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>(), A.Fake<IGameLogReaderFactory>());
|
||||||
|
|
||||||
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>());
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
@ -59,7 +59,7 @@ namespace ApplicationTests
|
|||||||
|
|
||||||
var server = new IW4MServer(mgr,
|
var server = new IW4MServer(mgr,
|
||||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>());
|
A.Fake<ITranslationLookup>(), A.Fake<IRConConnectionFactory>(), A.Fake<IGameLogReaderFactory>());
|
||||||
|
|
||||||
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>());
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
@ -63,7 +63,7 @@ namespace ApplicationTests
|
|||||||
var server = new IW4MServer(mgr,
|
var server = new IW4MServer(mgr,
|
||||||
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
new SharedLibraryCore.Configuration.ServerConfiguration() { IPAddress = "127.0.0.1", Port = 28960 },
|
||||||
A.Fake<ITranslationLookup>(),
|
A.Fake<ITranslationLookup>(),
|
||||||
A.Fake<IRConConnectionFactory>());
|
A.Fake<IRConConnectionFactory>(), A.Fake<IGameLogReaderFactory>());
|
||||||
|
|
||||||
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>());
|
var parser = new BaseEventParser(A.Fake<IParserRegexFactory>(), A.Fake<ILogger>());
|
||||||
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
parser.Configuration.GuidNumberStyle = System.Globalization.NumberStyles.Integer;
|
||||||
|
43
Tests/ApplicationTests/VcrTests.cs
Normal file
43
Tests/ApplicationTests/VcrTests.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using ApplicationTests.Fixtures;
|
||||||
|
using IW4MAdmin;
|
||||||
|
using IW4MAdmin.Application;
|
||||||
|
using IW4MAdmin.Application.Misc;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ApplicationTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class VcrTests
|
||||||
|
{
|
||||||
|
private IServiceProvider serviceProvider;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
serviceProvider = new ServiceCollection().BuildBase()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase("replay")]
|
||||||
|
public async Task ReplayEvents(string source)
|
||||||
|
{
|
||||||
|
var sourceData = await serviceProvider
|
||||||
|
.GetRequiredService<DataFileLoader>()
|
||||||
|
.Load<EventLog>(source);
|
||||||
|
|
||||||
|
var server = serviceProvider.GetRequiredService<IW4MServer>();
|
||||||
|
|
||||||
|
foreach (var gameEvent in sourceData.Values.First())
|
||||||
|
{
|
||||||
|
await server.ExecuteEvent(gameEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,7 @@ namespace WebfrontCore.Controllers
|
|||||||
IsRemote = true
|
IsRemote = true
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(remoteEvent);
|
Manager.AddEvent(remoteEvent);
|
||||||
List<CommandResponseInfo> response = null;
|
List<CommandResponseInfo> response = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
Loading…
Reference in New Issue
Block a user