Adding achievements to your game

Rajen Kishna, Technical Account Manager, Epic Games |
January 25, 2022
Now that we’ve covered Stats and Leaderboards in the previous two blog posts, let’s take a look at adding achievements to your game using the Achievements Interface. Achievements can be configured to unlock automatically based on stat progress or manually using the API. In this article, we’ll go over:
 

Epic Online Services achievements and Epic achievements

Before we dive into the implementation of Epic Online Services achievements, I want to take a moment to explain the relationship and differences between Epic Online Services (EOS) achievements and Epic achievements (in Early Access at the time of writing), which were announced in October of 2021.
Epic Online Services (EOS) achievements
  • Epic Online Services (EOS) achievements are—like many Epic Online Services features—platform-agnostic achievements that you can implement in your game. 
  • You can use EOS achievements to track progress and unlock achievements using your own in-game UI. 
  • While EOS achievements will be rendered by the Overlay for convenience, they are not necessarily linked to an Epic Games Store game, and thus will not be shown in the Epic Game Store player profile or game pages.
  • EOS achievements have no XP attached to them. Due to their platform-agnostic nature, you are free to implement any scoring mechanism for your game.
Epic achievements
  • Epic achievements are a configuration-only (no code required) feature to extend EOS achievements for the Epic ecosystem, including the Epic Games Store. 
  • Any unlocked (or previously unlocked) EOS achievements will result in the corresponding Epic achievements also being unlocked for that user. 
  • Epic achievements add an XP value to each achievement. XP values can range from 5 XP to 200 XP. The game (as of this posting) must have a total of 1,000 XP across all achievements.
  • Epic achievements are classified into three tiers, based on the XP value assigned: Bronze = 5-45 XP, Silver = 50-95 XP, and Gold = 100-200 XP
    • Note that an additional Platinum achievement (250 XP) is automatically awarded by completing all other achievements, for a total of 1,250 XP that can be earned for each game
  • Epic achievements progress will automatically be displayed in the player’s Epic Games Store library, player profile, and on the Epic Games Store game page (on the web and in the Epic Games Launcher).
  • Games that have configured Epic achievements will have their Epic achievements displayed in the Overlay (including XP), instead of the EOS achievements that were previously displayed.
  • Lastly, as teased in the announcement blog, Epic achievements will be expanded to include other social features, like avatars, in the future.

Because Epic achievements are currently in Early Access and games must be set up to publish in the Epic Games Store, we’ll only focus on Epic Online Services achievements in this blog post.

Changing our Client Policy

To use Achievements, we must first add actions to our Client Policy:
 
  1. Log in to the Developer Portal at https://dev.epicgames.com/portal/.
  2. Navigate to your product > Product Settings in the left menu and click on the Clients tab in the product settings screen.
  3. Click on the three dots next to the client policy you’re using and click on Update policy
  4. Scroll down to Features and click on the toggle button next to Achievements.
  5. Tick the boxes next to the following actions: 
    • findAchievementDefinitions: used to query achievement definitions
    • findAchievementsForLocalUser: used to query player achievement progress
    • unlockAchievementForLocalUser: used to unlock achievements for the logged in user
      • Note that this should be used with caution in production environments, as it could be reverse engineered and achievements could be unlocked by malicious users to unlock achievements without them being earned. A more robust approach is to unlock achievements via stats or unlock achievements via your own back-end server.
  6. Click Save & Exit to confirm.
Developer Portal Client Policy Achievements
Achievements Client Policy allowed features and actions

Creating achievements in the Dev Portal

Achievements are created in the Developer Portal and can be set up to unlock based on a stat or manually. Additionally, achievements can be set up as visible or hidden, depending on whether or not you want players to know what the achievement is before unlocking. Let’s set up a few achievements in the portal.
 
  1. Navigate to your product > Game Services > Achievements in the left menu.
  2. Here we can see the achievements for each deployment in our product (which will likely just be “Release in Live Sandbox” for now).
    • Note that there’s also a “Bulk Import / Export” button on the top right, which will let you streamline the back-up and creation process of achievements. We won’t go through this process in this post, however.
  3. Click on “Create New” on the top right to add a new achievement.
  4. In the flyout, you’ll see step one of two, which lets you define a stat to automatically unlock the achievement with. Select the SumStat stat in the drop-down. We also need to provide a threshold value in the box to the right of the stat. We’ll enter 50 here.
  5. We can define up to three stats here to base our achievement unlocks on, but for now we’ll stick with just this one. Click on “Next” to move to step two of two.
  6. Here we define the bulk of our achievement settings. Enter “50_TOTAL_CLICKS” as the Achievement ID.
  7. Keep or select the locale you’ll be testing in.
  8. We’ll keep this achievement as “Shown” under the “Visibility” setting.
  9. Upload the unlocked and locked icons for your achievement. This can be any 1024x1024 px or smaller image (JPG, PNG, BMP, or non-animated GIF) of 1.02 MB or less.
    • Note that the filename of the icon has to be unique across all your achievements, or a new upload with the same filename will overwrite the old file.
  10. Enter the locked and unlocked name and description:
    • Locked Display Name: Click, click, click…
    • Locked Description: How many clicks will it take?
    • Unlocked Display Name: Click champion
    • Unlocked Description: Clicked 50 times total.
    • Note that you can also enter an option Flavor Text, which is an arbitrary localized string that you may use in your game. We’ll skip this for now.
  11. Now we can click “Create” to finalize creating this achievement. After the flyout closes, you should see the achievement appear in the list.
 
