整合扩展

This commit is contained in:
陈思海 2026-03-23 20:01:59 +08:00
parent 7ae4ddac09
commit 919678b811
21 changed files with 602 additions and 2049 deletions

View File

@ -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
{

View File

@ -34,5 +34,35 @@
lhs.Scale(rhs);
return lhs;
}
/// <summary>
/// 将三维向量投影到 XZ 平面。
/// </summary>
public static Vector2 IgnoreYAxis(this Vector3 vector3)
{
return new Vector2(vector3.x, vector3.z);
}
/// <summary>
/// 保留 XZ 分量并清空 Y 轴。
/// </summary>
public static Vector3 FlattenY(this Vector3 vector3)
{
return new Vector3(vector3.x, 0f, vector3.z);
}
/// <summary>
/// 判断目标点是否位于当前方向的左侧。
/// </summary>
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;
}
}
}

View File

@ -1,206 +0,0 @@
using AlicizaX;
using ICSharpCode.SharpZipLib.GZip;
using System;
using System.IO;
namespace AlicizaX
{
/// <summary>
/// 默认压缩解压缩辅助器。
/// </summary>
[UnityEngine.Scripting.Preserve]
public class CompressionUtility
{
private const int CachedBytesLength = 0x1000;
private static readonly byte[] m_CachedBytes = new byte[CachedBytesLength];
/// <summary>
/// 压缩数据。
/// </summary>
/// <param name="bytes">要压缩的数据的二进制流。</param>
/// <param name="offset">要压缩的数据的二进制流的偏移。</param>
/// <param name="length">要压缩的数据的二进制流的长度。</param>
/// <param name="compressedStream">压缩后的数据的二进制流。</param>
/// <returns>是否压缩数据成功。</returns>
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;
}
}
/// <summary>
/// 压缩数据。
/// </summary>
/// <param name="stream">要压缩的数据的二进制流。</param>
/// <param name="compressedStream">压缩后的数据的二进制流。</param>
/// <returns>是否压缩数据成功。</returns>
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);
}
}
/// <summary>
/// 解压缩数据。
/// </summary>
/// <param name="bytes">要解压缩的数据的二进制流。</param>
/// <param name="offset">要解压缩的数据的二进制流的偏移。</param>
/// <param name="length">要解压缩的数据的二进制流的长度。</param>
/// <param name="decompressedStream">解压缩后的数据的二进制流。</param>
/// <returns>是否解压缩数据成功。</returns>
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);
}
}
/// <summary>
/// 解压缩数据。
/// </summary>
/// <param name="stream">要解压缩的数据的二进制流。</param>
/// <param name="decompressedStream">解压缩后的数据的二进制流。</param>
/// <returns>是否解压缩数据成功。</returns>
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;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ef59646f457548b0962c49a3434cf7e3
timeCreated: 1758265544

View File

@ -1,150 +0,0 @@
using UnityEngine;
namespace AlicizaX
{
/// <summary>
/// 坐标帮助类
/// </summary>
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;
}
/// <summary>
/// 求点到直线的距离采用数学公式Ax+By+C = 0; d = A*p.x + B * p.y + C / sqrt(A^2 + B ^ 2)
/// </summary>
/// <param name="startPoint">线的起点</param>
/// <param name="endPoint">线的终点</param>
/// <param name="point">点</param>
/// <returns></returns>
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);
;
}
/// <summary>
/// 判断射线是否碰撞到球体,如果碰撞到,返回射线起点到碰撞点之间的距离
/// </summary>
/// <param name="ray">射线</param>
/// <param name="center">中心点</param>
/// <param name="redis">半径</param>
/// <param name="dist">距离</param>
/// <returns></returns>
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;
}
/// <summary>
/// 勾股定理
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static float PythagoreanTheorem(float x, float y)
{
return Mathf.Sqrt(x * x + y * y);
}
/// <summary>
/// 去掉三维向量的Y轴把向量投射到xz平面。
/// </summary>
/// <param name="vector3"></param>
/// <returns></returns>
public static Vector2 IgnoreYAxis(this Vector3 vector3)
{
return new Vector2(vector3.x, vector3.z);
}
/// <summary>
/// 判断目标点是否位于向量的左边
/// </summary>
/// <returns>True is on left, false is on right</returns>
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;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: fb356e4ecfd547b280b88ca74a847918
timeCreated: 1666447289

View File

