Files
RAGECOOP-V/Server/Client.cs

229 lines
6.5 KiB
C#
Raw Normal View History

2022-10-23 19:02:39 +08:00
using System;
2022-09-08 12:41:56 -07:00
using System.Diagnostics;
2022-08-06 12:32:04 +08:00
using System.Net;
2022-09-08 12:41:56 -07:00
using System.Security.Cryptography;
2022-10-23 19:02:39 +08:00
using GTA.Native;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using RageCoop.Server.Scripting;
namespace RageCoop.Server;
2021-08-26 17:01:32 +02:00
2022-10-23 19:02:39 +08:00
/// <summary>
/// Represent a player connected to this server.
/// </summary>
public class Client
2021-08-26 17:01:32 +02:00
{
2022-10-23 19:02:39 +08:00
private readonly Stopwatch _latencyWatch = new();
internal readonly Dictionary<int, Action<object>> Callbacks = new();
private readonly Server Server;
private bool _autoRespawn = true;
private bool _displayNameTag = true;
internal long NetHandle = 0;
internal Client(Server server)
{
Server = server;
}
/// <summary>
/// Gets the total number of entities owned by this client
/// </summary>
public int EntitiesCount { get; internal set; }
/// <summary>
/// Th client's IP address and port.
/// </summary>
public IPEndPoint EndPoint => Connection?.RemoteEndPoint;
/// <summary>
/// Internal(LAN) address of this client, used for NAT hole-punching
/// </summary>
public IPEndPoint InternalEndPoint { get; internal set; }
internal NetConnection Connection { get; set; }
/// <summary>
/// The <see cref="ServerPed" /> instance representing the client's main character.
/// </summary>
public ServerPed Player { get; internal set; }
2022-07-01 13:54:18 +08:00
/// <summary>
2022-10-23 19:02:39 +08:00
/// The client's latency in seconds.
2022-07-01 13:54:18 +08:00
/// </summary>
2022-10-23 19:02:39 +08:00
public float Latency => Connection.AverageRoundtripTime / 2;
internal byte[] PublicKey { get; set; }
/// <summary>
/// Indicates whether the client has succefully loaded all resources.
/// </summary>
public bool IsReady { get; internal set; } = false;
/// <summary>
/// The client's username.
/// </summary>
public string Username { get; internal set; } = "N/A";
/// <summary>
/// Gets or sets whether to enable automatic respawn for this client's main ped.
/// </summary>
public bool EnableAutoRespawn
2021-08-26 17:01:32 +02:00
{
2022-10-23 19:02:39 +08:00
get => _autoRespawn;
set
{
2022-10-23 19:02:39 +08:00
BaseScript.SetAutoRespawn(this, value);
_autoRespawn = value;
}
2022-10-23 19:02:39 +08:00
}
2022-08-21 12:37:37 +08:00
2022-10-23 19:02:39 +08:00
/// <summary>
/// Gets or sets whether to enable automatic respawn for this client's main ped.
/// </summary>
public bool DisplayNameTag
{
get => _displayNameTag;
set
2022-09-08 12:41:56 -07:00
{
2022-10-23 19:02:39 +08:00
Server.BaseScript.SetNameTag(this, value);
_displayNameTag = value;
}
2022-10-23 19:02:39 +08:00
}
2022-10-23 19:02:39 +08:00
#region FUNCTIONS
2022-10-23 19:02:39 +08:00
/// <summary>
/// Kick this client
/// </summary>
/// <param name="reason"></param>
public void Kick(string reason = "You have been kicked!")
{
Connection?.Disconnect(reason);
}
/// <summary>
/// Kick this client
/// </summary>
/// <param name="reasons">Reasons to kick</param>
public void Kick(params string[] reasons)
{
Kick(string.Join(" ", reasons));
}
/// <summary>
/// Send a chat messsage to this client, not visible to others.
/// </summary>
/// <param name="message"></param>
/// <param name="from"></param>
public void SendChatMessage(string message, string from = "Server")
{
try
2021-12-11 14:00:22 +01:00
{
2022-10-23 19:02:39 +08:00
Server.SendChatMessage(from, message, this);
2021-12-11 14:00:22 +01:00
}
2022-10-23 19:02:39 +08:00
catch (Exception e)
2022-04-08 22:30:34 +02:00
{
2022-10-23 19:02:39 +08:00
Server.Logger?.Error(
$">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
2022-04-08 22:30:34 +02:00
}
2022-10-23 19:02:39 +08:00
}
2021-08-26 17:01:32 +02:00
2022-10-23 19:02:39 +08:00
/// <summary>
/// Send a native call to client and do a callback when the response received.
/// </summary>
/// <typeparam name="T">Type of the response</typeparam>
/// <param name="callBack"></param>
/// <param name="hash"></param>
/// <param name="args"></param>
public void SendNativeCall<T>(Action<object> callBack, Hash hash, params object[] args)
{
var argsList = new List<object>(args);
argsList.InsertRange(0,
new object[] { (byte)Type.GetTypeCode(typeof(T)), RequestNativeCallID<T>(callBack), (ulong)hash });
2021-12-10 13:38:03 +01:00
2022-10-23 19:02:39 +08:00
SendCustomEventQueued(CustomEvents.NativeCall, argsList.ToArray());
}
2022-06-23 09:46:38 +08:00
2022-10-23 19:02:39 +08:00
/// <summary>
/// Send a native call to client and ignore it's response.
/// </summary>
/// <param name="hash"></param>
/// <param name="args"></param>
public void SendNativeCall(Hash hash, params object[] args)
{
var argsList = new List<object>(args);
argsList.InsertRange(0, new object[] { (byte)TypeCode.Empty, (ulong)hash });
// Server.Logger?.Debug(argsList.DumpWithType());
SendCustomEventQueued(CustomEvents.NativeCall, argsList.ToArray());
}
private int RequestNativeCallID<T>(Action<object> callback)
{
var ID = 0;
lock (Callbacks)
2022-06-23 09:46:38 +08:00
{
2022-10-23 19:02:39 +08:00
while (ID == 0
|| Callbacks.ContainsKey(ID))
2022-06-23 09:46:38 +08:00
{
2022-10-23 19:02:39 +08:00
var rngBytes = new byte[4];
2022-06-23 09:46:38 +08:00
2022-10-23 19:02:39 +08:00
RandomNumberGenerator.Create().GetBytes(rngBytes);
2022-06-23 09:46:38 +08:00
2022-10-23 19:02:39 +08:00
// Convert the bytes into an integer
ID = BitConverter.ToInt32(rngBytes, 0);
2022-06-23 09:46:38 +08:00
}
2022-10-23 19:02:39 +08:00
Callbacks.Add(ID, callback);
2022-06-23 09:46:38 +08:00
}
2022-10-23 19:02:39 +08:00
return ID;
}
2022-10-23 19:02:39 +08:00
/// <summary>
/// Trigger a CustomEvent for this client
/// </summary>
/// <param name="flags"></param>
/// <param name="hash">An unique identifier of the event</param>
/// <param name="args">Arguments</param>
public void SendCustomEvent(CustomEventFlags flags, CustomEventHash hash, params object[] args)
{
if (!IsReady) Server.Logger?.Warning($"Player \"{Username}\" is not ready!");
2022-10-23 19:02:39 +08:00
try
2022-10-08 23:49:48 +08:00
{
2022-10-23 19:02:39 +08:00
var outgoingMessage = Server.MainNetServer.CreateMessage();
var writer = GetWriter();
CustomEvents.WriteObjects(writer, args);;
2022-10-23 19:02:39 +08:00
new Packets.CustomEvent(flags)
{
Hash = hash,
Payload = writer.ToByteArray(writer.Position)
2022-10-23 19:02:39 +08:00
}.Pack(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered,
(byte)ConnectionChannel.Event);
}
2022-10-23 19:02:39 +08:00
catch (Exception ex)
2022-07-05 11:18:26 +08:00
{
2022-10-23 19:02:39 +08:00
Server.Logger?.Error(ex);
2022-07-05 11:18:26 +08:00
}
2021-08-26 17:01:32 +02:00
}
2022-10-23 19:02:39 +08:00
public void SendCustomEventQueued(CustomEventHash hash, params object[] args)
{
SendCustomEvent(CustomEventFlags.Queued, hash, args);
}
public void SendCustomEvent(CustomEventHash hash, params object[] args)
{
SendCustomEvent(CustomEventFlags.None, hash, args);
}
#endregion
}