using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using Snxxz.UI; using System.Text.RegularExpressions; [XLua.LuaCallCSharp] public class InGameDownLoad : SingletonMonobehaviour { public const int BYTE_PER_KILOBYTE = 1024; public const int BYTE_PER_MILLIONBYTE = 1048576; List workingQueue = new List(); List tasks = new List(); Dictionary> mapTasks = new Dictionary>(); public bool inGameDownLoadAllow = false; public float progress { get { return Mathf.Clamp01((float)showDownLoadedSize / showTotalSize); } } public bool isDone { get { return state == State.Completed; } } public long showDownLoadedSize { get { return downLoadedSizeRecord + RemoteFile.TotalDownloadedSize - backGroundDownLoadSizeRecord; } } public long showTotalSize { get { return totalSize - backGroundDownLoadSizeRecord; } } public int showTotalCount { get { return totalCount - downLoadedCountRecord; } } public int showOkCount { get { return okCount - downLoadedCountRecord; } } long totalSize = 0; int totalCount = 0; int m_OkCount = 0; int okCount { get { return m_OkCount; } set { m_OkCount = value; } } long backGroundDownLoadSizeRecord = 0;//后台偷偷已经下载到资源量 long downLoadedSizeRecord = 0;//记录上次暂停时记录的下载量 int downLoadedCountRecord = 0;//已经下载完成的资源包数量 public event Action downLoadStateChangeEvent; public event Action dominantDownLoadEvent; Action onDownLoadOk; Dominant m_DominantState = Dominant.None; public Dominant dominantState { get { return m_DominantState; } private set { if (m_DominantState != value) { m_DominantState = value; if (dominantDownLoadEvent != null) { dominantDownLoadEvent(m_DominantState); } } } } State m_State = State.None; public State state { get { return m_State; } set { if (m_State != value) { m_State = value; if (downLoadStateChangeEvent != null) { downLoadStateChangeEvent(m_State); } } } } int maxWorkingTask = 2; TaskModel taskModel { get { return ModelCenter.Instance.GetModel(); } } public List rewards = new List(); public bool hasReward { get; private set; } public string completeDownLoadAccount { get { return LocalSave.GetString("InGameDownLoadCompleteAccount"); } set { LocalSave.SetString("InGameDownLoadCompleteAccount", value); } } public Redpoint downLoadRedpoint = new Redpoint(116); public void AssignTasks(List _tasks, Action _onDownLoadOk) { inGameDownLoadAllow = false; tasks = _tasks; tasks.Sort(AssetDownLoadPriorCompare); onDownLoadOk = _onDownLoadOk; totalCount = tasks.Count; okCount = 0; totalSize = 0; for (int i = 0; i < tasks.Count; i++) { var task = tasks[i]; totalSize += task.size; } for (var i = 0; i < tasks.Count; i++) { var assetVersion = tasks[i]; var mapId = PriorBundleConfig.GetAssetBelongToMap(assetVersion.GetAssetCategory(), assetVersion.fileName); if (mapId != 0) { if (!mapTasks.ContainsKey(mapId)) { mapTasks[mapId] = new List(); } mapTasks[mapId].Add(assetVersion); } } state = State.None; TaskModel.Event_MainlineTask -= OnMainTaskChange; TaskModel.Event_MainlineTask += OnMainTaskChange; PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerLevelChange; PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerLevelChange; } public void ParseRewardConfig() { var rewardString = FuncConfigConfig.Get("DownReward").Numerical1; var matches = Regex.Matches(rewardString, "(\\d+,\\d+,\\d+)"); for (int i = 0; i < matches.Count; i++) { rewards.Add(new Reward(matches[i].Value)); } } public void UpdateRewardInfo(HA319_tagMCPackDownloadRecord _package) { hasReward = _package.Record == 1; if (AssetVersionUtility.unPriorAssetDownLoadDone) { state = !hasReward && completeDownLoadAccount == PlayerDatas.Instance.baseData.AccID ? State.Award : State.Completed; } downLoadRedpoint.state = state == State.Award ? RedPointState.Simple : RedPointState.None; } public void RequestDownLoadReward(bool _manual) { var send = new CA504_tagCMPlayerGetReward(); send.RewardType = 15; send.DataEx = (byte)(_manual ? 0 : 1); GameNetSystem.Instance.SendInfo(send); } public float GetMapAssetDownLoadProgress(int mapId) { if (!mapTasks.ContainsKey(mapId)) { return 1f; } var tasks = mapTasks[mapId]; var total = tasks.Count; if (total == 0) { return 1f; } var completeCount = 0; foreach (var task in tasks) { if (task.localValid) { completeCount++; } } return completeCount / (float)total; } int mapId = 0; Action mapAssetDownLoadOk; public void RegisterMapAssetDownLoadOk(int mapId, Action callBack) { var progress = GetMapAssetDownLoadProgress(mapId); if (progress < 0.999f) { this.mapId = mapId; mapAssetDownLoadOk = callBack; } } public void UnRegisterMapAssetDownLoadOk() { this.mapId = 0; mapAssetDownLoadOk = null; } public void TryDownLoad(Dominant _dominant) { if (!inGameDownLoadAllow) { return; } if (tasks == null || tasks.Count == 0 || isDone) { return; } if (_dominant < dominantState) { return; } switch (_dominant) { case Dominant.None: if (InGameDownTestUtility.enable) { if (InGameDownTestUtility.isWifi) { StartDownLoad(); } } else { if (Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork) { StartDownLoad(); } } break; case Dominant.Half: if (dominantState == Dominant.None) { backGroundDownLoadSizeRecord = RemoteFile.TotalDownloadedSize; downLoadedCountRecord = okCount; } StartDownLoad(); dominantState = Dominant.Half; break; case Dominant.Whole: if (dominantState == Dominant.None) { backGroundDownLoadSizeRecord = RemoteFile.TotalDownloadedSize; downLoadedCountRecord = okCount; Pause(); state = State.Prepared; } else if (dominantState == Dominant.Half) { Pause(); state = State.Prepared; } dominantState = Dominant.Whole; WindowCenter.Instance.Open(); break; } } public void StartDownLoad() { if (state == State.None || state == State.Prepared || state == State.Pause) { state = State.DownLoad; RemoteFile.maxDownLoadTask = 2; RemoteFile.MaxConnectLimit = 12; StartCoroutine("Co_StartDownLoad"); } } public void Pause() { if (state == State.DownLoad) { StopCoroutine("Co_StartDownLoad"); foreach (var remoteFile in workingQueue) { remoteFile.Stop(); } workingQueue.Clear(); RemoteFile.maxDownLoadTask = 0; RemoteFile.MaxConnectLimit = 0; state = State.Pause; } } IEnumerator Co_StartDownLoad() { downLoadedSizeRecord += RemoteFile.TotalDownloadedSize; RemoteFile.Prepare(); workingQueue.Clear(); okCount = 0; var downLoadTasksQueues = new Queue(); for (int i = 0; i < tasks.Count; i++) { var assetVersion = tasks[i]; if (!assetVersion.localValid) { downLoadTasksQueues.Enqueue(assetVersion); } else { okCount++; } } while (okCount < totalCount) { while (workingQueue.Count < maxWorkingTask && downLoadTasksQueues.Count > 0) { var assetVersion = downLoadTasksQueues.Dequeue(); var remoteURL = StringUtility.Contact(VersionUtility.Instance.versionInfo.GetResourcesURL(VersionConfig.Get().branch), "/", assetVersion.relativePath); var localURL = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, assetVersion.relativePath); var remoteFile = new RemoteFile(); workingQueue.Add(remoteFile); remoteFile.Init(remoteURL, localURL, assetVersion, true); remoteFile.Begin(OnFileDownLoadCompleted); } yield return null; } TaskModel.Event_MainlineTask -= OnMainTaskChange; PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerLevelChange; WindowCenter.Instance.Close(); if (!hasReward) { if (dominantState == Dominant.None) { RequestDownLoadReward(false); state = State.Completed; } else { completeDownLoadAccount = PlayerDatas.Instance.baseData.AccID; state = State.Award; } } else { state = State.Completed; } downLoadRedpoint.state = state == State.Award ? RedPointState.Simple : RedPointState.None; if (onDownLoadOk != null) { onDownLoadOk(); onDownLoadOk = null; } } private void OnFileDownLoadCompleted(bool _ok, AssetVersion _assetVersion) { foreach (var remote in workingQueue) { if (remote.assetVersion == _assetVersion) { workingQueue.Remove(remote); break; } } if (_ok) { okCount++; _assetVersion.localValid = true; } else { var remoteURL = StringUtility.Contact(VersionUtility.Instance.versionInfo.GetResourcesURL(VersionConfig.Get().branch), "/", _assetVersion.relativePath); var localURL = StringUtility.Contact(ResourcesPath.Instance.ExternalStorePath, _assetVersion.relativePath); var remoteFile = new RemoteFile(); workingQueue.Add(remoteFile); remoteFile.Init(remoteURL, localURL, _assetVersion, true); remoteFile.Begin(OnFileDownLoadCompleted); } } Clock netSwitchClock; NetworkReachability m_NetworkReachability = NetworkReachability.NotReachable; NetworkReachability networkReachability { get { return m_NetworkReachability; } set { if (m_NetworkReachability != value) { m_NetworkReachability = value; if (dominantState != Dominant.Whole) { switch (m_NetworkReachability) { case NetworkReachability.ReachableViaCarrierDataNetwork: Pause(); var endTime = DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond * 3); if (netSwitchClock != null) { Clock.Stop(netSwitchClock); } netSwitchClock = Clock.AlarmAt(endTime, () => { if (CheckDominantDownLoad()) { TryDownLoad(Dominant.Whole); } }); break; case NetworkReachability.ReachableViaLocalAreaNetwork: TryDownLoad(Dominant.None); break; default: break; } } } } } bool m_SimulateWifi = true; public bool simulateWifi { get { return m_SimulateWifi; } set { if (m_SimulateWifi != value) { m_SimulateWifi = value; if (dominantState != Dominant.Whole) { if (m_SimulateWifi) { TryDownLoad(Dominant.None); } else { Pause(); var endTime = DateTime.Now + new TimeSpan(TimeSpan.TicksPerSecond * 10); Clock.AlarmAt(endTime, () => { if (CheckDominantDownLoad()) { TryDownLoad(Dominant.Whole); } }); } } } } } float netCheckTimer = 0f; private void LateUpdate() { if (state == State.None || state == State.Award || state == State.Completed) { return; } netCheckTimer += Time.deltaTime; if (InGameDownTestUtility.enable) { simulateWifi = InGameDownTestUtility.isWifi; } else { if (netCheckTimer > 3f) { netCheckTimer = 0f; networkReachability = Application.internetReachability; } } if (mapId != 0) { var progress = GetMapAssetDownLoadProgress(mapId); if (progress > 0.9999f) { if (mapAssetDownLoadOk != null) { mapAssetDownLoadOk(); mapAssetDownLoadOk = null; mapId = 0; } } } } public bool CheckDominantDownLoad() { if (tasks == null || tasks.Count == 0 || isDone || dominantState == Dominant.Whole || NewBieCenter.Instance.inGuiding) { return false; } if (GeneralDefine.inGameDownLoadLevelCheckPoints == null || GeneralDefine.inGameDownLoadLevelCheckPoints.Count == 0) { return false; } if (PlayerDatas.Instance.baseData.LV < GeneralDefine.inGameDownLoadLevelCheckPoints[0]) { return false; } if (PlayerDatas.Instance.baseData.LV < GeneralDefine.inGameDownLoadHighLevel) { if (InGameDownTestUtility.enable) { if (InGameDownTestUtility.isWifi) { return false; } } else { if (Application.internetReachability != NetworkReachability.ReachableViaCarrierDataNetwork) { return false; } } } if (!WindowCenter.Instance.IsOpen("MainInterfaceWin")) { return false; } if (WindowCenter.Instance.ExistAnyFullScreenOrMaskWin()) { return false; } return true; } public bool IsHighLevelPlayer() { if (GeneralDefine.inGameDownLoadLevelCheckPoints == null || GeneralDefine.inGameDownLoadLevelCheckPoints.Count == 0) { return false; } var level = PlayerDatas.Instance.baseData.LV; return level > GeneralDefine.inGameDownLoadHighLevel; } private void OnPlayerLevelChange(PlayerDataType refreshType) { switch (refreshType) { case PlayerDataType.LV: var level = PlayerDatas.Instance.baseData.LV; var count = GeneralDefine.inGameDownLoadLevelCheckPoints.Count; var lastLevelCheckPoint = GeneralDefine.inGameDownLoadLevelCheckPoints[count - 1]; if (GeneralDefine.inGameDownLoadLevelCheckPoints.Contains(level) || IsHighLevelPlayer()) { if (CheckDominantDownLoad()) { TryDownLoad(Dominant.Whole); } } break; } } private void OnMainTaskChange(int _taskId, int _state) { var mainTaskId = taskModel.currentMission; if (GeneralDefine.inGameDownLoadTaskCheckPoints.Contains(mainTaskId) && taskModel.currentMissionState == 1) { if (CheckDominantDownLoad()) { TryDownLoad(Dominant.Whole); } } } private int AssetDownLoadPriorCompare(AssetVersion lhs, AssetVersion rhs) { var categoryA = lhs.GetAssetCategory(); var categoryB = rhs.GetAssetCategory(); var priorA = PriorBundleConfig.GetAssetPrior(categoryA, lhs.fileName); var priorB = PriorBundleConfig.GetAssetPrior(categoryB, rhs.fileName); if (priorA != priorB) { return priorA < priorB ? -1 : 1; } else { var isManifestA = lhs.extersion == ".manifest"; var isManifestB = rhs.extersion == ".manifest"; if (!isManifestA && isManifestB) { return -1; } else if (isManifestA && !isManifestB) { return 1; } else { return 0; } } } private int GetMaxTask() { switch (Application.platform) { case RuntimePlatform.Android: if (DeviceUtility.cpu >= 4 && DeviceUtility.memory > 3.2f * 1024) { return 2; } else { return 1; } case RuntimePlatform.IPhonePlayer: if (DeviceUtility.cpu > 1 && DeviceUtility.memory > 1.5f * 1024) { return 2; } else { return 1; } case RuntimePlatform.WindowsEditor: return 2; default: return 1; } } private void Awake() { maxWorkingTask = GetMaxTask(); } public struct Reward { public int id; public int count; public bool bind; public Reward(string _input) { var matches = Regex.Matches(_input, "\\d+"); if (matches.Count > 0) { int.TryParse(matches[0].Value, out id); } else { id = 0; } if (matches.Count > 1) { int.TryParse(matches[1].Value, out count); } else { count = 0; } if (matches.Count > 2) { var temp = 0; int.TryParse(matches[2].Value, out temp); bind = temp == 1; } else { bind = false; } } } public enum State { None, Prepared, DownLoad, Pause, Award, Completed, } public enum Dominant { None = 0, Half = 1, Whole = 2, } }