From 1fd5279cd2c17bc84bf7f479c5e43812fb15eabd Mon Sep 17 00:00:00 2001 From: Jeonghyeon Ha Date: Tue, 19 Aug 2025 16:52:09 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=84=B0=EB=A8=B8=20?= =?UTF-8?q?=EC=8A=A4=ED=8F=B0=20=EA=B4=80=EB=A0=A8=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EC=99=80=20=EC=8A=A4=ED=85=8C=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../So/RestaurantData/DataObjects.meta | 8 ++ .../DataObjects/RestaurantCustomerData.asset | 3 + .../RestaurantCustomerData.asset.meta | 8 ++ .../RestaurantManagementData.asset | 0 .../RestaurantManagementData.asset.meta | 0 .../DataObjects/RestaurantPlayerData.asset | 3 + .../RestaurantPlayerData.asset.meta | 0 .../DataObjects/RestaurantRunData.asset | 3 + .../DataObjects/RestaurantRunData.asset.meta | 8 ++ .../So/RestaurantData/RestaurantData.asset | 4 +- .../RestaurantData/RestaurantPlayerData.asset | 3 - .../Npc/RestaurantNpcCharacter.cs | 2 - .../RestaurantCharacter.cs | 3 + .../Conrtollers/RestaurantRunController.cs | 119 +++++++++++++++- .../Run/Customer/CustomerFactory.cs | 16 ++- .../RestaurantControllerDataSo.cs | 2 +- .../DataObjects/RestaurantCustomerData.cs | 14 ++ .../RestaurantCustomerData.cs.meta | 3 + .../DataObjects/RestaurantRunData.cs | 15 ++ .../DataObjects/RestaurantRunData.cs.meta | 3 + .../_Scripts/RestaurantData/RestaurantData.cs | 20 ++- .../FlowStates/RestaurantCustomerState.cs | 133 +----------------- .../FlowStates/RestaurantRunState.cs | 8 +- Assets/_DDD/_Scripts/Utilities/Constants.cs | 3 - 24 files changed, 228 insertions(+), 153 deletions(-) create mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/DataObjects.meta create mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset create mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset.meta rename Assets/_DDD/_Addressables/So/RestaurantData/{ => DataObjects}/RestaurantManagementData.asset (100%) rename Assets/_DDD/_Addressables/So/RestaurantData/{ => DataObjects}/RestaurantManagementData.asset.meta (100%) create mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset rename Assets/_DDD/_Addressables/So/RestaurantData/{ => DataObjects}/RestaurantPlayerData.asset.meta (100%) create mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset create mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset.meta delete mode 100644 Assets/_DDD/_Addressables/So/RestaurantData/RestaurantPlayerData.asset create mode 100644 Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs create mode 100644 Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs.meta create mode 100644 Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs create mode 100644 Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs.meta diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects.meta b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects.meta new file mode 100644 index 000000000..fddfdb010 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5775216947354447bf06ea842721c73 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset new file mode 100644 index 000000000..053325a24 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:601800b5bf452fefff7efc5b6e270a7f75ca3cd7250fe35997f2a79a285ed774 +size 574 diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset.meta b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset.meta new file mode 100644 index 000000000..fccebd601 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantCustomerData.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5e868658773b4297852eba8396d6f73 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantManagementData.asset b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantManagementData.asset similarity index 100% rename from Assets/_DDD/_Addressables/So/RestaurantData/RestaurantManagementData.asset rename to Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantManagementData.asset diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantManagementData.asset.meta b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantManagementData.asset.meta similarity index 100% rename from Assets/_DDD/_Addressables/So/RestaurantData/RestaurantManagementData.asset.meta rename to Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantManagementData.asset.meta diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset new file mode 100644 index 000000000..85efaff85 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49fc3b72bcb23f6bb08a7531c01cfd1fb185e04975122fd2437f751b3855ab78 +size 1994 diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantPlayerData.asset.meta b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset.meta similarity index 100% rename from Assets/_DDD/_Addressables/So/RestaurantData/RestaurantPlayerData.asset.meta rename to Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset.meta diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset new file mode 100644 index 000000000..94664be82 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2981a9ecdc5765312836b1bc82524078b1d1c27ae6ab2888eb11fe39d196496e +size 435 diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset.meta b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset.meta new file mode 100644 index 000000000..9aa982885 --- /dev/null +++ b/Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantRunData.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a335d9a9b913a4e8292845e8a6362dd9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantData.asset b/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantData.asset index 1738a474b..498e50543 100644 --- a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantData.asset +++ b/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantData.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f38d7227d17b6d46090e24c935f39c6f5187d8d53fbfedd1a29cf6f35dd1f82 -size 745 +oid sha256:9be63dcf48ddd1c88a27ab66e3820baf25ca134596ad4a21672b902c7899dce3 +size 1082 diff --git a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantPlayerData.asset b/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantPlayerData.asset deleted file mode 100644 index da1a7b9da..000000000 --- a/Assets/_DDD/_Addressables/So/RestaurantData/RestaurantPlayerData.asset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e0feba0ccb8fc9f02626e4858a5dd9323f0537d17e6eb48261decfa1a5b55eff -size 1994 diff --git a/Assets/_DDD/_Scripts/RestaurantCharacter/Npc/RestaurantNpcCharacter.cs b/Assets/_DDD/_Scripts/RestaurantCharacter/Npc/RestaurantNpcCharacter.cs index f84416c76..fd0cc2ddd 100644 --- a/Assets/_DDD/_Scripts/RestaurantCharacter/Npc/RestaurantNpcCharacter.cs +++ b/Assets/_DDD/_Scripts/RestaurantCharacter/Npc/RestaurantNpcCharacter.cs @@ -5,14 +5,12 @@ namespace DDD public class RestaurantNpcCharacter : RestaurantCharacter { protected BehaviorTree _behaviorTree; - protected SpineController _spineController; protected override void Awake() { base.Awake(); _behaviorTree = GetComponent(); - _spineController = GetComponent(); } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs b/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs index 8d4921018..f1fd7ee00 100644 --- a/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs +++ b/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs @@ -8,9 +8,12 @@ public class RestaurantCharacter : MonoBehaviour, IGameCharacter, IInteractor [EnumToggleButtons, SerializeField] protected InteractionType _interactionType; RestaurantCharacterInteraction _interactionComponent; + protected SpineController _spineController; + protected virtual void Awake() { _interactionComponent = GetComponent(); + _spineController = GetComponent(); } protected virtual void Start() diff --git a/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/RestaurantRunController.cs b/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/RestaurantRunController.cs index 5b48a8551..179f4a908 100644 --- a/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/RestaurantRunController.cs +++ b/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/RestaurantRunController.cs @@ -1,3 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; using System.Threading.Tasks; using UnityEngine; @@ -5,30 +9,133 @@ namespace DDD { public class RestaurantRunController : FlowController { - RestaurantCustomerState _restaurantCustomerStateSo; + private RestaurantCustomerState _restaurantCustomerStateSo; + private RestaurantRunState _restaurantRunStateSo; + private CancellationTokenSource _cts; + + // Runtime dependencies used by the execution logic + private LevelDataSo _levelDataSo; + private CustomerDataSo _customerDataSo; + private CustomerPoolDataSo _customerPoolDataSo; + private ICustomerFactory _iCustomerFactory; + private ISpawnPointProvider _spawnPointProvider; + + // Debug-only: last built schedule (kept in controller to keep State pure) + private SpawnSchedule _spawnSchedule; + public override Task InitializeController() { _restaurantCustomerStateSo = RestaurantState.Instance.CustomerState; + _restaurantRunStateSo = RestaurantState.Instance.RunState; return Task.CompletedTask; } public override Task InitializeState() { + _spawnPointProvider ??= new SpawnPointProvider(); + _restaurantRunStateSo.InitializeSpawnPoint(_spawnPointProvider.GetSpawnPoint()); return Task.CompletedTask; } public override async Task OnReadyNewFlow(GameFlowState newFlowState) { - var restaurantCustomerStateHandle = _restaurantCustomerStateSo.OnReadyNewFlow(newFlowState); - await Task.WhenAll(restaurantCustomerStateHandle); + if (newFlowState == GameFlowState.RunRestaurant) + { + _cts?.Cancel(); + _cts?.Dispose(); + _cts = new CancellationTokenSource(); + await StartSpawnLoopAsync(_cts.Token); + } } - public override async Task OnExitCurrentFlow(GameFlowState exitingFlowState) + + public override Task OnExitCurrentFlow(GameFlowState exitingFlowState) { if (exitingFlowState == GameFlowState.RunRestaurant) { - var restaurantCustomerStateHandle = _restaurantCustomerStateSo.OnExitCurrentFlow(exitingFlowState); - await Task.WhenAll(restaurantCustomerStateHandle); + _cts?.Cancel(); + _cts?.Dispose(); + _cts = null; } + return Task.CompletedTask; + } + + private async Task StartSpawnLoopAsync(CancellationToken token) + { + _iCustomerFactory ??= new CustomerFactory(); + + var currentGameLevel = GameState.Instance.LevelState.Level; + _levelDataSo ??= DataManager.Instance.GetDataSo(); + _customerDataSo ??= DataManager.Instance.GetDataSo(); + _customerPoolDataSo ??= DataManager.Instance.GetDataSo(); + + var currentLevelData = _levelDataSo.GetDataList().FirstOrDefault(data => data.Level == currentGameLevel); + Debug.Assert(currentLevelData != null, "currentLevelData is null"); + if (currentLevelData == null) return; // 안전 가드 + + var normalPool = _customerPoolDataSo.GetDataById(currentLevelData.CustomerPool); + var specialPool = _customerPoolDataSo.GetDataById(currentLevelData.SpecialCustomerPool); + + await RunSpawnLoopAsync(currentLevelData, normalPool, specialPool, token); + } + + private async Task RunSpawnLoopAsync(LevelData levelData, CustomerPoolData normalPool, CustomerPoolData specialPool, CancellationToken token) + { + var runData = RestaurantData.Instance? RestaurantData.Instance.RunData : null; + float firstDelay = Mathf.Max(0f, runData? runData.FirstSpawnDelaySeconds : 5f); + if (firstDelay > 0) + { + await Awaitable.WaitForSecondsAsync(firstDelay, token); + } + + var scheduleBuilder = CreateBuilder(levelData.SpawnType); + int randomSeed = Environment.TickCount; + + SpawnSchedule MakeSchedule() => scheduleBuilder.Build(new SpawnScheduleBuildArgs + { + NormalIds = (IReadOnlyList) (normalPool?.ValidCustomers) ?? Array.Empty(), + SpecialIds = (IReadOnlyList) (specialPool?.ValidCustomers) ?? Array.Empty(), + NormalQuota = Math.Max(0, normalPool?.CustomerLimitCount ?? 0), + SpecialQuota = Math.Max(0, specialPool?.CustomerLimitCount ?? 0), + Seed = ++randomSeed + }); + + _spawnSchedule = MakeSchedule(); + float wait = Mathf.Max(0.1f, levelData.CustomerRespawnTime); + + while (token.IsCancellationRequested == false) + { + if (Application.isPlaying == false) + { + break; + } + + if (_spawnSchedule.TryDequeue(out var customerId) == false) break; + + if (_customerDataSo.TryGetDataById(customerId, out var customerData)) + { + var rotation = Quaternion.identity; + + _ = _iCustomerFactory.CreateAsync(new CustomerSpawnArgs + { + CustomerData = customerData, + Position = _restaurantRunStateSo.SpawnPoint, + Rotation = rotation, + Parent = null + }); + } + + await Task.Delay(TimeSpan.FromSeconds(wait), token); + } + } + + private static ISpawnScheduleBuilder CreateBuilder(SpawnType type) + { + return type switch + { + SpawnType.Random => new RandomSpawnScheduleBuilder(), + SpawnType.Regular => new RegularSpawnScheduleBuilder(), + _ => new RandomSpawnScheduleBuilder() + }; } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs b/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs index 9c826efb0..d69b62862 100644 --- a/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs +++ b/Assets/_DDD/_Scripts/RestaurantController/Conrtollers/Run/Customer/CustomerFactory.cs @@ -29,7 +29,21 @@ public async Task CreateAsync(CustomerSpawnArgs args) { if (!_customerPrefab) { - _customerPrefab = await AssetManager.LoadAsset(DataConstants.CustomerNpcPrefab); + var customerDataAsset = RestaurantData.Instance ? RestaurantData.Instance.CustomerData : null; + if (customerDataAsset == null || customerDataAsset.CustomerPrefab == null) + { + Debug.LogError("[CustomerFactory] RestaurantCustomerData or its CustomerPrefab reference is not set or not loaded."); + return null; + } + + var handle = customerDataAsset.CustomerPrefab.LoadAssetAsync(); + await handle.Task; + if (handle.Result == null) + { + Debug.LogError("[CustomerFactory] Failed to load customer prefab from AssetReference."); + return null; + } + _customerPrefab = handle.Result; } var newCustomer = Object.Instantiate(_customerPrefab, args.Position, args.Rotation, args.Parent); diff --git a/Assets/_DDD/_Scripts/RestaurantController/RestaurantControllerDataSo.cs b/Assets/_DDD/_Scripts/RestaurantController/RestaurantControllerDataSo.cs index d97179751..632ab5eec 100644 --- a/Assets/_DDD/_Scripts/RestaurantController/RestaurantControllerDataSo.cs +++ b/Assets/_DDD/_Scripts/RestaurantController/RestaurantControllerDataSo.cs @@ -2,7 +2,7 @@ namespace DDD { - [CreateAssetMenu(fileName = "RestaurantControllerData", menuName = "ScriptableObjects/RestaurantControllerData", order = 0)] + [CreateAssetMenu(fileName = "RestaurantControllerData", menuName = "RestaurantData/RestaurantControllerData", order = 0)] public class RestaurantControllerDataSo : ScriptableObject { diff --git a/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs new file mode 100644 index 000000000..4dd0e2bd8 --- /dev/null +++ b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs @@ -0,0 +1,14 @@ +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.ResourceProviders; + +namespace DDD +{ + [CreateAssetMenu(fileName = "RestaurantCustomerData", menuName = "RestaurantData/RestaurantCustomerData", order = 0)] + public class RestaurantCustomerData : ScriptableObject + { + [SerializeField] private AssetReferenceGameObject _customerPrefab; + + public AssetReferenceGameObject CustomerPrefab => _customerPrefab; + } +} diff --git a/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs.meta b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs.meta new file mode 100644 index 000000000..09853cec0 --- /dev/null +++ b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantCustomerData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3e9cf283e323467ea2e67b94905fbfcd +timeCreated: 1755587223 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs new file mode 100644 index 000000000..3e109e460 --- /dev/null +++ b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs @@ -0,0 +1,15 @@ +using Sirenix.OdinInspector; +using UnityEngine; + +namespace DDD +{ + [CreateAssetMenu(fileName = "RestaurantRunData", menuName = "RestaurantData/RestaurantRunData")] + public class RestaurantRunData : ScriptableObject + { + [Title("스폰 제어 (Persistent Data)")] + [Tooltip("플로우 시작 후 첫 손님이 등장하기까지 대기 시간(초)")] + [SerializeField] private float _firstSpawnDelaySeconds = 5f; + + public float FirstSpawnDelaySeconds => _firstSpawnDelaySeconds; + } +} diff --git a/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs.meta b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs.meta new file mode 100644 index 000000000..432dc9a05 --- /dev/null +++ b/Assets/_DDD/_Scripts/RestaurantData/DataObjects/RestaurantRunData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d0a7d53d11af4847860694610b3138f2 +timeCreated: 1755583002 \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs b/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs index 3f8892c30..2c484bdb8 100644 --- a/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs +++ b/Assets/_DDD/_Scripts/RestaurantData/RestaurantData.cs @@ -9,9 +9,13 @@ public class RestaurantData : ScriptSingleton { [SerializeField] private AssetReference _restaurantPlayerData; [SerializeField] private AssetReference _restaurantManagementData; + [SerializeField] private AssetReference _restaurantRunData; + [SerializeField] private AssetReference _restaurantCustomerData; public RestaurantPlayerData PlayerData { get; private set; } public RestaurantManagementData ManagementData { get; private set; } + public RestaurantRunData RunData { get; private set; } + public RestaurantCustomerData CustomerData { get; private set; } private bool _isLoaded; @@ -24,15 +28,25 @@ public async Task LoadData() var restaurantPlayerDataHandle = _restaurantPlayerData.LoadAssetAsync(); var restaurantManagementDataHandle = _restaurantManagementData.LoadAssetAsync(); + var restaurantRunDataHandle = _restaurantRunData.LoadAssetAsync(); + var restaurantCustomerDataHandle = _restaurantCustomerData.LoadAssetAsync(); - await restaurantPlayerDataHandle.Task; - await restaurantManagementDataHandle.Task; + 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"); _isLoaded = true; } @@ -43,6 +57,8 @@ private void OnDisable() _restaurantPlayerData.ReleaseAsset(); _restaurantManagementData.ReleaseAsset(); + _restaurantRunData.ReleaseAsset(); + _restaurantCustomerData.ReleaseAsset(); _isLoaded = false; } diff --git a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs index 26daa3568..0c326a38b 100644 --- a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs +++ b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantCustomerState.cs @@ -1,140 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Sirenix.OdinInspector; using UnityEngine; namespace DDD { - public class RestaurantCustomerState : ScriptableObject, IGameFlowHandler + public class RestaurantCustomerState : ScriptableObject { - [Title("스폰 제어")] - [Tooltip("플로우 시작 후 첫 손님이 등장하기까지 대기 시간(초)")] - [SerializeField] private float _firstSpawnDelaySeconds = 5f; - - [SerializeField] private Vector3 _spawnPoint = new(5f, 0f, 4f); - - [Title("디버그")] - [ReadOnly, SerializeField] private SpawnSchedule _spawnSchedule; - - private LevelDataSo _levelDataSo; - private CustomerDataSo _customerDataSo; - private CustomerPoolDataSo _customerPoolDataSo; - - private ICustomerFactory _iCustomerFactory; - - private CancellationTokenSource _spawnLoopCancellationTokenSource; - - public async Task OnReadyNewFlow(GameFlowState newFlowState) - { - if (newFlowState == GameFlowState.RunRestaurant) - { - await InitializeRunRestaurant(); - } - } - - public Task OnExitCurrentFlow(GameFlowState exitingFlowState) - { - if (exitingFlowState == GameFlowState.RunRestaurant) - { - _spawnLoopCancellationTokenSource?.Cancel(); - _spawnLoopCancellationTokenSource?.Dispose(); - _spawnLoopCancellationTokenSource = null; - } - - return Task.CompletedTask; - } - - private async Task InitializeRunRestaurant() - { - _iCustomerFactory = new CustomerFactory(); - - var currentGameLevel = GameState.Instance.LevelState.Level; - if (_levelDataSo == null) - { - _levelDataSo = DataManager.Instance.GetDataSo(); - } - if (_customerDataSo == null) - { - _customerDataSo = DataManager.Instance.GetDataSo(); - } - if (_customerPoolDataSo == null) - { - _customerPoolDataSo = DataManager.Instance.GetDataSo(); - } - var currentLevelData = _levelDataSo.GetDataList().FirstOrDefault(data => data.Level == currentGameLevel); - - Debug.Assert(currentLevelData != null, "currentLevelData is null"); - - var normalPool = _customerPoolDataSo.GetDataById(currentLevelData.CustomerPool); - var specialPool = _customerPoolDataSo.GetDataById(currentLevelData.SpecialCustomerPool); - - _spawnLoopCancellationTokenSource?.Cancel(); - _spawnLoopCancellationTokenSource = new CancellationTokenSource(); - await RunSpawnLoopAsync(currentLevelData, normalPool, specialPool, _spawnLoopCancellationTokenSource.Token); - } - - private async Task RunSpawnLoopAsync(LevelData levelData, CustomerPoolData normalPool, CustomerPoolData specialPool, CancellationToken token) - { - if (_firstSpawnDelaySeconds > 0) - { - await Awaitable.WaitForSecondsAsync(_firstSpawnDelaySeconds, token); - } - - var scheduleBuilder = CreateBuilder(levelData.SpawnType); - int randomSeed = Environment.TickCount; - - SpawnSchedule MakeSchedule() => scheduleBuilder.Build(new SpawnScheduleBuildArgs - { - NormalIds = (IReadOnlyList) (normalPool?.ValidCustomers) ?? Array.Empty(), - SpecialIds = (IReadOnlyList) (specialPool?.ValidCustomers) ?? Array.Empty(), - NormalQuota = Math.Max(0, normalPool?.CustomerLimitCount ?? 0), - SpecialQuota = Math.Max(0, specialPool?.CustomerLimitCount ?? 0), - Seed = ++randomSeed - }); - - _spawnSchedule = MakeSchedule(); - float wait = Mathf.Max(0.1f, levelData.CustomerRespawnTime); - - while (token.IsCancellationRequested == false) - { - if (Application.isPlaying == false) - { - _spawnLoopCancellationTokenSource?.Cancel(); - _spawnLoopCancellationTokenSource?.Dispose(); - _spawnLoopCancellationTokenSource = null; - break; - } - - if (_spawnSchedule.TryDequeue(out var customerId) == false) break; - - if (_customerDataSo.TryGetDataById(customerId, out var customerData)) - { - var rotation = Quaternion.identity; - - _ = _iCustomerFactory.CreateAsync(new CustomerSpawnArgs - { - CustomerData = customerData, - Position = _spawnPoint, - Rotation = rotation, - Parent = null - }); - } - - await Task.Delay(TimeSpan.FromSeconds(wait), token); - } - } - - private ISpawnScheduleBuilder CreateBuilder(SpawnType type) - { - return type switch - { - SpawnType.Random => new RandomSpawnScheduleBuilder(), - SpawnType.Regular => new RegularSpawnScheduleBuilder(), - _ => new RandomSpawnScheduleBuilder() - }; - } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantRunState.cs b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantRunState.cs index 7f730ffcc..e0dafce35 100644 --- a/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantRunState.cs +++ b/Assets/_DDD/_Scripts/RestaurantState/FlowStates/RestaurantRunState.cs @@ -4,6 +4,12 @@ namespace DDD { public class RestaurantRunState : ScriptableObject { - + private Vector3 _spawnPoint = new(5f, 0f, 4f); + public Vector3 SpawnPoint => _spawnPoint; + + public void InitializeSpawnPoint(Vector3 spawnPoint) + { + _spawnPoint = spawnPoint; + } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/Utilities/Constants.cs b/Assets/_DDD/_Scripts/Utilities/Constants.cs index b383b9120..7f438dcd7 100644 --- a/Assets/_DDD/_Scripts/Utilities/Constants.cs +++ b/Assets/_DDD/_Scripts/Utilities/Constants.cs @@ -23,7 +23,6 @@ public static class DataConstants public const string TasteDataSo = "TasteDataSo"; public const string EnvironmentDataSo = "EnvironmentDataSo"; public const string LevelDataSo = "LevelDataSo"; - public const string CustomerDataSo = "CustomerDataSo"; public const string CustomerPoolDataSo = "CustomerPoolDataSo"; public const string UiInputBindingSo = "UiInputBindingSo"; @@ -31,8 +30,6 @@ public static class DataConstants public const string AtlasLabel = "Atlas"; public const string BasePropSpriteMaterial = "BasePropSpriteMaterial"; - - public const string CustomerNpcPrefab = "CustomerNpc"; } public static class RestaurantPlayerAnimationType