From db5de56b3b7db973c4b7f31fda51dffcc83f70e1 Mon Sep 17 00:00:00 2001 From: NTG Date: Wed, 27 Aug 2025 17:52:33 +0900 Subject: [PATCH] =?UTF-8?q?Addressable=EA=B8=B0=EB=8A=A5=20AssetManager?= =?UTF-8?q?=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_ScriptAssets/Prefabs/AssetManager.prefab | 1 + .../Prefabs/InventoryManager.prefab | 1 + .../So/ManagerDefinitionSo.asset | 2 +- .../_Scripts/AssetManagement/AssetManager.cs | 311 ++++++++++++++---- Assets/_DDD/_Scripts/GameData/DataManager.cs | 4 +- Assets/_DDD/_Scripts/GameData/GameData.cs | 24 +- .../GameFramework/Scene/SceneManager.cs | 6 +- .../_Scripts/GameState/InventoryManager.cs | 7 +- .../Run/Customer/CustomerFactory.cs | 20 +- .../_Scripts/RestaurantData/RestaurantData.cs | 43 +-- .../RestaurantEnvironment.cs | 8 +- .../FlowStates/RestaurantCustomerState.cs | 27 +- .../_Scripts/Utilities/ScriptSingleton.cs | 15 +- 13 files changed, 314 insertions(+), 155 deletions(-) diff --git a/Assets/_DDD/_ScriptAssets/Prefabs/AssetManager.prefab b/Assets/_DDD/_ScriptAssets/Prefabs/AssetManager.prefab index 80b46c13c..f9da50762 100644 --- a/Assets/_DDD/_ScriptAssets/Prefabs/AssetManager.prefab +++ b/Assets/_DDD/_ScriptAssets/Prefabs/AssetManager.prefab @@ -45,3 +45,4 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _persistent: 1 + _enableDebugLog: 1 diff --git a/Assets/_DDD/_ScriptAssets/Prefabs/InventoryManager.prefab b/Assets/_DDD/_ScriptAssets/Prefabs/InventoryManager.prefab index d129e1fbd..e290e9188 100644 --- a/Assets/_DDD/_ScriptAssets/Prefabs/InventoryManager.prefab +++ b/Assets/_DDD/_ScriptAssets/Prefabs/InventoryManager.prefab @@ -45,3 +45,4 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _persistent: 1 + _inventoryTestDataSo: {fileID: 11400000, guid: 29d0dee3b70fbc44d992ea47012bc366, type: 2} diff --git a/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset b/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset index a76bc5919..198eb2519 100644 --- a/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset +++ b/Assets/_DDD/_ScriptAssets/So/ManagerDefinitionSo.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e22d6af69a361da6b510144cfed3df81e14ae58cc18093c2fed9f06553f42259 +oid sha256:b4d8b8e6ec2ca99570deababa75093849d4cfcd6af6c78fbcc857880b03c0226 size 1504 diff --git a/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs b/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs index d1ab863b7..3af080ccc 100644 --- a/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs +++ b/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs @@ -1,10 +1,6 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -#if UNITY_EDITOR -using UnityEditor.AddressableAssets; -#endif using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; @@ -15,7 +11,34 @@ namespace DDD { public class AssetManager : Singleton, IManager { - private static readonly Dictionary _cachedHandles = new(); + private struct CachedAsset + { + public AsyncOperationHandle Handle; + public int ReferenceCount; + + public CachedAsset(AsyncOperationHandle handle, int count = 1) + { + Handle = handle; + ReferenceCount = count; + } + } + + private struct CachedScene + { + public AsyncOperationHandle Handle; + public int ReferenceCount; + + public CachedScene(AsyncOperationHandle handle, int count = 1) + { + Handle = handle; + ReferenceCount = count; + } + } + + [SerializeField] private bool _enableDebugLog = false; + + private readonly Dictionary _cachedAssets = new(); + private readonly Dictionary _cachedScenes = new(); protected override void OnApplicationQuit() { @@ -24,110 +47,284 @@ protected override void OnApplicationQuit() ReleaseAllCached(); } - public void PreInit() - { - - } + public void PreInit() { } public async Task Init() { await Addressables.InitializeAsync().Task; } - public void PostInit() + public void PostInit() { } + + private string GetSafeAssetName(AssetReference assetReference) { + var editorAssetName = assetReference.editorAsset.name; + if (string.IsNullOrWhiteSpace(editorAssetName) == false) return editorAssetName; + return assetReference.ToString(); } - - public static async Task LoadAsset(string key) where T : UnityEngine.Object + + public async Task LoadAssetAsync(AssetReference assetReference) where T : Object { - if (_cachedHandles.TryGetValue(key, out var handle)) + var guidKey = assetReference.AssetGUID; + + if (_cachedAssets.TryGetValue(guidKey, out var cachedAsset)) { - if (handle.IsValid() && handle.Result is T result) + if (cachedAsset.Handle.IsValid() && cachedAsset.Handle.Result is T result) + { + cachedAsset.ReferenceCount++; + _cachedAssets[guidKey] = cachedAsset; + + if (_enableDebugLog) Debug.Log($"[AssetManager] 에셋 참조 카운트 증가: {GetSafeAssetName(assetReference)} -> {cachedAsset.ReferenceCount}\n실제 키 값: {guidKey}"); return result; - - Debug.LogWarning($"[AssetManager] Type mismatch or invalid handle for key: {key}"); - return handle.Result as T; + } + + _cachedAssets.Remove(guidKey); + Debug.LogWarning($"[AssetManager] 무효한 핸들 제거됨: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); } - - // ✅ 새로 로드 - var newHandle = Addressables.LoadAssetAsync(key); + + var newHandle = Addressables.LoadAssetAsync(guidKey); await newHandle.Task; if (newHandle.Status == AsyncOperationStatus.Succeeded) { - _cachedHandles[key] = newHandle; + _cachedAssets[guidKey] = new CachedAsset(newHandle, 1); + if (_enableDebugLog) Debug.Log($"[AssetManager] 에셋 로드 및 캐싱 완료: {GetSafeAssetName(assetReference)} (참조수: {_cachedAssets[guidKey].ReferenceCount})\n실제 키 값: {guidKey}"); return newHandle.Result; } - Debug.LogError($"[AssetManager] Failed to load asset: {key}"); + if (newHandle.IsValid()) + { + Addressables.Release(newHandle); + } + + Debug.LogError($"[AssetManager] 에셋 로드 실패: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); + return null; + } + + /// + /// ScriptSingleton을 위한 동기 로딩 + /// + public T LoadAsset(string key) where T : Object + { + if (_cachedAssets.TryGetValue(key, out var cachedAsset)) + { + if (cachedAsset.Handle.IsValid() && cachedAsset.Handle.Result is T result) + { + cachedAsset.ReferenceCount++; + _cachedAssets[key] = cachedAsset; + + if (_enableDebugLog) Debug.Log($"[AssetManager] 동기 로딩 - 에셋 참조 카운트 증가: {key} -> {cachedAsset.ReferenceCount}"); + return result; + } + + _cachedAssets.Remove(key); + Debug.LogWarning($"[AssetManager] 무효한 핸들 제거됨: {key}"); + } + + var handle = Addressables.LoadAssetAsync(key); + var loaded = handle.WaitForCompletion(); + + if (handle.Status == AsyncOperationStatus.Succeeded) + { + _cachedAssets[key] = new CachedAsset(handle, 1); + if (_enableDebugLog) Debug.Log($"[AssetManager] 동기 로딩 - 에셋 로드 및 캐싱 완료: {key} (참조수: {key})"); + return loaded; + } + + if (handle.IsValid()) + { + Addressables.Release(handle); + } + + Debug.LogError($"[AssetManager] 동기 로딩 - 에셋 로드 실패: {key}"); return null; } - public static async Task> LoadAssetsByLabel(string label) where T : UnityEngine.Object + public async Task> LoadAssetsByLabel(string label) where T : Object { - var handle = Addressables.LoadAssetsAsync(label, null); + if (_cachedAssets.TryGetValue(label, out var cachedAsset)) + { + if (cachedAsset.Handle.IsValid() && cachedAsset.Handle.Result is IList cachedResult) + { + cachedAsset.ReferenceCount++; + _cachedAssets[label] = cachedAsset; + + if (_enableDebugLog) Debug.Log($"[AssetManager] 라벨 에셋 참조 카운트 증가: {label} -> {cachedAsset.ReferenceCount}"); + return cachedResult.ToList(); + } + + _cachedAssets.Remove(label); + if (_enableDebugLog) Debug.LogWarning($"[AssetManager] 무효한 라벨 핸들 제거됨: {label}"); + } + + var handle = Addressables.LoadAssetsAsync(label); await handle.Task; if (handle.Status == AsyncOperationStatus.Succeeded) + { + _cachedAssets[label] = new CachedAsset(handle, 1); + if (_enableDebugLog) Debug.Log($"[AssetManager] 라벨 에셋 로드 및 캐싱 완료: {label} (참조수: {_cachedAssets[label].ReferenceCount})"); return handle.Result.ToList(); + } - Debug.LogError($"[AssetManager] Failed to load assets with label: {label}"); + if (handle.IsValid()) + { + Addressables.Release(handle); + } + + Debug.LogError($"[AssetManager] 라벨 에셋 로드 실패: {label}"); return new List(); } - public static async Task LoadScene(AssetReference assetReference, LoadSceneMode mode = LoadSceneMode.Additive, bool activateOnLoad = true) + public void ReleaseAsset(AssetReference assetReference) { + var guidKey = assetReference.AssetGUID; + + if (_cachedAssets.TryGetValue(guidKey, out var cachedAsset)) + { + cachedAsset.ReferenceCount--; + + if (cachedAsset.ReferenceCount <= 0) + { + if (cachedAsset.Handle.IsValid()) + { + Addressables.Release(cachedAsset.Handle); + if (_enableDebugLog) Debug.Log($"[AssetManager] 에셋 실제 해제됨: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); + } + _cachedAssets.Remove(guidKey); + } + else + { + _cachedAssets[guidKey] = cachedAsset; + if (_enableDebugLog) Debug.Log($"[AssetManager] 에셋 참조 카운트 감소: {GetSafeAssetName(assetReference)} -> {cachedAsset.ReferenceCount}\n실제 키 값: {guidKey}"); + } + } + else + { + if (_enableDebugLog) Debug.LogWarning($"[AssetManager] 캐시에서 에셋을 찾을 수 없음: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); + } + } + + public void ReleaseAsset(string key) + { + if (_cachedAssets.TryGetValue(key, out var cachedAsset)) + { + cachedAsset.ReferenceCount--; + + if (cachedAsset.ReferenceCount <= 0) + { + if (cachedAsset.Handle.IsValid()) + { + Addressables.Release(cachedAsset.Handle); + if (_enableDebugLog) Debug.Log($"[AssetManager] 에셋 실제 해제됨: {key}"); + } + _cachedAssets.Remove(key); + } + else + { + _cachedAssets[key] = cachedAsset; + if (_enableDebugLog) Debug.Log($"[AssetManager] 에셋 참조 카운트 감소: {key} -> {cachedAsset.ReferenceCount}"); + } + } + else + { + if (_enableDebugLog) Debug.LogWarning($"[AssetManager] 캐시에서 에셋을 찾을 수 없음: {key}"); + } + } + + public async Task LoadScene(AssetReference assetReference, LoadSceneMode mode = LoadSceneMode.Additive, bool activateOnLoad = true) + { + var guidKey = assetReference.AssetGUID; + + if (_cachedScenes.TryGetValue(guidKey, out var cachedScene)) + { + if (cachedScene.Handle.IsValid()) + { + cachedScene.ReferenceCount++; + _cachedScenes[guidKey] = cachedScene; + + if (_enableDebugLog) Debug.Log($"[AssetManager] 씬 참조 카운트 증가: {GetSafeAssetName(assetReference)} -> {cachedScene.ReferenceCount}\n실제 키 값: {guidKey}"); + return cachedScene.Handle.Result; + } + + _cachedScenes.Remove(guidKey); + if (_enableDebugLog) Debug.LogWarning($"[AssetManager] 무효한 씬 핸들 제거됨: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); + } + var handle = Addressables.LoadSceneAsync(assetReference, mode, activateOnLoad); await handle.Task; if (handle.Status == AsyncOperationStatus.Succeeded) + { + _cachedScenes[guidKey] = new CachedScene(handle, 1); + var sceneName = handle.Result.Scene.name; + if (_enableDebugLog) Debug.Log($"[AssetManager] 씬 로드 및 캐싱 완료: {sceneName} (참조수: {_cachedScenes[guidKey].ReferenceCount})\n실제 키 값: {guidKey}"); return handle.Result; + } + + if (handle.IsValid()) + { + Addressables.UnloadSceneAsync(handle); + } - Debug.LogError($"Scene load failed: {assetReference}"); + Debug.LogError($"[AssetManager] 씬 로드 실패: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); return default; } - - public static async Task UnloadScene(SceneInstance sceneInstance) - { - var handle = Addressables.UnloadSceneAsync(sceneInstance); - await handle.Task; - } - public static void ReleaseAllCached() + public async Task UnloadScene(AssetReference assetReference) { - if (_cachedHandles.Count == 0) return; + var guidKey = assetReference.AssetGUID; - foreach (var kvp in _cachedHandles) + if (_cachedScenes.TryGetValue(guidKey, out var cachedScene)) { - var handle = kvp.Value; - if (handle.IsValid()) + cachedScene.ReferenceCount--; + + if (cachedScene.ReferenceCount <= 0) { - Addressables.Release(handle); - //Debug.Log($"[AssetManager] Released handle for key: {kvp.Key}"); + if (cachedScene.Handle.IsValid()) + { + var sceneName = cachedScene.Handle.Result.Scene.name; + await Addressables.UnloadSceneAsync(cachedScene.Handle).Task; + if (_enableDebugLog) Debug.Log($"[AssetManager] 씬 실제 언로드됨: {sceneName}\n실제 키 값: {guidKey}"); + } + _cachedScenes.Remove(guidKey); + } + else + { + _cachedScenes[guidKey] = cachedScene; + if (_enableDebugLog) Debug.Log($"[AssetManager] 씬 참조 카운트 감소: {GetSafeAssetName(assetReference)} -> {cachedScene.ReferenceCount}\n실제 키 값: {guidKey}"); } } - _cachedHandles.Clear(); - - Debug.Log("[AssetManager] 모든 캐시된 Addressable 리소스를 해제했습니다."); + else + { + if (_enableDebugLog) Debug.LogWarning($"[AssetManager] 캐시에서 씬을 찾을 수 없음: {GetSafeAssetName(assetReference)}\n실제 키 값: {guidKey}"); + } } - public static bool HasLabel(string addressKey, string label) + public void ReleaseAllCached() { -#if UNITY_EDITOR - var settings = AddressableAssetSettingsDefaultObject.Settings; - if (settings == null) return false; + foreach (var kvp in _cachedAssets) + { + var cachedAsset = kvp.Value; + if (cachedAsset.Handle.IsValid()) + { + Addressables.Release(cachedAsset.Handle); + } + } + _cachedAssets.Clear(); + + foreach (var kvp in _cachedScenes) + { + var cachedScene = kvp.Value; + if (cachedScene.Handle.IsValid()) + { + Addressables.UnloadSceneAsync(cachedScene.Handle); + } + } + _cachedScenes.Clear(); - var entry = settings.groups - .SelectMany(g => g.entries) - .FirstOrDefault(e => e.address == addressKey); - - if (entry == null) return false; - - return entry.labels.Contains(label); -#else - return true; -#endif + if (_enableDebugLog) Debug.Log("[AssetManager] 모든 캐시된 Addressable 리소스를 강제 해제했습니다."); } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameData/DataManager.cs b/Assets/_DDD/_Scripts/GameData/DataManager.cs index 51277cba2..124a3f8e5 100644 --- a/Assets/_DDD/_Scripts/GameData/DataManager.cs +++ b/Assets/_DDD/_Scripts/GameData/DataManager.cs @@ -32,7 +32,7 @@ public void PostInit() private async Task LoadAllGameDataSo() { - var soList = await AssetManager.LoadAssetsByLabel(SoLabel); + var soList = await AssetManager.Instance.LoadAssetsByLabel(SoLabel); foreach (var so in soList) { @@ -45,7 +45,7 @@ private async Task LoadAllGameDataSo() private async Task LoadSpriteAtlas() { - List spriteAtlases = await AssetManager.LoadAssetsByLabel(DataConstants.AtlasLabel); + List spriteAtlases = await AssetManager.Instance.LoadAssetsByLabel(DataConstants.AtlasLabel); _spriteAtlas = new Dictionary(spriteAtlases.Count); foreach (var atlas in spriteAtlases) diff --git a/Assets/_DDD/_Scripts/GameData/GameData.cs b/Assets/_DDD/_Scripts/GameData/GameData.cs index 5bdd6653f..43933000f 100644 --- a/Assets/_DDD/_Scripts/GameData/GameData.cs +++ b/Assets/_DDD/_Scripts/GameData/GameData.cs @@ -21,19 +21,9 @@ public async Task LoadData() { return; } - - var gameLocalizationDataHandle = _gameLocalizationData.LoadAssetAsync(); - var test = AssetManager.LoadAsset(_gameLocalizationData.AssetGUID); - var popupUiDataHandle = _uiData.LoadAssetAsync(); - await gameLocalizationDataHandle.Task; - await popupUiDataHandle.Task; - - LocalizationData = gameLocalizationDataHandle.Result; - UiData = popupUiDataHandle.Result; - - Debug.Assert(LocalizationData != null, "GameLocalizationData is null"); - Debug.Assert(UiData != null, "UiData is null"); + LocalizationData = await AssetManager.Instance.LoadAssetAsync(_gameLocalizationData); + UiData = await AssetManager.Instance.LoadAssetAsync(_uiData); _isLoaded = true; } @@ -41,8 +31,16 @@ public async Task LoadData() private void OnDisable() { if (_isLoaded == false) return; + + var assetManager = AssetManager.Instance; + if (!assetManager) return; - _gameLocalizationData.ReleaseAsset(); + AssetManager.Instance.ReleaseAsset(_gameLocalizationData); + AssetManager.Instance.ReleaseAsset(_uiData); + + LocalizationData = null; + UiData = null; + _isLoaded = false; } } diff --git a/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs b/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs index 87a4f38ef..b58aa5bdf 100644 --- a/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs +++ b/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs @@ -84,7 +84,7 @@ public async Task PreloadAll() continue; } - var instance = await AssetManager.LoadScene(flowAssetPair.Value, activateOnLoad:false); + var instance = await AssetManager.Instance.LoadScene(flowAssetPair.Value, activateOnLoad:false); if (!instance.Scene.IsValid()) { Debug.LogError($"[SceneManager] {flowAssetPair.Key}의 씬 로딩 실패"); @@ -114,7 +114,7 @@ public async Task PreloadScene(GameFlowState gameFlowState) return; } - var loadedInstance = await AssetManager.LoadScene(assetRef); + var loadedInstance = await AssetManager.Instance.LoadScene(assetRef); if (!loadedInstance.Scene.IsValid()) { Debug.LogError($"[SceneManager] {gameFlowState}의 씬 로딩 실패"); @@ -170,7 +170,7 @@ public async Task UnloadScene(GameFlowState gameFlowState) } _loadedSceneDatas.Remove(gameFlowState); - await AssetManager.UnloadScene(sceneData.SceneInstance.Value); + await AssetManager.Instance.UnloadScene(assetRef); } } diff --git a/Assets/_DDD/_Scripts/GameState/InventoryManager.cs b/Assets/_DDD/_Scripts/GameState/InventoryManager.cs index 006d58597..3a8662186 100644 --- a/Assets/_DDD/_Scripts/GameState/InventoryManager.cs +++ b/Assets/_DDD/_Scripts/GameState/InventoryManager.cs @@ -27,6 +27,7 @@ public class InventoryManager : Singleton, IManager #if UNITY_EDITOR [Title("테스트용")] + [SerializeField] private InventoryTestDataSo _inventoryTestDataSo; #endif @@ -62,12 +63,8 @@ private void InitializeItemData() } #if UNITY_EDITOR - private async void ApplyEditorTestData() + private void ApplyEditorTestData() { - _inventoryTestDataSo = await AssetManager.LoadAsset(DataConstants.InventoryTestDataSo); - - if (_inventoryTestDataSo == null || !_inventoryTestDataSo.UseTestData) return; - foreach (var entry in _inventoryTestDataSo.TestItems) { if (string.IsNullOrWhiteSpace(entry.ItemId)) continue; diff --git a/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs b/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs index 9131469c6..c2fe54ce6 100644 --- a/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs +++ b/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs @@ -28,7 +28,6 @@ public struct CustomerSpawnArgs public class CustomerFactory : ICustomerFactory { private GameObject _customerPrefab; - private AsyncOperationHandle _customerPrefabHandle; public async Task CreateAsync(CustomerSpawnArgs args) { @@ -65,26 +64,13 @@ private async Task LoadCustomerAsset() Debug.LogError("[CustomerFactory] RestaurantCustomerData or its CustomerPrefab reference is not set."); return; } - - _customerPrefabHandle = customerDataAsset.CustomerPrefab.LoadAssetAsync(); - await _customerPrefabHandle.Task; - - if (_customerPrefabHandle.Result == null) - { - Debug.LogError("[CustomerFactory] Failed to load customer prefab from AssetReference."); - return; - } - - _customerPrefab = _customerPrefabHandle.Result; - Debug.Log("[CustomerFactory] Customer prefab loaded successfully."); + + _customerPrefab = await AssetManager.Instance.LoadAssetAsync(customerDataAsset.CustomerPrefab); } public void UnloadAssets() { - if (_customerPrefabHandle.IsValid()) - { - Addressables.Release(_customerPrefabHandle); - } + AssetManager.Instance.ReleaseAsset(RestaurantData.Instance.CustomerData.CustomerPrefab); _customerPrefab = null; Debug.Log("[CustomerFactory] Customer prefab unloaded."); } diff --git a/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs b/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs index 2c484bdb8..e17b1dd3d 100644 --- a/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs +++ b/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs @@ -25,28 +25,11 @@ public async Task LoadData() { return; } - - var restaurantPlayerDataHandle = _restaurantPlayerData.LoadAssetAsync(); - var restaurantManagementDataHandle = _restaurantManagementData.LoadAssetAsync(); - var restaurantRunDataHandle = _restaurantRunData.LoadAssetAsync(); - var restaurantCustomerDataHandle = _restaurantCustomerData.LoadAssetAsync(); - - await Task.WhenAll( - restaurantPlayerDataHandle.Task, - restaurantManagementDataHandle.Task, - restaurantRunDataHandle.Task, - restaurantCustomerDataHandle.Task - ); - - PlayerData = restaurantPlayerDataHandle.Result; - ManagementData = restaurantManagementDataHandle.Result; - RunData = restaurantRunDataHandle.Result; - CustomerData = restaurantCustomerDataHandle.Result; - - Debug.Assert(PlayerData != null, "RestaurantPlayerData is null"); - Debug.Assert(ManagementData != null, "RestaurantManagementData is null"); - Debug.Assert(RunData != null, "RestaurantRunData is null"); - Debug.Assert(CustomerData != null, "RestaurantCustomerData is null"); + + PlayerData = await AssetManager.Instance.LoadAssetAsync(_restaurantPlayerData); + ManagementData = await AssetManager.Instance.LoadAssetAsync(_restaurantManagementData); + RunData = await AssetManager.Instance.LoadAssetAsync(_restaurantRunData); + CustomerData = await AssetManager.Instance.LoadAssetAsync(_restaurantCustomerData); _isLoaded = true; } @@ -54,11 +37,19 @@ await Task.WhenAll( private void OnDisable() { if (_isLoaded == false) return; + + var assetManager = AssetManager.Instance; + if (!assetManager) return; - _restaurantPlayerData.ReleaseAsset(); - _restaurantManagementData.ReleaseAsset(); - _restaurantRunData.ReleaseAsset(); - _restaurantCustomerData.ReleaseAsset(); + AssetManager.Instance.ReleaseAsset(_restaurantPlayerData); + AssetManager.Instance.ReleaseAsset(_restaurantManagementData); + AssetManager.Instance.ReleaseAsset(_restaurantRunData); + AssetManager.Instance.ReleaseAsset(_restaurantCustomerData); + + PlayerData = null; + ManagementData = null; + RunData = null; + CustomerData = null; _isLoaded = false; } diff --git a/Assets/_DDD/_Scripts/RestaurantEnvironment/RestaurantEnvironment.cs b/Assets/_DDD/_Scripts/RestaurantEnvironment/RestaurantEnvironment.cs index 344fd6309..312e8f163 100644 --- a/Assets/_DDD/_Scripts/RestaurantEnvironment/RestaurantEnvironment.cs +++ b/Assets/_DDD/_Scripts/RestaurantEnvironment/RestaurantEnvironment.cs @@ -33,14 +33,14 @@ public async void Initialize(RestaurantPropLocation location) _renderer = spriteRenderer; spriteRenderer.sprite = DataManager.Instance.GetSprite(environmentData.SpriteKey); spriteRenderer.sortingOrder = 5; - Material material = await AssetManager.LoadAsset(DataConstants.BasePropSpriteMaterial); - spriteRenderer.material = new Material(material); + //Material material = await AssetManager.LoadAssetAsync(DataConstants.BasePropSpriteMaterial); + //spriteRenderer.material = new Material(material); } else if (environmentData.RendererType == RendererType.Spine) { var skeletonAnimation = _visualLook.AddComponent(); - var skeletonDataAsset = await AssetManager.LoadAsset(environmentData.SkeletonDataName); - skeletonAnimation.skeletonDataAsset = skeletonDataAsset; + //var skeletonDataAsset = await AssetManager.LoadAssetAsync(environmentData.SkeletonDataName); + //skeletonAnimation.skeletonDataAsset = skeletonDataAsset; var spineController = transform.AddComponent(); spineController.SetSkin(environmentData.SkinName); spineController.PlayAnimation(environmentData.DefaultAnimationName, true); diff --git a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs index b18f09bbe..87e46dd3d 100644 --- a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs +++ b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs @@ -1,17 +1,15 @@ using System.Collections.Generic; using System.Threading.Tasks; using Opsive.BehaviorDesigner.Runtime; -using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.AddressableAssets; -using UnityEngine.ResourceManagement.AsyncOperations; namespace DDD { public class RestaurantCustomerState : ScriptableObject { - private Dictionary _loadedSubtrees = new Dictionary(); - private Dictionary> _subtreeHandles = new Dictionary>(); + private Dictionary _loadedSubtrees = new(); + private Dictionary _subtreeAssetReference = new(); public async Task LoadCustomerBehaviorData() { @@ -40,14 +38,12 @@ public async Task LoadCustomerBehaviorData() private async Task LoadSubtreeAsync(CustomerType customerType, AssetReference subtreeReference) { - var handle = Addressables.LoadAssetAsync(subtreeReference); - _subtreeHandles[customerType] = handle; - - await handle.Task; - - if (handle.Result != null) + var subtree = await AssetManager.Instance.LoadAssetAsync(subtreeReference); + + if (subtree != null) { - _loadedSubtrees[customerType] = handle.Result; + _loadedSubtrees[customerType] = subtree; + _subtreeAssetReference[customerType] = subtreeReference; Debug.Log($"[RestaurantCustomerState] Loaded subtree for {customerType}"); } else @@ -58,16 +54,13 @@ private async Task LoadSubtreeAsync(CustomerType customerType, AssetReference su public void UnloadCustomerBehaviorData() { - foreach (var handle in _subtreeHandles.Values) + foreach (var assetReference in _subtreeAssetReference.Values) { - if (handle.IsValid()) - { - Addressables.Release(handle); - } + AssetManager.Instance.ReleaseAsset(assetReference); } _loadedSubtrees.Clear(); - _subtreeHandles.Clear(); + _subtreeAssetReference.Clear(); Debug.Log("[RestaurantCustomerState] Unloaded all customer behavior subtrees"); } diff --git a/Assets/_DDD/_Scripts/Utilities/ScriptSingleton.cs b/Assets/_DDD/_Scripts/Utilities/ScriptSingleton.cs index 9cffb682e..4aff59fcd 100644 --- a/Assets/_DDD/_Scripts/Utilities/ScriptSingleton.cs +++ b/Assets/_DDD/_Scripts/Utilities/ScriptSingleton.cs @@ -39,21 +39,16 @@ public static T Instance lock (_lock) { - // 이중 체크 락킹 패턴 if (_instance != null) return _instance; try { var key = ResolveAddressKey(); - var handle = Addressables.LoadAssetAsync(key); - - // 동기 로드: 메인 스레드에서 호출할 것을 권장합니다. - var loaded = handle.WaitForCompletion(); - - if (handle.Status != AsyncOperationStatus.Succeeded || loaded == null) + var loaded = AssetManager.Instance.LoadAsset(key); + if (loaded == null) { - throw new InvalidOperationException($"Addressables 로드 실패: 타입='{typeof(T).Name}', key='{key}'"); + throw new InvalidOperationException($"AssetManager를 통한 로드 실패: 타입='{typeof(T).Name}', key='{key}'"); } _instance = loaded; @@ -62,9 +57,9 @@ public static T Instance return _instance; } - catch (Exception) + catch (Exception e) { - throw; + throw new Exception(e.Message, e); } } }