少年修仙传客户端代码仓库
client_Wu Xijin
2018-08-14 fa1e861eaa0d06914823e88d1dd76f853d12f082
Core/GameEngine/Model/ConfigManager.cs
@@ -1,781 +1,774 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using TableConfig;
using UnityEngine;
using System.Threading;
public class ConfigManager : Singleton<ConfigManager>
{
    public static string CustomIV = "4vHKRj3yfzU=";
    public static string CustomKey = "xhVs6DRXLfUGxw+AhtfQdpQGoa+8SA9d";
    protected string[] lineStep = new string[] { "\r\n" }; //行间隔体
    protected string[] rowStep = new string[] { "\t" }; //段间隔体
    bool isPlaying = true;
    bool m_Inited = false;
    public bool inited {
        get { return m_Inited; }
        private set { m_Inited = value; }
    }
    Dictionary<int, Dictionary<string, ConfigBase>> configDictionary = new Dictionary<int, Dictionary<string, ConfigBase>>();
    public void RegisterGlobalEvent()
    {
        SnxxzGame.Instance.RemoveApplicationOutAction(OnApplicationOut);
        SnxxzGame.Instance.AddApplicationOutAction(OnApplicationOut);
    }
    public void PreLoadConfigs()
    {
        StartSyncTask<PriorBundleConfig>(AssetPath.Resource);
        StartSyncTask<PriorLanguageConfig>(AssetPath.Resource);
    }
    List<ConfigTask> configTasks = new List<ConfigTask>();
    public IEnumerator Co_LoadConfigs()
    {
        AddAsyncTask<IconConfig>();
        AddAsyncTask<ItemConfig>();
        AddAsyncTask<SkillConfig>();
        AddAsyncTask<mapnpcConfig>();
        AddAsyncTask<LoginSeverListConfig>();
        AddAsyncTask<DienstgradConfig>();
        AddAsyncTask<PlayerPropertyConfig>();
        AddAsyncTask<RealmConfig>();
        AddAsyncTask<ItemCompoundConfig>();
        AddAsyncTask<FuncConfigConfig>();
        AddAsyncTask<GodWeaponConfig>();
        AddAsyncTask<FuncOpenLVConfig>();
        AddAsyncTask<RichTextMsgReplaceConfig>();
        AddAsyncTask<SysInfoConfig>();
        AddAsyncTask<ItemPlusConfig>();
        AddAsyncTask<ItemPlusMaxConfig>();
        AddAsyncTask<PyTaskConfig>();
        AddAsyncTask<TASKINFOConfig>();
        AddAsyncTask<MailConfig>();
        AddAsyncTask<RuneTowerConfig>();
        AddAsyncTask<EquipWashConfig>();
        AddAsyncTask<EquipWashSpecConfig>();
        AddAsyncTask<AttrFruitConfig>();
        AddAsyncTask<RuneConfig>();
        AddAsyncTask<MapConfig>();
        AddAsyncTask<PlayerLVConfig>();
        AddAsyncTask<PetEatEquipConfig>();
        AddAsyncTask<PetInfoConfig>();
        AddAsyncTask<RandomNameConfig>();
        AddAsyncTask<PetClassCostConfig>();
        AddAsyncTask<NPCConfig>();
        AddAsyncTask<KickOutReasonConfig>();//检查断线原因
        AddAsyncTask<HorseConfig>();
        AddAsyncTask<HorseUpConfig>();
        AddAsyncTask<RankListConfig>();
        AddAsyncTask<OccupationNameConfig>();
        AddAsyncTask<EquipSuitAttrConfig>(); //装备套装属性
        AddAsyncTask<EquipSuitCompoundConfig>(); //装备套装锻造需要材料
        AddAsyncTask<DirtyWordConfig>();
        AddAsyncTask<EffectConfig>();
        AddAsyncTask<WingRefineAttrConfig>();
        AddAsyncTask<FamilyTechConfig>();
        AddAsyncTask<FamilyConfig>();
        AddAsyncTask<IconConfig>();
        AddAsyncTask<LanguageConfig>();
        AddAsyncTask<CreateRoleConfig>();
        AddAsyncTask<DamageNumConfig>();
        AddAsyncTask<DungeonConfig>();
        AddAsyncTask<JobSetupConfig>();
        AddAsyncTask<ModelResConfig>();
        AddAsyncTask<DailyQuestConfig>();
        AddAsyncTask<FaceConfig>();
        AddAsyncTask<DailyLivenessRewardConfig>();
        AddAsyncTask<JobNameConfig>();
        AddAsyncTask<MarketConfig>();
        AddAsyncTask<maptransportConfig>();
        AddAsyncTask<ItemPlusSumAttrConfig>();
        AddAsyncTask<RoleEquipStarsConfig>();
        AddAsyncTask<MonsterNameColorConfig>();
        AddAsyncTask<TreasureConfig>();
        AddAsyncTask<SuccessConfig>();
        AddAsyncTask<TreasureSkillConfig>();
        AddAsyncTask<mapAreaConfig>();
        AddAsyncTask<EquipDeComposeConfig>();
        AddAsyncTask<WindowSearchConfig>();
        AddAsyncTask<SignInConfig>();
        AddAsyncTask<ContinueSignInConfig>();
        AddAsyncTask<DungeonHintConfig>();
        AddAsyncTask<MapEventPointConfig>();
        AddAsyncTask<VIPAwardConfig>();
        AddAsyncTask<VipPrivilegeConfig>();
        AddAsyncTask<DailyQuestOpenTimeConfig>();
        AddAsyncTask<DungeonOpenTimeConfig>();
        AddAsyncTask<AppointItemConfig>();
        AddAsyncTask<EquipGSParamConfig>();
        AddAsyncTask<StoreConfig>();
        AddAsyncTask<WorldBossConfig>();
        AddAsyncTask<BossHomeConfig>();
        AddAsyncTask<PersonalBossConfig>();
        AddAsyncTask<ElderGodAreaConfig>();
        AddAsyncTask<RuneTowerFloorConfig>();
        AddAsyncTask<TreasureRefineConfig>();
        AddAsyncTask<AlchemyConfig>();
        AddAsyncTask<BlastFurnaceLVConfig>();
        AddAsyncTask<AlchemySpecConfig>();
        AddAsyncTask<QuestionBankConfig>();
        AddAsyncTask<WingRefineExpConfig>();
        AddAsyncTask<UnionLivenConfig>();
        AddAsyncTask<ActorShowConfig>();
        AddAsyncTask<FunctionForecastConfig>();
        AddAsyncTask<GmCmdConfig>();
        AddAsyncTask<GetItemWaysConfig>();
        AddAsyncTask<GuideConfig>();
        AddAsyncTask<ViewRoleFuncConfig>();
        AddAsyncTask<RoleStrongerConfig>();
        AddAsyncTask<RoleResourceConfig>();
        AddAsyncTask<AudioConfig>();
        AddAsyncTask<AreaCameraConfig>();
        AddAsyncTask<NPCDialogueConfig>();
        AddAsyncTask<TaskListConfig>();
        AddAsyncTask<DemonJarConfig>();
        AddAsyncTask<StoryMissionsConfig>();
        AddAsyncTask<DungeonStateTimeConfig>();
        AddAsyncTask<DungeonInspireConfig>();
        AddAsyncTask<RuneComposeConfig>();
        AddAsyncTask<BossInfoConfig>();
        AddAsyncTask<DialogConfig>();
        AddAsyncTask<SceneShadowConfig>();
        AddAsyncTask<ResourcesBackConfig>();
        AddAsyncTask<WeatherConfig>();
        AddAsyncTask<RuleConfig>();
        AddAsyncTask<MonsterRefreshPointConfig>();
        AddAsyncTask<DogzConfig>();
        AddAsyncTask<ChestsConfig>();
        AddAsyncTask<ChestsAwardConfig>();
        AddAsyncTask<NPCDropItemConfig>();
        AddAsyncTask<TeamTargetConfig>();
        AddAsyncTask<OSCBillRankAwardConfig>();
        AddAsyncTask<OSCBillTagAwardConfig>();
        AddAsyncTask<InSevenDaysConfig>();
        AddAsyncTask<OnlineAwardConfig>();
        AddAsyncTask<LVAawrdConfig>();
        AddAsyncTask<DemonRecommondPropertyConfig>();
        AddAsyncTask<InvestConfig>();
        AddAsyncTask<SuitEffectConfig>();
        AddAsyncTask<RefineStoveConfig>();
        AddAsyncTask<VIPKillNPCConfig>();
        AddAsyncTask<LoadingTipConfig>();
        AddAsyncTask<XMZZAchievementConfig>();
        AddAsyncTask<XBGetItemConfig>();
        AddAsyncTask<bossSkillTipsConfig>();
        AddAsyncTask<OSRedAchieveConfig>();
        AddAsyncTask<RedPackConfig>();
        AddAsyncTask<TreasureFindHostConfig>();
        AddAsyncTask<TreasureUpConfig>();
        AddAsyncTask<TreasurePrivilegeConfig>();
        AddAsyncTask<CTGConfig>();
        AddAsyncTask<MapResourcesConfig>();
        AddAsyncTask<FightPowerParamConfig>();
        AddAsyncTask<LoadingFunctionConfig>();
        AddAsyncTask<LoginAdConfig>();
        AddAsyncTask<FreeGoodsConfig>();
        AddAsyncTask<BossRebornConfig>();
        AddAsyncTask<UniquenessArriveConfig>();
        AddAsyncTask<AllPeoplePartyConfig>();
        AddAsyncTask<AllPeoplePartyAwardConfig>();
        AddAsyncTask<OrderInfoConfig>();
        AddAsyncTask<TrialExchangeConfig>();
        while (!AllCompleted())
        {
            var completedCount = 0;
            for (int i = 0; i < configTasks.Count; i++)
            {
                var task = configTasks[i];
                if (task.state == TaskState.ParseSuccess)
                {
                    completedCount++;
                }
            }
            var allowTaskCount = completedCount <= 7 ? GetMinWorkingTaskCount() : GetMaxWorkingTaskCount();
            var workingCount = 0;
            for (int i = 0; i < configTasks.Count; i++)
            {
                var task = configTasks[i];
                if (task.state > TaskState.None && task.state < TaskState.ParseSuccess)
                {
                    workingCount++;
                }
            }
            if (workingCount < allowTaskCount)
            {
                var leisureCount = allowTaskCount - workingCount;
                var startedTasksCount = 0;
                for (int i = 0; i < configTasks.Count; i++)
                {
                    var task = configTasks[i];
                    if (task.state == TaskState.None)
                    {
                        StartAsyncTask(task);
                        startedTasksCount++;
                    }
                    if (startedTasksCount >= leisureCount)
                    {
                        break;
                    }
                }
            }
            yield return null;
        }
    }
    public void SyncLoadConfigs()
    {
        StartSyncTask<NPCConfig>(AssetPath.ResourceOut);
        StartSyncTask<ModelResConfig>(AssetPath.ResourceOut);
        StartSyncTask<ActorShowConfig>(AssetPath.ResourceOut);
        StartSyncTask<IconConfig>(AssetPath.ResourceOut);
        StartSyncTask<SysInfoConfig>(AssetPath.ResourceOut);
        StartSyncTask<LanguageConfig>(AssetPath.ResourceOut);
    }
    public bool AllCompleted()
    {
        foreach (var task in configTasks)
        {
            if (task.state != TaskState.ParseSuccess)
            {
                // DesignDebug.LogFormat("未完成是配置解析任务:{0},当前状态:{1}", task.taskName, task.state);
                return false;
            }
        }
        return true;
    }
    public float GetProgress()
    {
        var count = 0;
        foreach (var task in configTasks)
        {
            if (task.state == TaskState.ParseSuccess)
            {
                count++;
            }
        }
        return (float)count / configTasks.Count;
    }
    public int GetTaskCount()
    {
        return configTasks.Count;
    }
    public void ConfigParsePostProcess()
    {
        foreach (var task in configTasks)
        {
            configDictionary[task.token] = task.container;
        }
        inited = true;
    }
    int GetMinWorkingTaskCount()
    {
        switch (Application.platform)
        {
            case RuntimePlatform.Android:
                if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 3.5f * 1024)
                {
                    return 4;
                }
                else if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 2.5f * 1024)
                {
                    return 2;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.IPhonePlayer:
                if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.WindowsEditor:
                return 50;
            default:
                return 1;
        }
    }
    int GetMaxWorkingTaskCount()
    {
        switch (Application.platform)
        {
            case RuntimePlatform.Android:
                if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 3.5f * 1024)
                {
                    return 20;
                }
                else if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 2.5f * 1024)
                {
                    return 10;
                }
                else if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.IPhonePlayer:
                if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024)
                {
                    return 10;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.WindowsEditor:
                return 50;
            default:
                return 5;
        }
    }
    ConfigTask AddAsyncTask<T>() where T : ConfigBase, new()
    {
        var typeName = typeof(T).Name;
        var path = string.Empty;
        var fileName = typeName.Substring(0, typeName.Length - 6);
        if (AssetSource.refdataFromEditor)
        {
            path = ResourcesPath.CONFIG_FODLER + "/" + fileName + ".txt";
        }
        else
        {
            var assetVersion = AssetVersionUtility.GetAssetVersion(StringUtility.Contact("config/", fileName, ".bytes"));
            path = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, assetVersion.relativePath);
        }
        var task = new ConfigTask(typeof(T), AssetSource.refdataFromEditor ? AssetPath.ResourceOut : AssetPath.External, path);
        Action<ConfigTask> launch = (ConfigTask _task) => { ReadFile(_task, OnEndReadFile<T>); };
        task.launch = launch;
        configTasks.Add(task);
        return task;
    }
    void StartAsyncTask(ConfigTask _task)
    {
        _task.state = TaskState.Working;
        _task.launch(_task);
    }
    void ReadFile(ConfigTask _task, Action<ConfigTask> _callBack)
    {
        ThreadPool.QueueUserWorkItem(
            (object _obj) =>
            {
                string[] lines = null;
                StreamReader sr = null;
                try
                {
                    if (_task.assetPath == AssetPath.ResourceOut)
                    {
                        var fileInfo = new FileInfo(_task.filePath);
                        var fs = fileInfo.OpenRead();
                        sr = new StreamReader(fs, Encoding.UTF8);
                        var content = sr.ReadToEnd();
                        lines = content.Split(lineStep, StringSplitOptions.None);
                    }
                    else if (_task.assetPath == AssetPath.External)
                    {
                        var tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
                        tripleDESCryptoServiceProvider.Key = Convert.FromBase64String(CustomKey);
                        tripleDESCryptoServiceProvider.IV = Convert.FromBase64String(CustomIV);
                        tripleDESCryptoServiceProvider.Mode = CipherMode.CBC;
                        tripleDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
                        var decryptor = tripleDESCryptoServiceProvider.CreateDecryptor();
                        var expectedSteam = new FileStream(_task.filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                        var bytes = new byte[expectedSteam.Length];
                        expectedSteam.Read(bytes, 0, bytes.Length);
                        var tableMs = new MemoryStream(bytes);
                        var crypS = new CryptoStream(tableMs, decryptor, CryptoStreamMode.Read);
                        sr = new StreamReader(crypS, Encoding.UTF8);
                        var content = sr.ReadToEnd();
                        lines = content.Split(lineStep, StringSplitOptions.None);
                    }
                    _task.state = TaskState.ReadFileSuccess;
                }
                catch (Exception ex)
                {
                    _task.state = TaskState.ReadFileFailure;
                    DesignDebug.Log(ex);
                }
                finally
                {
                    _task.contentLines = lines;
                    if (_callBack != null)
                    {
                        _callBack(_task);
                    }
                }
            }
            );
    }
    void AsyncParseConfig<T>(ConfigTask _task, Action<ConfigTask> _callBack) where T : ConfigBase, new()
    {
        ThreadPool.QueueUserWorkItem(
            (object _obj) =>
            {
                try
                {
                    var count = 0;
                    var container = _task.container as Dictionary<string, ConfigBase>;
                    for (int i = 3; i < _task.contentLines.Length; i++)
                    {
                        var contents = _task.contentLines[i].Split(rowStep, StringSplitOptions.None);
                        if (contents.Length <= 1)
                        {
                            continue;
                        }
                        var newConfig = new T();
                        newConfig.SetRawContent(contents);
                        newConfig.Parse();
                        newConfig.PostProcess();
                        if (newConfig is IConfigPostProcess)
                        {
                            (newConfig as IConfigPostProcess).OnConfigParseCompleted();
                        }
                        newConfig.parsed = true;
                        container[contents[0]] = newConfig;
                        count++;
                        if (count >= 500)
                        {
                            count = 0;
                            Thread.Sleep(30);
                        }
                    }
                    _task.state = TaskState.ParseSuccess;
                }
                catch (Exception ex)
                {
                    _task.state = TaskState.ParseFailure;
                    DesignDebug.Log(ex);
                }
                finally
                {
                    if (_callBack != null)
                    {
                        _callBack(_task);
                    }
                }
            }
            );
    }
    private void OnEndReadFile<T>(ConfigTask _task) where T : ConfigBase, new()
    {
        if (isPlaying && _task.state == TaskState.ReadFileFailure)
        {
            ReadFile(_task, OnEndReadFile<T>);
        }
        else
        {
            _task.capacity = Mathf.Max(_task.contentLines.Length - 3, 0);
            _task.container = new Dictionary<string, ConfigBase>(_task.capacity);
            AsyncParseConfig<T>(_task, OnEndParse<T>);
        }
    }
    private void OnEndParse<T>(ConfigTask _task) where T : ConfigBase, new()
    {
        if (isPlaying && _task.state == TaskState.ParseFailure)
        {
            Debug.LogFormat("配置表解析失败:{0}", _task.taskName);
            ReadFile(_task, OnEndReadFile<T>);
        }
    }
    private void StartSyncTask<T>(AssetPath _assetPath) where T : ConfigBase, new()
    {
        var typeName = typeof(T).Name;
        var fileName = typeName.Substring(0, typeName.Length - 6);
        string[] lines = null;
        var path = string.Empty;
        switch (_assetPath)
        {
            case AssetPath.Resource:
                path = StringUtility.Contact("Config/", fileName);
                var textAsset = Resources.Load<TextAsset>(path);
                lines = textAsset.text.Split(lineStep, StringSplitOptions.None);
                break;
            case AssetPath.ResourceOut:
                path = StringUtility.Contact(ResourcesPath.CONFIG_FODLER, "/", fileName, ".txt");
                lines = File.ReadAllLines(path, Encoding.UTF8);
                break;
            case AssetPath.External:
                var assetVersion = AssetVersionUtility.GetAssetVersion(StringUtility.Contact("config/", fileName, ".bytes"));
                path = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, assetVersion.relativePath);
                var provider = new TripleDESCryptoServiceProvider();
                provider.Key = Convert.FromBase64String(CustomKey);
                provider.IV = Convert.FromBase64String(CustomIV);
                provider.Mode = CipherMode.CBC;
                provider.Padding = PaddingMode.PKCS7;
                var decryptor = provider.CreateDecryptor();
                var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                var bytes = new byte[fs.Length];
                fs.Read(bytes, 0, bytes.Length);
                var ms = new MemoryStream(bytes);
                var crypS = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
                var sr = new StreamReader(crypS, Encoding.UTF8);
                var content = sr.ReadToEnd();
                lines = content.Split(lineStep, StringSplitOptions.None);
                break;
        }
        var task = new ConfigTask(typeof(T), _assetPath, path);
        configTasks.Add(task);
        task.contentLines = lines;
        if (lines != null && lines.Length > 3)
        {
            var length = Mathf.Max(lines.Length - 3, 0);
            task.capacity = length;
            task.container = new Dictionary<string, ConfigBase>(length);
            task.state = TaskState.ReadFileSuccess;
            SyncParseConfig<T>(task);
        }
        else
        {
            task.state = TaskState.ReadFileFailure;
        }
    }
    private void SyncParseConfig<T>(ConfigTask _task) where T : ConfigBase, new()
    {
        try
        {
            for (int i = 3; i < _task.contentLines.Length; i++)
            {
                var contents = _task.contentLines[i].Split(rowStep, StringSplitOptions.None);
                if (contents.Length <= 1)
                {
                    continue;
                }
                var newConfig = new T();
                newConfig.SetRawContent(contents);
                newConfig.Parse();
                newConfig.PostProcess();
                if (newConfig is IConfigPostProcess)
                {
                    (newConfig as IConfigPostProcess).OnConfigParseCompleted();
                }
                newConfig.parsed = true;
                _task.container[contents[0]] = newConfig;
            }
        }
        catch (Exception ex)
        {
            DesignDebug.Log(ex);
        }
        finally
        {
            _task.state = TaskState.ParseSuccess;
            configDictionary[_task.token] = _task.container;
        }
    }
    public T GetTemplate<T>(string _dwTemplateID) where T : ConfigBase, new()
    {
        if (string.IsNullOrEmpty(_dwTemplateID))
        {
            return null;
        }
        var token = typeof(T).MetadataToken;
        if (configDictionary.ContainsKey(token) == false)
        {
            DesignDebug.LogErrorFormat("not find the config:{0}", token);
            return null;
        }
        ConfigBase config = null;
        var dic = configDictionary[token];
        if (!dic.ContainsKey(_dwTemplateID))
        {
            DesignDebug.LogFormat("not find the config:{0},<color=#ff0000ff>ID:{1}</color>", typeof(T).Name, _dwTemplateID);
        }
        else
        {
            config = dic[_dwTemplateID];
        }
        if (config != null && !config.parsed)
        {
            config.Parse();
            config.PostProcess();
            config.parsed = true;
        }
        return config as T;
    }
    public T GetTemplate<T>(int _dwTemplateID) where T : ConfigBase, new()
    {
        return GetTemplate<T>(_dwTemplateID.ToString());
    }
    public bool ContainKey<T>(int _id)
    {
        return ContainKey<T>(_id.ToString());
    }
    public bool ContainKey<T>(string _key)
    {
        if (string.IsNullOrEmpty(_key))
        {
            return false;
        }
        var token = typeof(T).MetadataToken;
        if (configDictionary.ContainsKey(token) == false)
        {
            return false;
        }
        var dic = configDictionary[token];
        return dic.ContainsKey(_key);
    }
    public List<string> GetAllKeys<T>() where T : ConfigBase
    {
        var token = typeof(T).MetadataToken;
        if (!configDictionary.ContainsKey(token))
        {
            DesignDebug.LogErrorFormat("not find the dic of config: {0}", typeof(T).Name);
            return null;
        }
        var dicTemplate = configDictionary[token];
        return new List<string>(dicTemplate.Keys);
    }
    public List<T> GetAllValues<T>() where T : ConfigBase, new()
    {
        var token = typeof(T).MetadataToken;
        if (!configDictionary.ContainsKey(token))
        {
            DesignDebug.LogErrorFormat("not find the dic of config: {0}", typeof(T).Name);
            return null;
        }
        var configs = new List<T>();
        var dicTemplate = configDictionary[token];
        foreach (var value in dicTemplate.Values)
        {
            if (value != null && !value.parsed)
            {
                value.Parse();
                value.PostProcess();
                value.parsed = true;
            }
            configs.Add(value as T);
        }
        return configs;
    }
    class ConfigTask
    {
        public readonly Type type;
        public readonly int token;
        public readonly string taskName;
        public readonly AssetPath assetPath;
        public readonly string filePath;
        public Action<ConfigTask> launch;
        public int capacity = 0;
        public string[] contentLines;
        public Dictionary<string, ConfigBase> container;
        public TaskState state = TaskState.None;
        public ConfigTask(Type _type, AssetPath _assetPath, string _filePath)
        {
            type = _type;
            assetPath = _assetPath;
            taskName = type.Name;
            token = type.MetadataToken;
            filePath = _filePath;
        }
    }
    public enum TaskState
    {
        None = 0,
        Working = 1,
        ReadFileSuccess = 2,
        ReadFileFailure = 3,
        ParseFailure = 4,
        ParseSuccess = 5,
    }
    public enum AssetPath
    {
        Resource,
        ResourceOut,
        External,
    }
    private void OnApplicationOut()
    {
        isPlaying = false;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using TableConfig;
using UnityEngine;
using System.Threading;
public class ConfigManager : Singleton<ConfigManager>
{
    public readonly static string CustomIV = "4vHKRj3yfzU=";
    public readonly static string CustomKey = "xhVs6DRXLfUGxw+AhtfQdpQGoa+8SA9d";
    bool isPlaying = true;
    bool m_Inited = false;
    public bool inited {
        get { return m_Inited; }
        private set { m_Inited = value; }
    }
    Dictionary<int, Dictionary<string, ConfigBase>> configDictionary = new Dictionary<int, Dictionary<string, ConfigBase>>();
    public void RegisterGlobalEvent()
    {
        SnxxzGame.Instance.RemoveApplicationOutAction(OnApplicationOut);
        SnxxzGame.Instance.AddApplicationOutAction(OnApplicationOut);
    }
    public void PreLoadConfigs()
    {
        StartSyncTask<PriorBundleConfig>(AssetPath.Resource);
        StartSyncTask<PriorLanguageConfig>(AssetPath.Resource);
    }
    List<ConfigTask> configTasks = new List<ConfigTask>();
    public IEnumerator Co_LoadConfigs()
    {
        AddAsyncTask<IconConfig>();
        AddAsyncTask<ItemConfig>();
        AddAsyncTask<SkillConfig>();
        AddAsyncTask<TASKINFOConfig>();
        AddAsyncTask<mapnpcConfig>();
        AddAsyncTask<LoginSeverListConfig>();
        AddAsyncTask<DienstgradConfig>();
        AddAsyncTask<PlayerPropertyConfig>();
        AddAsyncTask<RealmConfig>();
        AddAsyncTask<ItemCompoundConfig>();
        AddAsyncTask<FuncConfigConfig>();
        AddAsyncTask<GodWeaponConfig>();
        AddAsyncTask<FuncOpenLVConfig>();
        AddAsyncTask<RichTextMsgReplaceConfig>();
        AddAsyncTask<SysInfoConfig>();
        AddAsyncTask<ItemPlusConfig>();
        AddAsyncTask<ItemPlusMaxConfig>();
        AddAsyncTask<PyTaskConfig>();
        AddAsyncTask<MailConfig>();
        AddAsyncTask<RuneTowerConfig>();
        AddAsyncTask<EquipWashConfig>();
        AddAsyncTask<EquipWashSpecConfig>();
        AddAsyncTask<AttrFruitConfig>();
        AddAsyncTask<RuneConfig>();
        AddAsyncTask<MapConfig>();
        AddAsyncTask<PlayerLVConfig>();
        AddAsyncTask<PetEatEquipConfig>();
        AddAsyncTask<PetInfoConfig>();
        AddAsyncTask<RandomNameConfig>();
        AddAsyncTask<PetClassCostConfig>();
        AddAsyncTask<NPCConfig>();
        AddAsyncTask<KickOutReasonConfig>();//检查断线原因
        AddAsyncTask<HorseConfig>();
        AddAsyncTask<HorseUpConfig>();
        AddAsyncTask<RankListConfig>();
        AddAsyncTask<OccupationNameConfig>();
        AddAsyncTask<EquipSuitAttrConfig>(); //装备套装属性
        AddAsyncTask<EquipSuitCompoundConfig>(); //装备套装锻造需要材料
        AddAsyncTask<DirtyWordConfig>();
        AddAsyncTask<EffectConfig>();
        AddAsyncTask<WingRefineAttrConfig>();
        AddAsyncTask<FamilyTechConfig>();
        AddAsyncTask<FamilyConfig>();
        AddAsyncTask<IconConfig>();
        AddAsyncTask<LanguageConfig>();
        AddAsyncTask<CreateRoleConfig>();
        AddAsyncTask<DamageNumConfig>();
        AddAsyncTask<DungeonConfig>();
        AddAsyncTask<JobSetupConfig>();
        AddAsyncTask<ModelResConfig>();
        AddAsyncTask<DailyQuestConfig>();
        AddAsyncTask<FaceConfig>();
        AddAsyncTask<DailyLivenessRewardConfig>();
        AddAsyncTask<JobNameConfig>();
        AddAsyncTask<MarketConfig>();
        AddAsyncTask<maptransportConfig>();
        AddAsyncTask<ItemPlusSumAttrConfig>();
        AddAsyncTask<RoleEquipStarsConfig>();
        AddAsyncTask<MonsterNameColorConfig>();
        AddAsyncTask<TreasureConfig>();
        AddAsyncTask<SuccessConfig>();
        AddAsyncTask<TreasureSkillConfig>();
        AddAsyncTask<mapAreaConfig>();
        AddAsyncTask<EquipDeComposeConfig>();
        AddAsyncTask<WindowSearchConfig>();
        AddAsyncTask<SignInConfig>();
        AddAsyncTask<ContinueSignInConfig>();
        AddAsyncTask<DungeonHintConfig>();
        AddAsyncTask<MapEventPointConfig>();
        AddAsyncTask<VIPAwardConfig>();
        AddAsyncTask<VipPrivilegeConfig>();
        AddAsyncTask<DailyQuestOpenTimeConfig>();
        AddAsyncTask<DungeonOpenTimeConfig>();
        AddAsyncTask<AppointItemConfig>();
        AddAsyncTask<EquipGSParamConfig>();
        AddAsyncTask<StoreConfig>();
        AddAsyncTask<WorldBossConfig>();
        AddAsyncTask<BossHomeConfig>();
        AddAsyncTask<PersonalBossConfig>();
        AddAsyncTask<ElderGodAreaConfig>();
        AddAsyncTask<RuneTowerFloorConfig>();
        AddAsyncTask<TreasureRefineConfig>();
        AddAsyncTask<AlchemyConfig>();
        AddAsyncTask<BlastFurnaceLVConfig>();
        AddAsyncTask<AlchemySpecConfig>();
        AddAsyncTask<QuestionBankConfig>();
        AddAsyncTask<WingRefineExpConfig>();
        AddAsyncTask<UnionLivenConfig>();
        AddAsyncTask<ActorShowConfig>();
        AddAsyncTask<FunctionForecastConfig>();
        AddAsyncTask<GmCmdConfig>();
        AddAsyncTask<GetItemWaysConfig>();
        AddAsyncTask<GuideConfig>();
        AddAsyncTask<ViewRoleFuncConfig>();
        AddAsyncTask<RoleStrongerConfig>();
        AddAsyncTask<RoleResourceConfig>();
        AddAsyncTask<AudioConfig>();
        AddAsyncTask<AreaCameraConfig>();
        AddAsyncTask<NPCDialogueConfig>();
        AddAsyncTask<TaskListConfig>();
        AddAsyncTask<DemonJarConfig>();
        AddAsyncTask<StoryMissionsConfig>();
        AddAsyncTask<DungeonStateTimeConfig>();
        AddAsyncTask<DungeonInspireConfig>();
        AddAsyncTask<RuneComposeConfig>();
        AddAsyncTask<BossInfoConfig>();
        AddAsyncTask<DialogConfig>();
        AddAsyncTask<SceneShadowConfig>();
        AddAsyncTask<ResourcesBackConfig>();
        AddAsyncTask<WeatherConfig>();
        AddAsyncTask<RuleConfig>();
        AddAsyncTask<MonsterRefreshPointConfig>();
        AddAsyncTask<DogzConfig>();
        AddAsyncTask<ChestsConfig>();
        AddAsyncTask<ChestsAwardConfig>();
        AddAsyncTask<NPCDropItemConfig>();
        AddAsyncTask<TeamTargetConfig>();
        AddAsyncTask<OSCBillRankAwardConfig>();
        AddAsyncTask<OSCBillTagAwardConfig>();
        AddAsyncTask<InSevenDaysConfig>();
        AddAsyncTask<OnlineAwardConfig>();
        AddAsyncTask<LVAawrdConfig>();
        AddAsyncTask<DemonRecommondPropertyConfig>();
        AddAsyncTask<InvestConfig>();
        AddAsyncTask<SuitEffectConfig>();
        AddAsyncTask<RefineStoveConfig>();
        AddAsyncTask<VIPKillNPCConfig>();
        AddAsyncTask<LoadingTipConfig>();
        AddAsyncTask<XMZZAchievementConfig>();
        AddAsyncTask<XBGetItemConfig>();
        AddAsyncTask<bossSkillTipsConfig>();
        AddAsyncTask<OSRedAchieveConfig>();
        AddAsyncTask<RedPackConfig>();
        AddAsyncTask<TreasureFindHostConfig>();
        AddAsyncTask<TreasureUpConfig>();
        AddAsyncTask<TreasurePrivilegeConfig>();
        AddAsyncTask<CTGConfig>();
        AddAsyncTask<MapResourcesConfig>();
        AddAsyncTask<FightPowerParamConfig>();
        AddAsyncTask<LoadingFunctionConfig>();
        AddAsyncTask<LoginAdConfig>();
        AddAsyncTask<FreeGoodsConfig>();
        AddAsyncTask<BossRebornConfig>();
        AddAsyncTask<UniquenessArriveConfig>();
        AddAsyncTask<AllPeoplePartyConfig>();
        AddAsyncTask<AllPeoplePartyAwardConfig>();
        AddAsyncTask<OrderInfoConfig>();
        AddAsyncTask<TrialExchangeConfig>();
        while (!AllCompleted())
        {
            var completedCount = 0;
            for (int i = 0; i < configTasks.Count; i++)
            {
                var task = configTasks[i];
                if (task.state == TaskState.ParseSuccess)
                {
                    completedCount++;
                }
            }
            var allowTaskCount = completedCount <= 7 ? GetMinWorkingTaskCount() : GetMaxWorkingTaskCount();
            var workingCount = 0;
            for (int i = 0; i < configTasks.Count; i++)
            {
                var task = configTasks[i];
                if (task.state > TaskState.None && task.state < TaskState.ParseSuccess)
                {
                    workingCount++;
                }
            }
            if (workingCount < allowTaskCount)
            {
                var leisureCount = allowTaskCount - workingCount;
                var startedTasksCount = 0;
                for (int i = 0; i < configTasks.Count; i++)
                {
                    var task = configTasks[i];
                    if (task.state == TaskState.None)
                    {
                        StartAsyncTask(task);
                        startedTasksCount++;
                    }
                    if (startedTasksCount >= leisureCount)
                    {
                        break;
                    }
                }
            }
            yield return null;
        }
    }
    public void SyncLoadConfigs()
    {
        StartSyncTask<NPCConfig>(AssetPath.ResourceOut);
        StartSyncTask<ModelResConfig>(AssetPath.ResourceOut);
        StartSyncTask<ActorShowConfig>(AssetPath.ResourceOut);
        StartSyncTask<IconConfig>(AssetPath.ResourceOut);
        StartSyncTask<SysInfoConfig>(AssetPath.ResourceOut);
        StartSyncTask<LanguageConfig>(AssetPath.ResourceOut);
    }
    public bool AllCompleted()
    {
        foreach (var task in configTasks)
        {
            if (task.state != TaskState.ParseSuccess)
            {
                // DesignDebug.LogFormat("未完成是配置解析任务:{0},当前状态:{1}", task.taskName, task.state);
                return false;
            }
        }
        return true;
    }
    public float GetProgress()
    {
        var count = 0;
        foreach (var task in configTasks)
        {
            if (task.state == TaskState.ParseSuccess)
            {
                count++;
            }
        }
        return (float)count / configTasks.Count;
    }
    public int GetTaskCount()
    {
        return configTasks.Count;
    }
    public void ConfigParsePostProcess()
    {
        foreach (var task in configTasks)
        {
            configDictionary[task.token] = task.container;
        }
        inited = true;
    }
    int GetMinWorkingTaskCount()
    {
        switch (Application.platform)
        {
            case RuntimePlatform.Android:
                if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 3.5f * 1024)
                {
                    return 4;
                }
                else if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 2.5f * 1024)
                {
                    return 2;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.IPhonePlayer:
                if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.WindowsEditor:
                return 50;
            default:
                return 1;
        }
    }
    int GetMaxWorkingTaskCount()
    {
        switch (Application.platform)
        {
            case RuntimePlatform.Android:
                if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 3.5f * 1024)
                {
                    return 20;
                }
                else if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 2.5f * 1024)
                {
                    return 10;
                }
                else if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024)
                {
                    return 4;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.IPhonePlayer:
                if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024)
                {
                    return 10;
                }
                else
                {
                    return 1;
                }
            case RuntimePlatform.WindowsEditor:
                return 50;
            default:
                return 5;
        }
    }
    ConfigTask AddAsyncTask<T>() where T : ConfigBase, new()
    {
        var typeName = typeof(T).Name;
        var path = string.Empty;
        var fileName = typeName.Substring(0, typeName.Length - 6);
        if (AssetSource.refdataFromEditor)
        {
            path = ResourcesPath.CONFIG_FODLER + "/" + fileName + ".txt";
        }
        else
        {
            path = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, "config/", fileName, ".bytes");
        }
        var task = new ConfigTask(typeof(T), AssetSource.refdataFromEditor ? AssetPath.ResourceOut : AssetPath.External, path);
        Action<ConfigTask> launch = (ConfigTask _task) => { ReadFile(_task, OnEndReadFile<T>); };
        task.launch = launch;
        configTasks.Add(task);
        return task;
    }
    void StartAsyncTask(ConfigTask _task)
    {
        _task.state = TaskState.Working;
        _task.launch(_task);
    }
    void ReadFile(ConfigTask _task, Action<ConfigTask> _callBack)
    {
        ThreadPool.QueueUserWorkItem(
            (object _obj) =>
            {
                string[] lines = null;
                StreamReader sr = null;
                try
                {
                    if (_task.assetPath == AssetPath.ResourceOut)
                    {
                        lines = File.ReadAllLines(_task.filePath, Encoding.UTF8);
                    }
                    else if (_task.assetPath == AssetPath.External)
                    {
                        var tripleDESCryptoServiceProvider = new TripleDESCryptoServiceProvider();
                        tripleDESCryptoServiceProvider.Key = Convert.FromBase64String(CustomKey);
                        tripleDESCryptoServiceProvider.IV = Convert.FromBase64String(CustomIV);
                        tripleDESCryptoServiceProvider.Mode = CipherMode.CBC;
                        tripleDESCryptoServiceProvider.Padding = PaddingMode.PKCS7;
                        var decryptor = tripleDESCryptoServiceProvider.CreateDecryptor();
                        var expectedSteam = new FileStream(_task.filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                        var bytes = new byte[expectedSteam.Length];
                        expectedSteam.Read(bytes, 0, bytes.Length);
                        var tableMs = new MemoryStream(bytes);
                        var crypS = new CryptoStream(tableMs, decryptor, CryptoStreamMode.Read);
                        sr = new StreamReader(crypS, Encoding.UTF8);
                        var content = sr.ReadToEnd();
                        lines = content.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                    }
                    _task.state = TaskState.ReadFileSuccess;
                }
                catch (Exception ex)
                {
                    _task.state = TaskState.ReadFileFailure;
                    DesignDebug.Log(ex);
                }
                finally
                {
                    _task.contentLines = lines;
                    if (_callBack != null)
                    {
                        _callBack(_task);
                    }
                }
            }
            );
    }
    void AsyncParseConfig<T>(ConfigTask _task, Action<ConfigTask> _callBack) where T : ConfigBase, new()
    {
        ThreadPool.QueueUserWorkItem(
            (object _obj) =>
            {
                try
                {
                    var count = 0;
                    var container = _task.container as Dictionary<string, ConfigBase>;
                    for (int i = 3; i < _task.contentLines.Length; i++)
                    {
                        var contents = _task.contentLines[i].Split(new string[] { "\t" }, StringSplitOptions.None);
                        if (contents.Length <= 1)
                        {
                            continue;
                        }
                        var newConfig = new T();
                        newConfig.SetRawContent(contents);
                        newConfig.Parse();
                        newConfig.PostProcess();
                        if (newConfig is IConfigPostProcess)
                        {
                            (newConfig as IConfigPostProcess).OnConfigParseCompleted();
                        }
                        newConfig.parsed = true;
                        container[contents[0]] = newConfig;
                        count++;
                        if (count >= 500)
                        {
                            count = 0;
                            Thread.Sleep(30);
                        }
                    }
                    _task.state = TaskState.ParseSuccess;
                }
                catch (Exception ex)
                {
                    _task.state = TaskState.ParseFailure;
                    DesignDebug.Log(ex);
                }
                finally
                {
                    if (_callBack != null)
                    {
                        _callBack(_task);
                    }
                }
            }
            );
    }
    private void OnEndReadFile<T>(ConfigTask _task) where T : ConfigBase, new()
    {
        if (isPlaying && _task.state == TaskState.ReadFileFailure)
        {
            ReadFile(_task, OnEndReadFile<T>);
        }
        else
        {
            _task.capacity = Mathf.Max(_task.contentLines.Length - 3, 0);
            _task.container = new Dictionary<string, ConfigBase>(_task.capacity);
            AsyncParseConfig<T>(_task, OnEndParse<T>);
        }
    }
    private void OnEndParse<T>(ConfigTask _task) where T : ConfigBase, new()
    {
        if (isPlaying && _task.state == TaskState.ParseFailure)
        {
            Debug.LogFormat("配置表解析失败:{0}", _task.taskName);
            ReadFile(_task, OnEndReadFile<T>);
        }
    }
    private void StartSyncTask<T>(AssetPath _assetPath) where T : ConfigBase, new()
    {
        var typeName = typeof(T).Name;
        var fileName = typeName.Substring(0, typeName.Length - 6);
        string[] lines = null;
        var path = string.Empty;
        switch (_assetPath)
        {
            case AssetPath.Resource:
                path = StringUtility.Contact("Config/", fileName);
                var textAsset = Resources.Load<TextAsset>(path);
                lines = textAsset.text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                break;
            case AssetPath.ResourceOut:
                path = StringUtility.Contact(ResourcesPath.CONFIG_FODLER, "/", fileName, ".txt");
                lines = File.ReadAllLines(path, Encoding.UTF8);
                break;
            case AssetPath.External:
                var assetVersion = AssetVersionUtility.GetAssetVersion(StringUtility.Contact("config/", fileName, ".bytes"));
                path = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, assetVersion.relativePath);
                var provider = new TripleDESCryptoServiceProvider();
                provider.Key = Convert.FromBase64String(CustomKey);
                provider.IV = Convert.FromBase64String(CustomIV);
                provider.Mode = CipherMode.CBC;
                provider.Padding = PaddingMode.PKCS7;
                var decryptor = provider.CreateDecryptor();
                var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                var bytes = new byte[fs.Length];
                fs.Read(bytes, 0, bytes.Length);
                var ms = new MemoryStream(bytes);
                var crypS = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
                var sr = new StreamReader(crypS, Encoding.UTF8);
                var content = sr.ReadToEnd();
                lines = content.Split(new string[] { "\r\n" }, StringSplitOptions.None);
                break;
        }
        var task = new ConfigTask(typeof(T), _assetPath, path);
        configTasks.Add(task);
        task.contentLines = lines;
        if (lines != null && lines.Length > 3)
        {
            var length = Mathf.Max(lines.Length - 3, 0);
            task.capacity = length;
            task.container = new Dictionary<string, ConfigBase>(length);
            task.state = TaskState.ReadFileSuccess;
            SyncParseConfig<T>(task);
        }
        else
        {
            task.state = TaskState.ReadFileFailure;
        }
    }
    private void SyncParseConfig<T>(ConfigTask _task) where T : ConfigBase, new()
    {
        try
        {
            for (int i = 3; i < _task.contentLines.Length; i++)
            {
                var contents = _task.contentLines[i].Split(new string[] { "\t" }, StringSplitOptions.None);
                if (contents.Length <= 1)
                {
                    continue;
                }
                var newConfig = new T();
                newConfig.SetRawContent(contents);
                newConfig.Parse();
                newConfig.PostProcess();
                if (newConfig is IConfigPostProcess)
                {
                    (newConfig as IConfigPostProcess).OnConfigParseCompleted();
                }
                newConfig.parsed = true;
                _task.container[contents[0]] = newConfig;
            }
        }
        catch (Exception ex)
        {
            DesignDebug.Log(ex);
        }
        finally
        {
            _task.state = TaskState.ParseSuccess;
            configDictionary[_task.token] = _task.container;
        }
    }
    public T GetTemplate<T>(string _dwTemplateID) where T : ConfigBase, new()
    {
        if (string.IsNullOrEmpty(_dwTemplateID))
        {
            return null;
        }
        var token = typeof(T).MetadataToken;
        if (configDictionary.ContainsKey(token) == false)
        {
            DesignDebug.LogErrorFormat("not find the config:{0}", token);
            return null;
        }
        ConfigBase config = null;
        var dic = configDictionary[token];
        if (!dic.ContainsKey(_dwTemplateID))
        {
            DesignDebug.LogFormat("not find the config:{0},<color=#ff0000ff>ID:{1}</color>", typeof(T).Name, _dwTemplateID);
        }
        else
        {
            config = dic[_dwTemplateID];
        }
        if (config != null && !config.parsed)
        {
            config.Parse();
            config.PostProcess();
            config.parsed = true;
        }
        return config as T;
    }
    public T GetTemplate<T>(int _dwTemplateID) where T : ConfigBase, new()
    {
        return GetTemplate<T>(_dwTemplateID.ToString());
    }
    public bool ContainKey<T>(int _id)
    {
        return ContainKey<T>(_id.ToString());
    }
    public bool ContainKey<T>(string _key)
    {
        if (string.IsNullOrEmpty(_key))
        {
            return false;
        }
        var token = typeof(T).MetadataToken;
        if (configDictionary.ContainsKey(token) == false)
        {
            return false;
        }
        var dic = configDictionary[token];
        return dic.ContainsKey(_key);
    }
    public List<string> GetAllKeys<T>() where T : ConfigBase
    {
        var token = typeof(T).MetadataToken;
        if (!configDictionary.ContainsKey(token))
        {
            DesignDebug.LogErrorFormat("not find the dic of config: {0}", typeof(T).Name);
            return null;
        }
        var dicTemplate = configDictionary[token];
        return new List<string>(dicTemplate.Keys);
    }
    public List<T> GetAllValues<T>() where T : ConfigBase, new()
    {
        var token = typeof(T).MetadataToken;
        if (!configDictionary.ContainsKey(token))
        {
            DesignDebug.LogErrorFormat("not find the dic of config: {0}", typeof(T).Name);
            return null;
        }
        var configs = new List<T>();
        var dicTemplate = configDictionary[token];
        foreach (var value in dicTemplate.Values)
        {
            if (value != null && !value.parsed)
            {
                value.Parse();
                value.PostProcess();
                value.parsed = true;
            }
            configs.Add(value as T);
        }
        return configs;
    }
    class ConfigTask
    {
        public readonly Type type;
        public readonly int token;
        public readonly string taskName;
        public readonly AssetPath assetPath;
        public readonly string filePath;
        public Action<ConfigTask> launch;
        public int capacity = 0;
        public string[] contentLines;
        public Dictionary<string, ConfigBase> container;
        public TaskState state = TaskState.None;
        public ConfigTask(Type _type, AssetPath _assetPath, string _filePath)
        {
            type = _type;
            assetPath = _assetPath;
            taskName = type.Name;
            token = type.MetadataToken;
            filePath = _filePath;
        }
    }
    public enum TaskState
    {
        None = 0,
        Working = 1,
        ReadFileSuccess = 2,
        ReadFileFailure = 3,
        ParseFailure = 4,
        ParseSuccess = 5,
    }
    public enum AssetPath
    {
        Resource,
        ResourceOut,
        External,
    }
    private void OnApplicationOut()
    {
        isPlaying = false;
    }
}