KINDNICK_URP/Assets/External/EVMC4U/CommunicationValidator.cs
2025-04-25 21:14:54 +09:00

256 lines
8.7 KiB
C#

/*
* ExternalReceiver
* https://sabowl.sakura.ne.jp/gpsnmeajp/
*
* MIT License
*
* Copyright (c) 2019 gpsnmeajp
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma warning disable 0414,0219
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Profiling;
namespace EVMC4U
{
public class CommunicationValidator : MonoBehaviour, IExternalReceiver
{
[Header("CommunicationValidator v1.2")]
[SerializeField, Label("動作状況")]
private string StatusMessage = ""; //Inspector表示用
#if EVMC4U_JA
[Header("UI オプション")]
#else
[Header("UI Option")]
#endif
[SerializeField, Label("画面上に表示する")]
public bool ShowInformation = false;
#if EVMC4U_JA
[Header("状態モニタ(表示用)")]
#else
[Header("Status Monitor(Read only)")]
#endif
[SerializeField, Label("受信処理再帰呼出し回数")]
private int CallCountMonitor = 0; //Inspector表示用
[SerializeField, Label("利用可能")]
public int Available = 0;
[SerializeField, Label("送信側Time")]
public float time = 0;
[SerializeField, Label("キャリブレーション状態")]
public CalibrationState calibrationState = 0;
[SerializeField, Label("キャリブレーションモード")]
public CalibrationMode calibrationMode = 0;
#if EVMC4U_JA
[Header("送信側受信状態(表示用)")]
#else
[Header("Receive Status(Read only)")]
#endif
[SerializeField, Label("受信許可")]
public bool ReceiveEnable = false;
[SerializeField, Label("受信ポート")]
public int ReceivePort = 0;
[SerializeField, Label("読み込み済み設定ファイルパス")]
public string LoadedConfigPath = "";
[SerializeField, Label("背景色")]
public Color backgroundColor = Color.clear;
#if EVMC4U_JA
[Header("送信側ウィンドウ属性情報")]
#else
[Header("Window Attribute Info(Read only)")]
#endif
[SerializeField, Label("最前面")]
public bool IsTopMost = false;
[SerializeField, Label("透過")]
public bool IsTransparent = false;
[SerializeField, Label("クリックスルー")]
public bool WindowClickThrough = false;
[SerializeField, Label("枠なし")]
public bool HideBorder = false;
#if EVMC4U_JA
[Header("デイジーチェーン")]
#else
[Header("Daisy Chain")]
#endif
public GameObject[] NextReceivers = new GameObject[1];
private ExternalReceiverManager externalReceiverManager = null;
bool shutdown = false;
readonly Rect rect1 = new Rect(0, 0, 120, 70);
readonly Rect rect2 = new Rect(10, 20, 100, 30);
readonly Rect rect3 = new Rect(10, 40, 100, 300);
void Start()
{
externalReceiverManager = new ExternalReceiverManager(NextReceivers);
StatusMessage = "Waiting for Master...";
}
//デイジーチェーンを更新
public void UpdateDaisyChain()
{
externalReceiverManager.GetIExternalReceiver(NextReceivers);
}
int GetAvailable()
{
return Available;
}
float GetRemoteTime()
{
return time;
}
void OnGUI()
{
if (ShowInformation)
{
GUI.TextField(rect1, "ExternalReceiver");
GUI.Label(rect2, "Available: " + GetAvailable());
GUI.Label(rect3, "Time: " + GetRemoteTime());
}
}
public void MessageDaisyChain(ref uOSC.Message message, int callCount)
{
//Startされていない場合無視
if (externalReceiverManager == null || enabled == false || gameObject.activeInHierarchy == false)
{
return;
}
if (shutdown)
{
return;
}
CallCountMonitor = callCount;
StatusMessage = "OK";
//異常を検出して動作停止
try
{
ProcessMessage(ref message);
}
catch (Exception e)
{
StatusMessage = "Error: Exception";
Debug.LogError(" --- Communication Error ---");
Debug.LogError(e.ToString());
shutdown = true;
return;
}
if (!externalReceiverManager.SendNextReceivers(message, callCount))
{
StatusMessage = "Infinite loop detected!";
shutdown = true;
}
}
private void ProcessMessage(ref uOSC.Message message)
{
//メッセージアドレスがない、あるいはメッセージがない不正な形式の場合は処理しない
if (message.address == null || message.values == null)
{
StatusMessage = "Bad message.";
return;
}
if (message.address == "/VMC/Ext/OK"
&& (message.values[0] is int))
{
Available = (int)message.values[0];
if (Available == 0)
{
StatusMessage = "Waiting for [Load VRM]";
}
else {
StatusMessage = "OK";
}
//V2.5 キャリブレーション状態(長さ3以上)
if (message.values.Length >= 3)
{
if ((message.values[1] is int) && (message.values[2] is int))
{
calibrationState = (CalibrationState)message.values[1];
calibrationMode = (CalibrationMode)message.values[2];
}
}
}
//データ送信時刻
else if (message.address == "/VMC/Ext/T"
&& (message.values[0] is float))
{
time = (float)message.values[0];
}
//V2.4 受信情報
else if (message.address == "/VMC/Ext/Rcv"
&& (message.values[0] is int)
&& (message.values[1] is int))
{
ReceiveEnable = (int)message.values[0] != 0;
ReceivePort = (int)message.values[1];
}
//V2.4 背景色情報
else if (message.address == "/VMC/Ext/Setting/Color"
&& (message.values[0] is float)
&& (message.values[1] is float)
&& (message.values[2] is float)
&& (message.values[3] is float))
{
backgroundColor = new Color((float)message.values[0], (float)message.values[1], (float)message.values[2], (float)message.values[3]);
}
//V2.4 ウィンドウ情報
else if (message.address == "/VMC/Ext/Setting/Win"
&& (message.values[0] is int)
&& (message.values[1] is int)
&& (message.values[2] is int)
&& (message.values[3] is int))
{
IsTopMost = (int)message.values[0] != 0;
IsTransparent = (int)message.values[1] != 0;
WindowClickThrough = (int)message.values[2] != 0;
HideBorder = (int)message.values[3] != 0;
}
//V2.5 読み込み済み設定ファイルパス情報
else if (message.address == "/VMC/Ext/Config"
&& (message.values[0] is string))
{
LoadedConfigPath = (string)message.values[0];
}
}
}
}