Files
RAGECOOP-V/RageCoop.Core/CoreUtils.cs

469 lines
16 KiB
C#
Raw Normal View History

2022-05-22 15:55:26 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA.Math;
2022-06-19 11:12:20 +08:00
using System.Security.Cryptography;
2022-06-03 16:28:02 +08:00
using System.Net;
2022-08-12 20:40:50 +08:00
using System.Net.Http;
2022-08-08 17:03:41 +08:00
using System.Net.Sockets;
2022-06-24 10:33:36 +08:00
using System.IO;
2022-07-01 12:22:31 +08:00
using System.Runtime.CompilerServices;
2022-08-10 20:42:47 +08:00
using Lidgren.Network;
2022-08-12 20:40:50 +08:00
using Newtonsoft.Json;
2022-07-01 12:22:31 +08:00
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
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-05-22 15:55:26 +08:00
public static (byte, byte[]) GetBytesFromObject(object obj)
{
switch (obj)
{
case byte _:
2022-06-23 09:46:38 +08:00
return (0x01, new byte[] { (byte)obj });
2022-05-22 15:55:26 +08:00
case short _:
return (0x02, BitConverter.GetBytes((short)obj));
case ushort _:
return (0x03, BitConverter.GetBytes((ushort)obj));
case int _:
return (0x04, BitConverter.GetBytes((int)obj));
case uint _:
return (0x05, BitConverter.GetBytes((uint)obj));
case long _:
return (0x06, BitConverter.GetBytes((long)obj));
case ulong _:
return (0x07, BitConverter.GetBytes((ulong)obj));
case float _:
return (0x08, BitConverter.GetBytes((float)obj));
case bool _:
return (0x09, BitConverter.GetBytes((bool)obj));
2022-06-19 11:12:20 +08:00
case string _:
2022-07-02 17:14:56 +08:00
return (0x10, ((string)obj).GetBytesWithLength());
case Vector3 _:
return (0x11,((Vector3)obj).GetBytes());
case Quaternion _:
return (0x12, ((Quaternion)obj).GetBytes());
case GTA.Model _:
return (0x13, BitConverter.GetBytes((GTA.Model)obj));
2022-07-03 15:28:28 +08:00
case Vector2 _:
return (0x14, ((Vector2)obj).GetBytes());
2022-07-02 17:14:56 +08:00
case Tuple<byte, byte[]> _:
var tup = (Tuple<byte, byte[]>)obj;
return (tup.Item1, tup.Item2);
2022-05-22 15:55:26 +08:00
default:
return (0x0, null);
}
}
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)
{
int port;
if (!int.TryParse(p, out port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
{
throw new FormatException(string.Format("Invalid end point port '{0}'", p));
}
return port;
}
2022-08-08 17:03:41 +08:00
public static IPAddress GetLocalAddress(string target= "8.8.8.8")
{
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);
}
}
internal struct IpInfo
{
[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
{
public static void AddVector3(this List<byte> bytes, Vector3 vec3)
2022-05-22 15:55:26 +08:00
{
bytes.AddRange(BitConverter.GetBytes(vec3.X));
bytes.AddRange(BitConverter.GetBytes(vec3.Y));
bytes.AddRange(BitConverter.GetBytes(vec3.Z));
}
public static void AddQuaternion(this List<byte> bytes, Quaternion quat)
2022-05-22 15:55:26 +08:00
{
bytes.AddRange(BitConverter.GetBytes(quat.X));
bytes.AddRange(BitConverter.GetBytes(quat.Y));
bytes.AddRange(BitConverter.GetBytes(quat.Z));
bytes.AddRange(BitConverter.GetBytes(quat.W));
}
public static void AddInt(this List<byte> bytes,int i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUint(this List<byte> bytes, uint i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
2022-07-04 22:50:47 +08:00
public static void AddShort(this List<byte> bytes, short i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUshort(this List<byte> bytes, ushort i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
2022-05-22 15:55:26 +08:00
public static void AddLong(this List<byte> bytes, long i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddUlong(this List<byte> bytes, ulong i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
public static void AddFloat(this List<byte> bytes, float i)
{
bytes.AddRange(BitConverter.GetBytes(i));
}
2022-08-06 11:40:38 +08:00
public static void AddBool(this List<byte> bytes, bool b)
{
bytes.Add(b? (byte)1 :(byte)0);
}
2022-06-19 11:12:20 +08:00
public static void AddString(this List<byte> bytes, string s)
{
var sb = Encoding.UTF8.GetBytes(s);
bytes.AddInt(sb.Length);
bytes.AddRange(sb);
}
2022-06-24 10:33:36 +08:00
public static void AddArray(this List<byte> bytes, byte[] toadd)
{
bytes.AddInt(toadd.Length);
bytes.AddRange(toadd);
}
public static byte[] GetBytes(this string s)
2022-05-22 15:55:26 +08:00
{
return Encoding.UTF8.GetBytes(s);
2022-05-22 15:55:26 +08:00
}
2022-06-19 11:12:20 +08:00
public static byte[] GetBytesWithLength(this string s)
{
var data = new List<byte>(100);
var sb = Encoding.UTF8.GetBytes(s);
data.AddInt(sb.Length);
data.AddRange(sb);
return data.ToArray();
}
public static string GetString(this byte[] data)
2022-05-22 15:55:26 +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-06-21 18:13:30 +08:00
2022-08-10 20:42:47 +08:00
2022-08-11 18:25:01 +08:00
public static T GetPacket<T>(this NetIncomingMessage msg,PacketPool pool=null) where T : Packet, new()
2022-08-10 20:42:47 +08:00
{
msg.ReadByte();
return GetPacket<T>(msg.ReadBytes(msg.ReadInt32()));
}
2022-08-11 18:25:01 +08:00
public static T GetPacket<T>(this byte[] data, PacketPool pool = null) where T : Packet, new()
2022-08-10 20:42:47 +08:00
{
2022-08-11 18:25:01 +08:00
T p = pool?.Get<T>() ?? new T();
2022-08-10 20:42:47 +08:00
p.Deserialize(data);
return p;
}
2022-06-21 18:13:30 +08:00
public static bool HasPedFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
public static bool HasVehFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
2022-06-22 14:18:20 +08:00
public static bool HasConfigFlag(this PlayerConfigFlags flagToCheck, PlayerConfigFlags flag)
{
return (flagToCheck & flag)!=0;
}
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();
foreach(var obj in objects)
{
sb.Append(obj.GetType()+":"+obj.ToString()+"\n");
}
return sb.ToString();
}
public static string Dump<T>(this IEnumerable<T> objects)
{
return "{"+string.Join(",",objects)+"}";
}
public static void ForEach<T>(this IEnumerable<T> objects,Action<T> action)
{
foreach(var obj in objects)
{
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-07-02 17:14:56 +08:00
public static byte[] Join(this List<byte[]> arrays,int lengthPerArray=-1)
2022-06-24 10:33:36 +08:00
{
if (arrays.Count==1) { return arrays[0]; }
2022-07-02 17:14:56 +08:00
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
}
/// <summary>
/// Some extension methods provided by RageCoop
/// </summary>
public static class PublicExtensions
{
/// <summary>
/// Get a SHA256 hashed byte array of the input string, internally used to hash password at client side.
/// </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));
}
/// <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-05-22 15:55:26 +08:00
}