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

437 lines
12 KiB (Stored with Git LFS)
Markdown

# SystemController 통합 가이드
## 개요
StreamDeck 단일 기능 버튼들을 통합 관리하는 시스템입니다. 각 기능은 하나의 버튼으로 매핑되어 간단하고 직관적으로 사용할 수 있습니다.
---
## 시스템 구조
### 1. Unity 측 (SystemController.cs)
**경로**: `Assets/Scripts/Streamdeck/SystemController.cs`
단일 기능 명령어들을 처리하는 통합 컨트롤러입니다.
**주요 메서드:**
- `ExecuteCommand(string command, Dictionary<string, object> parameters)` - 명령어 실행 진입점
**현재 구현된 기능:**
#### OptiTrack 마커 토글
```csharp
// 명령어: 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 명령을 라우팅합니다.
**통합 코드:**
```csharp
// 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):
```json
{
"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):
```javascript
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):
```javascript
case 'optitrack_marker_toggle':
handleOptitrackMarkerToggle(context);
break;
```
**마커 토글 핸들러** (Line 489-513):
```javascript
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):
```javascript
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**
```json
{
"type": "toggle_optitrack_markers"
}
```
**Unity 로그 (정상 동작 시)**
```
[StreamDeckServerManager] 시스템 명령어 실행: toggle_optitrack_markers
[SystemController] 명령어 실행: toggle_optitrack_markers
[SystemController] OptiTrack 마커 표시: True/False
```
---
## 새 기능 추가 방법
### 1단계: SystemController에 기능 추가
```csharp
// Assets/Scripts/Streamdeck/SystemController.cs
#region 새로운 기능 그룹
/// <summary>
/// 새로운 기능 설명
/// </summary>
public void NewFeatureMethod()
{
// 기능 구현
Log("새 기능 실행됨");
}
#endregion
```
### 2단계: ExecuteCommand에 case 추가
```csharp
switch (command)
{
// 기존 명령어들...
case "new_feature_command":
NewFeatureMethod();
break;
}
```
### 3단계: StreamDeckServerManager에 메시지 타입 추가
```csharp
// ProcessMessage의 switch문에 추가
case "new_feature_command":
HandleSystemCommand(message);
break;
```
### 4단계: manifest.json에 액션 추가
```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에 처리 로직 추가
**액션 등록:**
```javascript
else if (jsonObj.action === 'com.mirabox.streamingle.new_feature') {
settings.actionType = 'new_feature';
console.log('🎯 새 기능 등록:', jsonObj.context);
}
```
**클릭 처리:**
```javascript
case 'new_feature':
handleNewFeature(context);
break;
```
**핸들러 함수:**
```javascript
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단계: 배포
```bash
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.js``willAppear` 이벤트에서 `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 공식 문서
- 메인: https://creator.key123.vip/
- Getting Started: https://creator.key123.vip/en/guide/get-started.html
- Plugin SDK: https://creator.key123.vip/en/streamdock/plugin-sdk.html
### StreamDock SDK (GitHub)
- https://github.com/MiraboxSpace/StreamDock-Plugin-SDK
### 관련 문서
- `Implementation_Guide.md` - Streamingle 플러그인 구현 가이드
- `JSON_Protocol_Specification.md` - JSON 통신 프로토콜 명세
---
**작성일**: 2025-01-27
**버전**: 1.0
**작성자**: SystemController 통합 프로젝트