Unity WebGL UnityWebRequest Обработка данных - PullRequest
0 голосов
/ 26 сентября 2018

У меня проблема с Unity WebGL и способом обработки загруженных данных из UnityWebRequests.В автономной версии я жду загруженных данных с while (!async.isDone) { }, а затем json сериализует их.После этого я делаю yield return null;.Таким образом, данные обрабатываются после возврата урожая, когда они были полностью обработаны первыми.Но в WebGL while (!async.isDone) { } не разрешено, как объясняется в официальных документах WebGL Networking .

Итак, как лучше всего решить эту проблему?Что-то вроде вызова обработки в той же сопрограмме после завершения обработки?Но тогда у меня все еще есть проблема с созданием gameObjects с обработанными данными, поскольку вы можете создавать gameObjects только в основном потоке единицы.

Кто-нибудь сталкивался с такой же проблемой и нашел решение?

Заранее спасибо!

Обновление: Вот полный пример кода:

private IEnumerator m_GetUserToken(string accesscode, string password)
{
    UnityWebRequest request = new UnityWebRequest(v_ServerIP + "api-token-auth/", "POST");

    byte[] bodyRaw = Encoding.UTF8.GetBytes("{\"username\":\"" + accesscode + "\", \"password\":\"" + password + "\"}");
    request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
    request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
    request.SetRequestHeader("Content-Type", "application/json");
    request.chunkedTransfer = false;
    UnityWebRequestAsyncOperation async = request.SendWebRequest();

    while (!async.isDone) { }

    if (request.isNetworkError || request.isHttpError)
    {
        v_TokenSuccess = false;
        Debug.Log("Token Error: " + request.error);
        Debug.Log("Token Response Code: " + request.responseCode);
    }
    else
    {
        v_UserToken = JsonUtility.FromJson<UserToken>(request.downloadHandler.text);
        v_TokenSuccess = true;
    }
    yield return Timing.WaitForOneFrame;
}

Обновление2:

Поскольку это еще как-то неясно, вот еще один пример:

#Main Thread

string s = "";

StartCoroutine(functionname);
Debug.Log(s);

#Coroutine
private IEnumerator functionname(){
   downloadTextfromUrl
   while(!downloadFinished) {yield return null}
   s = downloadText;
}

Таким образом, после вызова yield return null вызывается Debug.Log(s), а s все еще пуст, поскольку s = downloadText еще не был вызван.

1 Ответ

0 голосов
/ 26 сентября 2018

Ожидая завершения запроса UnityWebRequest со свойством async.isDone, вы должны выходить из этого цикла while.Ваш текущий код может вызвать бесконечный цикл на устройствах Android или сбой загрузки.В документации, на которую вы ссылаетесь, написано, что вы можете использовать while (!async.isDone) , но вы должны ее получить.Это относится ко всем платформам, а не только к WebGL.

Заменить

while (!async.isDone) { }

на

while (!async.isDone) { yield return null; }

Это заставит цикл while выполнять каждый кадр и проверять, async.isDone имеет значение true вместо блокировки всей программы.


Примечание:

При втором редактировании вы также хотите получить доступ к загруженным данным вне функции.Например, вы хотите сделать это:

StartCoroutine(functionname());
//then use the downloaded data
Debug.Log(downloaded_data);

У вас есть два способа сделать это:

1 .Получите функцию coorutine, как я делал выше, но с yield return StartCoroutine(functionname()).Это должно быть сделано из другой функции сопрограммы:

Функция запроса:

string v_UserToken;

IEnumerator m_GetUserToken(string url)
{
    UnityWebRequest request = UnityWebRequest.Get(url);
    UnityWebRequestAsyncOperation async = request.SendWebRequest();
    while (!async.isDone) { yield return null; }

    if (request.isNetworkError || request.isHttpError)
    {
        v_UserToken = request.error;
    }
    else
    {
        v_UserToken = request.downloadHandler.text;
    }
}

Затем дождитесь его завершения после вызова:

IEnumerator AnotherCoroutineFunc()
{
    //Call and wait for the m_GetUserToken coroutine to finish
    yield return StartCoroutine(m_GetUserToken("YourURL"));
    //You can now use the v_UserToken variable
    Debug.Log(v_UserToken);
}

2 . Вы можете использовать Action, чтобы дождаться его.

Функция запроса с Action:

IEnumerator m_GetUserToken(string url, Action<string> result)
{
    UnityWebRequest request = UnityWebRequest.Get(url);
    UnityWebRequestAsyncOperation async = request.SendWebRequest();
    while (!async.isDone) { yield return null; }

    if (request.isNetworkError || request.isHttpError)
    {
        Debug.Log(request.error);
        if (result != null)
            result(request.error);
    }
    else
    {
        Debug.Log(request.downloadHandler.data);
        if (result != null)
            result(request.downloadHandler.text);
    }
}

Вы можете использовать лямбду для возврата результата:

void NonCoroutineFunction()
{
    StartCoroutine(m_GetUserToken("YourURL", (v_UserToken) =>
    {
        //You can now use the v_UserToken variable
        Debug.Log(v_UserToken);
    }));
}
...