Blog

Latest news and updates from the PlayFab developers

by Janeious 2020-04-28

Porting "Fusion Guards" from GameSparks to PlayFab (Part 1)

We are Janeious, an independent game development studio with offices in Ireland and Germany working on our community funded debut title “Fusion Guards”. The game is a turn-based RPG for mobile with a large backend component. After four years of development our game is currently in Beta on Android and iOS. We built our game on GameSparks but recently decided to investigate a migration to PlayFab. This is our journey:

First Steps

We decided to tackle the migration in small steps, so we wouldn’t get overwhelmed by the scale of what was required.

In this first tutorial, we look at migrating the basic player account details needed to setup the player when they first launch the app and get registered on PlayFab, including:

  • Registration & Login
  • Automatically Setting Up the Player Account
  • CloudScript
  • Custom Player Data
  • Custom Requests

Expectations

Coming from GameSparks, we knew there would be obstacles to face migrating from one service to another. Many of the out-of-the-box features we use in GameSparks are available on PlayFab, and you can get an idea of what comparable features you can match from GameSparks to PlayFab from their website.

However, we also use a lot of custom code and custom player data on GameSparks, so this was our main concern starting out.

Where Do We Put Player Data?

In GameSparks we create custom collections using the Game Data Service, which lets us stick any structures we need into a document we can reference using player’s ID. We needed to find something similar in PlayFab for custom player data.

How Do We Control Access to Player Data?

Because GameSparks lets us use custom data, as well as store public and private data on player accounts, we needed some way of restricting player data to read-only by the client. All our player data (with a few exceptions) is controlled by Cloud Code. We didn’t want the player to be able to change it if they hack the client.

Where to Start?

The simplest place to start was with player account features we could use out-of-the-box in PlayFab.

For us this included virtual currencies, which players use to buy upgrades and new items. We use a combination of the following currencies…

  • Cells: Our premium currency, used to buy shiny things
  • Credits: Currency earned in-game through missions and can be used for a variety of items and upgrades.
  • Timers: Used for loot-drops and refreshed at the start of each daily login.

Virtual Currencies

Both GameSparks and PlayFab have virtual currencies which operate much the same way. Virtual currencies are attributes of the player account. All that’s needed for each currency is a name and code. You can find out more about PlayFab currencies in the documentation.

Virtual currency in GameSparks
Virtual currency in GameSparks
Virtual currency in PlayFab
Virtual currency in PlayFab

Both services let you enter a starting amount for each currency so that when a new player account is created, the platform delivers that amount automatically to the player.

Recharging Currency

In Fusion Guards we have a set of currencies we call timers, which are used to get a limited number of free items per day. In GameSparks, we needed to use custom-code to reset these values every day. PlayFab already has a feature we used for this (without any custom code) called recharge. We were able to set our timers up immediately using the recharge feature.

Creating a new virtual currency in PlayFab
Creating a new virtual currency in PlayFab

Project Integration

Next we wanted to look at what player account features were available. Before we could do this we needed to start registering players with our client.

Since this is the first tutorial, we should talk briefly about how the SDK and frontend project setup work.

Coming from an existing project in GameSparks to PlayFab wasn’t difficult. Both have Unity SDK packages you can import directly. Both SDKs are easy to setup and there are guides available.

We did find the differences between the editor extensions package and the UnitySDK package confusing.

Most of the guides and video tutorials for PlayFab start with the extensions package. Start from there you won’t have any issues.

However, if you import the SDK first you’ll be wondering why things seem different in your project than in the guides, and you won’t have the option to link your project with your game. In that case you might want to uninstall the SDK and try again with the editor extensions.

Authentication & Registration

The first thing we needed to get setup was the PlayFab controller script to get registration and authentication working. 

This was pretty much identical to GameSparks. 

Although PlayFab doesn’t use websockets, it does use a request/response flow we could map to similar calls we used for GameSparks.

For example, onSuccess and OnFailed callbacks for authentication and registration can be replaced with similar PlayFab calls.

