2025-11-06 15:28:16 +09:00
|
|
|
|
using System;
|
2025-10-24 11:55:43 +09:00
|
|
|
|
using System.Collections;
|
2025-10-23 18:43:38 +09:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
2025-10-30 09:31:05 +09:00
|
|
|
|
using System.Threading;
|
2025-10-14 16:38:35 +09:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
2025-10-23 18:43:38 +09:00
|
|
|
|
|
2025-10-14 16:38:35 +09:00
|
|
|
|
public class AppManager : MonoBehaviour
|
|
|
|
|
|
{
|
2025-11-04 11:36:19 +09:00
|
|
|
|
public static AppManager Instance { get; private set; }
|
|
|
|
|
|
|
2025-10-14 16:38:35 +09:00
|
|
|
|
[SerializeField] private ProgramView view;
|
2025-10-24 14:36:33 +09:00
|
|
|
|
[SerializeField] private TCPView tcpView;
|
2025-11-11 18:36:52 +09:00
|
|
|
|
[SerializeField] private RobotInfoView robotInfoView;
|
2025-11-13 21:23:28 +09:00
|
|
|
|
[SerializeField] private ProgramInfoView programInfoView;
|
2025-11-14 13:50:31 +09:00
|
|
|
|
[SerializeField] private EnvView envView;
|
2025-10-15 10:39:44 +09:00
|
|
|
|
[SerializeField] private RobotController robotController;
|
2025-10-30 09:31:05 +09:00
|
|
|
|
|
2025-11-11 13:21:20 +09:00
|
|
|
|
private InteractionView leftInteractionView;
|
|
|
|
|
|
private InteractionView rightInteractionView;
|
2025-10-30 09:31:05 +09:00
|
|
|
|
[SerializeField] private PointManagerView pointManagerView;
|
|
|
|
|
|
[SerializeField] private PathLineView pathLineView;
|
|
|
|
|
|
[SerializeField] private PopupView popupView;
|
|
|
|
|
|
|
2025-10-24 11:55:43 +09:00
|
|
|
|
[SerializeField] private float motorStatePollInterval = 1.0f;
|
2025-11-19 18:38:48 +09:00
|
|
|
|
[SerializeField] private AudioSource robotAudio;
|
2025-11-04 11:36:19 +09:00
|
|
|
|
public CancellationTokenSource cancellationTokenSource;
|
|
|
|
|
|
private bool isModelAndStaticViewsReady = false;
|
|
|
|
|
|
private ProgramModel model;
|
2025-10-30 09:31:05 +09:00
|
|
|
|
private ProgramPresenter presenter;
|
2025-10-23 18:43:38 +09:00
|
|
|
|
private string hostip;
|
|
|
|
|
|
private int tcpPort;
|
|
|
|
|
|
private int udpPort;
|
|
|
|
|
|
private string configFileName = "config.cfg";
|
2025-11-04 11:36:19 +09:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Instance != null && Instance != this)
|
|
|
|
|
|
{
|
|
|
|
|
|
Destroy(gameObject);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Instance = this;
|
|
|
|
|
|
}
|
2025-11-21 13:18:03 +09:00
|
|
|
|
|
|
|
|
|
|
// RTT <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
// Nagle <20>˰<EFBFBD><CBB0><EFBFBD><EFBFBD><EFBFBD> <20><>Ȱ<EFBFBD><C8B0>ȭ (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
|
|
|
|
|
System.Net.ServicePointManager.UseNagleAlgorithm = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 100-Continue <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ٸ<EFBFBD><D9B8><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
|
|
|
|
|
System.Net.ServicePointManager.Expect100Continue = false;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
|
|
|
|
|
System.Net.ServicePointManager.DefaultConnectionLimit = 10;
|
2025-11-04 11:36:19 +09:00
|
|
|
|
}
|
2025-10-14 16:38:35 +09:00
|
|
|
|
|
2025-10-23 18:43:38 +09:00
|
|
|
|
async void Start()
|
2025-10-14 16:38:35 +09:00
|
|
|
|
{
|
2025-10-23 18:43:38 +09:00
|
|
|
|
LoadConfig();
|
2025-10-14 16:38:35 +09:00
|
|
|
|
|
2025-11-04 11:36:19 +09:00
|
|
|
|
model = new ProgramModel(hostip, tcpPort, udpPort, robotController);
|
2025-10-23 18:43:38 +09:00
|
|
|
|
await model.InitializeAsync();
|
|
|
|
|
|
|
2025-11-14 13:50:31 +09:00
|
|
|
|
if (view == null || tcpView == null || robotInfoView == null || programInfoView == null || envView == null || robotController == null ||
|
2025-11-06 15:28:16 +09:00
|
|
|
|
pointManagerView == null || popupView == null || pathLineView == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("AppManager<65><72> <20>ν<EFBFBD><CEBD><EFBFBD><EFBFBD>Ϳ<EFBFBD> [Static Views]<5D><> <20><><EFBFBD><EFBFBD> <20>Ҵ<EFBFBD><D2B4><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>", this);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-04 11:36:19 +09:00
|
|
|
|
isModelAndStaticViewsReady = true;
|
|
|
|
|
|
TryCreatePresenter();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void RegisterView(InteractionView Iview)
|
|
|
|
|
|
{
|
2025-11-11 13:21:20 +09:00
|
|
|
|
if (Iview.handSide == HandSide.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.leftInteractionView = Iview;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (Iview.handSide == HandSide.Right)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.rightInteractionView = Iview;
|
|
|
|
|
|
}
|
2025-11-04 11:36:19 +09:00
|
|
|
|
|
|
|
|
|
|
TryCreatePresenter();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void TryCreatePresenter()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (presenter != null) return;
|
|
|
|
|
|
|
2025-11-11 13:21:20 +09:00
|
|
|
|
if (!isModelAndStaticViewsReady || leftInteractionView == null || rightInteractionView == null)
|
2025-11-06 15:28:16 +09:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-19 18:38:48 +09:00
|
|
|
|
cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
|
|
|
2025-11-06 15:28:16 +09:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
presenter = new ProgramPresenter(
|
|
|
|
|
|
model,
|
|
|
|
|
|
view,
|
|
|
|
|
|
tcpView,
|
2025-11-11 18:36:52 +09:00
|
|
|
|
robotInfoView,
|
2025-11-13 21:23:28 +09:00
|
|
|
|
programInfoView,
|
2025-11-14 13:50:31 +09:00
|
|
|
|
envView,
|
2025-11-11 13:21:20 +09:00
|
|
|
|
leftInteractionView, rightInteractionView,
|
2025-11-06 15:28:16 +09:00
|
|
|
|
pointManagerView,
|
|
|
|
|
|
popupView,
|
2025-11-19 18:38:48 +09:00
|
|
|
|
pathLineView,
|
|
|
|
|
|
robotAudio,
|
|
|
|
|
|
cancellationTokenSource
|
2025-11-06 15:28:16 +09:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"Presenter <20><><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><DABF><EFBFBD> <20><><EFBFBD><EFBFBD> <20><EFBFBD>: {e.Message}\n{e.StackTrace}");
|
|
|
|
|
|
return; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
}
|
2025-11-04 11:36:19 +09:00
|
|
|
|
|
2025-10-15 10:39:44 +09:00
|
|
|
|
presenter.RegisterControlledRobot(robotController);
|
2025-11-04 11:36:19 +09:00
|
|
|
|
_ = presenter.UpdateMotorStateAsync();
|
|
|
|
|
|
|
|
|
|
|
|
_ = model.GetTCPAsync(cancellationTokenSource.Token);
|
|
|
|
|
|
_ = model.StartMovementCheckLoopAsync(cancellationTokenSource.Token);
|
2025-11-19 18:38:48 +09:00
|
|
|
|
_ = model.GetMovementState(cancellationTokenSource.Token);
|
2025-10-15 10:39:44 +09:00
|
|
|
|
|
2025-10-14 16:38:35 +09:00
|
|
|
|
view.DisplayProgram(null);
|
2025-10-24 11:55:43 +09:00
|
|
|
|
StartCoroutine(PollMotorStateCoroutine());
|
2025-10-14 16:38:35 +09:00
|
|
|
|
}
|
2025-10-23 18:43:38 +09:00
|
|
|
|
|
2025-11-19 18:38:48 +09:00
|
|
|
|
private void OnDestroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Instance == this)
|
|
|
|
|
|
{
|
|
|
|
|
|
cancellationTokenSource?.Cancel();
|
|
|
|
|
|
cancellationTokenSource?.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-23 18:43:38 +09:00
|
|
|
|
private void LoadConfig()
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20>⺻<EFBFBD><E2BABB> <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> ã<><C3A3> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
|
|
|
|
|
string defaultIp = "127.0.0.1";
|
|
|
|
|
|
int defaultPort = 8888;
|
|
|
|
|
|
|
|
|
|
|
|
string path = Path.Combine(Application.streamingAssetsPath, configFileName);
|
|
|
|
|
|
|
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var config = new Dictionary<string, string>();
|
|
|
|
|
|
string[] lines = File.ReadAllLines(path);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (string line in lines)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(line) || line.Trim().StartsWith("#"))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
string[] parts = line.Split('=');
|
|
|
|
|
|
if (parts.Length == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
config[parts[0].Trim()] = parts[1].Trim();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (config.ContainsKey("IP_ADDRESS"))
|
|
|
|
|
|
{
|
|
|
|
|
|
hostip = config["IP_ADDRESS"];
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
hostip = defaultIp;
|
|
|
|
|
|
Debug.LogWarning($"config <20><><EFBFBD>Ͽ<EFBFBD> IP_ADDRESS Ű<><C5B0> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>. <20>⺻<EFBFBD><E2BABB>({defaultIp}) <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (config.ContainsKey("TCP_PORT"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (int.TryParse(config["TCP_PORT"], out int parsedPort))
|
|
|
|
|
|
{
|
|
|
|
|
|
tcpPort = parsedPort;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
tcpPort = defaultPort;
|
|
|
|
|
|
Debug.LogWarning($"config <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> TCP_PORT <20><><EFBFBD><EFBFBD> <20>߸<EFBFBD><DFB8>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>. <20>⺻<EFBFBD><E2BABB>({defaultPort}) <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
tcpPort = defaultPort;
|
|
|
|
|
|
Debug.LogWarning($"config <20><><EFBFBD>Ͽ<EFBFBD> TCP_PORT Ű<><C5B0> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>. <20>⺻<EFBFBD><E2BABB>({defaultPort}) <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (config.ContainsKey("UDP_PORT"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (int.TryParse(config["UDP_PORT"], out int parsedPort))
|
|
|
|
|
|
{
|
|
|
|
|
|
udpPort = parsedPort;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
udpPort = defaultPort;
|
|
|
|
|
|
Debug.LogWarning($"config <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> UDP_PORT <20><><EFBFBD><EFBFBD> <20>߸<EFBFBD><DFB8>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>. <20>⺻<EFBFBD><E2BABB>({defaultPort}) <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
udpPort = defaultPort;
|
|
|
|
|
|
Debug.LogWarning($"config <20><><EFBFBD>Ͽ<EFBFBD> UDP_PORT Ű<><C5B0> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>. <20>⺻<EFBFBD><E2BABB>({defaultPort}) <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log($"Config <20>ε<EFBFBD> <20><><EFBFBD><EFBFBD>: {hostip}:{tcpPort}/{udpPort}");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (System.Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"Config <20><><EFBFBD><EFBFBD> <20>ε<EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><EFBFBD>: {e.Message}. <20>⺻<EFBFBD><E2BABB> <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
hostip = defaultIp;
|
|
|
|
|
|
tcpPort = defaultPort;
|
|
|
|
|
|
udpPort = defaultPort;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"{configFileName} <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ã<><C3A3> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>. <20>⺻<EFBFBD><E2BABB>({defaultIp}:{defaultPort}) <20><><EFBFBD><EFBFBD>.");
|
|
|
|
|
|
hostip = defaultIp;
|
|
|
|
|
|
tcpPort = defaultPort;
|
|
|
|
|
|
udpPort = defaultPort;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-24 11:55:43 +09:00
|
|
|
|
|
|
|
|
|
|
private IEnumerator PollMotorStateCoroutine()
|
|
|
|
|
|
{
|
|
|
|
|
|
while (true)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return new WaitForSeconds(motorStatePollInterval);
|
|
|
|
|
|
|
|
|
|
|
|
_ = presenter.UpdateMotorStateAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-14 16:38:35 +09:00
|
|
|
|
}
|