//
|
// GameApp.cs
|
// Create:
|
// 2019-10-29
|
// Description:
|
// 资源加载服务类,提供文件的同步异步加载,提供Unity AB的同步异步加载和资源的声明周期。
|
// Author:
|
// 薛林强 <545626463@qq.com>
|
//
|
// Copyright (c) 2026 虚幻骑士科技
|
|
using System;
|
using System.IO;
|
using UnityEngine;
|
using UnityEngine.Networking;
|
using Plugins.XAsset;
|
using UnityEngine.AddressableAssets;
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
using System.Collections.Generic;
|
using UnityEngine.SceneManagement;
|
using UnityEngine.ResourceManagement.ResourceProviders;
|
using UnityEngine.ResourceManagement;
|
|
namespace Skyunion
|
{
|
abstract class BaseAssetService : Module, IAssetService
|
{
|
protected IAssetService mAssetService;
|
protected GameObject mGameObject;
|
protected Dictionary<string, bool> mObjectHasPool = new Dictionary<string, bool>();
|
protected List<IAsset> mAssets = new List<IAsset>();
|
protected string m_obbPath = string.Empty;
|
protected struct InstanceRequest
|
{
|
public Action<GameObject> callback;
|
public string assetName;
|
}
|
protected struct LoadedCallback
|
{
|
public Action<IAsset> callback;
|
public IAsset asset;
|
}
|
private Queue<InstanceRequest> mInstanceOnePerFrameQueue = new Queue<InstanceRequest>();
|
private Queue<InstanceRequest> mInstanceSlowlyQueue = new Queue<InstanceRequest>();
|
private Queue<InstanceRequest> mInstanceQueue = new Queue<InstanceRequest>();
|
private Queue<LoadedCallback> mLoadAssetQueue = new Queue<LoadedCallback>();
|
|
public float m_unload_unused_asset_time = 30.0f;
|
protected float m_unload_unused_asset_timer;
|
public override void Update()
|
{
|
while (mInstanceQueue.Count > 0)
|
{
|
var request = mInstanceQueue.Dequeue();
|
if (request.callback != null)
|
{
|
Instantiate(request.assetName, request.callback);
|
}
|
}
|
int nCount = 0;
|
while(mInstanceSlowlyQueue.Count > 0 && nCount != 20)
|
{
|
var request = mInstanceSlowlyQueue.Dequeue();
|
if (request.callback != null)
|
{
|
this.Instantiate(request.assetName, request.callback);
|
}
|
nCount++;
|
}
|
|
if(mInstanceOnePerFrameQueue.Count > 0)
|
{
|
var request = mInstanceOnePerFrameQueue.Dequeue();
|
if (request.callback != null)
|
{
|
this.Instantiate(request.assetName, request.callback);
|
}
|
}
|
while (mLoadAssetQueue.Count > 0)
|
{
|
var respon = mLoadAssetQueue.Dequeue();
|
respon.callback?.Invoke(respon.asset);
|
}
|
|
m_unload_unused_asset_timer += Time.deltaTime;
|
if (m_unload_unused_asset_timer >= m_unload_unused_asset_time)
|
{
|
try
|
{
|
UnloadUnusedAssets();
|
}catch(Exception ex)
|
{
|
Debug.LogException(ex);
|
}
|
m_unload_unused_asset_timer = 0f;
|
}
|
}
|
|
public byte[] LoadFile(string path, bool readHotfix = true)
|
{
|
int nIndex = path.IndexOf(Application.streamingAssetsPath);
|
#if !UNITY_EDITOR
|
if (nIndex != -1)
|
{
|
// 需要判断 只有 包内的资源才走热更新
|
if (readHotfix && VersionUtil.HasHotfix)
|
{
|
var basePath = path.Substring(Application.streamingAssetsPath.Length + 1);
|
var hotfixPath = Path.Combine(VersionUtil.HotfixRuntimePath, basePath);
|
if (File.Exists(hotfixPath))
|
{
|
return File.ReadAllBytes(hotfixPath);
|
}
|
}
|
// Android 需要处理读取压缩包内的资源
|
#if UNITY_ANDROID
|
path = path.Substring(Application.streamingAssetsPath.Length + 1);
|
path = Path.Combine("assets", path);
|
byte[] bytes = null;
|
if (string.Empty.Equals(m_obbPath))
|
{
|
bytes = lzip.entry2Buffer(Application.dataPath, path);
|
}
|
else
|
{
|
bytes = lzip.entry2Buffer(m_obbPath, path);
|
}
|
return bytes;
|
#endif
|
}
|
#endif
|
return File.ReadAllBytes(path);
|
}
|
|
public void LoadFileAsync(string path, Action<byte[]> completed)
|
{
|
#if !UNITY_EDITOR
|
if (VersionUtil.HasHotfix)
|
{
|
// 需要判断 只有 包内的资源才走热更新
|
int nIndex = path.IndexOf(Application.streamingAssetsPath);
|
if (nIndex != -1)
|
{
|
var hotfixPath = Path.Combine(VersionUtil.HotfixRuntimePath, path.Substring(Application.streamingAssetsPath.Length+1));
|
if (File.Exists(hotfixPath))
|
{
|
path = hotfixPath;
|
path = path.Insert(0, "file://");
|
}
|
}
|
}
|
#endif
|
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IPHONE
|
path = path.Insert(0, "file://");
|
#endif
|
|
UnityWebRequest webFile = UnityWebRequest.Get(path);
|
webFile.SendWebRequest().completed += (AsyncOperation op) =>
|
{
|
completed?.Invoke(webFile.downloadHandler.data);
|
};
|
}
|
public void InstantiateOnePerFrame(string assetName, Action<GameObject> completed)
|
{
|
var request = new InstanceRequest();
|
request.assetName = assetName;
|
request.callback = completed;
|
mInstanceOnePerFrameQueue.Enqueue(request);
|
}
|
public void InstantiateSlowly(string assetName, Action<GameObject> completed)
|
{
|
var request = new InstanceRequest();
|
request.assetName = assetName;
|
request.callback = completed;
|
mInstanceSlowlyQueue.Enqueue(request);
|
}
|
public void InstantiateNextFrame(string assetName, Action<GameObject> completed)
|
{
|
var request = new InstanceRequest();
|
request.assetName = assetName;
|
request.callback = completed;
|
mInstanceQueue.Enqueue(request);
|
}
|
protected void LoadCallbackInUpdate(Action<IAsset> completed, IAsset asset)
|
{
|
var respon = new LoadedCallback();
|
respon.asset = asset;
|
respon.callback = completed;
|
mLoadAssetQueue.Enqueue(respon);
|
}
|
|
public abstract IAsset LoadAssetAsync<T>(string assetName, Action<IAsset> completed) where T : UnityEngine.Object;
|
|
public IAsset LoadAssetAsync<T>(string assetName, Action<IAsset> completed, UnityEngine.Object autoDestroyOwner) where T : UnityEngine.Object
|
{
|
IAsset asset = LoadAssetAsync<T>(assetName, completed);
|
asset.Attack(autoDestroyOwner);
|
mAssets.Add(asset);
|
return asset;
|
}
|
public abstract IAsset LoadSceneAssetAsync(string assetName, bool addictive, Action<IAsset> completed);
|
public abstract void Instantiate(string assetName, Action<GameObject> completed);
|
|
public virtual void Destroy(GameObject gameObject)
|
{
|
GameObject.Destroy(gameObject);
|
}
|
public virtual void Destroy(GameObject gameObject, float fadeTime)
|
{
|
GameObject.Destroy(gameObject, fadeTime);
|
}
|
|
public virtual void UnloadUnusedAssets()
|
{
|
}
|
public GameObject Instantiate(GameObject gameObject)
|
{
|
return GameObject.Instantiate(gameObject);
|
}
|
|
public void SetOBBPath(string obbPath)
|
{
|
m_obbPath = obbPath;
|
}
|
}
|
}
|