Compare commits

...

17 Commits

Author SHA1 Message Date
ALEXTANGXIAO
95dfac5294 支持普通协议对象数据结构不加入opcode
支持普通协议对象数据结构不加入opcode
2023-09-06 00:13:14 +08:00
ALEXTANGXIAO
14e95107c9 服务器ByteBuf消除警告
服务器ByteBuf消除警告
2023-09-05 23:57:12 +08:00
ALEXTANGXIAO
caf5b2b54e 导出网络协议增加了缓存文件保证一致性
导出网络协议增加了缓存文件保证一致性
2023-09-05 23:56:50 +08:00
ALEXTANG
285483034e Update Exporter.cs 2023-09-05 21:08:54 +08:00
ALEXTANG
1cdd8b63b4 同步服务器导出SceneType
同步服务器导出SceneType
2023-09-05 21:07:33 +08:00
ALEXTANG
4c748df7ac Update ProcedureInitPackage.cs 2023-09-05 20:53:56 +08:00
ALEXTANG
e1229b5a4b 移除无用Extension
移除无用Extension
2023-09-05 20:28:37 +08:00
ALEXTANG
b937fb1a37 [-] 移除Luban无用转表bat
[-] 移除Luban无用转表bat
2023-09-05 19:08:02 +08:00
ALEXTANG
87ab99b363 修复了KCPClientNetwork断开网络连接会发生异常的问题
修复了KCPClientNetwork断开网络连接会发生异常的问题
2023-09-05 14:39:53 +08:00
ALEXTANG
e3a47393f4 [+] 新增游戏物体缓存池ResourcePool
[+] 新增游戏物体缓存池ResourcePool
2023-09-05 14:35:19 +08:00
ALEXTANG
75725314ad FIxed 网络模块对象池复使用问题
FIxed 网络模块对象池复使用问题
2023-09-04 10:06:20 +08:00
ALEXTANG
d3ed2b21b9 Update AudioModule.cs 2023-08-28 20:53:40 +08:00
ALEXTANG
ec34dfbb16 Delete protobuf-net.csproj.meta 2023-08-28 20:41:10 +08:00
ALEXTANG
bd76e3a651 移除示例配置资源.
移除示例配置资源.
2023-08-28 20:35:30 +08:00
ALEXTANG
278c8f23be Update DefaultSettingSerializer.cs 2023-08-28 20:24:31 +08:00
ALEXTANG
42568db2ab Add System.Runtime.CompilerServices.Unsafe.dll
Add System.Runtime.CompilerServices.Unsafe.dll
2023-08-28 20:13:06 +08:00
ALEXTANG
b033c59b00 Aot程序集不查找热更域的Type
Aot程序集不查找热更域的Type
2023-08-28 15:08:18 +08:00
51 changed files with 1462 additions and 477 deletions

1
.gitignore vendored
View File

@@ -130,3 +130,4 @@ Bin/
#Server_Config #Server_Config
DotNet/Config/GameConfig DotNet/Config/GameConfig
DotNet/Config/ProtoBuf/OpCode.Cache

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 8f3bcefaf67e76141a6d8edeb8354fea
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 25113973d38eb5a48b064863830539a4
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: ef51ed54e72f97a4ab530b932680e08b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 090163c612f34ac4fb80004ac5f057b4
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -70,6 +70,10 @@ public static class Define
/// </summary> /// </summary>
public static string ClientCustomExportDirectory; public static string ClientCustomExportDirectory;
/// <summary> /// <summary>
/// SceneConfig.xlsx的位置
/// </summary>
public static string SceneConfigPath;
/// <summary>
/// 自定义导出代码存放的程序集 /// 自定义导出代码存放的程序集
/// </summary> /// </summary>
public static string CustomExportAssembly; public static string CustomExportAssembly;

View File

@@ -1,12 +1,34 @@
#if TENGINE_NET #if TENGINE_NET
namespace TEngine.Core; namespace TEngine.Core;
/// <summary>
/// 导出类型枚举,用于标识不同类型的导出操作。
/// </summary>
public enum ExportType public enum ExportType
{ {
/// <summary>
/// 无导出类型。
/// </summary>
None = 0, None = 0,
ProtoBuf = 1, // 导出ProtoBuf /// <summary>
AllExcelIncrement = 2, // 所有-增量导出Excel /// 导出ProtoBuf类型。
AllExcel = 3, // 所有-全量导出Excel /// </summary>
Max, // 这个一定放最后 ProtoBuf = 1,
/// <summary>
/// 导出网络协议并重新生成OpCode。
/// </summary>
ProtoBufAndOpCodeCache = 2,
/// <summary>
/// 所有数据的增量导出Excel类型。
/// </summary>
AllExcelIncrement = 3,
/// <summary>
/// 所有数据的全量导出Excel类型。
/// </summary>
AllExcel = 4,
/// <summary>
/// 导出类型枚举的最大值,一定要放在最后。
/// </summary>
Max,
} }
#endif #endif

View File

