186 lines
7.1 KiB
C#
186 lines
7.1 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.UIElements;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
[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 const string AutoOption = "자동 (auto)";
|
|
|
|
private StreamDeckServerManager manager;
|
|
private VisualElement playStatusContainer;
|
|
private Label playStatusLabel;
|
|
private Label lanIPLabel;
|
|
private Label dashboardUrlLabel;
|
|
private VisualElement dashboardPortField;
|
|
private VisualElement networkAdapterField;
|
|
|
|
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");
|
|
networkAdapterField = root.Q("networkAdapterField");
|
|
|
|
// 네트워크 어댑터 드롭다운
|
|
if (networkAdapterField != null)
|
|
BuildAdapterDropdown(networkAdapterField);
|
|
|
|
// Open Dashboard button (선택 어댑터 IP 우선)
|
|
var openBtn = root.Q<Button>("openDashboardBtn");
|
|
if (openBtn != null)
|
|
openBtn.clicked += () =>
|
|
{
|
|
string ip = ResolveHostAddress();
|
|
string host = !string.IsNullOrEmpty(ip) ? ip : "localhost";
|
|
Application.OpenURL($"http://{host}:{manager.dashboardPort}");
|
|
};
|
|
|
|
// LAN IP / URL 표시
|
|
UpdateLanLabels(ResolveHostAddress());
|
|
|
|
// 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, _ => UpdateLanLabels(ResolveHostAddress()));
|
|
root.TrackPropertyValue(wsPortProp, _ => UpdateLanLabels(ResolveHostAddress()));
|
|
|
|
// Play mode polling
|
|
root.schedule.Execute(UpdatePlayModeState).Every(500);
|
|
|
|
return root;
|
|
}
|
|
|
|
private void BuildAdapterDropdown(VisualElement container)
|
|
{
|
|
container.Clear();
|
|
|
|
var adapters = NetworkInterfaceUtil.GetAdapters();
|
|
string current = serializedObject.FindProperty("preferredHostAddress").stringValue;
|
|
|
|
var choices = new List<string> { AutoOption };
|
|
var labelToIp = new Dictionary<string, string> { { AutoOption, "" } };
|
|
foreach (var a in adapters)
|
|
{
|
|
string label = $"{a.name} — {a.ip}";
|
|
if (!labelToIp.ContainsKey(label))
|
|
{
|
|
choices.Add(label);
|
|
labelToIp[label] = a.ip;
|
|
}
|
|
}
|
|
|
|
// 현재 선택값 라벨 결정 (저장된 IP가 목록에 없으면 별도 항목으로 표시)
|
|
string currentLabel = AutoOption;
|
|
if (!string.IsNullOrEmpty(current))
|
|
{
|
|
var match = adapters.FirstOrDefault(a => a.ip == current);
|
|
if (!string.IsNullOrEmpty(match.ip))
|
|
{
|
|
currentLabel = $"{match.name} — {match.ip}";
|
|
}
|
|
else
|
|
{
|
|
currentLabel = $"{current} (현재 없음)";
|
|
choices.Add(currentLabel);
|
|
labelToIp[currentLabel] = current;
|
|
}
|
|
}
|
|
|
|
var dropdown = new DropdownField("Network Adapter")
|
|
{
|
|
choices = choices,
|
|
value = currentLabel,
|
|
tooltip = "대시보드 주소로 사용할 네트워크 어댑터.\n'자동'은 기본 게이트웨이가 있는 어댑터를 우선 선택합니다.\n서버 자체는 항상 모든 인터페이스+localhost에서 접속 가능합니다."
|
|
};
|
|
dropdown.RegisterValueChangedCallback(evt =>
|
|
{
|
|
string ip = labelToIp.TryGetValue(evt.newValue, out var v) ? v : "";
|
|
serializedObject.Update();
|
|
serializedObject.FindProperty("preferredHostAddress").stringValue = ip;
|
|
serializedObject.ApplyModifiedProperties();
|
|
UpdateLanLabels(NetworkInterfaceUtil.ResolveHostAddress(ip));
|
|
});
|
|
container.Add(dropdown);
|
|
|
|
var refreshBtn = new Button(() => BuildAdapterDropdown(container)) { text = "어댑터 목록 새로고침" };
|
|
refreshBtn.style.marginTop = 2;
|
|
container.Add(refreshBtn);
|
|
}
|
|
|
|
private string ResolveHostAddress()
|
|
{
|
|
if (manager == null) return "";
|
|
return NetworkInterfaceUtil.ResolveHostAddress(manager.preferredHostAddress);
|
|
}
|
|
|
|
private void UpdateLanLabels(string lanIP)
|
|
{
|
|
if (lanIPLabel != null)
|
|
lanIPLabel.text = !string.IsNullOrEmpty(lanIP) ? $"LAN IP: {lanIP}" : "LAN IP: not available";
|
|
|
|
if (dashboardUrlLabel != null && manager != null)
|
|
{
|
|
string local = $"http://localhost:{manager.dashboardPort}";
|
|
dashboardUrlLabel.text = !string.IsNullOrEmpty(lanIP)
|
|
? $"{local} | http://{lanIP}:{manager.dashboardPort}"
|
|
: 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");
|
|
}
|
|
}
|
|
}
|