Merge pull request 'feature/customer_moveto/FixToBlackboard' (#28) from feature/customer_moveto/FixToBlackboard into develop

Reviewed-on: #28
This commit is contained in:
Jeonghyeon 2025-08-28 04:01:29 +00:00
commit 08016f97b4
21 changed files with 104 additions and 114 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1210,9 +1210,6 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 7462519206451630147, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
insertIndex: -1
addedObject: {fileID: 3825874317044733320}
- targetCorrespondingSourceObject: {fileID: 7462519206451630147, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
insertIndex: -1
addedObject: {fileID: 1122074513716966771}
m_SourcePrefab: {fileID: 100100000, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
--- !u!1 &4266090516809920735 stripped
GameObject:
@ -1255,23 +1252,3 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: af69e82818254bfa9cabb2dbf9430850, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &1122074513716966771
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4266090516809920735}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 201f9e6d7ca7404baa9945950292a392, type: 3}
m_Name:
m_EditorClassIdentifier:
_interactionType: 4
_executionParameters:
_holdTime: 0
_displayParameters:
_messageKey:
_interactionAvailableFlows: 2
_aiInteractionPoints: []
autoInitialize: 1

View File

@ -426,7 +426,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 81e01dd8c1cc3404d805400eba1bb4ae, type: 3}
m_Name:
m_EditorClassIdentifier:
_availableInteractions: 5
_availableInteractions: 7
_nearColliders:
- {fileID: 0}
- {fileID: 0}

View File

@ -10,7 +10,6 @@ public enum InteractionType : uint
None = 0u,
RestaurantManagement = 1u << 0,
RestaurantOrder = 1u << 1,
RestaurantMeal = 1u << 2,
RestaurantCook = 1u << 3,
All = 0xFFFFFFFFu
}

View File

