Tutorial: Level System

This guide will show you how to create a linear skill tree whereby a set of skills directly follow from one to the next in a set. To illustrate this we will create a simple leveling system with ten levels. The levels are defined as skill definitions and then a single archetype serves as a single classification for the entire level system.

Pre-requisites

This guide assumes you have read and understand the following documents:

Events

In order to make a proper leveling system we will need to track two types of telemetry events: GainXP and SkillUnlocked. The GainXP is a custom event type we will use to track the amount of experience a given persona has earned over time. The SkillUnlocked event type is used to chain a set of levels together so that level 10 follows 9 which follows level 8 and so on.

Whenever a persona has earned experience an event will be sent to the telemetry_services system with the type GainXP and the value property set to the amount of experience actually earned.

This can be implemented as a server side feature (recommended) or by the client directly.

Sending events from a service

const data: any = {
    type: "GainXP",
    userId: user.uid,
    personaUid: user.personas[0].uid,
    value: 100,
};
EventUtils.record(new Event(config, user.uid, data));

Sending events from the SDK

Event eventObj = new Event
{
    Type = "GainXP",
    UserId = ClientSDK.LoggedInUser.uid,
    PersonaUid = ClientSDK.LoggedInUser.personas[0].uid,
    Value = 100
};
EventService eventService = ServiceFactory.GetService<EventService>();
await eventService.Create(eventObj);
std::shared_ptr<models::Event> eventObj(new models::Event);
eventObj->SetType("GainXP");
eventObj->SetUserUid(ClientSDK.LoggedInUser.uid);
eventObj->SetPersonaUid(ClientSDK.LoggedInUser.personas[0].uid);
eventObj->Set("value", 100);
auto eventService = ServiceFactory::GetInstance()->GetService<services::EventService>();
eventService->Create(eventObj).Wait();

Defining Levels as Skills

Now that we have a mechanism to track experience we can define our levels. Each level has have an associated skill definition where the requirements include the amount of relative experience that must be reached (from the prior level) as well as the previous level that must be required.

The first level in our system is very simple as it has no requirements. All players must start at level 1. Thus the skill definition looks as follows.

{
    uid: "e744aba4-e07e-43aa-bfb2-5ffe8cf064eb",
    name: "level_1",
    title: "Level 1",
    description: "You are level 1.",
    icon: "level1.png",
    requirements: [],
}

In order to create this definition with the service we send a POST request to the /skills endpoint containing the above as the payload.

POST /skills HTTP/1.1
Authorization: jwt <admin_token>
Content-Type: application/json

{
    name: "level_1",
    title: "Level 1",
    description: "You are level 1.",
    icon: "level1.png",
    requirements: [],
}

For level two we will add some experience as the sole requirement. We will choose a value of 1000 which means that at ten of the aforementioned events would need to be created in order to unlock the level.

{
    uid: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
    name: "level_2",
    title: "Level 2",
    description: "You are level 2.",
    icon: "level2.png",
    requirements: [
        {
            type: "GainXP",
            title: "Earn experience",
            description: "Requires 1000 experience.",
            icon: "xp.png",
            value: 1000,
        },
    ],
}

Just like the level 1 we create this definition by POSTing to the /skills endpoint.

POST /skills HTTP/1.1
Authorization: jwt <admin_token>
Content-Type: application/json

{
    uid: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
    name: "level_2",
    title: "Level 2",
    description: "You are level 2.",
    icon: "level2.png",
    requirements: [
        {
            type: "GainXP",
            title: "Earn experience",
            description: "Requires 1000 experience.",
            icon: "xp.png",
            value: 1000,
        },
    ],
}

For level 3 we will set an experience requirement as well as a SkillUnlocked requirement chaining it to level 2. Note that the value of the requiremnt will be the uid of the level two skill definition which in the above example is 1ea968f3-ca97-4d8c-8c9d-63d183942be0. This level will require 5000 experience points to achieve.

{
    uid: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
    name: "level_3",
    title: "Level 3",
    description: "You are level 3.",
    icon: "level3.png",
    requirements: [
        {
            type: "GainXP",
            title: "Earn experience",
            description: "Requires 1000 experience.",
            icon: "xp.png",
            value: 5000,
        },
        {
            type: "SkillUnlocked",
            title: "Level 2",
            description: "Requires level 2.",
            icon: "level2.png",
            value: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
        },
    ],
}

We can now create the remaining levels the same way as level 3, where the SkillUnlocked requirement references the level before it. Our final level, level 10 will thus look like the following.

{
    uid: "d0e030c7-c6c1-489f-9096-2c17285b4961",
    name: "level_10",
    title: "Level 10",
    description: "You are level 10.",
    icon: "level10.png",
    requirements: [
        {
            type: "GainXP",
            title: "Earn experience",
            description: "Requires 1000 experience.",
            icon: "xp.png",
            value: 100000,
        },
        {
            type: "SkillUnlocked",
            title: "Level 9",
            description: "Requires level 9.",
            icon: "level9.png",
            value: "351b9c8d-1773-464e-9d46-e5eb777ed6ed",
        },
    ],
}

