#c# #visual-studio #unity3d
Вопрос:
У меня есть предложение try-catch в многопользовательском проекте для проверки состояния соединения (через UDP) в Unity. Он получает обратный вызов от сервера в блоке кода try, а блок кода catch предназначен для получения исключения в случае внезапного прерывания соединения. Моя проблема в том, что блок catch не выполняет код, который я использую для информирования пользователя о том, что соединение с сервером было потеряно. Кажется, что он выполняет код только относительно исключения (например, Отладка.Error(e)).
//Callback from server connection
private void ConnectCallback(IAsyncResult _result) {
try {
//Ends connection
socket.EndConnect(_result);
} catch (Exception e) {
//These three lines are the problem. They won't execute
UIManager.instance.logPanel.enabled = true;
UIManager.instance.logPanel.text = "Servidor no disponible";
UIManager.instance.HideUsernameSelection();
}
//If theres no connection to the server the function returns
if (!socket.Connected)
{
return;
}
//Reference to data stream
stream = socket.GetStream();
//Packet for data received from server
receivedData = new Packet();
//Read
stream.BeginRead(receiveBuffer, 0, dataBufferSize, ReceiveCallback, null);
}
Есть ли в любом случае способ заставить блок catch выполнить код внутри него?
Комментарии:
1. разъем. EndConnect, похоже, завершает соединение (согласно комментариям в коде и документах MS). Я не вижу никакого метода подключения в попытке, так почему вы ожидаете, что обнаружите ошибку?
2. Извините, я не скопировал всю функцию целиком. Я только что обновил его. Я хочу выполнить функции из UIManager, если обратный вызов при подключении к серверу отрицательный, чтобы я мог показать пользовательский интерфейс повторного подключения и ошибку сервера.
Ответ №1:
Почти уверен, что проблема в том, что этот вызов выполняется асинхронно, поэтому в другом потоке/задаче.
Большая часть API Unity может использоваться только в основном потоке Unity. (Единственным исключением являются в основном все чистые математические структуры, которые непосредственно не влияют на сцену и не зависят от нее.)
В большинстве случаев это решается с помощью так называемого «Диспетчера основного потока». Это выглядит примерно так, например.
public class MainThreadDispatcher : MonoBehaviour
{
#region Singleton Pattern
private static MainThreadDispatcher _instance;
public static MainThreadDispatcher Instance
{
get
{
if(_instance) return _instance;
_instance = FindObjectOfType<MainThreadDispatcher>();
if(_instance) return _instance;
_instance = new GameObject(nameof (MainThreadDispatcher)).AddComponent<MainThreadDispatcher>();
}
}
private void Awake ()
{
if(_instance amp;amp; _instance != this)
{
Destroy (gameObject);
return;
}
_instance = this;
DontDestroyOnLoad(gameObject);
}
#endregion
#region Dispatcher
private readonly Queue<Action> _actions = new Queue<Action>();
private void LateUpdate ()
{
lock (_actions)
{
while(_actions.Count > 0)
{
var action = _actions.Dequeue();
action?.Invoke();
}
}
}
public void DoInMainThread(Action action)
{
lock(_actions)
{
_actions.Enqueue(action);
}
}
#endregion
}
И тогда вы предпочли бы отправить все, что связано с Unity API, например
try
{
//Ends connection
socket.EndConnect(_result);
}
catch (Exception e)
{
MainThreadDispatcher.Instance.DoInMainThread(() =>
{
// To have the information is always helpful I'd say ;)
Debug.LogWarning($"{e.GetType()} - {e.Message}/n{e.StackTrace}");
UIManager.instance.logPanel.enabled = true;
UIManager.instance.logPanel.text = "Servidor no disponible";
UIManager.instance.HideUsernameSelection();
}
}
Комментарии:
1. @alex2furious, я рад слышать, что ваша проблема решена, вы можете нажать » ✔ » для соответствующего ответа в качестве ответа. Это также поможет другим решить аналогичную проблему.