@ -1,266 +0,0 @@
using System;
namespace AlicizaX
{
/// <summary>
/// 游戏时间帮助类
/// </summary>
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;
/// <summary>
/// 时间差
/// </summary>
private static long _differenceTime;
private static bool _isSecLevel = true;
/// <summary>
/// 微秒
/// </summary>
public const long TicksPerMicrosecond = 1; //100微秒
/// <summary>
/// 10微秒
/// </summary>
public const long TicksPer = 10 * TicksPerMicrosecond;
/// <summary>
/// 1毫秒
/// </summary>
public const long TicksMillisecondUnit = TicksPer * 1000; //毫秒
/// <summary>
/// 1秒
/// </summary>
public const long TicksSecondUnit = TicksMillisecondUnit * 1000; // 秒 //10000000
/// <summary>
/// 设置时间差
/// </summary>
/// <param name="timeSpan"></param>
[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();
}
}
/// <summary>
/// 毫秒级
/// </summary>
/// <returns></returns>
[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;
}
/// <summary>
/// 服务器当前时间
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long ServerNow() //秒级
{
if (_isSecLevel)
{
return _differenceTime + ClientNow();
}
return (_differenceTime + ClientNowMillisecond()) / 1000;
}
/// <summary>
/// 将秒数转换成TimeSpan
/// </summary>
/// <param name="seconds">秒</param>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static TimeSpan FromSeconds(int seconds)
{
return TimeSpan.FromSeconds(seconds);
}
/// <summary>
/// 今天的客户端时间
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long ClientToday()
{
return (DateTime.Now.Date.ToUniversalTime().Ticks - Epoch) / TicksSecondUnit;
}
/// <summary>
/// 客户端时间,毫秒
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long ClientNow()
{
return (DateTime.UtcNow.Ticks - Epoch) / 10000;
}
/// <summary>
/// 客户端时间。秒
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long ClientNowSeconds()
{
return (DateTime.UtcNow.Ticks - Epoch) / 10000000;
}
/// <summary>
/// 客户端时间
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long Now()
{
return ClientNow();
}
/// <summary>
/// UTC时间 秒
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long UnixTimeSeconds()
{
return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
}
/// <summary>
/// UTC时间 毫秒
/// </summary>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long UnixTimeMilliseconds()
{
return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
}
/// <summary>
/// 按照UTC时间判断两个时间戳是否是同一天
/// </summary>
/// <param name="timestamp1">时间戳1</param>
/// <param name="timestamp2">时间戳2</param>
/// <returns>是否是同一天</returns>
[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;
}
/// <summary>
/// 按照本地时间判断两个时间戳是否是同一天
/// </summary>
/// <param name="timestamp1">时间戳1</param>
/// <param name="timestamp2">时间戳2</param>
/// <returns>是否是同一天</returns>
[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;
}
/// <summary>
/// UTC 时间戳 转换成UTC时间
/// </summary>
/// <param name="utcTimestamp">UTC时间戳,单位秒</param>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static DateTime UtcToUtcDateTime(long utcTimestamp)
{
return DateTimeOffset.FromUnixTimeSeconds(utcTimestamp).UtcDateTime;
}
/// <summary>
/// UTC 时间戳 转换成本地时间
/// </summary>
/// <param name="utcTimestamp">UTC时间戳,单位秒</param>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static DateTime UtcToLocalDateTime(long utcTimestamp)
{
return DateTimeOffset.FromUnixTimeSeconds(utcTimestamp).LocalDateTime;
}
/// <summary>
/// 判断两个时间是否是同一天
/// </summary>
/// <param name="time1">时间1</param>
/// <param name="time2">时间2</param>
/// <returns>是否是同一天</returns>
[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;
}
/// <summary>
/// 指定时间转换成Unix时间戳的时间差单位秒
/// </summary>
/// <param name="time">指定时间</param>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long LocalTimeToUnixTimeSeconds(DateTime time)
{
var utcDateTime = time.ToUniversalTime();
return (long)(utcDateTime - EpochTime).TotalSeconds;
}
/// <summary>
/// 指定时间转换成Unix时间戳的时间差单位毫秒
/// </summary>
/// <param name="time">指定时间</param>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static long LocalTimeToUnixTimeMilliseconds(DateTime time)
{
var utcDateTime = time.ToUniversalTime();
return (long)(utcDateTime - EpochTime).TotalMilliseconds;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 0d61562907c14a5295de01e78a41cd22
timeCreated: 1666538474

View File

@ -1,63 +0,0 @@
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace AlicizaX
{
/// <summary>
/// Unity 渲染帮助类
/// </summary>
public static class UnityRendererHelper
{
/// <summary>
/// 判断渲染组件是否在相机范围内
/// </summary>
/// <param name="renderer">渲染组件</param>
/// <param name="camera">相机对象</param>
/// <returns></returns>
public static bool IsVisibleFrom(Renderer renderer, Camera camera)
{
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}
/// <summary>
/// 判断渲染组件是否在相机范围内
/// </summary>
/// <param name="renderer">渲染对象</param>
/// <param name="camera">相机对象</param>
/// <returns></returns>
public static bool IsVisibleFrom(MeshRenderer renderer, Camera camera)
{
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}
/// <summary>
/// 获取相机快照
/// </summary>
/// <param name="main">相机</param>
/// <param name="scale">缩放比</param>
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;
}
}
}

