0
\$\begingroup\$

I have become completely stummped on this. I have a login screen i have created, i have everything working except 1 thing. When i click "login" i want to hide the Login screen object (wm.LoginSWindowHide()) below. and show a small window that shows "Authenticating", then change that text when done.

my code is below the ActionAuthentication method is called on click of the button method. The outcome i am seeing is the Rest call being done successfully then the authenticating window popup. even though i have specifically done it the other way around (change the windows, then make the call)

public void ActionAuthentication()
    {
        wm.AuthenticatingWindowShow();  //runs after DoAuth()
        wm.LoginWindowHide(); //runs after DoAuth()

       DoAuth();
    }


public void DoAuth()
{
    loginAPI.wwwData = null;
    loginAPI.Authenticate(UserNameInput.text, PasswordInput.text); 
    //this sets wwwData to the WWW result within the class.  which is why i can call
    //it later on and why i reset it to null before calling it (Clear the variable 
    //in case they failed a previous login)

    hasLoginBeenAttempted = true;
    PostAuth();



}

public void PostAuth()
{

        if (loginAPI.wwwData.isDone)
        {

         //Exeucte my code.... this is currently successful but runs before updating the windows.

        }
    }
}

i have tried using co routines to do this as i suspect it's running my code and blocking Update from occurring, but i get exactly the same result.

public void ActionAuthentication()
{
    wm.AuthenticatingWindowShow();
    wm.LoginWindowHide();
    StartCoroutine("DoAuth");

}


IEnumerator DoAuth()
{
    loginAPI.wwwData = null;
    loginAPI.Authenticate(UserNameInput.text, PasswordInput.text);
    yield return new WaitForRest(loginAPI);


}



public class WaitForRest : CustomYieldInstruction
{

    private bool isDone = false;

   public override bool keepWaiting
    {
        get
        {
            return isDone;
        }
    }

    public WaitForRest(API loginAPI)
    {
        if(loginAPI.wwwData.isDone)
        {
            isDone = true;
        }
    }
}

In case it helps, my API class contains the following code.

public WWW wwwData;

public API()
{
    wwwData = null;
}

public string Authenticate(string UserName, string Password)
{

    AuthData authData = new AuthData(UserName, Password);

    string body = JsonConvert.SerializeObject(authData);
    string url = "http://RandomURL/api/aPath/Authorise";

    byte[] postBody = Encoding.ASCII.GetBytes(body.ToCharArray());

    wwwData = DoPost(url, postBody);

    if (wwwData.error != null)
    {
        return wwwData.error;
    }
    else
    {
        return wwwData.text;
    }

}


public WWW DoPost(string url, byte[] requestBody)
{

    Dictionary<string, string> headers = new Dictionary<string, string>();
    headers.Add("Content-Type", "application/json");
    headers.Add("Accept", "application/json");

    WWW www = new WWW(url, requestBody, headers);

    return www;


}

I'm not adding the REST API Code because i don't think that's relevant and is successfully returning what i expect. (even to the code above, i just can't get it to execute in the right order)

\$\endgroup\$
1
  • \$\begingroup\$ How are you managing your windows? Can you provide to us the implementation of wm? \$\endgroup\$
    – EvilTak
    Jun 5, 2017 at 16:05

1 Answer 1

2
\$\begingroup\$

Any UI changes (like showing and hiding UI elements) only get applied when the currently executed event method (in this case ActionAuthentication) is finished. But that takes a while because your Authenticate method is blocking. It blocks because it requests the property wwwData.error before the webserver responded. As the documentation says:

If the object has not finished downloading the data, it will block until the download has finished. Use isDone or yield to see if the data is available.

Wrapping the call to that method with a coroutine doesn't help, because coroutines aren't actually doing multithreading. When you call StartCoroutine, the passed method is executed immediately until the first yield.

What you can do instead is make the method Authenticate a coroutine and have it do yield return new WaitForFixedUpdate()'s until the server responded:

wwwData = DoPost(url, postBody);

while (!wwwData.isDone) {
    yield return new WaitForFixedUpdate();
}

if (String.IsNullOrEmpty(wwwData.error))
{
    // handle error
}
else
{
    // handle success
}
\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .