2022-09-08 12:41:56 -07:00
|
|
|
|
using GTA.Math;
|
|
|
|
|
using Lidgren.Network;
|
|
|
|
|
using Newtonsoft.Json;
|
2022-10-05 15:53:57 +08:00
|
|
|
|
using RageCoop.Core.Scripting;
|
2022-09-08 12:41:56 -07:00
|
|
|
|
using System;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
using System.Collections.Generic;
|
2022-09-08 12:41:56 -07:00
|
|
|
|
using System.IO;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
using System.Linq;
|
2022-06-03 16:28:02 +08:00
|
|
|
|
using System.Net;
|
2022-08-12 20:40:50 +08:00
|
|
|
|
using System.Net.Http;
|
2022-09-08 12:41:56 -07:00
|
|
|
|
using System.Net.NetworkInformation;
|
2022-08-08 17:03:41 +08:00
|
|
|
|
using System.Net.Sockets;
|
2022-07-01 12:22:31 +08:00
|
|
|
|
using System.Runtime.CompilerServices;
|
2022-08-25 21:51:09 +08:00
|
|
|
|
using System.Runtime.InteropServices;
|
2022-09-08 12:41:56 -07:00
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
using System.Text;
|
2022-10-05 15:53:57 +08:00
|
|
|
|
using static ICSharpCode.SharpZipLib.Zip.ExtendedUnixData;
|
2022-07-01 12:22:31 +08:00
|
|
|
|
|
|
|
|
|
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
|
|
|
|
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
2022-08-20 15:20:25 +08:00
|
|
|
|
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
|
2022-08-23 16:29:43 +08:00
|
|
|
|
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
|
2022-05-22 15:55:26 +08:00
|
|
|
|
namespace RageCoop.Core
|
|
|
|
|
{
|
2022-07-29 19:11:31 +08:00
|
|
|
|
internal static class CoreUtils
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-29 19:11:31 +08:00
|
|
|
|
private static readonly HashSet<string> ToIgnore = new HashSet<string>()
|
|
|
|
|
{
|
|
|
|
|
"RageCoop.Client.dll",
|
|
|
|
|
"RageCoop.Core.dll",
|
|
|
|
|
"RageCoop.Server.dll",
|
|
|
|
|
"ScriptHookVDotNet3.dll",
|
|
|
|
|
"ScriptHookVDotNet.dll"
|
|
|
|
|
};
|
|
|
|
|
public static bool CanBeIgnored(this string name)
|
|
|
|
|
{
|
|
|
|
|
return ToIgnore.Contains(name);
|
|
|
|
|
}
|
2022-09-08 12:41:56 -07:00
|
|
|
|
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
|
|
|
|
switch (obj)
|
|
|
|
|
{
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case byte value:
|
2022-09-08 12:41:56 -07:00
|
|
|
|
m.Write((byte)0x01); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case short value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x02); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case ushort value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x03); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case int value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x04); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case uint value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x05); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case long value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x06); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case ulong value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x07); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case float value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x08); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case bool value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x09); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case string value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x10); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case Vector3 value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x11); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case Quaternion value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x12); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case GTA.Model value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x13); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case Vector2 value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x14); m.Write(value); break;
|
2022-08-27 14:23:28 +08:00
|
|
|
|
case byte[] value:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
m.Write((byte)0x15); m.WriteByteArray(value); break;
|
|
|
|
|
case Tuple<byte, byte[]> value:
|
|
|
|
|
m.Write(value.Item1); m.Write(value.Item2); break;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
default:
|
2022-09-08 12:37:06 -07:00
|
|
|
|
throw new Exception("Unsupported object type: " + obj.GetType());
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-06 11:40:38 +08:00
|
|
|
|
public static IPEndPoint StringToEndPoint(string endpointstring)
|
|
|
|
|
{
|
|
|
|
|
return StringToEndPoint(endpointstring, -1);
|
|
|
|
|
}
|
|
|
|
|
public static IPEndPoint StringToEndPoint(string endpointstring, int defaultport)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(endpointstring)
|
|
|
|
|
|| endpointstring.Trim().Length == 0)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Endpoint descriptor may not be empty.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (defaultport != -1 &&
|
|
|
|
|
(defaultport < IPEndPoint.MinPort
|
|
|
|
|
|| defaultport > IPEndPoint.MaxPort))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string[] values = endpointstring.Split(new char[] { ':' });
|
|
|
|
|
IPAddress ipaddy;
|
|
|
|
|
int port = -1;
|
|
|
|
|
|
|
|
|
|
//check if we have an IPv6 or ports
|
|
|
|
|
if (values.Length <= 2) // ipv4 or hostname
|
|
|
|
|
{
|
|
|
|
|
if (values.Length == 1)
|
|
|
|
|
//no port is specified, default
|
|
|
|
|
port = defaultport;
|
|
|
|
|
else
|
|
|
|
|
port = getPort(values[1]);
|
|
|
|
|
|
|
|
|
|
//try to use the address as IPv4, otherwise get hostname
|
|
|
|
|
if (!IPAddress.TryParse(values[0], out ipaddy))
|
2022-08-08 17:03:41 +08:00
|
|
|
|
ipaddy = GetIPfromHost(values[0]);
|
2022-08-06 11:40:38 +08:00
|
|
|
|
}
|
|
|
|
|
else if (values.Length > 2) //ipv6
|
|
|
|
|
{
|
|
|
|
|
//could [a:b:c]:d
|
|
|
|
|
if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
|
|
|
|
|
{
|
|
|
|
|
string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
|
|
|
|
|
ipaddy = IPAddress.Parse(ipaddressstring);
|
|
|
|
|
port = getPort(values[values.Length - 1]);
|
|
|
|
|
}
|
|
|
|
|
else //[a:b:c] or a:b:c
|
|
|
|
|
{
|
|
|
|
|
ipaddy = IPAddress.Parse(endpointstring);
|
|
|
|
|
port = defaultport;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (port == -1)
|
|
|
|
|
throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring));
|
|
|
|
|
|
|
|
|
|
return new IPEndPoint(ipaddy, port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int getPort(string p)
|
|
|
|
|
{
|
|
|
|
|
|
2022-09-08 12:41:56 -07:00
|
|
|
|
if (!int.TryParse(p, out int port)
|
2022-08-06 11:40:38 +08:00
|
|
|
|
|| port < IPEndPoint.MinPort
|
|
|
|
|
|| port > IPEndPoint.MaxPort)
|
|
|
|
|
{
|
|
|
|
|
throw new FormatException(string.Format("Invalid end point port '{0}'", p));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return port;
|
|
|
|
|
}
|
2022-09-08 12:41:56 -07:00
|
|
|
|
public static IPAddress GetLocalAddress(string target = "8.8.8.8")
|
2022-08-08 17:03:41 +08:00
|
|
|
|
{
|
|
|
|
|
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
|
|
|
|
|
{
|
|
|
|
|
socket.Connect(target, 65530);
|
|
|
|
|
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
|
|
|
|
|
return endPoint.Address;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-12 20:40:50 +08:00
|
|
|
|
public static IPAddress GetIPfromHost(string p)
|
2022-08-06 11:40:38 +08:00
|
|
|
|
{
|
|
|
|
|
var hosts = Dns.GetHostAddresses(p);
|
|
|
|
|
|
|
|
|
|
if (hosts == null || hosts.Length == 0)
|
|
|
|
|
throw new ArgumentException(string.Format("Host not found: {0}", p));
|
|
|
|
|
|
|
|
|
|
return hosts[0];
|
|
|
|
|
}
|
2022-08-12 20:40:50 +08:00
|
|
|
|
public static IpInfo GetIPInfo()
|
|
|
|
|
{
|
|
|
|
|
// TLS only
|
|
|
|
|
ServicePointManager.Expect100Continue = true;
|
|
|
|
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
|
|
|
|
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
|
|
|
|
|
|
|
|
|
var httpClient = new HttpClient();
|
|
|
|
|
HttpResponseMessage response = httpClient.GetAsync("https://ipinfo.io/json").GetAwaiter().GetResult();
|
|
|
|
|
if (response.StatusCode != HttpStatusCode.OK)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"IPv4 request failed! [{(int)response.StatusCode}/{response.ReasonPhrase}]");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
|
|
|
|
return JsonConvert.DeserializeObject<IpInfo>(content);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-21 19:13:12 +08:00
|
|
|
|
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
|
|
|
|
|
{
|
|
|
|
|
foreach (DirectoryInfo dir in source.GetDirectories())
|
|
|
|
|
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
|
|
|
|
|
foreach (FileInfo file in source.GetFiles())
|
|
|
|
|
file.CopyTo(Path.Combine(target.FullName, file.Name), true);
|
|
|
|
|
}
|
2022-09-07 09:52:40 +08:00
|
|
|
|
public static string GetInvariantRID()
|
2022-08-25 21:51:09 +08:00
|
|
|
|
{
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
|
|
|
{
|
|
|
|
|
return "win-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
|
|
|
|
|
}
|
2022-09-05 13:02:09 +02:00
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
2022-08-25 21:51:09 +08:00
|
|
|
|
{
|
|
|
|
|
return "linux-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
|
|
|
|
|
}
|
2022-09-05 13:02:09 +02:00
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
2022-08-25 21:51:09 +08:00
|
|
|
|
{
|
|
|
|
|
return "osx-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
|
|
|
|
|
}
|
|
|
|
|
return "unknown";
|
|
|
|
|
}
|
2022-08-12 20:40:50 +08:00
|
|
|
|
|
2022-09-07 09:52:40 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get local ip addresses on all network interfaces
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static List<IPAddress> GetLocalAddress()
|
|
|
|
|
{
|
|
|
|
|
var addresses = new List<IPAddress>();
|
|
|
|
|
foreach (NetworkInterface netInterface in NetworkInterface.GetAllNetworkInterfaces())
|
|
|
|
|
{
|
|
|
|
|
IPInterfaceProperties ipProps = netInterface.GetIPProperties();
|
|
|
|
|
foreach (UnicastIPAddressInformation addr in ipProps.UnicastAddresses)
|
|
|
|
|
{
|
|
|
|
|
addresses.Add(addr.Address);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return addresses;
|
|
|
|
|
}
|
2022-08-12 20:40:50 +08:00
|
|
|
|
}
|
2022-08-21 19:13:12 +08:00
|
|
|
|
internal class IpInfo
|
2022-08-12 20:40:50 +08:00
|
|
|
|
{
|
|
|
|
|
[JsonProperty("ip")]
|
|
|
|
|
public string Address { get; set; }
|
2022-06-03 16:28:02 +08:00
|
|
|
|
|
2022-08-12 20:40:50 +08:00
|
|
|
|
[JsonProperty("country")]
|
|
|
|
|
public string Country { get; set; }
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-07-01 14:39:43 +08:00
|
|
|
|
internal static class Extensions
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
public static byte[] GetBytes(this string s)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
return Encoding.UTF8.GetBytes(s);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-06-11 18:41:10 +08:00
|
|
|
|
public static string GetString(this byte[] data)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
return Encoding.UTF8.GetString(data);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-07-02 17:14:56 +08:00
|
|
|
|
public static byte[] GetBytes(this Vector3 vec)
|
|
|
|
|
{
|
|
|
|
|
// 12 bytes
|
|
|
|
|
return new List<byte[]>() { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y), BitConverter.GetBytes(vec.Z) }.Join(4);
|
|
|
|
|
}
|
2022-07-03 15:28:28 +08:00
|
|
|
|
|
|
|
|
|
public static byte[] GetBytes(this Vector2 vec)
|
|
|
|
|
{
|
|
|
|
|
// 8 bytes
|
|
|
|
|
return new List<byte[]>() { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y) }.Join(4);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-02 17:14:56 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="qua"></param>
|
|
|
|
|
/// <returns>An array of bytes with length 16</returns>
|
|
|
|
|
public static byte[] GetBytes(this Quaternion qua)
|
|
|
|
|
{
|
|
|
|
|
// 16 bytes
|
|
|
|
|
return new List<byte[]>() { BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), BitConverter.GetBytes(qua.W) }.Join(4);
|
|
|
|
|
}
|
2022-09-08 12:41:56 -07:00
|
|
|
|
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
|
2022-08-10 20:42:47 +08:00
|
|
|
|
{
|
2022-09-08 12:37:06 -07:00
|
|
|
|
var p = new T();
|
|
|
|
|
p.Deserialize(msg);
|
2022-08-10 20:42:47 +08:00
|
|
|
|
return p;
|
|
|
|
|
}
|
2022-10-05 15:53:57 +08:00
|
|
|
|
public static bool HasPedFlag(this PedDataFlags flags, PedDataFlags flag)
|
2022-06-21 18:13:30 +08:00
|
|
|
|
{
|
2022-10-05 15:53:57 +08:00
|
|
|
|
return (flags & flag) != 0;
|
2022-06-21 18:13:30 +08:00
|
|
|
|
}
|
2022-10-05 15:53:57 +08:00
|
|
|
|
public static bool HasProjDataFlag(this ProjectileDataFlags flags, ProjectileDataFlags flag)
|
2022-08-14 17:08:43 +08:00
|
|
|
|
{
|
2022-10-05 15:53:57 +08:00
|
|
|
|
return (flags & flag) != 0;
|
2022-08-14 17:08:43 +08:00
|
|
|
|
}
|
2022-06-21 18:13:30 +08:00
|
|
|
|
|
2022-10-05 15:53:57 +08:00
|
|
|
|
public static bool HasVehFlag(this VehicleDataFlags flags, VehicleDataFlags flag)
|
2022-06-21 18:13:30 +08:00
|
|
|
|
{
|
2022-10-05 15:53:57 +08:00
|
|
|
|
return (flags & flag) != 0;
|
2022-06-21 18:13:30 +08:00
|
|
|
|
}
|
2022-10-05 15:53:57 +08:00
|
|
|
|
public static bool HasConfigFlag(this PlayerConfigFlags flags, PlayerConfigFlags flag)
|
2022-06-22 14:18:20 +08:00
|
|
|
|
{
|
2022-10-05 15:53:57 +08:00
|
|
|
|
return (flags & flag) != 0;
|
|
|
|
|
}
|
|
|
|
|
public static bool HasEventFlag(this CustomEventFlags flags,CustomEventFlags flag)
|
|
|
|
|
{
|
|
|
|
|
return (flags & flag) != 0;
|
|
|
|
|
|
2022-06-22 14:18:20 +08:00
|
|
|
|
}
|
2022-06-23 09:46:38 +08:00
|
|
|
|
public static Type GetActualType(this TypeCode code)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case TypeCode.Boolean:
|
|
|
|
|
return typeof(bool);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Byte:
|
|
|
|
|
return typeof(byte);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Char:
|
|
|
|
|
return typeof(char);
|
|
|
|
|
|
|
|
|
|
case TypeCode.DateTime:
|
|
|
|
|
return typeof(DateTime);
|
|
|
|
|
|
|
|
|
|
case TypeCode.DBNull:
|
|
|
|
|
return typeof(DBNull);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Decimal:
|
|
|
|
|
return typeof(decimal);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Double:
|
|
|
|
|
return typeof(double);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Empty:
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
case TypeCode.Int16:
|
|
|
|
|
return typeof(short);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Int32:
|
|
|
|
|
return typeof(int);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Int64:
|
|
|
|
|
return typeof(long);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Object:
|
|
|
|
|
return typeof(object);
|
|
|
|
|
|
|
|
|
|
case TypeCode.SByte:
|
|
|
|
|
return typeof(sbyte);
|
|
|
|
|
|
|
|
|
|
case TypeCode.Single:
|
|
|
|
|
return typeof(Single);
|
|
|
|
|
|
|
|
|
|
case TypeCode.String:
|
|
|
|
|
return typeof(string);
|
|
|
|
|
|
|
|
|
|
case TypeCode.UInt16:
|
|
|
|
|
return typeof(UInt16);
|
|
|
|
|
|
|
|
|
|
case TypeCode.UInt32:
|
|
|
|
|
return typeof(UInt32);
|
|
|
|
|
|
|
|
|
|
case TypeCode.UInt64:
|
|
|
|
|
return typeof(UInt64);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
public static string DumpWithType(this IEnumerable<object> objects)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
2022-09-08 12:41:56 -07:00
|
|
|
|
foreach (var obj in objects)
|
2022-06-23 09:46:38 +08:00
|
|
|
|
{
|
2022-09-08 12:41:56 -07:00
|
|
|
|
sb.Append(obj.GetType() + ":" + obj.ToString() + "\n");
|
2022-06-23 09:46:38 +08:00
|
|
|
|
}
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
public static string Dump<T>(this IEnumerable<T> objects)
|
|
|
|
|
{
|
2022-09-05 13:02:09 +02:00
|
|
|
|
return $"{{{string.Join(",", objects)}}}";
|
2022-06-23 09:46:38 +08:00
|
|
|
|
}
|
2022-09-08 12:41:56 -07:00
|
|
|
|
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
|
2022-06-23 09:46:38 +08:00
|
|
|
|
{
|
2022-09-08 12:41:56 -07:00
|
|
|
|
foreach (var obj in objects)
|
2022-06-23 09:46:38 +08:00
|
|
|
|
{
|
|
|
|
|
action(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-24 10:33:36 +08:00
|
|
|
|
public static byte[] ReadToEnd(this Stream stream)
|
|
|
|
|
{
|
|
|
|
|
if (stream is MemoryStream)
|
|
|
|
|
return ((MemoryStream)stream).ToArray();
|
|
|
|
|
|
|
|
|
|
using (var memoryStream = new MemoryStream())
|
|
|
|
|
{
|
|
|
|
|
stream.CopyTo(memoryStream);
|
|
|
|
|
return memoryStream.ToArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-23 12:21:17 +08:00
|
|
|
|
public static MemoryStream ToMemStream(this Stream stream)
|
|
|
|
|
{
|
|
|
|
|
var memoryStream = new MemoryStream();
|
|
|
|
|
stream.CopyTo(memoryStream);
|
|
|
|
|
return memoryStream;
|
|
|
|
|
}
|
2022-09-08 12:41:56 -07:00
|
|
|
|
public static byte[] Join(this List<byte[]> arrays, int lengthPerArray = -1)
|
2022-06-24 10:33:36 +08:00
|
|
|
|
{
|
2022-09-08 12:41:56 -07:00
|
|
|
|
if (arrays.Count == 1) { return arrays[0]; }
|
|
|
|
|
var output = lengthPerArray == -1 ? new byte[arrays.Sum(arr => arr.Length)] : new byte[arrays.Count * lengthPerArray];
|
2022-06-24 10:33:36 +08:00
|
|
|
|
int writeIdx = 0;
|
|
|
|
|
foreach (var byteArr in arrays)
|
|
|
|
|
{
|
|
|
|
|
byteArr.CopyTo(output, writeIdx);
|
|
|
|
|
writeIdx += byteArr.Length;
|
|
|
|
|
}
|
|
|
|
|
return output;
|
|
|
|
|
}
|
2022-07-01 12:22:31 +08:00
|
|
|
|
|
|
|
|
|
public static bool IsSubclassOf(this Type type, string baseTypeName)
|
|
|
|
|
{
|
|
|
|
|
for (Type t = type.BaseType; t != null; t = t.BaseType)
|
|
|
|
|
if (t.FullName == baseTypeName)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-07-22 19:43:48 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Some extension methods provided by RageCoop
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static class PublicExtensions
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2022-07-23 23:45:20 +08:00
|
|
|
|
/// Get a SHA256 hashed byte array of the input string, internally used to hash password at client side.
|
2022-07-22 19:43:48 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="inputString"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static byte[] GetSHA256Hash(this string inputString)
|
|
|
|
|
{
|
|
|
|
|
using (HashAlgorithm algorithm = SHA256.Create())
|
|
|
|
|
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
|
|
|
|
|
}
|
2022-07-23 23:45:20 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Convert a byte array to hex-encoded string, internally used to trigger handshake event
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static string ToHexString(this byte[] data)
|
|
|
|
|
{
|
|
|
|
|
return BitConverter.ToString(data).Replace("-", String.Empty);
|
|
|
|
|
}
|
2022-08-12 18:02:43 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Convert a string to IP address
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ip"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static IPAddress ToIP(this string ip)
|
|
|
|
|
{
|
|
|
|
|
return IPAddress.Parse(ip);
|
|
|
|
|
}
|
2022-09-07 09:52:40 +08:00
|
|
|
|
|
2022-07-22 19:43:48 +08:00
|
|
|
|
}
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|