Connecting to the Living Assets API from Unity

Learn how to query user assets, and all assets for sale, from within Unity

Introduction

If your game is server authorative, it is likely that that vast majority of the interaction with the Living Assets API will be made from the server. However, in certain situations you may wish the game to connect directly to the Living Assets API. In this tutorial we will do exactly that.

Requirements

  • Basic familiarity with Unity and GraphQL.

  • Having followed the first tutorial on creating web3 wallets in Unity. Make sure you have the Newtonsoft JSON package installed, along with the Nethereum plugin, the AESEncryption script, and the KeyStore GameObject and script implemented, as described in the tutorial.

  • A sandbox universe, its ID, API endpoint, and dashboard access.

Creating a new asset and gifting it to a user

Fire up the Unity project from the the web3 wallets tutorial in Unity, run the project, and make a note of the address of the user:

Now let's create a new asset and assign it to the user:

  • Login to the Freeverse dashboard using the credentials provided by Freeverse

  • Click on the green '+' icon in the lower left corner and choose Create Asset

  • Upload an image, and set a name and description for the asset (all three fields are required). Please consider typical formats like the mentioned ones here

  • Click on the Assign to Web3 Address checkbox on the right of the screen, and paste the user address (3rd line of the output from Unity).

  • Click the Create Assets(s) button to create the asset and assign it immediately to the user.

You may do this multiple times to assign more than one asset to the user, if you wish.

Alternatively, you could modify the code from previous tutorials to have the Unity application send an action code along with the user address to your game server, and have the server create the asset, without you having to use the dashboard.

Setting up Unity to make GraphQL requests

A GraphQL request is nothing more than a specially formed request over HTTP. To make the request and receive the response in the correct format, we must create some special classes in Unity.

We are going to create a very simple helper class that takes a GraphQL query, and converts them into a UnityWebRequest object which we can launch at a later date. Create a new script called GraphQLClient, delete the boilerplate code, and type the following:

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;

namespace GraphQL {
  public class GraphQLClient {
    private string url;

    public GraphQLClient(string url) {
      this.url = url;
    }

    [System.Serializable]
    private class GraphQLQuery {
      public string query;
    }

    public UnityWebRequest Query(string query, string variables, string operationName) {
        var fullQuery = new GraphQLQuery () {
            query = query
        };
        string json = JsonUtility.ToJson (fullQuery);
        byte[] payload = Encoding.UTF8.GetBytes (json);
        UploadHandler data = new UploadHandlerRaw (payload);

        UnityWebRequest request = UnityWebRequest.PostWwwForm(url, UnityWebRequest.kHttpVerbPOST);
        request.uploadHandler = data;
        request.SetRequestHeader ("Content-Type", "application/json");
        return request;
    }
  }
}

This is pretty much the simplest possible way that we can format a GraphQL query in Unity, using a serializable nested class to store the query (though notably, without any variables.

This tutorial uses a very simple GraphQL parser, for clarity. In a production environment, you might choose to use a more robust solution, of which there are several, for example:

https://assetstore.unity.com/packages/tools/network/graphql-for-unity-199114

https://github.com/gazuntype/graphQL-client-unity

Query all the user's assets

We know that this user has at least one asset that belongs to them, so let's query the API to find out information about that asset. We are going to have to follow several steps to do this:

  1. Create a new script to launch queries and receive the responses

  2. Create a series of small C# classes to receive the JSON and deserialize it

  3. Launch the query and parse the response into the classes.

Create a new script and set up the query

In Unity, create a new script called Queries.cs and associate with the same GameObject in the scene as the KeyStore script. Remove the Update() function, and type the following, making sure to include the dependencies on UnityEngine.Networking and Newtonsoft.Json.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Newtonsoft.Json;

public class Queries : MonoBehaviour
{
    // change these variables
    private static string UNI_ID = "<paste_universe_ID_here>";
    private static string URL = "<paste_freeverse_endpoint_here>";

    public void LaunchQuery()
    {
        StartCoroutine (GetUserAssetsQuery( (bool success, string result) => {
            Debug.Log(result);
        }));
    }

    // Function to get all assets of user, accepts a callback function
    public IEnumerator GetUserAssetsQuery(System.Action<bool, string> callback) 
    {        
        // grab the user address from the Keystore
        KeyStore keyStore = GetComponent<KeyStore>();
        string USER_ADDRESS = keyStore.Address;

        // the query we will use to get the assets
        // see https://dev.livingassets.io/living-assets-api/information-queries
        string query = "query {getUserAssets(web3Address:\"" 
                        +USER_ADDRESS+"\", universe:"
                        +UNI_ID+") { totalCount nodes {assetid}}}";

        // create our GraphQL client instance and create and send the UnityWebRequest
        GraphQLClient client = new GraphQLClient (URL);
        using( UnityWebRequest www = client.Query(query, "{}", "")) 
        {
            yield return www.SendWebRequest();
            if (www.result == UnityWebRequest.Result.ConnectionError) 
                callback (false, www.error);
            else 
                callback (true, www.downloadHandler.text);
        }
    }
}

The main interest in this code is the GetUserAssets() function, which constructs a simple GraphQL query to obtain all the assets belonging to this user. For future flexibility, we are passing a callback function to GetUserAssets(), which receives either the response from the server, or prints any error.

Note how the query is launched by calling the LaunchQuery() function. This function can be called in any way you like. For testing purposes, it is convenient to add a simple UI button to the scene and link the button's OnClick event listener to the LaunchQuery function:

Upon running the application now, firing the LaunchQuery function will print the response from the server to the console:

Parsing the response from the server

The server response is in the format of a string, which we need to parse into C# variables. While we could do this ourselves, a more convenient way is to deserialize the data into a series of dedicated classes.

To save time writing these classes by hand, we can use the excellent https://json2csharp.com/ application, which takes any given JSON and automatically creates the required classes for deserialization with Newtonsoft's JSON package.

Paste these classes into Queries.cs, just below the dependencies.

Finally we can modify the LaunchQuery function to convert the result to JSON, deserialize it, and then, for informative purposes, print it to console.

    public void LaunchQuery()
    {
        StartCoroutine (GetUserAssetsQuery( (bool success, string result) => {
            
            // Deserialize the response
            Root deserializedResult = JsonConvert.DeserializeObject<Root>(result);
            
            // Print a summary of the results to the console
            print ("Number of assets owned by user:" + deserializedResult.data.getUserAssets.totalCount);
            foreach (Node node in deserializedResult.data.getUserAssets.nodes)
            {
                print("Asset ID: " + node.assetid);
            }
            
        }));
    }

Extending the tutorial to a real-world example

In a real-world example, the data from this query could be used to, for example, show the user which assets they own, along with the properties of those assets.

A simple way to obtain the properties of the assets returned by the first query made in the tutorial would be to launch a subsequent query targeting allAssets along with filters

string query = "query{allAssets(filter: {universeId: {equalTo: "
                +UNI_ID+"}, id: {in: [";
        
foreach(string aID in assetIDs) {
    query += "\""+aID+"\",";
}

query += "]}}){nodes{id ownerId props}}}";

The props of each node will give us the name, description, image URL, and properties of each asset. With this, you can display the assets within the game as you wish.

Last updated

freeverse.io