Streamingle_URP/Streamdeck/SYSTEM_CONTROLLER_GUIDE.md
2025-10-28 00:02:17 +09:00

12 KiB (Stored with Git LFS)

SystemController 통합 가이드

개요

StreamDeck 단일 기능 버튼들을 통합 관리하는 시스템입니다. 각 기능은 하나의 버튼으로 매핑되어 간단하고 직관적으로 사용할 수 있습니다.


시스템 구조

1. Unity 측 (SystemController.cs)

경로: Assets/Scripts/Streamdeck/SystemController.cs

단일 기능 명령어들을 처리하는 통합 컨트롤러입니다.

주요 메서드:

  • ExecuteCommand(string command, Dictionary<string, object> parameters) - 명령어 실행 진입점

현재 구현된 기능:

OptiTrack 마커 토글

// 명령어: toggle_optitrack_markers, show_optitrack_markers, hide_optitrack_markers
public void ToggleOptitrackMarkers()
public void ShowOptitrackMarkers()
public void HideOptitrackMarkers()

2. Unity 서버 (StreamDeckServerManager.cs)

경로: Assets/Scripts/Streamdeck/StreamDeckServerManager.cs

WebSocket 서버에서 SystemController 명령을 라우팅합니다.

통합 코드:

// Line 19
public SystemController systemController { get; private set; }

// Line 64-69
systemController = FindObjectOfType<SystemController>();
if (systemController == null)
{
    Debug.LogWarning("[StreamDeckServerManager] SystemController를 찾을 수 없습니다.");
}

// Line 347-351 (메시지 처리)
case "toggle_optitrack_markers":
case "show_optitrack_markers":
case "hide_optitrack_markers":
    HandleSystemCommand(message);
    break;

// Line 979-1014 (핸들러)
private void HandleSystemCommand(Dictionary<string, object> message)
{
    string messageType = message.ContainsKey("type") ? message["type"].ToString() : null;

    if (systemController == null)
    {
        Debug.LogError("[StreamDeckServerManager] SystemController가 null입니다!");
        return;
    }

    // 파라미터 추출
    Dictionary<string, object> parameters = new Dictionary<string, object>();
    if (message.ContainsKey("data"))
    {
        var dataObject = message["data"];
        if (dataObject is Newtonsoft.Json.Linq.JObject jObject)
        {
            foreach (var prop in jObject.Properties())
            {
                parameters[prop.Name] = prop.Value.ToString();
            }
        }
    }

    // SystemController의 ExecuteCommand 호출
    systemController.ExecuteCommand(messageType, parameters);
}

3. StreamDeck 플러그인 (manifest.json)

경로: Streamdeck/com.mirabox.streamingle.sdPlugin/manifest.json

새로운 액션 정의 (Line 115-137):

{
  "Icon": "images/optitrack_marker_icon.png",
  "Name": "OptiTrack Marker Toggle",
  "DisableAutomaticStates": false,
  "States": [
    {
      "Image": "images/optitrack_marker_icon.png",
      "TitleAlignment": "bottom",
      "FontSize": "12"
    },
    {
      "Image": "images/optitrack_marker_icon_off.png",
      "TitleAlignment": "bottom",
      "FontSize": "12"
    }
  ],
  "Settings": {},
  "Controllers": ["Keypad"],
  "UserTitleEnabled": true,
  "SupportedInMultiActions": true,
  "Tooltip": "Toggle OptiTrack markers visibility",
  "UUID": "com.mirabox.streamingle.optitrack_marker_toggle"
}

4. StreamDeck 플러그인 로직 (plugin/index.js)

경로: Streamdeck/com.mirabox.streamingle.sdPlugin/plugin/index.js

액션 타입 등록 (Line 94-100):

else if (jsonObj.action === 'com.mirabox.streamingle.optitrack_marker_toggle') {
    settings.actionType = 'optitrack_marker_toggle';
    console.log('🎯 OptiTrack 마커 토글 등록:', jsonObj.context);

    // 기본 제목 설정
    setButtonTitle(jsonObj.context, '마커\nON');
}