Developer Portal Achievements Click Champion
“Click champion” achievement created

Let’s also create a second, hidden achievement that we can manually unlock:
 
  1. Click on “Create New” to start adding a new achievement.
  2. Click “Next” in the flyout without specifying a stat in step one of two.
  3. Specify the details for this achievement:
    • Achievement ID: TOP_SECRET
    • Visibility: Hidden
    • Unlocked Display Name: You found it
    • Unlocked Description: Unlocked the hidden achievement.
    • Note that hidden visibility achievements do not have a locked display name or description.

Querying achievement definitions

Now let’s start implementing the code to query our achievement definitions:
 
  1. Create a new User Control in the Views folder called AchievementView:
  • We’ll have two separate ListViews in our UI for Achievements, one to display all the definitions, and one to display the player progress. For now, we’ll start with the ListView for all definitions, which will only occupy part of the UI.
 
  1. Open AchievementsView.xaml.cs to attach the ViewModel and hold the placeholder selection changed event handler:
  1. Add an AchievementsViewModel.cs class to the ViewModels folder:
  1. Add a reference to AchievementsViewModel in ViewModelLocator.cs:
  1. Add an AchievementsService.cs class to the Services folder to hold the definition query logic:
  • We call Achievements.QueryDefinitions to populate our local cache with all achievement definitions.
  • Then we iterate through all achievements returned, and copy them from the cache to our ObservableCollection through Achievements.CopyAchievementDefinitionV2ByIndex.
    • Note that we’re using the V2 APIs in the SDK, which replace the deprecated older APIs (e.g. CopyAchievementDefinitionByIndex).
 
  1. Add a AchievementsQueryDefinitionsCommand.cs class to the Commands folder:
  1. Open AchievementsViewModel.cs to declare and instantiate the command:
  1. Add the following line to the RaiseConnectCanExecuteChanged() method in ViewModelLocator.cs to ensure we can only query for Achievement definitions after successfully logging in through the Connect Interface:
  1. Lastly, add the AchievementsView to our TabControl in MainWindow.xaml:
Now when we run the app and authenticate through Auth and Connect, we can navigate to the Achievements tab and query the achievement definitions using the Query definitions button.
 
App Achievements QueryDefinitions
Achievement definitions queried

Querying player achievement progress

Now that we know how to retrieve all achievement definitions, let’s take a look at retrieving the player’s progress towards them:
 
  1. Open AchievementsView.xaml and add our second ListView and StackPanel right below the previous </ListView> tag:
  • We’re using a bit of a brute force method to display the stat that’s attached to the achievement (if any). We’re displaying the first stat in the array (even if there aren’t any). In a production environment you’ll have to validate the array of PlayerStatInfo returned in the StatInfo property before using it.
 
  1. Open AchievementsViewModel.cs and declare the following collection below the SelectedAchievement to hold player achievement progress:
  1. Open AchievementsService.cs and add the following method to hold our player achievement progress query logic:
 
  1. Add an AchievementsQueryPlayerAchievementsCommand.cs class to the Commands folder:
  1. Open AchievementsViewModel.cs to declare and instantiate the command:
  1. Open ViewModelLocator.cs and add the following line to the RaiseConnectCanExecuteChanged() method to ensure we can only query for player achievement progress after successfully logging in through the Connect Interface:
Now we can launch our app again and use the Query progress button to retrieve the player’s achievement progress.
 
App Achievements QueryPlayerAchievementsInitial
Player’s achievement progress queried

There are a few things to note here:
 
  • The DisplayName property returned from the QueryPlayerAchievements call is null, similar to the Description, IconURL, and FlavorText properties (which we’re not displaying in the UI). These properties are retrieved and stored into the SDK cache by the QueryDefinitions call, so we need to click the Query definitions button first to populate these properties in the cache.
  • The StatInfo property will be null unless the player has stat values ingested. In the screenshot above, I have the logged in player’s stats reset so there’s no value displayed.
  • Player progress reported as a double value between 0 and 1, representing a value between 0 and 100%. As the logged in player in the screenshot does not have the stat ingested, progress is 0.

After we navigate to the Stats tab in our sample app and ingest a number of clicks, we can return to the Achievements tab and Query definitions and Query progress sequentially to display the player’s progress:
 
App Achievements QueryPlayerAchievementsFinal
Player’s achievement progress queried

Unlocking achievements

We’ve set up one of our achievements to unlock manually and the other automatically using a stat. Let’s take a look at the code to manually unlock achievements and also how to get notified when an achievement is automatically unlocked.