View File

@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: f8cc8709b4b6495eab2f7dcba3529dcf
timeCreated: 1654011360

View File

@ -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
{
/// <summary>
/// 压缩帮助类
/// </summary>
[UnityEngine.Scripting.Preserve]
public static class ZipHelper
{
private static readonly Crc32 CRC = new Crc32();
/// <summary>
/// 压缩文件夹
/// </summary>
/// <param name="folderToZip">要压缩的文件夹路径</param>
/// <param name="stream">压缩前的Stream,方法执行后变为压缩完成后的文件</param>
/// <param name="password">密码</param>
/// <returns>是否成功</returns>
[UnityEngine.Scripting.Preserve]
public static bool CompressDirectoryToStream(string folderToZip, Stream stream, string password = null)
{
return CompressDirectoryToZipStream(folderToZip, stream, password) != null;
}
/// <summary>
/// 压缩文件夹
/// </summary>
/// <param name="folderToZip">要压缩的文件夹路径</param>
/// <param name="stream">压缩前的Stream,方法执行后变为压缩完成后的文件</param>
/// <param name="password">密码</param>
/// <returns>是否压缩成功返回ZipOutputStream否则返回null</returns>
[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;
}
/// <summary>
/// 递归压缩文件夹的内部方法
/// </summary>
/// <param name="folderToZip">要压缩的文件夹路径</param>
/// <param name="zipStream">压缩输出流</param>
/// <param name="parentFolderName">此文件夹的上级文件夹</param>
/// <returns>是否成功</returns>
[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;
}
/// <summary>
/// 压缩文件夹
/// </summary>
/// <param name="folderToZip">要压缩的文件夹路径</param>
/// <param name="zipFile">压缩文件完整路径</param>
/// <param name="password">密码</param>
/// <returns>是否成功</returns>
[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;
}
/// <summary>
/// 压缩文件
/// </summary>
/// <param name="fileToZip">要压缩的文件全名</param>
/// <param name="zipFile">压缩后的文件名</param>
/// <param name="password">密码</param>
/// <returns>是否成功</returns>
[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;
}
/// <summary>
/// 解压功能(解压压缩文件到指定目录)
/// </summary>
/// <param name="fileToUnZip">待解压的文件</param>
/// <param name="zipFolder">指定解压目标目录</param>
/// <param name="password">密码</param>
/// <returns>是否成功</returns>
[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;
}
/// <summary>
/// 压缩
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
[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();
}
}
/// <summary>
/// 解压缩
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
[UnityEngine.Scripting.Preserve]
public static byte[] Decompress(byte[] content)
{
return Decompress(content, 0, content.Length);
}
/// <summary>
/// 解压缩
/// </summary>
/// <param name="content"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <returns></returns>
[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();
}
}
}
}

View File

@ -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
{
/// <summary>
/// Zip 压缩相关的实用函数。
/// </summary>
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;
}
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 1d572c5f6d619fd4cab0970b865300f7
guid: 4d6547a46fce4ed7b0d0dce5f6f1a211
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -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
/// </summary>
public static partial class Compression
{
private const int CachedBytesLength = 0x1000;
/// <summary>
/// 压缩数据。
/// </summary>
@ -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;
}
}
}
}

View File

@ -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)

View File

@ -0,0 +1,93 @@
using UnityEngine;
namespace AlicizaX
{
public static partial class Utility
{
/// <summary>
/// 位置与几何相关的实用函数。
/// </summary>
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);
}
}
}
}

View File

@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 75d07d90984a5dc4698c98d2fe3809bf
timeCreated: 1474948216
licenseType: Pro
guid: c82a27c2ab4545f687eac25a4d731f16
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@ -0,0 +1,118 @@
using System;
namespace AlicizaX
{
public static partial class Utility
{
/// <summary>
/// 时间相关的实用函数。
/// </summary>
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();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c88fefb639f4d1dac58f77d9cbba2af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}