레스토랑 식사 인터랙션 서브 시스템 및 솔버 초기 구현 추가
This commit is contained in:
parent
24239dc138
commit
1663ff055c
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset
(Stored with Git LFS)
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset
(Stored with Git LFS)
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset
(Stored with Git LFS)
Binary file not shown.
@ -10,6 +10,10 @@ PrefabInstance:
|
||||
m_Modifications:
|
||||
- target: {fileID: 2686192822530022837, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
propertyPath: m_IsTrigger
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3540956906288785900, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
propertyPath: m_Layer
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3854744934792897056, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
@ -1172,6 +1176,10 @@ PrefabInstance:
|
||||
propertyPath: m_Name
|
||||
value: CustomerNpc
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7462519206451630147, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
propertyPath: m_Layer
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7545136660434259176, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
propertyPath: m_Constraints
|
||||
value: 112
|
||||
@ -1180,6 +1188,10 @@ PrefabInstance:
|
||||
propertyPath: m_IsKinematic
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8155105186346135386, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
propertyPath: m_Layer
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8165702938223525558, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
propertyPath: graphMask.value
|
||||
value: 2
|
||||
|
@ -426,7 +426,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 81e01dd8c1cc3404d805400eba1bb4ae, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_availableInteractions: 1
|
||||
_availableInteractions: 5
|
||||
_nearColliders:
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
|
@ -474,7 +474,8 @@ PrefabInstance:
|
||||
propertyPath: m_Name
|
||||
value: Prop_CustomerTable_002
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 551358949302262764, guid: 0b1ba2f28535d5147bc0ddf354d0712f, type: 3}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
BIN
Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset
(Stored with Git LFS)
BIN
Assets/_DDD/_Addressables/So/RestaurantData/DataObjects/RestaurantPlayerData.asset
(Stored with Git LFS)
Binary file not shown.
@ -12,6 +12,7 @@ public interface IInteractionSubsystemObject
|
||||
public interface IInteractionSubsystemObject<T> : IInteractionSubsystemObject where T : Enum
|
||||
{
|
||||
T GetInteractionSubsystemType();
|
||||
void SetInteractionSubsystemType(T inValue);
|
||||
}
|
||||
|
||||
public interface IInteractionSubsystemSolver
|
||||
|
@ -14,13 +14,13 @@ namespace DDD
|
||||
public class TimeLimiter : ILogicNode, IParentNode, ITaskComponentData, IDecorator, ISavableTask
|
||||
{
|
||||
[Tooltip("The index of the node.")]
|
||||
[SerializeField] ushort _Index;
|
||||
[SerializeField, HideInInspector] ushort _Index;
|
||||
|
||||
[Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")]
|
||||
[SerializeField] ushort _ParentIndex;
|
||||
[SerializeField, HideInInspector] ushort _ParentIndex;
|
||||
|
||||
[Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")]
|
||||
[SerializeField] ushort _SiblingIndex;
|
||||
[SerializeField, HideInInspector] ushort _SiblingIndex;
|
||||
|
||||
[Tooltip("최대 실행 시간(초)")]
|
||||
[SerializeField] float _timeLimit = 30.0f;
|
||||
@ -28,10 +28,6 @@ public class TimeLimiter : ILogicNode, IParentNode, ITaskComponentData, IDecorat
|
||||
[Tooltip("시간 초과 시 반환할 상태")]
|
||||
[SerializeField] private TaskStatus _timeoutStatus = TaskStatus.Failure;
|
||||
|
||||
[Header("Debug")]
|
||||
[Tooltip("로그 출력")]
|
||||
[SerializeField] private bool _enableDebug = false;
|
||||
|
||||
private ushort _ComponentIndex;
|
||||
|
||||
public ushort Index
|
||||
|
@ -12,6 +12,16 @@ public class StartRestaurantOrder : Action
|
||||
[SerializeField] private bool _requireCanInteract = true;
|
||||
[Tooltip("성공 시 블랙보드에 현재 인터랙션 대상을 등록합니다")]
|
||||
[SerializeField] private bool _registerOnBlackboard = true;
|
||||
|
||||
private IInteractor _interactor;
|
||||
private bool _isGetInteractor;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
_isGetInteractor = gameObject.TryGetComponent(out _interactor);
|
||||
if (!_isGetInteractor)
|
||||
Debug.LogError($"[{GetType().Name}] IInteractor를 찾을 수 없습니다: {gameObject.name}");
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
@ -26,13 +36,12 @@ public override TaskStatus OnUpdate()
|
||||
|
||||
// TODO : 아래 상호작용 수행 로직이 우리 프로젝트의 권장하는 방식이 아님. 플레이어가 오브젝트에 인터랙션하는 것과 비슷한 흐름으로 NPC가 오브젝트에 인터랙션하게 만들 것.
|
||||
// 상호작용 수행: 액션이 붙은 에이전트를 Interactor로 사용
|
||||
var isGetInteractor = gameObject.TryGetComponent<IInteractor>(out var interactor);
|
||||
if (!isGetInteractor || !interactor.CanInteractTo(outInteractable))
|
||||
if (!_isGetInteractor || !_interactor.CanInteractTo(outInteractable))
|
||||
{
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
var interacted = outInteractable.OnInteracted(interactor);
|
||||
var interacted = outInteractable.OnInteracted(_interactor);
|
||||
if (!interacted)
|
||||
{
|
||||
return TaskStatus.Failure;
|
||||
@ -41,7 +50,7 @@ public override TaskStatus OnUpdate()
|
||||
if (_registerOnBlackboard)
|
||||
{
|
||||
// 공용 블랙보드 우선
|
||||
var shared = gameObject.GetComponentInParent<IAISharedBlackboard>();
|
||||
var shared = gameObject.GetComponentInChildren<IAISharedBlackboard>();
|
||||
if (shared != null)
|
||||
{
|
||||
shared.SetCurrentInteractionTarget(outInteractable.gameObject);
|
||||
|
@ -0,0 +1,80 @@
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks.Actions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
//범용적으로 사용할 수 있을 것 같음
|
||||
//차후 제네릭으로 변경 가능성 있음
|
||||
public class WaitForPlayerInteraction : Action
|
||||
{
|
||||
[Tooltip("기다릴 상호작용 타입")]
|
||||
[SerializeField] private RestaurantMealType _targetOrderType = RestaurantMealType.WaitForOrder;
|
||||
|
||||
private IInteractionSubsystemObject<RestaurantMealType> _interactionSubsystem;
|
||||
private bool _isGetInteractionSubsystem;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
GameObject interactionTarget = null;
|
||||
var shared = gameObject.GetComponentInChildren<IAISharedBlackboard>();
|
||||
if (shared != null)
|
||||
{
|
||||
interactionTarget = shared.GetCurrentInteractionTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 하위 호환: 고객 전용 블랙보드 지원
|
||||
var customerBb = gameObject.GetComponentInParent<IRestaurantCustomerBlackboard>();
|
||||
interactionTarget = customerBb?.GetCurrentInteractionTarget();
|
||||
}
|
||||
|
||||
if (interactionTarget == null)
|
||||
{
|
||||
Debug.LogError($"[{GetType().Name}] interactionTarget을 찾을 수 없습니다: {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!interactionTarget.TryGetComponent<RestaurantInteractionComponent>(out var interactionComponent))
|
||||
Debug.LogError($"[{interactionTarget.name}] {nameof(interactionComponent)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
if (interactionComponent is IInteractionSubsystemOwner subsystemOwner)
|
||||
{
|
||||
if (!subsystemOwner.TryGetSubsystemObject<RestaurantMealType>(out var subsystem))
|
||||
{
|
||||
Debug.LogError($"[{GetType().Name}] {nameof(_targetOrderType)}의 Subsystem을 찾을 수 없습니다: {gameObject.name}");
|
||||
_isGetInteractionSubsystem = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_isGetInteractionSubsystem = true;
|
||||
subsystem.SetInteractionSubsystemType(_targetOrderType);
|
||||
|
||||
if (!gameObject.TryGetComponent<IInteractor>(out var interactor))
|
||||
{
|
||||
Debug.LogError($"[{GetType().Name}] IInteractor를 찾을 수 없습니다: {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
interactor.CanInteractTo(interactionComponent);
|
||||
|
||||
_interactionSubsystem = subsystem;
|
||||
}
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (!_isGetInteractionSubsystem) return TaskStatus.Failure;
|
||||
|
||||
TaskStatus result = CheckToSubsystemStatus();
|
||||
if (result == TaskStatus.Success) Debug.Log($"[{GetType().Name}] Success");
|
||||
return result;
|
||||
}
|
||||
|
||||
private TaskStatus CheckToSubsystemStatus()
|
||||
{
|
||||
return _interactionSubsystem.GetInteractionSubsystemType() == _targetOrderType
|
||||
? TaskStatus.Running
|
||||
: TaskStatus.Success;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bb97122045148169906d2f7b04a712e
|
||||
timeCreated: 1756171540
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals;
|
||||
using UnityEngine;
|
||||
@ -32,7 +34,7 @@ public override TaskStatus OnUpdate()
|
||||
|
||||
}
|
||||
|
||||
public static TaskStatus FindAvailableOrderInteractable(bool checkCanInteract, RestaurantOrderType targetOrderType, out RestaurantInteractionComponent outInteractable)
|
||||
public static TaskStatus FindAvailableOrderInteractable<T>(bool checkCanInteract, T targetOrderType, out RestaurantInteractionComponent outInteractable) where T : Enum
|
||||
{
|
||||
outInteractable = null;
|
||||
|
||||
@ -49,9 +51,10 @@ public static TaskStatus FindAvailableOrderInteractable(bool checkCanInteract, R
|
||||
// 서브시스템에서 RestaurantOrderType을 가져와 비교
|
||||
outInteractable = interactable as RestaurantInteractionComponent;
|
||||
if (outInteractable == null) continue;
|
||||
if (!outInteractable.TryGetSubsystemObject<RestaurantOrderType>(out var subsystem)) continue;
|
||||
if (!outInteractable.TryGetSubsystemObject<T>(out var subsystem)) continue;
|
||||
|
||||
if (subsystem.GetInteractionSubsystemType() == targetOrderType)
|
||||
if (EqualityComparer<T>.Default.Equals(subsystem.GetInteractionSubsystemType(), targetOrderType)
|
||||
)
|
||||
{
|
||||
// CheckCanInteract이 false면 타입만 맞으면 성공
|
||||
if (!checkCanInteract)
|
||||
|
@ -18,6 +18,11 @@ public RestaurantManagementType GetInteractionSubsystemType()
|
||||
return _managementType;
|
||||
}
|
||||
|
||||
public void SetInteractionSubsystemType(RestaurantManagementType inValue)
|
||||
{
|
||||
_managementType = inValue;
|
||||
}
|
||||
|
||||
public void InitializeSubsystem()
|
||||
{
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public enum RestaurantMealType : uint
|
||||
{
|
||||
None = 0u,
|
||||
WaitForOrder = 1u,
|
||||
WaitForServe = 1u << 1
|
||||
}
|
||||
public class RestaurantMealInteractionSubsystem : MonoBehaviour, IInteractionSubsystemObject<RestaurantMealType>
|
||||
{
|
||||
private RestaurantMealType _currentRestaurantMealType;
|
||||
private void Awake()
|
||||
{
|
||||
_currentRestaurantMealType = RestaurantMealType.None;
|
||||
}
|
||||
public RestaurantMealType GetInteractionSubsystemType()
|
||||
{
|
||||
return _currentRestaurantMealType;
|
||||
}
|
||||
|
||||
public void SetInteractionSubsystemType(RestaurantMealType inValue)
|
||||
{
|
||||
_currentRestaurantMealType = inValue;
|
||||
}
|
||||
|
||||
public void InitializeSubsystem()
|
||||
{
|
||||
_currentRestaurantMealType = RestaurantMealType.None;
|
||||
}
|
||||
|
||||
public bool CanInteract()
|
||||
{
|
||||
return _currentRestaurantMealType != RestaurantMealType.None;
|
||||
}
|
||||
|
||||
public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null)
|
||||
{
|
||||
var prev = _currentRestaurantMealType;
|
||||
_currentRestaurantMealType = GetNextState(prev);
|
||||
return true;
|
||||
}
|
||||
|
||||
private RestaurantMealType GetNextState(RestaurantMealType state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case RestaurantMealType.None : return RestaurantMealType.WaitForOrder;
|
||||
case RestaurantMealType.WaitForOrder : return RestaurantMealType.WaitForServe;
|
||||
case RestaurantMealType.WaitForServe : return RestaurantMealType.None;
|
||||
default: return RestaurantMealType.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31d5c600061a4f05b19824e068e0c2af
|
||||
timeCreated: 1756176676
|
@ -42,7 +42,7 @@ public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = nu
|
||||
|
||||
public void InitializeSubsystem()
|
||||
{
|
||||
|
||||
currentRestaurantOrderType = orderType;
|
||||
}
|
||||
|
||||
public RestaurantOrderType GetInteractionSubsystemType()
|
||||
@ -50,6 +50,11 @@ public RestaurantOrderType GetInteractionSubsystemType()
|
||||
return currentRestaurantOrderType;
|
||||
}
|
||||
|
||||
public void SetInteractionSubsystemType(RestaurantOrderType inValue)
|
||||
{
|
||||
currentRestaurantOrderType = inValue;
|
||||
}
|
||||
|
||||
private RestaurantOrderType GetNextState(RestaurantOrderType state)
|
||||
{
|
||||
switch (state)
|
||||
|
@ -12,7 +12,8 @@ public static class RestaurantInteractionSubsystems
|
||||
public static Dictionary<InteractionType, Type> TypeToSubsystem = new()
|
||||
{
|
||||
{InteractionType.RestaurantOrder, typeof(RestaurantOrderInteractionSubsystem)},
|
||||
{InteractionType.RestaurantManagement, typeof(RestaurantManagementInteractionSubsystem)}
|
||||
{InteractionType.RestaurantManagement, typeof(RestaurantManagementInteractionSubsystem)},
|
||||
{InteractionType.RestaurantMeal, typeof(RestaurantMealInteractionSubsystem)}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,8 @@ public static class RestaurantInteractionEventSolvers
|
||||
public static Dictionary<InteractionType, Type> TypeToSolver = new()
|
||||
{
|
||||
{InteractionType.RestaurantManagement, typeof(RestaurantManagementSolver)},
|
||||
{InteractionType.RestaurantOrder, typeof(RestaurantOrderSolver)}
|
||||
{InteractionType.RestaurantOrder, typeof(RestaurantOrderSolver)},
|
||||
{InteractionType.RestaurantMeal, typeof(RestaurantMealSolver)}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,17 @@
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public static class RestaurantManagementSolvers
|
||||
public class RestaurantManagementSolver : RestaurantSubsystemSolver<RestaurantManagementType>
|
||||
{
|
||||
public static Dictionary<RestaurantManagementType, Type> TypeToManagementSolver = new()
|
||||
|
||||
private Dictionary<RestaurantManagementType, Type> _typeToManagementSolver = new()
|
||||
{
|
||||
{ RestaurantManagementType.OpenRestaurantMenu, typeof(RestaurantManagementSolver_Menu) },
|
||||
{ RestaurantManagementType.StartRestaurant, typeof(RestaurantManagementSolver_Start) }
|
||||
};
|
||||
}
|
||||
public class RestaurantManagementSolver : RestaurantSubsystemSolver<RestaurantManagementType>
|
||||
{
|
||||
protected override Dictionary<RestaurantManagementType, Type> GetSubsystemSolverTypeMappings()
|
||||
{
|
||||
return RestaurantManagementSolvers.TypeToManagementSolver;
|
||||
return _typeToManagementSolver;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 601164c0231c43fca9349170e1e0ccec
|
||||
timeCreated: 1756176395
|
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public class RestaurantMealSolver : RestaurantSubsystemSolver<RestaurantMealType>
|
||||
{
|
||||
private Dictionary<RestaurantMealType, Type> _typeToMealSolver = new()
|
||||
{
|
||||
{ RestaurantMealType.WaitForOrder, typeof(RestaurantMealSolver_WaitForOrder) },
|
||||
{ RestaurantMealType.WaitForServe, typeof(RestaurantMealSolver_WaitForServe) }
|
||||
};
|
||||
protected override Dictionary<RestaurantMealType, Type> GetSubsystemSolverTypeMappings()
|
||||
{
|
||||
return _typeToMealSolver;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 391c551614be4f21a2e700f44569e92a
|
||||
timeCreated: 1756176491
|
@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public class RestaurantMealSolver_WaitForOrder : MonoBehaviour, IInteractionSubsystemSolver<RestaurantMealType>
|
||||
{
|
||||
public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
|
||||
ScriptableObject payloadSo = null)
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cff2611181194e4a92576bdbcead4fad
|
||||
timeCreated: 1756181225
|
@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public class RestaurantMealSolver_WaitForServe : MonoBehaviour, IInteractionSubsystemSolver<RestaurantMealType>
|
||||
{
|
||||
public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
|
||||
ScriptableObject payloadSo = null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9292616267b4299a3d2e0d29c84f69b
|
||||
timeCreated: 1756181667
|
@ -5,9 +5,9 @@
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public static class RestaurantOrderSolvers
|
||||
public class RestaurantOrderSolver : RestaurantSubsystemSolver<RestaurantOrderType>
|
||||
{
|
||||
public static Dictionary<RestaurantOrderType, Type> TypeToOrderSolver = new()
|
||||
private Dictionary<RestaurantOrderType, Type> _typeToOrderSolver = new()
|
||||
{
|
||||
{ RestaurantOrderType.Wait, typeof(RestaurantOrderSolver_Wait) },
|
||||
{ RestaurantOrderType.Reserved, typeof(RestaurantOrderSolver_Reserved) },
|
||||
@ -16,13 +16,9 @@ public static class RestaurantOrderSolvers
|
||||
{ RestaurantOrderType.Busy, typeof(RestaurantOrderSolver_Busy) },
|
||||
{ RestaurantOrderType.Dirty, typeof(RestaurantOrderSolver_Dirty) }
|
||||
};
|
||||
}
|
||||
|
||||
public class RestaurantOrderSolver : RestaurantSubsystemSolver<RestaurantOrderType>
|
||||
{
|
||||
protected override Dictionary<RestaurantOrderType, Type> GetSubsystemSolverTypeMappings()
|
||||
{
|
||||
return RestaurantOrderSolvers.TypeToOrderSolver;
|
||||
return _typeToOrderSolver;
|
||||
}
|
||||
}
|
||||
}
|
BIN
ProjectSettings/TagManager.asset
(Stored with Git LFS)
BIN
ProjectSettings/TagManager.asset
(Stored with Git LFS)
Binary file not shown.
Loading…
Reference in New Issue
Block a user