- 모든 컨트롤러 에디터를 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>
131 lines
4.8 KiB
C#
131 lines
4.8 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.UIElements;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
|
|
[CustomEditor(typeof(StreamDeckServerManager))]
|
|
public class StreamDeckServerManagerEditor : Editor
|
|
{
|
|
private const string UxmlPath = "Assets/Scripts/Streamdeck/Editor/UXML/StreamDeckServerManagerEditor.uxml";
|
|
private const string UssPath = "Assets/Scripts/Streamdeck/Editor/UXML/StreamDeckServerManagerEditor.uss";
|
|
private const string CommonUssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/StreamingleCommon.uss";
|
|
|
|
private StreamDeckServerManager manager;
|
|
private VisualElement playStatusContainer;
|
|
private Label playStatusLabel;
|
|
private Label lanIPLabel;
|
|
private Label dashboardUrlLabel;
|
|
private VisualElement dashboardPortField;
|
|
|
|
public override VisualElement CreateInspectorGUI()
|
|
{
|
|
manager = (StreamDeckServerManager)target;
|
|
var root = new VisualElement();
|
|
|
|
// Load stylesheets
|
|
var commonUss = AssetDatabase.LoadAssetAtPath<StyleSheet>(CommonUssPath);
|
|
if (commonUss != null) root.styleSheets.Add(commonUss);
|
|
|
|
var uss = AssetDatabase.LoadAssetAtPath<StyleSheet>(UssPath);
|
|
if (uss != null) root.styleSheets.Add(uss);
|
|
|
|
// Load UXML
|
|
var uxml = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(UxmlPath);
|
|
if (uxml != null) uxml.CloneTree(root);
|
|
|
|
// Cache references
|
|
playStatusContainer = root.Q("playStatusContainer");
|
|
playStatusLabel = root.Q<Label>("playStatusLabel");
|
|
lanIPLabel = root.Q<Label>("lanIPLabel");
|
|
dashboardUrlLabel = root.Q<Label>("dashboardUrlLabel");
|
|
dashboardPortField = root.Q("dashboardPortField");
|
|
|
|
// Open Dashboard button (LAN IP 우선)
|
|
var openBtn = root.Q<Button>("openDashboardBtn");
|
|
if (openBtn != null)
|
|
openBtn.clicked += () =>
|
|
{
|
|
string ip = GetLocalIPAddress();
|
|
string host = !string.IsNullOrEmpty(ip) ? ip : "localhost";
|
|
Application.OpenURL($"http://{host}:{manager.dashboardPort}");
|
|
};
|
|
|
|
// LAN IP detection
|
|
string lanIP = GetLocalIPAddress();
|
|
if (lanIPLabel != null)
|
|
lanIPLabel.text = !string.IsNullOrEmpty(lanIP) ? $"LAN IP: {lanIP}" : "LAN IP: not available";
|
|
|
|
UpdateDashboardUrl(lanIP);
|
|
|
|
// Track enableDashboard for conditional visibility
|
|
var enableProp = serializedObject.FindProperty("enableDashboard");
|
|
UpdateDashboardPortVisibility(enableProp.boolValue);
|
|
root.TrackPropertyValue(enableProp, prop => UpdateDashboardPortVisibility(prop.boolValue));
|
|
|
|
// Track port changes to update URL display
|
|
var dashboardPortProp = serializedObject.FindProperty("dashboardPort");
|
|
var wsPortProp = serializedObject.FindProperty("port");
|
|
root.TrackPropertyValue(dashboardPortProp, _ => UpdateDashboardUrl(lanIP));
|
|
root.TrackPropertyValue(wsPortProp, _ => UpdateDashboardUrl(lanIP));
|
|
|
|
// Play mode polling
|
|
root.schedule.Execute(UpdatePlayModeState).Every(500);
|
|
|
|
return root;
|
|
}
|
|
|
|
private void UpdateDashboardUrl(string lanIP)
|
|
{
|
|
if (dashboardUrlLabel == null || manager == null) return;
|
|
|
|
string local = $"http://localhost:{manager.dashboardPort}";
|
|
if (!string.IsNullOrEmpty(lanIP))
|
|
dashboardUrlLabel.text = $"{local} | http://{lanIP}:{manager.dashboardPort}";
|
|
else
|
|
dashboardUrlLabel.text = local;
|
|
}
|
|
|
|
private void UpdateDashboardPortVisibility(bool enabled)
|
|
{
|
|
if (dashboardPortField == null) return;
|
|
dashboardPortField.style.display = enabled ? DisplayStyle.Flex : DisplayStyle.None;
|
|
}
|
|
|
|
private void UpdatePlayModeState()
|
|
{
|
|
if (playStatusContainer == null || manager == null) return;
|
|
|
|
bool isPlaying = Application.isPlaying;
|
|
if (isPlaying)
|
|
{
|
|
if (!playStatusContainer.ClassListContains("sdm-play-status--visible"))
|
|
playStatusContainer.AddToClassList("sdm-play-status--visible");
|
|
|
|
if (playStatusLabel != null)
|
|
playStatusLabel.text = $"Running ({manager.ConnectedClientCount} clients)";
|
|
}
|
|
else
|
|
{
|
|
if (playStatusContainer.ClassListContains("sdm-play-status--visible"))
|
|
playStatusContainer.RemoveFromClassList("sdm-play-status--visible");
|
|
}
|
|
}
|
|
|
|
private static string GetLocalIPAddress()
|
|
{
|
|
try
|
|
{
|
|
var host = Dns.GetHostEntry(Dns.GetHostName());
|
|
foreach (var ip in host.AddressList)
|
|
{
|
|
if (ip.AddressFamily == AddressFamily.InterNetwork)
|
|
return ip.ToString();
|
|
}
|
|
}
|
|
catch { }
|
|
return "";
|
|
}
|
|
}
|