question

chad avatar image
chad asked

SimpleJson

It seems the JsonConvert has been depreciated and SimpleJson is the new way, but where can I find complete documentation to the new class and how to use it?

PlayFab.SimpleJson.DeserializeObject

 

Thank you

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1807605288 avatar image
1807605288 answered

There is a file in our sdk called JsonUnitTests.cs  This provides some working examples for you to emulate.

But SimpleJson is designed to be.... simple!

// To serialize an object, call the SerializeObject function:
string json = PlayFab.SimpleJson.SerializeObject(yourObj);
// To get it back, call DeserializeObject
YourType actualObj = PlayFab.SimpleJson.DeserializeObject<YourType>(json);

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

chad avatar image
chad answered

Thank you for your response.

That seems simple for object types that I create myself, but how do I know what object types to use when deserializing objects that come from the Server API? For example, how would I change this code (found in PlayFab's tutorial) to the new SimpleJson methods?

GetUserDataResult dataResult = JsonConvert.DeserializeObject(result.Results.ToString());
foreach (KeyValuePair entry in dataResult.Data)
{
  Debug.Log(entry.Key + " == " + entry.Value.Value);
}

https://api.playfab.com/docs/using-cloud-script/

Thank you
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

chad avatar image
chad answered

I tried this to get the data but this fails at the "UserDataRecord" line, which it seems like it shouldn't. This also doesn't seem to be right as it doesn't feel "simple" like the name suggests. Still trying to figure out the right way to accomplish converting this data..

 

Dictionary<string, object> dataResults = PlayFab.SimpleJson.DeserializeObject<Dictionary<string, object>>(result.ResultsEncoded);
Dictionary<string, object> userDataRecords = PlayFab.SimpleJson.DeserializeObject<Dictionary<string, object>>(dataResults["Data"].ToString());
foreach (KeyValuePair<string, object> userDataRecord in userDataRecords)
{
UserDataRecord temp = PlayFab.SimpleJson.DeserializeObject<UserDataRecord>(userDataRecord.Value.ToString());
Debug.Log(userDataRecord.Key + "=" + temp.Value);
}

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

chad avatar image
chad answered

Okay, one more time. I'm guessing this is a possible way this function is supposed to be used. I looked at the Json and created a class that mimicked the structure and passed that into the deserializer and it worked. 

Class I created:

public class GetUserReadOnlyData
{
public class UserDataRecord
{
public string Value;
public DateTime LastUpdated;
public string Permission;
}

public string PlayFabId;
public int DataVersion;
public Dictionary<string, UserDataRecord> Data;
}

 

Call to Deserializer:

GetUserReadOnlyData dataResults = PlayFab.SimpleJson.DeserializeObject<GetUserReadOnlyData>(result.ResultsEncoded);

Is this correct?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1807605288 avatar image
1807605288 answered

I need to resolve a few elements of this thread into separate answers.

First, cloudscript.  There is not a pre-defined return format for cloudscript.  So, for cloudscript, you DO want to create a custom object that matches the return format of a specific cloudscript call.  Different cloudscript calls return different results in different formats, so you have to match the signatures just as you say.

https://api.playfab.com/Documentation/Client/method/GetUserData
https://api.playfab.com/Documentation/Client/method/GetUserReadOnlyData
These api calls should return correctly formatted results, in pre-defined structures.  You shouldn't need to deserialize anything yourself.

So, to clarify our discussion, what api are you calling, with what parameters?  How are you getting json that contains UserDataRecords?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

chad avatar image
chad answered

I'm brand new to PlayFab and and just starting to learn how everything works here. I'm following your tutorial here https://api.playfab.com/docs/using-cloud-script/ but it's full of syntax errors and outdated code which makes it harder to understand. At the end of section "Deserializing Cloud Script JSON Strings", magic seems to happen where a Json string from the server gets converted into a PlayFab class called "GetUserDataResult" yet this code doesn't work at all and leaves me confused about how this is even supposed to work considering this code is now obsolete.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Sorry for the confusion. The C# in that document assumes you're using our Unity SDK, which passes a GetUserDataResult to the callback function you specify when you call GetUserData.

But that said, what syntax errors and obsolete code are you encountering? It is true that we'll be deprecating the RunCloudScript call in favor of ExecuteCloudScript soon, but the call will continue to work. One thing we're committed to is not having breaking changes which would impact existing titles.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

chad avatar image
chad answered

I'm using Unity.

 

With this line of code there are both obsolete classes/methods and syntax errors. The syntax errors I can deal with although it's questionable why they're there. Here's the code copied from the link I gave:

GetUserDataResult dataResult = JsonConvert.DeserializeObject(result.Results.ToString());
foreach (KeyValuePair entry in dataResult.Data)
{
  Debug.Log(entry.Key + " == " + entry.Value.Value);
}

As soon as I paste this code "KeyValuePair" errors out because it should say something like "KeyValuePair<string, string>" (I can't remember what the data types are). After that's figured out, it gives a warning that says JsonConvert is obsolete and to use SimpleJson. OK. So I change this to SimpleJson, and now SimpleJson requires a Generic Type which I paste in "GetUserDataResult" into hoping that's what it wants. That doesn't work. I'm stuck here wondering what Generic Type SimpleJson needs in order for this snippet of code to function.

 

Can you convert that snippet of code into functional code that uses SimpleJson the way it was intended?

 

Thank you

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1807605288 avatar image
1807605288 answered

Chad, thanks for your feedback.  I will try to get the CloudScript getting-started guide updated.

Somebody from PlayFab will post here one more time when it's been updated.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1807605288 avatar image
1807605288 answered

Chad:

Thank you for bringing this to our attention.  We have looked over the current CloudScript Getting Started guide, and we agree that it needs a re-write.

On that note, I've just finished the code-files that we will use to generate the next Getting Started Guide.  I've tested them myself, and they demonstrate the same set of features, with tested and working code.

Save this file as "cloud.js" and upload it as your latest revision of CloudScript using the same process:

========= FILE "cloud.js" BEGIN =========
handlers.helloWorld = function (args) {
    var message = "Hello " + currentPlayerId + "!";
    log.info(message);
    return { messageValue: message };
}

handlers.cloudScriptExample = function (args) {
    var message = "Hello " + args.name + "!";
    log.info(message);
    return { messageValue: message };
}

handlers.easyLogEvent = function (args)
{
    log.info(JSON.stringify(args.logMessage));
}
========= FILE "cloud.js" END =========

The other file you want is the Unity code that invokes these calls.
Save this file as "CloudScriptExample.cs", and add it to your unity project:

========= FILE "CloudScriptExample.cs" BEGIN =========
using UnityEngine;
using PlayFab;
using PlayFab.ClientModels;
using PlayFab.Json;

public class CloudScriptExample : MonoBehaviour
{
    public bool CloudHelloWorld = false;
    public bool CloudLog = false;

    /// <summary>
    /// This code just makes the example easy to run/rerun from the Inspector
    /// </summary>
    public void Update()
    {
        if (CloudHelloWorld)
        {
            CloudHelloWorld = false;
            StartCloudHelloWorld();
        }

        if (CloudLog)
        {
            CloudLog = false;
            StartCloudLog();
        }
    }

    /// <summary>
    /// A shared error handler for all api calls.
    /// You can have custom error handlers for each call, or a generic one that displays the full error
    /// </summary>
    private static void OnErrorShared(PlayFabError error)
    {
        Debug.LogError("Error in CloudScript Example:");
        string fullMsg = error.ErrorMessage;
        if (error.ErrorDetails != null)
            foreach (var pair in error.ErrorDetails)
                foreach (var eachMsg in pair.Value)
                    fullMsg += "\n" + pair.Key + ": " + eachMsg;
        Debug.LogError(fullMsg);
    }

    /// <summary>
    /// Mandatory setup for every project.
    /// You must assign a titleId - If you fail to do so, all calls will throw an error
    /// You must log in - If you fail to do so, all non-login calls will throw an error
    /// </summary>
    public void Start()
    {
        PlayFabSettings.TitleId = "NOTE: Put your title id here";
        PlayFabClientAPI.LoginWithCustomID(new LoginWithCustomIDRequest { CreateAccount = true, CustomId = "CloudExample" }, null, OnErrorShared);
    }

    /// <summary>
    /// Initialize the "Hello YOUR NAME" example
    /// </summary>
    private static void StartCloudHelloWorld()
    {
        ExecuteCloudScriptRequest request = new ExecuteCloudScriptRequest()
        {
            FunctionName = "cloudScriptExample", // Arbitrary function name (must exist in your uploaded cloud.js file)
            FunctionParameter = new { name = "YOUR NAME" }, // The parameter provided to your function
            GeneratePlayStreamEvent = true, // Optional - Shows this event in PlayStream
        };
        PlayFabClientAPI.ExecuteCloudScript(request, OnCloudHelloWorld, OnErrorShared);
    }

    /// <summary>
    /// The result handler for the "Hello YOUR NAME" example
    /// </summary>
    private static void OnCloudHelloWorld(ExecuteCloudScriptResult result)
    {
        Debug.Log(PlayFab.SimpleJson.SerializeObject(result));
        // Cloudscript returns arbitrary results, so you have to evaluate them one step and one parameter at a time
        Debug.Log(PlayFab.SimpleJson.SerializeObject(result.FunctionResult));
        JsonObject jsonResult = (JsonObject)result.FunctionResult;
        object messageValue;
        jsonResult.TryGetValue("messageValue", out messageValue);
        Debug.Log((string)messageValue);
    }

    /// <summary>
    /// Initialize the arbitrary inputs and logging example
    /// </summary>
    private static void StartCloudLog()
    {
        ExecuteCloudScriptRequest request = new ExecuteCloudScriptRequest()
        {
            FunctionName = "easyLogEvent", // Arbitrary function name (must exist in your uploaded cloud.js file)
            FunctionParameter = new { logMessage = "My log message" }, // The parameter provided to your function
            GeneratePlayStreamEvent = true, // Optional - Shows this event in PlayStream
        };
        PlayFabClientAPI.ExecuteCloudScript(request, OnCloudLog, OnErrorShared);
    }

    /// <summary>
    /// The result handler for the arbitrary inputs and logging example
    /// </summary>
    private static void OnCloudLog(ExecuteCloudScriptResult result)
    {
        // Cloudscript returns arbitrary results, so you have to evaluate them one step and one parameter at a time
        Debug.Log(PlayFab.SimpleJson.SerializeObject(result));
        foreach (var eachLog in result.Logs)
            Debug.Log(eachLog.Message);
    }
}
========= FILE "CloudScriptExample.cs" END =========

You need to replace "NOTE: Put your title id here" with the titleId for your PlayFab title, found in the Game Manager.
Attach the CloudScriptExample to any gameObject, run your game, and then view the component in the gameObject inspector.

This invokes cloudScript via our new (simpler) ExecuteCloudScript API.  Please let us know if you have any issues with these new example files.  Thanks for reporting the issue with our guide, and sorry for the problems.  We'll work to get the guide itself resolved and updated soon.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.