三国卡牌客户端基础资源仓库
yyl
2026-05-11 136be959f92596c5717d2642c9fcbb51501fe005
Assets/Editor/ConfigGen/ConfigGenerater.cs
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -12,14 +12,16 @@
public static class ConfigGenerater
{
    // 常量定义
    private const string ConfigsPath = "Assets/Scripts/Main/Config/Configs";
    private const string ResourcesOutConfigPath = "Assets/ResourcesOut/Config";
    private const string ConfigClassesPath = "Assets/Scripts/Main/Config/Configs";
    private const string ConfigManagerPath = "Assets/Scripts/Main/Config/ConfigManager.cs";
    public static List<string> ExcludeClassList = new List<string>()
    {
        //  特殊表格
        //  特殊表格(由 preInitConfig 单独加载,不进入 configTypes)
        "InitialFunctionConfig",
        "PriorLanguageConfig",
        "FuncConfigConfig",
        //  暂时无用的表
        "PlayerFacePicStarConfig",
@@ -46,25 +48,19 @@
                .Where(c => !string.IsNullOrEmpty(c) && char.IsUpper(c[0]))
                .ToList();
            // 2. 自动生成 ConfigManager.cs 的 LoadConfigs 方法,全部异步加载
            string configManagerPath = Path.Combine(Application.dataPath, ConfigManagerPath.Replace("Assets/", ""));
            var lines = File.ReadAllLines(configManagerPath).ToList();
            // 查找 LoadConfigs 方法起止行
            int startIdx = lines.FindIndex(l => l.Contains("protected async UniTask LoadConfigs()"));
            int openBrace = lines.FindIndex(startIdx, l => l.Trim() == "{");
            int endIdx = openBrace;
            int braceCount = 1;
            for (int i = openBrace + 1; i < lines.Count; i++)
            // --- 更新 configTypes HashSet ---
            int loadConfigsIdx = lines.FindIndex(l => l.Contains("protected async UniTask LoadConfigs()"));
            if (loadConfigsIdx < 0)
            {
                if (lines[i].Contains("{")) braceCount++;
                if (lines[i].Contains("}")) braceCount--;
                if (braceCount == 0) { endIdx = i; break; }
                Debug.LogError("未找到 'protected async UniTask LoadConfigs()',请检查 ConfigManager.cs 结构。");
                return;
            }
            // 生成 configTypes 初始化代码
            var configTypeLines = new List<string>();
            configTypeLines.Add("        // 自动生成:收集所有配置类型");
            configTypeLines.Add("        // 加载配置文件");
            configTypeLines.Add("        HashSet<Type> configTypes = new HashSet<Type>() {");
            for (int i = 0; i < configClasses.Count; i++)
            {
@@ -72,55 +68,88 @@
            }
            configTypeLines.Add("        };");
            // 替换原有 configTypes 初始化段
            int configTypesStart = lines.FindIndex(startIdx, l => l.Contains("HashSet<Type> configTypes"));
            int configTypesStart = lines.FindIndex(loadConfigsIdx, l => l.Contains("HashSet<Type> configTypes"));
            int configTypesEnd = configTypesStart;
            while (configTypesEnd < lines.Count && !lines[configTypesEnd].Trim().EndsWith("};")) configTypesEnd++;
            configTypesEnd++;
            lines.RemoveRange(configTypesStart, configTypesEnd - configTypesStart);
            lines.InsertRange(configTypesStart, configTypeLines);
            // --- 更新 Release() 方法体 ---
            int releaseIdx = lines.FindIndex(l => l.TrimStart().StartsWith("public override void Release()"));
            if (releaseIdx >= 0)
            {
                int releaseOpen = lines.FindIndex(releaseIdx, l => l.Trim() == "{");
                int releaseClose = releaseOpen;
                int braceCount = 1;
                for (int i = releaseOpen + 1; i < lines.Count; i++)
                {
                    foreach (char ch in lines[i])
                    {
                        if (ch == '{') braceCount++;
                        if (ch == '}') braceCount--;
                    }
                    if (braceCount == 0) { releaseClose = i; break; }
                }
                var releaseLines = new List<string>();
                foreach (string className in configClasses)
                {
                    releaseLines.Add($"        // 清空 {className} 字典");
                    releaseLines.Add($"        ClearConfigDictionary<{className}>();");
                }
                lines.RemoveRange(releaseOpen + 1, releaseClose - releaseOpen - 1);
                lines.InsertRange(releaseOpen + 1, releaseLines);
            }
            // 保存文件
            File.WriteAllLines(configManagerPath, lines);
            Debug.Log($"ConfigManager.cs 自动生成 LoadConfigs 配置类型成功,共 {configClasses.Count} 个类型。");
            Debug.Log($"ConfigManager.cs 自动生成成功,共 {configClasses.Count} 个类型。");
            AssetDatabase.Refresh();
        }
        catch (Exception ex)
        {
            Debug.LogError($"自动生成 ConfigManager.LoadConfigs 时发生错误: {ex.Message}\n{ex.StackTrace}");
            Debug.LogError($"自动生成 ConfigManager 时发生错误: {ex.Message}\n{ex.StackTrace}");
        }
    }
    /// <summary>
    /// 获取所有配置类
    /// </summary>
    /// <returns>配置类名称列表</returns>
    public static List<string> GetAllConfigClasses()
    {
        // 获取配置目录的完整路径
        string fullConfigsPath = Path.Combine(Application.dataPath, ConfigsPath.Replace("Assets/", ""));
        // 检查目录是否存在
        if (!Directory.Exists(fullConfigsPath))
        // 以 ResourcesOut/Config 为权威来源,扫描 .txt 文件生成类名
        string fullResPath = Path.Combine(Application.dataPath, ResourcesOutConfigPath.Replace("Assets/", ""));
        string fullCsPath  = Path.Combine(Application.dataPath, ConfigClassesPath.Replace("Assets/", ""));
        if (!Directory.Exists(fullResPath))
        {
            Debug.LogError($"配置目录不存在: {fullConfigsPath}");
            Debug.LogError($"ResourcesOut/Config 目录不存在: {fullResPath}");
            return new List<string>();
        }
        try
        {
            List<string> configClasses = new List<string>();
            // 获取所有C#文件
            string[] files = Directory.GetFiles(fullConfigsPath, "*.cs", SearchOption.TopDirectoryOnly);
            for (int i = 0; i < files.Length; i++)
            // 扫描 ResourcesOut/Config 下的 .txt 文件,构造类名 = 文件名 + "Config"
            string[] txtFiles = Directory.GetFiles(fullResPath, "*.txt", SearchOption.TopDirectoryOnly);
            foreach (string file in txtFiles)
            {
                string file = files[i];
                configClasses.Add(Path.GetFileNameWithoutExtension(file));
                string baseName  = Path.GetFileNameWithoutExtension(file);
                string className = baseName + "Config";
                // 交叉验证:对应的 C# 类文件必须存在
                string csFile = Path.Combine(fullCsPath, className + ".cs");
                if (!File.Exists(csFile))
                    continue;
                configClasses.Add(className);
            }
            return configClasses;
        }
        catch (Exception ex)
@@ -129,301 +158,4 @@
            return new List<string>();
        }
    }
    /// <summary>
    /// 生成配置管理器代码
    /// </summary>
    /// <param name="configClasses">配置类列表</param>
    private static void GenerateConfigManager(List<string> configClasses)
    {
        // 获取配置管理器的完整路径
        string fullConfigManagerPath = Path.Combine(Application.dataPath, ConfigManagerPath.Replace("Assets/", ""));
        try
        {
            // 生成完整的配置管理器代码
            string configManagerCode = GenerateFullConfigManagerCode(configClasses);
            // 写入文件
            File.WriteAllText(fullConfigManagerPath, configManagerCode);
            Debug.Log($"成功生成配置管理器: {fullConfigManagerPath}");
        }
        catch (Exception ex)
        {
            Debug.LogError($"生成配置管理器文件时发生错误: {ex.Message}");
        }
    }
    /// <summary>
    /// 生成完整的配置管理器代码
    /// </summary>
    /// <param name="configClasses">配置类列表</param>
    /// <returns>完整的配置管理器代码</returns>
    private static string GenerateFullConfigManagerCode(List<string> configClasses)
    {
        StringBuilder sb = new StringBuilder();
        // 头部命名空间
        sb.AppendLine("using System;");
        sb.AppendLine("using System.Collections.Generic;");
        sb.AppendLine("using UnityEngine;");
        sb.AppendLine("using Cysharp.Threading.Tasks;");
        sb.AppendLine("using System.Reflection;");
        sb.AppendLine("using System.Linq;");
        sb.AppendLine();
        sb.AppendLine("#if UNITY_EDITOR");
        sb.AppendLine("using UnityEditor;");
        sb.AppendLine("#endif");
        sb.AppendLine();
        sb.AppendLine("public class ConfigManager : ManagerBase<ConfigManager>");
        sb.AppendLine("{");
        sb.AppendLine("    public bool isLoadFinished");
        sb.AppendLine("    {");
        sb.AppendLine("        get;");
        sb.AppendLine("        private set;");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    private float loadingProgress = 0f;");
        sb.AppendLine();
        sb.AppendLine("    public override void Init()");
        sb.AppendLine("    {");
        sb.AppendLine("        base.Init();");
        sb.AppendLine("        InitConfigs();");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    public virtual async UniTask InitConfigs()");
        sb.AppendLine("    {");
        sb.AppendLine("        // 加载配置文件");
        sb.AppendLine("        await LoadConfigs();");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    protected async UniTask LoadConfigs()");
        sb.AppendLine("    {");
        sb.AppendLine("        loadingProgress = 0f;");
        sb.AppendLine("        isLoadFinished = false;");
        sb.AppendLine();
        sb.AppendLine("        // 加载配置文件");
        sb.AppendLine("        HashSet<Type> configTypes = new HashSet<Type>() {");
        for (int i = 0; i < configClasses.Count; i++)
        {
            sb.Append($"            typeof({configClasses[i]})");
            sb.AppendLine(i < configClasses.Count - 1 ? "," : "");
        }
        sb.AppendLine("        };");
        sb.AppendLine();
        sb.AppendLine("        int iterator = 0;");
        sb.AppendLine("        int totalConfigs = configTypes.Count;");
        sb.AppendLine();
        sb.AppendLine("        // 逐个加载配置并更新进度");
        sb.AppendLine("        foreach (var configType in configTypes)");
        sb.AppendLine("        {");
        sb.AppendLine("            var sw = System.Diagnostics.Stopwatch.StartNew();");
        sb.AppendLine("            LoadConfigByType(configType);");
        sb.AppendLine("            sw.Stop();");
        sb.AppendLine("#if UNITY_EDITOR");
        sb.AppendLine("            if (sw.ElapsedMilliseconds >= 500)");
        sb.AppendLine("            {");
        sb.AppendLine("                Debug.LogError($\"加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms\");");
        sb.AppendLine("            }");
        sb.AppendLine("            Debug.Log($\"加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms\");");
        sb.AppendLine("#endif");
        sb.AppendLine("            loadingProgress = (float)(iterator++ + 1) / totalConfigs;");
        sb.AppendLine("        }");
        sb.AppendLine();
        sb.AppendLine("        // 加载完成后设置isLoadFinished为true");
        sb.AppendLine("        loadingProgress = 1f;");
        sb.AppendLine("        isLoadFinished = true;");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    public void LoadConfigByType(Type configType)");
        sb.AppendLine("    {");
        sb.AppendLine("        string configName = configType.Name;");
        sb.AppendLine("        if (configName.EndsWith(\"Config\"))");
        sb.AppendLine("        {");
        sb.AppendLine("            configName = configName.Substring(0, configName.Length - 6);");
        sb.AppendLine("        }");
        sb.AppendLine("        string[] texts = ResManager.Instance.LoadConfig(configName);");
        sb.AppendLine("        if (texts != null)");
        sb.AppendLine("        {");
        sb.AppendLine("            string[] lines = texts;");
        sb.AppendLine("            var methodInfo = configType.GetMethod(\"Init\", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);");
        sb.AppendLine("            if (methodInfo != null)");
        sb.AppendLine("            {");
        sb.AppendLine("                methodInfo.Invoke(null, new object[] { lines });");
        sb.AppendLine("                // 设置初始化标志");
        sb.AppendLine("                var isInitField = configType.GetField(\"isInit\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);");
        sb.AppendLine("                if (isInitField != null)");
        sb.AppendLine("                {");
        sb.AppendLine("                    isInitField.SetValue(null, true);");
        sb.AppendLine("                }");
        sb.AppendLine("                Debug.Log($\"加载配置: {configType.Name} 成功\");");
        sb.AppendLine("            }");
        sb.AppendLine("            else");
        sb.AppendLine("            {");
        sb.AppendLine("                Debug.LogError($\"配置类 {configType.Name} 没有静态Init方法\");");
        sb.AppendLine("            }");
        sb.AppendLine("        }");
        sb.AppendLine("        else");
        sb.AppendLine("        {");
        sb.AppendLine("            Debug.LogError($\"找不到配置文件: {configName}\");");
        sb.AppendLine("        }");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    private async UniTask LoadConfig<T>() where T : class");
        sb.AppendLine("    {");
        sb.AppendLine("        string configName = typeof(T).Name;");
        sb.AppendLine();
        sb.AppendLine("        string[] texts = ResManager.Instance.LoadConfig(configName);");
        sb.AppendLine("        if (texts != null)");
        sb.AppendLine("        {");
        sb.AppendLine("            string[] lines = texts;");
        sb.AppendLine("            var methodInfo = typeof(T).GetMethod(\"Init\", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);");
        sb.AppendLine("            if (methodInfo != null)");
        sb.AppendLine("            {");
        sb.AppendLine("                methodInfo.Invoke(null, lines);");
        sb.AppendLine("                // 设置初始化标志");
        sb.AppendLine("                var isInitField = typeof(T).GetField(\"isInit\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);");
        sb.AppendLine("                if (isInitField != null)");
        sb.AppendLine("                {");
        sb.AppendLine("                    isInitField.SetValue(null, true);");
        sb.AppendLine("                }");
        sb.AppendLine("                Debug.Log($\"加载配置: {typeof(T).Name} 成功\");");
        sb.AppendLine("            }");
        sb.AppendLine("            else");
        sb.AppendLine("            {");
        sb.AppendLine("                Debug.LogError($\"配置类 {typeof(T).Name} 没有静态Init方法\");");
        sb.AppendLine("            }");
        sb.AppendLine("        }");
        sb.AppendLine("        else");
        sb.AppendLine("        {");
        sb.AppendLine("            Debug.LogError($\"找不到配置文件: {configName}\");");
        sb.AppendLine("        }");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    public float GetLoadingProgress()");
        sb.AppendLine("    {");
        sb.AppendLine("        return loadingProgress;");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    private void ClearConfigDictionary<T>() where T : class");
        sb.AppendLine("    {");
        sb.AppendLine("        // 重置 T 初始化状态");
        sb.AppendLine("        var isInitField = typeof(T).GetField(\"isInit\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);");
        sb.AppendLine("        if (isInitField != null)");
        sb.AppendLine("        {");
        sb.AppendLine("            isInitField.SetValue(null, false);");
        sb.AppendLine("        }");
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("    public override void Release()");
        sb.AppendLine("    {");
        foreach (string className in configClasses)
        {
            sb.AppendLine($"        // 清空 {className} 字典");
            sb.AppendLine($"        ClearConfigDictionary<{className}>();");
        }
        sb.AppendLine("    }");
        sb.AppendLine();
        sb.AppendLine("#if UNITY_EDITOR");
        sb.AppendLine("    [MenuItem(\"Tools/Config/自检\")]");
        sb.AppendLine("    public static void CheckAndGenerateFastConfig()");
        sb.AppendLine("    {");
        sb.AppendLine("        // 获取 Editor Assembly");
        sb.AppendLine("        var editorAsm = System.AppDomain.CurrentDomain.GetAssemblies()");
        sb.AppendLine("            .FirstOrDefault(a => a.FullName.Contains(\"Editor\"));");
        sb.AppendLine();
        sb.AppendLine("        if (editorAsm == null)");
        sb.AppendLine("        {");
        sb.AppendLine("            Debug.LogError(\"[自检] 未找到 Editor Assembly,无法自检。\");");
        sb.AppendLine("            return;");
        sb.AppendLine("        }");
        sb.AppendLine();
        sb.AppendLine("        // 反射获取 ConfigGenerater 类型");
        sb.AppendLine("        var configGeneraterType = editorAsm.GetType(\"ConfigGenerater\");");
        sb.AppendLine("        if (configGeneraterType == null)");
        sb.AppendLine("        {");
        sb.AppendLine("            Debug.LogError(\"[自检] 未找到 ConfigGenerater 类型。\");");
        sb.AppendLine("            return;");
        sb.AppendLine("        }");
        sb.AppendLine();
        sb.AppendLine("        // 调用 GetAllConfigClasses 静态方法");
        sb.AppendLine("        var getAllConfigClassesMethod = configGeneraterType.GetMethod(\"GetAllConfigClasses\", BindingFlags.Public | BindingFlags.Static);");
        sb.AppendLine("        var allConfigClasses = getAllConfigClassesMethod?.Invoke(null, null) as List<string>;");
        sb.AppendLine("        if (allConfigClasses == null)");
        sb.AppendLine("        {");
        sb.AppendLine("            Debug.LogError(\"[自检] 获取全部配置类失败。\");");
        sb.AppendLine("            return;");
        sb.AppendLine("        }");
        sb.AppendLine();
        sb.AppendLine("        // 获取 ExcludeClassList 字段");
        sb.AppendLine("        var excludeField = configGeneraterType.GetField(\"ExcludeClassList\", BindingFlags.Public | BindingFlags.Static);");
        sb.AppendLine("        var excludeClassList = excludeField?.GetValue(null) as List<string> ?? new List<string>();");
        sb.AppendLine();
        sb.AppendLine("        // 排除不需要的类");
        sb.AppendLine("        var checkClasses = allConfigClasses.Where(c => !excludeClassList.Contains(c)).ToList();");
        sb.AppendLine();
        sb.AppendLine("        List<string> fastName = new List<string>();");
        sb.AppendLine();
        sb.AppendLine("        foreach (var className in checkClasses)");
        sb.AppendLine("        {");
        sb.AppendLine("            // 这里也要用 Editor Assembly 获取类型");
        sb.AppendLine("            var configType = editorAsm.GetType(className) ?? Type.GetType(className);");
        sb.AppendLine("            if (configType == null)");
        sb.AppendLine("            {");
        sb.AppendLine("                Debug.LogWarning($\"[自检] 未找到类型: {className}\");");
        sb.AppendLine("                continue;");
        sb.AppendLine("            }");
        sb.AppendLine();
        sb.AppendLine("            var sw = System.Diagnostics.Stopwatch.StartNew();");
        sb.AppendLine();
        sb.AppendLine("            // 反射调用静态Init方法");
        sb.AppendLine("            string configName = configType.Name;");
        sb.AppendLine("            if (configName.EndsWith(\"Config\"))");
        sb.AppendLine("                configName = configName.Substring(0, configName.Length - 6);");
        sb.AppendLine();
        sb.AppendLine("            string[] texts = ResManager.Instance.LoadConfig(configName);");
        sb.AppendLine("            if (texts != null)");
        sb.AppendLine("            {");
        sb.AppendLine("                string[] lines = texts;");
        sb.AppendLine("                var methodInfo = configType.GetMethod(\"Init\", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);");
        sb.AppendLine("                if (methodInfo != null)");
        sb.AppendLine("                {");
        sb.AppendLine("                    methodInfo.Invoke(null, new object[] { lines });");
        sb.AppendLine("                }");
        sb.AppendLine("            }");
        sb.AppendLine();
        sb.AppendLine("            sw.Stop();");
        sb.AppendLine();
        sb.AppendLine("            if (sw.ElapsedMilliseconds >= 500)");
        sb.AppendLine("            {");
        sb.AppendLine("                Debug.LogError($\"[自检] 加载配置 {configType.Name} 耗时较长: {sw.ElapsedMilliseconds} ms\");");
        sb.AppendLine("            }");
        sb.AppendLine("            else if (sw.ElapsedMilliseconds <= 5)");
        sb.AppendLine("            {");
        sb.AppendLine("                fastName.Add(configType.Name);");
        sb.AppendLine("            }");
        sb.AppendLine("            Debug.Log($\"[自检] 加载配置: {configType.Name} 用时: {sw.ElapsedMilliseconds} ms\");");
        sb.AppendLine("        }");
        sb.AppendLine();
        sb.AppendLine("        // 释放所有已加载的配置");
        sb.AppendLine("        foreach (var className in checkClasses)");
        sb.AppendLine("        {");
        sb.AppendLine("            var configType = editorAsm.GetType(className) ?? Type.GetType(className);");
        sb.AppendLine("            if (configType == null) continue;");
        sb.AppendLine("            var methodInfo = configType.GetMethod(\"ForceRelease\", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);");
        sb.AppendLine("            if (methodInfo != null)");
        sb.AppendLine("            {");
        sb.AppendLine("                methodInfo.Invoke(null, null);");
        sb.AppendLine("            }");
        sb.AppendLine("        }");
        sb.AppendLine();
        sb.AppendLine("        System.IO.File.WriteAllText(Application.dataPath + \"/fastConfig.txt\", string.Join(\"\\n\", fastName));");
        sb.AppendLine("        Debug.Log($\"[自检] fastConfig.txt 生成完毕,快速表有:{string.Join(\", \", fastName)}\");");
        sb.AppendLine("    }");
        sb.AppendLine("#endif");
        sb.AppendLine("}");
        return sb.ToString();
    }
}
}