@ -12,11 +12,7 @@ public class LookAtInteractionTarget : Action
{
[Header("Target Settings")]
[Tooltip("InteractionPoints를 사용해 가장 적절한 지점을 바라봄")]
[SerializeField] private bool useInteractionPoints = true;
[Header("Update Settings")]
[Tooltip("프레임마다 갱신하여 지속적으로 바라볼지 (Running 반환) 여부. 비활성화 시 1회만 시도하고 성공 처리")]
[SerializeField] private bool continuousUpdate = true;
[SerializeField] private bool _useInteractionPoints = true;
// Visual 전용 컴포넌트(나중 구현)를 위한 최소 인터페이스
// 실제 구현은 Spine/애니메이션 제어 컴포넌트에서 이 인터페이스를 구현하세요.
@ -68,9 +64,8 @@ public override TaskStatus OnUpdate()
{
_visual?.UpdateLookAt(_currentLookPosition);
}
// 연속 업데이트면 Running, 아니면 1회만 시도 후 Success 반환
return continuousUpdate ? TaskStatus.Running : TaskStatus.Success;
return TaskStatus.Success;
}
public override void OnEnd()
@ -87,7 +82,7 @@ public override void OnEnd()
private Vector3 CalculateLookPosition(GameObject target)
{
if (!useInteractionPoints)
if (!_useInteractionPoints)
return target.transform.position;
if (target.TryGetComponent<RestaurantInteractionComponent>(out var ric))

View File

@ -188,7 +188,7 @@ public void Execute(ref DynamicBuffer<BranchComponent> branchComponents,
branchComponents[taskComponent.BranchIndex] = branchComponent;
continue;
}
else if (taskComponent.Status != TaskStatus.Running)
if (taskComponent.Status != TaskStatus.Running)
{
continue;
}

View File

@ -21,6 +21,7 @@ public class StartRestaurantOrder : Action
public override void OnStart()
{
_isGetInteractor = gameObject.TryGetComponent(out _interactor);
if (!_isGetInteractor)
Debug.LogError($"[{GetType().Name}] IInteractor를 찾을 수 없습니다: {gameObject.name}");
}

View File

@ -8,78 +8,42 @@ namespace DDD.Restaurant
//차후 제네릭으로 변경 가능성 있음
public class WaitForPlayerInteraction : Action
{
[Tooltip("기다릴 상호작용 타입")]
[SerializeField] private RestaurantMealType _targetOrderType = RestaurantMealType.WaitForOrder;
private IInteractionSubsystemObject<RestaurantMealType> _interactionSubsystem;
[SerializeField] private RestaurantOrderType _targetOrderType;
private IInteractionSubsystemObject<RestaurantOrderType> _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;
// }
GameObject interactionTarget = null;
if (!gameObject.TryGetComponent<IAISharedBlackboard>(out var sharedBlackboard)) return;
interactionTarget =
sharedBlackboard.GetBlackboardGameObject(
nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget));
if (!gameObject.TryGetComponent<RestaurantInteractionComponent>(out var interactionComponent))
if (interactionTarget == null)
{
Debug.LogError($"[{GetType().Name}]에서 interactionComponent를 찾을 수 없습니다: {gameObject.name}");
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 not IInteractionSubsystemOwner subsystemOwner)
{
Debug.LogError($"[{GetType().Name}]에서 {nameof(IInteractionSubsystemOwner)}를 찾을 수 없습니다: {gameObject.name}");
Debug.LogError(
$"[{GetType().Name}]에서 {nameof(IInteractionSubsystemOwner)}를 찾을 수 없습니다: {gameObject.name}");
return;
}
if (!subsystemOwner.TryGetSubsystemObject(out _interactionSubsystem))
{
Debug.LogError($"[{GetType().Name}]에서 {nameof(IInteractionSubsystemObject)}를 찾을 수 없습니다: {gameObject.name}");
Debug.LogError(
$"[{GetType().Name}]에서 {nameof(IInteractionSubsystemObject)}를 찾을 수 없습니다: {gameObject.name}");
return;
}
_interactionSubsystem.SetInteractionSubsystemType(_targetOrderType);
_isGetInteractionSubsystem = true;
}
@ -91,7 +55,7 @@ public override TaskStatus OnUpdate()
if (result == TaskStatus.Success) Debug.Log($"[{GetType().Name}] Success");
return result;
}
private TaskStatus CheckToSubsystemStatus()
{
return _interactionSubsystem.GetInteractionSubsystemType() == _targetOrderType

View File

@ -48,7 +48,7 @@ private async Task InitializeAiInternal(CustomerData inCustomerData)
_behaviorTree.Subgraph = subtree;
_blackboardComponent.InitializeWithBehaviorTree(_behaviorTree);
_blackboardComponent.SetCustomerData(inCustomerData);
_blackboardComponent.SetCustomerData(inCustomerData.Id);
// TODO : 1. Subtree - Action, Condition
// TODO : 2. Blackboard
_behaviorTree.StartBehavior();

View File

@ -17,10 +17,10 @@ public void InitializeWithBehaviorTree(BehaviorTree inBehaviorTree)
}
}
public void SetCustomerData(CustomerData inCustomerData)
public void SetCustomerData(string inCustomerDataId)
{
if (!_behaviorTree) return;
_behaviorTree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CustomerData), inCustomerData);
_behaviorTree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CustomerDataId), inCustomerDataId);
}
public void SetBlackboardGameObject(string key, GameObject inGameObject)

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
@ -99,5 +100,27 @@ public bool CanInteractTo(IInteractable interactable, ScriptableObject payloadSo
if (TryGetSolverFor(interactable, out var solver) == false) return false;
return solver.CanExecuteInteraction(this, interactable, payloadSo);
}
public virtual void InitializeSolvers()
{
var typesToSolver = RestaurantInteractionEventSolvers.TypeToSolver;
InitializeInteractionSolvers(typesToSolver);
}
protected void InitializeInteractionSolvers(Dictionary<InteractionType, Type> typesToSolver)
{
foreach (var typeToSolver in typesToSolver)
{
var flag = typeToSolver.Key;
if (flag == InteractionType.None) continue;
if ((AvailableInteractions & flag) == 0) continue;
if (!TryGetComponent(typeToSolver.Value, out _))
{
gameObject.AddComponent(typeToSolver.Value);
}
}
}
}
}

View File

@ -13,19 +13,8 @@ public class RestaurantCharacter : MonoBehaviour, IGameCharacter, IInteractor
protected virtual void Awake()
{
_interactionComponent = GetComponent<CharacterInteraction>();
_interactionComponent.InitializeSolvers();
_spineController = GetComponent<SpineController>();
foreach (var typeToSolver in RestaurantInteractionEventSolvers.TypeToSolver)
{
var flag = typeToSolver.Key;
if (flag == InteractionType.None) continue;
if ((_interactionComponent.AvailableInteractions & flag) == 0) continue;
if (!TryGetComponent(typeToSolver.Value, out _))
{
gameObject.AddComponent(typeToSolver.Value);
}
}
}
protected virtual void Start()

View File

