using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using TinaX.VFSKit;
using UnityEngine;
using TinaX.VFSKit.Const;
using TinaX.Utils;
namespace TinaX.VFSKitInternal.Utils
{
public static class VFSUtil
{
///
/// 是否为子路径, 如果相等也返回false
///
/// 路径1
/// 路径2
/// 是否互相检测,如果为false,只检查path1是否为path2的子路径;如果为true,互相判断两者是否为对方的子路径
///
public static bool IsSubpath(string path1, string path2, bool mutual = false)
{
string p1 = (path1.EndsWith("/") || path1.EndsWith("\\")) ? path1.Replace("\\", "/") : path1.Replace("\\", "/") + "/";
string p2 = (path2.EndsWith("/") || path2.EndsWith("\\")) ? path2.Replace("\\", "/") : path2.Replace("\\", "/") + "/";
if (p1 == p2) return false;
if (mutual)
{
//相互判断
return (p1.StartsWith(p2) || p2.StartsWith(p1));
}
else
{
//判断p1是否是p2的子路径
return p1.StartsWith(p2);
}
}
///
/// 是否为子路径或相同路径
///
/// 路径1
/// 路径2
/// 是否互相检测,如果为false,只检查path1是否为path2的子路径;如果为true,互相判断两者是否为对方的子路径
///
public static bool IsSameOrSubPath(string path1, string path2, bool mutual = false)
{
string p1 = (path1.EndsWith("/") || path1.EndsWith("\\")) ? path1.Replace("\\", "/") : path1.Replace("\\", "/") + "/";
string p2 = (path2.EndsWith("/") || path2.EndsWith("\\")) ? path2.Replace("\\", "/") : path2.Replace("\\", "/") + "/";
if (p1 == p2) return true;
if (mutual)
{
//相互判断
return (p1.StartsWith(p2) || p2.StartsWith(p1));
}
else
{
//判断p1是否是p2的子路径
return p1.StartsWith(p2);
}
}
public static bool IsInResources(string path)
{
return path.Replace('\\', '/').ToLower().Contains("/resources/");
}
///
/// 配置规范化
///
///
public static void NormalizationConfig(IVFSConfig config)
{
if (config == null) return;
//全局配置
//后缀名配置 补全缺失的“框架内部定义的必须存在的”配置项
#region 全局 后缀名 内部配置项
if (config.PGlobalVFS_Ignore_ExtName == null)
config.PGlobalVFS_Ignore_ExtName = new string[0];
List ext_list = new List();
foreach (var item in TinaX.VFSKitInternal.InternalVFSConfig.GlobalIgnoreExtName)
{
if (!config.PGlobalVFS_Ignore_ExtName.Contains(item))
{
ext_list.Add(item);
}
}
if (ext_list.Count > 0)
config.PGlobalVFS_Ignore_ExtName = ArrayUtil.Combine(config.PGlobalVFS_Ignore_ExtName, ext_list.ToArray());
#endregion
//后缀名配置必须要以点开头,并小写
#region 全局 后缀名 格式规范
if (config.PGlobalVFS_Ignore_ExtName != null && config.PGlobalVFS_Ignore_ExtName.Length > 0)
{
for (var i = 0; i < config.PGlobalVFS_Ignore_ExtName.Length; i++)
{
if (!config.PGlobalVFS_Ignore_ExtName[i].StartsWith("."))
config.PGlobalVFS_Ignore_ExtName[i] = "." + config.PGlobalVFS_Ignore_ExtName[i];
config.PGlobalVFS_Ignore_ExtName[i] = config.PGlobalVFS_Ignore_ExtName[i].ToLower();
}
}
#endregion
//后缀名配置 重复项
#region 全局 后缀名 重复项
if (config.PGlobalVFS_Ignore_ExtName != null && config.PGlobalVFS_Ignore_ExtName.Length > 0)
{
List list = new List(config.PGlobalVFS_Ignore_ExtName).Distinct().ToList();
if (list.Count != config.PGlobalVFS_Ignore_ExtName.Length)
config.PGlobalVFS_Ignore_ExtName = list.ToArray();
}
#endregion
#region 全局 忽略 路径 item
//补全内部设定
if (config.PGlobalVFS_Ignore_Path_Item == null)
config.PGlobalVFS_Ignore_Path_Item = new string[0];
List tmp_path_item_list = new List(config.PGlobalVFS_Ignore_Path_Item);
foreach (var item in TinaX.VFSKitInternal.InternalVFSConfig.GlobalIgnorePathItem)
{
if (!tmp_path_item_list.Contains(item))
{
tmp_path_item_list.Add(item);
}
}
List temp_2 = new List();
//查重和空白项目
for(int i = tmp_path_item_list.Count -1; i >= 0; i--)
{
if (!tmp_path_item_list[i].IsNullOrEmpty())
{
if(!temp_2.Any(item => item.ToLower() == tmp_path_item_list[i].ToLower()))
{
temp_2.Add(tmp_path_item_list[i]);
}
}
}
config.PGlobalVFS_Ignore_Path_Item = temp_2.ToArray();
#endregion
#region 全局 Assetbundle细节
if (config.PAssetBundleFileExtension.IsNullOrEmpty() || config.PAssetBundleFileExtension.IsNullOrWhiteSpace())
config.PAssetBundleFileExtension = InternalVFSConfig.default_AssetBundle_ExtName;
if (!config.PAssetBundleFileExtension.StartsWith("."))
{
config.PAssetBundleFileExtension = "." + config.PAssetBundleFileExtension;
}
config.PAssetBundleFileExtension = config.PAssetBundleFileExtension.ToLower();
#endregion
#region WebVFS
if (config.PDefaultWebVFSBaseUrl.IsNullOrEmpty() || config.PDefaultWebVFSBaseUrl.IsNullOrWhiteSpace())
{
config.PDefaultWebVFSBaseUrl = VFSKit.VFSKit.DefaultDownloadWebAssetUrl;
}
if (!config.PDefaultWebVFSBaseUrl.EndsWith("/"))
config.PDefaultWebVFSBaseUrl += "/";
#endregion
#region 至少包含一个Group
if (config.PGroups == null || config.PGroups.Length == 0)
{
config.PGroups = new VFSGroupOption[]{ VFSGroupOption.New() };
}
#endregion
}
///
/// 检查配置 (检查所有项目), 如果检查通过返回true, 否则返回false
///
///
///
/// 如果有group内folder相关的错误,则在此处体现
/// if error ,return false
public static bool CheckConfiguration(IVFSConfig config, out VFSErrorCode error, out GroupFolderInfo[] errorfolders)
{
errorfolders = null;
#region 没有任何Group?
if(config.PGroups == null || config.PGroups.Length == 0)
{
error = VFSErrorCode.NoneGroup;
return false;
}
#endregion
#region 检查组名称是否重复
List temp_list = new List();
foreach(var group in config.PGroups)
{
if (temp_list.Contains(group.GroupName))
{
//存在重复命名
error = VFSErrorCode.SameGroupName;
return false;
}
else
temp_list.Add(group.GroupName);
}
#endregion
#region 检查各组的folder配置是否冲突
if(CheckConfig_GroupFolder(ref config, out var folders))
{
errorfolders = folders;
error = VFSErrorCode.ConfigureGroupsConflict;
return false;
}
#endregion
error = default;
return true;
}
///
/// 配置检查: 检查各组的Folder是否有冲突, 如果有冲突,返回true
///
///
///
public static bool CheckConfig_GroupFolder(ref IVFSConfig config, out GroupFolderInfo[] folders)
{
if (config.PGroups == null || config.PGroups.Length == 0)
{
folders = null;
return false;
}
List list_folders = new List();
for (var i = 0; i < config.PGroups.Length; i++)
{
string group_name = config.PGroups[i].GroupName;
//检查组内部
if(config.PGroups[i].CheckFolderConflict(out var paths))
{
//有冲突
paths.ForEach(path => list_folders.Add(new GroupFolderInfo() { FolderPath = path, GroupName = group_name }));
folders = list_folders.ToArray();
return true;
}
//检查当前组与之前的组之间是否存在冲突
if(i > 0)
{
foreach (var path in config.PGroups[i].FolderPaths)
{
for (var j = 0; j < i; j++)
{
var _g_name = config.PGroups[i].GroupName;
if (config.PGroups[i].CheckFolderConflict(out var result_paths,true))
{
//有冲突
list_folders.Add(new GroupFolderInfo() { GroupName = group_name, FolderPath = path });
result_paths.ForEach(r_path => list_folders.Add(new GroupFolderInfo() { FolderPath = r_path, GroupName = _g_name }));
folders = list_folders.ToArray();
return true;
}
}
}
}
}
folders = null;
return false;
}
///
/// 判断给定的路径是否是个有效的扩展包(每个扩展组是一个独立的扩展包)
///
///
///
public static bool IsValidExtensionPackage(string package_path)
{
if (!Directory.Exists(package_path)) return false;
//检查,扩展包的根目录下会有的几个东西
//FileHash
string hash_path = Path.Combine(package_path, VFSConst.AssetBundleFilesHash_FileName);
if (!File.Exists(hash_path)) return false;
//group_option
if (!File.Exists(VFSUtil.Get_GroupOptions_InExtensionPackage(package_path))) return false;
//groupInfo
if (!File.Exists(VFSUtil.GetExtensionGroup_GroupInfo_Path_InGroupPath(package_path))) return false;
//manifest
if (!File.Exists(Path.Combine(package_path, VFSConst.AssetBundleManifestFileName))) return false;
return true;
}
///
/// 在给定的目录下,寻找有效可用的扩展组信息,返回组数组
///
/// 存放扩展组的根目录,该方法只会搜寻它的直接子目录
/// 如果提供Main Package版本信息,将只会返回满足扩展组对MainPackage最低版本限制的扩展组列表
/// 组名 数组
public static string[] GetValidExtensionGroupNames(string extensions_root_path, long? main_package_version = null)
{
if (!Directory.Exists(extensions_root_path)) return Array.Empty();
List groups = new List();
string[] folders = Directory.GetDirectories(extensions_root_path, "*", SearchOption.TopDirectoryOnly);
foreach (var folder in folders)
{
if (VFSUtil.IsValidExtensionPackage(folder))
{
//读取groupName
try
{
string group_info_path = Path.Combine(folder, VFSConst.VFS_ExtensionGroupInfo_FileName);
string group_info_json = File.ReadAllText(group_info_path);
var group_info_obj = JsonUtility.FromJson(group_info_json);
if (main_package_version != null)
{
//判断版本
if (main_package_version.Value >= group_info_obj.MainPackageVersionLimit)
groups.Add(group_info_obj.GroupName);
}
else
groups.Add(group_info_obj.GroupName);
}
catch (Exception e)
{
Debug.LogError("[TinaX.VFS] Exception while load extension package info : " + folder + "\n" + e.Message);
}
}
}
return groups.ToArray();
}
///
/// 获取扩展组的那个文件夹的名字,(不是完整路径)
///
///
///
public static string GetExtensionGroupFolderName(string group_name)
{
return group_name.ToLower();
}
///
/// 获取StreamingAssets下的存放packages的根目录 (eg: streamingassets/TinaX_VFS/android)
///
///
///
public static string GetPackagesRootFolderInStreamingAssets(string platform_name)
{
return Path.Combine(Application.streamingAssetsPath, VFSConst.VFS_STREAMINGASSETS_PATH, platform_name);
}
public static string GetPackagesRootFolderInStreamingAssets()
{
var pname = XPlatformUtil.GetNameText(XPlatformUtil.GetXRuntimePlatform(Application.platform));
return GetPackagesRootFolderInStreamingAssets(pname);
}
///
/// StreamingAssets 里的 vfs_root
///
///
public static string GetMainPackageFolderInStreamingAssets()
{
return GetMainPackageFolderInPackages(GetPackagesRootFolderInStreamingAssets());
}
///
/// 给定路径里的main package 路径(vfs_root)
///
///
///
public static string GetMainPackageFolderInPackages(string packages_root_path)
{
return Path.Combine(packages_root_path, VFSConst.VFS_FOLDER_MAIN);
}
///
/// StreamingAssets 里的 vfs_data
///
///
public static string GetDataFolderInStreamingAssets()
{
return GetDataFolderInPackages(GetPackagesRootFolderInStreamingAssets());
}
///
/// 获取给定路径里的data目录(vfs_data)
///
///
///
public static string GetDataFolderInPackages(string packages_root_path)
{
return Path.Combine(packages_root_path, VFSConst.VFS_FOLDER_DATA);
}
///
/// StreamingAssets 里的 vfs_extension
///
///
public static string GetExtensionPackageRootFolderInStreamingAssets()
{
return GetExtensionPackageRootFolderInPackages(GetPackagesRootFolderInStreamingAssets());
}
///
/// 在给定的根目录中,获取存放扩展包的文件夹的路径(vfs_extension)
///
///
///
public static string GetExtensionPackageRootFolderInPackages(string packages_root_path)
{
return Path.Combine(packages_root_path, VFSConst.VFS_FOLDER_EXTENSION);
}
///
/// 在给定的根目录中,获取到某个扩展组的根目录
///
///
///
///
public static string GetExtensionGroupFolder(string packages_root_path, string groupName)
{
return Path.Combine(VFSUtil.GetExtensionPackageRootFolderInPackages(packages_root_path), GetExtensionGroupFolderName(groupName));
}
///
/// 在给定的“扩展包根目录”中,获取某个扩展包中的assetbundle的路径
///
///
///
///
///
public static string GetAssetBundlePathFromExtensionGroup_InExtensionPackagesRootFolder(string extension_root_folder,string groupName,string assetbundleName)
{
return Path.Combine(extension_root_folder, GetExtensionGroupFolderName(groupName), assetbundleName);
}
///
/// 获取给定的根目录中(Packages root path),某个AssetBundle的位置
///
///
///
///
///
///
public static string GetAssetBundlePathFromPackages(bool isExtensionGroup, string packages_root_path, string assetBundleName, string group_name = null)
{
if (isExtensionGroup)
return GetAssetBundlePathFromExtensionGroup_InExtensionPackagesRootFolder(GetExtensionPackageRootFolderInPackages(packages_root_path), group_name, assetBundleName);
else
return Path.Combine(VFSUtil.GetMainPackageFolderInPackages(packages_root_path), assetBundleName);
}
///
/// 获取Main Package中某个组的AssetBundle的Hash记录文件
///
///
///
///
public static string GetMainPackageAssetBundleHashFilePath(string root_path, string groupName)
{
return Path.Combine(GetMainPackageAssetBundleHashFilesRootPath(root_path), groupName.GetMD5(true,true));
}
///
/// 获取Main Package中所有AssetBundle的hash记录文件存放的根目录(vfs_data/main_hashs/)
///
///
///
public static string GetMainPackageAssetBundleHashFilesRootPath(string root_path)
{
return Path.Combine(root_path, VFSConst.VFS_FOLDER_DATA, VFSConst.MainPackage_AssetBundle_Hash_Files_Folder);
}
///
/// 获取给定的根目录中 扩展组的AssetBundle的 Hash 记录文件
///
///
///
///
public static string GetExtensionGroup_AssetBundleHashFileFilePath(string root_path,string groupName)
{
return Path.Combine(root_path, VFSConst.VFS_FOLDER_EXTENSION, GetExtensionGroupFolderName(groupName), VFSConst.AssetBundleFilesHash_FileName);
}
///
/// 在给定的跟路径下获取记录MainPackage存放所有AssetBundleManifest文件的目录
///
///
///
public static string GetMainPackage_AssetBundleManifests_Folder(string packages_root_path)
{
return Path.Combine(packages_root_path, VFSConst.VFS_FOLDER_DATA, VFSConst.MainPackage_AssetBundleManifests_Folder);
}
///
/// 在给定的路径下获取记录 扩展组 的 AssetBundleManifest 的路径
///
///
///
///
public static string GetExtensionGroups_AssetBundleManifests_FilePath(string packages_root_path, string group_name)
{
return Path.Combine(packages_root_path, VFSConst.VFS_FOLDER_EXTENSION, GetExtensionGroupFolderName(group_name), VFSConst.AssetBundleManifestFileName);
}
///
/// 在给定的路径下 获取 MainPackage的 BuildInfo 的路径
///
///
///
public static string GetMainPackage_BuildInfo_Path(string package_root_path)
{
return Path.Combine(package_root_path, VFSConst.VFS_FOLDER_DATA, VFSConst.BuildInfoFileName);
}
///
/// 在给定的路径下 获取 扩展组的 BuildInfo 的路径
///
///
///
///
public static string GetExtensionGroup_BuildInfo_Path(string package_root_path, string group)
{
return GetExtensionGroup_BuildInfo_Path_InGroupPath(GetExtensionGroupFolder(package_root_path, group));
}
///
/// 在给定的 扩展组的根目录下 获取扩展组的 BuildInfo 文件路径
///
///
///
public static string GetExtensionGroup_BuildInfo_Path_InGroupPath(string group_path)
{
return Path.Combine(group_path, VFSConst.BuildInfoFileName);
}
///
/// 在给定的 扩展组的根目录下 获取扩展组的 GroupInfo 文件路径
///
///
///
public static string GetExtensionGroup_GroupInfo_Path_InGroupPath(string group_path)
{
return Path.Combine(group_path, VFSConst.VFS_ExtensionGroupInfo_FileName);
}
///
/// 在给定的路径下 获取 MainPackage的 版本信息 的路径
///
///
///
public static string GetMainPackage_VersionInfo_Path(string packages_root_path)
{
return Path.Combine(packages_root_path, VFSConst.VFS_FOLDER_DATA, VFSConst.PakcageVersionFileName);
}
///
/// 在给定的根目录中获取扩展组的option文件路径
///
public static string GetExtensionPackages_GroupOptions_FilePath(string packages_root_path, string group_name)
{
return Get_GroupOptions_InExtensionPackage(GetExtensionGroupFolder(packages_root_path, group_name));
}
///
/// 在给定的扩展包(组)的根目录中,获取GroupOptions文件的路径
///
///
///
public static string Get_GroupOptions_InExtensionPackage(string extension_group_path)
{
return Path.Combine(extension_group_path, VFSConst.ExtensionGroup_GroupOption_FileName);
}
///
/// 在给定的路径下 获取 扩展组的 版本信息 的路径
///
///
///
///
public static string GetExtensionGroup_VersionInfo_Path(string package_root_path, string group)
{
return Path.Combine(package_root_path, VFSConst.VFS_FOLDER_EXTENSION, GetExtensionGroupFolderName(group), VFSConst.PakcageVersionFileName);
}
///
/// 获取Runtime下的VFS主Config文件路径
///
///
///
public static string GetVFSConfigFilePath_InPackages(string packages_root_path)
{
return Path.Combine(GetDataFolderInPackages(packages_root_path), VFSConst.Config_Runtime_FileName);
}
public static string GetMainPackage_UpgradableVersionFilePath(string packages_root_path)
{
return Path.Combine(GetDataFolderInPackages(packages_root_path), VFSConst.Upgradable_Vesion_FileName);
}
}
}