Merge pull request '서브 시스템 수정, 인터렉트 컴포넌트에 서브 시스템 검색 인터페이스 추가' (#24) from feature/interaction_subsystem_management into feature/interaction_subsystem

Reviewed-on: #24
Reviewed-by: Jeonghyeon <jeonghyeon@capers.co.kr>
This commit is contained in:
san 2025-08-20 10:02:28 +00:00
commit acd2a6db82
24 changed files with 225 additions and 82 deletions

View File

@ -113,6 +113,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3} - targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 6899480242032072806} addedObject: {fileID: 6899480242032072806}
- targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
insertIndex: -1
addedObject: {fileID: -4132148316966952702}
m_SourcePrefab: {fileID: 100100000, guid: 1d634c3376e4a4684bc984ced9134847, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
--- !u!1 &9211739394093953175 stripped --- !u!1 &9211739394093953175 stripped
GameObject: GameObject:
@ -131,10 +134,14 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 201f9e6d7ca7404baa9945950292a392, type: 3} m_Script: {fileID: 11500000, guid: 201f9e6d7ca7404baa9945950292a392, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_interactionType: 2 _interactionType: 1
_holdTime: 0 _executionParameters:
_interactionMessageKey: Test _holdTime: 1
_displayParameters:
_messageKey:
_interactionAvailableFlows: 1 _interactionAvailableFlows: 1
_aiInteractionPoints: []
autoInitialize: 1
--- !u!114 &3538352761187622062 --- !u!114 &3538352761187622062
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -375,3 +382,16 @@ MonoBehaviour:
_outlineSharpness: 8 _outlineSharpness: 8
_currentOutlineType: 0 _currentOutlineType: 0
_currentOpacityMultiplier: 1 _currentOpacityMultiplier: 1
--- !u!114 &-4132148316966952702
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 9211739394093953175}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1235f6bde9304d8f85079f2777bd4b3c, type: 3}
m_Name:
m_EditorClassIdentifier:
_managementType: 1

View File

