[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:
@ -49,7 +49,7 @@ namespace SharedLibraryCore.Commands
|
||||
Data = cmd,
|
||||
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 response = E.Owner.CommandResult.Where(c => c.ClientId == E.Target.ClientId).ToList();
|
||||
|
@ -23,9 +23,9 @@ namespace SharedLibraryCore.Events
|
||||
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
|
||||
if (E.Type == GameEvent.EventType.Unknown)
|
||||
return;
|
||||
|
@ -194,6 +194,14 @@ namespace SharedLibraryCore
|
||||
Target = 4
|
||||
}
|
||||
|
||||
public enum EventSource
|
||||
{
|
||||
Unspecified,
|
||||
Log,
|
||||
Status,
|
||||
Internal
|
||||
}
|
||||
|
||||
static long NextEventId;
|
||||
static long GetNextEventId()
|
||||
{
|
||||
@ -214,6 +222,7 @@ namespace SharedLibraryCore
|
||||
}
|
||||
|
||||
public EventType Type;
|
||||
public EventSource Source { get; set; }
|
||||
/// <summary>
|
||||
/// suptype of the event for more detailed classification
|
||||
/// </summary>
|
||||
@ -229,7 +238,7 @@ namespace SharedLibraryCore
|
||||
public EFClient Target;
|
||||
public EFClient ImpersonationOrigin { get; set; }
|
||||
public Server Owner;
|
||||
public bool IsRemote { get; set; } = false;
|
||||
public bool IsRemote { get; set; }
|
||||
public object Extra { get; set; }
|
||||
private readonly ManualResetEvent _eventFinishedWaiter;
|
||||
public DateTime Time { get; set; }
|
||||
|
@ -1,18 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// This class handle games events (from log, manual events, etc)
|
||||
/// handles games events (from log, manual events, etc)
|
||||
/// </summary>
|
||||
public interface IEventHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Add a game event event to the queue to be processed
|
||||
/// </summary>
|
||||
/// <param name="gameEvent">Game event</param>
|
||||
void AddEvent(GameEvent gameEvent);
|
||||
/// <param name="manager">application manager instance</param>
|
||||
/// <param name="gameEvent">game event</param>
|
||||
void HandleEvent(IManager manager, GameEvent gameEvent);
|
||||
}
|
||||
}
|
||||
|
@ -4,18 +4,17 @@ using System.Threading.Tasks;
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// represents the abtraction of game log reading
|
||||
/// represents the abstraction of game log reading
|
||||
/// </summary>
|
||||
public interface IGameLogReader
|
||||
{
|
||||
/// <summary>
|
||||
/// get new events that have occured since the last poll
|
||||
/// </summary>
|
||||
/// <param name="server"></param>
|
||||
/// <param name="fileSizeDiff"></param>
|
||||
/// <param name="startPosition"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
||||
Task<IEnumerable<GameEvent>> ReadEventsFromLog(long fileSizeDiff, long startPosition);
|
||||
|
||||
/// <summary>
|
||||
/// 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();
|
||||
PenaltyService GetPenaltyService();
|
||||
/// <summary>
|
||||
/// Get the event handlers
|
||||
/// </summary>
|
||||
/// <returns>EventHandler for the manager</returns>
|
||||
IEventHandler GetEventHandler();
|
||||
/// <summary>
|
||||
/// enumerates the registered plugin instances
|
||||
/// </summary>
|
||||
IEnumerable<IPlugin> Plugins { get; }
|
||||
@ -68,7 +63,12 @@ namespace SharedLibraryCore.Interfaces
|
||||
string ExternalIPAddress { get; }
|
||||
CancellationToken CancellationToken { get; }
|
||||
bool IsRestartRequested { get; }
|
||||
//OnServerEventEventHandler OnServerEvent { get; set; }
|
||||
bool IsRunning { get; }
|
||||
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
|
||||
};
|
||||
|
||||
CurrentServer?.Manager.GetEventHandler().AddEvent(e);
|
||||
CurrentServer?.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
Warnings++;
|
||||
}
|
||||
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -202,7 +202,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
|
||||
Warnings = 0;
|
||||
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
}
|
||||
|
||||
sender.SetAdditionalProperty("_reportCount", reportCount + 1);
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -276,7 +276,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
e.FailReason = GameEvent.EventFailReason.Invalid;
|
||||
}
|
||||
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -308,7 +308,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
e.FailReason = GameEvent.EventFailReason.Invalid;
|
||||
}
|
||||
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
}
|
||||
|
||||
State = ClientState.Disconnecting;
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -366,7 +366,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
}
|
||||
|
||||
State = ClientState.Disconnecting;
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -400,7 +400,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
}
|
||||
|
||||
State = ClientState.Disconnecting;
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -428,7 +428,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
e.FailReason = GameEvent.EventFailReason.Permission;
|
||||
}
|
||||
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -464,7 +464,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
Level = newPermission;
|
||||
}
|
||||
|
||||
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
sender.CurrentServer.Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -565,7 +565,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
Owner = CurrentServer,
|
||||
};
|
||||
|
||||
CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||
CurrentServer.Manager.AddEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,7 +655,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
[NotMapped]
|
||||
public int Score { get; set; }
|
||||
[NotMapped]
|
||||
public bool IsBot => NetworkId == -1;
|
||||
public bool IsBot => NetworkId == Name.GenerateGuidFromString();
|
||||
|
||||
[NotMapped]
|
||||
public ClientState State { get; set; }
|
||||
@ -694,7 +694,7 @@ namespace SharedLibraryCore.Database.Models
|
||||
|
||||
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()
|
||||
|
@ -28,7 +28,7 @@ namespace SharedLibraryCore
|
||||
T7 = 8
|
||||
}
|
||||
|
||||
public Server(IManager mgr, IRConConnectionFactory rconConnectionFactory, ServerConfiguration config)
|
||||
public Server(ServerConfiguration config, IManager mgr, IRConConnectionFactory rconConnectionFactory, IGameLogReaderFactory gameLogReaderFactory)
|
||||
{
|
||||
Password = config.Password;
|
||||
IP = config.IPAddress;
|
||||
@ -46,6 +46,7 @@ namespace SharedLibraryCore
|
||||
NextMessage = 0;
|
||||
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
||||
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
||||
this.gameLogReaderFactory = gameLogReaderFactory;
|
||||
InitializeTokens();
|
||||
InitializeAutoMessages();
|
||||
}
|
||||
@ -134,7 +135,7 @@ namespace SharedLibraryCore
|
||||
Origin = sender,
|
||||
};
|
||||
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
Manager.AddEvent(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -296,7 +297,7 @@ namespace SharedLibraryCore
|
||||
{
|
||||
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; }
|
||||
@ -325,6 +326,7 @@ namespace SharedLibraryCore
|
||||
protected TimeSpan LastMessage;
|
||||
protected DateTime LastPoll;
|
||||
protected ManualResetEventSlim OnRemoteCommandResponse;
|
||||
protected IGameLogReaderFactory gameLogReaderFactory;
|
||||
|
||||
// only here for performance
|
||||
private readonly bool CustomSayEnabled;
|
||||
|
@ -6,7 +6,7 @@
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
|
||||
<Version>2.2.11</Version>
|
||||
<Version>2.2.12</Version>
|
||||
<Authors>RaidMax</Authors>
|
||||
<Company>Forever None</Company>
|
||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||
@ -20,8 +20,8 @@
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Description>Shared Library for IW4MAdmin</Description>
|
||||
<AssemblyVersion>2.2.11.0</AssemblyVersion>
|
||||
<FileVersion>2.2.11.0</FileVersion>
|
||||
<AssemblyVersion>2.2.12.0</AssemblyVersion>
|
||||
<FileVersion>2.2.12.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
|
||||
|
@ -16,6 +16,7 @@ using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static SharedLibraryCore.Database.Models.EFClient;
|
||||
using static SharedLibraryCore.Database.Models.EFPenalty;
|
||||
@ -50,6 +51,10 @@ namespace SharedLibraryCore
|
||||
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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return fallback.Value;
|
||||
}
|
||||
|
||||
long id = 0;
|
||||
|
||||
if (numberStyle == NumberStyles.Integer)
|
||||
long id;
|
||||
if (!string.IsNullOrEmpty(parsableAsNumber))
|
||||
{
|
||||
long.TryParse(str, numberStyle, CultureInfo.InvariantCulture, out id);
|
||||
|
||||
if (id < 0)
|
||||
if (numberStyle == NumberStyles.Integer)
|
||||
{
|
||||
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
|
||||
{
|
||||
long.TryParse(str.Length > 16 ? str.Substring(0, 16) : str, numberStyle, CultureInfo.InvariantCulture, out id);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(bot))
|
||||
{
|
||||
id = -1;
|
||||
#if DEBUG
|
||||
id = str.Sum(_c => _c);
|
||||
#endif
|
||||
// this is a special case for when a real guid is not provided, so we generated it from another source
|
||||
id = str.GenerateGuidFromString();
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
@ -338,6 +350,23 @@ namespace SharedLibraryCore
|
||||
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)
|
||||
{
|
||||
bool success = IPAddress.TryParse(str, out IPAddress ip);
|
||||
@ -900,6 +929,24 @@ namespace SharedLibraryCore
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
|
Reference in New Issue
Block a user