@@ -3,16 +3,21 @@ using System.Diagnostics;
using System.Reflection; using System.Reflection;
using System.Runtime.Loader; using System.Runtime.Loader;
using System.Text; using System.Text;
using TEngine.Core; using TEngine.Helper;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
#pragma warning disable CS8601 #pragma warning disable CS8601
#pragma warning disable CS8618
namespace TEngine.Core; namespace TEngine.Core;
/// <summary>
/// 数据导出器,用于执行导出操作。
/// </summary>
public sealed class Exporter public sealed class Exporter
{ {
/// <summary>
/// 开始执行数据导出操作。
/// </summary>
public void Start() public void Start()
{ {
Console.OutputEncoding = Encoding.UTF8; Console.OutputEncoding = Encoding.UTF8;
@@ -25,8 +30,9 @@ public sealed class Exporter
LogInfo("请输入你想要做的操作:"); LogInfo("请输入你想要做的操作:");
LogInfo("1:导出网络协议ProtoBuf"); LogInfo("1:导出网络协议ProtoBuf");
LogInfo("2:增量导出服务器启动Excel包含常量枚举"); LogInfo("2:导出网络协议并重新生成OpCodeProtoBuf");
LogInfo("3:量导出服务器启动Excel包含常量枚举"); LogInfo("3:量导出Excel包含常量枚举");
LogInfo("4:全量导出Excel包含常量枚举");
var keyChar = Console.ReadKey().KeyChar; var keyChar = Console.ReadKey().KeyChar;
@@ -39,13 +45,17 @@ public sealed class Exporter
LogInfo(""); LogInfo("");
exportType = (ExportType) key; exportType = (ExportType) key;
// LoadConfig();
switch (exportType) switch (exportType)
{ {
case ExportType.ProtoBuf: case ExportType.ProtoBuf:
{ {
_ = new ProtoBufExporter(); _ = new ProtoBufExporter(false);
break;
}
case ExportType.ProtoBufAndOpCodeCache:
{
_ = new ProtoBufExporter(true);
break; break;
} }
case ExportType.AllExcel: case ExportType.AllExcel:
@@ -61,58 +71,19 @@ public sealed class Exporter
Environment.Exit(0); Environment.Exit(0);
} }
#if old /// <summary>
// private void LoadConfig() /// 输出信息到控制台。
// { /// </summary>
// const string settingsName = "TEngineSettings.json"; /// <param name="msg">要输出的信息。</param>
// var currentDirectory = Directory.GetCurrentDirectory();
//
// if (!File.Exists(Path.Combine(currentDirectory, settingsName)))
// {
// throw new FileNotFoundException($"not found {settingsName} in OutputDirectory");
// }
//
// var configurationRoot = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
// .AddJsonFile(settingsName)
// .Build();
// // ProtoBuf文件所在的位置文件夹位置
// ProtoBufDefine.ProtoBufDirectory = configurationRoot["Export:ProtoBufDirectory:Value"];
// // ProtoBuf生成到服务端的文件夹位置
// ProtoBufDefine.ServerDirectory = configurationRoot["Export:ProtoBufServerDirectory:Value"];
// // ProtoBuf生成到客户端的文件夹位置
// ProtoBufDefine.ClientDirectory = configurationRoot["Export:ProtoBufClientDirectory:Value"];
// // ProtoBuf生成代码模板的位置
// ProtoBufDefine.ProtoBufTemplatePath = configurationRoot["Export:ProtoBufTemplatePath:Value"];
// // Excel配置文件根目录
// ExcelDefine.ProgramPath = configurationRoot["Export:ExcelProgramPath:Value"];
// // Excel版本文件的位置
// ExcelDefine.ExcelVersionFile = configurationRoot["Export:ExcelVersionFile:Value"];
// // Excel生成服务器代码的文件夹位置
// ExcelDefine.ServerFileDirectory = configurationRoot["Export:ExcelServerFileDirectory:Value"];
// // Excel生成客户端代码文件夹位置
// ExcelDefine.ClientFileDirectory = configurationRoot["Export:ExcelClientFileDirectory:Value"];
// // Excel生成服务器二进制数据文件夹位置
// ExcelDefine.ServerBinaryDirectory = configurationRoot["Export:ExcelServerBinaryDirectory:Value"];
// // Excel生成客户端二进制数据文件夹位置
// ExcelDefine.ClientBinaryDirectory = configurationRoot["Export:ExcelClientBinaryDirectory:Value"];
// // Excel生成服务器Json数据文件夹位置
// ExcelDefine.ServerJsonDirectory = configurationRoot["Export:ExcelServerJsonDirectory:Value"];
// // Excel生成客户端Json数据文件夹位置
// ExcelDefine.ClientJsonDirectory = configurationRoot["Export:ExcelClientJsonDirectory:Value"];
// // Excel生成代码模板的位置
// ExcelDefine.ExcelTemplatePath = configurationRoot["Export:ExcelTemplatePath:Value"];
// // 服务器自定义导出代码文件夹位置
// ExcelDefine.ServerCustomExportDirectory = configurationRoot["Export:ServerCustomExportDirectory:Value"];
// // 客户端自定义导出代码文件夹位置
// ExcelDefine.ClientCustomExportDirectory = configurationRoot["Export:ClientCustomExportDirectory:Value"];
// }
#endif
public static void LogInfo(string msg) public static void LogInfo(string msg)
{ {
Console.WriteLine(msg); Console.WriteLine(msg);
} }
/// <summary>
/// 输出错误信息到控制台。
/// </summary>
/// <param name="msg">要输出的错误信息。</param>
public static void LogError(string msg) public static void LogError(string msg)
{ {
ConsoleColor color = Console.ForegroundColor; ConsoleColor color = Console.ForegroundColor;
@@ -121,6 +92,10 @@ public sealed class Exporter
Console.ForegroundColor = color; Console.ForegroundColor = color;
} }
/// <summary>
/// 输出异常信息到控制台。
/// </summary>
/// <param name="e">要输出的异常。</param>
public static void LogError(Exception e) public static void LogError(Exception e)
{ {
ConsoleColor color = Console.ForegroundColor; ConsoleColor color = Console.ForegroundColor;

View File

@@ -0,0 +1,60 @@
#if TENGINE_NET
using TEngine.Helper;
namespace TEngine.Core;
/// <summary>
/// 网络协议操作码缓存。
/// </summary>
public class OpCodeCache
{
private readonly List<uint> _opCodes = new List<uint>();
private readonly SortedDictionary<string, uint> _opcodeCache;
private readonly SortedDictionary<string, uint> _saveOpCodeCache = new();
private readonly string _opcodeCachePath = $"{Define.ProtoBufDirectory}OpCode.Cache";
/// <summary>
/// 构造函数,用于初始化网络协议操作码缓存。
/// </summary>
public OpCodeCache(bool regenerate)
{
if (File.Exists(_opcodeCachePath) && !regenerate)
{
var readAllText = File.ReadAllText(_opcodeCachePath);
_opcodeCache = readAllText.Deserialize<SortedDictionary<string, uint>>();
_opCodes.AddRange(_opcodeCache.Values);
}
else
{
_opcodeCache = new SortedDictionary<string, uint>();
}
}
/// <summary>
/// 保存网络协议操作码。
/// </summary>
public void Save()
{
File.WriteAllText(_opcodeCachePath, _saveOpCodeCache.ToJson());
}
/// <summary>
/// 根据className获得OpCode、如果是新增的会产生一个新的OpCode。
/// </summary>
/// <param name="className">协议名。</param>
/// <param name="opcode">操作码。</param>
/// <returns></returns>
public uint GetOpcodeCache(string className, ref uint opcode)
{
if (!_opcodeCache.TryGetValue(className, out var opCode))
{
while (_opCodes.Contains(++opcode)) { }
opCode = opcode;
_opCodes.Add(opCode);
}
_saveOpCodeCache.Add(className, opCode);
return opCode;
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e0f0d02da06c4ca981417bfe43162809
timeCreated: 1693928511

View File

@@ -1,28 +1,52 @@
#if TENGINE_NET #if TENGINE_NET
using System.Text; using System.Text;
using TEngine.Core.Network; using TEngine.Core.Network;
using TEngine.Helper;
#pragma warning disable CS8604
#pragma warning disable CS8602
#pragma warning disable CS8600
#pragma warning disable CS8618
namespace TEngine.Core; namespace TEngine.Core;
/// <summary>
/// ProtoBuf操作码类型枚举
/// </summary>
public enum ProtoBufOpCodeType public enum ProtoBufOpCodeType
{ {
/// <summary>
/// 无
/// </summary>
None = 0, None = 0,
/// <summary>
/// 外部操作码类型
/// </summary>
Outer = 1, Outer = 1,
/// <summary>
/// 内部操作码类型
/// </summary>
Inner = 2, Inner = 2,
/// <summary>
/// 使用BSON的内部操作码类型
/// </summary>
InnerBson = 3, InnerBson = 3,
} }
/// <summary>
/// 操作码信息类
/// </summary>
public sealed class OpcodeInfo public sealed class OpcodeInfo
{ {
/// <summary>
/// 操作码
/// </summary>
public uint Code; public uint Code;
/// <summary>
/// 名称
/// </summary>
public string Name; public string Name;
} }
/// <summary>
/// ProtoBuf导出器类
/// </summary>
public sealed class ProtoBufExporter public sealed class ProtoBufExporter
{ {
private uint _aMessage; private uint _aMessage;
@@ -33,10 +57,13 @@ public sealed class ProtoBufExporter
private uint _aRouteResponse; private uint _aRouteResponse;
private string _serverTemplate; private string _serverTemplate;
private string _clientTemplate; private string _clientTemplate;
private readonly OpCodeCache _opCodeCache;
private readonly List<OpcodeInfo> _opcodes = new(); private readonly List<OpcodeInfo> _opcodes = new();
public ProtoBufExporter() /// <summary>
/// 构造函数,用于初始化导出器
/// </summary>
public ProtoBufExporter(bool regenerateOpCodeCache)
{ {
Console.OutputEncoding = Encoding.UTF8; Console.OutputEncoding = Encoding.UTF8;
@@ -60,11 +87,13 @@ public sealed class ProtoBufExporter
Directory.CreateDirectory($"{Define.ProtoBufDirectory}Inner"); Directory.CreateDirectory($"{Define.ProtoBufDirectory}Inner");
} }
if (!Directory.Exists($"{Define.ProtoBufDirectory}Bson")) if (!Directory.Exists($"{Define.ProtoBufDirectory}InnerBosn"))
{ {
Directory.CreateDirectory($"{Define.ProtoBufDirectory}Bson"); Directory.CreateDirectory($"{Define.ProtoBufDirectory}InnerBosn");
} }
_opCodeCache = new OpCodeCache(regenerateOpCodeCache);
var tasks = new Task[2]; var tasks = new Task[2];
tasks[0] = Task.Run(RouteType); tasks[0] = Task.Run(RouteType);
tasks[1] = Task.Run(async () => tasks[1] = Task.Run(async () =>
@@ -75,6 +104,7 @@ public sealed class ProtoBufExporter
await Start(ProtoBufOpCodeType.InnerBson); await Start(ProtoBufOpCodeType.InnerBson);
}); });
Task.WaitAll(tasks); Task.WaitAll(tasks);
_opCodeCache.Save();
} }
private async Task Start(ProtoBufOpCodeType opCodeType) private async Task Start(ProtoBufOpCodeType opCodeType)
@@ -99,8 +129,9 @@ public sealed class ProtoBufExporter
opCodeName = "OuterOpcode"; opCodeName = "OuterOpcode";
saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate); saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate);
saveDirectory.Add(Define.ProtoBufClientDirectory, _clientTemplate); saveDirectory.Add(Define.ProtoBufClientDirectory, _clientTemplate);
files.Add($"{Define.ProtoBufDirectory}OuterMessage.proto"); var protoBufFiles = FileHelper.GetDirectoryFile(
files.AddRange(Directory.GetFiles($"{Define.ProtoBufDirectory}Outer").ToList()); $"{Define.ProtoBufDirectory}Outer", "*.proto", SearchOption.AllDirectories);
files.AddRange(protoBufFiles);
break; break;
} }
case ProtoBufOpCodeType.Inner: case ProtoBufOpCodeType.Inner:
@@ -114,8 +145,8 @@ public sealed class ProtoBufExporter
_aRouteResponse = Opcode.InnerRouteResponse + 1000; _aRouteResponse = Opcode.InnerRouteResponse + 1000;
opCodeName = "InnerOpcode"; opCodeName = "InnerOpcode";
saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate); saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate);
files.Add($"{Define.ProtoBufDirectory}InnerMessage.proto"); var protoBufFiles = FileHelper.GetDirectoryFile($"{Define.ProtoBufDirectory}Inner", "*.proto", SearchOption.AllDirectories);
files.AddRange(Directory.GetFiles($"{Define.ProtoBufDirectory}Inner").ToList()); files.AddRange(protoBufFiles);
break; break;
} }
case ProtoBufOpCodeType.InnerBson: case ProtoBufOpCodeType.InnerBson:
@@ -129,8 +160,8 @@ public sealed class ProtoBufExporter
_aRouteResponse = Opcode.InnerBsonRouteResponse + 1000; _aRouteResponse = Opcode.InnerBsonRouteResponse + 1000;
opCodeName = "InnerBsonOpcode"; opCodeName = "InnerBsonOpcode";
saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate); saveDirectory.Add(Define.ProtoBufServerDirectory, _serverTemplate);
files.Add($"{Define.ProtoBufDirectory}InnerBsonMessage.proto"); var protoBufFiles = FileHelper.GetDirectoryFile($"{Define.ProtoBufDirectory}InnerBosn", "*.proto", SearchOption.AllDirectories);
files.AddRange(Directory.GetFiles($"{Define.ProtoBufDirectory}Bson").ToList()); files.AddRange(protoBufFiles);
break; break;
} }
} }
@@ -143,10 +174,13 @@ public sealed class ProtoBufExporter
var isMsgHead = false; var isMsgHead = false;
string responseTypeStr = null; string responseTypeStr = null;
string customRouteType = null; string customRouteType = null;
var protoFileText = await File.ReadAllTextAsync(filePath); var protoFileText = await File.ReadAllTextAsync(filePath);
foreach (var line in protoFileText.Split('\n')) foreach (var line in protoFileText.Split('\n'))
{ {
bool hadOpCode = true;
var currentLine = line.Trim(); var currentLine = line.Trim();
if (string.IsNullOrWhiteSpace(currentLine)) if (string.IsNullOrWhiteSpace(currentLine))
@@ -176,17 +210,20 @@ public sealed class ProtoBufExporter
switch (parameterArray.Length) switch (parameterArray.Length)
{ {
case 2: case 2:
responseTypeStr = parameterArray[1].Trim(); {
break; if (parameter == "ICustomRouteMessage")
case 3:
{ {
customRouteType = parameterArray[1].Trim(); customRouteType = parameterArray[1].Trim();
break;
if (parameterArray.Length == 3)
{
responseTypeStr = parameterArray[2].Trim();
} }
responseTypeStr = parameterArray[1].Trim();
break;
}
case 3:
{
responseTypeStr = parameterArray[1].Trim();
customRouteType = parameterArray[2].Trim();
break; break;
} }
} }
@@ -214,9 +251,13 @@ public sealed class ProtoBufExporter
{ {
file.AppendLine("\n\t{"); file.AppendLine("\n\t{");
if (string.IsNullOrWhiteSpace(parameter) || parameter == "IMessage") if (string.IsNullOrWhiteSpace(parameter))
{ {
opcodeInfo.Code += ++_aMessage; hadOpCode = false;
}
else if(parameter == "IMessage")
{
opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aMessage);
file.AppendLine($"\t\tpublic uint OpCode() {{ return {opCodeName}.{className}; }}"); file.AppendLine($"\t\tpublic uint OpCode() {{ return {opCodeName}.{className}; }}");
} }
else else
@@ -260,13 +301,13 @@ public sealed class ProtoBufExporter
case "IRequest": case "IRequest":
case "IBsonRequest": case "IBsonRequest":
{ {
opcodeInfo.Code += ++_aRequest; opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRequest);
break; break;
} }
case "IResponse": case "IResponse":
case "IBsonResponse": case "IBsonResponse":
{ {
opcodeInfo.Code += ++_aResponse; opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aResponse);
file.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]"); file.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]");
file.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); file.AppendLine("\t\tpublic uint ErrorCode { get; set; }");
break; break;
@@ -275,15 +316,15 @@ public sealed class ProtoBufExporter
{ {
if (parameter.EndsWith("RouteMessage") || parameter == "IRouteMessage") if (parameter.EndsWith("RouteMessage") || parameter == "IRouteMessage")
{ {
opcodeInfo.Code += ++_aRouteMessage; opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRouteMessage);
} }
else if (parameter.EndsWith("RouteRequest") || parameter == "IRouteRequest") else if (parameter.EndsWith("RouteRequest") || parameter == "IRouteRequest")
{ {
opcodeInfo.Code += ++_aRouteRequest; opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRouteRequest);
} }
else if (parameter.EndsWith("RouteResponse") || parameter == "IRouteResponse") else if (parameter.EndsWith("RouteResponse") || parameter == "IRouteResponse")
{ {
opcodeInfo.Code += ++_aRouteResponse; opcodeInfo.Code = _opCodeCache.GetOpcodeCache(className, ref _aRouteResponse);
file.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]"); file.AppendLine("\t\t[ProtoMember(91, IsRequired = true)]");
file.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); file.AppendLine("\t\tpublic uint ErrorCode { get; set; }");
} }
@@ -293,7 +334,10 @@ public sealed class ProtoBufExporter
} }
} }
if (hadOpCode)
{
_opcodes.Add(opcodeInfo); _opcodes.Add(opcodeInfo);
}
continue; continue;
} }
case "}": case "}":
@@ -359,7 +403,6 @@ public sealed class ProtoBufExporter
var csFile = Path.Combine(directory, $"{opCodeName}.cs"); var csFile = Path.Combine(directory, $"{opCodeName}.cs");
await File.WriteAllTextAsync(csFile, file.ToString()); await File.WriteAllTextAsync(csFile, file.ToString());
} }
#endregion #endregion
} }
@@ -479,6 +522,9 @@ public sealed class ProtoBufExporter
} }
} }
/// <summary>
/// 加载模板
/// </summary>
private void LoadTemplate() private void LoadTemplate()
{ {
string[] lines = File.ReadAllLines(Define.ProtoBufTemplatePath, Encoding.UTF8); string[] lines = File.ReadAllLines(Define.ProtoBufTemplatePath, Encoding.UTF8);

View File

@@ -1,26 +1,29 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
namespace TEngine.Core namespace TEngine
{ {
/// <summary>
/// 文件操作助手类,提供了各种文件操作方法。
/// </summary>
public static class FileHelper public static class FileHelper
{ {
/// <summary> /// <summary>
/// 获取文件全路径。 /// 获取相对路径的完整路径。
/// </summary> /// </summary>
/// <param name="relativePath"></param> /// <param name="relativePath">相对路径。</param>
/// <returns></returns> /// <returns>完整路径。</returns>
public static string GetFullPath(string relativePath) public static string GetFullPath(string relativePath)
{ {
return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath)); return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath));
} }
/// <summary> /// <summary>
/// 拷贝文件到目标路径如果目标目录不存在会自动创建目录 /// 将文件复制到目标路径如果目标目录不存在会自动创建目录
/// </summary> /// </summary>
/// <param name="sourceFile"></param> /// <param name="sourceFile">源文件路径。</param>
/// <param name="destinationFile"></param> /// <param name="destinationFile">目标文件路径。</param>
/// <param name="overwrite"></param> /// <param name="overwrite">是否覆盖已存在的目标文件。</param>
public static void Copy(string sourceFile, string destinationFile, bool overwrite) public static void Copy(string sourceFile, string destinationFile, bool overwrite)
{ {
var directoriesByFilePath = GetDirectoriesByFilePath(destinationFile); var directoriesByFilePath = GetDirectoriesByFilePath(destinationFile);
@@ -39,10 +42,10 @@ namespace TEngine.Core
} }
/// <summary> /// <summary>
/// 获取文件路径内的所有文件夹路径 /// 获取文件路径内的所有文件夹路径
/// </summary> /// </summary>
/// <param name="filePath"></param> /// <param name="filePath">文件路径。</param>
/// <returns></returns> /// <returns>文件夹路径列表。</returns>
public static List<string> GetDirectoriesByFilePath(string filePath) public static List<string> GetDirectoriesByFilePath(string filePath)
{ {
var dir = ""; var dir = "";
@@ -59,11 +62,11 @@ namespace TEngine.Core
} }
/// <summary> /// <summary>
/// 文件夹所有内容拷贝的目标位置 /// 文件夹内的所有内容复制到目标位置
/// </summary> /// </summary>
/// <param name="sourceDirectory"></param> /// <param name="sourceDirectory">源文件夹路径。</param>
/// <param name="destinationDirectory"></param> /// <param name="destinationDirectory">目标文件夹路径。</param>
/// <param name="overwrite"></param> /// <param name="overwrite">是否覆盖已存在的文件。</param>
public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite) public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite)
{ {
// 创建目标文件夹 // 创建目标文件夹
@@ -101,9 +104,21 @@ namespace TEngine.Core
} }
/// <summary> /// <summary>
/// 清除文件夹里的所有文件 /// 获取目录下的所有文件
/// </summary> /// </summary>
/// <param name="folderPath"></param> /// <param name="folderPath">文件夹路径。</param>
/// <param name="searchPattern">需要查找的文件通配符</param>
/// <param name="searchOption">查找的类型</param>
/// <returns></returns>
public static string[] GetDirectoryFile(string folderPath, string searchPattern, SearchOption searchOption)
{
return Directory.GetFiles(folderPath, searchPattern, searchOption);
}
/// <summary>
/// 清空文件夹内的所有文件。
/// </summary>
/// <param name="folderPath">文件夹路径。</param>
public static void ClearDirectoryFile(string folderPath) public static void ClearDirectoryFile(string folderPath)
{ {
if (!Directory.Exists(folderPath)) if (!Directory.Exists(folderPath))

View File

@@ -9,6 +9,7 @@ namespace TEngine.Core.Network
{ {
try try
{ {
DisposePackInfo = false;
switch (packInfo.ProtocolCode) switch (packInfo.ProtocolCode)
{ {
case > Opcode.InnerRouteResponse: case > Opcode.InnerRouteResponse:

View File

@@ -56,7 +56,6 @@ namespace TEngine.Core.Network
ThreadSynchronizationContext.Main.Post(OnConnectDisconnect); ThreadSynchronizationContext.Main.Post(OnConnectDisconnect);
} }
_socket.Disconnect(false);
_socket.Close(); _socket.Close();
} }

View File

@@ -69,6 +69,8 @@ public static class TEngineSettingsHelper
Define.ServerCustomExportDirectory = FileHelper.GetFullPath(root["Export:ServerCustomExportDirectory:Value"]); Define.ServerCustomExportDirectory = FileHelper.GetFullPath(root["Export:ServerCustomExportDirectory:Value"]);
// 客户端自定义导出代码 // 客户端自定义导出代码
Define.ClientCustomExportDirectory = FileHelper.GetFullPath(root["Export:ClientCustomExportDirectory:Value"]); Define.ClientCustomExportDirectory = FileHelper.GetFullPath(root["Export:ClientCustomExportDirectory:Value"]);
// SceneConfig.xlsx的位置
Define.SceneConfigPath = FileHelper.GetFullPath(root["Export:SceneConfigPath:Value"]);
// 自定义导出代码存放的程序集 // 自定义导出代码存放的程序集
Define.CustomExportAssembly = FileHelper.GetFullPath(root["Export:CustomExportAssembly:Value"]); Define.CustomExportAssembly = FileHelper.GetFullPath(root["Export:CustomExportAssembly:Value"]);
} }

View File

@@ -24,6 +24,8 @@ namespace GameMain
private async UniTaskVoid InitPackage(ProcedureOwner procedureOwner) private async UniTaskVoid InitPackage(ProcedureOwner procedureOwner)
{ {
if (GameModule.Resource.PlayMode == EPlayMode.HostPlayMode) if (GameModule.Resource.PlayMode == EPlayMode.HostPlayMode)
{
if (SettingsUtils.EnableUpdateData())
{ {
UpdateData updateData = await RequestUpdateData(); UpdateData updateData = await RequestUpdateData();
@@ -39,6 +41,7 @@ namespace GameMain
} }
} }
} }
}
var initializationOperation = GameModule.Resource.InitPackage(); var initializationOperation = GameModule.Resource.InitPackage();