The request structure is also similar, and was quick to setup using the guide in the PlayFab documentation.

/// <summary>
/// Delegate used for successful registration
/// </summary>
public delegate void onRegistrationSuccess(RegisterPlayFabUserResult result);
/// <summary>
/// Delegate used when a request failed
/// </summary>
public delegate void onReqFailed(PlayFabError error);
/// <summary>
/// Register the specified userName, password, onRegSuccess and onRegFailed.
/// </summary>
/// <param name="userName">User name.
/// <param name="password">Password.
/// <param name="onRegSuccess">On reg success.
/// <param name="onRegFailed">On reg failed.
public void Register(string userName, string password, onRegistrationSuccess onRegSuccess, onReqFailed onRegFailed)
    Debug.Log("PFM| Registering Player...");
    Debug.Log("PFM| Username:" + userName + ", Pass:" + password);
    var reqSettings = new RegisterPlayFabUserRequest();
    reqSettings.DisplayName = userName;
    reqSettings.Username = userName;
    reqSettings.Password = password;
    reqSettings.RequireBothUsernameAndEmail = false;
    PlayFabClientAPI.RegisterPlayFabUser(reqSettings, 
        (RegisterPlayFabUserResult regResult) => {
            Debug.Log("PFC| Registration Successful...");
            Debug.Log("PFC| Player [" + regResult.PlayFabId + "] Logged In...");
            onRegSuccess(regResult);
        },
        (PlayFabError error) =>
    
            onRegFailed(error);
            ProcessErrors(error);
        });

PlayFab has similar options for authentication to GameSparks. You have username/password, which requires registration, and you have customIDs you can map to deviceIDs to replace GameSparks’s device authentication request.

Player List

One nice feature of PlayFab is that once you have a player registered, you can search for them in the dashboard’s player list.

Player list in PlayFab
Player list in PlayFab

This is very handy for those new to PlayFab or evaluating a migration (we spent a lot of time in GameSparks building custom screens to search for and view player data). You can always look for players in the GameSparks data-explorer, but this tool is a lot closer to the kinds of tools we needed to build for game-maintenance, live-ops and customer support.

Cloud Scripts

Once we had a player registered, we needed to find a way to setup players automatically when PlayFab creates a new player.

This was our first big hurdle, as we didn’t know exactly what PlayFab was capable of and what we could customize and modify.

In GameSparks we would do this using a request, or with the out-of-the-box scripts you can stick code into after a player registers.

Example player registration script in GameSparks
Example player registration script in GameSpark

For Fusion Guards, we used a combination of both, but we decided to start with some automatic setup as soon as the player registered.

PlayFab doesn’t have an exact one-to-one match to GameSparks’ registration response, but they have something similar we were able to use.

In this section on CloudScripts we’ll explain how we achieved this.

Introduction to PlayFab CloudScript

As you can guess, CloudScripts are the PlayFab equivalent to GameSparks cloud-code. Both offer similar functions and customization and both systems use JavaScript. 

The first major difference is that in GameSparks you create a LogEventRequest, which is tied to a custom event (or an existing out-of-the-box you want to add functionality to).

Example LogEvent script in GameSparks
Example LogEvent script in GameSparks

In PlayFab events are controlled by a single CloudScript where we add different functions depending on what we need to do. 

CloudScript works similar to GameSparks, the main difference is that some functions you create here can be mapped to server-actions in PlayFab (such as executing a function when our player registers), or to client requests.

This made them an effective alternative to GameSparks LogEventRequests, with some limitations. You can find the CloudScript feature in the Automation tab.

PlayFab Automation tab
PlayFab Automation tab

There are a lot of example functions already in the CloudScript when you setup your game which will help you understand how to write your own functions. You can also get a good idea of how things work by following the guide in the documentation.

Setting Up the Player’s Account

Our first function in CloudScript set the player’s level and XP values. We’ll revisit this function later, as we migrate different parts of the project and add features. This was enough to test it works.

