141 lines
5.5 KiB
C#
141 lines
5.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
|
|
namespace DDD
|
|
{
|
|
public class RestaurantRunController : FlowController
|
|
{
|
|
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)
|
|
{
|
|
if (newFlowState == GameFlowState.RunRestaurant)
|
|
{
|
|
_cts?.Cancel();
|
|
_cts?.Dispose();
|
|
_cts = new CancellationTokenSource();
|
|
await StartSpawnLoopAsync(_cts.Token);
|
|
}
|
|
}
|
|
|
|
public override Task OnExitCurrentFlow(GameFlowState exitingFlowState)
|
|
{
|
|
if (exitingFlowState == GameFlowState.RunRestaurant)
|
|
{
|
|
_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<LevelDataSo>();
|
|
_customerDataSo ??= DataManager.Instance.GetDataSo<CustomerDataSo>();
|
|
_customerPoolDataSo ??= DataManager.Instance.GetDataSo<CustomerPoolDataSo>();
|
|
|
|
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<string>) (normalPool?.ValidCustomers) ?? Array.Empty<string>(),
|
|
SpecialIds = (IReadOnlyList<string>) (specialPool?.ValidCustomers) ?? Array.Empty<string>(),
|
|
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()
|
|
};
|
|
}
|
|
}
|
|
} |