494 lines
13 KiB
C#
494 lines
13 KiB
C#
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<RawKey> hotkeys = new List<RawKey>();
|
|
[System.NonSerialized] public bool isRecording = false;
|
|
[System.NonSerialized] private List<KeyCode> unityKeys = new List<KeyCode>();
|
|
[System.NonSerialized] private float recordStartTime;
|
|
[System.NonSerialized] private const float MAX_RECORD_TIME = 2f;
|
|
|
|
public EventGroup(string name)
|
|
{
|
|
groupName = name;
|
|
hotkeys = new List<RawKey>();
|
|
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<KeyCode, RawKey> _mapping;
|
|
|
|
static KeyMapping()
|
|
{
|
|
_mapping = new Dictionary<KeyCode, RawKey>(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<EventGroup> eventGroups = new List<EventGroup>();
|
|
|
|
[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<StreamDeckServerManager>();
|
|
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<UnityEvent>();
|
|
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
|
|
} |