버튼 클릭 처리 (Line 321-323):

case 'optitrack_marker_toggle':
    handleOptitrackMarkerToggle(context);
    break;

마커 토글 핸들러 (Line 489-513):

function handleOptitrackMarkerToggle(context) {
    console.log('🎯 OptiTrack 마커 토글 실행');

    // Unity에 마커 토글 요청
    const message = JSON.stringify({
        type: 'toggle_optitrack_markers'
    });

    console.log('📤 Unity에 OptiTrack 마커 토글 요청 전송:', message);
    console.log('🔍 Unity 연결 상태:', isUnityConnected);
    console.log('🔍 Unity 소켓 상태:', !!unitySocket);

    if (unitySocket && unitySocket.readyState === WebSocket.OPEN) {
        unitySocket.send(message);
        console.log('✅ 메시지 전송 완료');

        // 버튼 상태 토글 (0 <-> 1)
        toggleButtonState(context);
    } else {
        console.error('❌ Unity 소켓이 연결되지 않음');
        console.log('🔄 Unity 재연결 시도...');
        connectToUnity();
    }
}

버튼 상태 토글 (Line 515-543):

function toggleButtonState(context) {
    const settings = getCurrentSettings(context);
    const currentState = settings.currentState || 0;
    const newState = currentState === 0 ? 1 : 0;

    // 설정 업데이트
    settings.currentState = newState;
    setCurrentSettings(context, settings);

    // 버튼 상태 변경
    const stateMessage = {
        event: 'setState',
        context: context,
        payload: {
            state: newState,
            target: 0 // hardware and software
        }
    };

    if (websocket) {
        websocket.send(JSON.stringify(stateMessage));
        console.log('🎨 버튼 상태 업데이트:', newState === 0 ? 'ON' : 'OFF');
    }

    // 제목도 함께 변경
    const title = newState === 0 ? '마커\nON' : '마커\nOFF';
    setButtonTitle(context, title);
}

통신 프로토콜

WebSocket 메시지 형식

StreamDeck → Unity

{
  "type": "toggle_optitrack_markers"
}

Unity 로그 (정상 동작 시)

[StreamDeckServerManager] 시스템 명령어 실행: toggle_optitrack_markers
[SystemController] 명령어 실행: toggle_optitrack_markers
[SystemController] OptiTrack 마커 표시: True/False

새 기능 추가 방법

1단계: SystemController에 기능 추가

// Assets/Scripts/Streamdeck/SystemController.cs

#region 새로운 기능 그룹

/// <summary>
/// 새로운 기능 설명
/// </summary>
public void NewFeatureMethod()
{
    // 기능 구현
    Log("새 기능 실행됨");
}

#endregion

2단계: ExecuteCommand에 case 추가

switch (command)
{
    // 기존 명령어들...

    case "new_feature_command":
        NewFeatureMethod();
        break;
}

3단계: StreamDeckServerManager에 메시지 타입 추가

// ProcessMessage의 switch문에 추가
case "new_feature_command":
    HandleSystemCommand(message);
    break;

4단계: manifest.json에 액션 추가

{
  "Icon": "images/new_feature_icon.png",
  "Name": "New Feature",
  "DisableAutomaticStates": false,
  "States": [
    {
      "Image": "images/new_feature_icon.png",
      "TitleAlignment": "bottom",
      "FontSize": "12"
    }
  ],
  "Settings": {},
  "Controllers": ["Keypad"],
  "UserTitleEnabled": true,
  "SupportedInMultiActions": true,
  "Tooltip": "New feature description",
  "UUID": "com.mirabox.streamingle.new_feature"
}

5단계: plugin/index.js에 처리 로직 추가

액션 등록:

else if (jsonObj.action === 'com.mirabox.streamingle.new_feature') {
    settings.actionType = 'new_feature';
    console.log('🎯 새 기능 등록:', jsonObj.context);
}

클릭 처리:

case 'new_feature':
    handleNewFeature(context);
    break;

핸들러 함수:

