2021-03-22 12:09:25 -04:00
|
|
|
|
using SharedLibraryCore.Localization;
|
2018-11-05 22:01:29 -05:00
|
|
|
|
using System;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
|
|
|
using System.Linq;
|
2019-03-24 22:34:20 -04:00
|
|
|
|
using System.Text.RegularExpressions;
|
2019-11-15 15:50:20 -05:00
|
|
|
|
using System.Threading;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
using System.Threading.Tasks;
|
2020-11-11 18:31:26 -05:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using Serilog.Context;
|
2021-03-22 12:09:25 -04:00
|
|
|
|
using Data.Models;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
|
2018-11-05 22:01:29 -05:00
|
|
|
|
namespace SharedLibraryCore.Database.Models
|
2017-11-29 19:35:50 -05:00
|
|
|
|
{
|
2021-03-22 12:09:25 -04:00
|
|
|
|
public class EFClient : Data.Models.Client.EFClient
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-06-30 21:55:16 -04:00
|
|
|
|
public enum ClientState
|
|
|
|
|
{
|
2020-02-07 12:15:21 -05:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// default client state
|
|
|
|
|
/// </summary>
|
|
|
|
|
Unknown,
|
|
|
|
|
|
2018-08-27 18:07:54 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// represents when the client has been detected as joining
|
|
|
|
|
/// by the log file, but has not be authenticated by RCon
|
|
|
|
|
/// </summary>
|
2018-06-30 21:55:16 -04:00
|
|
|
|
Connecting,
|
2020-02-07 12:15:21 -05:00
|
|
|
|
|
2018-08-27 18:07:54 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// represents when the client has been authenticated by RCon
|
|
|
|
|
/// and validated by the database
|
|
|
|
|
/// </summary>
|
2018-06-30 21:55:16 -04:00
|
|
|
|
Connected,
|
2020-02-07 12:15:21 -05:00
|
|
|
|
|
2018-08-27 18:07:54 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// represents when the client is leaving (either through RCon or log file)
|
|
|
|
|
/// </summary>
|
2020-02-07 12:15:21 -05:00
|
|
|
|
Disconnecting
|
2018-06-30 21:55:16 -04:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public EFClient()
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
|
|
|
|
ConnectionTime = DateTime.UtcNow;
|
2017-11-29 19:35:50 -05:00
|
|
|
|
ClientNumber = -1;
|
2020-04-25 20:01:26 -04:00
|
|
|
|
SetAdditionalProperty("_reportCount", 0);
|
2019-04-02 21:20:37 -04:00
|
|
|
|
ReceivedPenalties = new List<EFPenalty>();
|
2019-12-26 19:17:49 -05:00
|
|
|
|
_processingEvent = new SemaphoreSlim(1, 1);
|
2019-11-15 15:50:20 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~EFClient()
|
|
|
|
|
{
|
2020-11-29 17:01:52 -05:00
|
|
|
|
_processingEvent?.Dispose();
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
2017-11-29 19:35:50 -05:00
|
|
|
|
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
2020-04-25 20:01:26 -04:00
|
|
|
|
return $"[Name={CurrentAlias?.Name ?? "--"}, NetworkId={NetworkId.ToString("X")}, IP={(string.IsNullOrEmpty(IPAddressString) ? "--" : IPAddressString)}, ClientSlot={ClientNumber}]";
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
2017-11-25 20:29:58 -05:00
|
|
|
|
|
2019-05-29 17:55:35 -04:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public virtual string Name
|
|
|
|
|
{
|
|
|
|
|
get { return CurrentAlias?.Name ?? "--"; }
|
|
|
|
|
set { if (CurrentAlias != null) CurrentAlias.Name = value; }
|
|
|
|
|
}
|
2019-08-10 10:08:26 -04:00
|
|
|
|
|
|
|
|
|
[NotMapped]
|
2019-11-18 09:08:09 -05:00
|
|
|
|
public string CleanedName => Name?.StripColors();
|
2019-08-10 10:08:26 -04:00
|
|
|
|
|
2019-05-29 17:55:35 -04:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public virtual int? IPAddress
|
|
|
|
|
{
|
|
|
|
|
get { return CurrentAlias.IPAddress; }
|
|
|
|
|
set { CurrentAlias.IPAddress = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[NotMapped]
|
|
|
|
|
public string IPAddressString => IPAddress.ConvertIPtoString();
|
2019-11-15 15:50:20 -05:00
|
|
|
|
|
2020-04-21 18:34:00 -04:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public bool IsIngame => ClientNumber >= 0;
|
|
|
|
|
|
2019-05-29 17:55:35 -04:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public virtual IDictionary<int, long> LinkedAccounts { get; set; }
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// send a message directly to the connected client
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="message">message content to send to client</param>
|
2021-01-17 22:58:18 -05:00
|
|
|
|
public GameEvent Tell(string message)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Message = message,
|
|
|
|
|
Target = this,
|
|
|
|
|
Owner = CurrentServer,
|
|
|
|
|
Type = GameEvent.EventType.Tell,
|
2021-01-17 22:58:18 -05:00
|
|
|
|
Data = message,
|
|
|
|
|
CorrelationId = CurrentServer.Manager.ProcessingEvents.Values
|
|
|
|
|
.FirstOrDefault(ev => ev.Type == GameEvent.EventType.Command && (ev.Origin?.ClientId == ClientId || ev.ImpersonationOrigin?.ClientId == ClientId))?.CorrelationId ?? Guid.NewGuid()
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
2021-01-17 22:58:18 -05:00
|
|
|
|
|
|
|
|
|
e.Output.Add(message.StripColors());
|
2018-09-29 15:52:22 -04:00
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
CurrentServer?.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-24 12:47:19 -05:00
|
|
|
|
public void Tell(IEnumerable<string> messages)
|
|
|
|
|
{
|
|
|
|
|
foreach(var message in messages)
|
|
|
|
|
{
|
|
|
|
|
#pragma warning disable 4014
|
|
|
|
|
Tell(message).WaitAsync();
|
|
|
|
|
#pragma warning restore 4014
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// warn a client with given reason
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="warnReason">reason for warn</param>
|
|
|
|
|
/// <param name="sender">client performing the warn</param>
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public GameEvent Warn(String warnReason, EFClient sender)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Warn,
|
|
|
|
|
Message = warnReason,
|
2018-10-03 22:20:49 -04:00
|
|
|
|
Data = warnReason,
|
2018-09-29 15:52:22 -04:00
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// enforce level restrictions
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (Level > sender.Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 22:20:49 -04:00
|
|
|
|
else
|
|
|
|
|
{
|
2019-05-02 23:33:38 -04:00
|
|
|
|
Warnings++;
|
2018-10-03 22:20:49 -04:00
|
|
|
|
}
|
2018-09-29 22:49:12 -04:00
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2018-10-02 13:39:08 -04:00
|
|
|
|
/// clear all warnings for a client
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// </summary>
|
2018-10-02 13:39:08 -04:00
|
|
|
|
/// <param name="sender">client performing the warn clear</param>
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <returns></returns>
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public GameEvent WarnClear(EFClient sender)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Type = GameEvent.EventType.WarnClear,
|
2018-09-29 15:52:22 -04:00
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
2018-10-02 13:39:08 -04:00
|
|
|
|
// enforce level restrictions
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (sender.Level <= Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-02 23:33:38 -04:00
|
|
|
|
Warnings = 0;
|
2018-09-29 15:52:22 -04:00
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
2018-10-02 13:39:08 -04:00
|
|
|
|
/// report a client for a given reason
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// </summary>
|
2018-10-02 13:39:08 -04:00
|
|
|
|
/// <param name="reportReason">reason for the report</param>
|
|
|
|
|
/// <param name="sender">client performing the report</param>
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <returns></returns>
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public GameEvent Report(string reportReason, EFClient sender)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Type = GameEvent.EventType.Report,
|
|
|
|
|
Message = reportReason,
|
|
|
|
|
Data = reportReason,
|
2018-09-29 15:52:22 -04:00
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
2018-10-03 22:20:49 -04:00
|
|
|
|
int reportCount = sender.GetAdditionalProperty<int>("_reportCount");
|
|
|
|
|
|
2019-06-24 12:01:34 -04:00
|
|
|
|
if (Equals(sender))
|
2018-10-02 13:39:08 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 22:20:49 -04:00
|
|
|
|
else if (reportCount > 2)
|
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Throttle;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-02 13:39:08 -04:00
|
|
|
|
else if (CurrentServer.Reports.Count(report => (report.Origin.NetworkId == sender.NetworkId &&
|
2019-05-02 23:33:38 -04:00
|
|
|
|
report.Target.NetworkId == NetworkId)) > 0)
|
2018-10-02 13:39:08 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Exception;
|
|
|
|
|
}
|
2018-09-29 15:52:22 -04:00
|
|
|
|
|
2018-10-03 22:20:49 -04:00
|
|
|
|
sender.SetAdditionalProperty("_reportCount", reportCount + 1);
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// flag a client for a given reason
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="flagReason">reason for flagging</param>
|
|
|
|
|
/// <param name="sender">client performing the flag</param>
|
|
|
|
|
/// <returns>game event for the flag</returns>
|
2019-06-25 19:01:47 -04:00
|
|
|
|
public GameEvent Flag(string flagReason, EFClient sender, TimeSpan? flagLength = null)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Flag,
|
|
|
|
|
Origin = sender,
|
|
|
|
|
Data = flagReason,
|
|
|
|
|
Message = flagReason,
|
2019-06-25 19:01:47 -04:00
|
|
|
|
Extra = flagLength,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Target = this,
|
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (Level >= sender.Level)
|
2018-05-10 01:34:29 -04:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
2018-05-10 01:34:29 -04:00
|
|
|
|
}
|
2018-05-08 00:58:46 -04:00
|
|
|
|
|
2019-08-12 21:00:40 -04:00
|
|
|
|
else if (Level == Permission.Flagged || Level == Permission.Banned)
|
2018-05-04 00:22:10 -04:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
|
|
|
|
}
|
2018-05-04 00:22:10 -04:00
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// unflag a client for a given reason
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="unflagReason">reason to unflag a player for</param>
|
|
|
|
|
/// <param name="sender">client performing the unflag</param>
|
|
|
|
|
/// <returns>game event for the un flug</returns>
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public GameEvent Unflag(string unflagReason, EFClient sender)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Unflag,
|
|
|
|
|
Origin = sender,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Target = this,
|
2018-09-29 15:52:22 -04:00
|
|
|
|
Data = unflagReason,
|
|
|
|
|
Message = unflagReason,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (sender.Level <= Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
2018-05-10 01:34:29 -04:00
|
|
|
|
}
|
2018-09-29 15:52:22 -04:00
|
|
|
|
|
2019-08-12 21:00:40 -04:00
|
|
|
|
else if (Level != Permission.Flagged || Level == Permission.Banned)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// kick a client for the given reason
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="kickReason">reason to kick for</param>
|
|
|
|
|
/// <param name="sender">client performing the kick</param>
|
2020-11-17 19:24:54 -05:00
|
|
|
|
public GameEvent Kick(string kickReason, EFClient sender) => Kick(kickReason, sender, null);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// kick a client for the given reason
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="kickReason">reason to kick for</param>
|
|
|
|
|
/// <param name="sender">client performing the kick</param>
|
|
|
|
|
/// <param name="originalPenalty">original client penalty</param>
|
|
|
|
|
public GameEvent Kick(string kickReason, EFClient sender, EFPenalty originalPenalty)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Kick,
|
|
|
|
|
Message = kickReason,
|
|
|
|
|
Target = this,
|
|
|
|
|
Origin = sender,
|
|
|
|
|
Data = kickReason,
|
2020-11-17 19:24:54 -05:00
|
|
|
|
Extra = originalPenalty,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// enforce level restrictions
|
2020-06-17 16:20:07 -04:00
|
|
|
|
if (sender.Level <= Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-06 19:35:30 -05:00
|
|
|
|
State = ClientState.Disconnecting;
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// temporarily ban a client for the given time span
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="tempbanReason">reason for the temp ban</param>
|
|
|
|
|
/// <param name="banLength">how long the temp ban lasts</param>
|
|
|
|
|
/// <param name="sender">client performing the tempban</param>
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public GameEvent TempBan(String tempbanReason, TimeSpan banLength, EFClient sender)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.TempBan,
|
|
|
|
|
Message = tempbanReason,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Data = tempbanReason,
|
2018-09-29 15:52:22 -04:00
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
|
|
|
|
Extra = banLength,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// enforce level restrictions
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (sender.Level <= Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-07 12:15:21 -05:00
|
|
|
|
State = ClientState.Disconnecting;
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// permanently ban a client
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="banReason">reason for the ban</param>
|
|
|
|
|
/// <param name="sender">client performing the ban</param>
|
2018-12-17 14:45:16 -05:00
|
|
|
|
public GameEvent Ban(String banReason, EFClient sender, bool isEvade)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Ban,
|
|
|
|
|
Message = banReason,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Data = banReason,
|
2018-09-29 15:52:22 -04:00
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
2018-12-16 22:16:56 -05:00
|
|
|
|
Owner = sender.CurrentServer,
|
|
|
|
|
Extra = isEvade
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// enforce level restrictions
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (sender.Level <= Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 14:39:21 -04:00
|
|
|
|
if (Level == Permission.Banned)
|
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-07 12:15:21 -05:00
|
|
|
|
State = ClientState.Disconnecting;
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-29 15:52:22 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// unban a client
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="unbanReason">reason for the unban</param>
|
|
|
|
|
/// <param name="sender">client performing the unban</param>
|
|
|
|
|
/// <returns></returns>
|
2019-03-24 22:34:20 -04:00
|
|
|
|
public GameEvent Unban(string unbanReason, EFClient sender)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-29 15:52:22 -04:00
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Unban,
|
|
|
|
|
Message = unbanReason,
|
|
|
|
|
Data = unbanReason,
|
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
2018-10-02 13:39:08 -04:00
|
|
|
|
Owner = sender.CurrentServer
|
2018-09-29 15:52:22 -04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// enforce level restrictions
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (Level > sender.Level)
|
2018-09-29 15:52:22 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2018-09-29 15:52:22 -04:00
|
|
|
|
return e;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
2018-09-29 15:52:22 -04:00
|
|
|
|
|
2019-03-24 22:34:20 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// sets the level of the client
|
|
|
|
|
/// </summary>
|
2019-04-02 21:20:37 -04:00
|
|
|
|
/// <param name="newPermission">new permission to set client to</param>
|
2019-03-24 22:34:20 -04:00
|
|
|
|
/// <param name="sender">user performing the set level</param>
|
|
|
|
|
/// <returns></returns>
|
2019-04-02 21:20:37 -04:00
|
|
|
|
public GameEvent SetLevel(Permission newPermission, EFClient sender)
|
2019-03-24 22:34:20 -04:00
|
|
|
|
{
|
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.ChangePermission,
|
2019-04-02 21:20:37 -04:00
|
|
|
|
Extra = newPermission,
|
2019-03-24 22:34:20 -04:00
|
|
|
|
Origin = sender,
|
|
|
|
|
Target = this,
|
|
|
|
|
Owner = sender.CurrentServer
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-02 23:33:38 -04:00
|
|
|
|
if (Level > sender.Level)
|
2019-03-24 22:34:20 -04:00
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Permission;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-16 12:32:42 -04:00
|
|
|
|
else if (Level == newPermission)
|
|
|
|
|
{
|
|
|
|
|
e.FailReason = GameEvent.EventFailReason.Invalid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Level = newPermission;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 17:50:02 -04:00
|
|
|
|
sender.CurrentServer.Manager.AddEvent(e);
|
2019-03-24 22:34:20 -04:00
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 22:01:29 -05:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Handles any client related logic on connection
|
|
|
|
|
/// </summary>
|
2019-11-15 15:50:20 -05:00
|
|
|
|
public bool IsAbleToConnectSimple()
|
2018-11-05 22:01:29 -05:00
|
|
|
|
{
|
|
|
|
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
2018-11-25 21:00:36 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
2018-11-05 22:01:29 -05:00
|
|
|
|
{
|
2021-06-27 21:31:39 -04:00
|
|
|
|
if (string.IsNullOrWhiteSpace(Name) || CleanedName.Replace(" ", "").Length <
|
|
|
|
|
(CurrentServer?.Manager?.GetApplicationSettings()?.Configuration()?.MinimumNameLength ?? 3))
|
2020-11-11 18:31:26 -05:00
|
|
|
|
{
|
2021-06-27 21:31:39 -04:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Kicking {Client} because their name is too short", ToString());
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Kick(loc["SERVER_KICK_MINNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-11-05 22:01:29 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
if (CurrentServer.Manager.GetApplicationSettings().Configuration()
|
|
|
|
|
.DisallowedClientNames
|
|
|
|
|
?.Any(_name => Regex.IsMatch(Name, _name)) ?? false)
|
|
|
|
|
{
|
2021-06-27 21:31:39 -04:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Kicking {Client} because their name is not allowed", ToString());
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Kick(loc["SERVER_KICK_GENERICNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-11-05 22:01:29 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
if (Name.Where(c => char.IsControl(c)).Count() > 0)
|
|
|
|
|
{
|
2021-06-27 21:31:39 -04:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Kicking {Client} because their name contains control characters", ToString());
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Kick(loc["SERVER_KICK_CONTROLCHARS"], Utilities.IW4MAdminClient(CurrentServer));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-11-05 22:01:29 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
// reserved slots stuff
|
|
|
|
|
// todo: bots don't seem to honor party_maxplayers/sv_maxclients
|
|
|
|
|
if (CurrentServer.MaxClients - (CurrentServer.GetClientsAsList().Count(_client => !_client.IsPrivileged() && !_client.IsBot)) < CurrentServer.ServerConfig.ReservedSlotNumber &&
|
|
|
|
|
!this.IsPrivileged() &&
|
|
|
|
|
CurrentServer.GetClientsAsList().Count <= CurrentServer.MaxClients &&
|
|
|
|
|
CurrentServer.MaxClients != 0)
|
|
|
|
|
{
|
2021-06-27 21:31:39 -04:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Kicking {Client} their spot is reserved", ToString());
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Kick(loc["SERVER_KICK_SLOT_IS_RESERVED"], Utilities.IW4MAdminClient(CurrentServer));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
2019-05-29 17:55:35 -04:00
|
|
|
|
|
|
|
|
|
return true;
|
2018-11-07 21:30:11 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task OnDisconnect()
|
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
2019-04-08 13:29:48 -04:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
TotalConnectionTime += ConnectionLength;
|
|
|
|
|
LastConnection = DateTime.UtcNow;
|
2019-04-08 13:29:48 -04:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Client {client} is leaving the game", ToString());
|
2020-02-07 12:15:21 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await CurrentServer.Manager.GetClientService().Update(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Utilities.DefaultLogger.LogError(e, "Could not update disconnected client {client}",
|
|
|
|
|
ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
State = ClientState.Unknown;
|
|
|
|
|
}
|
2020-02-07 12:15:21 -05:00
|
|
|
|
}
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-24 22:34:20 -04:00
|
|
|
|
public async Task OnJoin(int? ipAddress)
|
2018-11-05 22:01:29 -05:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
2018-12-31 21:52:19 -05:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Client {client} is joining the game from {source}", ToString(), ipAddress.HasValue ? "Status" : "Log");
|
2018-11-05 22:01:29 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
if (ipAddress != null)
|
2019-11-15 15:50:20 -05:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
IPAddress = ipAddress;
|
|
|
|
|
Utilities.DefaultLogger.LogInformation("Received ip from client {client}", ToString());
|
|
|
|
|
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
|
|
|
|
await CurrentServer.Manager.GetClientService().Update(this);
|
|
|
|
|
|
|
|
|
|
bool canConnect = await CanConnect(ipAddress);
|
|
|
|
|
|
|
|
|
|
if (!canConnect)
|
|
|
|
|
{
|
|
|
|
|
Utilities.DefaultLogger.LogInformation("Client {client} is not allowed to join the server",
|
|
|
|
|
ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Utilities.DefaultLogger.LogDebug("Creating join event for {client}", ToString());
|
|
|
|
|
var e = new GameEvent()
|
|
|
|
|
{
|
|
|
|
|
Type = GameEvent.EventType.Join,
|
|
|
|
|
Origin = this,
|
|
|
|
|
Target = this,
|
|
|
|
|
Owner = CurrentServer,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
CurrentServer.Manager.AddEvent(e);
|
|
|
|
|
}
|
2019-11-15 15:50:20 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
2019-03-24 22:34:20 -04:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Utilities.DefaultLogger.LogInformation("Waiting to receive ip from client {client}", ToString());
|
2019-04-02 21:20:37 -04:00
|
|
|
|
}
|
2019-03-24 22:34:20 -04:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
Utilities.DefaultLogger.LogDebug("OnJoin finished for {client}", ToString());
|
2019-03-24 22:34:20 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-29 13:43:40 -05:00
|
|
|
|
|
2020-02-06 19:35:30 -05:00
|
|
|
|
public async Task<bool> CanConnect(int? ipAddress)
|
2019-03-24 22:34:20 -04:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
using (LogContext.PushProperty("Server", CurrentServer?.ToString()))
|
2019-11-15 15:50:20 -05:00
|
|
|
|
{
|
2020-11-11 18:31:26 -05:00
|
|
|
|
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
|
|
|
|
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
|
|
|
|
|
bool isAbleToConnectSimple = IsAbleToConnectSimple();
|
2019-03-24 22:34:20 -04:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
if (!isAbleToConnectSimple)
|
2018-11-05 22:01:29 -05:00
|
|
|
|
{
|
2019-06-27 21:06:30 -04:00
|
|
|
|
return false;
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
|
|
|
|
var activePenalties = await CurrentServer.Manager.GetPenaltyService()
|
|
|
|
|
.GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
|
|
|
|
var banPenalty = activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Ban);
|
|
|
|
|
var tempbanPenalty =
|
|
|
|
|
activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.TempBan);
|
|
|
|
|
var flagPenalty =
|
|
|
|
|
activePenalties.FirstOrDefault(_penalty => _penalty.Type == EFPenalty.PenaltyType.Flag);
|
|
|
|
|
|
|
|
|
|
// we want to kick them if any account is banned
|
|
|
|
|
if (banPenalty != null)
|
2018-11-05 22:01:29 -05:00
|
|
|
|
{
|
2020-11-17 19:24:54 -05:00
|
|
|
|
if (Level != Permission.Banned)
|
2020-11-11 18:31:26 -05:00
|
|
|
|
{
|
|
|
|
|
Utilities.DefaultLogger.LogInformation(
|
|
|
|
|
"Client {client} is banned, but using a new GUID, we we're updating their level and kicking them",
|
|
|
|
|
ToString());
|
|
|
|
|
await SetLevel(Permission.Banned, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
|
|
|
|
CurrentServer.Manager.CancellationToken);
|
|
|
|
|
}
|
2020-11-17 19:24:54 -05:00
|
|
|
|
|
|
|
|
|
Utilities.DefaultLogger.LogInformation("Kicking {client} because they are banned", ToString());
|
|
|
|
|
Kick(loc["WEBFRONT_PENALTY_LIST_BANNED_REASON"], autoKickClient, banPenalty);
|
|
|
|
|
return false;
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
2018-11-25 21:00:36 -05:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
// we want to kick them if any account is tempbanned
|
|
|
|
|
if (tempbanPenalty != null)
|
|
|
|
|
{
|
|
|
|
|
Utilities.DefaultLogger.LogInformation("Kicking {client} because their GUID is temporarily banned",
|
|
|
|
|
ToString());
|
2020-11-17 19:24:54 -05:00
|
|
|
|
Kick(loc["WEBFRONT_PENALTY_LIST_TEMPBANNED_REASON"], autoKickClient, tempbanPenalty);
|
2020-11-11 18:31:26 -05:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-05-08 21:34:17 -04:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
// if we found a flag, we need to make sure all the accounts are flagged
|
|
|
|
|
if (flagPenalty != null && Level != Permission.Flagged)
|
|
|
|
|
{
|
|
|
|
|
Utilities.DefaultLogger.LogInformation(
|
|
|
|
|
"Flagged client {client} joining with new GUID, so we are changing their level to flagged",
|
|
|
|
|
ToString());
|
|
|
|
|
await SetLevel(Permission.Flagged, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
|
|
|
|
CurrentServer.Manager.CancellationToken);
|
|
|
|
|
}
|
2019-04-05 14:34:03 -04:00
|
|
|
|
|
2020-11-11 18:31:26 -05:00
|
|
|
|
// remove their auto flag
|
|
|
|
|
if (Level == Permission.Flagged &&
|
|
|
|
|
!activePenalties.Any(_penalty => _penalty.Type == EFPenalty.PenaltyType.Flag))
|
|
|
|
|
{
|
|
|
|
|
// remove their auto flag status after a week
|
|
|
|
|
Utilities.DefaultLogger.LogInformation("Unflagging {client} because the auto flag time has expired",
|
|
|
|
|
ToString());
|
|
|
|
|
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
|
|
|
|
}
|
2018-11-25 21:00:36 -05:00
|
|
|
|
}
|
2019-04-05 14:34:03 -04:00
|
|
|
|
|
2019-11-15 15:50:20 -05:00
|
|
|
|
return true;
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 20:29:58 -05:00
|
|
|
|
[NotMapped]
|
2017-11-29 19:35:50 -05:00
|
|
|
|
public int ClientNumber { get; set; }
|
2017-11-25 20:29:58 -05:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public int Ping { get; set; }
|
|
|
|
|
[NotMapped]
|
|
|
|
|
public int Warnings { get; set; }
|
|
|
|
|
[NotMapped]
|
|
|
|
|
public DateTime ConnectionTime { get; set; }
|
|
|
|
|
[NotMapped]
|
2018-09-07 23:29:42 -04:00
|
|
|
|
public int ConnectionLength => (int)(DateTime.UtcNow - ConnectionTime).TotalSeconds;
|
|
|
|
|
[NotMapped]
|
2017-11-25 20:29:58 -05:00
|
|
|
|
public Server CurrentServer { get; set; }
|
2018-02-09 02:21:25 -05:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public int Score { get; set; }
|
2018-02-14 14:01:26 -05:00
|
|
|
|
[NotMapped]
|
2020-05-04 17:50:02 -04:00
|
|
|
|
public bool IsBot => NetworkId == Name.GenerateGuidFromString();
|
2020-08-31 13:03:06 -04:00
|
|
|
|
[NotMapped]
|
2020-08-31 13:13:20 -04:00
|
|
|
|
public bool IsZombieClient => IsBot && Name == "Zombie";
|
|
|
|
|
[NotMapped]
|
2020-08-31 13:03:06 -04:00
|
|
|
|
public string XuidString => (NetworkId + 0x110000100000000).ToString("x");
|
|
|
|
|
[NotMapped]
|
|
|
|
|
public string GuidString => NetworkId.ToString("x");
|
2018-11-27 19:31:48 -05:00
|
|
|
|
|
2018-06-30 21:55:16 -04:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public ClientState State { get; set; }
|
2018-12-01 13:17:53 -05:00
|
|
|
|
|
2018-08-03 22:11:58 -04:00
|
|
|
|
[NotMapped]
|
|
|
|
|
// this is kinda dirty, but I need localizable level names
|
|
|
|
|
public ClientPermission ClientPermission => new ClientPermission()
|
|
|
|
|
{
|
|
|
|
|
Level = Level,
|
2021-01-24 12:47:19 -05:00
|
|
|
|
Name = Level.ToLocalizedLevelName()
|
2018-08-03 22:11:58 -04:00
|
|
|
|
};
|
2018-02-10 23:33:42 -05:00
|
|
|
|
|
2021-01-24 12:47:19 -05:00
|
|
|
|
[NotMapped]
|
|
|
|
|
public string Tag
|
|
|
|
|
{
|
|
|
|
|
get => GetAdditionalProperty<string>(EFMeta.ClientTag);
|
|
|
|
|
set => SetAdditionalProperty(EFMeta.ClientTag, value);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 15:50:20 -05:00
|
|
|
|
[NotMapped]
|
2019-12-26 19:17:49 -05:00
|
|
|
|
private readonly SemaphoreSlim _processingEvent;
|
2019-11-15 15:50:20 -05:00
|
|
|
|
|
|
|
|
|
public async Task Lock()
|
|
|
|
|
{
|
2019-12-26 19:17:49 -05:00
|
|
|
|
bool result = await _processingEvent.WaitAsync(Utilities.DefaultCommandTimeout);
|
2019-11-15 15:50:20 -05:00
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
if (!result)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Unlock()
|
|
|
|
|
{
|
2019-12-26 19:17:49 -05:00
|
|
|
|
if (_processingEvent.CurrentCount == 0)
|
2019-11-15 15:50:20 -05:00
|
|
|
|
{
|
2019-12-26 19:17:49 -05:00
|
|
|
|
_processingEvent.Release(1);
|
2019-11-15 15:50:20 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-10 23:33:42 -05:00
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
2020-05-04 17:50:02 -04:00
|
|
|
|
return obj.GetType() == typeof(EFClient) && ((EFClient)obj).NetworkId == this.NetworkId;
|
2018-02-10 23:33:42 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 22:01:29 -05:00
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
2019-05-04 10:17:18 -04:00
|
|
|
|
return IsBot ? ClientNumber : (int)NetworkId;
|
2018-11-05 22:01:29 -05:00
|
|
|
|
}
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
}
|