A cloneweb site

Achievements API

Achievements API is a mod originally developed to be used in Stargazer.
It lets developers easily add their own achievements with a user-friendly in-game UI.

Get started

To start using Achievements API, you need to:
- Add a reference to Mira API either through a DLL or project reference.
- Add a BepInDependency or SoftDependency on your plugin class like this:

[BepInDependency(AchievementsAPIPlugin.Id)]
[BepInDependency(AchievementsAPIPlugin.Id, BepInDependency.DependencyFlags.SoftDependency)]

Creating An Achievements Tab

To have a tab for your achievements to be stored in, you need to create a class implementing AchievementsTab.
AchievementsTab has the following members that need to be implemented for your Achievements to function correctly:

Member Required Default Description
string Name { get; } Yes — The name of the Achievements Tab, displayed in UI.
bool IsSelectable { get; } No true Whether the tab should be selectable in the Achievements Menu. Handy for custom UI's or internal achievements.
Color GetTabColor() No new Color32(255, 255, 150, 255) A method which gets the color of the Achievements Menu background when switching to this tab.
string IconPath { get; } No "AchievementsAPI.Resources.ExampleIcon.png" The path to the tab's icon, for if you don't have it as a Sprite.
Sprite GetIcon() No SpriteTools.LoadSpriteFromPath(IconPath, Assembly.GetCallingAssembly(), 100) A method which gets the icon of the tab, used for its icon in the Achievements Menu.

Example:

using AchievementsAPI.API;
using UnityEngine;

namespace TownOfExtra.Achievements;

public class ExampleAchievementsTab : AchievementsTab
{
public override string Name => "Example";
public override bool IsSelectable => true;

public override Color GetTabColor() => return new Color32(255, 255, 150, 255);
public override Sprite GetIcon() => "AchievementsAPI.Resources.ExampleIcon.png";
}

Creating Achievements

Single Unlock Achievements:

For each single unlock achievement (requires one thing to unlock, no progress) you need to create a BaseAchievement.
BaseAchievement has the following members that need to be implemented for your Achievement to function correctly:

Member Required Default Description
string Name Yes — The achievement's name.
string Description Yes — The achievement's description.
string IconPath Yes* — The achievement's icon path. *Use this constructor overload or provide a Sprite Icon directly.
Sprite Icon Yes* — The achievement's icon. *Use this constructor overload or provide an IconPath directly.
int Rarity No 0 The achievement's rarity: 0 = common (default), 1 = rare (blue), 2 = epic (purple), 3 = legendary (yellow).
bool Hidden No false Whether the achievement is hidden. Hidden achievements get the default icon, and their name and description are set to "Hidden Achievement" until unlocked.
bool HideRarity No true Whether to hide the achievement's rarity if the achievement is hidden.
Assembly? Assembly No Assembly.GetCallingAssembly() The assembly associated with the achievement, used to generate its Id.
bool Unlocked { get; } No false Whether the achievement has been unlocked.
string Id { get; } No Assembly.GetName().Name + "_" + Name The achievement's unique identifier.
void Unlock(bool showOnUI = true, bool doStorageUpdate = true) No — Unlocks the achievement. showOnUI shows an unlock animation on the HUD. doStorageUpdate indicates whether to update storage again; this is used to make CountAchievements properly update.

Example:

public BaseAchievement Welcome { get; set; } = new BaseAchievement(
    "Welcome!", "Launch the game with Achievements API installed.", "AchievementsAPI.Resources.ExampleIcon.png"
);

Count Unlock Achievements:

For each count unlock achievement (requires progression to unlock) you need to create a CountAchievement.
CountAchievement has the following members that need to be implemented for your Achievement to function correctly:

Member Required Default Description
int CurrentValue Yes — The current progress for this achievement.
int RequiredValue Yes — The required progress to unlock this achievement.
bool ProgressPersists No true Defines if the progress persists between games.
int Rarity No 0 The achievement's rarity: 0 = common (default), 1 = rare (blue), 2 = epic (purple), 3 = legendary (yellow).
bool Hidden No false Whether the achievement is hidden. Hidden achievements get the default icon, and their name and description are set to "Hidden Achievement" until unlocked.
bool HideRarity No true Whether to hide the achievement's rarity if the achievement is hidden.
bool HideProgress No false Whether to hide the achievement's progress if the achievement is hidden.
void Increment(int count, bool showOnUI = true) No — Increments the progress of this achievement by count. showOnUI shows an unlock animation on the HUD.
void SetValue(int value, bool showOnUI = true) No — Sets the progress of this achievement to value. showOnUI shows an unlock animation on the HUD.

Example:

public CountAchievement Taskmaster { get; set; } = new CountAchievement(
    "Taskmaster", "Do 5 tasks", "AchievementsAPI.Resources.ExampleIcon.png", 0, 5
);

Awarding Achievements

To award an achievement, you need to find your achievements tab, via AchievementsTabSingleton<ToexAchievementsTab>.Instance.
Once you have this instance, you can use it to access your achievements:

Unlocking BaseAchievements

To unlock a BaseAchievement, you can use achievement.Unlock();, for example:
AchievementsTabSingleton<ToexAchievementsTab>.Instance.Welcome.Unlock();

Progressing CountAchievements

To unlock a CountAchievement, you can use achievement.Increment(Amount); or achievement.SetValue(Amount);, for example:
AchievementsTabSingleton<ToexAchievementsTab>.Instance.Taskmaster.Increment(1); would add 1 to the achievement progress
and
AchievementsTabSingleton<ToexAchievementsTab>.Instance.Taskmaster.SetValue(10); would immediately unlock the achievement

Examples:

// Unlocking BaseAchievements
[HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Awake))]
[HarmonyPatch(Priority.Last)]
[HarmonyPostfix]
public static void OnMainMenuAwakePostfix(MainMenuManager __instance)
{
    AchievementsTabSingleton<ExampleTab>.Instance.Welcome.Unlock();
}

// Progressing CountAchievements
[HarmonyPostfix]
[HarmonyPatch(nameof(PlayerControl.CompleteTask))]
public static void PlayerCompleteTaskPostfix(PlayerControl __instance, uint idx)
{
    AchievementsTabSingleton<ExampleTab>.Instance.Taskmaster.Increment(1);
}