View File

@@ -14,10 +14,6 @@ namespace TEngine.Editor
"Assembly-CSharp", "Assembly-CSharp",
"GameMain.Runtime", "GameMain.Runtime",
"GameMain", "GameMain",
"GameBase",
"GameLogic",
"GameProto",
"BattleCore.Runtime",
}; };
private static readonly string[] RuntimeOrEditorAssemblyNames = private static readonly string[] RuntimeOrEditorAssemblyNames =
@@ -27,11 +23,7 @@ namespace TEngine.Editor
"TEngine.Editor", "TEngine.Editor",
"Assembly-CSharp-Editor", "Assembly-CSharp-Editor",
"GameMain", "GameMain",
"GameMain.Editor", "GameMain.Editor"
"GameBase",
"GameLogic",
"GameProto",
"BattleCore.Runtime",
}; };
/// <summary> /// <summary>

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 4029d25cf768d5440b7366c5e62c963f
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,134 +0,0 @@
using System;
using System.Diagnostics;
using UnityEngine;
#if !ODIN_INSPECTOR
namespace Sirenix.OdinInspector
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
[Conditional("UNITY_EDITOR")]
public class ButtonAttribute : Attribute
{
public ButtonAttribute()
{
}
public ButtonAttribute(string name)
{
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
[Conditional("UNITY_EDITOR")]
public sealed class ReadOnlyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
[Conditional("UNITY_EDITOR")]
public class ShowInInspectorAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
[Conditional("UNITY_EDITOR")]
public sealed class HideIfAttribute : Attribute
{
public string MemberName;
public object Value;
public bool Animate;
public HideIfAttribute(string memberName, bool animate = true)
{
this.MemberName = memberName;
this.Animate = animate;
}
}
[DontApplyToListElements]
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
[Conditional("UNITY_EDITOR")]
public sealed class OnValueChangedAttribute : Attribute
{
public string MethodName;
public bool IncludeChildren;
public OnValueChangedAttribute(string methodName, bool includeChildren = false)
{
this.MethodName = methodName;
this.IncludeChildren = includeChildren;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
[Conditional("UNITY_EDITOR")]
public class TableListAttribute : Attribute
{
public int DefaultMinColumnWidth = 40;
public bool DrawScrollView = true;
public int MinScrollViewHeight = 350;
public int CellPadding = 2;
public int NumberOfItemsPerPage;
public bool IsReadOnly;
public bool ShowIndexLabels;
public int MaxScrollViewHeight;
public bool AlwaysExpanded;
public bool HideToolbar;
[SerializeField] [HideInInspector] private bool showPagingHasValue;
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class DontApplyToListElementsAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
[DontApplyToListElements]
[Conditional("UNITY_EDITOR")]
public class PropertySpaceAttribute : Attribute
{
public float SpaceBefore;
public float SpaceAfter;
public PropertySpaceAttribute()
{
this.SpaceBefore = 8f;
this.SpaceAfter = 0.0f;
}
public PropertySpaceAttribute(float spaceBefore)
{
this.SpaceBefore = spaceBefore;
this.SpaceAfter = 0.0f;
}
public PropertySpaceAttribute(float spaceBefore, float spaceAfter)
{
this.SpaceBefore = spaceBefore;
this.SpaceAfter = spaceAfter;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
[Conditional("UNITY_EDITOR")]
public class LabelTextAttribute : Attribute
{
public string Text;
public LabelTextAttribute(string text)
{
this.Text = text;
}
}
}
#endif

View File

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

View File

@@ -1,34 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
public static partial class TransformExtension
{
public static float YDeg(this Transform tran)
{
return tran.eulerAngles.y;
}
public static void RemoveAllChildren(this Transform tran)
{
var count = tran.childCount;
for (int i = 0; i < count; i++)
{
GameObject.DestroyImmediate(tran.GetChild(0).gameObject);
}
}
public static List<Transform> GetAllChildren(this Transform tran)
{
var count = tran.childCount;
List<Transform> allTrans = new List<Transform>();
for (int i = 0; i < count; i++)
{
allTrans.Add(tran.GetChild(i));
}
return allTrans;
}
}
}

View File

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

View File

@@ -23,7 +23,7 @@ namespace TEngine
private float _volume = 1f; private float _volume = 1f;
private bool _enable = true; private bool _enable = true;
private AudioCategory[] _audioCategories = new AudioCategory[(int)AudioType.Max]; private readonly AudioCategory[] _audioCategories = new AudioCategory[(int)AudioType.Max];
private readonly float[] _categoriesVolume = new float[(int)AudioType.Max]; private readonly float[] _categoriesVolume = new float[(int)AudioType.Max];
public readonly Dictionary<string, AssetOperationHandle> AudioClipPool = new Dictionary<string, AssetOperationHandle>(); public readonly Dictionary<string, AssetOperationHandle> AudioClipPool = new Dictionary<string, AssetOperationHandle>();
public IResourceManager ResourceManager; public IResourceManager ResourceManager;
@@ -392,19 +392,20 @@ namespace TEngine
for (int i = 0; i < (int)AudioType.Max; ++i) for (int i = 0; i < (int)AudioType.Max; ++i)
{ {
if (_audioCategories[i] != null) var audioCategory = _audioCategories[i];
if (audioCategory != null)
{ {
for (int j = 0; j < _audioCategories[i].AudioAgents.Count; ++j) for (int j = 0; j < audioCategory.AudioAgents.Count; ++j)
{ {
if (_audioCategories[i].AudioAgents[j] != null) var audioAgent = audioCategory.AudioAgents[j];
if (audioAgent != null)
{ {
_audioCategories[i].AudioAgents[j].Destroy(); audioAgent.Destroy();
_audioCategories[i].AudioAgents[j] = null; audioAgent = null;
} }
} }
} }
audioCategory = null;
_audioCategories[i] = null;
} }
Initialize(); Initialize();
@@ -538,11 +539,11 @@ namespace TEngine
/// </summary> /// </summary>
private void Update() private void Update()
{ {
for (int i = 0; i < _audioCategories.Length; ++i) foreach (var audioCategory in _audioCategories)
{ {
if (_audioCategories[i] != null) if (audioCategory != null)
{ {
_audioCategories[i].Update(GameTime.deltaTime); audioCategory.Update(Time.deltaTime);
} }
} }
} }

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 62c8f710f3264758a89eaefc4ae88921
timeCreated: 1693831262

View File

@@ -0,0 +1,70 @@
using YooAsset;
namespace TEngine
{
public class CreatePoolOperation : GameAsyncOperation
{
private enum ESteps
{
None,
Waiting,
Done,
}
private readonly AssetOperationHandle _handle;
private ESteps _steps = ESteps.None;
internal CreatePoolOperation(AssetOperationHandle handle)
{
_handle = handle;
}
protected override void OnStart()
{
_steps = ESteps.Waiting;
}
protected override void OnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Waiting)
{
if (_handle.IsValid == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle)} is invalid.";
return;
}
if (_handle.IsDone == false)
return;
if (_handle.AssetObject == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle.AssetObject)} is null.";
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
/// <summary>
/// 等待异步实例化结束。
/// </summary>
public void WaitForAsyncComplete()
{
if (_handle != null)
{
if (_steps == ESteps.Done)
return;
_handle.WaitForAsyncComplete();
OnUpdate();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4e1853e7ff624c639fba990079beeee5
timeCreated: 1693831296

View File

@@ -0,0 +1,234 @@
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace TEngine
{
/// <summary>
/// 游戏物体对象池。
/// </summary>
internal class GameObjectPool
{
private readonly GameObject _root;
private readonly Queue<InstantiateOperation> _cacheOperations;
private readonly bool _dontDestroy;
private readonly int _initCapacity;
private readonly int _maxCapacity;
private readonly float _destroyTime;
private float _lastRestoreRealTime = -1f;
/// <summary>
/// 资源句柄。
/// </summary>
public AssetOperationHandle AssetHandle { private set; get; }
/// <summary>
/// 资源定位地址。
/// </summary>
public string Location { private set; get; }
/// <summary>
/// 内部缓存总数。
/// </summary>
public int CacheCount => _cacheOperations.Count;
/// <summary>
/// 外部使用总数。
/// </summary>
public int SpawnCount { private set; get; } = 0;
/// <summary>
/// 是否常驻不销毁。
/// </summary>
public bool DontDestroy => _dontDestroy;
/// <summary>
/// 游戏物体对象池。
/// </summary>
/// <param name="poolingRoot">对象池根节点。</param>
/// <param name="location">资源定位地址。</param>
/// <param name="dontDestroy">是否常驻不销毁。</param>
/// <param name="initCapacity">初始容量。</param>
/// <param name="maxCapacity">最大容量。</param>
/// <param name="destroyTime">对象池销毁时间。</param>
public GameObjectPool(GameObject poolingRoot, string location, bool dontDestroy, int initCapacity, int maxCapacity, float destroyTime)
{
_root = new GameObject(location);
_root.transform.parent = poolingRoot.transform;
Location = location;
_dontDestroy = dontDestroy;
_initCapacity = initCapacity;
_maxCapacity = maxCapacity;
_destroyTime = destroyTime;
// 创建缓存池
_cacheOperations = new Queue<InstantiateOperation>(initCapacity);
}
/// <summary>
/// 创建对象池。
/// </summary>
/// <param name="package">资源包。</param>
public void CreatePool(ResourcePackage package)
{
// 加载游戏对象
AssetHandle = package.LoadAssetAsync<GameObject>(Location);
// 创建初始对象
for (int i = 0; i < _initCapacity; i++)
{
var operation = AssetHandle.InstantiateAsync(_root.transform);
operation.Completed += Operation_Completed;
_cacheOperations.Enqueue(operation);
}
}
private void Operation_Completed(AsyncOperationBase obj)
{
if (obj.Status == EOperationStatus.Succeed)
{
var op = obj as InstantiateOperation;
if (op.Result != null)
op.Result.SetActive(false);
}
}
/// <summary>
/// 销毁游戏对象池。
/// </summary>
public void DestroyPool()
{
// 卸载资源对象
AssetHandle.Release();
AssetHandle = null;
// 销毁游戏对象
Object.Destroy(_root);
_cacheOperations.Clear();
SpawnCount = 0;
}
/// <summary>
/// 查询静默时间内是否可以销毁。
/// </summary>
public bool CanAutoDestroy()
{
if (_dontDestroy)
return false;
if (_destroyTime < 0)
return false;
if (_lastRestoreRealTime > 0 && SpawnCount <= 0)
return (Time.realtimeSinceStartup - _lastRestoreRealTime) > _destroyTime;
else
return false;
}
/// <summary>
/// 游戏对象池是否已经销毁。
/// </summary>
public bool IsDestroyed()
{
return AssetHandle == null;
}
/// <summary>
/// 回收操作。
/// </summary>
/// <param name="operation">资源实例化操作句柄。</param>
public void Restore(InstantiateOperation operation)
{
if (IsDestroyed())
{
DestroyInstantiateOperation(operation);
return;
}
SpawnCount--;
if (SpawnCount <= 0)
_lastRestoreRealTime = Time.realtimeSinceStartup;
// 如果外部逻辑销毁了游戏对象
if (operation.Status == EOperationStatus.Succeed)
{
if (operation.Result == null)
return;
}
// 如果缓存池还未满员
if (_cacheOperations.Count < _maxCapacity)
{
SetRestoreGameObject(operation.Result);
_cacheOperations.Enqueue(operation);
}
else
{
DestroyInstantiateOperation(operation);
}
}
/// <summary>
/// 丢弃操作。
/// </summary>
/// <param name="operation">资源实例化操作句柄。</param>
public void Discard(InstantiateOperation operation)
{
if (IsDestroyed())
{
DestroyInstantiateOperation(operation);
return;
}
SpawnCount--;
if (SpawnCount <= 0)
_lastRestoreRealTime = Time.realtimeSinceStartup;
DestroyInstantiateOperation(operation);
}
/// <summary>
/// 获取一个游戏对象。
/// </summary>
/// <param name="parent">父节点位置。</param>
/// <param name="position">位置。</param>
/// <param name="rotation">旋转。</param>
/// <param name="forceClone">是否强制克隆。</param>
/// <param name="userDatas">用户自定义数据。</param>
/// <returns>Spawn操作句柄。</returns>
public SpawnHandle Spawn(Transform parent, Vector3 position, Quaternion rotation, bool forceClone, params System.Object[] userDatas)
{
InstantiateOperation operation;
if (forceClone == false && _cacheOperations.Count > 0)
operation = _cacheOperations.Dequeue();
else
operation = AssetHandle.InstantiateAsync();
SpawnCount++;
SpawnHandle handle = new SpawnHandle(this, operation, parent, position, rotation, userDatas);
YooAssets.StartOperation(handle);
return handle;
}
private void DestroyInstantiateOperation(InstantiateOperation operation)
{
// 取消异步操作
operation.Cancel();
// 销毁游戏对象
if (operation.Result != null)
{
Object.Destroy(operation.Result);
}
}
private void SetRestoreGameObject(GameObject gameObj)
{
if (gameObj != null)
{
gameObj.SetActive(false);
gameObj.transform.SetParent(_root.transform);
gameObj.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3f0c9bab3d1243fda94ec9a08844ceee
timeCreated: 1693831296

View File

@@ -0,0 +1,253 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace TEngine
{
/// <summary>
/// 游戏对象池系统。
/// <remarks>用法 SpawnHandle handle = ResourcePool.SpawnAsync("Cube");</remarks>
/// </summary>
public static class ResourcePool
{
private static bool _isInitialize = false;
private static readonly List<Spawner> Spawners = new List<Spawner>();
private static GameObject _root;
private static Spawner _defaultSpawner = null;
/// <summary>
/// 默认Package对象生成器。
/// </summary>
private static Spawner DefaultSpawner => _defaultSpawner ??= CreateSpawner();
/// <summary>
/// 初始化游戏对象池系统
/// </summary>
internal static void Initialize(GameObject root)
{
if (_isInitialize)
throw new Exception($"{nameof(ResourcePool)} is initialized !");
if (_isInitialize == false)
{
_root = root;
_isInitialize = true;
Log.Info($"{nameof(ResourcePool)} Initialize !");
}
}
/// <summary>
/// 销毁游戏对象池系统
/// </summary>
internal static void Destroy()
{
if (_isInitialize)
{
foreach (var spawner in Spawners)
{
spawner.Destroy();
}
Spawners.Clear();
_isInitialize = false;
Log.Debug($"{nameof(ResourcePool)} destroy all !");
}
}
/// <summary>
/// 更新游戏对象池系统
/// </summary>
internal static void Update()
{
if (_isInitialize)
{
foreach (var spawner in Spawners)
{
spawner.Update();
}
}
}
/// <summary>
/// 创建游戏对象生成器
/// </summary>
/// <param name="packageName">资源包名称</param>
public static Spawner CreateSpawner(string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
{
packageName = GameModule.Resource.packageName;
}
// 获取资源包
var assetPackage = YooAssets.GetPackage(packageName);
if (assetPackage == null)
throw new Exception($"Not found asset package : {packageName}");
// 检测资源包初始化状态
if (assetPackage.InitializeStatus == EOperationStatus.None)
throw new Exception($"Asset package {packageName} not initialize !");
if (assetPackage.InitializeStatus == EOperationStatus.Failed)
throw new Exception($"Asset package {packageName} initialize failed !");
if (HasSpawner(packageName))
return GetSpawner(packageName);
Spawner spawner = new Spawner(_root, assetPackage);
Spawners.Add(spawner);
return spawner;
}
/// <summary>
/// 获取游戏对象生成器。
/// </summary>
/// <param name="packageName">资源包名称。</param>
public static Spawner GetSpawner(string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
{
packageName = GameModule.Resource.packageName;
}
foreach (var spawner in Spawners)
{
if (spawner.PackageName == packageName)
return spawner;
}
Log.Warning($"Not found spawner : {packageName}");
return null;
}
/// <summary>
/// 检测游戏对象生成器是否存在。
/// </summary>
/// <param name="packageName">资源包名称。</param>
public static bool HasSpawner(string packageName = "")
{
if (string.IsNullOrEmpty(packageName))
{
packageName = GameModule.Resource.packageName;
}
foreach (var spawner in Spawners)
{
if (spawner.PackageName == packageName)
return true;
}
return false;
}
#region
/// <summary>
/// 销毁所有对象池及其资源。
/// </summary>
/// <param name="includeAll">销毁所有对象池,包括常驻对象池。</param>
public static void DestroyAll(bool includeAll)
{
DefaultSpawner.DestroyAll(includeAll);
}
/// <summary>
/// 异步创建指定资源的游戏对象池。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="dontDestroy">资源常驻不销毁。</param>
/// <param name="initCapacity">对象池的初始容量。</param>
/// <param name="maxCapacity">对象池的最大容量。</param>
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
public static CreatePoolOperation CreateGameObjectPoolAsync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
return DefaultSpawner.CreateGameObjectPoolAsync(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
}
/// <summary>
/// 同步创建指定资源的游戏对象池。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="dontDestroy">资源常驻不销毁。</param>
/// <param name="initCapacity">对象池的初始容量。</param>
/// <param name="maxCapacity">对象池的最大容量。</param>
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
public static CreatePoolOperation CreateGameObjectPoolSync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
return DefaultSpawner.CreateGameObjectPoolSync(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
}
/// <summary>
/// 异步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public static SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
{
return DefaultSpawner.SpawnAsync(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 异步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public static SpawnHandle SpawnAsync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
{
return DefaultSpawner.SpawnAsync(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 异步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体。</param>
/// <param name="position">世界坐标。</param>
/// <param name="rotation">世界角度。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public static SpawnHandle SpawnAsync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
{
return DefaultSpawner.SpawnAsync(location, parent, position, rotation, forceClone, userDatas);
}
/// <summary>
/// 同步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public static SpawnHandle SpawnSync(string location, bool forceClone = false, params System.Object[] userDatas)
{
return DefaultSpawner.SpawnSync(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 同步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public static SpawnHandle SpawnSync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
{
return DefaultSpawner.SpawnAsync(location, parent, forceClone, userDatas);
}
/// <summary>
/// 同步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体。</param>
/// <param name="position">世界坐标。</param>
/// <param name="rotation">世界角度。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public static SpawnHandle SpawnSync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
{
return DefaultSpawner.SpawnSync(location,parent,position,rotation,forceClone,userDatas);
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: be208ee3e46e4243b9a68d4c7212015e
timeCreated: 1693831058

View File

@@ -0,0 +1,152 @@
using UnityEngine;
using YooAsset;
namespace TEngine
{
public sealed class SpawnHandle : GameAsyncOperation
{
private enum ESteps
{
None,
Waiting,
Done,
}
private readonly GameObjectPool _pool;
private InstantiateOperation _operation;
private readonly Transform _parent;
private readonly Vector3 _position;
private readonly Quaternion _rotation;
private ESteps _steps = ESteps.None;
/// <summary>
/// 实例化的游戏对象。
/// </summary>
public GameObject GameObj
{
get
{
if (_operation == null)
{
Log.Warning("The spawn handle is invalid !");
return null;
}
return _operation.Result;
}
}
/// <summary>
/// 用户自定义数据集。
/// </summary>
public System.Object[] UserDatas { private set; get; }
private SpawnHandle()
{
}
internal SpawnHandle(GameObjectPool pool, InstantiateOperation operation, Transform parent, Vector3 position, Quaternion rotation,
params System.Object[] userDatas)
{
_pool = pool;
_operation = operation;
_parent = parent;
_position = position;
_rotation = rotation;
UserDatas = userDatas;
}
protected override void OnStart()
{
_steps = ESteps.Waiting;
}
protected override void OnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Waiting)
{
if (_operation.IsDone == false)
return;
if (_operation.Status != EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _operation.Error;
return;
}
if (_operation.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Clone game object is null.";
return;
}
// 设置参数
_operation.Result.transform.SetParent(_parent);
_operation.Result.transform.SetPositionAndRotation(_position, _rotation);
_operation.Result.SetActive(true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
/// <summary>
/// 回收对象。
/// </summary>
public void Restore()
{
if (_operation != null)
{
ClearCompletedCallback();
CancelHandle();
_pool.Restore(_operation);
_operation = null;
}
}
/// <summary>
/// 丢弃对象。
/// </summary>
public void Discard()
{
if (_operation != null)
{
ClearCompletedCallback();
CancelHandle();
_pool.Discard(_operation);
_operation = null;
}
}
/// <summary>
/// 等待异步实例化结束。
/// </summary>
public void WaitForAsyncComplete()
{
if (_operation != null)
{
if (_steps == ESteps.Done)
return;
_operation.WaitForAsyncComplete();
OnUpdate();
}
}
private void CancelHandle()
{
if (IsDone == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"User cancelled !";
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eb2cdce8eb814f7c92c74199d065688a
timeCreated: 1693831296

View File

@@ -0,0 +1,262 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace TEngine
{
/// <summary>
/// 对象生成器。
/// </summary>
public class Spawner
{
private readonly List<GameObjectPool> _gameObjectPools = new List<GameObjectPool>(100);
private readonly List<GameObjectPool> _removeList = new List<GameObjectPool>(100);
private readonly GameObject _spawnerRoot;
private readonly ResourcePackage _package;
public string PackageName
{
get
{
return _package.PackageName;
}
}
private Spawner()
{
}
internal Spawner(GameObject poolingRoot, ResourcePackage package)
{
_spawnerRoot = new GameObject($"{package.PackageName}");
_spawnerRoot.transform.SetParent(poolingRoot.transform);
_package = package;
}
/// <summary>
/// 更新游戏对象池系统。
/// </summary>
internal void Update()
{
_removeList.Clear();
foreach (var pool in _gameObjectPools)
{
if (pool.CanAutoDestroy())
_removeList.Add(pool);
}
foreach (var pool in _removeList)
{
_gameObjectPools.Remove(pool);
pool.DestroyPool();
}
}
/// <summary>
/// 销毁游戏对象池系统。
/// </summary>
internal void Destroy()
{
DestroyAll(true);
}
/// <summary>
/// 销毁所有对象池及其资源。
/// </summary>
/// <param name="includeAll">销毁所有对象池,包括常驻对象池。</param>
public void DestroyAll(bool includeAll)
{
if (includeAll)
{
foreach (var pool in _gameObjectPools)
{
pool.DestroyPool();
}
_gameObjectPools.Clear();
}
else
{
List<GameObjectPool> removeList = new List<GameObjectPool>();
foreach (var pool in _gameObjectPools)
{
if (pool.DontDestroy == false)
removeList.Add(pool);
}
foreach (var pool in removeList)
{
_gameObjectPools.Remove(pool);
pool.DestroyPool();
}
}
}
/// <summary>
/// 异步创建指定资源的游戏对象池。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="dontDestroy">资源常驻不销毁。</param>
/// <param name="initCapacity">对象池的初始容量。</param>
/// <param name="maxCapacity">对象池的最大容量。</param>
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
public CreatePoolOperation CreateGameObjectPoolAsync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
return CreateGameObjectPoolInternal(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
}
/// <summary>
/// 同步创建指定资源的游戏对象池。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="dontDestroy">资源常驻不销毁。</param>
/// <param name="initCapacity">对象池的初始容量。</param>
/// <param name="maxCapacity">对象池的最大容量。</param>
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)。</param>
public CreatePoolOperation CreateGameObjectPoolSync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
var operation = CreateGameObjectPoolInternal(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
operation.WaitForAsyncComplete();
return operation;
}
/// <summary>
/// 创建指定资源的游戏对象池。
/// </summary>
private CreatePoolOperation CreateGameObjectPoolInternal(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
if (maxCapacity < initCapacity)
throw new Exception("The max capacity value must be greater the init capacity value.");
GameObjectPool pool = TryGetGameObjectPool(location);
if (pool != null)
{
Log.Warning($"GameObject pool is already existed : {location}");
var operation = new CreatePoolOperation(pool.AssetHandle);
YooAssets.StartOperation(operation);
return operation;
}
else
{
pool = new GameObjectPool(_spawnerRoot, location, dontDestroy, initCapacity, maxCapacity, destroyTime);
pool.CreatePool(_package);
_gameObjectPools.Add(pool);
var operation = new CreatePoolOperation(pool.AssetHandle);
YooAssets.StartOperation(operation);
return operation;
}
}
/// <summary>
/// 异步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
{
return SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 异步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public SpawnHandle SpawnAsync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
{
return SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 异步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体。</param>
/// <param name="position">世界坐标。</param>
/// <param name="rotation">世界角度。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public SpawnHandle SpawnAsync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
{
return SpawnInternal(location, parent, position, rotation, forceClone, userDatas);
}
/// <summary>
/// 同步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public SpawnHandle SpawnSync(string location, bool forceClone = false, params System.Object[] userDatas)
{
SpawnHandle handle = SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
handle.WaitForAsyncComplete();
return handle;
}
/// <summary>
/// 同步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public SpawnHandle SpawnSync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
{
SpawnHandle handle = SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
handle.WaitForAsyncComplete();
return handle;
}
/// <summary>
/// 同步实例化一个游戏对象。
/// </summary>
/// <param name="location">资源定位地址。</param>
/// <param name="parent">父物体。</param>
/// <param name="position">世界坐标。</param>
/// <param name="rotation">世界角度。</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象。</param>
/// <param name="userDatas">用户自定义数据。</param>
public SpawnHandle SpawnSync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
{
SpawnHandle handle = SpawnInternal(location, parent, position, rotation, forceClone, userDatas);
handle.WaitForAsyncComplete();
return handle;
}
/// <summary>
/// 实例化一个游戏对象。
/// </summary>
private SpawnHandle SpawnInternal(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone, params System.Object[] userDatas)
{
var pool = TryGetGameObjectPool(location);
if (pool != null)
{
return pool.Spawn(parent, position, rotation, forceClone, userDatas);
}
// 如果不存在创建游戏对象池
pool = new GameObjectPool(_spawnerRoot, location, false, 0, int.MaxValue, -1f);
pool.CreatePool(_package);
_gameObjectPools.Add(pool);
return pool.Spawn(parent, position, rotation, forceClone, userDatas);
}
private GameObjectPool TryGetGameObjectPool(string location)
{
foreach (var pool in _gameObjectPools)
{
if (pool.Location == location)
return pool;
}
return null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 570ac9abe8a04e77b49c42719a9fa93b
timeCreated: 1693831272

View File

@@ -12,6 +12,7 @@ namespace TEngine
internal partial class ResourceManager : GameFrameworkModule, IResourceManager internal partial class ResourceManager : GameFrameworkModule, IResourceManager
{ {
#region Propreties #region Propreties
/// <summary> /// <summary>
/// 资源包名称。 /// 资源包名称。
/// </summary> /// </summary>
@@ -75,20 +76,26 @@ namespace TEngine
/// </summary> /// </summary>
/// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks> /// <remarks>优先级较高的模块会优先轮询,并且关闭操作会后进行。</remarks>
internal override int Priority => 4; internal override int Priority => 4;
#endregion #endregion
#region #region
internal override void Update(float elapseSeconds, float realElapseSeconds) internal override void Update(float elapseSeconds, float realElapseSeconds)
{ {
ResourcePool.Update();
} }
internal override void Shutdown() internal override void Shutdown()
{ {
YooAssets.Destroy(); YooAssets.Destroy();
ResourcePool.Destroy();
} }
#endregion #endregion
#region #region
/// <summary> /// <summary>
/// 设置资源只读区路径。 /// 设置资源只读区路径。
/// </summary> /// </summary>
@@ -116,6 +123,7 @@ namespace TEngine
m_ReadWritePath = readWritePath; m_ReadWritePath = readWritePath;
} }
#endregion #endregion
public void Initialize() public void Initialize()
@@ -133,6 +141,7 @@ namespace TEngine
defaultPackage = YooAssets.CreatePackage(packageName); defaultPackage = YooAssets.CreatePackage(packageName);
YooAssets.SetDefaultPackage(defaultPackage); YooAssets.SetDefaultPackage(defaultPackage);
} }
ResourcePool.Initialize(GameModule.Resource.gameObject);
} }
public InitializationOperation InitPackage() public InitializationOperation InitPackage()
@@ -296,6 +305,7 @@ namespace TEngine
} }
#endregion #endregion
/// <summary> /// <summary>
/// 同步加载资源。 /// 同步加载资源。
/// </summary> /// </summary>
@@ -309,6 +319,7 @@ namespace TEngine
Log.Error("Asset name is invalid."); Log.Error("Asset name is invalid.");
return default; return default;
} }
AssetOperationHandle handle = YooAssets.LoadAssetSync<T>(assetName); AssetOperationHandle handle = YooAssets.LoadAssetSync<T>(assetName);
if (typeof(T) == typeof(GameObject)) if (typeof(T) == typeof(GameObject))
@@ -339,6 +350,7 @@ namespace TEngine
Log.Error("Asset name is invalid."); Log.Error("Asset name is invalid.");
return default; return default;
} }
AssetOperationHandle handle = YooAssets.LoadAssetSync<T>(assetName); AssetOperationHandle handle = YooAssets.LoadAssetSync<T>(assetName);
if (typeof(T) == typeof(GameObject)) if (typeof(T) == typeof(GameObject))
@@ -471,7 +483,8 @@ namespace TEngine
/// <param name="activateOnLoad">加载完毕时是否主动激活</param> /// <param name="activateOnLoad">加载完毕时是否主动激活</param>
/// <param name="priority">优先级</param> /// <param name="priority">优先级</param>
/// <returns>异步加载场景句柄。</returns> /// <returns>异步加载场景句柄。</returns>
public SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100) public SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true,
int priority = 100)
{ {
return YooAssets.LoadSceneAsync(location, sceneMode, activateOnLoad, priority); return YooAssets.LoadSceneAsync(location, sceneMode, activateOnLoad, priority);
} }
@@ -484,7 +497,8 @@ namespace TEngine
/// <param name="activateOnLoad">加载完毕时是否主动激活</param> /// <param name="activateOnLoad">加载完毕时是否主动激活</param>
/// <param name="priority">优先级</param> /// <param name="priority">优先级</param>
/// <returns>异步加载场景句柄。</returns> /// <returns>异步加载场景句柄。</returns>
public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true, int priority = 100) public SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool activateOnLoad = true,
int priority = 100)
{ {
return YooAssets.LoadSceneAsync(assetInfo, sceneMode, activateOnLoad, priority); return YooAssets.LoadSceneAsync(assetInfo, sceneMode, activateOnLoad, priority);
} }
@@ -563,6 +577,7 @@ namespace TEngine
{ {
Log.Error("Set Parent Failed"); Log.Error("Set Parent Failed");
} }
return gameObject; return gameObject;
} }
@@ -643,7 +658,8 @@ namespace TEngine
/// <param name="activateOnLoad">加载完毕时是否主动激活.</param> /// <param name="activateOnLoad">加载完毕时是否主动激活.</param>
/// <param name="priority">优先级.</param> /// <param name="priority">优先级.</param>
/// <returns>场景资源实例。</returns> /// <returns>场景资源实例。</returns>
public async UniTask<Scene> LoadSceneAsyncByUniTask(string location,CancellationToken cancellationToken,LoadSceneMode sceneMode = LoadSceneMode.Single, public async UniTask<Scene> LoadSceneAsyncByUniTask(string location, CancellationToken cancellationToken,
LoadSceneMode sceneMode = LoadSceneMode.Single,
bool activateOnLoad = true, int priority = 100) bool activateOnLoad = true, int priority = 100)
{ {
SceneOperationHandle handle = YooAssets.LoadSceneAsync(location, sceneMode, activateOnLoad, priority); SceneOperationHandle handle = YooAssets.LoadSceneAsync(location, sceneMode, activateOnLoad, priority);

View File

@@ -5,7 +5,7 @@
/// </summary> /// </summary>
public sealed class DefaultSettingSerializer : GameFrameworkSerializer<DefaultSetting> public sealed class DefaultSettingSerializer : GameFrameworkSerializer<DefaultSetting>
{ {
private static readonly byte[] Header = new byte[] { (byte)'G', (byte)'F', (byte)'S' }; private static readonly byte[] Header = new byte[] { (byte)'T', (byte)'E', (byte)'S' };
/// <summary> /// <summary>
/// 初始化默认游戏配置序列化器的新实例。 /// 初始化默认游戏配置序列化器的新实例。

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 3b9128b665b538746a11489aee369030
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -60,6 +60,10 @@
"Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/", "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/",
"Comment": "客户端自定义导出代码文件夹位置" "Comment": "客户端自定义导出代码文件夹位置"
}, },
"SceneConfigPath": {
"Value": "../../../Config/Excel/Server/SceneConfig.xlsx",
"Comment": "SceneConfig.xlsx的位置"
},
"CustomExportAssembly": { "CustomExportAssembly": {
"Value": "Logic", "Value": "Logic",
"Comment": "自定义导出代码存放的程序集" "Comment": "自定义导出代码存放的程序集"

View File

@@ -40,6 +40,7 @@ namespace Bright.Serialization
public sealed class ByteBuf : ICloneable, IEquatable<ByteBuf> public sealed class ByteBuf : ICloneable, IEquatable<ByteBuf>
{ {
#pragma warning disable CS8618
public ByteBuf() public ByteBuf()
{ {
Bytes = Array.Empty<byte>(); Bytes = Array.Empty<byte>();
@@ -76,6 +77,7 @@ namespace Bright.Serialization
{ {
return new ByteBuf(bytes, 0, bytes.Length); return new ByteBuf(bytes, 0, bytes.Length);
} }
#pragma warning restore CS8618
public void Replace(byte[] bytes) public void Replace(byte[] bytes)
{ {
@@ -1015,20 +1017,24 @@ namespace Bright.Serialization
return ((long)((ulong)x >> 1) ^ ((x & 1) << 63)); return ((long)((ulong)x >> 1) ^ ((x & 1) << 63));
} }
public void WriteString(string x) public void WriteString(string? x)
{ {
var n = x != null ? Encoding.UTF8.GetByteCount(x) : 0; var n = x != null ? Encoding.UTF8.GetByteCount(x) : 0;
WriteSize(n); WriteSize(n);
if (n > 0) if (n > 0)
{ {
EnsureWrite(n); EnsureWrite(n);
Encoding.UTF8.GetBytes(x, 0, x.Length, Bytes, WriterIndex); if (x != null)
{
Encoding.UTF8.GetBytes(x, 0, x.Length, this.Bytes, this.WriterIndex);
}
WriterIndex += n; WriterIndex += n;
} }
} }
// byte[], [start, end) // byte[], [start, end)
public static Func<byte[], int, int, string> StringCacheFinder { get; set; } public static Func<byte[], int, int, string>? StringCacheFinder { get; set; }
public string ReadString() public string ReadString()
{ {
@@ -1056,14 +1062,14 @@ namespace Bright.Serialization
} }
} }
public void WriteBytes(byte[] x) public void WriteBytes(byte[]? x)
{ {
var n = x != null ? x.Length : 0; var n = x != null ? x.Length : 0;
WriteSize(n); WriteSize(n);
if (n > 0) if (n > 0)
{ {
EnsureWrite(n); EnsureWrite(n);
x.CopyTo(Bytes, WriterIndex); x?.CopyTo(Bytes, WriterIndex);
WriterIndex += n; WriterIndex += n;
} }
} }
@@ -1485,12 +1491,12 @@ namespace Bright.Serialization
return string.Join(".", datas); return string.Join(".", datas);
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
return (obj is ByteBuf other) && Equals(other); return (obj is ByteBuf other) && Equals(other);
} }
public bool Equals(ByteBuf other) public bool Equals(ByteBuf? other)
{ {
if (other == null) if (other == null)
{ {

View File

@@ -1,48 +1,104 @@
#if TENGINE_NET #if TENGINE_NET
using System.Text; using System.Text;
using TEngine.Core; using TEngine.Core;
using TEngine.Helper;
namespace TEngine.Model; namespace TEngine.Model;
/// <summary>
/// 将场景类型配置表转换为枚举和字典的自定义导出类。
/// </summary>
public sealed class SceneTypeConfigToEnum : ACustomExport public sealed class SceneTypeConfigToEnum : ACustomExport
{ {
/// <summary>
/// 执行自定义导出操作。
/// </summary>
public override void Run() public override void Run()
{ {
var serverSceneType = new HashSet<string>(); // 获取场景配置表的完整路径
var instanceList = SceneConfigData.Instance.List; using var excelPackage = ExcelHelper.LoadExcel(Define.SceneConfigPath);
var sceneType = new Dictionary<string, string>();
foreach (var sceneConfig in instanceList) var sceneSubType = new Dictionary<string, string>();
// 获取场景类型配置工作表
var sceneTypeConfig = excelPackage.Workbook.Worksheets["SceneTypeConfig"];
// 遍历场景类型配置表的行
for (var row = 3; row <= sceneTypeConfig.Dimension.Rows; row++)
{ {
serverSceneType.Add(sceneConfig.SceneType); var sceneTypeId = sceneTypeConfig.GetCellValue(row, 1);
var sceneTypeStr = sceneTypeConfig.GetCellValue(row, 2);
if (string.IsNullOrEmpty(sceneTypeId) || string.IsNullOrEmpty(sceneTypeStr))
{
continue;
} }
if (serverSceneType.Count > 0) sceneType.Add(sceneTypeId, sceneTypeStr);
}
// 获取场景子类型配置工作表
var sceneSubTypeConfig = excelPackage.Workbook.Worksheets["SceneSubTypeConfig"];
// 遍历场景子类型配置表的行
for (var row = 3; row <= sceneSubTypeConfig.Dimension.Rows; row++)
{ {
Write(CustomExportType.Server, serverSceneType); var sceneSubTypeId = sceneSubTypeConfig.GetCellValue(row, 1);
var sceneSubTypeStr = sceneSubTypeConfig.GetCellValue(row, 2);
if (string.IsNullOrEmpty(sceneSubTypeId) || string.IsNullOrEmpty(sceneSubTypeStr))
{
continue;
}
sceneSubType.Add(sceneSubTypeId, sceneSubTypeStr);
}
// 如果存在场景类型或场景子类型,执行导出操作
if (sceneType.Count > 0 || sceneSubType.Count > 0)
{
Write(CustomExportType.Server, sceneType, sceneSubType);
} }
} }
private void Write(CustomExportType customExportType, HashSet<string> sceneTypes) private void Write(CustomExportType customExportType, Dictionary<string, string> sceneTypes, Dictionary<string, string> sceneSubType)
{ {
var index = 0;
var strBuilder = new StringBuilder(); var strBuilder = new StringBuilder();
var dicBuilder = new StringBuilder(); var dicBuilder = new StringBuilder();
// 添加命名空间和注释头部
strBuilder.AppendLine("namespace TEngine\n{"); strBuilder.AppendLine("namespace TEngine\n{");
strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑。"); strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑。");
strBuilder.AppendLine("\tpublic class SceneType\n\t{"); // 生成场景类型的静态类
dicBuilder.AppendLine("\n\t\tpublic static readonly Dictionary<string, int> SceneDic = new Dictionary<string, int>()\n\t\t{"); strBuilder.AppendLine("\tpublic static class SceneType\n\t{");
dicBuilder.AppendLine("\n\t\tpublic static readonly Dictionary<string, int> SceneTypeDic = new Dictionary<string, int>()\n\t\t{");
foreach (var str in sceneTypes) // 遍历场景类型字典,生成场景类型的常量和字典项
foreach (var (sceneTypeId, sceneTypeStr) in sceneTypes)
{ {
index++; dicBuilder.AppendLine($"\t\t\t{{ \"{sceneTypeStr}\", {sceneTypeId} }},");
dicBuilder.AppendLine($"\t\t\t{{ \"{str}\", {index} }},"); strBuilder.AppendLine($"\t\tpublic const int {sceneTypeStr} = {sceneTypeId};");
strBuilder.AppendLine($"\t\tpublic const int {str} = {index};");
} }
// 添加场景类型字典尾部,合并到主字符串构建器中
dicBuilder.AppendLine("\t\t};");
strBuilder.Append(dicBuilder);
strBuilder.AppendLine("\t}\n");
// 生成场景子类型的静态类
strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑。");
strBuilder.AppendLine("\tpublic static class SceneSubType\n\t{");
// 清空字典构建器,用于生成场景子类型的字典项
dicBuilder.Clear();
dicBuilder.AppendLine("\n\t\tpublic static readonly Dictionary<string, int> SceneSubTypeDic = new Dictionary<string, int>()\n\t\t{");
// 遍历场景子类型字典,生成场景子类型的常量和字典项
foreach (var (sceneSubTypeId, sceneSubTypeStr) in sceneSubType)
{
dicBuilder.AppendLine($"\t\t\t{{ \"{sceneSubTypeStr}\", {sceneSubTypeId} }},");
strBuilder.AppendLine($"\t\tpublic const int {sceneSubTypeStr} = {sceneSubTypeId};");
}
// 添加场景子类型字典尾部,合并到主字符串构建器中
dicBuilder.AppendLine("\t\t};"); dicBuilder.AppendLine("\t\t};");
strBuilder.Append(dicBuilder); strBuilder.Append(dicBuilder);
strBuilder.AppendLine("\t}\n}"); strBuilder.AppendLine("\t}\n}");
// 调用外部方法将生成的代码写入文件
Write("SceneType.cs", strBuilder.ToString(), customExportType); Write("SceneType.cs", strBuilder.ToString(), customExportType);
} }
} }

View File

@@ -7,6 +7,7 @@ namespace TEngine
public const int Addressable = 2; public const int Addressable = 2;
public const int Map = 3; public const int Map = 3;
public const int Chat = 4; public const int Chat = 4;
public const int Center = 5;
public static readonly Dictionary<string, int> SceneTypeDic = new Dictionary<string, int>() public static readonly Dictionary<string, int> SceneTypeDic = new Dictionary<string, int>()
{ {
@@ -14,6 +15,7 @@ namespace TEngine
{ "Addressable", 2 }, { "Addressable", 2 },
{ "Map", 3 }, { "Map", 3 },
{ "Chat", 4 }, { "Chat", 4 },
{ "Center", 5 },
}; };
} }

View File

@@ -1,10 +0,0 @@
set GEN_CLIENT=dotnet ..\Tools\Luban.ClientServer\Luban.ClientServer.dll
%GEN_CLIENT% -j cfg --^
-d Defines\__root__.xml ^
--input_data_dir Datas ^
--output_data_dir output_json ^
--output_code_dir Gen ^
--gen_types code_cs_unity_json,data_json ^
-s all
pause

View File

@@ -1,10 +0,0 @@
#!/bin/zsh
GEN_CLIENT=../Tools/Luban.ClientServer/Luban.ClientServer.dll
dotnet ${GEN_CLIENT} -j cfg --\
-d Defines/__root__.xml \
--input_data_dir Datas \
--output_data_dir output_json \
--output_code_dir Gen \
--gen_types code_cs_unity_json,data_json \
-s all