Social Infrastructure At Scale

How to create an in-game currency

Matthew

Matthew Revell

18 Jun 2019

In game currency

A key mechanism in modern gameplay is the engagement loop: a habitual series of activities that give the player a sense of reward. While some of the simplest games can be the most compelling, your players are unlikely to stick around unless that sense of reward has some greater sense of meaning.

That’s where your in-game economy plays its part. Not only does it create a more sophisticated reward mechanism but, of course, it provides a means to monetise your game. In this recipe, we’re going to look at how to use Nakama to develop the fundamental building block of your in-game economy: a virtual currency.

What we’ll cover

Over the course of this recipe, we’re going to:

  1. Create a player account
  2. Initialise that account with a currency balance
  3. View and add currency to the player’s wallet

To follow the recipe, you’ll need a Nakama instance and a basic knowledge of Lua. If you’re completely new to Nakama, take a look at our getting started guide.

Creating the player account

Player account identity in Nakama is super flexible. You can choose between several options, including identifying accounts by email address, social account, or other third-party identity service.

For this recipe, we’ll use the simplest method which is to create a semi-anonymous player account using a device identifier. To do so, we need:

You’ll also need the defaultkey for the Nakama instance.

Assuming Nakama is running locally, we can create our new user with the following lines of JavaScript:

1
2
const session = await client.authenticateDevice({ id: deviceId, create: true, username: "mycustomusername" });
console.info("Successfully authenticated:", session);

For a fuller example, and examples in languages other than JavaScript, take a look at our guide to authentication with Nakama.

Typically, we’d want to give new players an initial balance of our virtual currency. To do so, we’ll create some server-side code that runs automatically whenever Nakama creates a new player account.

Giving new players an initial balance

To give new players an initial balance of our virtual currency, we need to write a Lua script that has two distinct parts:

  1. First, it adds the initial balance.
  2. Then it tells Nakama when to run the script.

Let’s start by creating a Lua table that contains the state with which we want to initialise our new player’s wallet. We’ll give them 100 coins and 100 food.

1
2
3
4
5
6
local nk = require("nakama")
local function initialize_user(context, _payload)
local value = {
  coins = 100,
  food = 100
}

Next, we’ll create another table that forms the metadata we’ll store in Nakama’s wallet.

1
2
3
4
5
local user_id = context.user_id
local metadata = {
  reason = "wallet init"
}
pcall(nk.wallet_update, user_id, value, metadata, true)

When Nakama first loads, it evaluates each of the scripts available to it. The final line in our script tells Nakama to run the script after it receives a message indicating that a new player has been registered using the device ID authentication.

1
nk.register_req_after(initialize_user, “authenticaterequest_device”)

The fact that you can distinguish between different types of authentication opens up interesting possibilities. Say, for example, that want to encourage players to provide you with their email address. You could write another script that triggers when a new user created their account using email authentication and in that script give the new player 200 coins, instead of 100.

Now that our player has some coins, let’s check the balance.

Fetching the wallet balance

To fetch the wallet, we’ll need to fetch the full player profile. In JavaScript, that looks like this:

1
2
const account = await client.getAccount(session);
const wallet = JSON.parse(account.wallet);

Remember the Lua table we worked with earlier to set the content of the wallet? We can now access that data in our client-side language of choice. Here in JavaScript, we’d access it with:

1
const contents = wallet.contents;

You’ll need to fetch the wallet contents periodically from within your client-side code, either as part of your standard game loop or at times when you can reasonably expect that the wallet contents has changed (such as when the player makes a purchase).

Updating the player’s wallet

During normal gameplay, you’ll need to update player wallets when things happen such as:

Most wallet changes take place through code running on the Nakama server. Even if a change is initiated from within the player’s client, such as the player purchasing an item, you might prefer to action the change on the server-side. That enables you to verify changes before committing them.

Let’s say that we want to add 50 coins to the player’s wallet. First we need to fetch the wallet contents. That’ll give us a Lua table including the coins total. We’ll then add the number of coins that we passed in as an argument and save the newly updated table back into the wallet.

1
2
3
4
5
6
7
8
9
local nk = require("nakama")
local user_id = "95f05d94-cc66–445a-b4d1–9e262662cf79"-replace with the correct user id
local account = nk.account_get_id("user_id")
local wallet = account.wallet
wallet.coins = wallet.coins + 50
local status, err = pcall(nk.wallet_update, user_id, wallet)
if (not status) then
  nk.logger_info(("User wallet update error: %q"):format(err))
end

You can call read more about calling server side Lua scripts, such as this one, from within your game clients in our guide to working with RPC calls.

Taking your economy to the next level

In this recipe, we’ve looked at the fundamentals of working with an in-game currency. Look out for our post on taking your currency to the next level, by enabling players to use real currency to buy in-game currency.