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 extraInstall = null); Scene GetScene(SceneId id); UniTask UnloadSceneAsync(SceneId id); } public interface ISceneContainerManager { ObservableDictionary ScenesContainers { get; } } public interface ICustomSceneManagerInitializer { UniTask LoadConfigs(); } public class CustomCustomSceneManager : IDisposable, ISceneLoader, ISceneContainerManager, ICustomSceneManagerInitializer { private AsyncOperationHandle> _loadHandle; private AsyncOperationHandle> _configHandle; private readonly string _configsLabel; public ObservableDictionary ScenesContainers { get; } = new(); private Dictionary _sceneInfos = new(); private Dictionary> _loadedScenes = new(); public CustomCustomSceneManager(IConfigLocator configLocator) { _configsLabel = configLocator.TryGetManyConfigAssetReferences(); } // Киська // TODO При загрузке нескольких сцен сразу может быть неприятность public async UniTask LoadSceneAsync( SceneId id, LoadSceneMode loadMode, bool setActive, Action 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(_configsLabel, OnSceneConfigLoaded, Addressables.MergeMode.Union); await _configHandle.ToUniTask(); } private void OnSceneConfigLoaded(SceneInfo sceneInfoConfig) { SceneInfo sceneInfo = ScriptableObject.CreateInstance(); sceneInfo.SceneId = sceneInfoConfig.SceneId; sceneInfo.SceneAsset = sceneInfoConfig.SceneAsset; _sceneInfos.Add(sceneInfoConfig.SceneId, sceneInfo); } public void Dispose() { if(_configHandle.IsValid()) Addressables.Release(_configHandle); } } }