using System; using System.Collections; using System.Collections.Generic; using System.Linq; using BlueWater.Npcs.Customers; using BlueWater.Utility; using Sirenix.OdinInspector; using UnityEngine; using Random = UnityEngine.Random; namespace BlueWater.Tycoons { public class CustomerManager : Singleton { [Title("손님 데이터")] [field: SerializeField, Required] public CustomerDataSo CustomerDataSo { get; private set; } [SerializeField, Required] private Customer _customerPrefab; [SerializeField, Required] private Transform _customerSpawnTransform; [Title("대기중인 손님 정보")] [SerializeField] private float _checkEmptySeatInterval = 0.5f; [field: SerializeField] public List InstanceCustomers { get; private set; } = new(); [ShowInInspector] private Queue _waitingCustomers = new(); private CustomerTableController _customerTableController; private Coroutine _findEmptySeatCoroutineInstance; private void Start() { _customerTableController = TycoonManager.Instance.CustomerTableController; EventManager.OnCreateCustomer += TryFindEmptySeat; } private void OnDestroy() { EventManager.OnCreateCustomer -= TryFindEmptySeat; } public Customer CreateCustomer() { var currentLevelData = TycoonManager.Instance.GetCurrentLevelData(); var newCustomer = Instantiate(_customerPrefab, _customerSpawnTransform.position, Quaternion.identity); newCustomer.Initialize(currentLevelData); RegisterCustomer(newCustomer); return newCustomer; } public void TryFindEmptySeat() { // 1. 빈 자리를 체크한다. (빈 자리가 있다면 생성) // 2. 빈 자리가 없는 경우, Queue에 대기 손님을 넣고 빈 자리가 생길 때 생성 // 3. 생성하는 순간에 레벨 data 참조 // 이미 대기열에 사람들이 있는 경우, 새로운 손님도 바로 대기열에 넣는다. if (_waitingCustomers.Count > 0) { _waitingCustomers.Enqueue(1); return; } // 대기열에는 아무도 없는 경우 var emptySeat = _customerTableController.FindEmptySeat(); if (emptySeat == null) { // 내가 첫 대기열 손님이 된다. _waitingCustomers.Enqueue(1); Utils.StartUniqueCoroutine(this, ref _findEmptySeatCoroutineInstance, CheckEmptySeatCoroutine()); return; } var newCustomer = CreateCustomer(); newCustomer.SetTableSeat(emptySeat); emptySeat.ReserveSeat(); newCustomer.AIMovement.Move(emptySeat.SeatTransform.position); } private IEnumerator CheckEmptySeatCoroutine() { var checkEmptySeatInterval = new WaitForSeconds(_checkEmptySeatInterval); while (_waitingCustomers.Count > 0) { var emptySeat = _customerTableController.FindEmptySeat(); if (emptySeat != null) { _waitingCustomers.Dequeue(); var customer = CreateCustomer(); customer.SetTableSeat(emptySeat); emptySeat.ReserveSeat(); customer.AIMovement.Move(emptySeat.SeatTransform.position); continue; } yield return checkEmptySeatInterval; } _findEmptySeatCoroutineInstance = null; } public void RegisterCustomer(Customer customer) { Utils.RegisterList(InstanceCustomers, customer); } public void UnregisterCustomer(Customer customer) { Utils.UnregisterList(InstanceCustomers, customer); } public CustomerData GetRandomCustomerData() { var customerDataCount = CustomerDataSo.GetDataCount(); if (customerDataCount == 0) { Debug.LogError($"{CustomerDataSo}의 값이 비어있습니다."); return null; } return CustomerDataSo.GetRandomValue(); } public List GetCurrentCustomers() => InstanceCustomers; } }