Streamingle_URP/Assets/Scripts/Streamdeck/SimpleStreamDockCommunicator.cs

274 lines
7.8 KiB
C#

using UnityEngine;
using UnityEngine.Events;
using System;
using System.Collections;
using System.Text;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
[System.Serializable]
public class StreamDockEvent : UnityEvent<string, object> { }
public class SimpleStreamDockCommunicator : MonoBehaviour
{
[Header("연결 설정")]
[SerializeField] private string serverUrl = "ws://localhost:15732";
[SerializeField] private bool autoConnect = true;
[SerializeField] private float reconnectInterval = 5f;
[Header("이벤트")]
public StreamDockEvent OnStreamDockMessageReceived;
public UnityEvent OnConnected;
public UnityEvent OnDisconnected;
// 내부 변수
private ClientWebSocket webSocket;
private CancellationTokenSource cancellationTokenSource;
private bool isConnecting = false;
private bool isConnected = false;
// 프로퍼티
public bool IsConnected => isConnected;
void Start()
{
if (autoConnect)
{
ConnectToStreamDock();
}
}
void OnDestroy()
{
DisconnectFromStreamDock();
}
/// <summary>
/// StreamDock에 연결
/// </summary>
public async void ConnectToStreamDock()
{
if (isConnecting || isConnected) return;
isConnecting = true;
try
{
webSocket = new ClientWebSocket();
cancellationTokenSource = new CancellationTokenSource();
Debug.Log($"StreamDock에 연결 중... {serverUrl}");
await webSocket.ConnectAsync(new Uri(serverUrl), cancellationTokenSource.Token);
isConnected = true;
isConnecting = false;
Debug.Log("StreamDock에 연결되었습니다!");
OnConnected?.Invoke();
// 메시지 수신 시작
_ = ReceiveMessages();
}
catch (Exception e)
{
Debug.LogError($"StreamDock 연결 실패: {e.Message}");
isConnecting = false;
OnDisconnected?.Invoke();
// 재연결 시도
StartCoroutine(TryReconnect());
}
}
/// <summary>
/// StreamDock 연결 해제
/// </summary>
public async void DisconnectFromStreamDock()
{
if (!isConnected) return;
try
{
cancellationTokenSource?.Cancel();
if (webSocket != null && webSocket.State == WebSocketState.Open)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Unity 종료", CancellationToken.None);
}
}
catch (Exception e)
{
Debug.LogError($"연결 해제 중 오류: {e.Message}");
}
finally
{
isConnected = false;
webSocket?.Dispose();
webSocket = null;
OnDisconnected?.Invoke();
}
}
/// <summary>
/// StreamDock으로 메시지 전송
/// </summary>
public async void SendMessageToStreamDock(string eventType, object data = null)
{
if (!isConnected)
{
Debug.LogWarning("StreamDock에 연결되지 않았습니다.");
return;
}
try
{
var message = new
{
type = eventType,
data = data,
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
};
string jsonMessage = JsonUtility.ToJson(message);
byte[] buffer = Encoding.UTF8.GetBytes(jsonMessage);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, cancellationTokenSource.Token);
Debug.Log($"StreamDock으로 메시지 전송: {eventType}");
}
catch (Exception e)
{
Debug.LogError($"메시지 전송 실패: {e.Message}");
}
}
/// <summary>
/// 메시지 수신 처리
/// </summary>
private async Task ReceiveMessages()
{
var buffer = new byte[4096];
try
{
while (webSocket.State == WebSocketState.Open)
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationTokenSource.Token);
if (result.MessageType == WebSocketMessageType.Text)
{
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
ProcessReceivedMessage(message);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
Debug.Log("StreamDock에서 연결을 종료했습니다.");
break;
}
}
}
catch (Exception e)
{
Debug.LogError($"메시지 수신 중 오류: {e.Message}");
}
finally
{
isConnected = false;
OnDisconnected?.Invoke();
StartCoroutine(TryReconnect());
}
}
/// <summary>
/// 수신된 메시지 처리
/// </summary>
private void ProcessReceivedMessage(string message)
{
try
{
//Debug.Log($"StreamDock에서 메시지 수신: {message}");
// JSON 파싱 (간단한 구조)
if (message.Contains("type"))
{
// UnityEvent 호출
OnStreamDockMessageReceived?.Invoke("streamdock_message", message);
// 특정 이벤트 타입 처리
if (message.Contains("streamdock_button_clicked"))
{
HandleButtonClick(message);
}
else if (message.Contains("dial_rotate"))
{
HandleDialRotate(message);
}
else if (message.Contains("dial_press"))
{
HandleDialPress(message);
}
}
}
catch (Exception e)
{
Debug.LogError($"메시지 처리 중 오류: {e.Message}");
}
}
/// <summary>
/// 버튼 클릭 이벤트 처리
/// </summary>
private void HandleButtonClick(string message)
{
Debug.Log("StreamDock 버튼이 클릭되었습니다!");
OnStreamDockMessageReceived?.Invoke("button_clicked", message);
}
/// <summary>
/// 다이얼 회전 이벤트 처리
/// </summary>
private void HandleDialRotate(string message)
{
Debug.Log("StreamDock 다이얼이 회전했습니다!");
OnStreamDockMessageReceived?.Invoke("dial_rotate", message);
}
/// <summary>
/// 다이얼 누름 이벤트 처리
/// </summary>
private void HandleDialPress(string message)
{
Debug.Log("StreamDock 다이얼이 눌렸습니다!");
OnStreamDockMessageReceived?.Invoke("dial_press", message);
}
/// <summary>
/// 재연결 시도
/// </summary>
private IEnumerator TryReconnect()
{
yield return new WaitForSeconds(reconnectInterval);
if (!isConnected && !isConnecting)
{
Debug.Log("StreamDock 재연결 시도...");
ConnectToStreamDock();
}
}
// 테스트용 메서드들
[ContextMenu("테스트 메시지 전송")]
public void SendTestMessage()
{
SendMessageToStreamDock("test_message", new { message = "Unity에서 테스트 메시지" });
}
[ContextMenu("커스텀 이벤트 전송")]
public void SendCustomEvent()
{
SendMessageToStreamDock("custom_event", new { action = "test_action", value = 123 });
}
}