Creating the Archetype Definition

It is necessary to create an archetype for our set of levels. The archetype contains descriptive information about it as well as a list of the root skills in the tree. In this case, our root skills are level 1 and level 2. The system automatically traverses these root skills for children referenced as requirements to build the large tree(s).

{
    name: "levels",
    title: "Levels",
    description: "All levels that persona can achieve.",
    icon: "levels.png",
    skills: [
        "e744aba4-e07e-43aa-bfb2-5ffe8cf064eb",
        "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
    ],
}

Note that if level 2 is modified to incldue level 1 as a requirement then list of skills for the archetype can be reduced to only level 1.

The archetype is then created by sending a POST request to the /archetypes endpoint.

POST /archetypes HTTP/1.1
Authorization: jwt <admin_token>
Content-Type: application/json

{
    uid: "a3708071-cd11-498c-a886-29e089d859c0",
    name: "levels",
    title: "Levels",
    description: "All levels that persona can achieve.",
    icon: "levels.png",
    skills: [
        "e744aba4-e07e-43aa-bfb2-5ffe8cf064eb",
        "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
    ],
}

Enabling an archetype for a given persona

Now that our levels system has been created we can now enable it for personas so that they start tracking progress.

To enable an archetype for a given persona a PUT request is sent to the PUT /personas/{personaUid}/archetypes/{archetypeUid} endpoint. The request requires a payload containin the enabled state to set.

As an example imagine we have a persona with uid 4d1710e8-912e-4671-94d2-eaf51c301dcf. The request to enable the levels archetype would thus be.

POST /personas/4d1710e8-912e-4671-94d2-eaf51c301dcf/archetypes/a3708071-cd11-498c-a886-29e089d859c0 HTTP/1.1
Authorization: jwt <user_token>
Content-Type: application/json

{
    enabled: true
}

Retrieving Enabled Archetypes

Once an archetype has been enabled for a given persona it is possible to retrieve the complete definition of the archetype including the entire tree of skills associated with it by performing a GET request to the GET /personas/{personaUid}/archetypes/{archetypeUid} endpoint.

For our above example this request would look like.

GET /personas/4d1710e8-912e-4671-94d2-eaf51c301dcf/archetypes/a3708071-cd11-498c-a886-29e089d859c0 HTTP/1.1
Authorization: jwt <user_token>

The response of the above request will look like the following.

{
    uid: "a3708071-cd11-498c-a886-29e089d859c0",
    name: "levels",
    title: "Levels",
    description: "All levels that persona can achieve.",
    icon: "levels.png",
    skills: [
        {
            name: "level_1",
            title: "Level 1",
            description: "You are level 1.",
            icon: "level1.png",
            requirements: [],
        },
        {
            uid: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
            name: "level_2",
            title: "Level 2",
            description: "You are level 2.",
            icon: "level2.png",
            requirements: [
                {
                    type: "GainXP",
                    title: "Earn experience",
                    description: "Requires 1000 experience.",
                    icon: "xp.png",
                    value: 1000,
                },
            ],
        },
        {
            uid: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
            name: "level_3",
            title: "Level 3",
            description: "You are level 3.",
            icon: "level3.png",
            requirements: [
                {
                    type: "GainXP",
                    title: "Earn experience",
                    description: "Requires 1000 experience.",
                    icon: "xp.png",
                    value: 5000,
                },
                {
                    type: "SkillUnlocked",
                    title: "Level 2",
                    description: "Requires level 2.",
                    icon: "level2.png",
                    value: "1ea968f3-ca97-4d8c-8c9d-63d183942be0",
                },
            ],
        },
        ...
        {
            uid: "d0e030c7-c6c1-489f-9096-2c17285b4961",
            name: "level_10",
            title: "Level 10",
            description: "You are level 10.",
            icon: "level10.png",
            requirements: [
                {
                    type: "GainXP",
                    title: "Earn experience",
                    description: "Requires 1000 experience.",
                    icon: "xp.png",
                    value: 100000,
                },
                {
                    type: "SkillUnlocked",
                    title: "Level 9",
                    description: "Requires level 9.",
                    icon: "level9.png",
                    value: "351b9c8d-1773-464e-9d46-e5eb777ed6ed",
                },
            ],
        }
    ],
}

Retrieving Skill Progress

The current progress of a persona for a given archetype can be retrieved using the /personas/{personaUid}/archetypes/{archetypeUid}/skills endpoint.

GET /personas/4d1710e8-912e-4671-94d2-eaf51c301dcf/archetypes/a3708071-cd11-498c-a886-29e089d859c0/skills HTTP/1.1
Authorization: jwt <user_token>