Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/GameServices/GameMapService.cs

177 lines
5.8 KiB
C#
Raw Normal View History

2025-06-24 23:49:13 +08:00
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<GameMapService> _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<GameMapService> logger)
{
_logger = logger;
}
public string CurrentMap { get;private set; }
public UniTask<string> 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<Material>();
_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<MeshRenderer>())
{
foreach (var material in meshRenderer.sharedMaterials)
{
hashset.Add(material);
}
}
foreach (var terrain in gameObject.GetComponentsInChildren<Terrain>())
{
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<TaskStatus, TaskStatus> OnTaskStatusChanged;
public event Func<string, UniTask> OnMapChange;
public event Func<string, UniTask> OnMapChanging;
public event Action<Guid, string> OnMapChanged;
public event Action<Guid, float, string> OnMapLoadingProgress;
public void Dispose()
{
_cancellationTokenSource.Cancel();
}
}
}