[+] TEngineServer

[+] TEngineServer
This commit is contained in:
ALEXTANG
2023-07-13 17:17:26 +08:00
parent a69f53592e
commit 0c8f3a5f92
790 changed files with 52737 additions and 2533 deletions

View File

@@ -0,0 +1,432 @@
#if TENGINE_UNITY
using System;
using System.IO;
using System.Text;
using UnityEngine;
namespace TEngine.Core
{
public static class AudioHelper
{
// Force save as 16-bit .wav
const int BlockSize_16Bit = 2;
/// <summary>
/// Load PCM format *.wav audio file (using Unity's Application data path) and convert to AudioClip.
/// </summary>
/// <returns>The AudioClip.</returns>
/// <param name="filePath">Local file path to .wav file</param>
public static AudioClip ToAudioClip(string filePath)
{
if (!filePath.StartsWith(UnityEngine.Application.persistentDataPath) &&
!filePath.StartsWith(UnityEngine.Application.dataPath))
{
Debug.LogWarning(
"This only supports files that are stored using Unity's Application data path. \nTo load bundled resources use 'Resources.Load(\"filename\") typeof(AudioClip)' method. \nhttps://docs.unity3d.com/ScriptReference/Resources.Load.html");
return null;
}
var fileBytes = File.ReadAllBytes(filePath);
return ToAudioClip(fileBytes, 0);
}
public static AudioClip ToAudioClip(byte[] fileBytes, int offsetSamples = 0, string name = "wav")
{
//string riff = Encoding.ASCII.GetString (fileBytes, 0, 4);
//string wave = Encoding.ASCII.GetString (fileBytes, 8, 4);
int subchunk1 = BitConverter.ToInt32(fileBytes, 16);
UInt16 audioFormat = BitConverter.ToUInt16(fileBytes, 20);
// NB: Only uncompressed PCM wav files are supported.
string formatCode = FormatCode(audioFormat);
Debug.AssertFormat(audioFormat == 1 || audioFormat == 65534,
"Detected format code '{0}' {1}, but only PCM and WaveFormatExtensable uncompressed formats are currently supported.",
audioFormat, formatCode);
UInt16 channels = BitConverter.ToUInt16(fileBytes, 22);
int sampleRate = BitConverter.ToInt32(fileBytes, 24);
//int byteRate = BitConverter.ToInt32 (fileBytes, 28);
//UInt16 blockAlign = BitConverter.ToUInt16 (fileBytes, 32);
UInt16 bitDepth = BitConverter.ToUInt16(fileBytes, 34);
int headerOffset = 16 + 4 + subchunk1 + 4;
int subchunk2 = BitConverter.ToInt32(fileBytes, headerOffset);
//Debug.LogFormat ("riff={0} wave={1} subchunk1={2} format={3} channels={4} sampleRate={5} byteRate={6} blockAlign={7} bitDepth={8} headerOffset={9} subchunk2={10} filesize={11}", riff, wave, subchunk1, formatCode, channels, sampleRate, byteRate, blockAlign, bitDepth, headerOffset, subchunk2, fileBytes.Length);
float[] data;
switch (bitDepth)
{
case 8:
data = Convert8BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
break;
case 16:
data = Convert16BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
break;
case 24:
data = Convert24BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
break;
case 32:
data = Convert32BitByteArrayToAudioClipData(fileBytes, headerOffset, subchunk2);
break;
default:
throw new Exception(bitDepth + " bit depth is not supported.");
}
AudioClip audioClip = AudioClip.Create(name, data.Length, (int)channels, sampleRate, false);
audioClip.SetData(data, 0);
return audioClip;
}
#region wav file bytes to Unity AudioClip conversion methods
private static float[] Convert8BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
{
int wavSize = BitConverter.ToInt32(source, headerOffset);
headerOffset += sizeof(int);
Debug.AssertFormat(wavSize > 0 && wavSize == dataSize,
"Failed to get valid 8-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize,
headerOffset);
float[] data = new float[wavSize];
sbyte maxValue = sbyte.MaxValue;
int i = 0;
while (i < wavSize)
{
data[i] = (float)source[i] / maxValue;
++i;
}
return data;
}
private static float[] Convert16BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
{
int wavSize = BitConverter.ToInt32(source, headerOffset);
headerOffset += sizeof(int);
Debug.AssertFormat(wavSize > 0 && wavSize == dataSize,
"Failed to get valid 16-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize,
headerOffset);
int x = sizeof(Int16); // block size = 2
int convertedSize = wavSize / x;
float[] data = new float[convertedSize];
Int16 maxValue = Int16.MaxValue;
int offset = 0;
int i = 0;
while (i < convertedSize)
{
offset = i * x + headerOffset;
data[i] = (float)BitConverter.ToInt16(source, offset) / maxValue;
++i;
}
Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}",
data.Length, convertedSize);
return data;
}
private static float[] Convert24BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
{
int wavSize = BitConverter.ToInt32(source, headerOffset);
headerOffset += sizeof(int);
Debug.AssertFormat(wavSize > 0 && wavSize == dataSize,
"Failed to get valid 24-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize,
headerOffset);
int x = 3; // block size = 3
int convertedSize = wavSize / x;
int maxValue = Int32.MaxValue;
float[] data = new float[convertedSize];
byte[]
block = new byte[sizeof(int)]; // using a 4 byte block for copying 3 bytes, then copy bytes with 1 offset
int offset = 0;
int i = 0;
while (i < convertedSize)
{
offset = i * x + headerOffset;
Buffer.BlockCopy(source, offset, block, 1, x);
data[i] = (float)BitConverter.ToInt32(block, 0) / maxValue;
++i;
}
Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}",
data.Length, convertedSize);
return data;
}
private static float[] Convert32BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
{
int wavSize = BitConverter.ToInt32(source, headerOffset);
headerOffset += sizeof(int);
Debug.AssertFormat(wavSize > 0 && wavSize == dataSize,
"Failed to get valid 32-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize,
headerOffset);
int x = sizeof(float); // block size = 4
int convertedSize = wavSize / x;
Int32 maxValue = Int32.MaxValue;
float[] data = new float[convertedSize];
int offset = 0;
int i = 0;
while (i < convertedSize)
{
offset = i * x + headerOffset;
data[i] = (float)BitConverter.ToInt32(source, offset) / maxValue;
++i;
}
Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}",
data.Length, convertedSize);
return data;
}
#endregion
public static byte[] FromAudioClip(AudioClip audioClip)
{
string file;
return FromAudioClip(audioClip, out file, false);
}
public static byte[] FromAudioClip(AudioClip audioClip, out string filepath, bool saveAsFile = true,
string dirname = "recordings")
{
MemoryStream stream = new MemoryStream();
const int headerSize = 44;
// get bit depth
UInt16 bitDepth = 16; //BitDepth (audioClip);
// NB: Only supports 16 bit
//Debug.AssertFormat (bitDepth == 16, "Only converting 16 bit is currently supported. The audio clip data is {0} bit.", bitDepth);
// total file size = 44 bytes for header format and audioClip.samples * factor due to float to Int16 / sbyte conversion
int fileSize = audioClip.samples * BlockSize_16Bit + headerSize; // BlockSize (bitDepth)
// chunk descriptor (riff)
WriteFileHeader(ref stream, fileSize);
// file header (fmt)
WriteFileFormat(ref stream, audioClip.channels, audioClip.frequency, bitDepth);
// data chunks (data)
WriteFileData(ref stream, audioClip, bitDepth);
byte[] bytes = stream.ToArray();
// Validate total bytes
Debug.AssertFormat(bytes.Length == fileSize, "Unexpected AudioClip to wav format byte count: {0} == {1}",
bytes.Length, fileSize);
// Save file to persistant storage location
if (saveAsFile)
{
filepath = string.Format("{0}/{1}/{2}.{3}", UnityEngine.Application.persistentDataPath, dirname,
DateTime.UtcNow.ToString("yyMMdd-HHmmss-fff"), "wav");
Directory.CreateDirectory(Path.GetDirectoryName(filepath));
File.WriteAllBytes(filepath, bytes);
//Debug.Log ("Auto-saved .wav file: " + filepath);
}
else
{
filepath = null;
}
stream.Dispose();
return bytes;
}
#region write .wav file functions
private static int WriteFileHeader(ref MemoryStream stream, int fileSize)
{
int count = 0;
int total = 12;
// riff chunk id
byte[] riff = Encoding.ASCII.GetBytes("RIFF");
count += WriteBytesToMemoryStream(ref stream, riff, "ID");
// riff chunk size
int chunkSize = fileSize - 8; // total size - 8 for the other two fields in the header
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(chunkSize), "CHUNK_SIZE");
byte[] wave = Encoding.ASCII.GetBytes("WAVE");
count += WriteBytesToMemoryStream(ref stream, wave, "FORMAT");
// Validate header
Debug.AssertFormat(count == total, "Unexpected wav descriptor byte count: {0} == {1}", count, total);
return count;
}
private static int WriteFileFormat(ref MemoryStream stream, int channels, int sampleRate, UInt16 bitDepth)
{
int count = 0;
int total = 24;
byte[] id = Encoding.ASCII.GetBytes("fmt ");
count += WriteBytesToMemoryStream(ref stream, id, "FMT_ID");
int subchunk1Size = 16; // 24 - 8
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(subchunk1Size), "SUBCHUNK_SIZE");
UInt16 audioFormat = 1;
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(audioFormat), "AUDIO_FORMAT");
UInt16 numChannels = Convert.ToUInt16(channels);
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(numChannels), "CHANNELS");
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(sampleRate), "SAMPLE_RATE");
int byteRate = sampleRate * channels * BytesPerSample(bitDepth);
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(byteRate), "BYTE_RATE");
UInt16 blockAlign = Convert.ToUInt16(channels * BytesPerSample(bitDepth));
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(blockAlign), "BLOCK_ALIGN");
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(bitDepth), "BITS_PER_SAMPLE");
// Validate format
Debug.AssertFormat(count == total, "Unexpected wav fmt byte count: {0} == {1}", count, total);
return count;
}
private static int WriteFileData(ref MemoryStream stream, AudioClip audioClip, UInt16 bitDepth)
{
int count = 0;
int total = 8;
// Copy float[] data from AudioClip
float[] data = new float[audioClip.samples * audioClip.channels];
audioClip.GetData(data, 0);
byte[] bytes = ConvertAudioClipDataToInt16ByteArray(data);
byte[] id = Encoding.ASCII.GetBytes("data");
count += WriteBytesToMemoryStream(ref stream, id, "DATA_ID");
int subchunk2Size = Convert.ToInt32(audioClip.samples * BlockSize_16Bit); // BlockSize (bitDepth)
count += WriteBytesToMemoryStream(ref stream, BitConverter.GetBytes(subchunk2Size), "SAMPLES");
// Validate header
Debug.AssertFormat(count == total, "Unexpected wav data id byte count: {0} == {1}", count, total);
// Write bytes to stream
count += WriteBytesToMemoryStream(ref stream, bytes, "DATA");
// Validate audio data
Debug.AssertFormat(bytes.Length == subchunk2Size, "Unexpected AudioClip to wav subchunk2 size: {0} == {1}",
bytes.Length, subchunk2Size);
return count;
}
private static byte[] ConvertAudioClipDataToInt16ByteArray(float[] data)
{
MemoryStream dataStream = new MemoryStream();
int x = sizeof(Int16);
Int16 maxValue = Int16.MaxValue;
int i = 0;
while (i < data.Length)
{
dataStream.Write(BitConverter.GetBytes(Convert.ToInt16(data[i] * maxValue)), 0, x);
++i;
}
byte[] bytes = dataStream.ToArray();
// Validate converted bytes
Debug.AssertFormat(data.Length * x == bytes.Length,
"Unexpected float[] to Int16 to byte[] size: {0} == {1}", data.Length * x, bytes.Length);
dataStream.Dispose();
return bytes;
}
private static int WriteBytesToMemoryStream(ref MemoryStream stream, byte[] bytes, string tag = "")
{
int count = bytes.Length;
stream.Write(bytes, 0, count);
//Debug.LogFormat ("WAV:{0} wrote {1} bytes.", tag, count);
return count;
}
#endregion
/// <summary>
/// Calculates the bit depth of an AudioClip
/// </summary>
/// <returns>The bit depth. Should be 8 or 16 or 32 bit.</returns>
/// <param name="audioClip">Audio clip.</param>
public static UInt16 BitDepth(AudioClip audioClip)
{
UInt16 bitDepth =
Convert.ToUInt16(audioClip.samples * audioClip.channels * audioClip.length / audioClip.frequency);
Debug.AssertFormat(bitDepth == 8 || bitDepth == 16 || bitDepth == 32,
"Unexpected AudioClip bit depth: {0}. Expected 8 or 16 or 32 bit.", bitDepth);
return bitDepth;
}
private static int BytesPerSample(UInt16 bitDepth)
{
return bitDepth / 8;
}
private static int BlockSize(UInt16 bitDepth)
{
switch (bitDepth)
{
case 32:
return sizeof(Int32); // 32-bit -> 4 bytes (Int32)
case 16:
return sizeof(Int16); // 16-bit -> 2 bytes (Int16)
case 8:
return sizeof(sbyte); // 8-bit -> 1 byte (sbyte)
default:
throw new Exception(bitDepth + " bit depth is not supported.");
}
}
private static string FormatCode(UInt16 code)
{
switch (code)
{
case 1:
return "PCM";
case 2:
return "ADPCM";
case 3:
return "IEEE";
case 7:
return "μ-law";
case 65534:
return "WaveFormatExtensable";
default:
Debug.LogWarning("Unknown wav code format:" + code);
return "";
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,179 @@
using System;
using System.IO;
using System.Text;
namespace TEngine.Core
{
public static class ByteHelper
{
private static readonly string[] Suffix = { "Byte", "KB", "MB", "GB", "TB" };
public static long ReadInt64(FileStream stream)
{
var buffer = new byte[8];
stream.Read(buffer, 0, 8);
return BitConverter.ToInt64(buffer, 0);
}
public static int ReadInt32(FileStream stream)
{
var buffer = new byte[4];
stream.Read(buffer, 0, 4);
return BitConverter.ToInt32(buffer, 0);
}
public static long ReadInt64(MemoryStream stream)
{
var buffer = new byte[8];
stream.Read(buffer, 0, 8);
return BitConverter.ToInt64(buffer, 0);
}
public static int ReadInt32(MemoryStream stream)
{
var buffer = new byte[4];
stream.Read(buffer, 0, 4);
return BitConverter.ToInt32(buffer, 0);
}
public static string ToHex(this byte b)
{
return b.ToString("X2");
}
public static string ToHex(this byte[] bytes)
{
var stringBuilder = new StringBuilder();
foreach (var b in bytes)
{
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString();
}
public static string ToHex(this byte[] bytes, string format)
{
var stringBuilder = new StringBuilder();
foreach (var b in bytes)
{
stringBuilder.Append(b.ToString(format));
}
return stringBuilder.ToString();
}
public static string ToHex(this byte[] bytes, int offset, int count)
{
var stringBuilder = new StringBuilder();
for (var i = offset; i < offset + count; ++i)
{
stringBuilder.Append(bytes[i].ToString("X2"));
}
return stringBuilder.ToString();
}
public static string ToStr(this byte[] bytes)
{
return Encoding.Default.GetString(bytes);
}
public static string ToStr(this byte[] bytes, int index, int count)
{
return Encoding.Default.GetString(bytes, index, count);
}
public static string Utf8ToStr(this byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
public static string Utf8ToStr(this byte[] bytes, int index, int count)
{
return Encoding.UTF8.GetString(bytes, index, count);
}
public static void WriteTo(this byte[] bytes, int offset, uint num)
{
bytes[offset] = (byte)(num & 0xff);
bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
bytes[offset + 2] = (byte)((num & 0xff0000) >> 16);
bytes[offset + 3] = (byte)((num & 0xff000000) >> 24);
}
public static void WriteTo(this byte[] bytes, int offset, int num)
{
bytes[offset] = (byte)(num & 0xff);
bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
bytes[offset + 2] = (byte)((num & 0xff0000) >> 16);
bytes[offset + 3] = (byte)((num & 0xff000000) >> 24);
}
public static void WriteTo(this byte[] bytes, int offset, byte num)
{
bytes[offset] = num;
}
public static void WriteTo(this byte[] bytes, int offset, short num)
{
bytes[offset] = (byte)(num & 0xff);
bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
}
public static void WriteTo(this byte[] bytes, int offset, ushort num)
{
bytes[offset] = (byte)(num & 0xff);
bytes[offset + 1] = (byte)((num & 0xff00) >> 8);
}
public static string ToReadableSpeed(this long byteCount)
{
var i = 0;
double dblSByte = byteCount;
if (byteCount <= 1024)
{
return $"{dblSByte:0.##}{Suffix[i]}";
}
for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024)
{
dblSByte = byteCount / 1024.0;
}
return $"{dblSByte:0.##}{Suffix[i]}";
}
public static string ToReadableSpeed(this ulong byteCount)
{
var i = 0;
double dblSByte = byteCount;
if (byteCount <= 1024)
{
return $"{dblSByte:0.##}{Suffix[i]}";
}
for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024)
{
dblSByte = byteCount / 1024.0;
}
return $"{dblSByte:0.##}{Suffix[i]}";
}
/// <summary>
/// 合并一个数组
/// </summary>
/// <param name="bytes"></param>
/// <param name="otherBytes"></param>
/// <returns></returns>
public static byte[] MergeBytes(byte[] bytes, byte[] otherBytes)
{
var result = new byte[bytes.Length + otherBytes.Length];
bytes.CopyTo(result, 0);
otherBytes.CopyTo(result, bytes.Length);
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,77 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace TEngine.Core
{
public static class CryptHelper
{
// 对应的字符串SYUwQN360OPY1gaL
// 在这个网站随机生成的 http://tool.c7sky.com/password/
private static readonly byte[] Key =
{
0x53, 0x59, 0x55, 0x77, 0x51, 0x4e, 0x33, 0x36,
0x30, 0x4f, 0x50, 0x59, 0x31, 0x67, 0x61, 0x4c
};
/// <summary>
/// 创建一个新的KEY
/// </summary>
/// <param name="keyStr">一个长度为16的字符串、如果超过只会截取前16位</param>
/// <returns>返回的是一个十六进制的字符串、每个用,分割的、每个都是一个byte</returns>
public static string CreateKey(string keyStr)
{
if (keyStr.Length > 16)
{
keyStr = keyStr.Substring(0, 15);
}
var bytes = Encoding.UTF8.GetBytes(keyStr);
return $"0x{BitConverter.ToString(bytes, 0).Replace("-", ", 0x").ToLower()}";
}
/// <summary>
/// AES 加密
/// </summary>
/// <param name="toEncryptArray"></param>
/// <returns></returns>
public static byte[] AesEncrypt(byte[] toEncryptArray)
{
var rm = Aes.Create();
rm.Key = Key;
rm.Mode = CipherMode.ECB;
rm.Padding = PaddingMode.PKCS7;
var cTransform = rm.CreateEncryptor();
return cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
}
/// <summary>
/// AES 解密
/// </summary>
/// <param name="toEncryptArray"></param>
/// <returns></returns>
public static MemoryStream AesDecryptReturnStream(byte[] toEncryptArray)
{
var bytes = AesDecrypt(toEncryptArray);
return new MemoryStream(bytes);
}
/// <summary>
/// AES 解密
/// </summary>
/// <param name="toEncryptArray"></param>
/// <returns></returns>
public static byte[] AesDecrypt(byte[] toEncryptArray)
{
var rm = Aes.Create();
rm.Key = Key;
rm.Mode = CipherMode.ECB;
rm.Padding = PaddingMode.PKCS7;
var cTransform = rm.CreateDecryptor();
return cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
}
}
}

View File

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

View File

@@ -0,0 +1,112 @@
using System.Collections.Generic;
using System.IO;
namespace TEngine.Core
{
public static class FileHelper
{
/// <summary>
/// 拷贝文件到目标路径、如果目标目录不存在会自动创建目录
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="destinationFile"></param>
/// <param name="overwrite"></param>
public static void Copy(string sourceFile, string destinationFile, bool overwrite)
{
var directoriesByFilePath = GetDirectoriesByFilePath(destinationFile);
foreach (var dir in directoriesByFilePath)
{
if (Directory.Exists(dir))
{
continue;
}
Directory.CreateDirectory(dir);
}
File.Copy(sourceFile, destinationFile, overwrite);
}
/// <summary>
/// 获取文件路径内的所有文件夹路径
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static List<string> GetDirectoriesByFilePath(string filePath)
{
var dir = "";
var directories = new List<string>();
var fileDirectories = filePath.Split('/');
for (var i = 0; i < fileDirectories.Length - 1; i++)
{
dir = $"{dir}{fileDirectories[i]}/";
directories.Add(dir);
}
return directories;
}
/// <summary>
/// 把文件夹里所有内容拷贝的目标位置
/// </summary>
/// <param name="sourceDirectory"></param>
/// <param name="destinationDirectory"></param>
/// <param name="overwrite"></param>
public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite)
{
// 创建目标文件夹
if (!Directory.Exists(destinationDirectory))
{
Directory.CreateDirectory(destinationDirectory);
}
// 获取当前文件夹中的所有文件
var files = Directory.GetFiles(sourceDirectory);
// 拷贝文件到目标文件夹
foreach (var file in files)
{
var fileName = Path.GetFileName(file);
var destinationPath = Path.Combine(destinationDirectory, fileName);
File.Copy(file, destinationPath, overwrite);
}
// 获取源文件夹中的所有子文件夹
var directories = Directory.GetDirectories(sourceDirectory);
// 递归方式拷贝文件夹
foreach (var directory in directories)
{
var directoryName = Path.GetFileName(directory);
var destinationPath = Path.Combine(destinationDirectory, directoryName);
CopyDirectory(directory, destinationPath, overwrite);
}
}
/// <summary>
/// 清除文件夹里的所有文件
/// </summary>
/// <param name="folderPath"></param>
public static void ClearDirectoryFile(string folderPath)
{
if (!Directory.Exists(folderPath))
{
return;
}
var files = Directory.GetFiles(folderPath);
foreach (var file in files)
{
File.Delete(file);
}
}
}
}

View File

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

View File

@@ -0,0 +1,29 @@
using System;
using Newtonsoft.Json;
#pragma warning disable CS8603
namespace TEngine.Core
{
public static class JsonHelper
{
public static string ToJson<T>(this T t)
{
return JsonConvert.SerializeObject(t);
}
public static object Deserialize(this string json, Type type, bool reflection = true)
{
return JsonConvert.DeserializeObject(json, type);
}
public static T Deserialize<T>(this string json)
{
return JsonConvert.DeserializeObject<T>(json);
}
public static T Clone<T>(T t)
{
return t.ToJson().Deserialize<T>();
}
}
}

View File

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

View File

@@ -0,0 +1,27 @@
using System.IO;
using System.Security.Cryptography;
namespace TEngine.Core
{
public static class MD5Helper
{
public static string FileMD5(string filePath)
{
using var file = new FileStream(filePath, FileMode.Open);
return FileMD5(file);
}
public static string FileMD5(FileStream fileStream)
{
var md5 = MD5.Create();
return md5.ComputeHash(fileStream).ToHex("x2");
}
public static string BytesMD5(byte[] bytes)
{
var md5 = MD5.Create();
bytes = md5.ComputeHash(bytes);
return bytes.ToHex("x2");
}
}
}

View File

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

View File

@@ -0,0 +1,15 @@
using System.IO;
using TEngine.IO;
namespace TEngine.Core
{
public static class MemoryStreamHelper
{
private static readonly RecyclableMemoryStreamManager Manager = new RecyclableMemoryStreamManager();
public static MemoryStream GetRecyclableMemoryStream()
{
return Manager.GetStream();
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 90685e6f420bcae4f851975873f430c9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
#if TENGINE_NET
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
using Unity.Mathematics;
namespace TEngine.Core;
public sealed class MongoHelper : Singleton<MongoHelper>
{
private readonly HashSet<int> _registerCount = new HashSet<int>(3);
static MongoHelper()
{
// 自动注册IgnoreExtraElements
var conventionPack = new ConventionPack {new IgnoreExtraElementsConvention(true)};
ConventionRegistry.Register("IgnoreExtraElements", conventionPack, type => true);
BsonSerializer.TryRegisterSerializer(typeof(float2), new StructBsonSerialize<float2>());
BsonSerializer.TryRegisterSerializer(typeof(float3), new StructBsonSerialize<float3>());
BsonSerializer.TryRegisterSerializer(typeof(float4), new StructBsonSerialize<float4>());
BsonSerializer.TryRegisterSerializer(typeof(quaternion), new StructBsonSerialize<quaternion>());
}
protected override void OnLoad(int assemblyName)
{
if (_registerCount.Count == 3)
{
return;
}
_registerCount.Add(assemblyName);
Task.Run(() =>
{
foreach (var type in AssemblyManager.ForEach(assemblyName))
{
if (type.IsInterface || type.IsAbstract || !typeof(Entity).IsAssignableFrom(type))
{
continue;
}
BsonClassMap.LookupClassMap(type);
}
});
}
public T Deserialize<T>(byte[] bytes)
{
return BsonSerializer.Deserialize<T>(bytes);
}
public object Deserialize(byte[] bytes, Type type)
{
return BsonSerializer.Deserialize(bytes, type);
}
public object Deserialize(byte[] bytes, string type)
{
return BsonSerializer.Deserialize(bytes, Type.GetType(type));
}
public T Deserialize<T>(Stream stream)
{
return BsonSerializer.Deserialize<T>(stream);
}
public object Deserialize(Stream stream, Type type)
{
return BsonSerializer.Deserialize(stream, type);
}
public object DeserializeFrom(Type type, MemoryStream stream)
{
return Deserialize(stream, type);
}
public T DeserializeFrom<T>(MemoryStream stream)
{
return Deserialize<T>(stream);
}
public T DeserializeFrom<T>(byte[] bytes, int index, int count)
{
return BsonSerializer.Deserialize<T>(bytes.AsMemory(index, count).ToArray());
}
public byte[] SerializeTo<T>(T t)
{
return t.ToBson();
}
public void SerializeTo<T>(T t, MemoryStream stream)
{
var bytes = t.ToBson();
stream.Write(bytes, 0, bytes.Length);
}
public T Clone<T>(T t)
{
return Deserialize<T>(t.ToBson());
}
}
#endif
#if TENGINE_UNITY
using System;
using System.IO;
namespace TEngine.Core
{
public sealed class MongoHelper : Singleton<MongoHelper>
{
public object DeserializeFrom(Type type, MemoryStream stream)
{
return null;
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,57 @@
#if TENGINE_NET
using System.Reflection;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace TEngine.Core;
public class StructBsonSerialize<TValue> : StructSerializerBase<TValue> where TValue : struct
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TValue value)
{
var nominalType = args.NominalType;
var bsonWriter = context.Writer;
bsonWriter.WriteStartDocument();
var fields = nominalType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field in fields)
{
bsonWriter.WriteName(field.Name);
BsonSerializer.Serialize(bsonWriter, field.FieldType, field.GetValue(value));
}
bsonWriter.WriteEndDocument();
}
public override TValue Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
//boxing is required for SetValue to work
object obj = new TValue();
var actualType = args.NominalType;
var bsonReader = context.Reader;
bsonReader.ReadStartDocument();
while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
{
var name = bsonReader.ReadName(Utf8NameDecoder.Instance);
var field = actualType.GetField(name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
var value = BsonSerializer.Deserialize(bsonReader, field.FieldType);
field.SetValue(obj, value);
}
}
bsonReader.ReadEndDocument();
return (TValue) obj;
}
}
#endif

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9557f6157233b304fb1f1669311f5fc9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using ProtoBuf;
namespace TEngine
{
[ProtoContract]
public abstract class AProto
{
public virtual void AfterDeserialization() => EndInit();
protected virtual void EndInit() { }
}
}

View File

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

View File

@@ -0,0 +1,58 @@
using System;
using System.IO;
using ProtoBuf;
#pragma warning disable CS8604
namespace TEngine.Core
{
public static class ProtoBufHelper
{
public static object FromBytes(Type type, byte[] bytes, int index, int count)
{
using var stream = new MemoryStream(bytes, index, count);
return Serializer.Deserialize(type, stream);
}
public static T FromBytes<T>(byte[] bytes)
{
using var stream = new MemoryStream(bytes, 0, bytes.Length);
return Serializer.Deserialize<T>(stream);
// return FromBytes<T>(bytes, 0, bytes.Length);
}
public static T FromBytes<T>(byte[] bytes, int index, int count)
{
using var stream = new MemoryStream(bytes, index, count);
return Serializer.Deserialize<T>(stream);
}
public static byte[] ToBytes(object message)
{
using var stream = new MemoryStream();
Serializer.Serialize(stream, message);
return stream.ToArray();
}
public static void ToStream(object message, MemoryStream stream)
{
Serializer.Serialize(stream, message);
}
public static object FromStream(Type type, MemoryStream stream)
{
return Serializer.Deserialize(type, stream);
}
public static T FromStream<T>(MemoryStream stream)
{
return (T) Serializer.Deserialize(typeof(T), stream);
}
public static T Clone<T>(T t)
{
var bytes = ToBytes(t);
using var stream = new MemoryStream(bytes, 0, bytes.Length);
return Serializer.Deserialize<T>(stream);
}
}
}

View File

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

View File

@@ -0,0 +1,251 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using TEngine.DataStructure;
namespace TEngine.Core
{
public static class RandomHelper
{
private static readonly Random Random = new Random();
private static readonly byte[] Byte8 = new byte[8];
private static readonly byte[] Byte2 = new byte[2];
public static ulong RandUInt64()
{
Random.NextBytes(Byte8);
return BitConverter.ToUInt64(Byte8, 0);
}
public static long RandInt64()
{
Random.NextBytes(Byte8);
return BitConverter.ToInt64(Byte8, 0);
}
public static uint RandUInt32()
{
return (uint) Random.Next();
}
public static ushort RandUInt16()
{
Random.NextBytes(Byte2);
return BitConverter.ToUInt16(Byte2, 0);
}
/// <summary>
/// 获取lower与Upper之间的随机数,包含下限,不包含上限
/// </summary>
/// <param name="lower"></param>
/// <param name="upper"></param>
/// <returns></returns>
public static int RandomNumber(int lower, int upper)
{
return Random.Next(lower, upper);
}
public static bool RandomBool()
{
return Random.Next(2) == 0;
}
public static T RandomArray<T>(this T[] array)
{
return array[RandomNumber(0, array.Count() - 1)];
}
public static T RandomArray<T>(this List<T> array)
{
return array[RandomNumber(0, array.Count() - 1)];
}
/// <summary>
/// 打乱数组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr">要打乱的数组</param>
public static void BreakRank<T>(List<T> arr)
{
if (arr == null || arr.Count < 2)
{
return;
}
for (var i = 0; i < arr.Count / 2; i++)
{
var index = Random.Next(0, arr.Count);
(arr[index], arr[arr.Count - index - 1]) = (arr[arr.Count - index - 1], arr[index]);
}
}
public static float RandFloat01()
{
var value = Random.NextDouble();
return (float) value;
}
private static int Rand(int n)
{
var rd = new Random();
// 注意返回值是左闭右开所以maxValue要加1
return rd.Next(1, n + 1);
}
/// <summary>
/// 通过权重随机
/// </summary>
/// <param name="weights"></param>
/// <returns></returns>
public static int RandomByWeight(int[] weights)
{
var sum = weights.Sum();
var numberRand = Rand(sum);
var sumTemp = 0;
for (var i = 0; i < weights.Length; i++)
{
sumTemp += weights[i];
if (numberRand <= sumTemp)
{
return i;
}
}
return -1;
}
/// <summary>
/// 固定概率的随机、就是某数值上限里比出多少次
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static int RandomByFixedProbability(int[] args)
{
var argCount = args.Length;
var sum = args.Sum();
var random = Random.NextDouble() * sum;
while (sum > random)
{
sum -= args[argCount - 1];
argCount--;
}
return argCount;
}
/// <summary>
/// 返回随机数。
/// </summary>
/// <param name="containNegative">是否包含负数。</param>
/// <returns>返回一个随机的单精度浮点数。</returns>
public static float NextFloat(bool containNegative = false)
{
float f;
var buffer = new byte[4];
if (containNegative)
{
do
{
Random.NextBytes(buffer);
f = BitConverter.ToSingle(buffer, 0);
} while ((f >= float.MinValue && f < float.MaxValue) == false);
return f;
}
do
{
Random.NextBytes(buffer);
f = BitConverter.ToSingle(buffer, 0);
} while ((f >= 0 && f < float.MaxValue) == false);
return f;
}
/// <summary>
/// 返回一个小于所指定最大值的非负随机数。
/// </summary>
/// <param name="maxValue">要生成的随机数的上限(随机数不能取该上限值)。 maxValue 必须大于或等于零。</param>
/// <returns>大于等于零且小于 maxValue 的单精度浮点数,即:返回值的范围通常包括零但不包括 maxValue。 不过,如果 maxValue 等于零,则返回 maxValue。</returns>
public static float NextFloat(float maxValue)
{
if (maxValue.Equals(0))
{
return maxValue;
}
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException("“maxValue”必须大于 0。", "maxValue");
}
float f;
var buffer = new byte[4];
do
{
Random.NextBytes(buffer);
f = BitConverter.ToSingle(buffer, 0);
} while ((f >= 0 && f < maxValue) == false);
return f;
}
/// <summary>
/// 返回一个指定范围内的随机数。
/// </summary>
/// <param name="minValue">返回的随机数的下界(随机数可取该下界值)。</param>
/// <param name="maxValue">返回的随机数的上界(随机数不能取该上界值)。 maxValue 必须大于或等于 minValue。</param>
/// <returns>一个大于等于 minValue 且小于 maxValue 的单精度浮点数,即:返回的值范围包括 minValue 但不包括 maxValue。 如果 minValue 等于 maxValue则返回 minValue。</returns>
public static float NextFloat(float minValue, float maxValue)
{
if (minValue.Equals(maxValue))
{
return minValue;
}
if (minValue > maxValue)
{
throw new ArgumentOutOfRangeException("“minValue”不能大于 maxValue。", "minValue");
}
float f;
var buffer = new byte[4];
do
{
Random.NextBytes(buffer);
f = BitConverter.ToSingle(buffer, 0);
} while ((f >= minValue && f < maxValue) == false);
return f;
}
/// <summary>
/// 在4个Vector2点范围内随机出一个位置
/// </summary>
/// <param name="minX">X轴最小值</param>
/// <param name="maxX">X轴最大值</param>
/// <param name="minY">Y轴最小值</param>
/// <param name="maxY">Y轴最大值</param>
/// <returns></returns>
public static Vector2 NextVector2(float minX, float maxX, float minY, float maxY)
{
return new Vector2(NextFloat(minX, maxX), NextFloat(minY, maxY));
}
public static string RandomNumberCode(int len = 6)
{
int num = 0;
for (int i = 0; i < len; i++)
{
int number = RandomNumber(0, 10);
num = num * 10 + number;
}
return num.ToString();
}
}
}

View File

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

View File

@@ -0,0 +1,36 @@
using System;
namespace TEngine.Core
{
public static class TimeHelper
{
public const long Hour = 3600000; // 小时毫秒值 60 * 60 * 1000
public const long Minute = 60000; // 分钟毫秒值 60 * 1000
public const long OneDay = 86400000; // 天毫秒值 24 * 60 * 60 * 1000
private const long Epoch = 621355968000000000L; // 1970年1月1日的Ticks
private static readonly DateTime Dt1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long Now => (DateTime.UtcNow.Ticks - Epoch) / 10000;
#if TENGINE_UNITY
public static long TimeDiff;
public static long ServerNow => Now + TimeDiff;
#endif
public static long Transition(DateTime d)
{
return (d.Ticks - Epoch) / 10000;
}
public static DateTime Transition(long timeStamp)
{
return Dt1970.AddTicks(timeStamp);
}
public static DateTime TransitionLocal(long timeStamp)
{
return Dt1970.AddTicks(timeStamp).ToLocalTime();
}
}
}

View File

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