@ -97,6 +97,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3} - targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
insertIndex: -1 insertIndex: -1
addedObject: {fileID: 5410819217098966190} addedObject: {fileID: 5410819217098966190}
- targetCorrespondingSourceObject: {fileID: 4438924429928472453, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
insertIndex: -1
addedObject: {fileID: -1096657863250535257}
m_SourcePrefab: {fileID: 100100000, guid: 1d634c3376e4a4684bc984ced9134847, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 1d634c3376e4a4684bc984ced9134847, type: 3}
--- !u!1 &580268897300907643 stripped --- !u!1 &580268897300907643 stripped
GameObject: GameObject:
@ -116,9 +119,12 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_interactionType: 1 _interactionType: 1
_holdTime: 0 _executionParameters:
_interactionMessageKey: Test _holdTime: 1
_displayParameters:
_messageKey:
_interactionAvailableFlows: 1 _interactionAvailableFlows: 1
_aiInteractionPoints: []
--- !u!114 &4545680930728379745 --- !u!114 &4545680930728379745
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -359,3 +365,15 @@ MonoBehaviour:
_outlineSharpness: 8 _outlineSharpness: 8
_currentOutlineType: 0 _currentOutlineType: 0
_currentOpacityMultiplier: 1 _currentOpacityMultiplier: 1
--- !u!114 &-1096657863250535257
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 580268897300907643}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1235f6bde9304d8f85079f2777bd4b3c, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@ -423,7 +423,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 81e01dd8c1cc3404d805400eba1bb4ae, type: 3} m_Script: {fileID: 11500000, guid: 81e01dd8c1cc3404d805400eba1bb4ae, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_interactionType: 4294967287 _availableInteractions: 1
_nearColliders: _nearColliders:
- {fileID: 0} - {fileID: 0}
- {fileID: 0} - {fileID: 0}

View File

@ -8,10 +8,9 @@ namespace DDD
public enum InteractionType : uint public enum InteractionType : uint
{ {
None = 0u, None = 0u,
RestaurantManagementUi = 1u << 0, RestaurantManagement = 1u << 0,
OpenRestaurant = 1u << 1, RestaurantOrder = 1u << 1,
RestaurantOrder = 1u << 2, RestaurantMeal = 1u << 2,
RestaurantMeal = 1u << 3,
All = 0xFFFFFFFFu All = 0xFFFFFFFFu
} }

View File

@ -5,7 +5,6 @@ namespace DDD
{ {
public interface IInteractionSubsystemObject public interface IInteractionSubsystemObject
{ {
Type GetSubsystemEnumType();
void InitializeSubsystem(); void InitializeSubsystem();
bool CanInteract(); bool CanInteract();
bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null); bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null);

View File

@ -0,0 +1,10 @@
using System;
using UnityEngine;
namespace DDD
{
public interface IInteractionSubsystemOwner
{
public bool TryGetSubsystemObject<T>(out IInteractionSubsystemObject<T> subsystemObject) where T : Enum;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 254d64ce6ee84b20a154931fcf04958f
timeCreated: 1755681729

View File

@ -1,16 +0,0 @@
using System;
namespace DDD
{
[Flags]
public enum RestaurantManagementType : uint
{
OpenRestaurantMenu = 0,
StartRestaurant = 1,
}
//public class RestaurantManagementInteraction : RestaurantInteractionComponent, IInteractionSubsystemObject<RestaurantManagementType>
//{
//
//}
}

View File

@ -0,0 +1,36 @@
using System;
using UnityEngine;
namespace DDD
{
[Flags]
public enum RestaurantManagementType : uint
{
OpenRestaurantMenu = 0,
StartRestaurant = 1,
}
public class RestaurantManagementInteractionSubsystem : MonoBehaviour, IInteractionSubsystemObject<RestaurantManagementType>
{
[SerializeField] protected RestaurantManagementType _managementType = RestaurantManagementType.OpenRestaurantMenu;
public RestaurantManagementType GetInteractionSubsystemType()
{
return _managementType;
}
public void InitializeSubsystem()
{
}
public bool CanInteract()
{
return true;
}
public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null)
{
return true;
}
}
}

View File

@ -16,8 +16,6 @@ public class RestaurantOrderInteractionSubsystem : MonoBehaviour, IInteractionSu
[SerializeField] protected RestaurantOrderType orderType = RestaurantOrderType.Wait; [SerializeField] protected RestaurantOrderType orderType = RestaurantOrderType.Wait;
private RestaurantOrderType currentRestaurantOrderType; private RestaurantOrderType currentRestaurantOrderType;
public Type GetSubsystemEnumType() => typeof(RestaurantOrderType);
private void Start() private void Start()
{ {
currentRestaurantOrderType = orderType; currentRestaurantOrderType = orderType;

View File

@ -1,3 +1,4 @@
using System;
using Spine.Unity; using Spine.Unity;
using Unity.VisualScripting; using Unity.VisualScripting;
using UnityEngine; using UnityEngine;

View File

@ -11,12 +11,13 @@ public static class RestaurantInteractionSubsystems
{ {
public static Dictionary<InteractionType, Type> TypeToSubsystem = new() public static Dictionary<InteractionType, Type> TypeToSubsystem = new()
{ {
{InteractionType.RestaurantOrder, typeof(RestaurantOrderInteractionSubsystem)} {InteractionType.RestaurantOrder, typeof(RestaurantOrderInteractionSubsystem)},
{InteractionType.RestaurantManagement, typeof(RestaurantManagementInteractionSubsystem)}
}; };
} }
public class RestaurantInteractionComponent : MonoBehaviour, IInteractable public class RestaurantInteractionComponent : MonoBehaviour, IInteractable, IInteractionSubsystemOwner
{ {
// Single interaction type // Single interaction type
[ValueDropdown("GetAllInteractionTypes")] [ValueDropdown("GetAllInteractionTypes")]
@ -25,9 +26,18 @@ public class RestaurantInteractionComponent : MonoBehaviour, IInteractable
[SerializeField] protected InteractionDisplayParameters _displayParameters = new InteractionDisplayParameters(""); [SerializeField] protected InteractionDisplayParameters _displayParameters = new InteractionDisplayParameters("");
[SerializeField] protected GameFlowState _interactionAvailableFlows; [SerializeField] protected GameFlowState _interactionAvailableFlows;
[SerializeField] private Transform[] _aiInteractionPoints; [SerializeField] private Transform[] _aiInteractionPoints;
[SerializeField] private bool autoInitialize = true;
private Dictionary<InteractionType, IInteractionSubsystemObject> _subsystems = new(); private Dictionary<InteractionType, IInteractionSubsystemObject> _subsystems = new();
private void Start()
{
if (autoInitialize)
{
InitializeInteraction(_interactionType);
}
}
private static IEnumerable GetAllInteractionTypes() private static IEnumerable GetAllInteractionTypes()
{ {
return System.Enum.GetValues(typeof(InteractionType)) return System.Enum.GetValues(typeof(InteractionType))
@ -153,5 +163,20 @@ public Vector3[] GetInteractionPoints()
} }
return positions; return positions;
} }
public bool TryGetSubsystemObject<T>(out IInteractionSubsystemObject<T> subsystemObject) where T : Enum
{
foreach (var interactionSubsystemObject in _subsystems.Values)
{
if (interactionSubsystemObject is IInteractionSubsystemObject<T> subsystem)
{
subsystemObject = subsystem;
return true;
}
}
subsystemObject = null;
return false;
}
} }
} }

View File

@ -13,8 +13,7 @@ public static class RestaurantInteractionEventSolvers
{ {
public static Dictionary<InteractionType, Type> TypeToSolver = new() public static Dictionary<InteractionType, Type> TypeToSolver = new()
{ {
{InteractionType.RestaurantManagementUi, typeof(RestaurantManagementUiEventSolver)}, {InteractionType.RestaurantManagement, typeof(RestaurantManagementSolver)},
{InteractionType.OpenRestaurant, typeof(RestaurantOpenEventSolver)},
{InteractionType.RestaurantOrder, typeof(RestaurantOrderSolver)} {InteractionType.RestaurantOrder, typeof(RestaurantOrderSolver)}
}; };
} }

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ad4643acb4b34f1ab27e79503ccff0dd
timeCreated: 1755677592

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using DDD.RestaurantOrders;
using UnityEngine;
namespace DDD
{
public static class RestaurantManagementSolvers
{
public static 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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c457857b6ba0432db546ef0d8970548d
timeCreated: 1755677639

View File

@ -2,11 +2,11 @@
namespace DDD namespace DDD
{ {
public class RestaurantManagementUiEventSolver : MonoBehaviour, IInteractionSolver public class RestaurantManagementSolver_Menu : MonoBehaviour, IInteractionSubsystemSolver<RestaurantManagementType>
{ {
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null) public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{ {
if (CanExecuteInteraction() == false) return false; if (CanExecuteInteractionSubsystem(interactor, interactable, payloadSo) == false) return false;
var evt = GameEvents.OpenPopupUiEvent; var evt = GameEvents.OpenPopupUiEvent;
evt.UiType = typeof(RestaurantManagementUi); evt.UiType = typeof(RestaurantManagementUi);
@ -14,7 +14,7 @@ public bool ExecuteInteraction(IInteractor interactor, IInteractable interactabl
return true; return true;
} }
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null) ScriptableObject payloadSo = null)
{ {
GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState; GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState;

View File

@ -3,22 +3,23 @@
namespace DDD namespace DDD
{ {
public class RestaurantOpenEventSolver : MonoBehaviour, IInteractionSolver public class RestaurantManagementSolver_Start : MonoBehaviour, IInteractionSubsystemSolver<RestaurantManagementType>
{ {
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null)
{
if (CanExecuteInteraction() == false) return false;
_ = GameFlowManager.Instance.ChangeFlow(GameFlowState.RunRestaurant);
return true;
}
private RestaurantManagementState GetManagementState() private RestaurantManagementState GetManagementState()
{ {
return RestaurantState.Instance.ManagementState; return RestaurantState.Instance.ManagementState;
} }
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, ScriptableObject payloadSo = null) public bool ExecuteInteractionSubsystem(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
if (CanExecuteInteractionSubsystem(interactor, interactable, payloadSo) == false) return false;
_ = GameFlowManager.Instance.ChangeFlow(GameFlowState.RunRestaurant);
return true;
}
public bool CanExecuteInteractionSubsystem(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{ {
GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState; GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState;

View File

@ -15,42 +15,11 @@ public static class RestaurantOrderSolvers
}; };
} }
public class RestaurantOrderSolver : MonoBehaviour, IInteractionSolver public class RestaurantOrderSolver : RestaurantSubsystemSolver<RestaurantOrderType>
{ {
private Dictionary<RestaurantOrderType, IInteractionSubsystemSolver<RestaurantOrderType>> _solvers = new(); protected override Dictionary<RestaurantOrderType, Type> GetSubsystemSolverTypeMappings()
private void Start()
{ {
foreach (var orderSolver in RestaurantOrderSolvers.TypeToOrderSolver) return RestaurantOrderSolvers.TypeToOrderSolver;
{
var solver = (IInteractionSubsystemSolver<RestaurantOrderType>)gameObject.AddComponent(orderSolver.Value);
_solvers.Add(orderSolver.Key, solver);
}
}
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
return TryGetSolver(interactable, out var solver) &&
solver.ExecuteInteractionSubsystem(interactor, interactable, payloadSo);
}
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
return TryGetSolver(interactable, out var solver) &&
solver.CanExecuteInteractionSubsystem(interactor, interactable, payloadSo);
}
// Solver를 가져오는 공통 로직
private bool TryGetSolver(IInteractable interactable, out IInteractionSubsystemSolver<RestaurantOrderType> solver)
{
solver = null;
if (interactable is not IInteractionSubsystemObject<RestaurantOrderType> subsystem)
return false;
var type = subsystem.GetInteractionSubsystemType();
return _solvers.TryGetValue(type, out solver);
} }
} }
} }

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace DDD
{
public abstract class RestaurantSubsystemSolver<T> : MonoBehaviour, IInteractionSolver where T : Enum
{
private Dictionary<T, IInteractionSubsystemSolver<T>> _solvers = new();
protected abstract Dictionary<T, Type> GetSubsystemSolverTypeMappings();
private void Start()
{
foreach (var subsystemSolverType in GetSubsystemSolverTypeMappings())
{
var solver = (IInteractionSubsystemSolver<T>)gameObject.AddComponent(subsystemSolverType.Value);
_solvers.Add(subsystemSolverType.Key, solver);
}
}
public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null)
{
return TryGetSolver(interactable, out var solver) &&
solver.ExecuteInteractionSubsystem(interactor, interactable, payloadSo);
}
public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null,
ScriptableObject payloadSo = null)
{
return TryGetSolver(interactable, out var solver) &&
solver.CanExecuteInteractionSubsystem(interactor, interactable, payloadSo);
}
// Solver를 가져오는 공통 로직
private bool TryGetSolver(IInteractable interactable, out IInteractionSubsystemSolver<T> solver)
{
solver = null;
var owner = interactable as IInteractionSubsystemOwner;
IInteractionSubsystemObject<T> subsystem = null;
bool isExist = owner != null && owner.TryGetSubsystemObject<T>(out subsystem);
if (!isExist || subsystem == null) return false;
var type = subsystem.GetInteractionSubsystemType();
return _solvers.TryGetValue(type, out solver);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 716224c78a914321b7b7e43a93860465
timeCreated: 1755677990