Saturday, March 15, 2014

Unity Part VIII: Unity and Parse.com Part 2: The Reckoning

I'm having a lot of difficulty understanding multi-threading in parse.com. I've posted question to Parse's forums and I'll be updating my blog when I get it all figured out.

The main issue I'm having is continuing the execute code after calling an asynchronous command to parse and getting a response. I get this error:

InternalGetGameObject can only be called from the main thread. 
Constructors and field initializers will be executed from the loading thread when loading a scene. 
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

It occurs from doing something that, I think, should be very basic: Hiding my login form after a successful login. Here's the code:

private void ValidLogin(string un, string pw, LoginCallback loginCallback)
{
    Task task = ParseUser.LogInAsync(un, pw).ContinueWith(t =>
    {
        if (t.IsFaulted || t.IsCanceled)
        {
            _LoginErrorMessage = t.Exception.Message;
        }
        Test();
    });
}

private void Test()
{
    if (_LoginErrorMessage == "")
    {
        SetVarsFromParseUser();
        SaveLocalUserData();
        RemoveLoginForm(); // This function causes an error
    }
    else
    {
        PrintFormErrorMessage(_LoginErrorMessage);
    }
}

public void RemoveLoginForm()
{

    LoginUserMenuInstance.gameObject.SetActive(false);
}

Removing "RemoveLoginForm" negates the error, but then my login form would be on the screen... forever!!!

I suspect the error is from trying to execute code for the main thread in a subthread, but I have no idea how to achieve what I want to do otherwise.

This week I also got local save data in. I am basically saving to XML at the moment, but this is insecure, so I'd like to find a better way. At the moment, the user could simply edit the XML to cheat. Nevertheless, I've included my method below.


private void SaveXml()
{
    GameData.username = Username;
    GameData.password = Utility.Md5Sum(Password);   // Custom function for converting to MD5
    XmlSerializer serializer = new XmlSerializer(typeof(GameData));
    FileStream stream = new FileStream(_DataFile, FileMode.Create);
    serializer.Serialize(stream, GameData);
    stream.Close();
}

private bool OpenXml()
{
    Xml = new XmlDocument();
    XmlSerializer serializer = new XmlSerializer(typeof(GameData));
    FileStream stream = new FileStream(_DataFile, FileMode.Open);
    GameData = serializer.Deserialize(stream) as GameData;
    stream.Close();
    return true; // for later in case I decide to do error checking.
}
As you can see, the code requires a custom class for handling XML and I've named mine GameData. I've included it so you can see how it works.
using System.Xml;
using System.Xml.Serialization;
 
[XmlRoot("GameData")]
public class GameData
{
    public string username;
    public string password;
    public int lastLocation;
    public uint goldCoinCount;
    public uint productoTronCount;
    public uint cityLandLotCount;
    public uint beachLandLotCount;
    public uint forestLandLotCount;
    public uint mineLandLotCount;
    public uint storage;    
}
For more info on saving and loading XML for your Unity game, check out this article on Unity's wiki.

No comments:

Post a Comment