From 919678b811b5e468bd703cd74271b7581a6a4583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Mon, 23 Mar 2026 20:01:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E5=90=88=E6=89=A9=E5=B1=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnityEngine.CommonExtensions.cs | 38 + .../UnityEngine.Vector3/Vector3Extensions.cs | 30 + Runtime/ABase/Helper/CompressionUtility.cs | 206 ---- Runtime/ABase/Helper/GameHelper.cs | 1013 ----------------- Runtime/ABase/Helper/GameHelper.cs.meta | 3 - Runtime/ABase/Helper/PositionHelper.cs | 150 --- Runtime/ABase/Helper/PositionHelper.cs.meta | 3 - Runtime/ABase/Helper/TimerHelper.cs | 266 ----- Runtime/ABase/Helper/TimerHelper.cs.meta | 3 - Runtime/ABase/Helper/UnityRendererHelper.cs | 63 - .../ABase/Helper/UnityRendererHelper.cs.meta | 3 - Runtime/ABase/Helper/ZipHelper.cs | 327 ------ .../ABase/Utility/Utility.Compression.Zip.cs | 240 ++++ .../Utility.Compression.Zip.cs.meta} | 2 +- Runtime/ABase/Utility/Utility.Compression.cs | 69 +- Runtime/ABase/Utility/Utility.Math.cs | 2 +- Runtime/ABase/Utility/Utility.Position.cs | 93 ++ .../Utility.Position.cs.meta} | 5 +- Runtime/ABase/Utility/Utility.Time.cs | 118 ++ Runtime/ABase/Utility/Utility.Time.cs.meta | 11 + .../ABase/Utility/Utility.Unity.Gameplay.cs | 6 +- 21 files changed, 602 insertions(+), 2049 deletions(-) delete mode 100644 Runtime/ABase/Helper/CompressionUtility.cs delete mode 100644 Runtime/ABase/Helper/GameHelper.cs delete mode 100644 Runtime/ABase/Helper/GameHelper.cs.meta delete mode 100644 Runtime/ABase/Helper/PositionHelper.cs delete mode 100644 Runtime/ABase/Helper/PositionHelper.cs.meta delete mode 100644 Runtime/ABase/Helper/TimerHelper.cs delete mode 100644 Runtime/ABase/Helper/TimerHelper.cs.meta delete mode 100644 Runtime/ABase/Helper/UnityRendererHelper.cs delete mode 100644 Runtime/ABase/Helper/UnityRendererHelper.cs.meta delete mode 100644 Runtime/ABase/Helper/ZipHelper.cs create mode 100644 Runtime/ABase/Utility/Utility.Compression.Zip.cs rename Runtime/ABase/{Helper/CompressionUtility.cs.meta => Utility/Utility.Compression.Zip.cs.meta} (83%) create mode 100644 Runtime/ABase/Utility/Utility.Position.cs rename Runtime/ABase/{Helper/ZipHelper.cs.meta => Utility/Utility.Position.cs.meta} (69%) create mode 100644 Runtime/ABase/Utility/Utility.Time.cs create mode 100644 Runtime/ABase/Utility/Utility.Time.cs.meta diff --git a/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs b/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs index 9e841be..8ac3867 100644 --- a/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs +++ b/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs @@ -1,5 +1,7 @@ +using System; using AlicizaX; using UnityEngine.UI; +using UnityEngine.SceneManagement; namespace UnityEngine { @@ -82,6 +84,42 @@ namespace UnityEngine } } + [UnityEngine.Scripting.Preserve] + public static class RendererExtensions + { + public static bool IsVisibleFrom(this Renderer renderer, Camera camera) + { + Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera); + return GeometryUtility.TestPlanesAABB(planes, renderer.bounds); + } + } + + [UnityEngine.Scripting.Preserve] + public static class CameraExtensions + { + public static Texture2D GetCaptureScreenshot(this Camera camera, float scale = 0.5f) + { + Rect rect = new Rect(0f, 0f, Screen.width * scale, Screen.height * scale); + string name = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"); + RenderTexture renderTexture = RenderTexture.GetTemporary((int)rect.width, (int)rect.height, 0); + renderTexture.name = SceneManager.GetActiveScene().name + "_" + renderTexture.width + "_" + renderTexture.height + "_" + name; + camera.targetTexture = renderTexture; + camera.Render(); + + RenderTexture.active = renderTexture; + Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false) + { + name = renderTexture.name + }; + screenShot.ReadPixels(rect, 0, 0); + screenShot.Apply(); + camera.targetTexture = null; + RenderTexture.active = null; + RenderTexture.ReleaseTemporary(renderTexture); + return screenShot; + } + } + [UnityEngine.Scripting.Preserve] public static class AngleExtensions { diff --git a/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs b/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs index 02cebc0..5d5d477 100644 --- a/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs +++ b/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs @@ -34,5 +34,35 @@ lhs.Scale(rhs); return lhs; } + + /// + /// 将三维向量投影到 XZ 平面。 + /// + public static Vector2 IgnoreYAxis(this Vector3 vector3) + { + return new Vector2(vector3.x, vector3.z); + } + + /// + /// 保留 XZ 分量并清空 Y 轴。 + /// + public static Vector3 FlattenY(this Vector3 vector3) + { + return new Vector3(vector3.x, 0f, vector3.z); + } + + /// + /// 判断目标点是否位于当前方向的左侧。 + /// + public static bool PointOnLeftSideOfVector(this Vector3 vector3, Vector3 originPoint, Vector3 point) + { + Vector2 origin = originPoint.IgnoreYAxis(); + Vector2 targetDirection = (point.IgnoreYAxis() - origin).normalized; + Vector2 direction = vector3.IgnoreYAxis(); + float verticalX = origin.x; + float verticalY = (-verticalX * direction.x) / direction.y; + Vector2 normalVertical = new Vector2(verticalX, verticalY).normalized; + return Vector2.Dot(normalVertical, targetDirection) < 0f; + } } } diff --git a/Runtime/ABase/Helper/CompressionUtility.cs b/Runtime/ABase/Helper/CompressionUtility.cs deleted file mode 100644 index 3547fee..0000000 --- a/Runtime/ABase/Helper/CompressionUtility.cs +++ /dev/null @@ -1,206 +0,0 @@ -using AlicizaX; -using ICSharpCode.SharpZipLib.GZip; -using System; -using System.IO; - -namespace AlicizaX -{ - /// - /// 默认压缩解压缩辅助器。 - /// - [UnityEngine.Scripting.Preserve] - public class CompressionUtility - { - private const int CachedBytesLength = 0x1000; - private static readonly byte[] m_CachedBytes = new byte[CachedBytesLength]; - - /// - /// 压缩数据。 - /// - /// 要压缩的数据的二进制流。 - /// 要压缩的数据的二进制流的偏移。 - /// 要压缩的数据的二进制流的长度。 - /// 压缩后的数据的二进制流。 - /// 是否压缩数据成功。 - public static bool Compress(byte[] bytes, int offset, int length, Stream compressedStream) - { - if (bytes == null) - { - return false; - } - - if (offset < 0 || length < 0 || offset + length > bytes.Length) - { - return false; - } - - if (compressedStream == null) - { - return false; - } - - try - { - GZipOutputStream gZipOutputStream = new GZipOutputStream(compressedStream); - gZipOutputStream.Write(bytes, offset, length); - gZipOutputStream.Finish(); - ProcessHeader(compressedStream); - return true; - } - catch - { - return false; - } - } - - /// - /// 压缩数据。 - /// - /// 要压缩的数据的二进制流。 - /// 压缩后的数据的二进制流。 - /// 是否压缩数据成功。 - public static bool Compress(Stream stream, Stream compressedStream) - { - if (stream == null) - { - return false; - } - - if (compressedStream == null) - { - return false; - } - - try - { - GZipOutputStream gZipOutputStream = new GZipOutputStream(compressedStream); - int bytesRead = 0; - while ((bytesRead = stream.Read(m_CachedBytes, 0, CachedBytesLength)) > 0) - { - gZipOutputStream.Write(m_CachedBytes, 0, bytesRead); - } - - gZipOutputStream.Finish(); - ProcessHeader(compressedStream); - return true; - } - catch - { - return false; - } - finally - { - Array.Clear(m_CachedBytes, 0, CachedBytesLength); - } - } - - /// - /// 解压缩数据。 - /// - /// 要解压缩的数据的二进制流。 - /// 要解压缩的数据的二进制流的偏移。 - /// 要解压缩的数据的二进制流的长度。 - /// 解压缩后的数据的二进制流。 - /// 是否解压缩数据成功。 - public static bool Decompress(byte[] bytes, int offset, int length, Stream decompressedStream) - { - if (bytes == null) - { - return false; - } - - if (offset < 0 || length < 0 || offset + length > bytes.Length) - { - return false; - } - - if (decompressedStream == null) - { - return false; - } - - MemoryStream memoryStream = null; - try - { - memoryStream = new MemoryStream(bytes, offset, length, false); - using (GZipInputStream gZipInputStream = new GZipInputStream(memoryStream)) - { - int bytesRead = 0; - while ((bytesRead = gZipInputStream.Read(m_CachedBytes, 0, CachedBytesLength)) > 0) - { - decompressedStream.Write(m_CachedBytes, 0, bytesRead); - } - } - - return true; - } - catch - { - return false; - } - finally - { - if (memoryStream != null) - { - memoryStream.Dispose(); - memoryStream = null; - } - - Array.Clear(m_CachedBytes, 0, CachedBytesLength); - } - } - - /// - /// 解压缩数据。 - /// - /// 要解压缩的数据的二进制流。 - /// 解压缩后的数据的二进制流。 - /// 是否解压缩数据成功。 - public static bool Decompress(Stream stream, Stream decompressedStream) - { - if (stream == null) - { - return false; - } - - if (decompressedStream == null) - { - return false; - } - - try - { - GZipInputStream gZipInputStream = new GZipInputStream(stream); - int bytesRead = 0; - while ((bytesRead = gZipInputStream.Read(m_CachedBytes, 0, CachedBytesLength)) > 0) - { - decompressedStream.Write(m_CachedBytes, 0, bytesRead); - } - - return true; - } - catch - { - return false; - } - finally - { - Array.Clear(m_CachedBytes, 0, CachedBytesLength); - } - } - - private static void ProcessHeader(Stream compressedStream) - { - if (compressedStream.Length >= 8L) - { - long current = compressedStream.Position; - compressedStream.Position = 4L; - compressedStream.WriteByte(25); - compressedStream.WriteByte(134); - compressedStream.WriteByte(2); - compressedStream.WriteByte(32); - compressedStream.Position = current; - } - } - } -} diff --git a/Runtime/ABase/Helper/GameHelper.cs b/Runtime/ABase/Helper/GameHelper.cs deleted file mode 100644 index 0787f17..0000000 --- a/Runtime/ABase/Helper/GameHelper.cs +++ /dev/null @@ -1,1013 +0,0 @@ -using System.Linq; -using System.Globalization; -using System.Collections.Generic; - -using System.Text.RegularExpressions; -using AlicizaX; -using UnityEngine; -using UnityEngine.UI; - -#if UNITY_EDITOR -using UnityEditor; -#endif - -namespace UnityEngine -{ - public static class GameHelper - { - - - /// - /// Change color alpha (0 is transparent, 1 is opaque). - /// - public static Color Alpha(this Color col, float alpha) - { - col.a = alpha; - return col; - } - - /// - /// Change lightness of the color. - /// - public static Color Lightness(this Color col, float lightness) - { - Color.RGBToHSV(col, out var hue, out var saturation, out var _); - return Color.HSVToRGB(hue, saturation, lightness); - } - - /// - /// Change image color alpha (0 is transparent, 1 is opaque). - /// - public static void Alpha(this Image image, float alpha) - { - Color color = image.color; - color.a = alpha; - image.color = color; - } - - /// - /// Set Sound Clip to the Audio Source. - /// - public static void SetSoundClip(this AudioSource audioSource, SoundClip soundClip, float volumeMul = 1f, bool play = false) - { - if (soundClip == null || soundClip.audioClip == null || audioSource == null) return; - - if (audioSource.clip != soundClip.audioClip) - audioSource.clip = soundClip.audioClip; - - audioSource.volume = soundClip.volume * volumeMul; - - if(play && !audioSource.isPlaying) - audioSource.Play(); - } - - /// - /// Play One Shot Sudio Clip in the audio source. - /// - public static void PlayOneShotSoundClip(this AudioSource audioSource, SoundClip soundClip, float volumeMul = 1f) - { - if (soundClip == null || soundClip.audioClip == null || audioSource == null) - return; - - audioSource.PlayOneShot(soundClip.audioClip, soundClip.volume * volumeMul); - } - - /// - /// Create new unique Guid. - /// - public static string GetGuid() => System.Guid.NewGuid().ToString("N"); - - /// - /// Change the GameObject layer including all children. - /// - public static void SetLayerRecursively(this GameObject obj, int layer) - { - if (layer < 0 || layer > 31) - { - Debug.LogError("Invalid layer value. Must be between 0 and 31."); - return; - } - - obj.layer = layer; - - foreach (Transform child in obj.transform) - { - child.gameObject.SetLayerRecursively(layer); - } - } - - /// - /// Set the rendering layer of the MeshRenderer in the GameObject. - /// - public static void SetRenderingLayer(this GameObject obj, uint layer, bool set = true) - { - if (layer < 0 || layer > 31) - { - Debug.LogError("Invalid layer value. Must be between 0 and 31."); - return; - } - - uint layerMask = 1u << (int)layer; - - foreach (MeshRenderer renderer in obj.GetComponentsInChildren()) - { - if (set) renderer.renderingLayerMask |= layerMask; - else renderer.renderingLayerMask &= ~layerMask; - } - } - - /// - /// Basic raycast with interact layer checking. - /// - /// Status whether the object hit by the raycast has an interact layer. - public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int cullLayers, Layer interactLayer) - { - if (Physics.Raycast(ray, out RaycastHit hit, maxDistance, cullLayers)) - { - if (interactLayer.CompareLayer(hit.collider.gameObject)) - { - hitInfo = hit; - return true; - } - } - - hitInfo = default; - return false; - } - - /// - /// Check if the value-A and value-B are close to the tolerance. - /// - public static bool IsApproximate(float valueA, float valueB, float tollerance) - { - return Mathf.Abs(valueA - valueB) < tollerance; - } - - /// - /// Correct the Angle. - /// - public static float FixAngle(this float angle, float min, float max) - { - if (angle < min) - angle += 360F; - if (angle > max) - angle -= 360F; - - return angle; - } - - /// - /// Correct the Angle (-180, 180). - /// - public static float FixAngle180(this float angle) - { - if (angle < -180F) - angle += 360F; - if (angle > 180F) - angle -= 360F; - - return angle; - } - - /// - /// Correct the Angle (-360, 360). - /// - public static float FixAngle(this float angle) - { - if (angle < -360F) - angle += 360F; - if (angle > 360F) - angle -= 360F; - - return angle; - } - - /// - /// Correct the Angle (0 - 360). - /// - public static float FixAngle360(this float angle) - { - if (angle < 0) - angle += 360F; - if (angle > 360F) - angle -= 360F; - - return angle; - } - - /// - /// Check if value is in vector range. - /// - public static bool InRange(this Vector2 vector, float value, bool equal = false) - { - return equal ? value >= vector.x && value <= vector.y : - value > vector.x && value < vector.y; - } - - /// - /// Check if value is in vector degrees. - /// - public static bool InDegrees(this Vector2 vector, float value, bool equal = false) - { - if(vector.x > vector.y) - { - return equal ? value >= (vector.x - 360) && value <= vector.y : - value > (vector.x - 360) && value < vector.y; - } - else - { - return equal ? value >= vector.x && value <= vector.y : - value > vector.x && value < vector.y; - } - } - - /// - /// Convert string to title case. - /// - public static string ToTitleCase(this string str) - { - return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower()); - } - - /// - /// Check if string is empty. - /// - public static bool IsEmpty(this string str) - { - return string.IsNullOrEmpty(str); - } - - /// - /// Returns a string or otherwise if the string is empty. - /// - public static string Or(this string str, string otherwise) - { - return !string.IsNullOrEmpty(str) ? str : otherwise; - } - - /// - /// Compare Layer with LayerMask. - /// - public static bool CompareLayer(this LayerMask layermask, int layer) - { - return layermask == (layermask | (1 << layer)); - } - - /// - /// Function to generate a random integer number (No Duplicates). - /// - public static int RandomUnique(int min, int max, int last) - { - System.Random rnd = new System.Random(); - - if (min + 1 < max) - { - return Enumerable.Range(min, max).OrderBy(x => rnd.Next()).Where(x => x != last).Take(1).Single(); - } - else - { - return min; - } - } - - /// - /// Function to generate a random integer without excluded numbers. - /// - public static int RandomExclude(int min, int max, int[] ex, int maxIterations = 1000) - { - int result; - int iterations = 0; - - do - { - if (iterations > maxIterations) - { - result = -1; - break; - } - - result = UnityEngine.Random.Range(min, max); - iterations++; - } - while (ex.Contains(result)); - - return result; - } - - /// - /// Function to generate a random unique integer without excluded numbers. - /// - public static int RandomExcludeUnique(int min, int max, int[] ex, int[] current, int maxIterations = 1000) - { - return RandomExclude(min, max, ex.Concat(current).ToArray(), maxIterations); - } - - /// - /// Pick a random element from item array. - /// - public static T Random(this T[] items) - { - System.Random rnd = new System.Random(); - if(items.Length > 0) return items[rnd.Next(0, items.Length)]; - return default; - } - - /// - /// Get Random Value from Min/Max vector. - /// - public static float Random(this Vector2 vector) - { - return UnityEngine.Random.Range(vector.x, vector.y); - } - - /// - /// Get Random Value from Min/Max structure. - /// - public static float Random(this MinMax minMax) - { - return UnityEngine.Random.Range(minMax.RealMin, minMax.RealMax); - } - - /// - /// Get Random Value from Min/Max structure. - /// - public static int Random(this MinMaxInt minMax) - { - return UnityEngine.Random.Range(minMax.RealMin, minMax.RealMax); - } - - /// - /// Oscillate between the two values at speed. - /// - public static float PingPong(float min, float max, float speed = 1f) - { - return Mathf.PingPong(Time.time * speed, max - min) + min; - } - - /// - /// Wrap value between min and max values. - /// - public static int Wrap(int value, int min, int max) - { - int newValue = value % max; - if (newValue < min) newValue = max - 1; - return newValue; - } - - /// - /// Determines where a value lies between three points. - /// - public static float InverseLerp3(float min, float mid, float max, float t) - { - if (t <= min) return 0f; - if (t >= max) return 0f; - - if (t <= mid) return Mathf.InverseLerp(min, mid, t); - else return 1f - Mathf.InverseLerp(mid, max, t); - } - - /// - /// Get closest index from an integer array using a value. - /// - public static int ClosestIndex(this int[] array, int value) - { - int closestIndex = 0; - int minDifference = Mathf.Abs(array[0] - value); - - for (int i = 1; i < array.Length; i++) - { - int difference = Mathf.Abs(array[i] - value); - if (difference < minDifference) - { - minDifference = difference; - closestIndex = i; - } - } - - return closestIndex; - } - - /// - /// Play OneShot Audio Clip 2D. - /// - public static AudioSource PlayOneShot2D(Vector3 position, AudioClip clip, float volume = 1f, string name = "OneShotAudio") - { - if(clip == null) - return null; - - GameObject go = new GameObject(name); - go.transform.position = position; - AudioSource source = go.AddComponent(); - source.spatialBlend = 0f; - source.clip = clip; - source.volume = volume; - source.Play(); - Object.Destroy(go, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); - return source; - } - - /// - /// Play OneShot Sound Clip 3D. - /// - public static AudioSource PlayOneShot2D(Vector3 position, SoundClip clip, string name = "OneShotAudio") - { - if (clip == null || clip.audioClip == null) - return null; - - AudioClip audioClip = clip.audioClip; - float volume = clip.volume; - return PlayOneShot2D(position, audioClip, volume, name); - } - - /// - /// Play OneShot Audio Clip 3D. - /// - public static AudioSource PlayOneShot3D(Vector3 position, AudioClip clip, float volume = 1f, string name = "OneShotAudio") - { - if (clip == null) - return null; - - GameObject go = new GameObject(name); - go.transform.position = position; - AudioSource source = go.AddComponent(); - source.spatialBlend = 1f; - source.clip = clip; - source.volume = volume; - source.Play(); - Object.Destroy(go, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); - return source; - } - - /// - /// Play OneShot Audio Clip 3D. - /// - public static AudioSource PlayOneShot3D(Vector3 position, AudioClip clip, float maxDistance, float volume = 1f, string name = "OneShotAudio") - { - if (clip == null) - return null; - - GameObject go = new GameObject(name); - go.transform.position = position; - AudioSource source = go.AddComponent(); - source.spatialBlend = 1f; - source.clip = clip; - source.volume = volume; - source.maxDistance = maxDistance; - source.Play(); - Object.Destroy(go, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); - return source; - } - - /// - /// Play OneShot Sound Clip 3D. - /// - public static AudioSource PlayOneShot3D(Vector3 position, SoundClip clip, string name = "OneShotAudio") - { - if (clip == null || clip.audioClip == null) - return null; - - AudioClip audioClip = clip.audioClip; - float volume = clip.volume; - return PlayOneShot3D(position, audioClip, volume, name); - } - - /// - /// Remap range A to range B. - /// - public static float Remap(float minA, float maxA, float minB, float maxB, float t) - { - return minB + (t - minA) * (maxB - minB) / (maxA - minA); - } - - /// - /// Replace string part inside two chars - /// - public static string ReplacePart(this string str, char start, char end, string replace) - { - int chStart = str.IndexOf(start); - int chEnd = str.IndexOf(end); - string old = str.Substring(chStart, chEnd - chStart + 1); - return str.Replace(old, replace); - } - - /// - /// Replace tag inside two chars (Regex). - /// - public static string RegexReplaceTag(this string str, char start, char end, string tag, string replace) - { - Regex regex = new Regex($@"\{start}({tag})\{end}"); - if(regex.Match(str).Success) - return regex.Replace(str, replace); - - return str; - } - - /// - /// Get a value between two chars (Regex). - /// - public static bool RegexGet(this string str, char start, char end, out string result) - { - // escaping special characters if necessary - string escapedStart = Regex.Escape(start.ToString()); - string escapedEnd = Regex.Escape(end.ToString()); - - // regex pattern to match text between 'start' and 'end' characters - string pattern = $"{escapedStart}(.*?){escapedEnd}"; - - Match match = Regex.Match(str, pattern); - if (match.Success) - { - result = match.Groups[1].Value; - return true; - } - - result = string.Empty; - return false; - } - - /// - /// Get all values between two chars (Regex). - /// - public static bool RegexGetMany(this string str, char start, char end, out string[] results) - { - // escaping special characters if necessary - string escapedStart = Regex.Escape(start.ToString()); - string escapedEnd = Regex.Escape(end.ToString()); - - // regex pattern to match text between 'start' and 'end' characters - string pattern = $"{escapedStart}(.*?){escapedEnd}"; - - // using Regex.Matches to find all matches - MatchCollection matches = Regex.Matches(str, pattern); - - // check if there are any matches - if (matches.Count > 0) - { - // initialize a list to hold the results - List matchList = new List(); - - foreach (Match match in matches) - { - // add each found match to the list, excluding the 'start' and 'end' characters - matchList.Add(match.Groups[1].Value); - } - - // convert the list to an array and assign to 'results' - results = matchList.ToArray(); - return true; - } - - results = new string[0]; - return false; - } - - /// - /// Replace a word in string (Regex). - /// - public static string RegexReplace(this string str, string word, string replace) - { - string escapedWord = Regex.Escape(word); - string pattern = $@"\b{escapedWord}\b"; - - // replace the word with the provided replacement text - return Regex.Replace(str, pattern, replace); - } - - /// - /// Check if any animator state is being played. - /// - public static bool IsAnyPlaying(this Animator animator) - { - AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); - return (stateInfo.length + 0.1f > stateInfo.normalizedTime || animator.IsInTransition(0)) && !stateInfo.IsName("Default"); - } - - /// - /// Applies an ease-out easing function, which starts the interpolation quickly and then slows down as it approaches the end point. - /// - public static float EaseOut(float start, float end, float t) - { - t = Mathf.Clamp01(t); - t = Mathf.Sin(t * Mathf.PI * 0.5f); - return Mathf.Lerp(start, end, t); - } - - /// - /// Applies an ease-in easing function, which starts the interpolation slowly and then accelerates as it approaches the end point. - /// - public static float EaseIn(float start, float end, float t) - { - t = Mathf.Clamp01(t); - t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f); - return Mathf.Lerp(start, end, t); - } - - /// - /// Implements a smooth step interpolation, offering a more gradual and smoother transition. - /// - /// - /// Use this when you want an even gentler and smoother transition, especially for animations. - /// - public static float SmootherStep(float start, float end, float t) - { - t = Mathf.Clamp01(t); - t = t * t * t * (t * (6f * t - 15f) + 10f); - return Mathf.Lerp(start, end, t); - } - } - - public static class GizmosE - { - /// - /// Draw arrow using gizmos. - /// - public static void DrawGizmosArrow(Vector3 pos, Vector3 direction, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20.0f) - { - Gizmos.DrawRay(pos, direction); - - Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * new Vector3(0, 0, 1); - Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * new Vector3(0, 0, 1); - Gizmos.DrawRay(pos + direction, right * arrowHeadLength); - Gizmos.DrawRay(pos + direction, left * arrowHeadLength); - } - - /// - /// Draw wire capsule. - /// - public static void DrawWireCapsule(Vector3 p1, Vector3 p2, float radius) - { -#if UNITY_EDITOR - // Special case when both points are in the same position - if (p1 == p2) - { - // DrawWireSphere works only in gizmo methods - Gizmos.DrawWireSphere(p1, radius); - return; - } - using (new Handles.DrawingScope(Gizmos.color, Gizmos.matrix)) - { - Quaternion p1Rotation = Quaternion.LookRotation(p1 - p2); - Quaternion p2Rotation = Quaternion.LookRotation(p2 - p1); - - // Check if capsule direction is collinear to Vector.up - float c = Vector3.Dot((p1 - p2).normalized, Vector3.up); - if (c == 1f || c == -1f) - { - // Fix rotation - p2Rotation = Quaternion.Euler(p2Rotation.eulerAngles.x, p2Rotation.eulerAngles.y + 180f, p2Rotation.eulerAngles.z); - } - - // First side - Handles.DrawWireArc(p1, p1Rotation * Vector3.left, p1Rotation * Vector3.down, 180f, radius); - Handles.DrawWireArc(p1, p1Rotation * Vector3.up, p1Rotation * Vector3.left, 180f, radius); - Handles.DrawWireDisc(p1, (p2 - p1).normalized, radius); - // Second side - Handles.DrawWireArc(p2, p2Rotation * Vector3.left, p2Rotation * Vector3.down, 180f, radius); - Handles.DrawWireArc(p2, p2Rotation * Vector3.up, p2Rotation * Vector3.left, 180f, radius); - Handles.DrawWireDisc(p2, (p1 - p2).normalized, radius); - // Lines - Handles.DrawLine(p1 + p1Rotation * Vector3.down * radius, p2 + p2Rotation * Vector3.down * radius); - Handles.DrawLine(p1 + p1Rotation * Vector3.left * radius, p2 + p2Rotation * Vector3.right * radius); - Handles.DrawLine(p1 + p1Rotation * Vector3.up * radius, p2 + p2Rotation * Vector3.up * radius); - Handles.DrawLine(p1 + p1Rotation * Vector3.right * radius, p2 + p2Rotation * Vector3.left * radius); - } -#endif - } - - /// - /// Draw wire capsule. - /// - public static void DrawWireCapsule(Vector3 position, Quaternion rotation, float radius, float height) - { -#if UNITY_EDITOR - Matrix4x4 angleMatrix = Matrix4x4.TRS(position, rotation, Handles.matrix.lossyScale); - using (new Handles.DrawingScope(angleMatrix)) - { - var pointOffset = (height - (radius * 2)) / 2; - - //draw sideways - Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.left, Vector3.back, -180, radius); - Handles.DrawLine(new Vector3(0, pointOffset, -radius), new Vector3(0, -pointOffset, -radius)); - Handles.DrawLine(new Vector3(0, pointOffset, radius), new Vector3(0, -pointOffset, radius)); - Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.left, Vector3.back, 180, radius); - //draw frontways - Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.back, Vector3.left, 180, radius); - Handles.DrawLine(new Vector3(-radius, pointOffset, 0), new Vector3(-radius, -pointOffset, 0)); - Handles.DrawLine(new Vector3(radius, pointOffset, 0), new Vector3(radius, -pointOffset, 0)); - Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.back, Vector3.left, -180, radius); - //draw center - Handles.DrawWireDisc(Vector3.up * pointOffset, Vector3.up, radius); - Handles.DrawWireDisc(Vector3.down * pointOffset, Vector3.up, radius); - - } -#endif - } - - /// - /// Draw the label aligned to the center of the position. - /// - public static void DrawCenteredLabel(Vector3 position, string labelText, GUIStyle style = null) - { -#if UNITY_EDITOR - if (style == null) style = new GUIStyle(GUI.skin.label); - - GUIContent content = new GUIContent(labelText); - Vector2 labelSize = style.CalcSize(content); - - // Calculate the offset to center the label - Vector3 screenPosition = HandleUtility.WorldToGUIPoint(position); - screenPosition.x -= labelSize.x / 2; - screenPosition.y -= labelSize.y / 2; - Vector3 worldPosition = HandleUtility.GUIPointToWorldRay(screenPosition).origin; - - Handles.Label(worldPosition, labelText, style); -#endif - } - - /// - /// Draw disc at the position. - /// - public static void DrawDisc(Vector3 position, float radius, Color outerColor, Color innerColor) - { -#if UNITY_EDITOR - Handles.color = innerColor; - Handles.DrawSolidDisc(position, Vector3.up, radius); - Handles.color = outerColor; - Handles.DrawWireDisc(position, Vector3.up, radius); -#endif - } - } - - public static class VectorE - { - /// - /// Determines where a value lies between two vectors. - /// - public static float InverseLerp(Vector3 a, Vector3 b, Vector3 value) - { - if (a != b) - { - Vector3 AB = b - a; - Vector3 AV = value - a; - float t = Vector3.Dot(AV, AB) / Vector3.Dot(AB, AB); - return Mathf.Clamp01(t); - } - - return 0f; - } - - /// - /// Get position in Quadratic Bezier Curve. - /// - /// Starting point - /// Ending point - /// Control point - public static Vector3 QuadraticBezier(Vector3 p1, Vector3 p2, Vector3 cp, float t) - { - t = Mathf.Clamp01(t); - Vector3 m1 = Vector3.LerpUnclamped(p1, cp, t); - Vector3 m2 = Vector3.LerpUnclamped(cp, p2, t); - return Vector3.LerpUnclamped(m1, m2, t); - } - - /// - /// Bezier Curve between multiple points. - /// - public static Vector3 BezierCurve(float t, params Vector3[] points) - { - if (points.Length < 1) return Vector3.zero; - else if (points.Length == 1) return points[0]; - - t = Mathf.Clamp01(t); - Vector3[] cp = points; - int n = points.Length - 1; - - while (n > 1) - { - Vector3[] rp = new Vector3[n]; - for (int i = 0; i < rp.Length; i++) - { - rp[i] = Vector3.LerpUnclamped(cp[i], cp[i + 1], t); - } - - cp = rp; - n--; - } - - return Vector3.LerpUnclamped(cp[0], cp[1], t); - } - - /// - /// Linearly interpolates between three points. - /// - public static Vector3 Lerp3(Vector3 a, Vector3 b, Vector3 c, float t) - { - t = Mathf.Clamp01(t); - if (t <= 0.5f) return Vector3.LerpUnclamped(a, b, t * 2f); - return Vector3.LerpUnclamped(b, c, (t * 2f) - 1f); - } - - /// - /// Linearly interpolates between multiple points. - /// - public static Vector3 RangeLerp(float t, params Vector3[] points) - { - if (points.Length < 1) return Vector3.zero; - else if (points.Length == 1) return points[0]; - - t = Mathf.Clamp01(t); - int pointsCount = points.Length - 1; - float scale = 1f / pointsCount; - float remap = GameHelper.Remap(0, 1, 0, pointsCount, t); - int index = Mathf.Clamp(Mathf.FloorToInt(remap), 0, pointsCount - 1); - float indexT = Mathf.InverseLerp(index * scale, (index + 1) * scale, t); - return Vector3.LerpUnclamped(points[index], points[index + 1], indexT); - } - - /// - /// Linearly interpolates between two, three or multiple points. - ///
The function selects the best method for linear interpolation.
- ///
- public static Vector3 Lerp(float t, Vector3[] points) - { - if (points.Length > 3) - { - return RangeLerp(t, points); - } - else if (points.Length == 3) - { - return Lerp3(points[0], points[1], points[2], t); - } - else if (points.Length == 2) - { - return Vector3.Lerp(points[0], points[1], t); - } - else if (points.Length == 1) - { - return points[0]; - } - - return Vector3.zero; - } - - /// - /// Scale a vector by another vector and return the scaled vector. - /// - public static Vector3 Multiply(this Vector3 lhs, Vector3 rhs) - { - lhs.Scale(rhs); - return lhs; - } - - /// - /// Checks if a collection contains all values from another collection. - /// - public static bool ContainsAll(this IEnumerable source, IEnumerable values) - { - return !source.Except(values).Any(); - } - } - - public static class AxisE - { - /// - /// Convert Axis to Vector3 Direction. - /// - public static Vector3 Convert(this Axis axis) => axis switch - { - Axis.X => Vector3.right, - Axis.X_Negative => Vector3.left, - Axis.Y => Vector3.up, - Axis.Y_Negative => Vector3.down, - Axis.Z => Vector3.forward, - Axis.Z_Negative => Vector3.back, - _ => Vector3.up, - }; - - /// - /// Convert Axis to Transform Direction. - /// - public static Vector3 Direction(this Transform transform, Axis axis) - { - return axis switch - { - Axis.X => transform.right, - Axis.X_Negative => -transform.right, - Axis.Y => transform.up, - Axis.Y_Negative => -transform.up, - Axis.Z => transform.forward, - Axis.Z_Negative => -transform.forward, - _ => transform.up, - }; - } - - /// - /// Get Vector Axis Component. - /// - public static float Component(this Vector3 vector, Axis axis) - { - return axis switch - { - Axis.X or Axis.X_Negative => vector.x, - Axis.Y or Axis.Y_Negative => vector.y, - Axis.Z or Axis.Z_Negative => vector.z, - _ => vector.y, - }; - } - - /// - /// Set Vector Axis Component Value. - /// - public static Vector3 SetComponent(this Vector3 vector, Axis axis, float value) - { - switch (axis) - { - case Axis.X: - case Axis.X_Negative: - vector.x = value; break; - case Axis.Y: - case Axis.Y_Negative: - vector.y = value; break; - case Axis.Z: - case Axis.Z_Negative: - vector.z = value; break; - } - return vector; - } - - /// - /// Clamp Vector Axis to Range. - /// - public static Vector3 Clamp(this Vector3 vector, Axis axis, MinMax limits) - { - switch (axis) - { - case Axis.X: - case Axis.X_Negative: - vector.x = Mathf.Clamp(vector.x, limits.RealMin, limits.RealMax); break; - case Axis.Y: - case Axis.Y_Negative: - vector.y = Mathf.Clamp(vector.y, limits.RealMin, limits.RealMax); break; - case Axis.Z: - case Axis.Z_Negative: - vector.z = Mathf.Clamp(vector.z, limits.RealMin, limits.RealMax); break; - } - return vector; - } - } - - public static class RectTransformE - { - public static void SetWidth(this RectTransform rectTransform, float width) - { - Vector2 size = rectTransform.sizeDelta; - size.x = width; - rectTransform.sizeDelta = size; - } - - public static void SetHeight(this RectTransform rectTransform, float height) - { - Vector2 size = rectTransform.sizeDelta; - size.y = height; - rectTransform.sizeDelta = size; - } - - public static void SetAnchoredX(this RectTransform rectTransform, float x) - { - Vector2 position = rectTransform.anchoredPosition; - position.x = x; - rectTransform.anchoredPosition = position; - } - - public static void SetAnchoredY(this RectTransform rectTransform, float y) - { - Vector2 position = rectTransform.anchoredPosition; - position.y = y; - rectTransform.anchoredPosition = position; - } - - public static IEnumerable GetChildTransforms(this RectTransform rectTransform) - { - foreach (var item in rectTransform) - { - yield return item as RectTransform; - } - } - } - - public struct Pair - { - public T1 Key { get; set; } - public T2 Value { get; set; } - public bool IsAssigned - { - get => Key != null && Value != null; - } - - public Pair(T1 key, T2 value) - { - Key = key; - Value = value; - } - } -} diff --git a/Runtime/ABase/Helper/GameHelper.cs.meta b/Runtime/ABase/Helper/GameHelper.cs.meta deleted file mode 100644 index 6bea2c8..0000000 --- a/Runtime/ABase/Helper/GameHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: ef59646f457548b0962c49a3434cf7e3 -timeCreated: 1758265544 \ No newline at end of file diff --git a/Runtime/ABase/Helper/PositionHelper.cs b/Runtime/ABase/Helper/PositionHelper.cs deleted file mode 100644 index 7153975..0000000 --- a/Runtime/ABase/Helper/PositionHelper.cs +++ /dev/null @@ -1,150 +0,0 @@ -using UnityEngine; - -namespace AlicizaX -{ - /// - /// 坐标帮助类 - /// - public static class PositionHelper - { - public static Vector3 RayCastV2ToV3(Vector2 pos) - { - return new Vector3(pos.x, 0, pos.y); - } - - public static Vector3 RayCastXYToV3(float x, float y) - { - return new Vector3(x, 0, y); - } - - public static Vector3 RayCastV3ToV3(Vector3 pos) - { - return new Vector3(pos.x, 0, pos.z); - } - - public static Quaternion AngleToQuaternion(int angle) - { - return Quaternion.AngleAxis(-angle, Vector3.up) * Quaternion.AngleAxis(90, Vector3.up); - } - - public static Quaternion GetVector3ToQuaternion(Vector3 source, Vector3 dire) - { - Vector3 nowPos = source; - if (nowPos == dire) - { - return new Quaternion(); - } - - Vector3 direction = (dire - nowPos).normalized; - return Quaternion.LookRotation(direction, Vector3.up); - } - - - public static float Distance2D(Vector3 v1, Vector3 v2) - { - Vector2 d1 = new Vector2(v1.x, v1.z); - Vector2 d2 = new Vector2(v2.x, v2.z); - return Vector2.Distance(d1, d2); - } - - public static Quaternion GetAngleToQuaternion(float angle) - { - return Quaternion.AngleAxis(-angle, Vector3.up) * Quaternion.AngleAxis(90, Vector3.up); - } - - public static float Vector3ToAngle360(Vector3 from, Vector3 to) - { - float angle = Vector3.Angle(from, to); - Vector3 cross = Vector3.Cross(from, to); - return cross.y > 0 ? angle : 360 - angle; - } - - /// - /// 求点到直线的距离,采用数学公式Ax+By+C = 0; d = A*p.x + B * p.y + C / sqrt(A^2 + B ^ 2) - /// - /// 线的起点 - /// 线的终点 - /// 点 - /// - public static float DistanceOfPointToVector(Vector3 startPoint, Vector3 endPoint, Vector3 point) - { - Vector2 startVe2 = startPoint.IgnoreYAxis(); - Vector2 endVe2 = endPoint.IgnoreYAxis(); - float A = endVe2.y - startVe2.y; - float B = startVe2.x - endVe2.x; - float C = endVe2.x * startVe2.y - startVe2.x * endVe2.y; - float denominator = Mathf.Sqrt(A * A + B * B); - Vector2 pointVe2 = point.IgnoreYAxis(); - return Mathf.Abs((A * pointVe2.x + B * pointVe2.y + C) / denominator); - ; - } - - /// - /// 判断射线是否碰撞到球体,如果碰撞到,返回射线起点到碰撞点之间的距离 - /// - /// 射线 - /// 中心点 - /// 半径 - /// 距离 - /// - public static bool RayCastSphere(Ray ray, Vector3 center, float redis, out float dist) - { - dist = 0; - Vector3 ma = center - ray.origin; - float distance = Vector3.Cross(ma, ray.direction).magnitude / ray.direction.magnitude; - if (distance < redis) - { - float op = PythagoreanTheorem(Vector3.Distance(center, ray.origin), distance); - float rp = PythagoreanTheorem(redis, distance); - dist = op - rp; - return true; - } - - return false; - } - - /// - /// 勾股定理 - /// - /// - /// - /// - public static float PythagoreanTheorem(float x, float y) - { - return Mathf.Sqrt(x * x + y * y); - } - - /// - /// 去掉三维向量的Y轴,把向量投射到xz平面。 - /// - /// - /// - public static Vector2 IgnoreYAxis(this Vector3 vector3) - { - return new Vector2(vector3.x, vector3.z); - } - - /// - /// 判断目标点是否位于向量的左边 - /// - /// True is on left, false is on right - public static bool PointOnLeftSideOfVector(this Vector3 vector3, Vector3 originPoint, Vector3 point) - { - Vector2 originVec2 = originPoint.IgnoreYAxis(); - - Vector2 pointVec2 = (point.IgnoreYAxis() - originVec2).normalized; - - Vector2 vector2 = vector3.IgnoreYAxis(); - - float verticalX = originVec2.x; - - float verticalY = (-verticalX * vector2.x) / vector2.y; - - Vector2 norVertical = (new Vector2(verticalX, verticalY)).normalized; - - float dotValue = Vector2.Dot(norVertical, pointVec2); - - return dotValue < 0f; - } - } -} diff --git a/Runtime/ABase/Helper/PositionHelper.cs.meta b/Runtime/ABase/Helper/PositionHelper.cs.meta deleted file mode 100644 index a0eb9de..0000000 --- a/Runtime/ABase/Helper/PositionHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: fb356e4ecfd547b280b88ca74a847918 -timeCreated: 1666447289 \ No newline at end of file diff --git a/Runtime/ABase/Helper/TimerHelper.cs b/Runtime/ABase/Helper/TimerHelper.cs deleted file mode 100644 index 42b4a98..0000000 --- a/Runtime/ABase/Helper/TimerHelper.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; - -namespace AlicizaX -{ - /// - /// 游戏时间帮助类 - /// - public static class TimerHelper - { - private static readonly DateTime EpochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - private static readonly long Epoch = EpochTime.Ticks; - - /// - /// 时间差 - /// - private static long _differenceTime; - - private static bool _isSecLevel = true; - - /// - /// 微秒 - /// - public const long TicksPerMicrosecond = 1; //100微秒 - - /// - /// 10微秒 - /// - public const long TicksPer = 10 * TicksPerMicrosecond; - - /// - /// 1毫秒 - /// - public const long TicksMillisecondUnit = TicksPer * 1000; //毫秒 - - /// - /// 1秒 - /// - public const long TicksSecondUnit = TicksMillisecondUnit * 1000; // 秒 //10000000 - - /// - /// 设置时间差 - /// - /// - [UnityEngine.Scripting.Preserve] - public static void SetDifferenceTime(long timeSpan) - { - if (timeSpan > 1000000000000) - { - _isSecLevel = false; - } - else - { - _isSecLevel = true; - } - - if (_isSecLevel) - { - _differenceTime = timeSpan - ClientNow(); - } - else - { - _differenceTime = timeSpan - ClientNowMillisecond(); - } - } - - /// - /// 毫秒级 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long ClientNowMillisecond() - { - return (DateTime.UtcNow.Ticks - Epoch) / TicksMillisecondUnit; - } - - [UnityEngine.Scripting.Preserve] - public static long ServerToday() - { - if (_isSecLevel) - { - return _differenceTime + ClientToday(); - } - - return (_differenceTime + ClientTodayMillisecond()) / 1000; - } - - [UnityEngine.Scripting.Preserve] - public static long ClientTodayMillisecond() - { - return (DateTime.Now.Date.ToUniversalTime().Ticks - Epoch) / 10000; - } - - /// - /// 服务器当前时间 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long ServerNow() //秒级 - { - if (_isSecLevel) - { - return _differenceTime + ClientNow(); - } - - return (_differenceTime + ClientNowMillisecond()) / 1000; - } - - /// - /// 将秒数转换成TimeSpan - /// - /// 秒 - /// - [UnityEngine.Scripting.Preserve] - public static TimeSpan FromSeconds(int seconds) - { - return TimeSpan.FromSeconds(seconds); - } - - /// - /// 今天的客户端时间 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long ClientToday() - { - return (DateTime.Now.Date.ToUniversalTime().Ticks - Epoch) / TicksSecondUnit; - } - - /// - /// 客户端时间,毫秒 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long ClientNow() - { - return (DateTime.UtcNow.Ticks - Epoch) / 10000; - } - - /// - /// 客户端时间。秒 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long ClientNowSeconds() - { - return (DateTime.UtcNow.Ticks - Epoch) / 10000000; - } - - /// - /// 客户端时间 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long Now() - { - return ClientNow(); - } - - /// - /// UTC时间 秒 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long UnixTimeSeconds() - { - return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds(); - } - - /// - /// UTC时间 毫秒 - /// - /// - [UnityEngine.Scripting.Preserve] - public static long UnixTimeMilliseconds() - { - return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds(); - } - - - /// - /// 按照UTC时间判断两个时间戳是否是同一天 - /// - /// 时间戳1 - /// 时间戳2 - /// 是否是同一天 - [UnityEngine.Scripting.Preserve] - public static bool IsUnixSameDay(long timestamp1, long timestamp2) - { - var time1 = UtcToUtcDateTime(timestamp1); - var time2 = UtcToUtcDateTime(timestamp2); - return time1.Date.Year == time2.Date.Year && time1.Date.Month == time2.Date.Month && time1.Date.Day == time2.Date.Day; - } - - /// - /// 按照本地时间判断两个时间戳是否是同一天 - /// - /// 时间戳1 - /// 时间戳2 - /// 是否是同一天 - [UnityEngine.Scripting.Preserve] - public static bool IsLocalSameDay(long timestamp1, long timestamp2) - { - var time1 = UtcToLocalDateTime(timestamp1); - var time2 = UtcToLocalDateTime(timestamp2); - return time1.Date.Year == time2.Date.Year && time1.Date.Month == time2.Date.Month && time1.Date.Day == time2.Date.Day; - } - - /// - /// UTC 时间戳 转换成UTC时间 - /// - /// UTC时间戳,单位秒 - /// - [UnityEngine.Scripting.Preserve] - public static DateTime UtcToUtcDateTime(long utcTimestamp) - { - return DateTimeOffset.FromUnixTimeSeconds(utcTimestamp).UtcDateTime; - } - - /// - /// UTC 时间戳 转换成本地时间 - /// - /// UTC时间戳,单位秒 - /// - [UnityEngine.Scripting.Preserve] - public static DateTime UtcToLocalDateTime(long utcTimestamp) - { - return DateTimeOffset.FromUnixTimeSeconds(utcTimestamp).LocalDateTime; - } - - /// - /// 判断两个时间是否是同一天 - /// - /// 时间1 - /// 时间2 - /// 是否是同一天 - [UnityEngine.Scripting.Preserve] - public static bool IsSameDay(DateTime time1, DateTime time2) - { - return time1.Date.Year == time2.Date.Year && time1.Date.Month == time2.Date.Month && time1.Date.Day == time2.Date.Day; - } - - /// - /// 指定时间转换成Unix时间戳的时间差,单位秒 - /// - /// 指定时间 - /// - [UnityEngine.Scripting.Preserve] - public static long LocalTimeToUnixTimeSeconds(DateTime time) - { - var utcDateTime = time.ToUniversalTime(); - return (long)(utcDateTime - EpochTime).TotalSeconds; - } - - /// - /// 指定时间转换成Unix时间戳的时间差,单位毫秒 - /// - /// 指定时间 - /// - [UnityEngine.Scripting.Preserve] - public static long LocalTimeToUnixTimeMilliseconds(DateTime time) - { - var utcDateTime = time.ToUniversalTime(); - return (long)(utcDateTime - EpochTime).TotalMilliseconds; - } - } -} diff --git a/Runtime/ABase/Helper/TimerHelper.cs.meta b/Runtime/ABase/Helper/TimerHelper.cs.meta deleted file mode 100644 index 4ccf0fb..0000000 --- a/Runtime/ABase/Helper/TimerHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 0d61562907c14a5295de01e78a41cd22 -timeCreated: 1666538474 \ No newline at end of file diff --git a/Runtime/ABase/Helper/UnityRendererHelper.cs b/Runtime/ABase/Helper/UnityRendererHelper.cs deleted file mode 100644 index 194ff2e..0000000 --- a/Runtime/ABase/Helper/UnityRendererHelper.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace AlicizaX -{ - /// - /// Unity 渲染帮助类 - /// - public static class UnityRendererHelper - { - /// - /// 判断渲染组件是否在相机范围内 - /// - /// 渲染组件 - /// 相机对象 - /// - public static bool IsVisibleFrom(Renderer renderer, Camera camera) - { - Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera); - return GeometryUtility.TestPlanesAABB(planes, renderer.bounds); - } - - /// - /// 判断渲染组件是否在相机范围内 - /// - /// 渲染对象 - /// 相机对象 - /// - public static bool IsVisibleFrom(MeshRenderer renderer, Camera camera) - { - Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera); - return GeometryUtility.TestPlanesAABB(planes, renderer.bounds); - } - - /// - /// 获取相机快照 - /// - /// 相机 - /// 缩放比 - public static Texture2D GetCaptureScreenshot(Camera main, float scale = 0.5f) - { - Rect rect = new Rect(0, 0, Screen.width * scale, Screen.height * scale); - string name = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"); - RenderTexture renderTexture = RenderTexture.GetTemporary((int)rect.width, (int)rect.height, 0); - renderTexture.name = SceneManager.GetActiveScene().name + "_" + renderTexture.width + "_" + renderTexture.height + "_" + name; - main.targetTexture = renderTexture; - main.Render(); - - RenderTexture.active = renderTexture; - Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false) - { - name = renderTexture.name - }; - screenShot.ReadPixels(rect, 0, 0); - screenShot.Apply(); - main.targetTexture = null; - RenderTexture.active = null; - RenderTexture.ReleaseTemporary(renderTexture); - return screenShot; - } - } -} diff --git a/Runtime/ABase/Helper/UnityRendererHelper.cs.meta b/Runtime/ABase/Helper/UnityRendererHelper.cs.meta deleted file mode 100644 index 6343692..0000000 --- a/Runtime/ABase/Helper/UnityRendererHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: f8cc8709b4b6495eab2f7dcba3529dcf -timeCreated: 1654011360 \ No newline at end of file diff --git a/Runtime/ABase/Helper/ZipHelper.cs b/Runtime/ABase/Helper/ZipHelper.cs deleted file mode 100644 index 339acc2..0000000 --- a/Runtime/ABase/Helper/ZipHelper.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System; -using System.IO; -using ICSharpCode.SharpZipLib.Checksums; -using ICSharpCode.SharpZipLib.Zip; -using ICSharpCode.SharpZipLib.Zip.Compression; -using UnityEngine; - -namespace AlicizaX -{ - /// - /// 压缩帮助类 - /// - [UnityEngine.Scripting.Preserve] - public static class ZipHelper - { - private static readonly Crc32 CRC = new Crc32(); - - /// - /// 压缩文件夹 - /// - /// 要压缩的文件夹路径 - /// 压缩前的Stream,方法执行后变为压缩完成后的文件 - /// 密码 - /// 是否成功 - [UnityEngine.Scripting.Preserve] - public static bool CompressDirectoryToStream(string folderToZip, Stream stream, string password = null) - { - return CompressDirectoryToZipStream(folderToZip, stream, password) != null; - } - - - /// - /// 压缩文件夹 - /// - /// 要压缩的文件夹路径 - /// 压缩前的Stream,方法执行后变为压缩完成后的文件 - /// 密码 - /// 是否压缩成功返回ZipOutputStream,否则返回null - [UnityEngine.Scripting.Preserve] - public static ZipOutputStream CompressDirectoryToZipStream(string folderToZip, Stream stream, string password = null) - { - if (!Directory.Exists(folderToZip)) - { - return null; - } - - ZipOutputStream zipStream = new ZipOutputStream(stream); - zipStream.SetLevel(6); - if (!string.IsNullOrEmpty(password)) - { - zipStream.Password = password; - } - - if (CompressDirectory(folderToZip, zipStream, "")) - { - zipStream.Finish(); - return zipStream; - } - - GC.Collect(1); - return null; - } - - /// - /// 递归压缩文件夹的内部方法 - /// - /// 要压缩的文件夹路径 - /// 压缩输出流 - /// 此文件夹的上级文件夹 - /// 是否成功 - [UnityEngine.Scripting.Preserve] - private static bool CompressDirectory(string folderToZip, ZipOutputStream zipStream, string parentFolderName) - { - //这段是创建空文件夹,注释掉可以去掉空文件夹(因为在写入文件的时候也会创建文件夹) - if (parentFolderName.IsNotNullOrWhiteSpace()) - { - var ent = new ZipEntry(parentFolderName + "/"); - zipStream.PutNextEntry(ent); - zipStream.Flush(); - } - - var files = Directory.GetFiles(folderToZip); - foreach (string file in files) - { - byte[] buffer = File.ReadAllBytes(file); - var path = Path.GetFileName(file); - if (parentFolderName.IsNotNullOrWhiteSpace()) - { - path = parentFolderName + Path.DirectorySeparatorChar + Path.GetFileName(file); - } - - var ent = new ZipEntry(path) - { - //ent.DateTime = File.GetLastWriteTime(file);//设置文件最后修改时间 - DateTime = DateTime.Now, - Size = buffer.Length, - }; - - CRC.Reset(); - CRC.Update(buffer); - - ent.Crc = CRC.Value; - zipStream.PutNextEntry(ent); - zipStream.Write(buffer, 0, buffer.Length); - } - - var folders = Directory.GetDirectories(folderToZip); - foreach (var folder in folders) - { - var folderName = folder.Substring(folder.LastIndexOf('\\') + 1); - - if (parentFolderName.IsNotNullOrWhiteSpace()) - { - folderName = parentFolderName + "\\" + folder.Substring(folder.LastIndexOf('\\') + 1); - } - - if (!CompressDirectory(folder, zipStream, folderName)) - { - return false; - } - } - - return true; - } - - /// - /// 压缩文件夹 - /// - /// 要压缩的文件夹路径 - /// 压缩文件完整路径 - /// 密码 - /// 是否成功 - [UnityEngine.Scripting.Preserve] - public static bool CompressDirectory(string folderToZip, string zipFile, string password = null) - { - if (folderToZip.EndsWithFast(Path.DirectorySeparatorChar.ToString()) || folderToZip.EndsWithFast("/")) - { - folderToZip = folderToZip.Substring(0, folderToZip.Length - 1); - } - - var zipStream = CompressDirectoryToZipStream(folderToZip, new FileStream(zipFile, FileMode.Create, FileAccess.Write, FileShare.Write), password); - if (zipStream == null) - { - return false; - } - - zipStream.Close(); - return true; - } - - /// - /// 压缩文件 - /// - /// 要压缩的文件全名 - /// 压缩后的文件名 - /// 密码 - /// 是否成功 - [UnityEngine.Scripting.Preserve] - public static bool CompressFile(string fileToZip, string zipFile, string password = null) - { - if (!File.Exists(fileToZip)) - { - return false; - } - - using (var readStream = File.OpenRead(fileToZip)) - { - byte[] buffer = new byte[readStream.Length]; - var read = readStream.Read(buffer, 0, buffer.Length); - using (var writeStream = File.Create(zipFile)) - { - var entry = new ZipEntry(Path.GetFileName(fileToZip)) - { - DateTime = DateTime.Now, - Size = readStream.Length - }; - CRC.Reset(); - CRC.Update(buffer); - entry.Crc = CRC.Value; - using (var zipStream = new ZipOutputStream(writeStream)) - { - if (!string.IsNullOrEmpty(password)) - { - zipStream.Password = password; - } - - zipStream.PutNextEntry(entry); - zipStream.SetLevel(Deflater.BEST_COMPRESSION); - zipStream.Write(buffer, 0, buffer.Length); - } - } - } - - GC.Collect(1); - - return true; - } - - /// - /// 解压功能(解压压缩文件到指定目录) - /// - /// 待解压的文件 - /// 指定解压目标目录 - /// 密码 - /// 是否成功 - [UnityEngine.Scripting.Preserve] - public static bool DecompressFile(string fileToUnZip, string zipFolder, string password = null) - { - if (!System.IO.File.Exists(fileToUnZip)) - { - return false; - } - - if (!Directory.Exists(zipFolder)) - { - Directory.CreateDirectory(zipFolder); - } - - if (!zipFolder.EndsWith("\\")) - { - zipFolder += "\\"; - } - - using (var zipStream = new ZipInputStream(System.IO.File.OpenRead(fileToUnZip))) - { - if (!string.IsNullOrEmpty(password)) - { - zipStream.Password = password; - } - - ZipEntry zipEntry = null; - while ((zipEntry = zipStream.GetNextEntry()) != null) - { - if (zipEntry.IsDirectory) - { - continue; - } - - if (string.IsNullOrEmpty(zipEntry.Name)) - { - continue; - } - - string fileName = zipFolder + zipEntry.Name.Replace('/', '\\'); - var index = zipEntry.Name.LastIndexOf('/'); - if (index != -1) - { - string path = zipFolder + zipEntry.Name.Substring(0, index).Replace('/', '\\'); - System.IO.Directory.CreateDirectory(path); - } - - var bytes = new byte[zipEntry.Size]; - var read = zipStream.Read(bytes, 0, bytes.Length); - System.IO.File.WriteAllBytes(fileName, bytes); - } - } - - GC.Collect(1); - return true; - } - - /// - /// 压缩 - /// - /// - /// - [UnityEngine.Scripting.Preserve] - public static byte[] Compress(byte[] content) - { - //return content; - Deflater compressor = new Deflater(); - compressor.SetLevel(Deflater.BEST_COMPRESSION); - - compressor.SetInput(content); - compressor.Finish(); - - using (MemoryStream bos = new MemoryStream(content.Length)) - { - var buf = new byte[4096]; - while (!compressor.IsFinished) - { - int n = compressor.Deflate(buf); - bos.Write(buf, 0, n); - } - - return bos.ToArray(); - } - } - - /// - /// 解压缩 - /// - /// - /// - [UnityEngine.Scripting.Preserve] - public static byte[] Decompress(byte[] content) - { - return Decompress(content, 0, content.Length); - } - - /// - /// 解压缩 - /// - /// - /// - /// - /// - [UnityEngine.Scripting.Preserve] - public static byte[] Decompress(byte[] content, int offset, int count) - { - //return content; - Inflater decompressor = new Inflater(); - decompressor.SetInput(content, offset, count); - using (MemoryStream bos = new MemoryStream(content.Length)) - { - var buf = new byte[4096]; - while (!decompressor.IsFinished) - { - int n = decompressor.Inflate(buf); - bos.Write(buf, 0, n); - } - - return bos.ToArray(); - } - } - } -} diff --git a/Runtime/ABase/Utility/Utility.Compression.Zip.cs b/Runtime/ABase/Utility/Utility.Compression.Zip.cs new file mode 100644 index 0000000..af1fbf7 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Compression.Zip.cs @@ -0,0 +1,240 @@ +using System; +using System.IO; +using ICSharpCode.SharpZipLib.Checksums; +using ICSharpCode.SharpZipLib.Zip; +using ICSharpCode.SharpZipLib.Zip.Compression; + +namespace AlicizaX +{ + public static partial class Utility + { + /// + /// Zip 压缩相关的实用函数。 + /// + public static class Zip + { + private static readonly Crc32 s_Crc32 = new Crc32(); + + public static bool CompressDirectoryToStream(string folderToZip, Stream stream, string password = null) + { + return CompressDirectoryToZipStream(folderToZip, stream, password) != null; + } + + public static ZipOutputStream CompressDirectoryToZipStream(string folderToZip, Stream stream, string password = null) + { + if (!Directory.Exists(folderToZip) || stream == null) + { + return null; + } + + ZipOutputStream zipStream = new ZipOutputStream(stream); + zipStream.SetLevel(6); + if (!string.IsNullOrEmpty(password)) + { + zipStream.Password = password; + } + + if (!CompressDirectoryInternal(folderToZip, zipStream, string.Empty)) + { + zipStream.Dispose(); + return null; + } + + zipStream.Finish(); + return zipStream; + } + + public static bool CompressDirectory(string folderToZip, string zipFile, string password = null) + { + if (string.IsNullOrEmpty(folderToZip) || string.IsNullOrEmpty(zipFile)) + { + return false; + } + + folderToZip = folderToZip.TrimEnd(System.IO.Path.DirectorySeparatorChar, '/'); + using (FileStream writeStream = new FileStream(zipFile, FileMode.Create, FileAccess.Write, FileShare.Write)) + { + return CompressDirectoryToZipStream(folderToZip, writeStream, password) != null; + } + } + + public static bool CompressFile(string fileToZip, string zipFile, string password = null) + { + if (!System.IO.File.Exists(fileToZip) || string.IsNullOrEmpty(zipFile)) + { + return false; + } + + byte[] buffer = System.IO.File.ReadAllBytes(fileToZip); + using (FileStream writeStream = System.IO.File.Create(zipFile)) + using (ZipOutputStream zipStream = new ZipOutputStream(writeStream)) + { + if (!string.IsNullOrEmpty(password)) + { + zipStream.Password = password; + } + + ZipEntry entry = new ZipEntry(System.IO.Path.GetFileName(fileToZip)) + { + DateTime = DateTime.Now, + Size = buffer.Length + }; + + s_Crc32.Reset(); + s_Crc32.Update(buffer); + entry.Crc = s_Crc32.Value; + + zipStream.PutNextEntry(entry); + zipStream.SetLevel(Deflater.BEST_COMPRESSION); + zipStream.Write(buffer, 0, buffer.Length); + } + + return true; + } + + public static bool DecompressFile(string fileToUnzip, string zipFolder, string password = null) + { + if (!System.IO.File.Exists(fileToUnzip) || string.IsNullOrEmpty(zipFolder)) + { + return false; + } + + Directory.CreateDirectory(zipFolder); + + using (ZipInputStream zipStream = new ZipInputStream(System.IO.File.OpenRead(fileToUnzip))) + { + if (!string.IsNullOrEmpty(password)) + { + zipStream.Password = password; + } + + ZipEntry zipEntry; + while ((zipEntry = zipStream.GetNextEntry()) != null) + { + if (zipEntry.IsDirectory || string.IsNullOrEmpty(zipEntry.Name)) + { + continue; + } + + string relativePath = zipEntry.Name.Replace('/', System.IO.Path.DirectorySeparatorChar); + string outputPath = System.IO.Path.Combine(zipFolder, relativePath); + string directory = System.IO.Path.GetDirectoryName(outputPath); + if (!string.IsNullOrEmpty(directory)) + { + Directory.CreateDirectory(directory); + } + + using (FileStream fileStream = System.IO.File.Create(outputPath)) + { + zipStream.CopyTo(fileStream); + } + } + } + + return true; + } + + public static byte[] Compress(byte[] content) + { + if (content == null) + { + return null; + } + + Deflater compressor = new Deflater(); + compressor.SetLevel(Deflater.BEST_COMPRESSION); + compressor.SetInput(content); + compressor.Finish(); + + using (MemoryStream output = new MemoryStream(content.Length)) + { + byte[] buffer = new byte[4096]; + while (!compressor.IsFinished) + { + int read = compressor.Deflate(buffer); + output.Write(buffer, 0, read); + } + + return output.ToArray(); + } + } + + public static byte[] Decompress(byte[] content) + { + return content == null ? null : Decompress(content, 0, content.Length); + } + + public static byte[] Decompress(byte[] content, int offset, int count) + { + if (content == null) + { + return null; + } + + Inflater decompressor = new Inflater(); + decompressor.SetInput(content, offset, count); + using (MemoryStream output = new MemoryStream(content.Length)) + { + byte[] buffer = new byte[4096]; + while (!decompressor.IsFinished) + { + int read = decompressor.Inflate(buffer); + output.Write(buffer, 0, read); + } + + return output.ToArray(); + } + } + + private static bool CompressDirectoryInternal(string folderToZip, ZipOutputStream zipStream, string parentFolderName) + { + if (!string.IsNullOrWhiteSpace(parentFolderName)) + { + ZipEntry entry = new ZipEntry(parentFolderName + "/"); + zipStream.PutNextEntry(entry); + zipStream.Flush(); + } + + string[] files = Directory.GetFiles(folderToZip); + foreach (string file in files) + { + byte[] buffer = System.IO.File.ReadAllBytes(file); + string path = System.IO.Path.GetFileName(file); + if (!string.IsNullOrWhiteSpace(parentFolderName)) + { + path = parentFolderName + System.IO.Path.DirectorySeparatorChar + System.IO.Path.GetFileName(file); + } + + ZipEntry entry = new ZipEntry(path) + { + DateTime = DateTime.Now, + Size = buffer.Length + }; + + s_Crc32.Reset(); + s_Crc32.Update(buffer); + entry.Crc = s_Crc32.Value; + zipStream.PutNextEntry(entry); + zipStream.Write(buffer, 0, buffer.Length); + } + + string[] folders = Directory.GetDirectories(folderToZip); + foreach (string folder in folders) + { + string folderName = System.IO.Path.GetFileName(folder); + if (!string.IsNullOrWhiteSpace(parentFolderName)) + { + folderName = parentFolderName + System.IO.Path.DirectorySeparatorChar + folderName; + } + + if (!CompressDirectoryInternal(folder, zipStream, folderName)) + { + return false; + } + } + + return true; + } + } + } +} diff --git a/Runtime/ABase/Helper/CompressionUtility.cs.meta b/Runtime/ABase/Utility/Utility.Compression.Zip.cs.meta similarity index 83% rename from Runtime/ABase/Helper/CompressionUtility.cs.meta rename to Runtime/ABase/Utility/Utility.Compression.Zip.cs.meta index 193ed8a..65f50e7 100644 --- a/Runtime/ABase/Helper/CompressionUtility.cs.meta +++ b/Runtime/ABase/Utility/Utility.Compression.Zip.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1d572c5f6d619fd4cab0970b865300f7 +guid: 4d6547a46fce4ed7b0d0dce5f6f1a211 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Runtime/ABase/Utility/Utility.Compression.cs b/Runtime/ABase/Utility/Utility.Compression.cs index 50b3019..1ea25a3 100644 --- a/Runtime/ABase/Utility/Utility.Compression.cs +++ b/Runtime/ABase/Utility/Utility.Compression.cs @@ -1,6 +1,8 @@ using System; using System.IO; +using ICSharpCode.SharpZipLib.GZip; + namespace AlicizaX { public static partial class Utility @@ -10,6 +12,8 @@ namespace AlicizaX /// public static partial class Compression { + private const int CachedBytesLength = 0x1000; + /// /// 压缩数据。 /// @@ -90,7 +94,14 @@ namespace AlicizaX try { - return CompressionUtility.Compress(bytes, offset, length, compressedStream); + using (GZipOutputStream gzipOutputStream = new GZipOutputStream(compressedStream)) + { + gzipOutputStream.Write(bytes, offset, length); + gzipOutputStream.Finish(); + } + + ProcessHeader(compressedStream); + return true; } catch (Exception exception) { @@ -143,7 +154,20 @@ namespace AlicizaX try { - return CompressionUtility.Compress(stream, compressedStream); + byte[] cachedBytes = new byte[CachedBytesLength]; + using (GZipOutputStream gzipOutputStream = new GZipOutputStream(compressedStream)) + { + int bytesRead; + while ((bytesRead = stream.Read(cachedBytes, 0, CachedBytesLength)) > 0) + { + gzipOutputStream.Write(cachedBytes, 0, bytesRead); + } + + gzipOutputStream.Finish(); + } + + ProcessHeader(compressedStream); + return true; } catch (Exception exception) { @@ -236,7 +260,18 @@ namespace AlicizaX try { - return CompressionUtility.Decompress(bytes, offset, length, decompressedStream); + byte[] cachedBytes = new byte[CachedBytesLength]; + using (MemoryStream memoryStream = new MemoryStream(bytes, offset, length, false)) + using (GZipInputStream gzipInputStream = new GZipInputStream(memoryStream)) + { + int bytesRead; + while ((bytesRead = gzipInputStream.Read(cachedBytes, 0, CachedBytesLength)) > 0) + { + decompressedStream.Write(cachedBytes, 0, bytesRead); + } + } + + return true; } catch (Exception exception) { @@ -289,7 +324,17 @@ namespace AlicizaX try { - return CompressionUtility.Decompress(stream, decompressedStream); + byte[] cachedBytes = new byte[CachedBytesLength]; + using (GZipInputStream gzipInputStream = new GZipInputStream(stream)) + { + int bytesRead; + while ((bytesRead = gzipInputStream.Read(cachedBytes, 0, CachedBytesLength)) > 0) + { + decompressedStream.Write(cachedBytes, 0, bytesRead); + } + } + + return true; } catch (Exception exception) { @@ -301,6 +346,22 @@ namespace AlicizaX throw new GameFrameworkException(Text.Format("Can not decompress with exception '{0}'.", exception), exception); } } + + private static void ProcessHeader(Stream compressedStream) + { + if (compressedStream.Length < 8L) + { + return; + } + + long current = compressedStream.Position; + compressedStream.Position = 4L; + compressedStream.WriteByte(25); + compressedStream.WriteByte(134); + compressedStream.WriteByte(2); + compressedStream.WriteByte(32); + compressedStream.Position = current; + } } } } diff --git a/Runtime/ABase/Utility/Utility.Math.cs b/Runtime/ABase/Utility/Utility.Math.cs index 3952c0d..b104307 100644 --- a/Runtime/ABase/Utility/Utility.Math.cs +++ b/Runtime/ABase/Utility/Utility.Math.cs @@ -16,7 +16,7 @@ namespace AlicizaX public static float PingPong(float min, float max, float speed = 1f) { - return Mathf.PingPong(Time.time * speed, max - min) + min; + return Mathf.PingPong(UnityEngine.Time.time * speed, max - min) + min; } public static int Wrap(int value, int min, int max) diff --git a/Runtime/ABase/Utility/Utility.Position.cs b/Runtime/ABase/Utility/Utility.Position.cs new file mode 100644 index 0000000..af0a638 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Position.cs @@ -0,0 +1,93 @@ +using UnityEngine; + +namespace AlicizaX +{ + public static partial class Utility + { + /// + /// 位置与几何相关的实用函数。 + /// + public static class Position + { + public static Vector3 RayCastV2ToV3(Vector2 position) + { + return position.ToVector3(); + } + + public static Vector3 RayCastXYToV3(float x, float y) + { + return new Vector3(x, 0f, y); + } + + public static Vector3 RayCastV3ToV3(Vector3 position) + { + return position.FlattenY(); + } + + public static Quaternion AngleToQuaternion(int angle) + { + return GetAngleToQuaternion(angle); + } + + public static Quaternion GetAngleToQuaternion(float angle) + { + return Quaternion.AngleAxis(-angle, Vector3.up) * Quaternion.AngleAxis(90f, Vector3.up); + } + + public static Quaternion GetVector3ToQuaternion(Vector3 source, Vector3 direction) + { + if (source == direction) + { + return Quaternion.identity; + } + + return Quaternion.LookRotation((direction - source).normalized, Vector3.up); + } + + public static float Distance2D(Vector3 a, Vector3 b) + { + return Vector2.Distance(a.IgnoreYAxis(), b.IgnoreYAxis()); + } + + public static float Vector3ToAngle360(Vector3 from, Vector3 to) + { + float angle = Vector3.Angle(from, to); + Vector3 cross = Vector3.Cross(from, to); + return cross.y > 0f ? angle : 360f - angle; + } + + public static float DistanceOfPointToVector(Vector3 startPoint, Vector3 endPoint, Vector3 point) + { + Vector2 start = startPoint.IgnoreYAxis(); + Vector2 end = endPoint.IgnoreYAxis(); + float a = end.y - start.y; + float b = start.x - end.x; + float c = end.x * start.y - start.x * end.y; + float denominator = Mathf.Sqrt(a * a + b * b); + Vector2 point2 = point.IgnoreYAxis(); + return Mathf.Abs((a * point2.x + b * point2.y + c) / denominator); + } + + public static bool RayCastSphere(Ray ray, Vector3 center, float radius, out float distance) + { + distance = 0f; + Vector3 originToCenter = center - ray.origin; + float perpendicularDistance = Vector3.Cross(originToCenter, ray.direction).magnitude / ray.direction.magnitude; + if (perpendicularDistance >= radius) + { + return false; + } + + float centerDistance = PythagoreanTheorem(Vector3.Distance(center, ray.origin), perpendicularDistance); + float radiusDistance = PythagoreanTheorem(radius, perpendicularDistance); + distance = centerDistance - radiusDistance; + return true; + } + + public static float PythagoreanTheorem(float x, float y) + { + return Mathf.Sqrt(x * x + y * y); + } + } + } +} diff --git a/Runtime/ABase/Helper/ZipHelper.cs.meta b/Runtime/ABase/Utility/Utility.Position.cs.meta similarity index 69% rename from Runtime/ABase/Helper/ZipHelper.cs.meta rename to Runtime/ABase/Utility/Utility.Position.cs.meta index f1761c8..c4459d4 100644 --- a/Runtime/ABase/Helper/ZipHelper.cs.meta +++ b/Runtime/ABase/Utility/Utility.Position.cs.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: 75d07d90984a5dc4698c98d2fe3809bf -timeCreated: 1474948216 -licenseType: Pro +guid: c82a27c2ab4545f687eac25a4d731f16 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/Runtime/ABase/Utility/Utility.Time.cs b/Runtime/ABase/Utility/Utility.Time.cs new file mode 100644 index 0000000..4bcfa95 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Time.cs @@ -0,0 +1,118 @@ +using System; + +namespace AlicizaX +{ + public static partial class Utility + { + /// + /// 时间相关的实用函数。 + /// + public static class Time + { + private static readonly DateTime EpochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private static long s_DifferenceTime; + private static bool s_IsSecondLevel = true; + + public const long TicksPerMicrosecond = 1; + public const long TicksPer = 10 * TicksPerMicrosecond; + public const long TicksMillisecondUnit = TicksPer * 1000; + public const long TicksSecondUnit = TicksMillisecondUnit * 1000; + + public static void SetDifferenceTime(long timeSpan) + { + s_IsSecondLevel = timeSpan <= 1000000000000; + s_DifferenceTime = s_IsSecondLevel ? timeSpan - ClientNowSeconds() : timeSpan - ClientNowMillisecond(); + } + + public static long ClientNowMillisecond() + { + return (DateTime.UtcNow.Ticks - EpochTime.Ticks) / TicksMillisecondUnit; + } + + public static long ServerToday() + { + return s_IsSecondLevel ? s_DifferenceTime + ClientToday() : (s_DifferenceTime + ClientTodayMillisecond()) / 1000; + } + + public static long ClientTodayMillisecond() + { + return (DateTime.Now.Date.ToUniversalTime().Ticks - EpochTime.Ticks) / TicksMillisecondUnit; + } + + public static long ServerNow() + { + return s_IsSecondLevel ? s_DifferenceTime + ClientNowSeconds() : (s_DifferenceTime + ClientNowMillisecond()) / 1000; + } + + public static TimeSpan FromSeconds(int seconds) + { + return TimeSpan.FromSeconds(seconds); + } + + public static long ClientToday() + { + return (DateTime.Now.Date.ToUniversalTime().Ticks - EpochTime.Ticks) / TicksSecondUnit; + } + + public static long ClientNow() + { + return ClientNowMillisecond(); + } + + public static long ClientNowSeconds() + { + return (DateTime.UtcNow.Ticks - EpochTime.Ticks) / TicksSecondUnit; + } + + public static long Now() + { + return ClientNow(); + } + + public static long UnixTimeSeconds() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + } + + public static long UnixTimeMilliseconds() + { + return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + } + + public static bool IsUnixSameDay(long timestamp1, long timestamp2) + { + return IsSameDay(UtcToUtcDateTime(timestamp1), UtcToUtcDateTime(timestamp2)); + } + + public static bool IsLocalSameDay(long timestamp1, long timestamp2) + { + return IsSameDay(UtcToLocalDateTime(timestamp1), UtcToLocalDateTime(timestamp2)); + } + + public static DateTime UtcToUtcDateTime(long utcTimestamp) + { + return DateTimeOffset.FromUnixTimeSeconds(utcTimestamp).UtcDateTime; + } + + public static DateTime UtcToLocalDateTime(long utcTimestamp) + { + return DateTimeOffset.FromUnixTimeSeconds(utcTimestamp).LocalDateTime; + } + + public static bool IsSameDay(DateTime time1, DateTime time2) + { + return time1.Date == time2.Date; + } + + public static long LocalTimeToUnixTimeSeconds(DateTime time) + { + return new DateTimeOffset(time.ToUniversalTime()).ToUnixTimeSeconds(); + } + + public static long LocalTimeToUnixTimeMilliseconds(DateTime time) + { + return new DateTimeOffset(time.ToUniversalTime()).ToUnixTimeMilliseconds(); + } + } + } +} diff --git a/Runtime/ABase/Utility/Utility.Time.cs.meta b/Runtime/ABase/Utility/Utility.Time.cs.meta new file mode 100644 index 0000000..23537cd --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Time.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c88fefb639f4d1dac58f77d9cbba2af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs b/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs index be64cef..d7ae7a3 100644 --- a/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs +++ b/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs @@ -44,7 +44,7 @@ namespace AlicizaX source.clip = clip; source.volume = volume; source.Play(); - Object.Destroy(gameObject, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); + Object.Destroy(gameObject, clip.length * ((UnityEngine.Time.timeScale < 0.01f) ? 0.01f : UnityEngine.Time.timeScale)); return source; } @@ -72,7 +72,7 @@ namespace AlicizaX source.clip = clip; source.volume = volume; source.Play(); - Object.Destroy(gameObject, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); + Object.Destroy(gameObject, clip.length * ((UnityEngine.Time.timeScale < 0.01f) ? 0.01f : UnityEngine.Time.timeScale)); return source; } @@ -91,7 +91,7 @@ namespace AlicizaX source.volume = volume; source.maxDistance = maxDistance; source.Play(); - Object.Destroy(gameObject, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); + Object.Destroy(gameObject, clip.length * ((UnityEngine.Time.timeScale < 0.01f) ? 0.01f : UnityEngine.Time.timeScale)); return source; }