RestaurantController 구조 변경, State/Data 분리, 단일 RestaurantDataSo 및 RestaurantStateSo 인스턴스 생성

This commit is contained in:
Jeonghyeon Ha 2025-08-14 20:35:16 +09:00
parent 0687587483
commit 2d48d1b603
83 changed files with 565 additions and 243 deletions

View File

@ -98,5 +98,5 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
_interactionType: 2
_holdTime: 1.3
_holdTime: 0
_interactionMessageKey: Test

View File

@ -74,7 +74,6 @@ PrefabInstance:
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
insertIndex: -1
addedObject: {fileID: 2285326470091144097}
addedObject: {fileID: 8104602334973352575}
m_SourcePrefab: {fileID: 100100000, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
--- !u!1 &580268897300907643 stripped
@ -82,7 +81,6 @@ GameObject:
m_CorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
m_PrefabInstance: {fileID: 3861763275173960190}
m_PrefabAsset: {fileID: 0}
--- !u!114 &2285326470091144097
--- !u!114 &8104602334973352575
MonoBehaviour:
m_ObjectHideFlags: 0
@ -96,5 +94,5 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
_interactionType: 1
_holdTime: 1
_holdTime: 0
_interactionMessageKey: Test

BIN
Assets/_DDD/_Addressables/So/RestaurantDataSo.asset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c702efebbff4144429b6f07cf841bc42
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -2390,7 +2390,7 @@ MonoBehaviour:
_menuCategoryTabs: {fileID: 8937672504025748459}
_cookwareCategoryTabs: {fileID: 195952124745473889}
_completeBatchFilledImage: {fileID: 4012160685168048845}
_holdCompleteTime: 1
_holdCompleteTime: 10
--- !u!225 &1368992355976611131
CanvasGroup:
m_ObjectHideFlags: 0

View File

@ -10,7 +10,8 @@ public class InventoryView : MonoBehaviour, IEventHandler<InventoryChangedEvent>
{
[SerializeField] private Transform _slotParent;
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementDataSo restaurantManagementDataSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
private InventoryCategoryType _currenInventoryCategoryType = InventoryCategoryType.Food;
private readonly Dictionary<string, ItemSlotUi> _slotLookup = new();
@ -37,9 +38,9 @@ private void OnDisable()
public async Task Initialize()
{
_restaurantManagementSo =
await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
Debug.Assert(_restaurantManagementSo != null, "_todayMenuDataSo != null");
restaurantManagementStateSo = RestaurantState.instance.ManagementState;
restaurantManagementDataSo = RestaurantDataSo.instance.ManagementData;
Debug.Assert(restaurantManagementDataSo != null, "_todayMenuDataSo != null");
Clear();
@ -48,7 +49,7 @@ public async Task Initialize()
_slotLookup.Clear();
foreach (var model in models)
{
var itemSlotUi = Instantiate(_restaurantManagementSo.ItemSlotUiPrefab, _slotParent);
var itemSlotUi = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _slotParent);
var slot = itemSlotUi.GetComponent<ItemSlotUi>();
await slot.Initialize(model, new InventorySlotUiStrategy());
itemSlotUi.name = ItemSlotUiName + model.Id;
@ -104,7 +105,7 @@ public void UpdateCategoryView(InventoryCategoryType category)
var model = slot.Model;
string id = model.Id;
bool isRegisteredTodayMenu = model.ItemType == ItemType.Recipe && _restaurantManagementSo.IsContainTodayMenu(id);
bool isRegisteredTodayMenu = model.ItemType == ItemType.Recipe && restaurantManagementStateSo.IsContainTodayMenu(id);
bool matchCategory = MatchesCategory(model, _currenInventoryCategoryType);
bool shouldShow = !isRegisteredTodayMenu && matchCategory;

View File

@ -22,7 +22,9 @@ public class ItemDetailView : MonoBehaviour, IEventHandler<ItemSlotSelectedEvent
[SerializeField] private HorizontalLayoutGroup _tasteHashTagContentLayoutGroup;
[SerializeField] private RectTransform _tasteHashTagContent2;
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementDataSo restaurantManagementDataSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
private List<TasteHashTagSlotUi> _tasteHashTagSlotUis = new();
private ItemViewModel _currentItemViewModel;
private TaskCompletionSource<bool> _isInitialized = new();
@ -33,8 +35,10 @@ public class ItemDetailView : MonoBehaviour, IEventHandler<ItemSlotSelectedEvent
private async void Start()
{
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
Debug.Assert(_restaurantManagementSo != null, "RestaurantManagementSo is null");
restaurantManagementDataSo = RestaurantDataSo.instance.ManagementData;
restaurantManagementStateSo = RestaurantState.instance.ManagementState;
Debug.Assert(restaurantManagementDataSo != null, "RestaurantManagementSo is null");
Debug.Assert(restaurantManagementStateSo != null, "RestaurantManagementSo is null");
_nameLabel.text = string.Empty;
_descriptionLabel.text = string.Empty;
@ -94,8 +98,8 @@ private void UpdateTasteHashTags(ItemViewModel model)
var outlineColor = model.RecipeType switch
{
RecipeType.FoodRecipe => _restaurantManagementSo.FoodTasteOutlineColor,
RecipeType.DrinkRecipe => _restaurantManagementSo.DrinkTasteOutlineColor,
RecipeType.FoodRecipe => restaurantManagementDataSo.FoodTasteOutlineColor,
RecipeType.DrinkRecipe => restaurantManagementDataSo.DrinkTasteOutlineColor,
_ => throw new ArgumentOutOfRangeException()
};
@ -104,7 +108,7 @@ private void UpdateTasteHashTags(ItemViewModel model)
foreach (var tasteData in tasteDatas)
{
var newTasteHashTag = Instantiate(_restaurantManagementSo.TasteHashTagSlotUiPrefab, _tasteHashTagContent1, false);
var newTasteHashTag = Instantiate(restaurantManagementDataSo.TasteHashTagSlotUiPrefab, _tasteHashTagContent1, false);
newTasteHashTag.Initialize(outlineColor, tasteData);
LayoutRebuilder.ForceRebuildLayoutImmediate(newTasteHashTag.RectTransform);

View File

@ -2,7 +2,7 @@ namespace DDD
{
public interface IItemSlotInteractorStrategy
{
void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantManagementSo);
void OnRemoved(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantManagementSo);
void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementStateSo restaurantManagementStateSo);
void OnRemoved(ItemSlotUi itemSlotUi, RestaurantManagementStateSo restaurantManagementStateSo);
}
}

View File

@ -15,7 +15,7 @@ public enum TodayMenuEventType
public class ItemSlotInteractor : MonoBehaviour, IInteractableUi
{
private ItemSlotUi _itemSlotUi;
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
private TaskCompletionSource<bool> _isInitialized = new();
private TodayMenuEventType _todayMenuEventType = TodayMenuEventType.None;
@ -30,8 +30,8 @@ public async Task Initialize(TodayMenuEventType todayMenuEventType, IItemSlotInt
{
_todayMenuEventType = todayMenuEventType;
Strategy = strategy;
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
restaurantManagementStateSo = RestaurantState.instance.ManagementState;
_isInitialized.SetResult(true);
}
@ -42,10 +42,10 @@ public async Task OnInteract()
switch (_todayMenuEventType)
{
case TodayMenuEventType.Add:
Strategy.OnAdded(_itemSlotUi, _restaurantManagementSo);
Strategy.OnAdded(_itemSlotUi, restaurantManagementStateSo);
break;
case TodayMenuEventType.Remove:
Strategy.OnRemoved(_itemSlotUi, _restaurantManagementSo);
Strategy.OnRemoved(_itemSlotUi, restaurantManagementStateSo);
break;
case TodayMenuEventType.None:
default:

View File

@ -2,13 +2,13 @@ namespace DDD
{
public class TodayMenuInteractorStrategy : IItemSlotInteractorStrategy
{
public void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantManagementSo)
public void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementStateSo restaurantManagementStateSo)
{
if (itemSlotUi.Strategy is not InventorySlotUiStrategy inventorySlotUiStrategy) return;
if (inventorySlotUiStrategy.CanCrafting(itemSlotUi))
{
restaurantManagementSo.TryAddTodayMenu(itemSlotUi.Model);
restaurantManagementStateSo.TryAddTodayMenu(itemSlotUi.Model);
}
else
{
@ -21,11 +21,11 @@ public void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantMana
}
}
public void OnRemoved(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantManagementSo)
public void OnRemoved(ItemSlotUi itemSlotUi, RestaurantManagementStateSo restaurantManagementStateSo)
{
if (itemSlotUi.Strategy is InventorySlotUiStrategy) return;
restaurantManagementSo.TryRemoveTodayMenu(itemSlotUi.Model);
restaurantManagementStateSo.TryRemoveTodayMenu(itemSlotUi.Model);
}
}
}

View File

@ -6,7 +6,7 @@ namespace DDD
public class TodayMenuSlotUiStrategy : IItemSlotUiStrategy
{
private readonly RecipeType _recipeType;
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
public string AnimatorControllerKey => "TodayMenuSlotUi";
@ -17,7 +17,7 @@ public TodayMenuSlotUiStrategy(RecipeType recipeType)
public async Task Setup(ItemSlotUi ui, ItemViewModel model)
{
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
restaurantManagementStateSo = RestaurantState.instance.ManagementState;
if (model == null)
{
@ -40,7 +40,7 @@ public async Task Setup(ItemSlotUi ui, ItemViewModel model)
}
string markSpriteKey = null;
if (_restaurantManagementSo.IsCookwareMatched(ui.Model.Id))
if (restaurantManagementStateSo.IsCookwareMatched(ui.Model.Id))
{
markSpriteKey = SpriteConstants.CheckYesSpriteKey;
}

View File

@ -12,7 +12,8 @@ public class TodayMenuView : MonoBehaviour, IEventHandler<TodayMenuAddedEvent>,
private List<ItemSlotUi> _foodSlots;
private List<ItemSlotUi> _drinkSlots;
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
private RestaurantManagementDataSo restaurantManagementDataSo;
private void Start()
{
@ -27,19 +28,20 @@ private void OnDestroy()
private async Task Initialize()
{
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
Debug.Assert(_restaurantManagementSo != null, "_restaurantManagementSo != null");
restaurantManagementStateSo = RestaurantState.instance.ManagementState;
restaurantManagementDataSo = RestaurantDataSo.instance.ManagementData;
Debug.Assert(restaurantManagementStateSo != null, "_restaurantManagementSo != null");
foreach (Transform child in _todayFoodContent)
{
Destroy(child.gameObject);
}
int maxFoodCount = _restaurantManagementSo!.MaxFoodCount;
int maxFoodCount = restaurantManagementStateSo!.MaxFoodCount;
_foodSlots = new List<ItemSlotUi>(maxFoodCount);
for (int i = 0; i < _restaurantManagementSo.MaxFoodCount; i++)
for (int i = 0; i < restaurantManagementStateSo.MaxFoodCount; i++)
{
var go = Instantiate(_restaurantManagementSo.ItemSlotUiPrefab, _todayFoodContent);
var go = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _todayFoodContent);
var slot = go.GetComponent<ItemSlotUi>();
await slot.Initialize(null, new TodayMenuSlotUiStrategy(RecipeType.FoodRecipe));
var itemSlotInteractor = go.GetComponent<ItemSlotInteractor>();
@ -53,11 +55,11 @@ private async Task Initialize()
Destroy(child.gameObject);
}
int maxDrinkCount = _restaurantManagementSo.MaxDrinkCount;
int maxDrinkCount = restaurantManagementStateSo.MaxDrinkCount;
_drinkSlots = new List<ItemSlotUi>(maxDrinkCount);
for (int i = 0; i < _restaurantManagementSo.MaxDrinkCount; i++)
for (int i = 0; i < restaurantManagementStateSo.MaxDrinkCount; i++)
{
var go = Instantiate(_restaurantManagementSo.ItemSlotUiPrefab, _todayDrinkContent);
var go = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _todayDrinkContent);
var slot = go.GetComponent<ItemSlotUi>();
await slot.Initialize(null, new TodayMenuSlotUiStrategy(RecipeType.DrinkRecipe));
var itemSlotInteractor = go.GetComponent<ItemSlotInteractor>();
@ -85,7 +87,7 @@ public void Invoke(TodayMenuRemovedEvent evt)
private void UpdateView()
{
int foodIndex = 0;
foreach (var foodRecipeIdCountPair in _restaurantManagementSo.TodayFoodRecipeIds)
foreach (var foodRecipeIdCountPair in restaurantManagementStateSo.TodayFoodRecipeIds)
{
if (foodIndex >= _foodSlots.Count) break;
@ -102,7 +104,7 @@ private void UpdateView()
}
int drinkIndex = 0;
foreach (var drinkRecipeIdCountPair in _restaurantManagementSo.TodayDrinkRecipeIds)
foreach (var drinkRecipeIdCountPair in restaurantManagementStateSo.TodayDrinkRecipeIds)
{
if (drinkIndex >= _drinkSlots.Count) break;

View File

@ -2,13 +2,13 @@ namespace DDD
{
public class TodayCookwareInteractorStrategy : IItemSlotInteractorStrategy
{
public void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantManagementSo)
public void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementStateSo restaurantManagementStateSo)
{
if (itemSlotUi.Strategy is not InventorySlotUiStrategy inventorySlotUiStrategy) return;
if (inventorySlotUiStrategy.CanCrafting(itemSlotUi))
{
restaurantManagementSo.TryAddTodayCookware(itemSlotUi.Model);
restaurantManagementStateSo.TryAddTodayCookware(itemSlotUi.Model);
}
else
{
@ -21,11 +21,11 @@ public void OnAdded(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantMana
}
}
public void OnRemoved(ItemSlotUi itemSlotUi, RestaurantManagementSo restaurantManagementSo)
public void OnRemoved(ItemSlotUi itemSlotUi, RestaurantManagementStateSo restaurantManagementStateSo)
{
if (itemSlotUi.Strategy is InventorySlotUiStrategy) return;
restaurantManagementSo.TryRemoveTodayCookware(itemSlotUi.Model);
restaurantManagementStateSo.TryRemoveTodayCookware(itemSlotUi.Model);
}
}
}

View File

@ -5,7 +5,7 @@ namespace DDD
{
public class TodayCookwareSlotUiStrategy : IItemSlotUiStrategy
{
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
public string AnimatorControllerKey => "TodayMenuSlotUi";

View File

@ -11,8 +11,9 @@ public class TodayRestaurantStateView : MonoBehaviour, IEventHandler<TodayMenuAd
private List<ItemSlotUi> _workerSlots;
private List<ItemSlotUi> _cookwareSlots;
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
private RestaurantManagementDataSo restaurantManagementDataSo;
private void Start()
{
@ -27,19 +28,20 @@ private void OnDestroy()
private async Task Initialize()
{
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
Debug.Assert(_restaurantManagementSo != null, "_restaurantManagementSo != null");
restaurantManagementStateSo = RestaurantState.instance.ManagementState;
restaurantManagementDataSo = RestaurantDataSo.instance.ManagementData;
Debug.Assert(restaurantManagementStateSo != null, "_restaurantManagementSo != null");
foreach (Transform child in _todayWorkerContent)
{
Destroy(child.gameObject);
}
int maxCookwareCount = _restaurantManagementSo!.MaxCookwareCount;
int maxCookwareCount = restaurantManagementStateSo!.MaxCookwareCount;
_workerSlots = new List<ItemSlotUi>(maxCookwareCount);
for (int i = 0; i < _restaurantManagementSo.MaxCookwareCount; i++)
for (int i = 0; i < restaurantManagementStateSo.MaxCookwareCount; i++)
{
var go = Instantiate(_restaurantManagementSo.ItemSlotUiPrefab, _todayWorkerContent);
var go = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _todayWorkerContent);
var slot = go.GetComponent<ItemSlotUi>();
await slot.Initialize(null, new TodayWorkerSlotUiStrategy());
var itemSlotInteractor = go.GetComponent<ItemSlotInteractor>();
@ -54,9 +56,9 @@ private async Task Initialize()
}
_cookwareSlots = new List<ItemSlotUi>(maxCookwareCount);
for (int i = 0; i < _restaurantManagementSo.MaxCookwareCount; i++)
for (int i = 0; i < restaurantManagementStateSo.MaxCookwareCount; i++)
{
var go = Instantiate(_restaurantManagementSo.ItemSlotUiPrefab, _todayCookwareContent);
var go = Instantiate(restaurantManagementDataSo.ItemSlotUiPrefab, _todayCookwareContent);
var slot = go.GetComponent<ItemSlotUi>();
await slot.Initialize(null, new TodayCookwareSlotUiStrategy());
var itemSlotInteractor = go.GetComponent<ItemSlotInteractor>();
@ -84,7 +86,7 @@ public void Invoke(TodayMenuRemovedEvent evt)
private void UpdateView()
{
int workerIndex = 0;
foreach (var workerKey in _restaurantManagementSo.TodayWorkerIds)
foreach (var workerKey in restaurantManagementStateSo.TodayWorkerIds)
{
if (workerIndex >= _workerSlots.Count) break;
@ -101,7 +103,7 @@ private void UpdateView()
}
int cookwareIndex = 0;
foreach (var cookwareKey in _restaurantManagementSo.CookwareToRecipeIds.Keys)
foreach (var cookwareKey in restaurantManagementStateSo.CookwareToRecipeIds.Keys)
{
if (cookwareIndex >= _cookwareSlots.Count) break;

View File

@ -5,7 +5,7 @@ namespace DDD
{
public class TodayWorkerSlotUiStrategy : IItemSlotUiStrategy
{
private RestaurantManagementSo _restaurantManagementSo;
private RestaurantManagementStateSo restaurantManagementStateSo;
public string AnimatorControllerKey => "TodayMenuSlotUi";

View File

@ -9,7 +9,7 @@ public class RestaurantPlayerInput : MonoBehaviour
private async void Start()
{
_playerDataSo = await AssetManager.LoadAsset<RestaurantPlayerDataSo>(DataConstants.RestaurantPlayerDataSo);
_playerDataSo = RestaurantDataSo.instance.PlayerData;
_playerDataSo.OpenManagementUiAction = InputManager.Instance.GetAction(InputActionMaps.Restaurant, nameof(RestaurantActions.OpenManagementUi));
_playerDataSo.OpenManagementUiAction.performed += OnOpenManagementUi;

View File

@ -17,7 +17,7 @@ protected override void Start()
private async Task Initialize()
{
_restaurantPlayerDataSo = await AssetManager.LoadAsset<RestaurantPlayerDataSo>(DataConstants.RestaurantPlayerDataSo);
_restaurantPlayerDataSo = RestaurantDataSo.instance.PlayerData;
Debug.Assert(_restaurantPlayerDataSo != null, "_restaurantPlayerDataSo is null");
_restaurantPlayerDataSo!.InteractAction = InputManager.Instance.GetAction(InputActionMaps.Restaurant, nameof(RestaurantActions.Interact));

View File

@ -81,8 +81,7 @@ private async System.Threading.Tasks.Task InitializePlayerData()
{
try
{
_playerDataSo =
await AssetManager.LoadAsset<RestaurantPlayerDataSo>(DataConstants.RestaurantPlayerDataSo);
_playerDataSo = RestaurantDataSo.instance.PlayerData;
SubscribeToInputEvents();
_isInitialized = true;
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7b8a2db30b704457b1fa4cf2a0e48255
timeCreated: 1755153982

View File

@ -0,0 +1,46 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
public class RestaurantEnvironmentController : RestaurantFlowController
{
private RestaurantEnvironmentStateSo _environmentState;
public override async Task InitializeController()
{
}
public override async Task InitializeState()
{
_environmentState = RestaurantState.instance.EnvironmentState;
}
public override async Task OnReadyNewFlow(GameFlowState newFlowState)
{
// if(newFlowState == GameFlowState.ReadyForRestaurant) GenerateDummyEnvironmentProps(); // XXX : DUMMY! REMOVE THIS
}
public override async Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
}
private void GenerateDummyEnvironmentProps()
{
// Make dummy placement data
foreach (EnvironmentData prop in DataManager.Instance.GetDataSo<EnvironmentDataSo>().GetDataList())
{
for (int i = 0; i < 10; i++)
{
// Make a random position
Vector2 randomPos = new Vector2(
Random.Range(-10f, 10f),
Random.Range(10f, 20f)
);
var randomPropData = new RestaurantPropLocation(prop.Id, randomPos);
_environmentState.Props.Add(randomPropData);
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ecaa037e76094edb85505ae8ef4a30bf
timeCreated: 1755158160

View File

@ -0,0 +1,26 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
public class RestaurantManagementController : RestaurantFlowController
{
public override async Task InitializeController()
{
}
public override async Task InitializeState()
{
// Load default asset
RestaurantState.instance.ManagementState.InitializeReadyForRestaurant();
}
public override async Task OnReadyNewFlow(GameFlowState newFlowState)
{
}
public override async Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d8111d425c954cbcad66b43ebeabdc87
timeCreated: 1755154065

View File

@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
public class RestaurantPlayerController : RestaurantFlowController
{
public override async Task InitializeController()
{
}
public override async Task InitializeState()
{
}
public override async Task OnReadyNewFlow(GameFlowState newFlowState)
{
if (newFlowState == GameFlowState.ReadyForRestaurant)
{
List<Task> tasks = new List<Task>();
// Spawn player job
CreateRestaurantPlayer createRestaurantPlayerJob = new CreateRestaurantPlayer();
var createPlayerReadyHandle = createRestaurantPlayerJob.ReadyFlowTask();
var createPlayerHandle = createRestaurantPlayerJob.RunFlowTask();
tasks.Add(createPlayerReadyHandle);
tasks.Add(createPlayerHandle);
Task.WhenAll(tasks);
}
}
public override async Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
if (exitingFlowState == GameFlowState.SettlementRestaurant)
{
// TODO : Remove player character
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ea2ec95b780049508f65b62fbe7d3182
timeCreated: 1755160563

View File

@ -0,0 +1,30 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
public class RestaurantRunController : RestaurantFlowController
{
RestaurantCustomerStateSo _restaurantCustomerStateSo;
public override async Task InitializeController()
{
}
public override async Task InitializeState()
{
}
public override async Task OnReadyNewFlow(GameFlowState newFlowState)
{
var restaurantCustomerStateHandle = _restaurantCustomerStateSo.OnReadyNewFlow(newFlowState);
}
public override async Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
if (exitingFlowState == GameFlowState.RunRestaurant)
{
var restaurantCustomerStateHandle = _restaurantCustomerStateSo.OnExitCurrentFlow(exitingFlowState);
await Task.WhenAll(restaurantCustomerStateHandle);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0bafd7933ff74e0dbe0f6bc728148ad7
timeCreated: 1755154487

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 48d5c919df704a56b8ce8d4378eacd35
timeCreated: 1755161934

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cf3b380b71a04861b2089308511b0fd2
timeCreated: 1755160110

View File

@ -0,0 +1,23 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
public class CreateRestaurantEnvironment : RestaurantFlowTask
{
public override async Task ReadyFlowTask()
{
}
public override async Task RunFlowTask()
{
// TODO : Base prefab from EnvironmentDataSo
var props = RestaurantState.instance.EnvironmentState.Props;
foreach (var prop in props)
{
// TODO : Instantiate and Initialize
}
}
}
}

View File

@ -0,0 +1,30 @@
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace DDD
{
public class CreateRestaurantPlayer : RestaurantFlowTask
{
[SerializeField]
private Vector3 _spawnPosition;
public override async Task ReadyFlowTask()
{
}
public override async Task RunFlowTask()
{
// TODO : Player exist check
var playerPrefab = await AssetManager.LoadAsset<GameObject>(CommonConstants.RestaurantPlayer);
var player = PrefabUtility.InstantiatePrefab(playerPrefab) as GameObject;
player.transform.position = _spawnPosition;
player.transform.rotation = playerPrefab.transform.rotation;
player.name = CommonConstants.RestaurantPlayer;
CameraManager.Instance.GetCameraGameObject(CameraType.RestaurantBaseCamera)
.SetFollowAndLookAtTarget(player.transform);
}
}
}

View File

@ -1,25 +0,0 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
[CreateAssetMenu(fileName = "CreateRestaurantPlayerSo", menuName = "GameFlow/CreateRestaurantPlayerSo")]
public class CreateRestaurantPlayerSo : ScriptableObject, IGameFlowHandler
{
[SerializeField]
private Vector3 _spawnPosition;
public async Task OnReadyNewFlow(GameFlowState newFlowState)
{
var playerPrefab = await AssetManager.LoadAsset<GameObject>(CommonConstants.RestaurantPlayer);
var player = Instantiate(playerPrefab, _spawnPosition, playerPrefab.transform.rotation);
player.name = CommonConstants.RestaurantPlayer;
CameraManager.Instance.GetCameraGameObject(CameraType.RestaurantBaseCamera).SetFollowAndLookAtTarget(player.transform);
}
public Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
return Task.CompletedTask;
}
}
}

View File

@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
@ -5,26 +7,34 @@ namespace DDD
{
public class RestaurantController : Singleton<RestaurantController>, IManager, IGameFlowHandler
{
public RestaurantEnvironmentStateSo RestaurantEnvironmentStateSo { get; private set; }
public RestaurantCustomerStateSo RestaurantCustomerStateSo { get; private set; }
// static definitions
private static readonly List<Type> RestaurantFlowControllerTypes = new()
{
typeof(RestaurantPlayerController),
typeof(RestaurantEnvironmentController),
typeof(RestaurantManagementController),
typeof(RestaurantRunController)
};
private const string CreateRestaurantPlayerSo = "CreateRestaurantPlayerSo";
private const string CreateEnvironmentSo = "CreateEnvironmentSo";
public RestaurantState GetRestaurantState() => RestaurantState.instance;
public RestaurantDataSo RestaurantData() => RestaurantDataSo.instance;
private List<RestaurantFlowController> _restaurantFlowControllers = new();
public void PreInit()
{
LoadOrCreateRestaurantState();
RegisterFlowHandler();
}
public async Task Init()
{
await LoadData();
await RestaurantDataSo.instance.LoadData();
}
public void PostInit()
{
GenerateDummyEnvironmentProps();// XXX : DUMMY! REMOVE THIS
InitializeAllFlowControllers();
}
private void RegisterFlowHandler()
@ -32,70 +42,54 @@ private void RegisterFlowHandler()
GameFlowManager.Instance.FlowHandlers.Add(this);
}
private void LoadOrCreateRestaurantState()
private void InitializeAllFlowControllers()
{
// TODO : Load states from saved files. if none, create them.
RestaurantEnvironmentStateSo = ScriptableObject.CreateInstance<RestaurantEnvironmentStateSo>();
// Create controllers and initialize them
foreach (var restaurantFlowControllerType in RestaurantFlowControllerTypes)
{
// create new controllers from restaurantFlowControllerType
var newController = ScriptableObject.CreateInstance(restaurantFlowControllerType);
var newFlowController = newController as RestaurantFlowController;
_restaurantFlowControllers.Add(newFlowController);
newFlowController.InitializeController();
}
foreach (var restaurantFlowController in _restaurantFlowControllers)
{
restaurantFlowController.InitializeState();
}
}
private async Task LoadData()
{
RestaurantCustomerStateSo = await AssetManager.LoadAsset<RestaurantCustomerStateSo>(DataConstants.RestaurantCustomerStateSo);
}
private void GenerateDummyEnvironmentProps()
{
// Make dummy placement data
foreach (EnvironmentData prop in DataManager.Instance.GetDataSo<EnvironmentDataSo>().GetDataList())
{
for (int i = 0; i < 10; i++)
{
// Make random position
Vector2 randomPos = new Vector2(
Random.Range(-10f, 10f),
Random.Range(10f, 20f)
);
var randomPropData = new RestaurantEnvironmentData(prop.Id, randomPos);
RestaurantEnvironmentStateSo.RestaurantEnvironmentProps.Add(randomPropData);
}
}
}
public async Task OnReadyNewFlow(GameFlowState newFlowState)
{
List<Task> tasks = new List<Task>();
// Default restaurant initialization
if (newFlowState == GameFlowState.ReadyForRestaurant)
{
CreateRestaurantPlayerSo createRestaurantPlayerSoJob = await AssetManager.LoadAsset<CreateRestaurantPlayerSo>(CreateRestaurantPlayerSo);
//CreateEnvironmentSo createEnvironmentSoJob = await AssetManager.LoadAsset<CreateEnvironmentSo>(CreateEnvironmentSo);
RestaurantManagementSo restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
var playerHandle = createRestaurantPlayerSoJob.OnReadyNewFlow(newFlowState);
//var propHandle = createEnvironmentSoJob.OnReadyNewFlow(newFlowState);
var todayMenuHandle = restaurantManagementSo.OnReadyNewFlow(newFlowState);
// Combine handles and return it
// Switch keymap
InputManager.Instance.SwitchCurrentActionMap(InputActionMaps.Restaurant);
await Task.WhenAll(playerHandle, todayMenuHandle);
}
else if (newFlowState == GameFlowState.RunRestaurant)
{
var restaurantCustomerStateHandle = RestaurantCustomerStateSo.OnReadyNewFlow(newFlowState);
await Task.WhenAll(restaurantCustomerStateHandle);
// Restaurant FlowControllers - Player, Environment, Management, Run, ...
foreach (var flowController in _restaurantFlowControllers)
{
tasks.Add(flowController.OnReadyNewFlow(newFlowState));
}
await Task.WhenAll(tasks);
}
public async Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
if (exitingFlowState == GameFlowState.ReadyForRestaurant)
List<Task> tasks = new List<Task>();
foreach (var flowController in _restaurantFlowControllers)
{
}
else if (exitingFlowState == GameFlowState.RunRestaurant)
{
var restaurantCustomerStateHandle = RestaurantCustomerStateSo.OnExitCurrentFlow(exitingFlowState);
await Task.WhenAll(restaurantCustomerStateHandle);
tasks.Add(flowController.OnExitCurrentFlow(exitingFlowState));
}
await Task.WhenAll(tasks);
}
}
}

View File

@ -0,0 +1,10 @@
using UnityEngine;
namespace DDD
{
[CreateAssetMenu(fileName = "RestaurantControllerData", menuName = "ScriptableObjects/RestaurantControllerData", order = 0)]
public class RestaurantControllerDataSo : ScriptableObject
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c3b0a722a1b452cbf02909232ae1b6f
timeCreated: 1755164592

View File

@ -0,0 +1,16 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
public abstract class RestaurantFlowController : ScriptableObject
{
public abstract Task InitializeController();
public abstract Task InitializeState();
public abstract Task OnReadyNewFlow(GameFlowState newFlowState);
public abstract Task OnExitCurrentFlow(GameFlowState exitingFlowState);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8e6271efae2e406098e6590001448373
timeCreated: 1755154355

View File

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace DDD
{
public abstract class RestaurantFlowTask
{
public abstract Task ReadyFlowTask();
public abstract Task RunFlowTask();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ba7572f469684e698181b16bb249e10b
timeCreated: 1755160268

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9ec68f33a1734f80b8370112f3cb71d2
timeCreated: 1755165763

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c5f37e0a2cdb465f9da5cd844a932a90
timeCreated: 1755168508

View File

@ -0,0 +1,17 @@
using Sirenix.OdinInspector;
using UnityEngine;
namespace DDD
{
[CreateAssetMenu(fileName = "RestaurantManagementDataSo", menuName = "RestaurantData/RestaurantManagementDataSo", order = 0)]
public class RestaurantManagementDataSo : ScriptableObject
{
public ItemSlotUi ItemSlotUiPrefab;
[Title("선택된 메뉴 상세 내용")]
public TasteHashTagSlotUi TasteHashTagSlotUiPrefab;
public Color FoodTasteOutlineColor = Color.magenta;
public Color DrinkTasteOutlineColor = Color.magenta;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3aa53e94b0504f26bb0cee017d1dddbc
timeCreated: 1755167516

View File

@ -3,7 +3,7 @@
namespace DDD
{
[CreateAssetMenu(fileName = "RestaurantPlayerDataSo", menuName = "ScriptableObjects/RestaurantPlayerDataSo")]
[CreateAssetMenu(fileName = "RestaurantPlayerDataSo", menuName = "RestaurantData/RestaurantPlayerDataSo")]
public class RestaurantPlayerDataSo : ScriptableObject
{
public bool IsDrawLineDebug = true;

View File

@ -0,0 +1,49 @@
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace DDD
{
[CreateAssetMenu(fileName = "RestaurantDataSo", menuName = "RestaurantData/RestaurantDataSo", order = 0)]
public class RestaurantDataSo : ScriptableSingleton<RestaurantDataSo>
{
[Header("Asset References")]
[SerializeField] private AssetReference RestaurantPlayerDataSo;
[SerializeField] private AssetReference RestaurantManagementDataSo;
public RestaurantPlayerDataSo PlayerData { get; private set; }
public RestaurantManagementDataSo ManagementData { get; private set; }
private bool _isLoaded;
public async Task LoadData()
{
if (_isLoaded)
{
return;
}
var playerHandle = RestaurantPlayerDataSo.LoadAssetAsync<RestaurantPlayerDataSo>();
var managementHandle = RestaurantManagementDataSo.LoadAssetAsync<RestaurantManagementDataSo>();
await playerHandle.Task;
await managementHandle.Task;
PlayerData = playerHandle.Result;
ManagementData = managementHandle.Result;
_isLoaded = true;
}
private void OnDisable()
{
if (!_isLoaded) return;
RestaurantPlayerDataSo.ReleaseAsset();
RestaurantManagementDataSo.ReleaseAsset();
_isLoaded = false;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f47eda10f73c497d9894967fae3cd2d8
timeCreated: 1755165774

View File

@ -1,26 +0,0 @@
using System.Threading.Tasks;
using UnityEngine;
namespace DDD
{
[CreateAssetMenu(fileName = "CreateEnvironmentSo", menuName = "GameFlow/CreateEnvironmentSo")]
public class CreateEnvironmentSo : ScriptableObject, IGameFlowHandler
{
public async Task OnReadyNewFlow(GameFlowState newFlowState)
{
var baseRestaurantEnvironmentPrefab = await AssetManager.LoadAsset<GameObject>(CommonConstants.BaseRestaurantEnvironment);
var props = RestaurantController.Instance.RestaurantEnvironmentStateSo.RestaurantEnvironmentProps;
foreach (var prop in props)
{
var restaurantEnvironment = Instantiate(baseRestaurantEnvironmentPrefab).GetComponent<RestaurantEnvironment>();
restaurantEnvironment.Initialize(prop);
}
}
public Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
return Task.CompletedTask;
}
}
}

View File

@ -6,16 +6,16 @@ namespace DDD
{
public class RestaurantEnvironment : MonoBehaviour
{
private RestaurantEnvironmentData _restaurantEnvironmentData;
private RestaurantPropLocation restaurantPropLocation;
private Collider _collider;
private Transform _rootObject;
private Transform _visualLook;
private Renderer _renderer;
public async void Initialize(RestaurantEnvironmentData data)
public async void Initialize(RestaurantPropLocation location)
{
EnvironmentData environmentData = DataManager.Instance.GetDataSo<EnvironmentDataSo>().GetDataById(data.Id);
EnvironmentData environmentData = DataManager.Instance.GetDataSo<EnvironmentDataSo>().GetDataById(location.Id);
_collider = GetComponent<Collider>();
_rootObject = transform.Find(CommonConstants.RootObject);
@ -48,7 +48,7 @@ public async void Initialize(RestaurantEnvironmentData data)
_collider.isTrigger = environmentData.IsTrigger == 1;
transform.position = new Vector3(data.Position.x, 0f, data.Position.y);
transform.position = new Vector3(location.Position.x, 0f, location.Position.y);
transform.localScale = Vector3.one * environmentData.Size;
// Interaction initialize

View File

@ -5,18 +5,6 @@ namespace DDD
{
public class RestaurantOpenEventSolver : MonoBehaviour, IInteractionSolver
{
private RestaurantManagementSo _restaurantManagementSo;
private void Start()
{
_ = Initialize();
}
private async Task Initialize()
{
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(DataConstants.RestaurantManagementSo);
}
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null)
{
if (CanExecuteInteraction() == false) return false;
@ -25,10 +13,16 @@ public bool ExecuteInteraction(IInteractor interactor, IInteractable interactabl
return true;
}
private RestaurantManagementStateSo GetManagementState()
{
return RestaurantState.instance.ManagementState;
}
public bool CanExecuteInteraction()
{
GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState;
return currentGameFlowState == GameFlowState.ReadyForRestaurant && _restaurantManagementSo.IsOpenable();
return currentGameFlowState == GameFlowState.ReadyForRestaurant && GetManagementState().IsOpenable();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e2c8f17cffc84440a720e0b241c61a05
timeCreated: 1755159485

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace DDD
{
[Serializable]
public class RestaurantPropLocation
{
public string Id;
public Vector2 Position;
public RestaurantPropLocation(string id, Vector2 position)
{
Id = id;
Position = position;
}
}
public class RestaurantEnvironmentStateSo : ScriptableObject
{
public List<RestaurantPropLocation> Props = new List<RestaurantPropLocation>();
public List<RestaurantPropLocation> Objects = new List<RestaurantPropLocation>();
}
}

View File

@ -6,18 +6,11 @@
namespace DDD
{
[CreateAssetMenu(fileName = "RestaurantManagementSo", menuName = "GameState/RestaurantManagementSo")]
public class RestaurantManagementSo : ScriptableObject, IGameFlowHandler
public class RestaurantManagementStateSo : ScriptableObject
{
// TODO : 체크리스트 기능
public ItemSlotUi ItemSlotUiPrefab;
[Title("선택된 메뉴 상세 내용")]
public TasteHashTagSlotUi TasteHashTagSlotUiPrefab;
public Color FoodTasteOutlineColor = Color.magenta;
public Color DrinkTasteOutlineColor = Color.magenta;
// TODO : 데이터에서 초기화하고, 동적으로 변경
[Title("오늘의 레스토랑 상태")]
public int MaxFoodCount = 8;
public int MaxDrinkCount = 6;
@ -35,23 +28,9 @@ public class RestaurantManagementSo : ScriptableObject, IGameFlowHandler
public IReadOnlyList<string> TodayWorkerIds => _todayWorkerIds;
public IReadOnlyDictionary<string, HashSet<string>> CookwareToRecipeIds => _cookwareToRecipeIds;
public Task OnReadyNewFlow(GameFlowState newFlowState)
{
if (newFlowState == GameFlowState.ReadyForRestaurant)
{
InitializeReadyForRestaurant();
}
return Task.CompletedTask;
}
public Task OnExitCurrentFlow(GameFlowState exitingFlowState)
{
return Task.CompletedTask;
}
private void InitializeReadyForRestaurant()
public void InitializeReadyForRestaurant()
{
// TODO : Load from disk if possible (save data)
_todayFoodRecipeIds.Clear();
_todayDrinkRecipeIds.Clear();
_todayWorkerIds.Clear();
@ -68,6 +47,11 @@ public bool IsOpenable()
return _isOpenable;
}
public RestaurantManagementDataSo GetManagementData()
{
return RestaurantDataSo.instance.ManagementData;
}
public bool TryAddTodayMenu(ItemViewModel model)
{
string recipeId = model.Id;

View File

@ -0,0 +1,9 @@
using UnityEngine;
namespace DDD
{
public class RestaurantPlayerStateSo : ScriptableObject
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc65892536714c08bc2cd202851e0c0f
timeCreated: 1755168640

View File

@ -0,0 +1,9 @@
using UnityEngine;
namespace DDD
{
public class RestaurantRunStateSo : ScriptableObject
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 692fb4e2437a48768e4bcf5a57d2883d
timeCreated: 1755153808

View File

@ -1,18 +0,0 @@
using System;
using UnityEngine;
namespace DDD
{
[Serializable]
public class RestaurantEnvironmentData
{
public string Id;
public Vector2 Position;
public RestaurantEnvironmentData(string id, Vector2 position)
{
Id = id;
Position = position;
}
}
}

View File

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 0d90911f4c827e3439a9a28d25e9bf93

View File

@ -1,12 +0,0 @@
using System.Collections.Generic;
using UnityEngine;
namespace DDD
{
// [CreateAssetMenu(fileName = "FILENAME", menuName = "MENUNAME", order = 0)]
public class RestaurantEnvironmentStateSo : ScriptableObject
{
public List<RestaurantEnvironmentData> RestaurantEnvironmentProps = new List<RestaurantEnvironmentData>();
public List<RestaurantEnvironmentData> RestaurantEnvironmentObjects = new List<RestaurantEnvironmentData>();
}
}

View File

@ -0,0 +1,22 @@
using UnityEditor;
using UnityEngine;
namespace DDD
{
public class RestaurantState : ScriptableSingleton<RestaurantState>
{
public RestaurantManagementStateSo ManagementState { get; private set; }
public RestaurantRunStateSo RunState { get; private set; }
public RestaurantEnvironmentStateSo EnvironmentState { get; private set; }
public RestaurantPlayerStateSo PlayerState { get; private set; }
// TODO : Load from disk(SaveData)
private void OnEnable()
{
ManagementState = CreateInstance<RestaurantManagementStateSo>();
RunState = CreateInstance<RestaurantRunStateSo>();
EnvironmentState = CreateInstance<RestaurantEnvironmentStateSo>();
PlayerState = CreateInstance<RestaurantPlayerStateSo>();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6fa023349eb642e1b7ce4a7966b2228c
timeCreated: 1755159513

View File

@ -5,7 +5,6 @@ public static class CommonConstants
public const string RootObject = "RootObject";
public const string VisualLook = "VisualLook";
public const string RestaurantPlayer = "RestaurantPlayer";
public const string BaseRestaurantEnvironment = "BaseRestaurantEnvironment";
public const string Clone = "(Clone)";
public const string Panel = "Panel";
}
@ -25,10 +24,9 @@ public static class DataConstants
public const string LevelDataSo = "LevelDataSo";
public const string CustomerDataSo = "CustomerDataSo";
public const string CustomerPoolDataSo = "CustomerPoolDataSo";
public const string RestaurantPlayerDataSo = "RestaurantPlayerDataSo";
public const string UiInputBindingSo = "UiInputBindingSo";
public const string RestaurantManagementSo = "RestaurantManagementSo";
public const string RestaurantCustomerStateSo = "RestaurantCustomerStateSo";
public const string RestaurantDataSo = "RestaurantDataSo";
public const string AtlasLabel = "Atlas";
public const string BasePropSpriteMaterial = "BasePropSpriteMaterial";