Achievements
Overview
AccelByte Cloud's Achievement service is a tool developers can use to increase player engagement with their game. Recognizing players' progress in your game and rewarding them with items or new characters not only fosters deeper enjoyment of your game but brand loyalty as well. There are two main types of achievements: incremental and non-incremental. Both of these types are explained below.
Incremental Achievements
Incremental achievements work in conjunction with our Cloud Statistics service. When a player's stats are updated, the Achievement service checks if the conditions for any incremental achievements have been met. If the conditions for achievement have been met the achievement will be unlocked. Here are a couple of examples of incremental achievements:
- Collect 10,000 gold In order to unlock packs of bullets, a player must collect 10,000 gold.
- Collect 100 items To unlock the Collector trait, a player must collect 100 items.
Non-Incremental Achievements
Non-incremental achievements don't require a goal value to be hit, and as such do not need to be integrated with the Statistics service. Here are some examples of non-incremental achievements:
- Play your first game To unlock a bundle of weapons, a player must play the game.
- Kill 25 thieves in a single game To earn their first medal, players must kill 25 thieves in a single game.
Prerequisites
You will need to create a Statistics configuration as the statistic code will be used when you create an Incremental Achievement.
Permissions
Permissions are used to grant access to specific resources within our services. Make sure your account has the following permissions before you attempt to manage achievements in the Admin Portal. For a full list of permissions that impact achievements management, see the Achievements tab of the permissions reference.
Usage | Resource | Action |
---|---|---|
Create New Achievement | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Create |
Export Achievement Configuration | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Read |
Import Achievement Configuration | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Update |
Query All Achievements | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Read |
Get an Achievement | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Read |
Update an Achievement | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Update |
Delete an Achievement | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Update |
Update Achievements List Order | ADMIN:NAMESPACE:{namespace}:ACHIEVEMENT | Update |
Query User Achievements Include Achieved and In-progress Achievement | ADMIN:NAMESPACE:{namespace}:USER:{userId}:ACHIEVEMENT | Read |
Unlock an Achievement | NAMESPACE:{namespace}:USER:{userId}:ACHIEVEMENT | Update |
Permissions work slightly differently depending on whether they are assigned to IAM Clients or Roles assigned to users. For more information, read the Authentication and Authorization documentation.
Manage Achievements in the Admin Portal
Create a New Achievement Configuration
On the Achievements page of the Admin Portal, click the Add Achievements button.
The Add New Achievements form will appear. Fill in the required fields.
Input the Code of the achievement with an appropriate format, e.g., kill-enemies-achievement.
Input the Name of the achievement with a readable string. This will be a public-facing name.
Input the Description of the achievement. This description is also public-facing.
Choose if you want the achievement to be Hidden. Hidden achievements are not shown when they are still locked, but will appear once unlocked.
Select Incremental for an incremental achievement, or leave the checkbox unselected for a non-incremental achievement. In this case, we're creating an incremental achievement so, we need to input the Goal Value and a StatCode of a statistics configuration associated with this achievement.
NOTE
The Goal Value should not exceed the Max. Value defined in the Statistic Configuration.
Input the Tag field with contextual information related to the achievement. You can input up to five tags. This field is optional.
Select an image for the Locked Icon. This image will be displayed for players who do not have this achievement yet.
Select an image for the Unlocked Icon. This image will display when the achievement is unlocked.
Once completed, click Add. Your new configuration will be added to the list.
Export Achievement Configurations
You can export your achievement configurations in JSON format by following the steps below.
In the Achievements page, open the dropdown menu next to the Add Achievements button and choose Export Configuration.
The download will start. Once it's finished, open the JSON file to see your achievement configs.
[
{
"Hidden": false,
"Incremental": false,
"ID": "5ec4b6ee296bxxde03cdeee1",
"ListOrder": 1,
"GoalValue": 0,
"UnlockedIcons": [
{
"url": "https://cdn.demo.accelbyte.io/files/accelbyte/achievements/54a4c4485ac34a63a0ece0e849b488e0.png",
"slug": "rectangle-1png"
}
],
"LockedIcons": [
{
"url": "https://cdn.demo.accelbyte.io/files/accelbyte/achievements/53351a0b28134d008600bb5fb6cf23c3.png",
"slug": "rectanglepng"
}
],
"CreatedAt": "2020-05-20T04:49:50.825Z",
"UpdatedAt": "2020-05-20T04:49:50.825Z",
"Namespace": "accelbyte",
"AchievementCode": "penta-kill",
"StatCode": "",
"DefaultLanguage": "en",
"Tags": [
"kills"
],
"Name": {
"en": "Penta Kill"
},
"Description": {
"en": "Penta Kill description"
}
}
]
Import an Achievement Configuration
In the Achievements page, open the dropdown menu next to the Add Achievement button and choose Import Configuration.
The Import Configuration form will appear.
- Choose a File to Import. The file should be in JSON format.
- Select the Import Method.
- Choose Replace if you want to replace an old config with a new one. The new config must have the same key as the config you want to replace. If you have multiple configs in your file, any configs with unique keys will also be imported.
- Choose Leave Out if you want to add a new config without replacing any old configs. Using this method, any configs in your JSON file whose keys match existing configs will not be imported. Only configs with unique keys will be imported.
Click Import.
Confirm the import configuration by typing IMPORT in the pop-up form below.
Implement Achievements with the Client SDKs
Unlock an Achievement
There are two ways to unlock a player's achievement: either from Game Client or from the Game Dedicated Server.
Unlock an Achievement from the Game Client
NOTE
This function can only be used for non-incremental achievements that do not affect gameplay, such as the player's first time entering the lobby, their first time inviting a friend, etc.
- Unreal Engine
- Unity
FString AchievementCode = FString("MyAchievementCode");
FRegistry::Achievement.UnlockAchievement(AchievementCode, FVoidHandler::CreateLambda([]()
{
// Do something if UnlocKAchievement has been successful
}), FErrorHandler:: CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UnlockAchievement has an error
UE_LOG(LogTemp, Log, TEXT("Error UnlockAchievement, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
string achievementCode = "MyAchievementCode";
AccelBytePlugin.GetAchievement().UnlockAchievement(achievementCode, result =>
{
if (result.IsError)
{
// Do something if UnlockAchievement has an error
Debug.Log($"Error UnlockAchievement, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
}
else
{
// Do something if UnlockAchievement has been successful
}
});
Unlock an Achievement from the Dedicated Server
Unlocking an achievement from the server is usually done after a match is completed.
- Unreal Engine
- Unity
FString AchievementCode = FString("MyAchievementCode");
FString UserId = FString("SomeUserId");
FRegistry::ServerAchievement.UnlockAchievement(UserId, AchievementCode, FVoidHandler::CreateLambda([]()
{
// Do something if UnlockAchievement has been successful
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UnlockAchievement has an error
UE_LOG(LogTemp, Log, TEXT("Error UnlockAchievement, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
string achievementCode = "MyAchievementCode";
string userId = "SomeUserId";
AccelByteServerPlugin.GetAchievement().UnlockAchievement(userId, achievementCode, result =>
{
if (result.IsError)
{
// Do something if UnlockAchievement has an error
Debug.Log($"Error UnlockAchievement, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
}
else
{
// Do something if UnlockAchievement has been successful
}
});
Achievements Query
Get a Single Achievement
You can use this function to retrieve achievement info, such as the achievement name, description, goalValue, etc.
- Unreal Engine
- Unity
FString AchievementCode = FString("MyAchievementCode");
FRegistry::Achievement.GetAchievement(AchievementCode, THandler<FAccelByteModelsMultiLanguageAchievement>::CreateLambda([](const FAccelByteModelsMultiLanguageAchievement& Result)
{
// Do something if GetAchievement has been successful
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if GetAchievement has an error
UE_LOG(LogTemp, Log, TEXT("Error GetAchievement, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}));
string achievementCode = "MyAchievementCode";
AccelBytePlugin.GetAchievement().GetAchievement(achievementCode, result =>
{
if (result.IsError)
{
// Do something if GetAchievement has an error
Debug.Log($"Error GetAchievement, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
}
else
{
// Do something if GetAchievement has been successful
}
});
Query All Achievements
You can use this function to retrieve a list of all achievements in the related namespace.
- Unreal Engine
- Unity
FString Language = FString("en");
EAccelByteAchievementListSortBy SortBy = EAccelByteAchievementListSortBy::LISTORDER;
int32 Offset = 0;
int32 Limit = 50;
FRegistry::Achievement.QueryAchievements(Language, SortBy, THandler<FAccelByteModelsPaginatedPublicAchievement>::CreateLambda([](const FAccelByteModelsPaginatedPublicAchievement& Result)
{
// Do something if QueryAchievements has been successful
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if QueryAchievements has an error
UE_LOG(LogTemp, Log, TEXT("Error QueryAchievements, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}), Offset, Limit);
string language = "en";
AchievementSortBy sortBy = AchievementSortBy.LISTORDER;
int offset = 0;
int limit = 50;
AccelBytePlugin.GetAchievement().QueryAchievements(language, sortBy, result =>
{
if (result.IsError)
{
// Do something if QueryAchievements has an error
Debug.Log($"Error QueryAchievements, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
}
else
{
// Do something if QueryAchievements has been successful
}
}, offset, limit);
Query a Player's Achievement
Use this function to query a player's unlocked and in-progress achievements. This function is called from a specific player who is already logged in to justice iam or currently a player that has been logged into the game.
- Unreal Engine
- Unity
EAccelByteAchievementListSortBy SortBy = EAccelByteAchievementListSortBy::LISTORDER;
int32 Offset = 0;
int32 Limit = 50;
FRegistry::Achievement.QueryUserAchievements(SortBy, THandler<FAccelByteModelsPaginatedUserAchievement>::CreateLambda([](const FAccelByteModelsPaginatedUserAchievement& Result)
{
// Do something if QueryUserAchievements has been successful
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if QueryUserAchievements has an error
UE_LOG(LogTemp, Log, TEXT("Error QueryUserAchievements, Error Code: %d Error Message: %s"), ErrorCode, *ErrorMessage);
}), Offset, Limit);
AchievementSortBy sortBy = AchievementSortBy.LISTORDER;
int offset = 0;
int limit = 50;
AccelBytePlugin.GetAchievement().QueryUserAchievements(sortBy, result =>
{
if (result.IsError)
{
// Do something if QueryUserAchievements has an error
Debug.Log($"Error QueryUserAchievements, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
}
else
{
// Do something if QueryUserAchievements has been successful
}
}, offset, limit);
Connect Custom Services to Achievements using the Server SDKs
SDK Initialization
Before using the Achievement service from the SDK, you will need to initialize your server-side SDK to make you authorized and able to perform create, read, update, and delete actions.
Golang SDK Initialization
Before using the Achievement service from the Golang SDK, you will need to initialize the SDK by following the steps below:
- Create your OAuth Client and assign the necessary permissions to access the IAM service.
- Log in as a Client using the SDK.
- Initialize the OAuth 2.0 service using the following function:
- Golang
achievementsService := &achievement.AchievementsService{
Client: factory.NewAchievementClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
Once completed, you can use the Golang SDK to create, read, update, or delete the Achievement service from your serverless app.
Python SDK Initialization
Before using the Achievement service from the Python SDK, you will need to initialize the SDK by following the steps below:
- Create your OAuth Client and assign the necessary permissions to access the Matchmaking service.
- Log in as a Client using the SDK.
Once completed, you can use the Python SDK to create, read, update, or delete the Achievement service from your serverless app.
.NET (C#) SDK Initialization
Before using the Achievement service, you will need to set some permissions. Use the following .NET namespaces:
using AccelByte.Sdk.Api.Achievement.Model;
using AccelByte.Sdk.Api.Achievement.Operation;
using AccelByte.Sdk.Api.Achievement.Wrapper;
Java SDK Initialization
Before using the Achievement service, you will need to set some permissions. Initialize the Achievements wrapper from Achievement service using the following code:
Achievements wAchievements = new Achievements(sdk);
Once completed, you can use the SDK to create, read, update, or delete achievements.
Create an Achievement
Use the following function to create an achievement:
- Golang
- Python
- C#
- Java
ok, err := achievementsService.AdminCreateNewAchievement(input)
if err != nil {
logrus.Error(err)
return err
}
return nil
from accelbyte_py_sdk.api.achievement import admin_create_new_achievement
from accelbyte_py_sdk.api.achievement.models import ModelsAchievementRequest
from accelbyte_py_sdk.api.achievement.models import ModelsIcon
result, error = admin_create_new_achievement(
body=ModelsAchievementRequest.create(
achievement_code="<your-achievement-code>",
default_language="<your-default-language>",
description={"<your-description-key>": "<your-description-value>"},
goal_value=420,
hidden=False,
incremental=True,
locked_icons=[ModelsIcon.create(
slug="<your-icon-slug>",
url="<your-icon-url>"
)],
name={"<your-name-key>": "<your-name-value>"},
stat_code="<your-stat-code>",
tags=["<your-tag>"],
unlocked_icons=[ModelsIcon.create(
slug="<your-icon-slug>",
url="<your-icon-url>"
)]
)
)
if error:
print(error)
Achievements wAchievements = new Achievements(sdk);
ModelsAchievementRequest newAchievement = new ModelsAchievementRequest()
{
AchievementCode = "achievement-code",
DefaultLanguage = "en",
Name = new Dictionary<string, string>()
{
{"en", "Achievement Name" }
},
Description = new Dictionary<string, string>
{
{"en", "Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..." }
},
GoalValue = 1000.0,
StatCode = "stat-code",
Hidden = true,
Incremental = false,
LockedIcons = new List<ModelsIcon>()
{
new ModelsIcon()
{
Slug = "shield-locked",
Url = "http://your-image-url"
}
},
UnlockedIcons = new List<ModelsIcon>()
{
new ModelsIcon()
{
Slug = "shield-unlocked",
Url = "http://your-image-url"
}
},
Tags = new List<string>()
};
ModelsAchievementResponse? cResp = wAchievements.AdminCreateNewAchievement(AdminCreateNewAchievement.Builder
.Build(newAchievement, sdk.Namespace));
ModelsAchievementRequest newAchievement = ModelsAchievementRequest.builder()
.achievementCode(achievementCode)
.defaultLanguage("en")
.name(Collections.singletonMap("en", achievementName))
.description(Collections.singletonMap("en", achievementDesc))
.goalValue(1000f)
.statCode(achievementCode)
.hidden(true)
.incremental(false)
.lockedIcons(Arrays.asList(new ModelsIcon[] { ModelsIcon.builder()
.slug("shield-locked")
.url("https://cdn.demo.accelbyte.io/files/accelbyte/achievements/50000f325ef841a6972a005779e20991.png")
.build() }))
.unlockedIcons(Arrays.asList(new ModelsIcon[] { ModelsIcon.builder()
.slug("shield-unlocked")
.url("https://cdn.demo.accelbyte.io/files/accelbyte/achievements/fe89fd07102f4057be202fbd3fdd9a21.png")
.build() }))
.tags(Arrays.asList(new String[] { "sdk", "test", "java" }))
.build();
ModelsAchievementResponse cResp = wAchievements.adminCreateNewAchievement(
AdminCreateNewAchievement.builder()
.namespace(namespace)
.body(newAchievement)
.build());
Delete an Achievement
Use the following function to delete an achievement:
- Golang
- Python
- C#
- Java
err := achievementsService.AdminDeleteAchievement(input)
if err != nil {
logrus.Error(err)
return err
}
return nil
from accelbyte_py_sdk.api.achievement import admin_delete_achievement
result, error = admin_delete_achievement(
achievement_code="<your-achievement-code>"
)
if error:
print(error)
```</TabItem>
<TabItem label="C#" value="C#">
```csharp
Achievements wAchievements = new Achievements(sdk);
ModelsAchievementResponse? achievement = wAchievements.AdminGetAchievement(AdminGetAchievement.Builder
.Build("<achievement_code>", sdk.Namespace));
Achievements wAchievements = new Achievements(sdk);
wAchievements.AdminDeleteAchievement(AdminDeleteAchievement.Builder
.Build("<achievement_code>", sdk.Namespace));
wAchievements.adminDeleteAchievement(AdminDeleteAchievement.builder()
.namespace(namespace)
.achievementCode(achievementCode)
.build());
Retrieve All Achievements
Use the following function to retrieve all achievements:
- Golang
- Python
- C#
- Java
ok, err := achievementsService.AdminListAchievements(input)
if err != nil {
logrus.Error(err)
return err
}
return nil
from accelbyte_py_sdk.api.achievement import admin_list_achievements
result, error = admin_list_achievements(
limit=20,
offset=0
)
if error:
print(error)
Achievements wAchievements = new Achievements(sdk);
ModelsPaginatedAchievementResponse? achievementList = wAchievements.AdminListAchievements(AdminListAchievements.Builder
.SetLimit(100)
.SetOffset(0)
.Build(sdk.Namespace));
ModelsPaginatedAchievementResponse gaResp = wAchievements
.adminListAchievements(AdminListAchievements.builder()
.namespace(namespace)
.limit(100)
.offset(0)
.build());
Retrieve an Achievement by Its Code
Use the following function to retrieve an achievement by code:
- Golang
- Python
- Java
ok, err := achievementsService.AdminGetAchievement(input)
if err != nil {
logrus.Error(err)
return err
}
from accelbyte_py_sdk.api.achievement import admin_get_achievement
result, error = admin_get_achievement(
achievement_code="<your-achievement-code>"
)
if error:
print(error)
ModelsAchievementResponse rResp = wAchievements.adminGetAchievement(AdminGetAchievement.builder()
.namespace(namespace)
.achievementCode(achievementCode)
.build());
Assertions.assertNotNull(rResp);
Assertions.assertEquals(rResp.getGoalValue(), 2000f);
Assertions.assertEquals(rResp.getName().get("en"), achievementName);
Update an Achievement
Use the following function to update an achievement:
- Golang
- Python
- C#
- Java
ok, err := achievementsService.AdminListAchievements(input)
if err != nil {
logrus.Error(err)
return err
}
return nil
from accelbyte_py_sdk.api.achievement import admin_update_achievement
from accelbyte_py_sdk.api.achievement.models import ModelsAchievementUpdateRequest
from accelbyte_py_sdk.api.achievement.models import ModelsIcon
result, error = admin_update_achievement(
achievement_code="<your-achievement-code>",
body=ModelsAchievementUpdateRequest.create(
default_language="<your-default-language>",
description={"<your-description-key>": "<your-description-value>"},
goal_value=420,
hidden=False,
incremental=True,
locked_icons=[ModelsIcon.create(
slug="<your-icon-slug>",
url="<your-icon-url>"
)],
name={"<your-name-key>": "<your-name-value>"},
stat_code="<your-stat-code>",
tags=["<your-tag>"],
unlocked_icons=[ModelsIcon.create(
slug="<your-icon-slug>",
url="<your-icon-url>"
)]
)
)
if error:
print(error)
Achievements wAchievements = new Achievements(sdk);
ModelsAchievementUpdateRequest updateAchievement = new ModelsAchievementUpdateRequest()
{
GoalValue = 2000.0
};
ModelsAchievementResponse? uResp = wAchievements.AdminUpdateAchievement(AdminUpdateAchievement.Builder
.Build(updateAchievement, "<achievement_code>", sdk.Namespace));
ModelsAchievementUpdateRequest updateAchievement = ModelsAchievementUpdateRequest.builder()
.goalValue(2000f)
.build();
ModelsAchievementResponse uResp = wAchievements.adminUpdateAchievement(
AdminUpdateAchievement.builder()
.namespace(namespace)
.achievementCode(achievementCode)
.body(updateAchievement)
.build());
Related Concepts
- To learn more about achievements, see our Cloud API Reference documentation.
- Once you have set up achievements, you can create Rewards and Leaderboards.
- Golang test case files
- Python test case files
- .NET (C#) test case files
- Java test case files