[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:
RaidMax
2020-05-04 16:50:02 -05:00
parent b49592d666
commit 267e0b8cbe
50 changed files with 775 additions and 233 deletions

View File

@ -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();

View File

@ -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;

View File

@ -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; }

View File

@ -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);
}
}

View File

@ -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

View 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);
}
}

View File

@ -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);
}
}

View File

@ -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()

View File

@ -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;

View File

@ -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'">

View File

@ -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>