인벤토리 및 ui 로직 변경

This commit is contained in:
NTG_Lenovo 2025-08-06 15:02:37 +09:00
parent ec6afcd2ae
commit 2084bbcb32
5 changed files with 123 additions and 49 deletions

View File

@ -6,11 +6,20 @@
namespace DDD
{
public enum InventorySortType
{
None = 0,
NameAscending,
NameDescending,
QuantityAscending,
QuantityDescending
}
public class InventoryManager : Singleton<InventoryManager>, IManager
{
[Title("아이템 전체 목록")]
[ShowInInspector, ReadOnly]
private Dictionary<string, ItemData> _itemDataLookup;
private Dictionary<string, ItemData> _allItemDataLookup;
[Title("아이템 보유 목록")]
[ShowInInspector, ReadOnly]
@ -41,7 +50,7 @@ private void InitializeItemData()
var itemDataSo = DataManager.Instance.GetDataSo<ItemDataSo>();
Debug.Assert(itemDataSo != null, "itemDataSo != null");
_itemDataLookup = itemDataSo.GetDataList()
_allItemDataLookup = itemDataSo.GetDataList()
.Where(item => !string.IsNullOrEmpty(item.Id))
.ToDictionary(item => item.Id, item => item);
@ -72,7 +81,7 @@ private async void ApplyEditorTestData()
public bool AddItem(string id, int quantity = 1)
{
if (!_itemDataLookup.ContainsKey(id))
if (!_allItemDataLookup.ContainsKey(id))
{
Debug.LogError($"[Inventory] 등록되지 않은 아이템 ID: {id}");
return false;
@ -123,12 +132,14 @@ public bool RemoveItem(string id, int quantity = 1)
return true;
}
public IReadOnlyDictionary<string, ItemData> AllItemDataLookup => _allItemDataLookup;
public IReadOnlyDictionary<string, InventoryItemData> InventoryItems => _inventoryItemDatas;
public bool TryGetItemData(string id, out ItemData itemData) => _itemDataLookup.TryGetValue(id, out itemData);
public bool ContainInventoryItem(string id) => _inventoryItemDatas.ContainsKey(id);
public bool TryGetInventoryItemData(string id, out InventoryItemData inventoryItemData) => _inventoryItemDatas.TryGetValue(id, out inventoryItemData);
public int GetItemCount(string id) => _inventoryItemDatas.TryGetValue(id, out var itemData) ? itemData.Quantity : 0;
public ItemData GetItemDataByIdOrNull(string id)
{
_itemDataLookup.TryGetValue(id, out var itemData);
_allItemDataLookup.TryGetValue(id, out var itemData);
return itemData;
}
}

View File

@ -9,10 +9,33 @@ public class InventorySlotUiStrategy : IItemSlotUiStrategy
public void Setup(ItemSlotUi ui, ItemViewModel model)
{
ui.SetIcon(model.ItemSprite);
ui.ShowCountText();
if (InventoryManager.Instance.ContainInventoryItem(model.Id))
{
ui.SetIcon(model.ItemSprite);
ui.ShowCountText();
ui.HideMark();
ui.SetButtonInteractable(true);
return;
}
// TODO : 임시 초기화 값
string emptySpriteKey = SpriteConstants.EmptyFoodSpriteKey;
if (model.ItemType == ItemType.Recipe)
{
if (model.RecipeType == RecipeType.FoodRecipe)
{
emptySpriteKey = SpriteConstants.EmptyFoodSpriteKey;
}
else if (model.RecipeType == RecipeType.DrinkRecipe)
{
emptySpriteKey = SpriteConstants.EmptyDrinkSpriteKey;
}
}
ui.SetIcon(DataManager.Instance.GetSprite(emptySpriteKey));
ui.HideCountText();
ui.HideMark();
ui.SetButtonInteractable(true);
ui.SetButtonInteractable(false);
}
public async Task<RuntimeAnimatorController> GetAnimatorController()
@ -22,10 +45,12 @@ public async Task<RuntimeAnimatorController> GetAnimatorController()
public void OnInventoryChanged(ItemSlotUi ui)
{
if (ui.Model == null) return;
ui.Model.UpdateCount();
ui.ShowCountText();
var model = ui.Model;
if (InventoryManager.Instance.ContainInventoryItem(model.Id))
{
ui.Model.UpdateCount();
ui.ShowCountText();
}
}
public bool CanCrafting(ItemSlotUi ui)

View File

@ -1,23 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace DDD
{
public class InventoryView : MonoBehaviour, IEventHandler<InventoryChangedEvent>, IEventHandler<TodayMenuAddedEvent>, IEventHandler<TodayMenuRemovedEvent>
public class InventoryView : MonoBehaviour, IEventHandler<InventoryChangedEvent>,
IEventHandler<TodayMenuAddedEvent>, IEventHandler<TodayMenuRemovedEvent>
{
[SerializeField] private Transform _slotParent;
private RestaurantManagementSo _restaurantManagementSo;
private InventoryCategoryType _currenInventoryCategoryType = InventoryCategoryType.Food;
private readonly Dictionary<string, ItemSlotUi> _slotLookup = new();
private GameObject _firstSlot;
private InventorySortType _currentSortType = InventorySortType.None;
private const string ItemSlotUiName = "ItemSlotUi_";
private void OnEnable()
{
EventBus.Register<InventoryChangedEvent>(this);
@ -31,13 +32,15 @@ private void OnDisable()
EventBus.Unregister<TodayMenuAddedEvent>(this);
EventBus.Unregister<TodayMenuRemovedEvent>(this);
}
public GameObject GetInitialSelected() => _firstSlot;
public async Task Initialize()
{
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
_restaurantManagementSo =
await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
Debug.Assert(_restaurantManagementSo != null, "_todayMenuDataSo != null");
Clear();
var models = ItemViewModelFactory.CreateRestaurantManagementInventoryItem();
@ -66,51 +69,79 @@ public async Task Initialize()
_slotLookup[model.Id] = slot;
}
}
public void SetSortType(InventorySortType sortType)
{
_currentSortType = sortType;
UpdateView();
}
private IEnumerable<ItemSlotUi> SortSlots(IEnumerable<ItemSlotUi> slots)
{
return _currentSortType switch
{
InventorySortType.NameAscending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenBy(slot => slot.Model.DisplayName),
InventorySortType.NameDescending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenByDescending(slot => slot.Model.DisplayName),
InventorySortType.QuantityAscending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenBy(slot => slot.Model.Count),
InventorySortType.QuantityDescending => slots.OrderByDescending(slot => slot.Model.HasItem).ThenByDescending(slot => slot.Model.Count),
InventorySortType.None => slots.OrderBy(slot => slot.Model.Id),
_ => slots
};
}
public void UpdateCategoryView(InventoryCategoryType category)
{
_currenInventoryCategoryType = category;
_firstSlot = null;
foreach (var kvp in _slotLookup)
var filteredSlots = _slotLookup.Values;
var sortedSlots = SortSlots(filteredSlots);
int siblingIndex = 0;
foreach (var slot in sortedSlots)
{
var id = kvp.Key;
var slot = kvp.Value;
var model = slot.Model;
string id = model.Id;
// 1. 오늘의 메뉴에 등록된 경우 필터링
bool isRegisteredTodayMenu = model.ItemType == ItemType.Recipe && _restaurantManagementSo.IsContainTodayMenu(id);
// 2. 현재 선택된 카테고리에 맞는지 필터링
bool matchCategory = MatchesCategory(model, _currenInventoryCategoryType);
// 3. 조건을 모두 만족할 경우만 활성화
bool shouldShow = !isRegisteredTodayMenu && matchCategory;
slot.SetActive(shouldShow);
if (shouldShow && _firstSlot == null)
if (shouldShow && model.HasItem)
{
_firstSlot = slot.gameObject;
slot.transform.SetSiblingIndex(siblingIndex++);
if (_firstSlot == null)
{
_firstSlot = slot.gameObject;
}
}
}
}
private bool MatchesCategory(ItemViewModel model, InventoryCategoryType category)
{
switch (category)
{
case InventoryCategoryType.Food:
if (model.ItemType != ItemType.Recipe) return false;
return DataManager.Instance.GetDataSo<RecipeDataSo>().TryGetDataById(model.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe;
return DataManager.Instance.GetDataSo<RecipeDataSo>()
.TryGetDataById(model.Id, out var foodRecipe) && foodRecipe.RecipeType == RecipeType.FoodRecipe;
case InventoryCategoryType.Drink:
if (model.ItemType != ItemType.Recipe) return false;
return DataManager.Instance.GetDataSo<RecipeDataSo>().TryGetDataById(model.Id, out var drinkRecipe) && drinkRecipe.RecipeType == RecipeType.DrinkRecipe;
return DataManager.Instance.GetDataSo<RecipeDataSo>()
.TryGetDataById(model.Id, out var drinkRecipe) &&
drinkRecipe.RecipeType == RecipeType.DrinkRecipe;
case InventoryCategoryType.Ingredient:
return model.ItemType == ItemType.Ingredient;
case InventoryCategoryType.Cookware:
return DataManager.Instance.GetDataSo<CookwareDataSo>().TryGetDataById(model.Id, out var cookwareData);
return DataManager.Instance.GetDataSo<CookwareDataSo>()
.TryGetDataById(model.Id, out var cookwareData);
case InventoryCategoryType.Special:
return false;
default:

View File

@ -25,6 +25,8 @@ public ItemViewModel(string id, ItemType itemType)
Count = 0;
}
public bool HasItem => Count > 0;
public string DisplayName => LocalizationManager.Instance.GetName(Id);
public RecipeType RecipeType => ItemType == ItemType.Recipe ? DataManager.Instance.GetDataSo<RecipeDataSo>().GetDataById(Id).RecipeType : RecipeType.None;
public Sprite ItemSprite
{

View File

@ -7,18 +7,23 @@ public static class ItemViewModelFactory
public static List<ItemViewModel> CreateRestaurantManagementInventoryItem()
{
var result = new List<ItemViewModel>();
foreach (var kvp in InventoryManager.Instance.InventoryItems)
var allItemDataLookup = InventoryManager.Instance.AllItemDataLookup;
foreach (var keyItemDataPair in allItemDataLookup)
{
var id = kvp.Key;
var item = InventoryManager.Instance.GetItemDataByIdOrNull(id);
if (item == null) continue;
var id = keyItemDataPair.Key;
var itemData = keyItemDataPair.Value;
var modelCount = item.ItemType switch
int modelCount = 0;
if (InventoryManager.Instance.ContainInventoryItem(id))
{
ItemType.Recipe => CalculateCraftableCount(item.Id),
_ => InventoryManager.Instance.GetItemCount(id)
};
var model = new ItemViewModel(item.Id, item.ItemType, modelCount);
modelCount = itemData.ItemType switch
{
ItemType.Recipe => CalculateCraftableCount(itemData.Id),
_ => InventoryManager.Instance.GetItemCount(id)
};
}
var model = new ItemViewModel(id, itemData.ItemType, modelCount);
result.Add(model);
}