using UnityEngine; using System.Collections.Generic; using System.Linq; using Streamingle; using UnityRawInput; using UnityEngine.Events; public class EventController : MonoBehaviour, IController { #region Classes [System.Serializable] public class EventGroup { [Header("Event Settings")] public string groupName = "New Event Group"; public UnityEvent unityEvent = new UnityEvent(); [Header("Hotkey Settings")] public List hotkeys = new List(); [System.NonSerialized] public bool isRecording = false; [System.NonSerialized] private List unityKeys = new List(); [System.NonSerialized] private float recordStartTime; [System.NonSerialized] private const float MAX_RECORD_TIME = 2f; public EventGroup(string name) { groupName = name; hotkeys = new List(); unityEvent = new UnityEvent(); } public void StartRecording() { isRecording = true; recordStartTime = Time.time; hotkeys.Clear(); } public void StopRecording() { isRecording = false; InitializeUnityKeys(); } public void UpdateRecording() { if (!isRecording) return; if (Time.time - recordStartTime > MAX_RECORD_TIME) { StopRecording(); return; } foreach (KeyCode keyCode in System.Enum.GetValues(typeof(KeyCode))) { if (Input.GetKeyDown(keyCode) && KeyMapping.TryGetRawKey(keyCode, out RawKey rawKey)) { if (!hotkeys.Contains(rawKey)) { hotkeys.Add(rawKey); } } } bool allKeysReleased = hotkeys.Any() && hotkeys.All(key => !Input.GetKey(KeyMapping.TryGetKeyCode(key, out KeyCode keyCode) ? keyCode : KeyCode.None)); if (allKeysReleased) { StopRecording(); } } public void InitializeUnityKeys() { unityKeys.Clear(); if (hotkeys == null || !hotkeys.Any()) return; foreach (var hotkey in hotkeys) { if (KeyMapping.TryGetKeyCode(hotkey, out KeyCode keyCode) && keyCode != KeyCode.None) { unityKeys.Add(keyCode); } } } public bool IsTriggered() { if (isRecording) return false; if (hotkeys == null || !hotkeys.Any()) return false; bool allHotkeysPressed = hotkeys.All(key => RawInput.IsKeyDown(key)); if (allHotkeysPressed) return true; if (unityKeys.Any()) { return unityKeys.All(key => Input.GetKey(key)); } return false; } public void ExecuteEvent() { if (unityEvent != null) { unityEvent.Invoke(); } } public override string ToString() => hotkeys?.Any() == true ? $"{groupName} ({string.Join(" + ", hotkeys)})" : $"{groupName} (설정되지 않음)"; } private static class KeyMapping { private static readonly Dictionary _mapping; static KeyMapping() { _mapping = new Dictionary(RawKeySetup.KeyMapping); } public static bool TryGetRawKey(KeyCode keyCode, out RawKey rawKey) { return _mapping.TryGetValue(keyCode, out rawKey); } public static bool TryGetKeyCode(RawKey rawKey, out KeyCode keyCode) { var pair = _mapping.FirstOrDefault(x => x.Value == rawKey); keyCode = pair.Key; return keyCode != KeyCode.None; } public static bool IsValidRawKey(RawKey key) { return _mapping.ContainsValue(key); } } #endregion #region Events public delegate void EventGroupExecutedEventHandler(EventGroup eventGroup); public event EventGroupExecutedEventHandler OnEventExecuted; #endregion #region Fields [SerializeField] public List eventGroups = new List(); [Header("Event Control Settings")] [SerializeField] private bool autoFindEvents = false; // 태그 기능 비활성화 private EventGroup currentGroup; private StreamDeckServerManager streamDeckManager; #endregion #region Properties public EventGroup CurrentGroup => currentGroup; public int CurrentIndex => eventGroups.IndexOf(currentGroup); #endregion #region Unity Messages private void Awake() { InitializeEventGroups(); InitializeRawInput(); // StreamDeckServerManager 찾기 streamDeckManager = FindObjectOfType(); if (streamDeckManager == null) { Debug.LogWarning("[EventController] StreamDeckServerManager를 찾을 수 없습니다. 스트림덱 연동이 비활성화됩니다."); } } private void OnDestroy() { if (RawInput.IsRunning) { RawInput.OnKeyDown -= HandleRawKeyDown; RawInput.Stop(); } } private void Update() { UpdateHotkeyRecording(); HandleHotkeys(); } #endregion #region Initialization public void InitializeEventGroups() { // 태그 기능 제거 - 수동으로 이벤트 그룹을 추가해야 함 // 첫 번째 그룹을 기본으로 설정 if (eventGroups.Count > 0 && currentGroup == null) { currentGroup = eventGroups[0]; } Debug.Log($"[EventController] {eventGroups.Count}개의 이벤트 그룹이 초기화되었습니다."); } private void InitializeRawInput() { if (!RawInput.IsRunning) { RawInput.Start(); RawInput.WorkInBackground = true; } // 중복 구독 방지를 위해 먼저 해제 후 구독 RawInput.OnKeyDown -= HandleRawKeyDown; RawInput.OnKeyDown += HandleRawKeyDown; } private void UpdateHotkeyRecording() { foreach (var group in eventGroups) { if (group.isRecording) { group.UpdateRecording(); } } } private void HandleRawKeyDown(RawKey key) { // 핫키 레코딩 중일 때는 처리하지 않음 if (eventGroups.Any(g => g.isRecording)) return; } private void HandleHotkeys() { foreach (var group in eventGroups) { if (group.IsTriggered()) { ExecuteEvent(group); } } } #endregion #region Public Methods public void Set(int index) { if (index < 0 || index >= eventGroups.Count) { Debug.LogWarning($"[EventController] 유효하지 않은 인덱스: {index}"); return; } currentGroup = eventGroups[index]; Debug.Log($"[EventController] 현재 이벤트 그룹: {currentGroup.groupName}"); // StreamDeck에 알림 if (streamDeckManager != null) { streamDeckManager.NotifyEventChanged(); } } public void ExecuteEvent(int index) { if (index < 0 || index >= eventGroups.Count) { Debug.LogWarning($"[EventController] 유효하지 않은 인덱스: {index}"); return; } ExecuteEvent(eventGroups[index]); } public void ExecuteEvent(EventGroup group) { if (group == null) { Debug.LogWarning("[EventController] 이벤트 그룹이 null입니다."); return; } Debug.Log($"[EventController] 이벤트 실행: {group.groupName}"); group.ExecuteEvent(); // 이벤트 발생 알림 OnEventExecuted?.Invoke(group); // StreamDeck에 알림 if (streamDeckManager != null) { streamDeckManager.NotifyEventChanged(); } } public void ExecuteCurrentEvent() { if (currentGroup != null) { ExecuteEvent(currentGroup); } else { Debug.LogWarning("[EventController] 현재 이벤트 그룹이 설정되지 않았습니다."); } } public void AddGroup(string groupName, GameObject targetObject = null) { var newGroup = new EventGroup(groupName); if (targetObject != null) { // 대상 오브젝트에 UnityEvent 컴포넌트가 있다면 연결 var eventComponent = targetObject.GetComponent(); if (eventComponent != null) { newGroup.unityEvent = eventComponent; } } eventGroups.Add(newGroup); Debug.Log($"[EventController] 이벤트 그룹 추가: {groupName}"); } public void RemoveGroup(int index) { if (index < 0 || index >= eventGroups.Count) { Debug.LogWarning($"[EventController] 유효하지 않은 인덱스: {index}"); return; } var groupToRemove = eventGroups[index]; eventGroups.RemoveAt(index); if (currentGroup == groupToRemove) { currentGroup = eventGroups.Count > 0 ? eventGroups[0] : null; } Debug.Log($"[EventController] 이벤트 그룹 제거: {groupToRemove.groupName}"); } public void StartRecordingHotkey(int groupIndex) { if (groupIndex < 0 || groupIndex >= eventGroups.Count) { Debug.LogWarning($"[EventController] 유효하지 않은 인덱스: {groupIndex}"); return; } eventGroups[groupIndex].StartRecording(); Debug.Log($"[EventController] 핫키 레코딩 시작: {eventGroups[groupIndex].groupName}"); } public void StopRecordingHotkey(int groupIndex) { if (groupIndex < 0 || groupIndex >= eventGroups.Count) { Debug.LogWarning($"[EventController] 유효하지 않은 인덱스: {groupIndex}"); return; } eventGroups[groupIndex].StopRecording(); Debug.Log($"[EventController] 핫키 레코딩 종료: {eventGroups[groupIndex].groupName}"); } private void NotifyEventChanged() { // StreamDeck에 이벤트 변경 알림 if (streamDeckManager != null) { streamDeckManager.NotifyEventChanged(); } } #endregion #region StreamDeck Integration public EventListData GetEventListData() { var eventData = new EventPresetData[eventGroups.Count]; for (int i = 0; i < eventGroups.Count; i++) { var group = eventGroups[i]; eventData[i] = new EventPresetData { index = i, name = group.groupName, hotkey = group.hotkeys.Any() ? string.Join(" + ", group.hotkeys) : "설정되지 않음" }; } return new EventListData { event_count = eventGroups.Count, events = eventData, current_index = CurrentIndex }; } public EventStateData GetCurrentEventState() { return new EventStateData { current_index = CurrentIndex, event_name = currentGroup?.groupName ?? "없음", total_events = eventGroups.Count }; } public string GetEventListJson() { return JsonUtility.ToJson(GetEventListData()); } public string GetEventStateJson() { return JsonUtility.ToJson(GetCurrentEventState()); } #endregion #region Data Classes [System.Serializable] public class EventPresetData { public int index; public string name; public string hotkey; } [System.Serializable] public class EventListData { public int event_count; public EventPresetData[] events; public int current_index; } [System.Serializable] public class EventStateData { public int current_index; public string event_name; public int total_events; } #endregion #region IController Implementation public string GetControllerId() { return "event_controller"; } public string GetControllerName() { return "Event Controller"; } public object GetControllerData() { return GetEventListData(); } public void ExecuteAction(string actionId, object parameters) { switch (actionId) { case "execute_event": if (parameters is int executeIndex) { ExecuteEvent(executeIndex); } break; case "set_event": if (parameters is int setIndex) { Set(setIndex); } break; default: Debug.LogWarning($"[EventController] 알 수 없는 액션: {actionId}"); break; } } #endregion }