using BrewMonster; using BrewMonster.Network; using CSNetwork.GPDataType; using System; using System.Collections; using System.IO; using System.IO.Compression; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using UnityEngine; public static class EC_Utility { static A3DVECTOR3 a3DVECTOR = new A3DVECTOR3(); static Vector3 vector3 = new Vector3(); public static byte glb_CompressDirH(float x, float z) { const float fInvInter = 256.0f / 360.0f; if (Math.Abs(x) < 0.00001f) { if (z > 0.0f) return 64; else return 192; } else { // atan2 trong C# trả về radian, cần đổi sang độ float fDeg = (float)(Math.Atan2(z, x) * (180.0 / Math.PI)); // đảm bảo góc nằm trong [0, 360) if (fDeg < 0) fDeg += 360.0f; return (byte)(fDeg * fInvInter); } } public static bool BinaryEquals(T1 a, T2 b) where T1 : struct where T2 : struct { ReadOnlySpan bytesA = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref a, 1)); ReadOnlySpan bytesB = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref b, 1)); // if sizes differ → not equal if (bytesA.Length != bytesB.Length) return false; return bytesA.SequenceEqual(bytesB); } public static float FIX8TOFLOAT(int x) => x / 256.0f; public static T ByteArrayToStructure(byte[] data) where T : struct { int size = Marshal.SizeOf(typeof(T)); if (data.Length < size) throw new ArgumentException($"Data length {data.Length} < struct size {size}"); IntPtr ptr = Marshal.AllocHGlobal(size); try { Marshal.Copy(data, 0, ptr, size); return Marshal.PtrToStructure(ptr); } finally { Marshal.FreeHGlobal(ptr); } } public static A3DVECTOR3 glb_DecompressDirH(byte byDir) { const float fInter = 360.0f / 256.0f; float fRad = Mathf.Deg2Rad * (byDir * fInter); A3DVECTOR3 v; v.x = Mathf.Cos(fRad); v.z = Mathf.Sin(fRad); v.y = 0.0f; return v; } public static System.Numerics.Vector3 ToNumerics(this UnityEngine.Vector3 v) { return new System.Numerics.Vector3(v.x, v.y, v.z); } public static A3DVECTOR3 ToA3DVECTOR3(this UnityEngine.Vector3 v) { a3DVECTOR.Clear(); a3DVECTOR.x = v.x; a3DVECTOR.y = v.y; a3DVECTOR.z = v.z; return a3DVECTOR; } public static Vector3 ToVector3(A3DVECTOR3 a3DVECTOR3) { vector3 = Vector3.zero; vector3.x = a3DVECTOR3.x; vector3.y = a3DVECTOR3.y; vector3.z = a3DVECTOR3.z; return vector3; } public static float MagnitudeH(this Vector3 v) { return Mathf.Sqrt(v.x * v.x + v.z * v.z); } public static string FixGBKString(string input) { // Giả sử input hiện đang là "Æð" // B1: lấy bytes theo "Latin1" (mỗi ký tự 1 byte giữ nguyên giá trị gốc) byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(input); // B2: giải mã lại bằng GBK (Code page 936) string decoded = Encoding.GetEncoding(936).GetString(bytes); return decoded; } public static string BuildActionName(PLAYER_ACTION action, int weaponType, string tail = "") { string prefix = action.data.ActionPrefix ?? string.Empty; string suffix = string.Empty; if (action.data.action_weapon_suffix != null && weaponType >= 0 && weaponType < action.data.action_weapon_suffix.Length) { suffix = action.data.action_weapon_suffix[weaponType].Suffix ?? string.Empty; } var tailFixed = FixGBKString(tail); return $"{prefix}_{suffix}{tail}"; } public static string BuildActionName(PLAYER_ACTION_INFO_CONFIG data, int weaponType, string midBody = "") { string prefix = data.ActionPrefix ?? string.Empty; string suffix = string.Empty; if (data.action_weapon_suffix != null && weaponType >= 0 && weaponType < data.action_weapon_suffix.Length) { suffix = data.action_weapon_suffix[weaponType].Suffix ?? string.Empty; } var midBodyFixed = FixGBKString(midBody); return $"{prefix}{midBodyFixed}{suffix}"; } public static byte glb_BuildBLSMask() { byte byMask = 0; CECConfigs pConfigs = EC_Game.GetConfigs(); /* if (pConfigs->GetGameSettings().bBls_NoRed) byMask |= GP_BLSMASK_NORED; if (pConfigs->GetGameSettings().bBls_NoMafia) byMask |= GP_BLSMASK_NOMAFIA; if (pConfigs->GetGameSettings().bBls_Self) byMask |= GP_BLSMASK_SELF; if (pConfigs->GetGameSettings().bBls_NoAlliance) byMask |= GP_BLSMASK_NOALLIANCE; if (pConfigs->GetGameSettings().bBls_NoForce) byMask |= GP_BLSMASK_NOFORCE;*/ return byMask; } public static byte glb_BuildPVPMask(bool bForceAttack) { byte byMask = 0; if (bForceAttack) byMask |= (byte)PVP_mask.GP_PVPMASK_FORCE; //else //{ // CECConfigs* pConfigs = g_pGame->GetConfigs(); // if (pConfigs->GetGameSettings().bAtk_Player) // { // byMask |= GP_PVPMASK_FORCE; // if (pConfigs->GetGameSettings().bAtk_NoMafia) // byMask |= GP_PVPMASK_NOMAFIA; // if (pConfigs->GetGameSettings().bAtk_NoWhite) // byMask |= GP_PVPMASK_NOWHITE; // if (pConfigs->GetGameSettings().bAtk_NoAlliance) // byMask |= GP_PVPMASK_NOALLIANCE; // if (pConfigs->GetGameSettings().bAtk_NoForce) // byMask |= GP_PVPMASK_NOFORCE; // } //} return byMask; } public static T a_ClampFloor(T x, T min) where T : IComparable { return (x.CompareTo(min) < 0) ? min : x; } public static T a_Min(T x, T y) where T : IComparable { return (y.CompareTo(x) < 0) ? y : x; } public static bool STRING_TO_A3DCOLOR(string str, out Color clr) { // ��� A3DCOLOR_TO_STRING ������ת�� // [English] Parse according to A3DCOLOR_TO_STRING conversion format bool ret = false; clr = Color.white; byte[] rgb = new byte[6]; int nLen = str != null ? str.Length : 0; while (nLen == 7) { // ����ĸ��ת����Сд // [English] Convert uppercase letters to lowercase str = str.ToLowerInvariant(); if (str[0] != '^') break; char c; int i; for (i = 1; i < nLen; ++i) { c = str[i]; if (c >= '0' && c <= '9') { rgb[i - 1] = (byte)(c - '0'); } else if (c >= 'a' && c <= 'f') { rgb[i - 1] = (byte)(10 + (c - 'a')); } else { break; } } if (i < nLen) break; byte r = (byte)((rgb[0] << 4) + rgb[1]); byte g = (byte)((rgb[2] << 4) + rgb[3]); byte b = (byte)((rgb[4] << 4) + rgb[5]); clr = new Color(r / 255f, g / 255f, b / 255f, 1f); ret = true; break; } return ret; } // ===== Text/Color helpers moved from EC_InventoryUI ===== public static string FormatForLegacyText(string text) { if (string.IsNullOrEmpty(text)) return string.Empty; StringBuilder result = new StringBuilder(text); result.Replace("\\r", "\n"); return ProcessColorCodesForLegacy(result); } public static string FormatForTextMeshPro(string text) { if (string.IsNullOrEmpty(text)) return string.Empty; StringBuilder result = new StringBuilder(text); result.Replace("\\r", "\n"); return ProcessColorCodes(result); } public static string ProcessColorCodes(StringBuilder text) { string pattern = @"\^([0-9A-Fa-f]{6})"; return Regex.Replace(text.ToString(), pattern, match => { string hexColor = match.Groups[1].Value; return $""; }, RegexOptions.None); } public static string ProcessColorCodesForLegacy(StringBuilder text) { string pattern = @"\^([0-9A-Fa-f]{6})"; return Regex.Replace(text.ToString(), pattern, match => { string hexColor = match.Groups[1].Value; Color color = HexToColor(hexColor); return $""; }, RegexOptions.None); } private static Color HexToColor(string hex) { if (hex == null || hex.Length != 6) return Color.white; try { int r = Convert.ToInt32(hex.Substring(0, 2), 16); int g = Convert.ToInt32(hex.Substring(2, 2), 16); int b = Convert.ToInt32(hex.Substring(4, 2), 16); return new Color(r / 255f, g / 255f, b / 255f, 1f); } catch { return Color.white; } } }