In the CloudScript window we added a new function called createNewAccount.

Adding a new CloudScript function
Adding a new CloudScript function

We don’t pass anything into this function, as it will always setup the same parameters for each player.

All we needed to do was set some basic account information and call the UpdateUserReadOnlyData function. This sets user data which can only be read by the client. We can change this data using the CloudScript API, but the client has no permission to change it.  This is exactly what we wanted. (You can see an example in a PlayFab tutorial.)

/*
* Set the basic account details for this player upon registration
* @return {JSON} result
*/
handlers.createNewAccount = function(){
    // [1] - We need to create an object which will contain the basic details we are going to set //
    //       In this case it will be the level and the xp //
    var newAccountData = { "level" : 1, "xp" : 0 };
    // [2] - Next we are going to set the player's account data as read-only so that the client cannot change it //
    var result = server.UpdateUserReadOnlyData({ "PlayFabId" : currentPlayerId, "Data" : newAccountData, "Permission": "Private" });
    return {
        "result" : result
    
}

Logging

To test this we needed to log the result of the data-update. This let us track any registration errors and log the name of the player who registered.

Logging in CloudScript is pretty simple. (You can find out more from the PlayFab documentation.)

/*
* Set the basic account details for this player upon registration
* @return {JSON} result
*/
handlers.createNewAccount = function(){
    // [1] - We need to create an object which will contain the basic details we are going to set //
    //       In this case it will be the level and the xp //
    var newAccountData = { "level" : 1, "xp" : 0 };
    // [2] - Next we are going to set the player's account data as read-only so that the client cannot change it //
    var result = server.UpdateUserReadOnlyData({ "PlayFabId" : currentPlayerId, "Data" : newAccountData, "Permission": "Private" });
    // [3] - we'll log that this player has setup their account //
    var p = server.GetPlayerProfile({ "PlayFabId" : currentPlayerId });
    log.info("Player Registered ["+p.PlayerProfile.DisplayName+"]...");
    // [4] - We will log the result //
    if(result){
        log.info(result);
    }else{
        var errorMessage = "Error setting up player account ["+currentPlayerId+"]...";
        log.error(errorMessage);
        return {
            "error" : errorMessage
        
    
}

Deploying CloudScript Code

With the account creation flow setup, we just needed to make sure our API script was running the correct version. 

Each time you save the CloudScript, you create a new revision. (This is handy for version control, as it allows you to maintain a list of change-sets.)

To get the new version with the account setup code running on the live server we needed to deploy it.

At the top of the CloudScript window you can see your revision number and which revision is live. You need to save your revision and then click on the revision you want to deploy.

CloudScript revision number
CloudScript revision numbe

Debugging & Testing

For the next step, we wanted to test functions.

In GameSparks there’s a feature called the Test Harness which allows us to test calls.

GameSparks Test Harness
GameSparks Test Harness

PlayFab have their own tool to run CloudScripts which is similar.

If you go to the Player List, you can select a player from the list and click on the CloudScript tab.

CloudScript tab
CloudScript tab

You can see the current revision, and a drop-down with a list of functions available in that revision.

We just needed to select the createNewAccount function we created and click on Run Cloud Script.

(We didn’t need to pass any JSON into this function because our function doesn’t take any arguments.)

Test Response

CloudScript test response
CloudScript test response

When we ran the CloudScript function we could see logs containing the player’s display-name, along with the version of this player’s data. This let us debug and test our code in a similar way to GameSparks Test Harness.   

While this tool is not as comprehensive as the GameSparks Test Harness, it does give an alternative to testing everything through the client.

Rules

The next step was to have this function run automatically anytime a player registers. As mentioned before, in GameSparks we would use the RegistrationResponse, but in PlayFab we needed to setup a new Rule.

Editing a rule in PlayFab
Editing a rule in PlayFab

In our case we created a rule called OnPlayerCreated, which was triggered by the com.playfab.player_created event. 

There are a lot of useful events in the drop-down list which are handy to keep in mind for later components of your migration so it’s a good idea to take a look through that list for future reference.

To set this up, we added an Action to this Rule, which was to Execute Cloud Code Script, with our createNewAccount function selected.

We also toggled Publish Results As PlayStream Event on, so we could monitor logging while testing.

OnPlayerCreated rule
OnPlayerCreated rule

With that done we were ready to start registering players.

PlayStream

If you click on the dashboard tab, and then the PlayStream monitor, you will see there are some events already in your PlayStream.

PlayStream Monitor
PlayStream Monitor
There is a small “(i)” icon to the right of each of the PlayStream logs. If you click on this icon you will see details of the event that took place.
Raw event JSON
Raw event JSON
This is one way to check logs. (PlayFab doesn’t give access to the raw database logs, so we needed a way to check what was going on in our scripts.

Validation

Now we’ve seen how to execute CloudScript and how we can log and monitor events. What if we want to see that data while debugging?

In GameSparks we would have to either check our custom-built player manage screens or look in the database using the Data Explorer. 

In PlayFab you can check this data through the “Players” tab. Select the player that you ran code on and then go to Player Data (Title).

Player Data (Title)
Player Data (Title)
Here you can see that we set an object for level and XP.

Returning the Player Details

The next thing we needed was a request to call from the client and get this information back. We use this after login, or whenever we need to sync the player details, for example when the app is refreshed or the player has the app minimized for a long period of time.

GameSparks and PlayFab both have out-of-the-box functionality for getting player data, however, for our game we needed to limit the player’s access to these details. We don’t want players to be able to modify their currency or level for example. This should be completely handled by the backend.

We created a new function to return the level and XP from the player account. It’s also returns the player’s current balance for the cells, credits and timers we setup earlier.

We had to do some digging to find the correct APIs to use for this request, but it wasn’t too hard to figure out using the API documentation.

A good tip for finding the API’s you need to get is to check the forums for answers.

Often, we were looking for an API to get something back (the currency balance for example) only to find we could access this using an API we didn’t expect.  In this case, we used the GetUserInventory call, which fetches the player’s currency balances.

/*
* Return the player's account data
* @return {JSON} playerData
*/
handlers.getPlayerDetails = function(){
    // [1] - Now we can fetch the player's data //
    var playerDataRAW = server.GetUserReadOnlyData({ "PlayFabId" : currentPlayerId });
    // [2] - We want to convert this data to a JSON format we can parse in the client //
    var playerData = { "balances" : {} };
    for(var key in playerDataRAW.Data){
        var dataType = typeof playerDataRAW.Data[key].Value;
        switch(dataType){
            case "string" : {
                playerData[key] = playerDataRAW.Data[key].Value;
            } break;
            case "number" : {
                playerData[key] = parseInt(playerDataRAW.Data[key].Value);
            } break;
        
    
    // [3] - Now we can use the GetUserInventory call to get the player's current currency balances
    var playerInv = server.GetUserInventory({ "PlayFabId" : currentPlayerId });
    for(var vcKey in playerInv.VirtualCurrency){
        playerData.balances[vcKey] =  playerInv.VirtualCurrency[vcKey];
    
    
    return {
        "playerData" : playerData
    
}

We wanted to keep the structure similar to what we used in GameSparks, so we just nested the balances object in the response to fit what we already had on the frontend.

A quick test using one of our players and we were good to go.

Testing getPlayerDetails
Testing getPlayerDetails

Custom Requests Client-Side

We don’t want to go too much into how we hooked up requests from PlayFab to our Unity project, as there is a lot of custom code in there that specifically applies to what we need our game to do that won’t apply to your game.

But it’s interesting to look at how PlayFab deals with custom requests on the frontend as it’s similar to GameSparks.

The biggest difference is in how both systems deal with JSON, both as input (request payload) and output (response payload). Now, in the getPlayerDetails example we have no input, so we’ll skip input until later.

For PlayFab, the custom requests are sent using the PlayFabClientAPI.ExecuteCloudScript method, similar to registration and authentication. There’s a PlayFab guide that goes into more details.

/// <summary>
/// Used to return player details from the server
/// </summary>
/// <param name="onReqSuccess">
/// <param name="onRegFailed">
public void GetPlayerDetails(onReqSuccess onReqSuccess, onReqFailed onRegFailed)
    
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest(
    
        FunctionName = "getPlayerDetails", 
        GeneratePlayStreamEvent = true,
    },(ExecuteCloudScriptResult result) => {
        onReqSuccess(result);
    },
        (PlayFabError error) =>
   
            onRegFailed(error);
            ProcessErrors(error);
        });
/// <summary>
/// Delegate used for processing successful responses
/// </summary>
/// <param name="result">
public delegate void onReqSuccess(ExecuteCloudScriptResult result);

The PlayFab UnitySDK uses the Simple JSON integration to parse responses, although you could integrate your own parser if you needed to. 

Because GameSparks uses its own JSON object wrapper, we did need to take things apart a bit more than we’d have liked to parse the response data, but as you can imagine, this is because we were relying on another system to begin with.

So, to give an example you could call this GetPlayerDetails method and create a PlayerDetails class which can be constructed from the response.

public PlayerDetails(JsonObject response)
    
        if (response != null)
        
            response.TryGetValue("playerData", out object playerDataTemp);
            JsonObject playerData = (JsonObject)playerDataTemp;
            playerData.TryGetValue("level", out object levelTemp);
            playerData.TryGetValue("xp", out object xpTemp);
            level = int.Parse(levelTemp.ToString());
            xp = int.Parse(xpTemp.ToString());
            // Now we can parse the balances //
            playerData.TryGetValue("balances", out object playerBalancesTemp);
            JsonObject playerBalances = (JsonObject)playerBalancesTemp;
            playerBalances.TryGetValue("cells", out object cellsTemp);
            playerBalances.TryGetValue("credits", out object creditsTemp);
            playerBalances.TryGetValue("timer1", out object timer1Temp);
            cells = int.Parse(cellsTemp.ToString());
            credits = int.Parse(creditsTemp.ToString());
            timer1 = int.Parse(timer1Temp.ToString());

This is going to get a bit messy for more complicated responses, so we will probably clean this up in future.

Player Settings 1

The next thing we needed to figure out was a way to update player details from the client. As you can imagine this isn’t too far away from what we’d already done. We needed a function in the CloudScript, saved on the Player Data Object, in this case as public, and a client method that sends that info to PlayFab.

We started with a new function called setSettings. The only thing to note here is that we can’t nest objects in Player Data Objects, we can only add key-value pairs. So, to make things easier to maintain later on, we prefixed these fields with “settings_”.

/*
* Sets the player settings to the attributes passed into this function
* @param {JSON} args
* @return {JSON} response
*/
handlers.setSettings = function(args){
    // [1] - We'll do some validation on the settings passed in //
    var settings = {
        "settings_language" : (args.hasOwnProperty("language"))? args.language : "English", // << default - English
        "settings_volumeMusic": (args.hasOwnProperty("volumeMusic"))? args.volumeMusic : 50, // << default - 50
        "settings_volumeSFX": (args.hasOwnProperty("volumeSFX"))? args.volumeSFX : 50, // << default - 50
        "settings_notificationsPush": (args.hasOwnProperty("notificationsPus"))? args.notificationsPush : false, // << default - false
        "settings_notificationInGame": (args.hasOwnProperty("notificationInGame"))? args.notificationInGame : true, // << default - true
        "settings_autoCompleteWarning": (args.hasOwnProperty("notificationInGame"))? args.autoCompleteWarning : true, // << default - true
    
    // [2] - And now we can just update the player objects //
    var result = server.UpdateUserReadOnlyData({ "PlayFabId" : currentPlayerId, "Data" : settings, "Permission": "Private" });
    if(result){
        return {
            "status" : result
        
    }else{
        var errorMessage = "Error saving player settings ["+currentPlayerId+"]...";
        log.error(errorMessage);
        return {
            "error" : errorMessage
        
    
}

An important change in this function is the args parameter we passed in. This is a JSON object that contains the details we pass in from the client.

Testing & Validation

As you saw before, we could test this from the PlayFab portal before we jump into the client to hook up the request. The difference this time was we needed to pass in our JSON so there was something for the function to set.

Testing setSettings
Testing setSettings
And we were able to check out those fields immediately on the player account.

Bingo!

Sending Request Payload Client-Side

It’s straightforward to add data to the request payload. 

The request structure doesn’t change at all from what we saw with GetPlayerDetails and the registration requests, the only new thing was a field for FunctionParameters.

PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest()
        
            FunctionName = "setSettings",
            FunctionParameter = new
            
                language = "English",
                volumeMusic = 100,
                volumeSFX = 100,
                notificationsPush = false,
                notificationInGame = true,
                autoCompleteWarning = true
            },
            GeneratePlayStreamEvent = true,
        }, onReqSuccess, onReqFailed);

Now, obviously this is just an example. For normal operation in our game we’d add the settings to the PlayerDetails object, pass them in to the function and separate the values out for this FunctionParameter field, but you get the idea.

Player Settings 2

The next thing we needed to figure out was a way to update player details from the client. We needed a function in the CloudScript, that could validate what the player sends up and a client method to send that info to PlayFab.

For migrating the entire player account from GameSparks to PlayFab we needed a few more bits and pieces, but to start with we thought we’d try updating some players settings (volume, language, notification preferences etc.). These are basic requirements, but we knew if we could get those working we could use something similar in the future.

After looking at the UpdateUserReadOnlyData, we were thinking of going with key-value pairs being set on the Player Data, as we did for xp and level.

However, our settings, and other account information are setup as JSON objects in GameSparks, so translating them all to key-value pairs might get a bit messy in the long-run.

JSON settings data
JSON settings data

Luckily, PlayFab does have an alternative to this which works with something they call Entities.

This allows us to set object-data/JSON on an entity like our player, and it comes with its own set of APIs for the server and client. There is actually an example of how to use this call included in the default CloudScript example you get when you setup a new project. (Look for the makeEntityAPICall function.) But we will go through what we did to get this working here.

First, we created a new handler function called setSettings. This function needs two input attributes we hadn’t used before. We added args and context.

/**
 * This function will store the settings details passed in on the player's Entity Objects
 * @param {JSON} args
 * @param {JSON} context
 * @return {JSON} response
 */
handlers.setSettings = function (args, context) {
    
    
}

These are common attributes for PlayFab requests. The args parameter is used to get input from whatever source called the function (the client in this example). The context is important, as it contains a lot of information about the player and event which called the function and that’s where we get the Entity information we use to set the data on the player.

/**
 * This function will store the settings details passed in on the player's Entity Objects
 * @param {JSON} args
 * @param {JSON} context
 * @return {JSON} response
 */
handlers.setSettings = function (args, context) {
     // [1] - We'll do some validation on the settings passed in //
    var settings = {
        "language" : (args.hasOwnProperty("language"))? args.language : "English", // << default - English
        "volumeMusic": (args.hasOwnProperty("volumeMusic"))? args.volumeMusic : 50, // << default - 50
        "volumeSFX": (args.hasOwnProperty("volumeSFX"))? args.volumeSFX : 50, // << default - 50
        "notificationsPush": (args.hasOwnProperty("notificationsPus"))? args.notificationsPush : false, // << default - false
        "notificationInGame": (args.hasOwnProperty("notificationInGame"))? args.notificationInGame : true, // << default - true
        "autoCompleteWarning": (args.hasOwnProperty("notificationInGame"))? args.autoCompleteWarning : true, // << default - true
    }
    // [2] - We'll grab the entityProfile from the context so we can construct the SetObjects request //
    var entityProfile = context.currentEntity;
    // [3] - We need to create an object called settings, which we will add to the player's account //
    var apiResult = entity.SetObjects({
        Entity: entityProfile.Entity,
        Objects: [
            {
                ObjectName: "settings",
                DataObject: settings
            }
        ]
    });
    // [4] - We#ll return the results //
    return {
        response : apiResult.SetResults[0].SetResult
    };
}

Now, since this function needs entity context, we need to call it from the client in order to test it. So, we setup the client request next.

Sending Request Payloads

The client call for this request is similar to what we did before with our getPlayerDetails request. However, we need to use a slightly different API from the PlayFab SDK for the request to have the context of our player entity.

This is important, because we were doing this to begin with and our requests were getting error logs that the entity variable was missing from our scripts. So, in this request we use ExecuteEntityCloudScript and not ExecuteCloudScript. But otherwise it’s mostly the same.

We did also add a new field in the request which includes the parameter we want to send.

/// <summary>
/// Sets the player settings on the server
/// </summary>
/// <param name="onReqSuccess">
/// <param name="onRegFailed">
public void SetSettings(onEntityReqSuccess onReqSuccess, onReqFailed onRegFailed)
{
    Debug.Log("PFM| Settings Player Settings...");
    PlayFabCloudScriptAPI.ExecuteEntityCloudScript(new PlayFab.CloudScriptModels.ExecuteEntityCloudScriptRequest()
    {
        FunctionName = "setSettings",
        FunctionParameter = new
        {
            language = "English",
            volumeMusic = 100,
            volumeSFX = 100,
            notificationsPush = false,
            notificationInGame = true,
            autoCompleteWarning = true
        },
        GeneratePlayStreamEvent = true,
    }, (PlayFab.CloudScriptModels.ExecuteCloudScriptResult result) => {
        Debug.Log(result.ToJson());
        if (onReqSuccess != null)
        {
            onReqSuccess(result);
        }
    },
    (PlayFabError error) => {
        onRegFailed(error);
        ProcessErrors(error);
    });
}

Now, obviously this is just an example. For normal operation in our game we’d add the settings to the PlayerDetails object, pass them in to the function and separate the values out for this FunctionParameter field, but you get the idea.

Testing & Validation

By running this request on the client you should be able to see the results in the console. But you can also check what values you just set by selecting a player from the Players tab and selecting the Objects tab.

Objects tab
Objects tab
And that’s it, our player’s settings were ready and when we needed to get them back we could use the same process and return the settings using the GetObjects function.

GitHub Integration

Once we had created some functions, we started to think about maintaining our code and perhaps taking our development out of the PlayFab portals script editor and into our own IDE.

Both PlayFab and GameSparks have Github integrations and they are both easy to setup. 

We didn’t really have to look into tutorials for this integration. 

Looking through the Add-Ons section, we found GitHub there, and with a couple of clicks everything was setup to the migration repo.

PlayFab GitHub Add-on
PlayFab GitHub Add-on
One thing that was confusing about this integration was that PlayFab syncs changes automatically.

It will find a script in the repo you link and just use that script as a revision in the portal. 

So, the next time you go into the portal to deploy your code, it seems like nothing has changed, which confused us a bit. And it looks like there is nothing you can select or update or sync.

In fact, PlayFab has already synced your repo, and you can see it has stored your commits as difference revisions.

Revisions
Revisions

We can just select the latest revision and deploy the code.

Conclusion

And that’s it!

We’re done for this first part of our investigation. So far things have been straight-forward.

The main problems we had were with the CloudScript API. This we put down to getting used to the platform. JSON parsing client-side was a bit of a pain, and we will likely revisit this to clean it up and optimize in the future.

For the next step we are going to look at getting our loot-tables migrated to PlayFab. This is going to involve a bit of virtual goods, player inventory, and some requests and cloud code to deliver items and consume the virtual currency setup in this tutorial.