user 41270a34f5 Refactor: 전체 에디터 UXML 전환 + 대시보드/런타임 UI + 한글화 + NanumGothic 폰트
- 모든 컨트롤러 에디터를 IMGUI → UI Toolkit(UXML/USS)으로 전환
  (Camera, Item, Event, Avatar, System, StreamDeck, OptiTrack, Facial)
- StreamingleCommon.uss 공통 테마 + 개별 에디터 USS 스타일시트
- SystemController 서브매니저 분리 (OptiTrack, Facial, Recording, Screenshot 등)
- 런타임 컨트롤 패널 (ESC 토글, 좌측 오버레이, 150% 스케일)
- 웹 대시보드 서버 (StreamingleDashboardServer) + 리타게팅 통합
- 설정 도구(StreamingleControllerSetupTool) UXML 재작성 + 원클릭 설정
- SimplePoseTransfer UXML 에디터 추가
- 전체 UXML 한글화 + NanumGothic 폰트 적용
- Streamingle.Debug → Streamingle.Debugging 네임스페이스 변경 (Debug.Log 충돌 해결)
- 불필요 코드 제거 (rawkey.cs, RetargetingHTTPServer, OptitrackSkeletonAnimator 등)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 02:51:43 +09:00

196 lines
6.6 KiB
C#

using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// StreamDeck 단일 기능 버튼들을 통합 관리하는 시스템 컨트롤러
/// 각 기능은 서브매니저로 분리되어 있으며, 명령어 디스패치 파사드 역할
/// </summary>
public class SystemController : MonoBehaviour
{
[Header("OptiTrack")]
public OptiTrackManager optiTrack = new OptiTrackManager();
[Header("Facial Motion Capture")]
public FacialMotionManager facialMotion = new FacialMotionManager();
[Header("Motion Recording")]
public MotionRecordingManager motionRecording = new MotionRecordingManager();
[Header("Screenshot")]
public ScreenshotManager screenshot = new ScreenshotManager();
[Header("Cloth Simulation")]
public ClothSimulationManager clothSimulation = new ClothSimulationManager();
[Header("Avatar Head")]
public AvatarHeadManager avatarHead = new AvatarHeadManager();
[Header("Retargeting Remote")]
public RetargetingRemoteManager retargetingRemote = new RetargetingRemoteManager();
[Header("Runtime Control Panel")]
public RuntimeControlPanelManager runtimeControlPanel = new RuntimeControlPanelManager();
[Header("Debug")]
public bool enableDebugLog = true;
// 싱글톤 패턴
public static SystemController Instance { get; private set; }
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
private void Start()
{
optiTrack.Initialize(Log, LogError);
facialMotion.Initialize(Log, LogError);
motionRecording.Initialize(optiTrack, Log, LogError);
screenshot.Initialize(Log, LogError);
clothSimulation.Initialize(Log, LogError);
avatarHead.Initialize(Log, LogError);
retargetingRemote.Initialize(Log, LogError);
runtimeControlPanel.Initialize(transform, Log, LogError);
Log("SystemController 초기화 완료");
Log($"OptiTrack 클라이언트: {(optiTrack.optitrackClient != null ? "" : "")}");
Log($"Motion Recorder 개수: {motionRecording.motionRecorders.Count}");
Log($"Facial Motion 클라이언트 개수: {facialMotion.facialMotionClients.Count}");
Log($"Screenshot 카메라: {(screenshot.screenshotCamera != null ? "" : "")}");
}
/// <summary>
/// 명령어 실행 - WebSocket에서 받은 명령을 적절한 매니저로 디스패치
/// </summary>
public void ExecuteCommand(string command, Dictionary<string, object> parameters)
{
Log($"명령어 실행: {command}");
switch (command)
{
// OptiTrack 마커
case "toggle_optitrack_markers":
optiTrack.ToggleOptitrackMarkers();
break;
case "show_optitrack_markers":
optiTrack.ShowOptitrackMarkers();
break;
case "hide_optitrack_markers":
optiTrack.HideOptitrackMarkers();
break;
case "reconnect_optitrack":
optiTrack.ReconnectOptitrack();
break;
case "spawn_optitrack_client":
optiTrack.SpawnOptitrackClientFromPrefab();
break;
// Facial Motion
case "reconnect_facial_motion":
facialMotion.ReconnectFacialMotion();
break;
case "refresh_facial_motion_clients":
facialMotion.RefreshFacialMotionClients();
break;
// Motion Recording
case "start_motion_recording":
motionRecording.StartMotionRecording();
break;
case "stop_motion_recording":
motionRecording.StopMotionRecording();
break;
case "toggle_motion_recording":
motionRecording.ToggleMotionRecording();
break;
case "refresh_motion_recorders":
motionRecording.RefreshMotionRecorders();
break;
// Screenshot
case "capture_screenshot":
screenshot.CaptureScreenshot();
break;
case "capture_alpha_screenshot":
screenshot.CaptureAlphaScreenshot();
break;
case "open_screenshot_folder":
screenshot.OpenScreenshotFolder();
break;
// Avatar Head
case "refresh_avatar_head_colliders":
avatarHead.RefreshAvatarHeadColliders();
break;
// MagicaCloth
case "refresh_magica_cloth":
case "reset_magica_cloth":
clothSimulation.ResetAllMagicaCloth();
break;
case "reset_magica_cloth_keep_pose":
clothSimulation.ResetAllMagicaClothKeepPose();
break;
// Retargeting Remote
case "start_retargeting_remote":
retargetingRemote.StartRetargetingRemote();
break;
case "stop_retargeting_remote":
retargetingRemote.StopRetargetingRemote();
break;
case "toggle_retargeting_remote":
retargetingRemote.ToggleRetargetingRemote();
break;
case "refresh_retargeting_characters":
retargetingRemote.AutoRegisterRetargetingCharacters();
break;
default:
LogError($"알 수 없는 명령어: {command}");
break;
}
}
private void Update()
{
runtimeControlPanel.Tick();
}
private void OnDestroy()
{
screenshot.Cleanup();
runtimeControlPanel.Cleanup();
}
// --- 하위 호환 프로퍼티 (StreamDeckServerManager 등 외부 참조용) ---
public OptitrackStreamingClient optitrackClient => optiTrack.optitrackClient;
public bool IsRecording() => motionRecording.IsRecording();
public List<Transform> GetAvatarHeadTargets() => avatarHead.GetAvatarHeadTargets();
public void RefreshAvatarHeadColliders() => avatarHead.RefreshAvatarHeadColliders();
public bool IsRetargetingRemoteRunning() => retargetingRemote.IsRetargetingRemoteRunning();
public string GetRetargetingRemoteUrl() => retargetingRemote.GetRetargetingRemoteUrl();
private void Log(string message)
{
if (enableDebugLog)
{
Debug.Log($"[SystemController] {message}");
}
}
private void LogError(string message)
{
Debug.LogError($"[SystemController] {message}");
}
}