using System; using System.Collections; using System.Collections.Generic; using System.Linq; using DDD.Audios; using DDD.Interfaces; using DDD.Npcs.Customers; using DDD.ScriptableObjects; using DDD.Utility; using Sirenix.OdinInspector; using UnityEngine; using Random = UnityEngine.Random; namespace DDD.Tycoons { [Serializable] public class RoundSkinData { [field: SerializeField] public int MinRound { get; private set; } [field: SerializeField] public List Skins { get; private set; } = new(); } public class CustomerController : MonoBehaviour { [Title("손님 데이터")] [SerializeField, Required] private Customer _customerPrefab; [SerializeField, Required] private Transform _customerSpawnTransform; [SerializeField] private string _createCustomerSfxName = "CreateCustomer"; [Title("라운드별 스킨 데이터")] [SerializeField] private List _roundSkinData = new(); [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 int _instanceCount; private void Start() { _customerTableController = TycoonManager.Instance.CustomerTableController; EventManager.OnCreateCustomer += TryFindEmptySeat; EventManager.OnDestroyCustomer += UnregisterCustomer; } private void OnDestroy() { EventManager.OnCreateCustomer -= TryFindEmptySeat; EventManager.OnDestroyCustomer -= UnregisterCustomer; } public Customer CreateCustomer() { var currentLevelData = TycoonManager.Instance.GetCurrentLevelData(); //List randomSkins = GetSkins(); var newCustomer = Instantiate(_customerPrefab, _customerSpawnTransform.position, Quaternion.identity); newCustomer.Initialize(currentLevelData, _customerSpawnTransform, null); newCustomer.gameObject.name = $"Customer (Clone) {_instanceCount}"; _instanceCount++; RegisterCustomer(newCustomer); AudioManager.Instance.PlaySfx(_createCustomerSfxName); 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 Customer FindCustomerMatchingItem(CraftRecipeData servingTableItem) { foreach (var element in InstanceCustomers) { if (!element || element.IsReceivedItem || element.IsMatchedServer) continue; if (servingTableItem.Idx != element.OrderedCraftRecipeData.Idx || servingTableItem.CraftingToolQueue.Count > 0) continue; return element; } return null; } public int OrderedCocktailCount(string cocktailDataIdx) { return InstanceCustomers.Count(element => element.IsOrderedCocktail() && element.OrderedCocktailData.Idx == cocktailDataIdx); } public List GetSkins() { int currentRound = int.Parse(TycoonManager.Instance.GetCurrentLevelData().Idx); foreach (var data in _roundSkinData.Where(data => currentRound >= data.MinRound)) { return data.Skins; } return new List { "default" }; } } }