using System.Collections.Generic;
using System.IO;
using GameFramework.Runtime;
using UnityEngine;
using YooAsset;
namespace TEngine
{
internal partial class ResourceManager
{
///
/// 远端资源地址查询服务类
///
private class RemoteServices : IRemoteServices
{
private readonly string _defaultHostServer;
private readonly string _fallbackHostServer;
public RemoteServices(string defaultHostServer, string fallbackHostServer)
{
_defaultHostServer = defaultHostServer;
_fallbackHostServer = fallbackHostServer;
}
string IRemoteServices.GetRemoteMainURL(string fileName)
{
return $"{_defaultHostServer}/{fileName}";
}
string IRemoteServices.GetRemoteFallbackURL(string fileName)
{
return $"{_fallbackHostServer}/{fileName}";
}
}
///
/// 资源文件流加载解密类
///
private class FileStreamDecryption : IDecryptionServices
{
///
/// 同步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
///
AssetBundle IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo, out Stream managedStream)
{
BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
managedStream = bundleStream;
return AssetBundle.LoadFromStream(bundleStream, fileInfo.ConentCRC, GetManagedReadBufferSize());
}
///
/// 异步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
///
AssetBundleCreateRequest IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo, out Stream managedStream)
{
BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
managedStream = bundleStream;
return AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.ConentCRC, GetManagedReadBufferSize());
}
private static uint GetManagedReadBufferSize()
{
return 1024;
}
}
///
/// 资源文件偏移加载解密类
///
private class FileOffsetDecryption : IDecryptionServices
{
///
/// 同步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
///
AssetBundle IDecryptionServices.LoadAssetBundle(DecryptFileInfo fileInfo, out Stream managedStream)
{
managedStream = null;
return AssetBundle.LoadFromFile(fileInfo.FileLoadPath, fileInfo.ConentCRC, GetFileOffset());
}
///
/// 异步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
///
AssetBundleCreateRequest IDecryptionServices.LoadAssetBundleAsync(DecryptFileInfo fileInfo, out Stream managedStream)
{
managedStream = null;
return AssetBundle.LoadFromFileAsync(fileInfo.FileLoadPath, fileInfo.ConentCRC, GetFileOffset());
}
private static ulong GetFileOffset()
{
return 32;
}
}
}
///
/// 资源文件解密流
///
public class BundleStream : FileStream
{
public const byte KEY = 64;
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
{
}
public BundleStream(string path, FileMode mode) : base(path, mode)
{
}
public override int Read(byte[] array, int offset, int count)
{
var index = base.Read(array, offset, count);
for (int i = 0; i < array.Length; i++)
{
array[i] ^= KEY;
}
return index;
}
}
///
/// 资源文件查询服务类
///
public class GameQueryServices : IBuildinQueryServices
{
///
/// 查询内置文件的时候,是否比对文件哈希值
///
public static bool CompareFileCRC = false;
public bool Query(string packageName, string fileName, string fileCRC)
{
// 注意:fileName包含文件格式
return StreamingAssetsHelper.FileExists(packageName, fileName, fileCRC);
}
}
public class StreamingAssetsDefine
{
///
/// 根目录名称(保持和YooAssets资源系统一致)
///
public const string RootFolderName = "package";
}
#if UNITY_EDITOR
public sealed class StreamingAssetsHelper
{
public static void Init()
{
}
public static bool FileExists(string packageName, string fileName, string fileCRC)
{
string filePath = Path.Combine(Application.streamingAssetsPath, StreamingAssetsDefine.RootFolderName, packageName, fileName);
if (File.Exists(filePath))
{
if (GameQueryServices.CompareFileCRC)
{
string crc32 = YooAsset.HashUtility.FileCRC32(filePath);
return crc32 == fileCRC;
}
else
{
return true;
}
}
else
{
return false;
}
}
}
#else
public sealed class StreamingAssetsHelper
{
private class PackageQuery
{
public readonly Dictionary Elements = new Dictionary(1000);
}
private static bool _isInit = false;
private static readonly Dictionary _packages = new Dictionary(10);
///
/// 初始化
///
public static void Init()
{
if (_isInit == false)
{
_isInit = true;
var manifest = Resources.Load("BuildinFileManifest");
if (manifest != null)
{
foreach (var element in manifest.BuildinFiles)
{
if (_packages.TryGetValue(element.PackageName, out PackageQuery package) == false)
{
package = new PackageQuery();
_packages.Add(element.PackageName, package);
}
package.Elements.Add(element.FileName, element);
}
}
}
}
///
/// 内置文件查询方法
///
public static bool FileExists(string packageName, string fileName, string fileCRC32)
{
if (_isInit == false)
Init();
if (_packages.TryGetValue(packageName, out PackageQuery package) == false)
return false;
if (package.Elements.TryGetValue(fileName, out var element) == false)
return false;
if (GameQueryServices.CompareFileCRC)
{
return element.FileCRC32 == fileCRC32;
}
else
{
return true;
}
}
}
#endif
#if UNITY_EDITOR
internal class PreprocessBuild : UnityEditor.Build.IPreprocessBuildWithReport
{
public int callbackOrder
{
get { return 0; }
}
///
/// 在构建应用程序前处理
/// 原理:在构建APP之前,搜索StreamingAssets目录下的所有资源文件,然后将这些文件信息写入内置清单,内置清单存储在Resources文件夹下。
///
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
string saveFilePath = "Assets/AATemp/Resources/BuildinFileManifest.asset";
if (File.Exists(saveFilePath))
{
File.Delete(saveFilePath);
UnityEditor.AssetDatabase.SaveAssets();
UnityEditor.AssetDatabase.Refresh();
}
string folderPath = $"{Application.dataPath}/StreamingAssets/{StreamingAssetsDefine.RootFolderName}";
DirectoryInfo root = new DirectoryInfo(folderPath);
if (root.Exists == false)
{
Debug.LogWarning($"没有发现YooAsset内置目录 : {folderPath}");
return;
}
var manifest = ScriptableObject.CreateInstance();
FileInfo[] files = root.GetFiles("*", SearchOption.AllDirectories);
foreach (var fileInfo in files)
{
if (fileInfo.Extension == ".meta")
continue;
if (fileInfo.Name.StartsWith("PackageManifest_"))
continue;
BuildinFileManifest.Element element = new BuildinFileManifest.Element();
element.PackageName = fileInfo.Directory.Name;
element.FileCRC32 = YooAsset.HashUtility.FileCRC32(fileInfo.FullName);
element.FileName = fileInfo.Name;
manifest.BuildinFiles.Add(element);
}
if (Directory.Exists("Assets/AATemp/Resources") == false)
Directory.CreateDirectory("Assets/AATemp/Resources");
UnityEditor.AssetDatabase.CreateAsset(manifest, saveFilePath);
UnityEditor.AssetDatabase.SaveAssets();
UnityEditor.AssetDatabase.Refresh();
Debug.Log($"一共{manifest.BuildinFiles.Count}个内置文件,内置资源清单保存成功 : {saveFilePath}");
}
}
#endif
}