using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Drawing.Printing; using System.IO; using System.Linq; using System.Text.RegularExpressions; using BITKit.Mod; using Cysharp.Threading.Tasks; using Microsoft.Extensions.Logging; using UnityEditor; using UnityEngine; using YooAsset; using ILogger = Microsoft.Extensions.Logging.ILogger; using Object = UnityEngine.Object; namespace BITKit.IO { public class YooAssetModHelper { public static string Url = "http://server.bitfall.icu:21982/com.project.b/Mods"; public static readonly ConcurrentDictionary> PackagesManifestDictionary = new(); public static async UniTask LoadMods(ILogger logger=null) { try { var modPath = Path.Combine(Environment.CurrentDirectory, "Mods"); if (Application.platform is RuntimePlatform.Android) { modPath = Path.Combine($"/storage/emulated/0/{Application.identifier}/Mods/"); } foreach (var directoryInfo in new DirectoryInfo(modPath).GetDirectories()) { var packageName = directoryInfo.Name; logger?.LogInformation($"开始加载:{packageName}"); var package = YooAssets.CreatePackage(packageName); var initPars = new HostPlayModeParameters() { BuildinQueryServices = new GameQueryServices(), RemoteServices = new RemoteServices($"{Url}/{directoryInfo.Name}",$"file://{directoryInfo.FullName}") }; await package.InitializeAsync(initPars); var update = package.UpdatePackageVersionAsync(); await update.ToUniTask(); var manifest = package.UpdatePackageManifestAsync(update.PackageVersion); await manifest.ToUniTask(); var downloader = package.CreateResourceDownloader(10, 3); if (logger is not null) { downloader.OnDownloadProgressCallback = (totalDownloadCount, currentDownloadCount, totalDownloadBytes, currentDownloadBytes) => { //下载进度 var progress = (float)currentDownloadBytes / totalDownloadBytes; logger.LogInformation($"已下载{(int)(progress*100)}%,资源数量{currentDownloadBytes}/{totalDownloadBytes}"); }; downloader.OnDownloadErrorCallback = (fileName, error) => { logger.LogError($"资源[{fileName}]下载错误::{error}"); }; } downloader.BeginDownload(); await downloader.ToUniTask(); var mod = new MyMod() { FolderPath = directoryInfo.FullName, PackageName = packageName, Name = packageName }; await ModService.Install(mod); await ModService.Load(mod); YooAssetUtils.RegisterResourcePackage(package); logger?.LogInformation($"已加载:{packageName},路径:{directoryInfo.FullName}"); } return; } catch (Exception e) { if (logger is not null) { logger.LogCritical(e.Message,e); } else { BIT4Log.LogException(e); } } logger?.LogInformation($"未找到Mod"); } private static HashSet BuildPackageCache(string obj) { var package = YooAssets.GetPackage(obj); var playMode = package.GetType().GetField("_playModeImpl", ReflectionHelper.Flags)!.GetValue(package); var manifest = playMode.GetType().GetProperty("ActiveManifest", ReflectionHelper.Flags)!.GetValue(playMode); var dictionary = manifest.GetType().GetField("AssetDic", ReflectionHelper.Flags)!.GetValue(manifest) as IDictionary; var hashset = new HashSet(); foreach (var key in dictionary.Keys) { hashset.Add(key?.ToString()); } var assetPathMapping1=manifest.GetType().GetField("AssetPathMapping1", ReflectionHelper.Flags)!.GetValue(manifest) as IDictionary; foreach (var key in assetPathMapping1.Keys) { hashset.Add(key); } return hashset; } public static async UniTask> LoadAssets( string[] arg) { var list = new List(); foreach (var resourcePackage in YooAssetUtils.RegisteredResourcePackages) { foreach (var assetInfo in resourcePackage.GetAssetInfos(arg)) { var asyncHandle = resourcePackage.LoadAssetAsync(assetInfo); await asyncHandle; list.Add(asyncHandle.AssetObject); } } return list; } public static async UniTask LoadAsset(string arg) { foreach (var resourcePackage in YooAssetUtils.RegisteredResourcePackages.Reverse()) { if(PackagesManifestDictionary.GetOrAdd(resourcePackage.PackageName,BuildPackageCache).Contains(arg) is false)continue; var assetInfo = resourcePackage.GetAssetInfo(arg); if(string.IsNullOrEmpty(assetInfo.Error) is false)continue; var handle = resourcePackage.LoadAssetAsync(arg); await handle; return handle.AssetObject; } return null; } } }