function handleNewFeature(context) {
    console.log('🎯 새 기능 실행');

    const message = JSON.stringify({
        type: 'new_feature_command'
    });

    if (unitySocket && unitySocket.readyState === WebSocket.OPEN) {
        unitySocket.send(message);
        console.log('✅ 메시지 전송 완료');
    }
}

6단계: 배포

cd Streamdeck
deploy-plugin.bat

디버깅 방법

Unity 측 디버깅

Unity Console에서 로그 확인:

[SystemController] 명령어 실행: <command>

StreamDeck 플러그인 디버깅

방법 1: 개발자 도구 (Electron 기반)

  • StreamDock 소프트웨어에서 F12 또는 Ctrl+Shift+I 시도
  • Console 탭에서 JavaScript 로그 확인

방법 2: 로그 파일

  • 경로: %APPDATA%\Hotspot\StreamDock\logs\
  • 최신 로그 파일 확인

방법 3: Unity 로그만으로 확인

  • 버튼 클릭 시 Unity Console에 예상되는 로그가 나오는지 확인
  • 잘못된 메시지가 오면 플러그인 설정 문제

트러블슈팅

문제: 버튼을 눌러도 Unity에 메시지가 안 옴

해결:

  1. Unity에서 SystemController GameObject가 씬에 있는지 확인
  2. StreamDeckServerManager가 SystemController를 찾았는지 로그 확인
  3. Unity WebSocket 서버가 포트 10701에서 실행 중인지 확인

문제: 잘못된 메시지 타입이 옴 (예: switch_camera)

해결:

  1. StreamDeck에서 올바른 액션을 추가했는지 확인
  2. 기존 버튼이 아닌 새 버튼에 "OptiTrack Marker Toggle" 액션을 추가
  3. deploy-plugin.bat를 실행하여 최신 플러그인 배포

문제: 버튼에 제목이 안 나옴

해결:

  1. plugin/index.jswillAppear 이벤트에서 setButtonTitle 호출 확인
  2. 제목에 \n으로 줄바꿈 가능 (예: '마커\nON')

문제: 버튼 상태가 안 바뀜

해결:

  1. manifest.json에서 DisableAutomaticStates: false 확인
  2. States 배열에 2개 상태 정의 확인
  3. toggleButtonState 함수에서 setState 메시지 전송 확인

파일 위치 정리

Unity 파일

Assets/Scripts/Streamdeck/
├── SystemController.cs                    # 단일 기능 통합 컨트롤러
├── StreamDeckServerManager.cs            # WebSocket 서버 & 라우팅
└── StreamDeckService.cs                  # WebSocket 서비스 (기존)

StreamDeck 플러그인 파일

Streamdeck/com.mirabox.streamingle.sdPlugin/
├── manifest.json                         # 액션 정의
├── plugin/
│   └── index.js                         # 플러그인 로직
├── propertyInspector/                   # 설정 UI (기존 액션용)
└── images/                              # 아이콘 이미지
    ├── optitrack_marker_icon.png       # 마커 ON 상태
    └── optitrack_marker_icon_off.png   # 마커 OFF 상태

배포 스크립트

Streamdeck/
├── deploy-plugin.bat                    # 간편 실행용 배치 파일
├── deploy-plugin.ps1                    # 실제 배포 스크립트
└── DEPLOY_README.md                     # 배포 가이드

현재 구현된 기능 목록

1. OptiTrack 마커 토글

  • 명령어: toggle_optitrack_markers, show_optitrack_markers, hide_optitrack_markers
  • UUID: com.mirabox.streamingle.optitrack_marker_toggle
  • 설명: OptiTrack 마커 표시를 켜거나 끔
  • 버튼 상태: 2개 (ON/OFF)
  • 제목: "마커\nON" ↔ "마커\nOFF"

참고 자료

StreamDock 공식 문서

StreamDock SDK (GitHub)

관련 문서

  • Implementation_Guide.md - Streamingle 플러그인 구현 가이드
  • JSON_Protocol_Specification.md - JSON 통신 프로토콜 명세

작성일: 2025-01-27 버전: 1.0 작성자: SystemController 통합 프로젝트