diff --git a/Application/EventParsers/BaseEventParser.cs b/Application/EventParsers/BaseEventParser.cs
index b0c3cf0d..28b97545 100644
--- a/Application/EventParsers/BaseEventParser.cs
+++ b/Application/EventParsers/BaseEventParser.cs
@@ -49,6 +49,13 @@ namespace IW4MAdmin.Application.EventParsers
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
Configuration.Join.AddMapping(ParserRegex.GroupType.OriginName, 4);
+
+ Configuration.JoinTeam.Pattern = @"^(JT);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);([0-9]+);(\w+);(.+)$";
+ Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.EventType, 1);
+ Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginNetworkId, 2);
+ Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginClientNumber, 3);
+ Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginTeam, 4);
+ Configuration.JoinTeam.AddMapping(ParserRegex.GroupType.OriginName, 5);
Configuration.Damage.Pattern = @"^(D);(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0);(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32});(-?[A-Fa-f0-9_]{1,32}|bot[0-9]+|0)?;(-?[0-9]+);(axis|allies|world|none)?;([^;]{1,32})?;((?:[0-9]+|[a-z]+|_|\+)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
Configuration.Damage.AddMapping(ParserRegex.GroupType.EventType, 1);
@@ -100,6 +107,7 @@ namespace IW4MAdmin.Application.EventParsers
{"K", GameEvent.EventType.Kill},
{"D", GameEvent.EventType.Damage},
{"J", GameEvent.EventType.PreConnect},
+ {"JT", GameEvent.EventType.JoinTeam },
{"Q", GameEvent.EventType.PreDisconnect},
};
}
@@ -322,6 +330,42 @@ namespace IW4MAdmin.Application.EventParsers
}
}
+ if (eventType == GameEvent.EventType.JoinTeam)
+ {
+ var match = Configuration.JoinTeam.PatternMatcher.Match(logLine);
+
+ if (match.Success)
+ {
+ var originIdString = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginNetworkId]];
+ var originName = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginName]];
+ var team = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginTeam]];
+
+ var networkId = originIdString.IsBotGuid() ?
+ originName.GenerateGuidFromString() :
+ originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
+
+ return new GameEvent
+ {
+ Type = GameEvent.EventType.JoinTeam,
+ Data = logLine,
+ Origin = new EFClient
+ {
+ CurrentAlias = new EFAlias
+ {
+ Name = match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginName]].TrimNewLine(),
+ },
+ NetworkId = networkId,
+ ClientNumber = Convert.ToInt32(match.Values[Configuration.JoinTeam.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]),
+ State = EFClient.ClientState.Connected,
+ },
+ Extra = team,
+ RequiredEntity = GameEvent.EventRequiredEntity.None,
+ GameTime = gameTime,
+ Source = GameEvent.EventSource.Log
+ };
+ }
+ }
+
if (eventType == GameEvent.EventType.PreDisconnect)
{
var match = Configuration.Quit.PatternMatcher.Match(logLine);
diff --git a/Application/EventParsers/DynamicEventParserConfiguration.cs b/Application/EventParsers/DynamicEventParserConfiguration.cs
index 59873bf1..d3815c42 100644
--- a/Application/EventParsers/DynamicEventParserConfiguration.cs
+++ b/Application/EventParsers/DynamicEventParserConfiguration.cs
@@ -8,11 +8,12 @@ namespace IW4MAdmin.Application.EventParsers
/// generic implementation of the IEventParserConfiguration
/// allows script plugins to generate dynamic configurations
///
- sealed internal class DynamicEventParserConfiguration : IEventParserConfiguration
+ internal sealed class DynamicEventParserConfiguration : IEventParserConfiguration
{
public string GameDirectory { get; set; }
public ParserRegex Say { get; set; }
public ParserRegex Join { get; set; }
+ public ParserRegex JoinTeam { get; set; }
public ParserRegex Quit { get; set; }
public ParserRegex Kill { get; set; }
public ParserRegex Damage { get; set; }
@@ -26,6 +27,7 @@ namespace IW4MAdmin.Application.EventParsers
{
Say = parserRegexFactory.CreateParserRegex();
Join = parserRegexFactory.CreateParserRegex();
+ JoinTeam = parserRegexFactory.CreateParserRegex();
Quit = parserRegexFactory.CreateParserRegex();
Kill = parserRegexFactory.CreateParserRegex();
Damage = parserRegexFactory.CreateParserRegex();
diff --git a/Application/IO/NetworkGameLogReader.cs b/Application/IO/NetworkGameLogReader.cs
index a58ffa5d..9b81dc69 100644
--- a/Application/IO/NetworkGameLogReader.cs
+++ b/Application/IO/NetworkGameLogReader.cs
@@ -89,7 +89,7 @@ namespace IW4MAdmin.Application.IO
var lines = logData
.Split('\n')
- .Where(line => line.Length > 0);
+ .Where(line => line.Length > 0 && !line.Contains('ΓΏ'));
foreach (var eventLine in lines)
{
diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs
index ad67d616..bea9fe37 100644
--- a/Application/IW4MServer.cs
+++ b/Application/IW4MServer.cs
@@ -713,6 +713,11 @@ namespace IW4MAdmin
await E.Owner.ExecuteCommandAsync(E.Data);
}
}
+
+ else if (E.Type == GameEvent.EventType.JoinTeam)
+ {
+ E.Origin.UpdateTeam(E.Extra as string);
+ }
lock (ChatHistory)
{
diff --git a/GameFiles/IW4x/userraw/scripts/_integration.gsc b/GameFiles/IW4x/userraw/scripts/_integration.gsc
index 296ee685..8d55bbb0 100644
--- a/GameFiles/IW4x/userraw/scripts/_integration.gsc
+++ b/GameFiles/IW4x/userraw/scripts/_integration.gsc
@@ -623,7 +623,7 @@ UnhideImpl()
return;
}
- if ( IsDefined( self.isHidden ) && !self.isHidden )
+ if ( !IsDefined( self.isHidden ) || !self.isHidden )
{
self IPrintLnBold( "You are not hidden" );
return;
diff --git a/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs b/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs
index d2cffc2d..c08b5835 100644
--- a/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs
+++ b/SharedLibraryCore/Interfaces/IEventParserConfiguration.cs
@@ -18,6 +18,11 @@ namespace SharedLibraryCore.Interfaces
/// stores the regex information for a join event printed in the game log
///
ParserRegex Join { get; set; }
+
+ ///
+ /// stores the regex information for a join team event printed in the game log
+ ///
+ ParserRegex JoinTeam { get; set; }
///
/// stores the regex information for a quit event printed in the game log
@@ -59,4 +64,4 @@ namespace SharedLibraryCore.Interfaces
///
NumberStyles GuidNumberStyle { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/SharedLibraryCore/PartialEntities/EFClient.cs b/SharedLibraryCore/PartialEntities/EFClient.cs
index 2c08e3e3..5ade8760 100644
--- a/SharedLibraryCore/PartialEntities/EFClient.cs
+++ b/SharedLibraryCore/PartialEntities/EFClient.cs
@@ -39,6 +39,14 @@ namespace SharedLibraryCore.Database.Models
Disconnecting
}
+ public enum TeamType
+ {
+ Unknown,
+ Spectator,
+ Allies,
+ Axis
+ }
+
[NotMapped] private readonly SemaphoreSlim _processingEvent;
public EFClient()
@@ -101,6 +109,9 @@ namespace SharedLibraryCore.Database.Models
[NotMapped] public string GuidString => NetworkId.ToString("x");
[NotMapped] public ClientState State { get; set; }
+
+ [NotMapped] public TeamType Team { get; set; }
+ [NotMapped] public string TeamName { get; set; }
[NotMapped]
// this is kinda dirty, but I need localizable level names
@@ -710,6 +721,17 @@ namespace SharedLibraryCore.Database.Models
return true;
}
+ public void UpdateTeam(string newTeam)
+ {
+ if (string.IsNullOrEmpty(newTeam))
+ {
+ return;
+ }
+
+ Team = Enum.TryParse(newTeam, true, out TeamType team) ? team : TeamType.Unknown;
+ TeamName = newTeam;
+ }
+
public async Task Lock()
{
var result = await _processingEvent.WaitAsync(Utilities.DefaultCommandTimeout);