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 { 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> configDictionary = new Dictionary>(); public void RegisterGlobalEvent() { SnxxzGame.Instance.RemoveApplicationOutAction(OnApplicationOut); SnxxzGame.Instance.AddApplicationOutAction(OnApplicationOut); } public void PreLoadConfigs() { StartSyncTask(AssetPath.Resource); StartSyncTask(AssetPath.Resource); } List configTasks = new List(); public IEnumerator Co_LoadConfigs() { AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask();//检查断线原因 AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); //装备套装属性 AddAsyncTask(); //装备套装锻造需要材料 AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); AddAsyncTask(); 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(AssetPath.ResourceOut); StartSyncTask(AssetPath.ResourceOut); StartSyncTask(AssetPath.ResourceOut); StartSyncTask(AssetPath.ResourceOut); StartSyncTask(AssetPath.ResourceOut); StartSyncTask(AssetPath.ResourceOut); StartSyncTask(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() 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 launch = (ConfigTask _task) => { ReadFile(_task, OnEndReadFile); }; task.launch = launch; configTasks.Add(task); return task; } void StartAsyncTask(ConfigTask _task) { _task.state = TaskState.Working; _task.launch(_task); } void ReadFile(ConfigTask _task, Action _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; DebugEx.Log(ex); } finally { _task.contentLines = lines; if (_callBack != null) { _callBack(_task); } } } ); } void AsyncParseConfig(ConfigTask _task, Action _callBack) where T : ConfigBase, new() { ThreadPool.QueueUserWorkItem( (object _obj) => { try { var count = 0; var container = _task.container as Dictionary; 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; DebugEx.Log(ex); } finally { if (_callBack != null) { _callBack(_task); } } } ); } private void OnEndReadFile(ConfigTask _task) where T : ConfigBase, new() { if (isPlaying && _task.state == TaskState.ReadFileFailure) { ReadFile(_task, OnEndReadFile); } else { _task.capacity = Mathf.Max(_task.contentLines.Length - 3, 0); _task.container = new Dictionary(_task.capacity); AsyncParseConfig(_task, OnEndParse); } } private void OnEndParse(ConfigTask _task) where T : ConfigBase, new() { if (isPlaying && _task.state == TaskState.ParseFailure) { Debug.LogFormat("配置表解析失败:{0}", _task.taskName); ReadFile(_task, OnEndReadFile); } } private void StartSyncTask(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(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(length); task.state = TaskState.ReadFileSuccess; SyncParseConfig(task); } else { task.state = TaskState.ReadFileFailure; } } private void SyncParseConfig(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) { DebugEx.Log(ex); } finally { _task.state = TaskState.ParseSuccess; configDictionary[_task.token] = _task.container; } } public T GetTemplate(string _dwTemplateID) where T : ConfigBase, new() { if (string.IsNullOrEmpty(_dwTemplateID)) { return null; } var token = typeof(T).MetadataToken; if (configDictionary.ContainsKey(token) == false) { DebugEx.LogErrorFormat("not find the config:{0}", token); return null; } ConfigBase config = null; var dic = configDictionary[token]; if (!dic.ContainsKey(_dwTemplateID)) { DebugEx.LogFormat("not find the config:{0},ID:{1}", 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(int _dwTemplateID) where T : ConfigBase, new() { return GetTemplate(_dwTemplateID.ToString()); } public bool ContainKey(int _id) { return ContainKey(_id.ToString()); } public bool ContainKey(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 GetAllKeys() where T : ConfigBase { var token = typeof(T).MetadataToken; if (!configDictionary.ContainsKey(token)) { DebugEx.LogErrorFormat("not find the dic of config: {0}", typeof(T).Name); return null; } var dicTemplate = configDictionary[token]; return new List(dicTemplate.Keys); } public List GetAllValues() where T : ConfigBase, new() { var token = typeof(T).MetadataToken; if (!configDictionary.ContainsKey(token)) { DebugEx.LogErrorFormat("not find the dic of config: {0}", typeof(T).Name); return null; } var configs = new List(); 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 launch; public int capacity = 0; public string[] contentLines; public Dictionary 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; } }