341 lines
13 KiB
C#
341 lines
13 KiB
C#
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;
|
||
|
||
/// <summary>
|
||
/// 断线重连管理
|
||
/// </summary>
|
||
public class ReconnectMgr : SingletonMono<ReconnectMgr>
|
||
{
|
||
[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<string> experiencedScene = new List<string>();//用户经历过的场景
|
||
|
||
/// <summary>
|
||
/// 初始化函数,记录时间间隔
|
||
/// </summary>
|
||
public void Init()
|
||
{
|
||
localStatPath = Application.streamingAssetsPath + "/" + localStatFileName;
|
||
//UserExamStat.experiencedScene.Clear();//清空用户经历过的场景
|
||
//experiencedScene.Clear();
|
||
}
|
||
/// <summary>
|
||
/// 用户每经历一个场景就需要保存一个场景的数据
|
||
/// </summary>
|
||
//public bool IntoNewScene(string sceneName)
|
||
//{
|
||
// if (UserExamStat.experiencedScene.Contains(sceneName))
|
||
// return false;
|
||
// else
|
||
// {
|
||
// UserExamStat.experiencedScene.Add(sceneName);
|
||
// return true;
|
||
// }
|
||
//}
|
||
|
||
ReconnectMgr()//构造函数
|
||
{
|
||
Init();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录用户状态
|
||
/// </summary>
|
||
public void RealtimeStatWriter()
|
||
{
|
||
//记录步骤相关各项信息
|
||
UserExamStat.schemeID = ProcessManager.Instance.schemeID;
|
||
//记录得分情况
|
||
ScoreBase scoreBase = FindFirstObjectByType<ScoreBase>();
|
||
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<string, List<ItemInfo>> 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<string, ItemInfo> 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<PermanentTriggerBase>();
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取常驻交互的属性
|
||
/// </summary>
|
||
/// <param name="permanentTriggerBase"></param>
|
||
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<ReconnetAtrribute>() != null)
|
||
{
|
||
ReconnetAtrribute attribute = field.GetCustomAttribute<ReconnetAtrribute>();
|
||
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<JsonData>(triggerJson);
|
||
FieldInfo[] fieldInfo = permanentTriggerBase.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||
foreach (FieldInfo field in fieldInfo)
|
||
{
|
||
if (field.GetCustomAttribute<ReconnetAtrribute>() != null)
|
||
{
|
||
try
|
||
{
|
||
ReconnetAtrribute attribute = field.GetCustomAttribute<ReconnetAtrribute>();
|
||
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());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取用户状态(先使用同步,后用异步)
|
||
/// </summary>
|
||
public bool RealtimeStatReader()
|
||
{
|
||
if (File.Exists(localStatPath))
|
||
{
|
||
try
|
||
{
|
||
StreamReader sr = new StreamReader(localStatPath);
|
||
string user_last_stat = sr.ReadToEnd();
|
||
sr.Close();
|
||
UserExamStat = JsonMapper.ToObject<TB_UserExamStat>(user_last_stat);
|
||
return true;
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogError(e.ToString());
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 恢复现场
|
||
/// </summary>
|
||
public void RecoverScene()
|
||
{
|
||
//先恢复场景
|
||
ScenesManager.Instance.LoadSceneAsyn(UserExamStat.sceneName, () =>
|
||
{
|
||
//右侧工具栏切换
|
||
if (!GameManager.UIMgr.GetPanel<UI_MenuBar>())//office场景下,右侧工具栏可能会隐藏
|
||
{
|
||
GameManager.UIMgr.ShowPanel<UI_MenuBar>(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<TooRoomMannger>();
|
||
List<ItemInfo> 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<ItemInfo> 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<PermanentTriggerBase>();
|
||
List<ReconnectTriggerInfo> 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<Tool_SelectComponent>() == null)//工具材料已经恢复过了
|
||
{
|
||
item.transform.localPosition = ret.selfPosInScene;
|
||
item.transform.localEulerAngles = ret.selfRotInScene;
|
||
SetTriggerAttribute(ret.triggerInfo, item);
|
||
//item.LoadCurrentTriggerStat(ret.triggerInfo);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//恢复记录的分数
|
||
ScoreBase scoreBase = FindFirstObjectByType<ScoreBase>();
|
||
if (scoreBase != null)
|
||
{
|
||
Dictionary<int, ScoreSubjectStep> 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);
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自动保存用户状态,
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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();
|
||
}
|
||
}
|
||
}
|