Note that, as mentioned earlier, unlocking achievements manually in the game’s code may expose an attack vector for malicious users to unlock achievements that they haven’t earned.
 
  1. Open AchievementService.cs and add the following method to hold our manual achievement unlock logic:
 
  1. Add an AchievementsUnlockAchievementCommand.cs class to the Commands folder:
  1. Open AchievementsViewModel.cs to declare and instantiate the command:
  1. Lastly, open AchievementsView.xaml.cs and add the following line to the AchievementsListView_SelectionChanged method, to make sure we can only click the Unlock button once an achievement is selected:
When you run the app and authenticate, navigate to the Achievements tab and click Query definitions. Then click on the TOP_SECRET achievement and click the Unlock button. The UI won’t change, but you should see an “UnlockAchievements Success” message in the Debug Output in Visual Studio. Note that this code applies to visible and hidden achievements.

Now we can click Query progress and our achievement will show up in the list. Hidden achievements are not returned by the QueryPlayerAchievements call until unlocked, as seen previously.
 
App Achievements UnlockAchievement
Hidden achievement manually unlocked

Finally, let’s subscribe to achievement unlock notifications, so we can run our own code when an achievement unlocks via stat progression:
 
  1. Open AchievementsService.cs and add the following methods to subscribe to and unsubscribe from achievement notifications:
  • We’re calling Achievements.AddNotifyAchievementsUnlockedV2 to set up notifications, passing in a callback method that will get called when an achievement is unlocked by ingesting stats associated with the achievement. Note that this method will also be called when you manually unlock achievements.
  • AchievementsUnlockedCallback will just write a line to the Debug Output in this case, but this is where you’d handle any UI to inform the player that they’ve unlocked an achievement.
  • AddNotifyAchievementsUnlockedV2 will return a notificationId, which you can use to stop being notified about achievement unlocks. We’re not implementing that in this sample, but that’s what the RemoveNotification method does.
 
  1. To keep things simple, add the following call to the QueryDefinitions method in AchievementsService.cs just above ViewModelLocator.Main.StatusBarText = string.Empty to start getting notified after calling QueryDefinitions:
Run the app again and authenticate, then navigate to the Achievements tab and click the Query definitions button. To check progress toward our achievement of 50 clicks total, click the Query progress button. If it’s not unlocked yet, note the progress and navigate to the Stats tab to ingest more clicks until it unlocks.

You should see a message pop up in the Debug Output in Visual Studio indicating the achievement was unlocked. If you already had the achievement unlocked, follow the steps in the next section to reset the achievement and also reset the player’s stats if necessary.

Looking up and modifying player achievements

If at any point in time you need to manually adjust a player’s achievements, either unlocking or resetting/locking them, you can do this in the Developer Portal:
 
  1. Log in to the Developer Portal at https://dev.epicgames.com/portal/.
  2. Navigate to your product > Game Services > Achievements in the left menu.
  3. Click on the “Player Lookup” button on the top right.
  4. In the flyout, enter the player’s Product User ID (PUID) or account-specific ID (e.g. Epic account ID) and click on “Search”.
  5. A list of the player’s achievements will appear with their current progress and unlock status. In this list, you can click the ellipsis button to either unlock or reset this achievement.

Note that you can also use the “Reset All” or “Unlock All” buttons to quickly toggle all achievements, but be cautious using this in a production environment. This is most useful during development. Another good practice is to create a separate deployment for testing achievements during development, as all player data is scoped to a specific deployment.

Developer Portal Achievements Player Lookup
Unlock or reset achievements in the Developer Portal

Usage limitations and requirements

As with the other services we’ve looked at, Achievements has some usage limitations in place to ensure reliability and availability for all users. At the time of writing, these are the limitations (be sure to check the documentation for the most up-to-date information):
 
  • 1000 total achievements maximum per deployment
  • Three stats maximum an achievement can automatically unlock from

Achievements also must adhere to the following requirements:
 
  • 256 characters maximum for an achievement ID
  • Achievement ID cannot contain the following characters: , { ^ } % ` ] > [ ~ < # | & $ @ = ; ? \ ( ) * /
  • Icon file name cannot contain the following characters:  , { ^ } % ` ] > [ ~ < # | & $ @ = ; : + ? ! \ ( ) * /
  • 22 localized text variants maximum per achievement
  • 1.02 MB maximum file size for achievement icons
  • 1024 x 1024 pixels maximum resolution for achievement icons
  • PNG, JPG, BMP, or non-animated GIF format only for achievement icons

Lastly, there are per-user or per-deployment rate limits for API calls for client or server calls respectively, which you can find in the documentation.

Get the code

Get the code for this article below. Follow the Usage instructions in the GitHub repo to set up the downloaded code.
 
The full list of articles in this series can be found in the series reference. For feedback or questions, head over to the Community forum.

    We succeed when you succeed

    Epic believes in an open, integrated games community.
    By offering our online services to everyone for free, we aim to empower more developers to serve their own player communities.