using System.Collections; using System.Collections.Generic; using UnityEngine; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.IO; using LitJson; using System; using Unity.Burst.CompilerServices; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.ComponentModel; /// /// 断线重连管理 /// public class ReconnectMgr : SingletonMono { [HideInInspector] public string localStatFileName = "realtimeStat.json";//保存文件的文件名 [HideInInspector] public int countDown_AutoSave = 600;//自动保存的时间间隔 private TB_UserExamStat UserExamStat = new TB_UserExamStat(); private string localStatPath = ""; private Coroutine coroutine;//自动保存倒计时 //[HideInInspector] //public List experiencedScene = new List();//用户经历过的场景 /// /// 初始化函数,记录时间间隔 /// public void Init() { localStatPath = Application.streamingAssetsPath + "/" + localStatFileName; //UserExamStat.experiencedScene.Clear();//清空用户经历过的场景 //experiencedScene.Clear(); } /// /// 用户每经历一个场景就需要保存一个场景的数据 /// //public bool IntoNewScene(string sceneName) //{ // if (UserExamStat.experiencedScene.Contains(sceneName)) // return false; // else // { // UserExamStat.experiencedScene.Add(sceneName); // return true; // } //} ReconnectMgr()//构造函数 { Init(); } /// /// 记录用户状态 /// public void RealtimeStatWriter() { //记录步骤相关各项信息 UserExamStat.schemeID = ProcessManager.Instance.schemeID; //记录得分情况 ScoreBase scoreBase = FindFirstObjectByType(); UserExamStat.systemID = scoreBase.systemId; UserExamStat.allSubScore.Clear(); if (scoreBase != null) { foreach (var item in scoreBase.GetStepScore()) { ReconnectSubScoreInfo sub = new ReconnectSubScoreInfo(); sub.index = item.Key; sub.subProcessId = item.Value.subProcessId; sub.currentScore = item.Value.currentScore; sub.isDone = item.Value.isDone; UserExamStat.allSubScore.Add(sub); }; //保存场景内独有信息 UserExamStat.currentSceneOtherInfo = scoreBase.SaveSceneBufferList(); } //记录装备材料信息 UserExamStat.allToolAndMaterial.Clear(); UserExamStat.currentSceneTools.Clear(); Dictionary> toolAndMaterialDic = PacksackBagMgr.Instance.GetCurrentBagData(); foreach (var item in toolAndMaterialDic) { foreach (var itemInfo in item.Value) { UserExamStat.allToolAndMaterial.Add(((ItemInfo)itemInfo).toolName); ReconnectItemInfo rec = new ReconnectItemInfo();//获取场景内(工具间)所有可以装备材料的物品 rec.toolId = itemInfo.toolId; rec.toolName = itemInfo.toolName; rec.triggerID = itemInfo.triggerID; //rec.toolOrDeviceOrMaterial = item.itemInfo.toolOrDeviceOrMaterial; rec.selfPosInToolRoom = itemInfo.selfPosInToolRoom; UserExamStat.currentSceneTools.Add(rec); } } //记录已穿戴设备 UserExamStat.allWear.Clear(); Dictionary wearDic = PacksackBagMgr.Instance.wearDic; foreach (var item in wearDic) { UserExamStat.allWear.Add(((ItemInfo)item.Value).toolName); } //获取当前所加载场景的名字 UserExamStat.sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; //获取场景内(现场)所有可以出发的装置 UserExamStat.currentSceneTriggers.Clear(); PermanentTriggerBase[] allPermanentTriggers = FindObjectsOfType(); foreach (PermanentTriggerBase item in allPermanentTriggers) { ReconnectTriggerInfo ret = new ReconnectTriggerInfo(); ret.triggerName = item.triggerName; ret.triggerID = item.triggerID; ret.selfPosInScene = item.transform.localPosition; ret.selfRotInScene = item.transform.localEulerAngles; ret.triggerInfo = GetTriggerAttribute(item);//item.SaveCurrentTriggerStat(); UserExamStat.currentSceneTriggers.Add(ret); } //转换为JSON var settings = new JsonSerializerSettings(); settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; settings.Formatting = Formatting.Indented;//避免循环引用(继承其他类) string UserJson = JsonConvert.SerializeObject(UserExamStat, settings); Debug.Log("自动保存成功"); File.WriteAllText(localStatPath, UserJson); } /// /// 获取常驻交互的属性 /// /// public string GetTriggerAttribute(PermanentTriggerBase permanentTriggerBase) { JsonData ptbData = new JsonData(); FieldInfo[] fieldInfo = permanentTriggerBase.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo field in fieldInfo) { if (field.GetCustomAttribute() != null) { ReconnetAtrribute attribute = field.GetCustomAttribute(); object value = field.GetValue(permanentTriggerBase); ptbData[field.Name] = value.ToString(); } } //return Regex.Unescape(ptbData.ToJson()); return ptbData.ToJson(); } public void SetTriggerAttribute(string triggerJson, PermanentTriggerBase permanentTriggerBase) { JsonData ptbData = JsonMapper.ToObject(triggerJson); FieldInfo[] fieldInfo = permanentTriggerBase.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo field in fieldInfo) { if (field.GetCustomAttribute() != null) { try { ReconnetAtrribute attribute = field.GetCustomAttribute(); Type type = field.GetValue(permanentTriggerBase).GetType(); string tmp = ptbData[field.Name].ToString(); field.SetValue(permanentTriggerBase, Convert.ChangeType(tmp, type)); }catch (Exception ex) { Debug.LogError("SetTriggerAttribute恢复错误:" + ex.ToString()); } } } } /// /// 读取用户状态(先使用同步,后用异步) /// public bool RealtimeStatReader() { if (File.Exists(localStatPath)) { try { StreamReader sr = new StreamReader(localStatPath); string user_last_stat = sr.ReadToEnd(); sr.Close(); UserExamStat = JsonMapper.ToObject(user_last_stat); return true; } catch (System.Exception e) { Debug.LogError(e.ToString()); return false; } } else { return false; } } /// /// 恢复现场 /// public void RecoverScene() { //先恢复场景 ScenesManager.Instance.LoadSceneAsyn(UserExamStat.sceneName, () => { //右侧工具栏切换 if (!GameManager.UIMgr.GetPanel())//office场景下,右侧工具栏可能会隐藏 { GameManager.UIMgr.ShowPanel(E_UI_Layer.Mid, (panel) => { panel.Init(); GameManager.EventMgr.EventTrigger(Enum_EventType.SwitchScene, GameManager.RunModelMgr.SceneType); }); } else GameManager.EventMgr.EventTrigger(Enum_EventType.SwitchScene, GameManager.RunModelMgr.SceneType); //恢复背包中的装备 TooRoomMannger tooRoomMannger = FindAnyObjectByType(); List itemInPack = ToolAndmaterialMgr.Instance.CreateItemInfoByName(UserExamStat.allToolAndMaterial); foreach (ItemInfo item in itemInPack) { for (int j = 0; j < UserExamStat.currentSceneTools.Count; j++) { if (item.toolName == UserExamStat.currentSceneTools[j].toolName) { item.selfPosInToolRoom = UserExamStat.currentSceneTools[j].selfPosInToolRoom; UserExamStat.currentSceneTools.RemoveAt(j); break; } } PacksackBagMgr.Instance.AddOneToolOrMater(item); } if (tooRoomMannger != null) tooRoomMannger.RemoveRepeat(); //恢复已穿戴的装备 List itemWear = ToolAndmaterialMgr.Instance.CreateItemInfoByName(UserExamStat.allWear); foreach (ItemInfo item in itemWear) { PacksackBagMgr.Instance.WearItemState(item, true); if (tooRoomMannger != null)//如果在工具间,则修改穿着 { tooRoomMannger.Wear(item.toolName, true); } } //恢复场景内各个触发器状态 PermanentTriggerBase[] allPermanentTriggers = FindObjectsOfType(); List allReconTrigs = UserExamStat.currentSceneTriggers; foreach (PermanentTriggerBase item in allPermanentTriggers) { item.gameObject.SetActive(false); foreach (ReconnectTriggerInfo ret in allReconTrigs) { if (item.triggerName == ret.triggerName) { item.gameObject.SetActive(true); if (item.gameObject.GetComponent() == null)//工具材料已经恢复过了 { item.transform.localPosition = ret.selfPosInScene; item.transform.localEulerAngles = ret.selfRotInScene; SetTriggerAttribute(ret.triggerInfo, item); //item.LoadCurrentTriggerStat(ret.triggerInfo); } break; } } } //恢复记录的分数 ScoreBase scoreBase = FindFirstObjectByType(); if (scoreBase != null) { Dictionary reconnectScore = scoreBase.GetStepScore(); foreach (var item in UserExamStat.allSubScore) { if (reconnectScore.ContainsKey(item.index)) { reconnectScore[item.index].currentScore = item.currentScore; reconnectScore[item.index].isDone = item.isDone; } } scoreBase.setCurrentScore(UserExamStat.currentScore); scoreBase.LoadSceneBufferList(UserExamStat.currentSceneOtherInfo); } }); } /// /// 自动保存用户状态, /// /// private IEnumerator AutoSaveStat() { int countDown = countDown_AutoSave; WaitForSeconds waitForSeconds = new WaitForSeconds(1); while (countDown > 0) { yield return waitForSeconds; //Exam为考试模式,Practice为练习模式,考试模式加入后,进入要重置时间,重新启动 if (ProcessManager.Instance.mode == E_ModeType.Practice) { countDown--; //Debug.Log("自动保存倒计时:" + countDown); if (countDown <= 0) { ReconnectMgr.Instance.RealtimeStatWriter();//需要在GameManager里面初始化 Debug.Log("完成状态自动保存"); countDown = countDown_AutoSave; } } } } private void Start() { coroutine = StartCoroutine(AutoSaveStat()); } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.T))//测试用,按T读取状态保存 { RealtimeStatWriter(); Debug.Log("当前场景:" + UserExamStat.sceneName); } else if (Input.GetKeyDown(KeyCode.Y)) { RealtimeStatReader(); RecoverScene(); } } }