Files
Hasebe/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs
T
2026-09-20 15:26:03 +03:00

109 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Code.Infrastructure.Configs;
using Code.Infrastructure.Utils;
using Cysharp.Threading.Tasks;
using ObservableCollections;
using Reflex.Core;
using UnityEngine;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
namespace Code.Infrastructure.SceneLoader
{
using UnityEngine.AddressableAssets;
public interface ISceneLoader
{
UniTask LoadSceneAsync(SceneId id, LoadSceneMode loadMode, bool setActive, Action<Scene, ContainerBuilder> extraInstall = null);
Scene GetScene(SceneId id);
UniTask UnloadSceneAsync(SceneId id);
}
public interface ISceneContainerManager
{
ObservableDictionary<SceneId, Container> ScenesContainers { get; }
}
public interface ICustomSceneManagerInitializer
{
UniTask LoadConfigs();
}
public class CustomCustomSceneManager : IDisposable, ISceneLoader, ISceneContainerManager,
ICustomSceneManagerInitializer
{
private AsyncOperationHandle<IList<SceneInfo>> _loadHandle;
private AsyncOperationHandle<IList<SceneInfo>> _configHandle;
private readonly string _configsLabel;
public ObservableDictionary<SceneId, Container> ScenesContainers { get; } = new();
private Dictionary<SceneId, SceneInfo> _sceneInfos = new();
private Dictionary<SceneId, AsyncOperationHandle<SceneInstance>> _loadedScenes = new();
public CustomCustomSceneManager(IConfigLocator configLocator)
{
_configsLabel = configLocator.TryGetManyConfigAssetReferences<SceneInfo>();
}
// Киська
// TODO При загрузке нескольких сцен сразу может быть неприятность
public async UniTask LoadSceneAsync(
SceneId id,
LoadSceneMode loadMode,
bool setActive,
Action<Scene, ContainerBuilder> extraInstall = null)
{
if (loadMode == LoadSceneMode.Single)
for (var i = 0; i < _loadedScenes.Count; i++)
UnloadSceneAsync(_loadedScenes.Keys.ToList()[i]).Forget();
if (extraInstall != null) ContainerScope.OnSceneContainerBuilding += extraInstall;
_loadedScenes.Add(id, Addressables.LoadSceneAsync(_sceneInfos[id].SceneAsset, LoadSceneMode.Additive));
await _loadedScenes[id];
if (extraInstall != null) ContainerScope.OnSceneContainerBuilding -= extraInstall;
if (setActive) SceneManager.SetActiveScene(_loadedScenes[id].Result.Scene);
}
public Scene GetScene(SceneId id) => _loadedScenes[id].Result.Scene;
public async UniTask UnloadSceneAsync(SceneId id)
{
await Addressables.UnloadSceneAsync(_loadedScenes[id]);
_loadedScenes.Remove(id);
}
public async UniTask LoadConfigs()
{
if (!await AddressablesUtilities.CheckLabelExists(_configsLabel)) return;
_configHandle =
Addressables.LoadAssetsAsync<SceneInfo>(_configsLabel, OnSceneConfigLoaded,
Addressables.MergeMode.Union);
await _configHandle.ToUniTask();
}
private void OnSceneConfigLoaded(SceneInfo sceneInfoConfig)
{
SceneInfo sceneInfo = ScriptableObject.CreateInstance<SceneInfo>();
sceneInfo.SceneId = sceneInfoConfig.SceneId;
sceneInfo.SceneAsset = sceneInfoConfig.SceneAsset;
_sceneInfos.Add(sceneInfoConfig.SceneId, sceneInfo);
}
public void Dispose()
{
if(_configHandle.IsValid()) Addressables.Release(_configHandle);
}
}
}