425 lines
14 KiB
C#
425 lines
14 KiB
C#
// 在AssetBundleManager等资源管理器生成前,预先处理资源问题的管理器
|
||
// 提前处理资源更新,服务器列表下载等一系列情况
|
||
// 注:这个东西运作的时候,没有AssetBundle,没有Lua,不要试图做任何相关操作。
|
||
|
||
using System.Collections.Generic;
|
||
using System.Reflection;
|
||
using AssetUpdate;
|
||
using Games.GlobeDefine;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using SceneHub = UnityEngine.SceneManagement.SceneManager;
|
||
|
||
public class AssetUpdateManager : MonoBehaviour
|
||
{
|
||
// 处理不同渠道的Php链接数据
|
||
private const string _channelConfig = "Channel.txt";
|
||
|
||
private IAssetAsyncAction _currentAction;
|
||
|
||
public static Assembly dllAssembly { get; private set; }
|
||
|
||
private static string _channel;
|
||
|
||
public static string channel
|
||
{
|
||
get { return _channel; }
|
||
private set { _channel = value; }
|
||
}
|
||
|
||
public static string assetVersionUri { get; private set; }
|
||
|
||
public static bool useResources
|
||
{
|
||
get { return _useResources; }
|
||
}
|
||
|
||
private static bool _useResources = true;
|
||
|
||
public AssetUpdateState state { get; private set; }
|
||
public AssetUpdateError error { get; private set; }
|
||
public static string assetUri { get; private set; }
|
||
public static int assetVersion { get; private set; }
|
||
public static string apkUri { get; private set; }
|
||
public static string apkVersion { get; private set; }
|
||
|
||
public List<AssetDependencyItem> downloadList { get; private set; }
|
||
public AssetDependencyInfo mainInfo { get; private set; }
|
||
public Dictionary<string, string> streamingPathInfo { get; private set; }
|
||
|
||
private const string currentVersionPref = "CurrentVersion";
|
||
|
||
public static int LoadCurrentVersion()
|
||
{
|
||
var currentVersion = PlayerPrefs.GetInt(currentVersionPref, default(int));
|
||
if (currentVersion <= 0)
|
||
{
|
||
var versionFile = Resources.Load<TextAsset>(AssetConst.currentVersionFile).text;
|
||
int version;
|
||
if (int.TryParse(versionFile, out version))
|
||
currentVersion = version;
|
||
}
|
||
|
||
return currentVersion;
|
||
}
|
||
|
||
private void SaveCurrentVersion()
|
||
{
|
||
PlayerPrefs.SetInt(currentVersionPref, assetVersion);
|
||
}
|
||
|
||
private void Awake()
|
||
{
|
||
Debug.Log("AssetUpdateManager Awake");
|
||
_useResources = false;
|
||
AssetUpdateDownloaderTick.CreateInstance();
|
||
if (!FirstSceneBg.instance)
|
||
FirstSceneBg.CreateInstance();
|
||
CreateEventSystem();
|
||
}
|
||
|
||
public static void CreateEventSystem()
|
||
{
|
||
if (!EventSystem.current)
|
||
{
|
||
var eventObj = new GameObject("EventSystem");
|
||
eventObj.AddComponent<EventSystem>();
|
||
eventObj.AddComponent<StandaloneInputModule>();
|
||
DontDestroyOnLoad(eventObj);
|
||
}
|
||
}
|
||
|
||
private void OnConfigLoad(WWW www)
|
||
{
|
||
var text = string.IsNullOrEmpty(www.error) ? www.text : string.Empty;
|
||
var channelError = false;
|
||
if (string.IsNullOrEmpty(text))
|
||
channelError = true;
|
||
else
|
||
{
|
||
var lines = AssetUtils.TextToLines(text);
|
||
if (lines.Length < 2)
|
||
channelError = true;
|
||
else
|
||
{
|
||
channel = lines[0].Trim();
|
||
assetVersionUri = lines[1].Trim();
|
||
if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(assetVersionUri))
|
||
channelError = true;
|
||
if (lines.Length > 2)
|
||
{
|
||
var extra = lines[2].Trim();
|
||
if (lines.Length > 2 && !string.IsNullOrEmpty(extra))
|
||
FirstSceneBg.instance.SetPublishText(extra);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (channelError)
|
||
Debug.LogError("Unable to Parse Channel file! This is not recoverable!");
|
||
else
|
||
{
|
||
// 清理上次执行残留的rawJsonText
|
||
// 当前项目没有类似数据缓存库一样的类,暂时直接用静态传递
|
||
assetUri = string.Empty;
|
||
state = AssetUpdateState.GetUpdateInfo;
|
||
StartCurrentAction();
|
||
}
|
||
|
||
FirstSceneBg.instance.ShowGameVersion();
|
||
// 清理上次执行残留的rawJsonText
|
||
// 当前项目没有类似数据缓存库一样的类,暂时直接用静态传递
|
||
assetUri = string.Empty;
|
||
state = AssetUpdateState.GetUpdateInfo;
|
||
StartCurrentAction();
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
// 特别处理Android Resume时期的诡异情况,该状况下,AssetBundle未被清空,但实际Bundle管理器已被析构
|
||
AssetBundle.UnloadAllAssetBundles(true);
|
||
Debug.Log("加载渠道文件" + _channelConfig);
|
||
AssetUpdateDownloaderTick.instance.LoadStreamingAsset(_channelConfig, OnConfigLoad);
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
// 即使AppQuit也需要处理OnDestroy,否则会在编辑器中导致下载不中断
|
||
if (state != AssetUpdateState.Complete && _currentAction != null)
|
||
{
|
||
_currentAction.Dispose();
|
||
_currentAction = null;
|
||
}
|
||
}
|
||
|
||
private void StartCurrentAction()
|
||
{
|
||
switch (state)
|
||
{
|
||
case AssetUpdateState.GetUpdateInfo:
|
||
{
|
||
var httpAction = new HttpsGetAction(10f);
|
||
_currentAction = httpAction;
|
||
httpAction.Start();
|
||
}
|
||
break;
|
||
case AssetUpdateState.DownloadAssetList:
|
||
{
|
||
var assetListAction = new AssetVersionAction();
|
||
_currentAction = assetListAction;
|
||
assetListAction.Start(assetVersion, assetUri);
|
||
}
|
||
break;
|
||
case AssetUpdateState.CompareAssetList:
|
||
{
|
||
var assetCompareAction = new AssetCompareAction();
|
||
_currentAction = assetCompareAction;
|
||
assetCompareAction.Start(mainInfo);
|
||
}
|
||
break;
|
||
case AssetUpdateState.DownloadFile:
|
||
{
|
||
var downloadAction = new ProjectDownloadAction();
|
||
_currentAction = downloadAction;
|
||
downloadAction.Start(assetUri, downloadList);
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
Debug.LogError(string.Format("Unhandled state {0} in StartCurrentAction!", state));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
private static T ConvertAction<T>(IAssetAsyncAction action) where T : class, IAssetAsyncAction
|
||
{
|
||
var result = action as T;
|
||
if (result == null)
|
||
Debug.LogError("Logic Error: current Action is not " + typeof(T));
|
||
return result;
|
||
}
|
||
|
||
public static JsonAssetInfo HandleHttpGetAction(HttpsGetAction httpAction)
|
||
{
|
||
JsonAssetInfo jsonAssetInfo = null;
|
||
if (httpAction != null)
|
||
{
|
||
if (httpAction.jsonData == null)
|
||
Debug.LogError("HttpsGetAction Error: failed to get json from server!");
|
||
else
|
||
jsonAssetInfo = JsonAssetInfo.Create(httpAction.jsonData);
|
||
}
|
||
|
||
return jsonAssetInfo;
|
||
}
|
||
|
||
private void EndCurrentAction()
|
||
{
|
||
error = AssetUpdateError.UnknownError;
|
||
switch (state)
|
||
{
|
||
case AssetUpdateState.GetUpdateInfo:
|
||
{
|
||
var httpAction = ConvertAction<HttpsGetAction>(_currentAction);
|
||
error = AssetUpdateError.AssetJsonError;
|
||
if (httpAction != null)
|
||
{
|
||
var jsonAssetInfo = HandleHttpGetAction(httpAction);
|
||
if (jsonAssetInfo == null)
|
||
Debug.LogError("Failed to convert jsonData to JsonAssetInfo!");
|
||
else
|
||
{
|
||
assetUri = jsonAssetInfo.assetUri;
|
||
assetVersion = jsonAssetInfo.assetVersion;
|
||
apkUri = jsonAssetInfo.apkUri;
|
||
apkVersion = jsonAssetInfo.apkVersion;
|
||
error = apkVersion == Application.version
|
||
? AssetUpdateError.Success
|
||
: AssetUpdateError.ApkUpdate;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case AssetUpdateState.DownloadAssetList:
|
||
{
|
||
var assetInfoAction = ConvertAction<AssetVersionAction>(_currentAction);
|
||
if (assetInfoAction != null)
|
||
{
|
||
error = assetInfoAction.error;
|
||
if (error == AssetUpdateError.Success)
|
||
mainInfo = assetInfoAction.mainInfo;
|
||
}
|
||
}
|
||
break;
|
||
case AssetUpdateState.CompareAssetList:
|
||
{
|
||
var assetCompareAction = ConvertAction<AssetCompareAction>(_currentAction);
|
||
if (assetCompareAction != null)
|
||
{
|
||
downloadList = assetCompareAction.downloadList;
|
||
streamingPathInfo = assetCompareAction.streamingPathInfo;
|
||
error = AssetUpdateError.Success;
|
||
}
|
||
}
|
||
break;
|
||
case AssetUpdateState.DownloadFile:
|
||
{
|
||
var downloadAction = ConvertAction<ProjectDownloadAction>(_currentAction);
|
||
if (downloadAction != null)
|
||
error = downloadAction.error;
|
||
}
|
||
break;
|
||
case AssetUpdateState.Complete:
|
||
case AssetUpdateState.Error:
|
||
break;
|
||
default:
|
||
{
|
||
Debug.LogError(string.Format("Unhandled state {0} in StartCurrentAction!", state));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void HandleStateError()
|
||
{
|
||
var errorState = state;
|
||
state = AssetUpdateState.Error;
|
||
Debug.LogError("Error on Step " + errorState);
|
||
switch (error)
|
||
{
|
||
case AssetUpdateError.AssetJsonError:
|
||
{
|
||
LiteConfirmWin.Open("资源同步错误", "无法获得服务器文件版本号!\n请在网络通畅的情况下再次尝试!",
|
||
new LiteConfirmButtonData("确定", RestartProcess));
|
||
}
|
||
break;
|
||
case AssetUpdateError.VersionDataError:
|
||
{
|
||
LiteConfirmWin.Open("资源清单错误", "无法获得正确的服务器文件清单!\n请在网络通畅的情况下再次尝试!",
|
||
new LiteConfirmButtonData("确定", RestartProcess));
|
||
}
|
||
break;
|
||
case AssetUpdateError.DownloadError:
|
||
{
|
||
LiteConfirmWin.Open("资源下载错误", "无法下载所需文件!\n请在网络通畅的情况下再次尝试!",
|
||
new LiteConfirmButtonData("确定", RestartProcess));
|
||
}
|
||
break;
|
||
case AssetUpdateError.FileCreateError:
|
||
{
|
||
LiteConfirmWin.Open("读写错误", "无法更新资源文件!\n请检查硬盘容量,并确保游戏拥有响应读写权限!",
|
||
new LiteConfirmButtonData("确定", RestartProcess));
|
||
}
|
||
break;
|
||
case AssetUpdateError.ApkError:
|
||
case AssetUpdateError.ApkUpdate:
|
||
{
|
||
OpenApkUri(apkUri);
|
||
}
|
||
break;
|
||
case AssetUpdateError.UserCancel:
|
||
{
|
||
// 用户自行选择取消更新
|
||
RestartProcess();
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
Debug.LogError(string.Format("Unhandled error type {0} in HandleStateError!", error));
|
||
LiteConfirmWin.Open("网络错误", "无法获得服务器列表\n请在网络通畅的情况下再次尝试!",
|
||
new LiteConfirmButtonData("确定", RestartProcess));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void OnAllActionComplete()
|
||
{
|
||
_currentAction = null;
|
||
TryToEndProcess();
|
||
}
|
||
|
||
private static void OnApkUpdateConfirm(string uri)
|
||
{
|
||
Debug.Log(string.Format("Open apk uri at {0}!", uri));
|
||
Application.OpenURL(uri);
|
||
// 锁死当前界面,防止用户关闭浏览器后,需要重启唤起
|
||
OpenApkUri(uri);
|
||
}
|
||
|
||
public static void OpenApkUri(string uri)
|
||
{
|
||
LiteConfirmWin.Open("安装包更新", "点击确定从商店下载最新版本的游戏安装包!\n" + uri,
|
||
new LiteConfirmButtonData("确定", () => OnApkUpdateConfirm(uri)));
|
||
}
|
||
|
||
private void RestartProcess()
|
||
{
|
||
SceneHub.LoadScene(SceneHub.GetActiveScene().name);
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (state < AssetUpdateState.Complete && _currentAction != null)
|
||
// 完成当前Action
|
||
if (_currentAction.UpdateTimeout())
|
||
{
|
||
// 从当前Action中读取错误码
|
||
EndCurrentAction();
|
||
if (error == AssetUpdateError.Success)
|
||
{
|
||
state++;
|
||
if (state == AssetUpdateState.Complete)
|
||
OnAllActionComplete();
|
||
else
|
||
StartCurrentAction();
|
||
}
|
||
else
|
||
{
|
||
HandleStateError();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void TryToEndProcess()
|
||
{
|
||
// if (_complete && _ui.complete) EndProcess();
|
||
GameObject.DestroyObject(this);
|
||
if (state == AssetUpdateState.Complete)
|
||
StartGame();
|
||
}
|
||
|
||
private void StartGame()
|
||
{
|
||
SaveCurrentVersion();
|
||
SceneHub.LoadScene(GlobeVar.sceneLogin);
|
||
}
|
||
|
||
#region 通用功能
|
||
|
||
public enum AssetUpdateState
|
||
{
|
||
GetUpdateInfo,
|
||
DownloadAssetList,
|
||
CompareAssetList,
|
||
DownloadFile,
|
||
Complete,
|
||
Error
|
||
}
|
||
|
||
public enum AssetUpdateError
|
||
{
|
||
Success,
|
||
FileCreateError,
|
||
AssetJsonError,
|
||
VersionDataError,
|
||
DownloadError,
|
||
ApkError,
|
||
UserCancel,
|
||
ApkUpdate,
|
||
UnknownError
|
||
}
|
||
|
||
#endregion
|
||
} |