Fix : 스트림덱 코드 추가 이벤트 컨트롤러 추가 및 자동화 세팅 기능 추가
This commit is contained in:
parent
624e117a2a
commit
cbdd8228ce
493
Assets/Scripts/Editor/StreamingleControllerSetupToolAdvanced.cs
Normal file
493
Assets/Scripts/Editor/StreamingleControllerSetupToolAdvanced.cs
Normal file
@ -0,0 +1,493 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Streamingle.Editor
|
||||
{
|
||||
public class StreamingleControllerSetupToolAdvanced : EditorWindow
|
||||
{
|
||||
private bool createCameraManager = true;
|
||||
private bool createItemController = true;
|
||||
private bool createEventController = true;
|
||||
private bool createStreamDeckManager = true;
|
||||
|
||||
private string parentObjectName = "Streamingle 컨트롤러들";
|
||||
private bool createParentObject = true;
|
||||
|
||||
// 고급 옵션
|
||||
private bool autoConnectExistingControllers = true;
|
||||
private bool setupDefaultSettings = true;
|
||||
private bool createSampleData = false;
|
||||
private bool moveExistingControllersToParent = true;
|
||||
|
||||
// 기존 컨트롤러 참조
|
||||
private StreamDeckServerManager existingStreamDeckManager;
|
||||
private CameraManager existingCameraManager;
|
||||
private ItemController existingItemController;
|
||||
private EventController existingEventController;
|
||||
|
||||
[MenuItem("Tools/Streamingle/고급 컨트롤러 설정 도구")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GetWindow<StreamingleControllerSetupToolAdvanced>("고급 Streamingle 설정");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
FindExistingControllers();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Label("고급 Streamingle 컨트롤러 설정 도구", EditorStyles.boldLabel);
|
||||
GUILayout.Space(10);
|
||||
|
||||
// 기존 컨트롤러 상태 표시
|
||||
ShowExistingControllersStatus();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// 부모 오브젝트 설정
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
GUILayout.Label("부모 오브젝트 설정", EditorStyles.boldLabel);
|
||||
createParentObject = EditorGUILayout.Toggle("부모 오브젝트 생성", createParentObject);
|
||||
if (createParentObject)
|
||||
{
|
||||
parentObjectName = EditorGUILayout.TextField("부모 오브젝트 이름", parentObjectName);
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// 컨트롤러 선택
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
GUILayout.Label("생성할 컨트롤러들", EditorStyles.boldLabel);
|
||||
|
||||
createStreamDeckManager = EditorGUILayout.Toggle("StreamDeck 서버 매니저", createStreamDeckManager);
|
||||
createCameraManager = EditorGUILayout.Toggle("카메라 매니저", createCameraManager);
|
||||
createItemController = EditorGUILayout.Toggle("아이템 컨트롤러", createItemController);
|
||||
createEventController = EditorGUILayout.Toggle("이벤트 컨트롤러", createEventController);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// 고급 옵션
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
GUILayout.Label("고급 옵션", EditorStyles.boldLabel);
|
||||
|
||||
autoConnectExistingControllers = EditorGUILayout.Toggle("기존 컨트롤러 자동 연결", autoConnectExistingControllers);
|
||||
setupDefaultSettings = EditorGUILayout.Toggle("기본 설정 구성", setupDefaultSettings);
|
||||
createSampleData = EditorGUILayout.Toggle("샘플 데이터 생성", createSampleData);
|
||||
moveExistingControllersToParent = EditorGUILayout.Toggle("기존 컨트롤러를 부모 하위로 이동", moveExistingControllersToParent);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
GUILayout.Space(20);
|
||||
|
||||
// 버튼들
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("선택된 컨트롤러들 생성", GUILayout.Height(30)))
|
||||
{
|
||||
CreateControllers();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("기존 컨트롤러들 연결", GUILayout.Height(30)))
|
||||
{
|
||||
ConnectExistingControllers();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("컨트롤러 상태 새로고침", GUILayout.Height(25)))
|
||||
{
|
||||
FindExistingControllers();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("기존 컨트롤러들을 부모 하위로 이동", GUILayout.Height(25)))
|
||||
{
|
||||
MoveExistingControllersToParent();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// 정보 표시
|
||||
EditorGUILayout.HelpBox(
|
||||
"자동 감지 및 연결 기능이 포함된 고급 설정 도구입니다.\n" +
|
||||
"'기존 컨트롤러들 연결'을 사용하여 찾은 컨트롤러들을 StreamDeck 매니저에 연결하세요.\n" +
|
||||
"'기존 컨트롤러들을 부모 하위로 이동'을 사용하여 발견된 컨트롤러들을 정리하세요.",
|
||||
MessageType.Info
|
||||
);
|
||||
}
|
||||
|
||||
private void ShowExistingControllersStatus()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
GUILayout.Label("기존 컨트롤러 상태", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("StreamDeck 서버 매니저:", GUILayout.Width(200));
|
||||
if (existingStreamDeckManager != null)
|
||||
{
|
||||
string parentInfo = GetParentInfo(existingStreamDeckManager.transform);
|
||||
EditorGUILayout.LabelField($"✓ 발견됨 {parentInfo}", EditorStyles.boldLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("✗ 발견되지 않음", EditorStyles.boldLabel);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("카메라 매니저:", GUILayout.Width(200));
|
||||
if (existingCameraManager != null)
|
||||
{
|
||||
string parentInfo = GetParentInfo(existingCameraManager.transform);
|
||||
EditorGUILayout.LabelField($"✓ 발견됨 {parentInfo}", EditorStyles.boldLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("✗ 발견되지 않음", EditorStyles.boldLabel);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("아이템 컨트롤러:", GUILayout.Width(200));
|
||||
if (existingItemController != null)
|
||||
{
|
||||
string parentInfo = GetParentInfo(existingItemController.transform);
|
||||
EditorGUILayout.LabelField($"✓ 발견됨 {parentInfo}", EditorStyles.boldLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("✗ 발견되지 않음", EditorStyles.boldLabel);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Label("이벤트 컨트롤러:", GUILayout.Width(200));
|
||||
if (existingEventController != null)
|
||||
{
|
||||
string parentInfo = GetParentInfo(existingEventController.transform);
|
||||
EditorGUILayout.LabelField($"✓ 발견됨 {parentInfo}", EditorStyles.boldLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("✗ 발견되지 않음", EditorStyles.boldLabel);
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private string GetParentInfo(Transform transform)
|
||||
{
|
||||
if (transform.parent == null)
|
||||
{
|
||||
return "(루트)";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"({transform.parent.name} 하위)";
|
||||
}
|
||||
}
|
||||
|
||||
private void FindExistingControllers()
|
||||
{
|
||||
existingStreamDeckManager = FindObjectOfType<StreamDeckServerManager>();
|
||||
existingCameraManager = FindObjectOfType<CameraManager>();
|
||||
existingItemController = FindObjectOfType<ItemController>();
|
||||
existingEventController = FindObjectOfType<EventController>();
|
||||
}
|
||||
|
||||
private void CreateControllers()
|
||||
{
|
||||
GameObject parentObject = null;
|
||||
|
||||
// 부모 오브젝트 생성
|
||||
if (createParentObject)
|
||||
{
|
||||
parentObject = new GameObject(parentObjectName);
|
||||
UnityEngine.Debug.Log($"부모 오브젝트 생성됨: {parentObjectName}");
|
||||
}
|
||||
|
||||
// StreamDeck Server Manager 생성
|
||||
if (createStreamDeckManager && existingStreamDeckManager == null)
|
||||
{
|
||||
CreateStreamDeckManager(parentObject);
|
||||
}
|
||||
|
||||
// Camera Manager 생성
|
||||
if (createCameraManager && existingCameraManager == null)
|
||||
{
|
||||
CreateCameraManager(parentObject);
|
||||
}
|
||||
|
||||
// Item Controller 생성
|
||||
if (createItemController && existingItemController == null)
|
||||
{
|
||||
CreateItemController(parentObject);
|
||||
}
|
||||
|
||||
// Event Controller 생성
|
||||
if (createEventController && existingEventController == null)
|
||||
{
|
||||
CreateEventController(parentObject);
|
||||
}
|
||||
|
||||
// 기존 컨트롤러들을 부모 하위로 이동
|
||||
if (moveExistingControllersToParent && parentObject != null)
|
||||
{
|
||||
MoveExistingControllersToParent(parentObject);
|
||||
}
|
||||
|
||||
// 생성된 오브젝트들을 선택
|
||||
if (parentObject != null)
|
||||
{
|
||||
Selection.activeGameObject = parentObject;
|
||||
EditorGUIUtility.PingObject(parentObject);
|
||||
}
|
||||
|
||||
// 기존 컨트롤러 상태 업데이트
|
||||
FindExistingControllers();
|
||||
|
||||
UnityEngine.Debug.Log("Streamingle 컨트롤러 설정 완료!");
|
||||
}
|
||||
|
||||
private void MoveExistingControllersToParent(GameObject parent = null)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
// 기존 부모 오브젝트 찾기 또는 생성
|
||||
parent = GameObject.Find(parentObjectName);
|
||||
if (parent == null)
|
||||
{
|
||||
parent = new GameObject(parentObjectName);
|
||||
UnityEngine.Debug.Log($"부모 오브젝트 생성됨: {parentObjectName}");
|
||||
}
|
||||
}
|
||||
|
||||
int movedCount = 0;
|
||||
|
||||
// StreamDeck Server Manager 이동
|
||||
if (existingStreamDeckManager != null && existingStreamDeckManager.transform.parent != parent.transform)
|
||||
{
|
||||
existingStreamDeckManager.transform.SetParent(parent.transform);
|
||||
movedCount++;
|
||||
UnityEngine.Debug.Log($"StreamDeck 서버 매니저를 {parent.name} 하위로 이동");
|
||||
}
|
||||
|
||||
// Camera Manager 이동
|
||||
if (existingCameraManager != null && existingCameraManager.transform.parent != parent.transform)
|
||||
{
|
||||
existingCameraManager.transform.SetParent(parent.transform);
|
||||
movedCount++;
|
||||
UnityEngine.Debug.Log($"카메라 매니저를 {parent.name} 하위로 이동");
|
||||
}
|
||||
|
||||
// Item Controller 이동
|
||||
if (existingItemController != null && existingItemController.transform.parent != parent.transform)
|
||||
{
|
||||
existingItemController.transform.SetParent(parent.transform);
|
||||
movedCount++;
|
||||
UnityEngine.Debug.Log($"아이템 컨트롤러를 {parent.name} 하위로 이동");
|
||||
}
|
||||
|
||||
// Event Controller 이동
|
||||
if (existingEventController != null && existingEventController.transform.parent != parent.transform)
|
||||
{
|
||||
existingEventController.transform.SetParent(parent.transform);
|
||||
movedCount++;
|
||||
UnityEngine.Debug.Log($"이벤트 컨트롤러를 {parent.name} 하위로 이동");
|
||||
}
|
||||
|
||||
if (movedCount > 0)
|
||||
{
|
||||
UnityEngine.Debug.Log($"{movedCount}개의 컨트롤러를 {parent.name} 하위로 이동했습니다.");
|
||||
|
||||
// 부모 오브젝트 선택
|
||||
Selection.activeGameObject = parent;
|
||||
EditorGUIUtility.PingObject(parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.Log("이동할 컨트롤러가 없습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectExistingControllers()
|
||||
{
|
||||
if (existingStreamDeckManager == null)
|
||||
{
|
||||
UnityEngine.Debug.LogError("StreamDeck 서버 매니저를 찾을 수 없습니다! 먼저 생성해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// StreamDeck Manager에 컨트롤러들 연결
|
||||
SerializedObject serializedObject = new SerializedObject(existingStreamDeckManager);
|
||||
serializedObject.Update();
|
||||
|
||||
// Camera Manager 연결
|
||||
if (existingCameraManager != null)
|
||||
{
|
||||
var cameraManagerProperty = serializedObject.FindProperty("cameraManager");
|
||||
if (cameraManagerProperty != null)
|
||||
{
|
||||
cameraManagerProperty.objectReferenceValue = existingCameraManager;
|
||||
}
|
||||
}
|
||||
|
||||
// Item Controller 연결
|
||||
if (existingItemController != null)
|
||||
{
|
||||
var itemControllerProperty = serializedObject.FindProperty("itemController");
|
||||
if (itemControllerProperty != null)
|
||||
{
|
||||
itemControllerProperty.objectReferenceValue = existingItemController;
|
||||
}
|
||||
}
|
||||
|
||||
// Event Controller 연결
|
||||
if (existingEventController != null)
|
||||
{
|
||||
var eventControllerProperty = serializedObject.FindProperty("eventController");
|
||||
if (eventControllerProperty != null)
|
||||
{
|
||||
eventControllerProperty.objectReferenceValue = existingEventController;
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
UnityEngine.Debug.Log("기존 컨트롤러들을 StreamDeck 서버 매니저에 연결했습니다!");
|
||||
}
|
||||
|
||||
private void CreateStreamDeckManager(GameObject parent)
|
||||
{
|
||||
GameObject streamDeckObject = new GameObject("StreamDeck 서버 매니저");
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
streamDeckObject.transform.SetParent(parent.transform);
|
||||
}
|
||||
|
||||
// StreamDeckServerManager 스크립트 추가
|
||||
var streamDeckManager = streamDeckObject.AddComponent<StreamDeckServerManager>();
|
||||
|
||||
// 기본 설정
|
||||
SerializedObject serializedObject = new SerializedObject(streamDeckManager);
|
||||
serializedObject.Update();
|
||||
|
||||
// 포트 설정 (기본값: 10701)
|
||||
var portProperty = serializedObject.FindProperty("port");
|
||||
if (portProperty != null)
|
||||
{
|
||||
portProperty.intValue = 10701;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
UnityEngine.Debug.Log("StreamDeck 서버 매니저 생성됨");
|
||||
}
|
||||
|
||||
private void CreateCameraManager(GameObject parent)
|
||||
{
|
||||
GameObject cameraObject = new GameObject("카메라 매니저");
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
cameraObject.transform.SetParent(parent.transform);
|
||||
}
|
||||
|
||||
// CameraManager 스크립트 추가
|
||||
var cameraManager = cameraObject.AddComponent<CameraManager>();
|
||||
|
||||
// 기본 설정
|
||||
SerializedObject serializedObject = new SerializedObject(cameraManager);
|
||||
serializedObject.Update();
|
||||
|
||||
// 카메라 프리셋 리스트 초기화
|
||||
var cameraPresetsProperty = serializedObject.FindProperty("cameraPresets");
|
||||
if (cameraPresetsProperty != null)
|
||||
{
|
||||
cameraPresetsProperty.ClearArray();
|
||||
cameraPresetsProperty.arraySize = 0;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
UnityEngine.Debug.Log("카메라 매니저 생성됨");
|
||||
}
|
||||
|
||||
private void CreateItemController(GameObject parent)
|
||||
{
|
||||
GameObject itemObject = new GameObject("아이템 컨트롤러");
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
itemObject.transform.SetParent(parent.transform);
|
||||
}
|
||||
|
||||
// ItemController 스크립트 추가
|
||||
var itemController = itemObject.AddComponent<ItemController>();
|
||||
|
||||
// 기본 설정
|
||||
SerializedObject serializedObject = new SerializedObject(itemController);
|
||||
serializedObject.Update();
|
||||
|
||||
// 아이템 그룹 리스트 초기화
|
||||
var itemGroupsProperty = serializedObject.FindProperty("itemGroups");
|
||||
if (itemGroupsProperty != null)
|
||||
{
|
||||
itemGroupsProperty.ClearArray();
|
||||
itemGroupsProperty.arraySize = 0;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
UnityEngine.Debug.Log("아이템 컨트롤러 생성됨");
|
||||
}
|
||||
|
||||
private void CreateEventController(GameObject parent)
|
||||
{
|
||||
GameObject eventObject = new GameObject("이벤트 컨트롤러");
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
eventObject.transform.SetParent(parent.transform);
|
||||
}
|
||||
|
||||
// EventController 스크립트 추가
|
||||
var eventController = eventObject.AddComponent<EventController>();
|
||||
|
||||
// 기본 설정
|
||||
SerializedObject serializedObject = new SerializedObject(eventController);
|
||||
serializedObject.Update();
|
||||
|
||||
// 이벤트 그룹 리스트 초기화
|
||||
var eventGroupsProperty = serializedObject.FindProperty("eventGroups");
|
||||
if (eventGroupsProperty != null)
|
||||
{
|
||||
eventGroupsProperty.ClearArray();
|
||||
eventGroupsProperty.arraySize = 0;
|
||||
}
|
||||
|
||||
// 자동 찾기 비활성화
|
||||
var autoFindEventsProperty = serializedObject.FindProperty("autoFindEvents");
|
||||
if (autoFindEventsProperty != null)
|
||||
{
|
||||
autoFindEventsProperty.boolValue = false;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
UnityEngine.Debug.Log("이벤트 컨트롤러 생성됨");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84a4d570d6f8faa44bafc90ed4780108
|
||||
@ -14,6 +14,7 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
private List<StreamDeckService> connectedClients = new List<StreamDeckService>();
|
||||
public CameraManager cameraManager { get; private set; }
|
||||
public ItemController itemController { get; private set; }
|
||||
public EventController eventController { get; private set; }
|
||||
|
||||
// 싱글톤 패턴으로 StreamDeckService에서 접근 가능하도록
|
||||
public static StreamDeckServerManager Instance { get; private set; }
|
||||
@ -44,6 +45,13 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
Debug.LogWarning("[StreamDeckServerManager] ItemController를 찾을 수 없습니다. 아이템 컨트롤 기능이 비활성화됩니다.");
|
||||
}
|
||||
|
||||
// EventController 찾기
|
||||
eventController = FindObjectOfType<EventController>();
|
||||
if (eventController == null)
|
||||
{
|
||||
Debug.LogWarning("[StreamDeckServerManager] EventController를 찾을 수 없습니다. 이벤트 컨트롤 기능이 비활성화됩니다.");
|
||||
}
|
||||
|
||||
StartServer();
|
||||
}
|
||||
|
||||
@ -152,7 +160,9 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
camera_data = cameraManager.GetCameraListData(),
|
||||
current_camera = cameraManager.GetCurrentCameraState(),
|
||||
item_data = itemController?.GetItemListData(),
|
||||
current_item = itemController?.GetCurrentItemState()
|
||||
current_item = itemController?.GetCurrentItemState(),
|
||||
event_data = eventController?.GetEventListData(),
|
||||
current_event = eventController?.GetCurrentEventState()
|
||||
}
|
||||
};
|
||||
|
||||
@ -221,6 +231,28 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
Debug.Log("[StreamDeckServerManager] 아이템 변경 알림 전송됨");
|
||||
}
|
||||
|
||||
// 이벤트 변경 시 모든 클라이언트에게 알림
|
||||
public void NotifyEventChanged()
|
||||
{
|
||||
if (eventController == null) return;
|
||||
|
||||
var updateMessage = new
|
||||
{
|
||||
type = "event_changed",
|
||||
timestamp = DateTime.UtcNow.ToString("o"),
|
||||
version = "1.0",
|
||||
data = new
|
||||
{
|
||||
event_data = eventController.GetEventListData(),
|
||||
current_event = eventController.GetCurrentEventState()
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(updateMessage);
|
||||
BroadcastMessage(json);
|
||||
Debug.Log("[StreamDeckServerManager] 이벤트 변경 알림 전송됨");
|
||||
}
|
||||
|
||||
// 메시지 처리 로직을 여기로 이동
|
||||
private void ProcessMessage(string messageData, StreamDeckService service)
|
||||
{
|
||||
@ -250,6 +282,18 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
HandleGetItemList(service);
|
||||
break;
|
||||
|
||||
case "execute_event":
|
||||
HandleExecuteEvent(message);
|
||||
break;
|
||||
|
||||
case "set_event":
|
||||
HandleSetEvent(message);
|
||||
break;
|
||||
|
||||
case "get_event_list":
|
||||
HandleGetEventList(service);
|
||||
break;
|
||||
|
||||
case "test":
|
||||
// 테스트 메시지 에코 응답
|
||||
var response = new
|
||||
@ -587,6 +631,202 @@ public class StreamDeckServerManager : MonoBehaviour
|
||||
string json = JsonConvert.SerializeObject(response);
|
||||
service.SendMessage(json);
|
||||
}
|
||||
|
||||
private void HandleExecuteEvent(Dictionary<string, object> message)
|
||||
{
|
||||
Debug.Log($"[StreamDeckServerManager] 이벤트 실행 요청 수신");
|
||||
|
||||
if (eventController == null)
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] eventController가 null입니다!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (message.ContainsKey("data"))
|
||||
{
|
||||
var dataObject = message["data"];
|
||||
|
||||
if (dataObject is Newtonsoft.Json.Linq.JObject jObject)
|
||||
{
|
||||
if (jObject.ContainsKey("event_index"))
|
||||
{
|
||||
var eventIndexToken = jObject["event_index"];
|
||||
|
||||
if (int.TryParse(eventIndexToken?.ToString(), out int eventIndex))
|
||||
{
|
||||
if (eventIndex >= 0 && eventIndex < (eventController.eventGroups?.Count ?? 0))
|
||||
{
|
||||
Debug.Log($"[StreamDeckServerManager] 이벤트 {eventIndex}번 실행");
|
||||
eventController.ExecuteEvent(eventIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] 잘못된 이벤트 인덱스: {eventIndex}, 유효 범위: 0-{(eventController.eventGroups?.Count ?? 0) - 1}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] event_index 파싱 실패: {eventIndexToken}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] data에 'event_index' 키가 없습니다");
|
||||
}
|
||||
}
|
||||
else if (dataObject is Dictionary<string, object> data)
|
||||
{
|
||||
if (data.ContainsKey("event_index"))
|
||||
{
|
||||
var eventIndexObj = data["event_index"];
|
||||
|
||||
if (int.TryParse(eventIndexObj?.ToString(), out int eventIndex))
|
||||
{
|
||||
if (eventIndex >= 0 && eventIndex < (eventController.eventGroups?.Count ?? 0))
|
||||
{
|
||||
Debug.Log($"[StreamDeckServerManager] 이벤트 {eventIndex}번 실행");
|
||||
eventController.ExecuteEvent(eventIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] 잘못된 이벤트 인덱스: {eventIndex}, 유효 범위: 0-{(eventController.eventGroups?.Count ?? 0) - 1}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] event_index 파싱 실패: {eventIndexObj}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] data에 'event_index' 키가 없습니다");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] data가 예상된 타입이 아닙니다: {dataObject?.GetType().Name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] 메시지에 'data' 키가 없습니다");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] 이벤트 실행 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSetEvent(Dictionary<string, object> message)
|
||||
{
|
||||
Debug.Log($"[StreamDeckServerManager] 이벤트 설정 요청 수신");
|
||||
|
||||
if (eventController == null)
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] eventController가 null입니다!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (message.ContainsKey("data"))
|
||||
{
|
||||
var dataObject = message["data"];
|
||||
|
||||
if (dataObject is Newtonsoft.Json.Linq.JObject jObject)
|
||||
{
|
||||
if (jObject.ContainsKey("event_index"))
|
||||
{
|
||||
var eventIndexToken = jObject["event_index"];
|
||||
|
||||
if (int.TryParse(eventIndexToken?.ToString(), out int eventIndex))
|
||||
{
|
||||
if (eventIndex >= 0 && eventIndex < (eventController.eventGroups?.Count ?? 0))
|
||||
{
|
||||
Debug.Log($"[StreamDeckServerManager] 이벤트 {eventIndex}번으로 설정");
|
||||
eventController.Set(eventIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] 잘못된 이벤트 인덱스: {eventIndex}, 유효 범위: 0-{(eventController.eventGroups?.Count ?? 0) - 1}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] event_index 파싱 실패: {eventIndexToken}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] data에 'event_index' 키가 없습니다");
|
||||
}
|
||||
}
|
||||
else if (dataObject is Dictionary<string, object> data)
|
||||
{
|
||||
if (data.ContainsKey("event_index"))
|
||||
{
|
||||
var eventIndexObj = data["event_index"];
|
||||
|
||||
if (int.TryParse(eventIndexObj?.ToString(), out int eventIndex))
|
||||
{
|
||||
if (eventIndex >= 0 && eventIndex < (eventController.eventGroups?.Count ?? 0))
|
||||
{
|
||||
Debug.Log($"[StreamDeckServerManager] 이벤트 {eventIndex}번으로 설정");
|
||||
eventController.Set(eventIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] 잘못된 이벤트 인덱스: {eventIndex}, 유효 범위: 0-{(eventController.eventGroups?.Count ?? 0) - 1}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] event_index 파싱 실패: {eventIndexObj}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] data에 'event_index' 키가 없습니다");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] data가 예상된 타입이 아닙니다: {dataObject?.GetType().Name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StreamDeckServerManager] 메시지에 'data' 키가 없습니다");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[StreamDeckServerManager] 이벤트 설정 실패: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleGetEventList(StreamDeckService service)
|
||||
{
|
||||
if (eventController == null) return;
|
||||
|
||||
var response = new
|
||||
{
|
||||
type = "event_list_response",
|
||||
timestamp = DateTime.UtcNow.ToString("o"),
|
||||
version = "1.0",
|
||||
data = new
|
||||
{
|
||||
event_data = eventController.GetEventListData(),
|
||||
current_event = eventController.GetCurrentEventState()
|
||||
}
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(response);
|
||||
service.SendMessage(json);
|
||||
}
|
||||
}
|
||||
|
||||
public class StreamDeckService : WebSocketBehavior
|
||||
|
||||
@ -1,259 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[CustomEditor(typeof(ItemController))]
|
||||
public class ItemControllerEditor : Editor
|
||||
{
|
||||
private ItemController itemController;
|
||||
private bool showGroupSettings = true;
|
||||
private bool showGroupList = true;
|
||||
private bool showTestActions = true;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
itemController = (ItemController)target;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Item Controller Tools", EditorStyles.boldLabel);
|
||||
|
||||
// 현재 상태 표시
|
||||
DrawCurrentState();
|
||||
|
||||
// 그룹 설정 섹션
|
||||
showGroupSettings = EditorGUILayout.Foldout(showGroupSettings, "Group Management");
|
||||
if (showGroupSettings)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
EditorGUILayout.LabelField("Quick Group Actions", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Add Selected Objects as New Group"))
|
||||
{
|
||||
AddSelectedObjectsAsGroup();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Refresh Item Groups"))
|
||||
{
|
||||
itemController.InitializeItemGroups();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Clear All Groups"))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Clear Groups", "모든 그룹을 삭제하시겠습니까?", "Yes", "No"))
|
||||
{
|
||||
itemController.itemGroups.Clear();
|
||||
Debug.Log("[ItemControllerEditor] 모든 그룹이 삭제되었습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
// 그룹 리스트 섹션
|
||||
showGroupList = EditorGUILayout.Foldout(showGroupList, "Current Group List");
|
||||
if (showGroupList)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
if (itemController.itemGroups != null && itemController.itemGroups.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < itemController.itemGroups.Count; i++)
|
||||
{
|
||||
var group = itemController.itemGroups[i];
|
||||
if (group != null)
|
||||
{
|
||||
DrawGroupItem(i, group);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("No groups registered", EditorStyles.centeredGreyMiniLabel);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
// 테스트 액션 섹션
|
||||
showTestActions = EditorGUILayout.Foldout(showTestActions, "Test Actions");
|
||||
if (showTestActions)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Activate All Groups"))
|
||||
{
|
||||
itemController.ActivateAllGroups();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Deactivate All Groups"))
|
||||
{
|
||||
itemController.DeactivateAllGroups();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (itemController.itemGroups.Count > 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("Set Active Group:", EditorStyles.miniLabel);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
for (int i = 0; i < Mathf.Min(3, itemController.itemGroups.Count); i++)
|
||||
{
|
||||
if (GUILayout.Button($"Group {i}"))
|
||||
{
|
||||
itemController.Set(i);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCurrentState()
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
EditorGUILayout.LabelField("Current State", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.LabelField($"Total Groups: {itemController.itemGroups?.Count ?? 0}");
|
||||
EditorGUILayout.LabelField($"Current Group: {(itemController.CurrentGroup?.groupName ?? "None")}");
|
||||
EditorGUILayout.LabelField($"Current Index: {itemController.CurrentIndex}");
|
||||
|
||||
if (itemController.CurrentGroup != null)
|
||||
{
|
||||
EditorGUILayout.LabelField($"Active: {itemController.CurrentGroup.IsActive()}",
|
||||
itemController.CurrentGroup.IsActive() ? EditorStyles.boldLabel : EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
private void DrawGroupItem(int index, ItemController.ItemGroup group)
|
||||
{
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
// 그룹 헤더
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField($"{index + 1}. {group.groupName}", EditorStyles.boldLabel);
|
||||
|
||||
// 활성화 상태 토글
|
||||
bool isActive = group.IsActive();
|
||||
bool newActive = EditorGUILayout.Toggle(isActive, GUILayout.Width(20));
|
||||
if (newActive != isActive)
|
||||
{
|
||||
group.SetActive(newActive);
|
||||
}
|
||||
|
||||
// 토글 버튼
|
||||
if (GUILayout.Button("Toggle", GUILayout.Width(50)))
|
||||
{
|
||||
itemController.ToggleGroup(index);
|
||||
}
|
||||
|
||||
// 핫키 레코딩 버튼
|
||||
if (GUILayout.Button(group.isRecording ? "Stop" : "Record", GUILayout.Width(60)))
|
||||
{
|
||||
if (group.isRecording)
|
||||
{
|
||||
itemController.StopRecordingHotkey(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemController.StartRecordingHotkey(index);
|
||||
}
|
||||
}
|
||||
|
||||
// 삭제 버튼
|
||||
if (GUILayout.Button("X", GUILayout.Width(20)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Delete Group", $"그룹 '{group.groupName}'을 삭제하시겠습니까?", "Yes", "No"))
|
||||
{
|
||||
itemController.RemoveGroup(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
// 핫키 표시
|
||||
if (group.hotkeys != null && group.hotkeys.Count > 0)
|
||||
{
|
||||
EditorGUILayout.LabelField($"Hotkey: {string.Join(" + ", group.hotkeys)}", EditorStyles.miniLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Hotkey: 설정되지 않음", EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
// 아이템 오브젝트들
|
||||
EditorGUILayout.LabelField("Items:", EditorStyles.miniLabel);
|
||||
if (group.itemObjects != null)
|
||||
{
|
||||
for (int j = 0; j < group.itemObjects.Length; j++)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField($" {j + 1}.", GUILayout.Width(30));
|
||||
|
||||
GameObject obj = group.itemObjects[j];
|
||||
GameObject newObj = (GameObject)EditorGUILayout.ObjectField(obj, typeof(GameObject), true);
|
||||
if (newObj != obj)
|
||||
{
|
||||
group.itemObjects[j] = newObj;
|
||||
}
|
||||
|
||||
// 아이템 삭제 버튼
|
||||
if (GUILayout.Button("X", GUILayout.Width(20)))
|
||||
{
|
||||
var newArray = new GameObject[group.itemObjects.Length - 1];
|
||||
int newIndex = 0;
|
||||
for (int k = 0; k < group.itemObjects.Length; k++)
|
||||
{
|
||||
if (k != j)
|
||||
{
|
||||
newArray[newIndex] = group.itemObjects[k];
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
group.itemObjects = newArray;
|
||||
break;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// 아이템 추가 버튼
|
||||
if (GUILayout.Button("Add Item"))
|
||||
{
|
||||
var newArray = new GameObject[group.itemObjects.Length + 1];
|
||||
group.itemObjects.CopyTo(newArray, 0);
|
||||
group.itemObjects = newArray;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
private void AddSelectedObjectsAsGroup()
|
||||
{
|
||||
GameObject[] selectedObjects = Selection.gameObjects;
|
||||
if (selectedObjects.Length > 0)
|
||||
{
|
||||
string groupName = $"Group {itemController.itemGroups.Count + 1}";
|
||||
itemController.AddGroup(groupName, selectedObjects);
|
||||
Debug.Log($"[ItemControllerEditor] {selectedObjects.Length}개의 선택된 오브젝트를 새 그룹 '{groupName}'으로 추가했습니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[ItemControllerEditor] 선택된 오브젝트가 없습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31447d4896db6c9458ce66dae88feec8
|
||||
@ -0,0 +1,491 @@
|
||||
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.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
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f1686151b323be4ba49f1ec12f88471
|
||||
BIN
Streamdeck/com.mirabox.streamingle.sdPlugin/images/event_icon.png
(Stored with Git LFS)
Normal file
BIN
Streamdeck/com.mirabox.streamingle.sdPlugin/images/event_icon.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Streamdeck/com.mirabox.streamingle.sdPlugin/manifest.json
(Stored with Git LFS)
BIN
Streamdeck/com.mirabox.streamingle.sdPlugin/manifest.json
(Stored with Git LFS)
Binary file not shown.
@ -8,6 +8,7 @@ let unitySocket = null;
|
||||
let isUnityConnected = false;
|
||||
let cameraList = []; // 카메라 목록 저장
|
||||
let itemList = []; // 아이템 목록 저장
|
||||
let eventList = []; // 이벤트 목록 저장
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
@ -85,19 +86,26 @@ function connectElgatoStreamDeckSocket(inPort, inUUID, inEvent, inInfo, inAction
|
||||
break;
|
||||
case 'willAppear':
|
||||
console.log('👀 버튼 나타남:', jsonObj.context);
|
||||
console.log('🔍 Action UUID:', jsonObj.action);
|
||||
|
||||
let settings = jsonObj.payload?.settings || {};
|
||||
console.log('⚙️ 초기 설정:', settings);
|
||||
|
||||
// action UUID로 actionType 결정
|
||||
if (jsonObj.action === 'com.mirabox.streamingle.item') {
|
||||
settings.actionType = 'item';
|
||||
console.log('🎯 아이템 컨트롤러 등록:', jsonObj.context);
|
||||
} else if (jsonObj.action === 'com.mirabox.streamingle.event') {
|
||||
settings.actionType = 'event';
|
||||
console.log('🎯 이벤트 컨트롤러 등록:', jsonObj.context);
|
||||
} else {
|
||||
settings.actionType = 'camera';
|
||||
console.log('📹 카메라 컨트롤러 등록:', jsonObj.context);
|
||||
}
|
||||
|
||||
console.log('🎯 최종 actionType:', settings.actionType);
|
||||
buttonContexts.set(jsonObj.context, settings);
|
||||
console.log('💾 설정 저장됨:', settings);
|
||||
updateButtonTitle(jsonObj.context);
|
||||
|
||||
// Unity가 이미 연결되어 있다면 Property Inspector에 상태 전송
|
||||
@ -107,6 +115,8 @@ function connectElgatoStreamDeckSocket(inPort, inUUID, inEvent, inInfo, inAction
|
||||
let actionUUID = 'com.mirabox.streamingle.camera';
|
||||
if (actionType === 'item') {
|
||||
actionUUID = 'com.mirabox.streamingle.item';
|
||||
} else if (actionType === 'event') {
|
||||
actionUUID = 'com.mirabox.streamingle.event';
|
||||
}
|
||||
|
||||
sendToPropertyInspector(jsonObj.context, 'unity_connected', { connected: true }, actionUUID);
|
||||
@ -122,6 +132,23 @@ function connectElgatoStreamDeckSocket(inPort, inUUID, inEvent, inInfo, inAction
|
||||
handlePropertyInspectorMessage(jsonObj.payload, jsonObj.context, jsonObj.action);
|
||||
break;
|
||||
|
||||
case 'setSettings':
|
||||
console.log('💾 setSettings 이벤트 수신:', jsonObj.payload, 'context:', jsonObj.context);
|
||||
if (jsonObj.payload && jsonObj.context) {
|
||||
const currentSettings = getCurrentSettings(jsonObj.context);
|
||||
console.log('📋 저장 전 설정:', currentSettings);
|
||||
|
||||
// actionType을 유지하면서 설정 업데이트
|
||||
const updatedSettings = { ...currentSettings, ...jsonObj.payload };
|
||||
setCurrentSettings(jsonObj.context, updatedSettings);
|
||||
|
||||
const newSettings = getCurrentSettings(jsonObj.context);
|
||||
console.log('✅ 설정 저장 완료:', newSettings);
|
||||
console.log('🎯 액션 타입:', newSettings.actionType);
|
||||
updateButtonTitle(jsonObj.context);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❓ 알 수 없는 이벤트:', jsonObj.event);
|
||||
break;
|
||||
@ -170,6 +197,13 @@ function connectToUnity() {
|
||||
unitySocket.send(message);
|
||||
console.log('📋 아이템 목록 요청:', message);
|
||||
}, 200);
|
||||
|
||||
// 이벤트 목록 요청
|
||||
setTimeout(() => {
|
||||
const message = JSON.stringify({ type: 'get_event_list' });
|
||||
unitySocket.send(message);
|
||||
console.log('📋 이벤트 목록 요청:', message);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
unitySocket.onmessage = function(event) {
|
||||
@ -195,6 +229,8 @@ function connectToUnity() {
|
||||
let actionUUID = 'com.mirabox.streamingle.camera';
|
||||
if (actionType === 'item') {
|
||||
actionUUID = 'com.mirabox.streamingle.item';
|
||||
} else if (actionType === 'event') {
|
||||
actionUUID = 'com.mirabox.streamingle.event';
|
||||
}
|
||||
sendToPropertyInspector(context, 'unity_disconnected', { connected: false }, actionUUID);
|
||||
}
|
||||
@ -233,6 +269,9 @@ function handleButtonClick(context) {
|
||||
case 'item':
|
||||
handleItemAction(settings);
|
||||
break;
|
||||
case 'event':
|
||||
handleEventAction(settings);
|
||||
break;
|
||||
default:
|
||||
console.log('⚠️ 알 수 없는 액션 타입:', actionType);
|
||||
// 기본적으로 카메라 액션으로 처리
|
||||
@ -310,6 +349,44 @@ function handleItemAction(settings) {
|
||||
}
|
||||
}
|
||||
|
||||
// 이벤트 액션 처리
|
||||
function handleEventAction(settings) {
|
||||
let eventIndex = settings.eventIndex;
|
||||
const eventAction = settings.eventAction || 'execute'; // 기본값은 execute
|
||||
|
||||
// 이벤트 인덱스가 설정되지 않았으면 0 사용
|
||||
if (typeof eventIndex !== 'number') {
|
||||
eventIndex = 0;
|
||||
console.log('⚠️ 이벤트 인덱스가 설정되지 않음, 기본값 0 사용');
|
||||
}
|
||||
|
||||
console.log('🎯 이벤트 액션:', eventAction, '인덱스:', eventIndex);
|
||||
|
||||
let messageType = 'execute_event';
|
||||
if (eventAction === 'set') {
|
||||
messageType = 'set_event';
|
||||
}
|
||||
|
||||
// Unity에 이벤트 액션 요청
|
||||
const message = JSON.stringify({
|
||||
type: messageType,
|
||||
data: {
|
||||
event_index: eventIndex
|
||||
}
|
||||
});
|
||||
|
||||
console.log('📤 Unity에 이벤트 액션 요청 전송:', message);
|
||||
console.log('🔍 Unity 연결 상태:', isUnityConnected);
|
||||
console.log('🔍 Unity 소켓 상태:', !!unitySocket);
|
||||
|
||||
if (unitySocket && unitySocket.readyState === WebSocket.OPEN) {
|
||||
unitySocket.send(message);
|
||||
console.log('✅ 메시지 전송 완료');
|
||||
} else {
|
||||
console.error('❌ Unity 소켓이 연결되지 않음');
|
||||
}
|
||||
}
|
||||
|
||||
// Property Inspector 메시지 처리
|
||||
function handlePropertyInspectorMessage(payload, context, actionUUID) {
|
||||
const command = payload.command;
|
||||
@ -341,6 +418,15 @@ function handlePropertyInspectorMessage(payload, context, actionUUID) {
|
||||
currentIndex: currentItemIndex
|
||||
}, actionUUID);
|
||||
}
|
||||
if (eventList.length > 0) {
|
||||
// 현재 활성 이벤트 인덱스 찾기
|
||||
const currentEventIndex = eventList.findIndex(event => event.isActive) || 0;
|
||||
console.log('📡 현재 활성 이벤트 인덱스:', currentEventIndex);
|
||||
sendToPropertyInspector(context, 'event_list', {
|
||||
events: eventList,
|
||||
currentIndex: currentEventIndex
|
||||
}, actionUUID);
|
||||
}
|
||||
} else {
|
||||
// Unity가 연결되지 않은 경우에도 빈 목록 전송
|
||||
console.log('📡 Unity 연결 안됨 - 빈 목록 전송');
|
||||
@ -352,6 +438,10 @@ function handlePropertyInspectorMessage(payload, context, actionUUID) {
|
||||
items: [],
|
||||
currentIndex: 0
|
||||
}, actionUUID);
|
||||
sendToPropertyInspector(context, 'event_list', {
|
||||
events: [],
|
||||
currentIndex: 0
|
||||
}, actionUUID);
|
||||
}
|
||||
break;
|
||||
case 'get_camera_list':
|
||||
@ -370,6 +460,14 @@ function handlePropertyInspectorMessage(payload, context, actionUUID) {
|
||||
console.log('📤 Unity에 아이템 목록 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'get_event_list':
|
||||
console.log('🎯 이벤트 목록 요청');
|
||||
if (isUnityConnected && unitySocket) {
|
||||
const message = JSON.stringify({ type: 'get_event_list' });
|
||||
unitySocket.send(message);
|
||||
console.log('📤 Unity에 이벤트 목록 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'switch_camera':
|
||||
console.log('📹 카메라 전환 요청:', payload.cameraIndex);
|
||||
if (isUnityConnected && unitySocket) {
|
||||
@ -403,6 +501,28 @@ function handlePropertyInspectorMessage(payload, context, actionUUID) {
|
||||
console.log('📤 Unity에 아이템 설정 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'execute_event':
|
||||
console.log('🎯 이벤트 실행 요청:', payload.eventIndex);
|
||||
if (isUnityConnected && unitySocket) {
|
||||
const message = JSON.stringify({
|
||||
type: 'execute_event',
|
||||
data: { event_index: payload.eventIndex }
|
||||
});
|
||||
unitySocket.send(message);
|
||||
console.log('📤 Unity에 이벤트 실행 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'set_event':
|
||||
console.log('🎯 이벤트 설정 요청:', payload.eventIndex);
|
||||
if (isUnityConnected && unitySocket) {
|
||||
const message = JSON.stringify({
|
||||
type: 'set_event',
|
||||
data: { event_index: payload.eventIndex }
|
||||
});
|
||||
unitySocket.send(message);
|
||||
console.log('📤 Unity에 이벤트 설정 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'refresh_camera_list':
|
||||
console.log('🔄 카메라 목록 새로고침 요청');
|
||||
if (isUnityConnected && unitySocket) {
|
||||
@ -419,10 +539,19 @@ function handlePropertyInspectorMessage(payload, context, actionUUID) {
|
||||
console.log('📤 Unity에 아이템 목록 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'refresh_event_list':
|
||||
console.log('🔄 이벤트 목록 새로고침 요청');
|
||||
if (isUnityConnected && unitySocket) {
|
||||
const message = JSON.stringify({ type: 'get_event_list' });
|
||||
unitySocket.send(message);
|
||||
console.log('📤 Unity에 이벤트 목록 요청 전송');
|
||||
}
|
||||
break;
|
||||
case 'update_title':
|
||||
console.log('🏷️ 버튼 제목 업데이트 요청');
|
||||
updateButtonTitle(context);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❓ 알 수 없는 Property Inspector 명령:', command);
|
||||
}
|
||||
@ -454,6 +583,8 @@ function sendToPropertyInspector(context, event, payload, actionUUID = null) {
|
||||
|
||||
if (actionType === 'item') {
|
||||
action = 'com.mirabox.streamingle.item';
|
||||
} else if (actionType === 'event') {
|
||||
action = 'com.mirabox.streamingle.event';
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,6 +640,18 @@ function handleUnityMessage(data) {
|
||||
}
|
||||
}
|
||||
|
||||
// 이벤트 데이터 처리
|
||||
if (data.data.event_data) {
|
||||
let events = data.data.event_data.events || data.data.event_data;
|
||||
if (Array.isArray(events)) {
|
||||
eventList = events;
|
||||
console.log('🎯 이벤트 목록 저장됨:', eventList.length, '개');
|
||||
} else {
|
||||
eventList = [];
|
||||
console.log('⚠️ 이벤트 데이터가 배열이 아님:', events);
|
||||
}
|
||||
}
|
||||
|
||||
updateAllButtonTitles();
|
||||
|
||||
// Property Inspector들에게 Unity 연결 상태 알림
|
||||
@ -528,6 +671,8 @@ function handleUnityMessage(data) {
|
||||
let actionUUID = 'com.mirabox.streamingle.camera';
|
||||
if (actionType === 'item') {
|
||||
actionUUID = 'com.mirabox.streamingle.item';
|
||||
} else if (actionType === 'event') {
|
||||
actionUUID = 'com.mirabox.streamingle.event';
|
||||
}
|
||||
|
||||
console.log('🔍 컨텍스트 분석:', context, 'Action Type:', actionType, 'Action UUID:', actionUUID);
|
||||
@ -556,6 +701,17 @@ function handleUnityMessage(data) {
|
||||
items: itemList,
|
||||
currentIndex: currentItemIndex
|
||||
}, actionUUID);
|
||||
} else if (actionUUID === 'com.mirabox.streamingle.event') {
|
||||
// 이벤트 컨트롤러에는 이벤트 데이터만 전송
|
||||
let currentEventIndex = 0;
|
||||
if (typeof data.data.event_data?.current_index === 'number' && data.data.event_data.current_index >= 0) {
|
||||
currentEventIndex = data.data.event_data.current_index;
|
||||
}
|
||||
console.log('🎯 이벤트 컨트롤러에 이벤트 데이터 전송:', context, '이벤트 수:', eventList.length);
|
||||
sendToPropertyInspector(context, 'event_list', {
|
||||
events: eventList,
|
||||
currentIndex: currentEventIndex
|
||||
}, actionUUID);
|
||||
}
|
||||
}
|
||||
console.log('✅ Property Inspector들에게 Unity 연결 알림 전송 완료');
|
||||
@ -716,6 +872,76 @@ function handleUnityMessage(data) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'event_changed':
|
||||
console.log('🎯 이벤트 변경 알림');
|
||||
console.log('📋 이벤트 데이터 구조:', JSON.stringify(data.data, null, 2));
|
||||
if (data.data && data.data.event_data) {
|
||||
let events = data.data.event_data.events || data.data.event_data;
|
||||
|
||||
console.log('🎯 추출된 이벤트 배열:', events);
|
||||
console.log('🎯 이벤트 배열 타입:', Array.isArray(events) ? 'Array' : typeof events);
|
||||
|
||||
if (Array.isArray(events)) {
|
||||
eventList = events;
|
||||
console.log('🎯 이벤트 목록 업데이트됨:', eventList.length, '개');
|
||||
console.log('🎯 이벤트 목록 내용:', JSON.stringify(eventList, null, 2));
|
||||
updateAllButtonTitles();
|
||||
|
||||
// Property Inspector들에게 이벤트 목록 전송 (이벤트 컨트롤러만)
|
||||
for (const context of buttonContexts.keys()) {
|
||||
const settings = getCurrentSettings(context);
|
||||
const actionType = settings.actionType || 'camera';
|
||||
|
||||
console.log('🔍 컨텍스트 분석:', context, 'Action Type:', actionType);
|
||||
|
||||
if (actionType === 'event') {
|
||||
console.log('🎯 이벤트 컨트롤러 발견 - Property Inspector에 데이터 전송');
|
||||
sendToPropertyInspector(context, 'event_list', {
|
||||
events: eventList,
|
||||
currentIndex: data.data.event_data?.current_index || 0
|
||||
}, 'com.mirabox.streamingle.event');
|
||||
} else {
|
||||
console.log('⚠️ 이벤트 컨트롤러가 아님 - Action Type:', actionType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ 이벤트 목록 응답에서 이벤트 데이터가 배열이 아님');
|
||||
console.log('📋 events:', events);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'event_list_response':
|
||||
console.log('🎯 이벤트 목록 수신');
|
||||
|
||||
if (data.data && data.data.event_data) {
|
||||
let events = data.data.event_data.events || data.data.event_data;
|
||||
|
||||
if (Array.isArray(events)) {
|
||||
eventList = events;
|
||||
const currentIndex = data.data.current_event ?? data.data.event_data?.current_index ?? 0;
|
||||
console.log('🎯 이벤트 목록 업데이트됨:', eventList.length, '개');
|
||||
updateAllButtonTitles();
|
||||
|
||||
// Property Inspector들에게 이벤트 목록 전송 (이벤트 컨트롤러만)
|
||||
for (const context of buttonContexts.keys()) {
|
||||
const settings = getCurrentSettings(context);
|
||||
const actionType = settings.actionType || 'camera';
|
||||
|
||||
if (actionType === 'event') {
|
||||
sendToPropertyInspector(context, 'event_list', {
|
||||
events: eventList,
|
||||
currentIndex: currentIndex
|
||||
}, 'com.mirabox.streamingle.event');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ 이벤트 목록 응답에서 이벤트 데이터가 배열이 아님');
|
||||
console.log('📋 events:', events);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❓ 알 수 없는 Unity 메시지 타입:', data.type);
|
||||
}
|
||||
@ -740,6 +966,10 @@ function updateButtonTitle(context) {
|
||||
let title = 'Camera';
|
||||
let isActive = true; // 아이템 활성화 상태 (기본값: 활성)
|
||||
|
||||
console.log('🏷️ 버튼 제목 업데이트 시작 - Context:', context);
|
||||
console.log('🏷️ 설정:', settings);
|
||||
console.log('🏷️ 액션 타입:', actionType);
|
||||
|
||||
if (actionType === 'camera') {
|
||||
const cameraIndex = typeof settings.cameraIndex === 'number' ? settings.cameraIndex : 0;
|
||||
title = `카메라 ${cameraIndex + 1}`;
|
||||
@ -787,6 +1017,25 @@ function updateButtonTitle(context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (actionType === 'event') {
|
||||
const eventIndex = typeof settings.eventIndex === 'number' ? settings.eventIndex : 0;
|
||||
title = `이벤트 ${eventIndex + 1}`;
|
||||
|
||||
// 이벤트 목록에서 이름 찾기
|
||||
if (eventList && eventList.length > eventIndex) {
|
||||
const event = eventList[eventIndex];
|
||||
if (event && (event.name || event.groupName)) {
|
||||
// 이벤트 이름에서 불필요한 부분 제거하고 짧게 만들기
|
||||
let eventName = event.name || event.groupName;
|
||||
let shortName = eventName
|
||||
.replace('Event', '')
|
||||
.replace('Group', '')
|
||||
.replace('_', ' ')
|
||||
.substring(0, 10); // 최대 10글자
|
||||
|
||||
title = shortName || `이벤트 ${eventIndex + 1}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StreamDock에 제목 업데이트 요청
|
||||
@ -807,12 +1056,13 @@ function updateButtonTitle(context) {
|
||||
websocket.send(JSON.stringify(message));
|
||||
console.log('🏷️ 버튼 제목 업데이트:', title, '(액션 타입:', actionType, ', 활성:', isActive, ')');
|
||||
|
||||
// 아이템이나 카메라가 비활성화되어 있으면 아이콘을 어둡게 표시
|
||||
// 아이템이나 카메라가 비활성화되어 있으면 아이콘을 어둡게 표시 (이벤트는 제외)
|
||||
if ((actionType === 'item' || actionType === 'camera') && !isActive) {
|
||||
setButtonState(context, false); // 비활성 상태로 설정
|
||||
} else {
|
||||
} else if (actionType === 'item' || actionType === 'camera') {
|
||||
setButtonState(context, true); // 활성 상태로 설정
|
||||
}
|
||||
// 이벤트 컨트롤러는 활성/비활성 상태 변경 없음 (항상 활성)
|
||||
}
|
||||
|
||||
// 버튼 상태 설정 (활성/비활성)
|
||||
@ -825,7 +1075,7 @@ function setButtonState(context, isActive) {
|
||||
const settings = getCurrentSettings(context);
|
||||
const actionType = settings.actionType || 'camera';
|
||||
|
||||
// 아이템 컨트롤러와 카메라 컨트롤러 모두 상태 변경 적용
|
||||
// 아이템 컨트롤러와 카메라 컨트롤러만 상태 변경 적용 (이벤트 컨트롤러는 제외)
|
||||
if (actionType === 'item' || actionType === 'camera') {
|
||||
// 방법 1: setState 이벤트 사용
|
||||
const stateMessage = {
|
||||
|
||||
@ -0,0 +1,190 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Streamingle Event Inspector</title>
|
||||
<style>
|
||||
body {
|
||||
background: #222;
|
||||
color: #fff;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
min-height: 300px;
|
||||
}
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
padding: 8px;
|
||||
background: #333;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 8px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.dot.green { background: #28a745; }
|
||||
.dot.red { background: #dc3545; }
|
||||
.section {
|
||||
margin-bottom: 16px;
|
||||
padding: 8px;
|
||||
background: #333;
|
||||
border-radius: 4px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-weight: bold;
|
||||
color: #ddd;
|
||||
}
|
||||
select, input[type="checkbox"] {
|
||||
margin-right: 8px;
|
||||
background: #444;
|
||||
color: #fff;
|
||||
border: 1px solid #555;
|
||||
border-radius: 3px;
|
||||
padding: 4px;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.current {
|
||||
margin-top: 8px;
|
||||
color: #17a2b8;
|
||||
font-weight: bold;
|
||||
}
|
||||
button {
|
||||
padding: 6px 12px;
|
||||
background: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
background: #666;
|
||||
}
|
||||
.connected { color: #28a745; font-weight: bold; }
|
||||
.disconnected { color: #dc3545; font-weight: bold; }
|
||||
|
||||
/* 로그 영역 스타일 */
|
||||
.log-section {
|
||||
margin-top: 16px;
|
||||
border-top: 1px solid #444;
|
||||
padding-top: 12px;
|
||||
}
|
||||
.log-toggle {
|
||||
background: #555;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 4px 8px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.log-area {
|
||||
background: #111;
|
||||
color: #0f0;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 11px;
|
||||
padding: 8px;
|
||||
border-radius: 3px;
|
||||
height: 120px;
|
||||
overflow-y: auto;
|
||||
display: none;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
.log-area.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 로딩 상태 */
|
||||
.loading {
|
||||
color: #ffc107;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 이벤트 목록 스타일 */
|
||||
.event-list {
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 연결 상태 -->
|
||||
<div class="status">
|
||||
<div id="statusDot" class="dot red"></div>
|
||||
<span id="connection-status" class="disconnected">Unity 연결 안됨</span>
|
||||
</div>
|
||||
|
||||
<!-- 이벤트 그룹 선택 섹션 -->
|
||||
<div class="section">
|
||||
<label for="event-select">이벤트 그룹 선택</label>
|
||||
<div class="event-list">
|
||||
<select id="event-select" disabled>
|
||||
<option value="">이벤트 그룹 목록 로딩 중...</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="current" id="current-event">현재 이벤트 그룹: -</div>
|
||||
</div>
|
||||
|
||||
<!-- 설정 섹션 -->
|
||||
<div class="section">
|
||||
<input type="checkbox" id="autoExecute" checked>
|
||||
<label for="autoExecute" style="display:inline; font-weight:normal;">자동 실행</label>
|
||||
</div>
|
||||
|
||||
<!-- 액션 섹션 -->
|
||||
<div class="section">
|
||||
<button id="refresh-button" disabled>이벤트 그룹 목록 새로고침</button>
|
||||
<button id="execute-button" disabled>이벤트 실행</button>
|
||||
</div>
|
||||
|
||||
<!-- 디버그 로그 섹션 -->
|
||||
<div class="log-section">
|
||||
<button class="log-toggle" onclick="toggleLog()">📋 디버그 로그 보기</button>
|
||||
<div id="logArea" class="log-area"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 로그 토글 함수
|
||||
function toggleLog() {
|
||||
const logArea = document.getElementById('logArea');
|
||||
logArea.classList.toggle('show');
|
||||
}
|
||||
|
||||
// 페이지 로드 시 초기화
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('📋 Event Property Inspector HTML 로드됨');
|
||||
|
||||
// 초기 상태 설정
|
||||
const statusDot = document.getElementById('statusDot');
|
||||
const connectionStatus = document.getElementById('connection-status');
|
||||
const eventSelect = document.getElementById('event-select');
|
||||
const refreshButton = document.getElementById('refresh-button');
|
||||
const executeButton = document.getElementById('execute-button');
|
||||
|
||||
if (statusDot) console.log('✅ statusDot 요소 찾음');
|
||||
if (connectionStatus) console.log('✅ connection-status 요소 찾음');
|
||||
if (eventSelect) console.log('✅ event-select 요소 찾음');
|
||||
if (refreshButton) console.log('✅ refresh-button 요소 찾음');
|
||||
if (executeButton) console.log('✅ execute-button 요소 찾음');
|
||||
});
|
||||
</script>
|
||||
<script src="index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,308 @@
|
||||
// Event Controller Property Inspector
|
||||
let websocket = null;
|
||||
let uuid = null;
|
||||
let settings = {};
|
||||
let eventList = [];
|
||||
let isUnityConnected = false;
|
||||
|
||||
// DOM 요소들
|
||||
let eventSelect = null;
|
||||
let statusDot = null;
|
||||
let connectionStatus = null;
|
||||
let currentEvent = null;
|
||||
let refreshButton = null;
|
||||
let executeButton = null;
|
||||
let autoExecute = null;
|
||||
let logArea = null;
|
||||
|
||||
function logToScreen(msg, color = "#fff") {
|
||||
let logDiv = document.getElementById('logArea');
|
||||
if (!logDiv) return;
|
||||
const line = document.createElement('div');
|
||||
line.style.color = color;
|
||||
line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
|
||||
logDiv.appendChild(line);
|
||||
logDiv.scrollTop = logDiv.scrollHeight;
|
||||
}
|
||||
|
||||
console.log = function(...args) {
|
||||
logToScreen(args.map(a => (typeof a === 'object' ? JSON.stringify(a) : a)).join(' '), '#0f0');
|
||||
};
|
||||
console.error = function(...args) {
|
||||
logToScreen(args.map(a => (typeof a === 'object' ? JSON.stringify(a) : a)).join(' '), '#f55');
|
||||
};
|
||||
|
||||
// DOM 초기화
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
eventSelect = document.getElementById('event-select');
|
||||
statusDot = document.getElementById('statusDot');
|
||||
connectionStatus = document.getElementById('connection-status');
|
||||
currentEvent = document.getElementById('current-event');
|
||||
refreshButton = document.getElementById('refresh-button');
|
||||
executeButton = document.getElementById('execute-button');
|
||||
autoExecute = document.getElementById('autoExecute');
|
||||
logArea = document.getElementById('logArea');
|
||||
|
||||
if (refreshButton) refreshButton.addEventListener('click', onRefreshClicked);
|
||||
if (executeButton) executeButton.addEventListener('click', onExecuteClicked);
|
||||
if (eventSelect) eventSelect.addEventListener('change', onEventSelectionChanged);
|
||||
if (autoExecute) autoExecute.addEventListener('change', onAutoExecuteChanged);
|
||||
|
||||
console.log('✅ Event Property Inspector 준비 완료');
|
||||
});
|
||||
|
||||
// StreamDeck 연결
|
||||
window.connectElgatoStreamDeckSocket = function(inPort, inUUID, inEvent, inInfo, inActionInfo) {
|
||||
uuid = inUUID;
|
||||
console.log('🔌 StreamDeck 연결 시작:', inPort, inUUID);
|
||||
|
||||
try {
|
||||
if (inActionInfo) {
|
||||
const actionInfo = JSON.parse(inActionInfo);
|
||||
settings = actionInfo.payload?.settings || {};
|
||||
console.log('⚙️ 초기 설정:', settings);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('ActionInfo 파싱 오류:', e);
|
||||
}
|
||||
|
||||
if (!websocket) {
|
||||
websocket = new WebSocket('ws://localhost:' + inPort);
|
||||
|
||||
websocket.onopen = function() {
|
||||
console.log('✅ StreamDeck 연결됨');
|
||||
websocket.send(JSON.stringify({ event: inEvent, uuid: inUUID }));
|
||||
|
||||
// Unity 상태 요청
|
||||
setTimeout(() => {
|
||||
sendToPlugin('get_unity_status');
|
||||
}, 500);
|
||||
};
|
||||
|
||||
websocket.onmessage = function(evt) {
|
||||
try {
|
||||
const jsonObj = JSON.parse(evt.data);
|
||||
handleMessage(jsonObj);
|
||||
} catch (e) {
|
||||
console.error('메시지 파싱 오류:', e);
|
||||
}
|
||||
};
|
||||
|
||||
websocket.onclose = function() {
|
||||
console.log('❌ StreamDeck 연결 끊어짐');
|
||||
websocket = null;
|
||||
};
|
||||
|
||||
websocket.onerror = function(e) {
|
||||
console.error('WebSocket 오류:', e);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function sendToPlugin(command, data = {}) {
|
||||
if (!websocket) return;
|
||||
const message = {
|
||||
action: 'com.mirabox.streamingle.event',
|
||||
event: 'sendToPlugin',
|
||||
context: uuid,
|
||||
payload: { command, ...data }
|
||||
};
|
||||
websocket.send(JSON.stringify(message));
|
||||
console.log('📤 Plugin으로 메시지 전송:', command, data);
|
||||
}
|
||||
|
||||
function handleMessage(jsonObj) {
|
||||
console.log('📨 메시지 수신:', jsonObj.event);
|
||||
|
||||
if (jsonObj.event === 'sendToPropertyInspector' && jsonObj.payload && jsonObj.payload.event) {
|
||||
const innerEvent = jsonObj.payload.event;
|
||||
console.log('📨 Property Inspector 이벤트:', innerEvent);
|
||||
|
||||
switch (innerEvent) {
|
||||
case 'unity_connected':
|
||||
updateUnityConnection(true);
|
||||
break;
|
||||
case 'unity_disconnected':
|
||||
updateUnityConnection(false);
|
||||
break;
|
||||
case 'event_list':
|
||||
updateEventList(jsonObj.payload.events, jsonObj.payload.currentIndex);
|
||||
break;
|
||||
case 'event_changed':
|
||||
updateEventState(jsonObj.payload.currentIndex);
|
||||
break;
|
||||
case 'camera_list':
|
||||
console.log('📹 카메라 목록 수신 (이벤트 Property Inspector에서는 무시)');
|
||||
break;
|
||||
case 'item_list':
|
||||
console.log('🎯 아이템 목록 수신 (이벤트 Property Inspector에서는 무시)');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonObj.event === 'didReceiveSettings' && jsonObj.payload && jsonObj.context) {
|
||||
settings = jsonObj.payload.settings || {};
|
||||
console.log('⚙️ 설정 수신:', settings);
|
||||
|
||||
if (settings.eventIndex !== undefined && eventSelect) {
|
||||
eventSelect.value = settings.eventIndex;
|
||||
console.log('🎯 이벤트 인덱스 설정됨:', settings.eventIndex);
|
||||
}
|
||||
|
||||
if (settings.autoExecute !== undefined && autoExecute) {
|
||||
autoExecute.checked = settings.autoExecute;
|
||||
}
|
||||
|
||||
updateCurrentEvent();
|
||||
}
|
||||
}
|
||||
|
||||
function updateUnityConnection(connected) {
|
||||
isUnityConnected = connected;
|
||||
|
||||
if (statusDot) {
|
||||
statusDot.className = 'dot ' + (connected ? 'green' : 'red');
|
||||
}
|
||||
|
||||
if (connectionStatus) {
|
||||
connectionStatus.textContent = connected ? 'Unity 연결됨' : 'Unity 연결 안됨';
|
||||
connectionStatus.className = connected ? 'connected' : 'disconnected';
|
||||
}
|
||||
|
||||
if (eventSelect) {
|
||||
eventSelect.disabled = !connected;
|
||||
}
|
||||
|
||||
if (refreshButton) {
|
||||
refreshButton.disabled = !connected;
|
||||
}
|
||||
|
||||
if (executeButton) {
|
||||
executeButton.disabled = !connected;
|
||||
}
|
||||
|
||||
console.log('🔗 Unity 연결 상태 변경:', connected);
|
||||
}
|
||||
|
||||
function updateEventList(events, currentIndex) {
|
||||
eventList = events || [];
|
||||
console.log('🎯 이벤트 목록 업데이트:', eventList.length, '개');
|
||||
|
||||
if (!eventSelect) return;
|
||||
|
||||
eventSelect.innerHTML = '';
|
||||
|
||||
if (eventList.length === 0) {
|
||||
const option = document.createElement('option');
|
||||
option.value = '';
|
||||
option.textContent = '이벤트 그룹이 없습니다';
|
||||
eventSelect.appendChild(option);
|
||||
} else {
|
||||
eventList.forEach((event, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = index;
|
||||
option.textContent = event.name || event.groupName || `이벤트 그룹 ${index + 1}`;
|
||||
eventSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
// 현재 선택된 이벤트 설정
|
||||
if (settings.eventIndex !== undefined) {
|
||||
eventSelect.value = settings.eventIndex;
|
||||
} else if (currentIndex !== undefined) {
|
||||
eventSelect.value = currentIndex;
|
||||
}
|
||||
|
||||
updateCurrentEvent();
|
||||
}
|
||||
|
||||
function updateCurrentEvent() {
|
||||
if (!currentEvent) return;
|
||||
|
||||
const selectedIndex = eventSelect ? parseInt(eventSelect.value) : -1;
|
||||
if (selectedIndex >= 0 && selectedIndex < eventList.length) {
|
||||
const selectedEvent = eventList[selectedIndex];
|
||||
currentEvent.textContent = `현재 이벤트 그룹: ${selectedEvent.name || selectedEvent.groupName || `이벤트 그룹 ${selectedIndex + 1}`}`;
|
||||
} else {
|
||||
currentEvent.textContent = '현재 이벤트 그룹: -';
|
||||
}
|
||||
}
|
||||
|
||||
function updateEventState(currentIndex) {
|
||||
console.log('🎯 이벤트 상태 업데이트:', currentIndex);
|
||||
|
||||
if (eventSelect && currentIndex !== undefined) {
|
||||
eventSelect.value = currentIndex;
|
||||
updateCurrentEvent();
|
||||
}
|
||||
}
|
||||
|
||||
function onEventSelectionChanged() {
|
||||
if (!eventSelect) return;
|
||||
|
||||
const selectedIndex = parseInt(eventSelect.value);
|
||||
console.log('🎯 이벤트 선택 변경:', selectedIndex);
|
||||
|
||||
if (selectedIndex >= 0) {
|
||||
settings.eventIndex = selectedIndex;
|
||||
|
||||
// StreamDeck에 설정 저장 (카메라 컨트롤러와 동일한 방식)
|
||||
if (websocket && uuid) {
|
||||
websocket.send(JSON.stringify({
|
||||
action: 'com.mirabox.streamingle.event',
|
||||
event: 'setSettings',
|
||||
context: uuid,
|
||||
payload: {
|
||||
eventIndex: selectedIndex,
|
||||
actionType: 'event' // actionType 명시적으로 설정
|
||||
}
|
||||
}));
|
||||
console.log('💾 설정 저장됨:', { eventIndex: selectedIndex, actionType: 'event' });
|
||||
}
|
||||
|
||||
// Unity에 이벤트 설정 요청 (자동 실행 여부와 관계없이)
|
||||
if (isUnityConnected) {
|
||||
console.log('📤 Unity에 이벤트 설정 전송:', selectedIndex);
|
||||
sendToPlugin('set_event', { event_index: selectedIndex });
|
||||
} else {
|
||||
console.log('⚠️ Unity가 연결되지 않아 이벤트 설정을 전송할 수 없습니다');
|
||||
}
|
||||
|
||||
updateCurrentEvent();
|
||||
}
|
||||
}
|
||||
|
||||
function onAutoExecuteChanged() {
|
||||
if (!autoExecute) return;
|
||||
|
||||
settings.autoExecute = autoExecute.checked;
|
||||
console.log('⚙️ 자동 실행 설정 변경:', settings.autoExecute);
|
||||
|
||||
// StreamDeck에 설정 저장 (카메라 컨트롤러와 동일한 방식)
|
||||
if (websocket && uuid) {
|
||||
websocket.send(JSON.stringify({
|
||||
action: 'com.mirabox.streamingle.event',
|
||||
event: 'setSettings',
|
||||
context: uuid,
|
||||
payload: { autoExecute: settings.autoExecute }
|
||||
}));
|
||||
console.log('💾 자동 실행 설정 저장됨:', { autoExecute: settings.autoExecute });
|
||||
}
|
||||
}
|
||||
|
||||
function onRefreshClicked() {
|
||||
console.log('🔄 이벤트 목록 새로고침 요청');
|
||||
sendToPlugin('get_event_list');
|
||||
}
|
||||
|
||||
function onExecuteClicked() {
|
||||
if (!eventSelect) return;
|
||||
|
||||
const selectedIndex = parseInt(eventSelect.value);
|
||||
if (selectedIndex >= 0) {
|
||||
console.log('▶️ 이벤트 실행 요청:', selectedIndex);
|
||||
sendToPlugin('execute_event', { event_index: selectedIndex });
|
||||
} else {
|
||||
console.log('⚠️ 이벤트가 선택되지 않았습니다');
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user