@ -5,12 +5,12 @@ namespace DDD
public enum RestaurantCustomerBlackboardKey
{
SelfGameObject,
CustomerData,
CustomerDataId,
CurrentInteractionTarget,
}
public interface ICustomerBlackboard
{
void SetCustomerData(CustomerData inCustomerData);
void SetCustomerData(string inCustomerDataId);
}
}

View File

@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.InputSystem;
@ -35,6 +37,18 @@ private Task Initialize()
return Task.CompletedTask;
}
public override void InitializeSolvers()
{
var typesToSolver = RestaurantInteractionEventSolvers.TypeToSolver;
var playerSolver = RestaurantInteractionEventSolvers.TypeToPlayerSolver;
foreach(var pair in playerSolver)
{
typesToSolver.Remove(pair.Key);
}
InitializeInteractionSolvers(typesToSolver);
InitializeInteractionSolvers(playerSolver);
}
protected override void OnDestroy()
{
base.OnDestroy();

View File

@ -1,4 +1,5 @@
using System;
using Unity.VisualScripting;
using UnityEngine;
namespace DDD
@ -23,11 +24,13 @@ public RestaurantMealType GetInteractionSubsystemType()
public void SetInteractionSubsystemType(RestaurantMealType inValue)
{
Debug.Log($"[{gameObject.GetHashCode()}, {GetType().Name}] SetInteractionSubsystemType {inValue.ToString()}");
_currentRestaurantMealType = inValue;
}
public void InitializeSubsystem()
{
Debug.Log($"[{gameObject.GetHashCode()}, {GetType().Name}] InitializeSubsystem");
_currentRestaurantMealType = RestaurantMealType.None;
}
@ -38,6 +41,7 @@ public bool CanInteract()
public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null)
{
Debug.Log($"[{gameObject.GetHashCode()}, {GetType().Name}] OnInteracted");
var prev = _currentRestaurantMealType;
_currentRestaurantMealType = GetNextState(prev);
return true;

View File

@ -13,7 +13,6 @@ public static class RestaurantInteractionSubsystems
{
{InteractionType.RestaurantOrder, typeof(InteractionSubsystem_Order)},
{InteractionType.RestaurantManagement, typeof(InteractionSubsystem_Management)},
{InteractionType.RestaurantMeal, typeof(InteractionSubsystem_Meal)}
};
}

View File

@ -10,9 +10,12 @@ public static class RestaurantInteractionEventSolvers
{
{InteractionType.RestaurantManagement, typeof(RestaurantManagementSolver)},
{InteractionType.RestaurantOrder, typeof(RestaurantOrderSolver)},
{InteractionType.RestaurantMeal, typeof(RestaurantMealSolver)},
{InteractionType.RestaurantCook, typeof(RestaurantCookSolver)}
};
public static Dictionary<InteractionType, Type> TypeToPlayerSolver = new()
{
{InteractionType.RestaurantOrder, typeof(RestaurantOrderPlayerSolver)},
};
}
public class RestaurantInteractionEvent : IEvent

View File

@ -10,9 +10,19 @@ public class RestaurantOrderSolver : RestaurantSubsystemSolver<RestaurantOrderTy
{
{ RestaurantOrderType.Wait, typeof(RestaurantOrderSolver_Wait) },
{ RestaurantOrderType.Reserved, typeof(RestaurantOrderSolver_Reserved) },
{ RestaurantOrderType.Busy, typeof(RestaurantOrderSolver_Busy) },
};
protected override Dictionary<RestaurantOrderType, Type> GetSubsystemSolverTypeMappings()
{
return _typeToOrderSolver;
}
}
public class RestaurantOrderPlayerSolver : RestaurantSubsystemSolver<RestaurantOrderType>
{
private Dictionary<RestaurantOrderType, Type> _typeToOrderSolver = new()
{
{ RestaurantOrderType.Order, typeof(RestaurantOrderSolver_Order) },
{ RestaurantOrderType.Serve, typeof(RestaurantOrderSolver_Serve) },
{ RestaurantOrderType.Busy, typeof(RestaurantOrderSolver_Busy) },
{ RestaurantOrderType.Dirty, typeof(RestaurantOrderSolver_Dirty) }
};
protected override Dictionary<RestaurantOrderType, Type> GetSubsystemSolverTypeMappings()

View File

@ -0,0 +1,9 @@
using UnityEngine;
namespace DDD.Restaurant
{
public class PropUiDisplayComponent : MonoBehaviour
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 37e749c7ec5440d587f83c715f29ca8f
timeCreated: 1756353198