using System; using System.Collections; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using BITKit; using BITKit.IO; using Cysharp.Threading.Tasks; using Microsoft.Extensions.Logging; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.SceneManagement; using YooAsset; namespace Project.B.Map { public class GameMapService : IGameMapService,IDisposable { public bool PreloadShaders { get; set; } = true; private readonly ILogger _logger; private const string MenuScene = "map_menu"; private readonly ValidHandle _isBusy = new(); public TaskStatus TaskStatus { get => _taskStatus; private set { if (_taskStatus == value) return; OnTaskStatusChanged?.Invoke(_taskStatus, value); _taskStatus = value; } } private TaskStatus _taskStatus; private readonly CancellationTokenSource _cancellationTokenSource = new(); public GameMapService(ILogger logger) { _logger = logger; } public string CurrentMap { get;private set; } public UniTask GetMapAsync() { return UniTask.FromResult(CurrentMap); } public async UniTask StartMapAsync(string map) { await _isBusy; using var _ = _isBusy.GetHandle(); TaskStatus = TaskStatus.Running; SceneHandle handle = null; ResourcePackage mapPackage = null; CurrentMap = map; await OnMapChange.UniTaskFunc(map); await UniTask.NextFrame(); foreach (var resourcePackage in YooAssetUtils.RegisteredResourcePackages) { if (YooAssetModHelper.PackagesManifestDictionary[resourcePackage.PackageName].Contains(map) is false) continue; var assetInfo = resourcePackage.GetAssetInfo(map); mapPackage = resourcePackage; handle = resourcePackage.LoadSceneAsync(assetInfo.AssetPath); } if (handle is null) { throw new Exception($"找不到地图:{map}"); } while (handle.IsDone is false && handle.IsValid) { await UniTask.NextFrame(); OnMapLoadingProgress?.Invoke(Guid.Empty, handle.Progress, "正在加载地图"); //if(_cancellationTokenSource.IsCancellationRequested)return; } if (PreloadShaders) { OnMapLoadingProgress?.Invoke(Guid.Empty, 1, "地图加载完成,正在查找着色器..."); if (YooAssetModHelper.PackagesManifestDictionary[mapPackage.PackageName].Contains("MyShaderVariants")) { var shaderAssetInfo = mapPackage.GetAssetInfo("MyShaderVariants"); var hashset = new HashSet(); _logger.LogInformation("已找到着色器,加载中..."); OnMapLoadingProgress?.Invoke(Guid.Empty, 1, "找到着色器,正在初始化..."); var assetHandle = mapPackage.LoadAssetSync(shaderAssetInfo); var shader = (ShaderVariantCollection)assetHandle.AssetObject; shader.WarmUp(); foreach (var gameObject in handle.SceneObject.GetRootGameObjects()) { foreach (var meshRenderer in gameObject.GetComponentsInChildren()) { foreach (var material in meshRenderer.sharedMaterials) { hashset.Add(material); } } foreach (var terrain in gameObject.GetComponentsInChildren()) { hashset.Add(terrain.materialTemplate); } } foreach (var material in hashset) { if (!material) continue; if (material.shader is null) continue; material.shader = Shader.Find(material.shader.name); } _logger.LogInformation($"着色器加载完成,有Shader{shader.shaderCount}个,Variant:{shader.variantCount}个"); } else { _logger.LogInformation("未找到着色器,跳过加载..."); } OnMapLoadingProgress?.Invoke(Guid.Empty, 1, "着色器预热完成,准备就绪"); TaskStatus = TaskStatus.RanToCompletion; await OnMapChanging.UniTaskFunc(map); OnMapChanged?.Invoke(Guid.Empty, CurrentMap); } } public async UniTask StopMapAsync() { await _isBusy; using var _ = _isBusy.GetHandle(); TaskStatus = TaskStatus.WaitingForActivation; //if(_cancellationTokenSource.IsCancellationRequested)return; await YooAssets.LoadSceneAsync(MenuScene); OnMapChanged?.Invoke(Guid.Empty, string.Empty); } public event Action OnTaskStatusChanged; public event Func OnMapChange; public event Func OnMapChanging; public event Action OnMapChanged; public event Action OnMapLoadingProgress; public void Dispose() { _cancellationTokenSource.Cancel(); } } }