Skip to content

These docs were made completely by AI, so they might be right, or wrong, you'll need to test them yourself. This was made for a easier understanding of everything. So use at your own risk. If anything is wrong, please don't hurt to make a PR on the page you have a problem with. ON GITHUB

Custom Achievements

Achievements in LCE are a tree of unlockable goals that extend the Stat class. Each one has a parent dependency, an icon, a position on the achievement screen map, and a trigger condition defined in gameplay code. This guide breaks down the whole system and shows you how to add your own.

The achievement system has three layers:

  1. Stat (base class) - Holds an ID, a name, and a value counter per difficulty. Lives in Minecraft.World/Stat.h.
  2. Achievement (subclass of Stat) - Adds an icon, x/y position on the map, a parent dependency, and an optional golden frame. Lives in Minecraft.World/Achievement.h.
  3. Achievements (static registry) - A static class that holds pointers to every achievement and manages the global list. Lives in Minecraft.World/Achievements.h.

When the player does something (crafts an item, kills a mob, enters a biome), the game calls player->awardStat(). If the stat is an Achievement, it gets recorded in the StatsCounter and the platform-specific award system (trophies, Xbox achievements, etc.) gets notified.

Here’s the class hierarchy:

// Stat is the base: just an ID, name, and formatter
class Stat {
public:
const int id;
const wstring name;
bool awardLocallyOnly;
// ...
};
// Achievement adds tree position, icon, parent, and golden flag
class Achievement : public Stat {
public:
const int x, y; // position on the achievement map
Achievement *requires; // parent achievement (NULL = root)
const shared_ptr<ItemInstance> icon;
private:
bool isGoldenVar; // golden frame for special achievements
// ...
};

Every achievement maps to an entry in the eAward enum defined in Console_Awards_enum.h. This enum is what the platform layer uses to track which trophies/achievements have been unlocked:

enum eAward {
eAward_TakingInventory = 0, // Open your inventory
eAward_GettingWood, // Punch a tree
eAward_Benchmarking, // Build a workbench
eAward_TimeToMine, // Build a pickaxe
eAward_HotTopic, // Build a furnace
eAward_AquireHardware, // Smelt an iron ingot
eAward_TimeToFarm, // Build a hoe
eAward_BakeBread, // Make bread
eAward_TheLie, // Bake a cake
eAward_GettingAnUpgrade, // Build a stone pickaxe
eAward_DeliciousFish, // Cook fish
eAward_OnARail, // Travel 500m by minecart
eAward_TimeToStrike, // Build a sword
eAward_MonsterHunter, // Kill a hostile mob
eAward_CowTipper, // Kill a cow
eAward_WhenPigsFly, // Fly a pig off a cliff
eAward_LeaderOfThePack, // Tame 5 wolves
eAward_MOARTools, // Craft one of each tool type
eAward_DispenseWithThis, // Build a dispenser
eAward_InToTheNether, // Light a nether portal
eAward_mine100Blocks, // Mine 100 blocks
eAward_kill10Creepers, // Kill 10 creepers
eAward_eatPorkChop, // Cook and eat porkchop
eAward_play100Days, // Play for 100 in-game days
eAward_arrowKillCreeper, // Kill creeper with arrow
eAward_socialPost, // Take a screenshot
// ... plus extended achievements behind #ifdef _EXTENDED_ACHIEVEMENTS
eAward_Max,
};
AchievementEnumTriggerParentGolden?
Taking InventoryeAward_TakingInventoryOpen inventory screenNone (root)No
Getting WoodeAward_GettingWoodMine a log blockTaking InventoryNo
BenchmarkingeAward_BenchmarkingCraft a workbenchGetting WoodNo
Time to Mine!eAward_TimeToMineCraft a wooden pickaxeBenchmarkingNo
Hot TopiceAward_HotTopicCraft a furnaceTime to MineNo
Acquire HardwareeAward_AquireHardwareSmelt iron ingot from furnaceHot TopicNo
Time to Farm!eAward_TimeToFarmCraft a wooden hoeBenchmarkingNo
Bake BreadeAward_BakeBreadCraft breadTime to FarmNo
The LieeAward_TheLieCraft a cakeTime to FarmNo
Getting an UpgradeeAward_GettingAnUpgradeCraft a stone pickaxeTime to MineNo
Delicious FisheAward_DeliciousFishSmelt a fish in a furnaceHot TopicNo
On A RaileAward_OnARailTravel 500+ blocks by minecartAcquire HardwareYes
Time to Strike!eAward_TimeToStrikeCraft a wooden swordBenchmarkingNo
Monster HuntereAward_MonsterHunterKill a hostile mobTime to StrikeNo
Cow TippereAward_CowTipperKill a cowTime to StrikeNo
When Pigs FlyeAward_WhenPigsFlyRide a pig off a cliffCow TipperYes
AchievementEnumTriggerLocal Only?
Leader of the PackeAward_LeaderOfThePackTame 5 wolves totalYes
MOAR ToolseAward_MOARToolsCraft one of each tool type (shovel, pickaxe, axe, hoe)Yes
Dispense With ThiseAward_DispenseWithThisCraft a dispenserNo
Into The NethereAward_InToTheNetherLight a nether portal with flint and steelNo
Mine 100 BlockseAward_mine100BlocksMine 100 total blocksYes
Kill 10 CreeperseAward_kill10CreepersKill 10 creepers totalYes
Pork ChopeAward_eatPorkChopCook and eat a porkchopPlatform-dependent
Play for 100 DayseAward_play100DaysPlay for 100 in-game days (100 * 24000 ticks)Yes
Arrow Kill CreepereAward_arrowKillCreeperKill a creeper with a bowNo

These are behind #ifndef _XBOX and are available on PS3, PS Vita, and later platforms:

AchievementTriggerGolden?
Sniper DuelKill a skeleton from 50+ blocks away with a bowYes
Diamonds!Pick up a diamondNo
Return to SenderKill a ghast with its own fireballYes
Into FirePick up a blaze rodNo
Local BreweryBrew a potionNo
The End?Enter the EndYes
The End.Defeat the Ender DragonYes
EnchanterUse an enchantment tableNo

Extended Achievements (_EXTENDED_ACHIEVEMENTS)

Section titled “Extended Achievements (_EXTENDED_ACHIEVEMENTS)”

Available on PS4 (Orbis) and later platforms:

AchievementTrigger
OverkillDeal 9+ hearts of damage in one hit
LibrarianCraft a bookshelf
Adventuring TimeVisit 17+ different biomes
RepopulationBreed two cows
Diamonds to YouThrow a diamond to another player
The HagglerAcquire 30 emeralds (mined + traded)
Pot PlanterCraft and place a flower pot
It’s a Sign!Craft and place a sign
Iron BellyEat rotten flesh (stop hunger with iron)
Have a Shearful DayShear a sheep
Rainbow CollectionCollect all 16 wool colors
Stayin’ FrostyCreate a snow golem
Chestful of CobblestoneFill a chest with 27 stacks of cobblestone
Renewable EnergySmelt wood logs in a furnace
Music to my EarsPlay a music disc in a jukebox
Body GuardCreate an iron golem
Iron ManWear a full set of iron armor
Zombie DoctorCure a zombie villager
Lion TamerTame an ocelot

Achievements form a tree using the requires pointer. A player needs to unlock the parent before the child shows as available on the achievement screen.

The main tree looks like this:

Taking Inventory (root)
└── Getting Wood
└── Benchmarking (Workbench)
├── Time to Mine (Pickaxe)
│ ├── Hot Topic (Furnace)
│ │ ├── Acquire Hardware (Iron)
│ │ │ ├── On A Rail ★
│ │ │ └── Diamonds!
│ │ ├── Delicious Fish
│ │ └── Enchanter
│ └── Getting an Upgrade (Stone Pickaxe)
├── Time to Farm (Hoe)
│ ├── Bake Bread
│ └── The Lie (Cake)
└── Time to Strike (Sword)
├── Monster Hunter
│ └── Sniper Duel ★
└── Cow Tipper
└── When Pigs Fly ★

Stars mark golden achievements. The 4J console-specific achievements all use buildSword as their parent (though this is mostly ignored since the position params are 0,0 on console).

In Console_Awards_enum.h, add your new award right before eAward_Max:

enum eAward {
// ... existing awards ...
eAward_lionTamer,
// Your new achievement
eAward_myCustomAchievement,
eAward_Max,
};

In Achievements.h, add a static pointer for your achievement:

class Achievements {
// ... existing achievements ...
static Achievement *lionTamer;
// Your new one
static Achievement *myCustomAchievement;
static void staticCtor();
static void init();
};

In Achievements.cpp, add the NULL initializer and then construct it in staticCtor():

// At the top with the other initializers
Achievement *Achievements::myCustomAchievement = NULL;
// Inside staticCtor(), at the end
void Achievements::staticCtor()
{
// ... existing achievements ...
Achievements::myCustomAchievement = (new Achievement(
eAward_myCustomAchievement, // enum ID
L"myCustomAchievement", // localization key
0, 0, // x, y position on map
Item::diamond, // icon (Item* or Tile*)
(Achievement*) NULL // parent (NULL = no dependency)
))->postConstruct();
}

The constructor parameters are:

ParamTypeWhat it does
idint (eAward)Gets added to ACHIEVEMENT_OFFSET (0x500000) to make the stat ID
namewstringUsed as achievement.<name> for the localized display name
x, yintPosition on the achievement map (24px per unit)
iconItem* or Tile*The item/block icon shown in the UI
requiresAchievement*Parent in the achievement tree, or NULL

In GenericStats.cpp, add a static method so the rest of the code can reference your achievement:

Stat* GenericStats::myCustomAchievement()
{
return instance->get_achievement(eAward_myCustomAchievement);
}
byteArray GenericStats::param_myCustomAchievement()
{
return instance->getParam_achievement(eAward_myCustomAchievement);
}

And declare both in GenericStats.h:

static Stat* myCustomAchievement();
static byteArray param_myCustomAchievement();

In CommonStats.cpp, add the case to get_achievement():

Stat *CommonStats::get_achievement(eAward achievementId)
{
switch (achievementId)
{
// ... existing cases ...
case eAward_myCustomAchievement:
return (Stat *) Achievements::myCustomAchievement;
default:
return (Stat *) NULL;
}
}

Now you just call awardStat() from wherever makes sense:

player->awardStat(
GenericStats::myCustomAchievement(),
GenericStats::param_myCustomAchievement()
);

There are two patterns for triggering achievements: simple triggers and stat-checked triggers.

These fire the achievement directly when something happens. Used for one-off actions like “craft this item” or “enter this place”:

// In ResultSlot::checkTakeAchievements() - fires when player crafts
if (carried->id == Tile::workBench_Id)
player->awardStat(GenericStats::buildWorkbench(), GenericStats::param_buildWorkbench());
// In FurnaceResultSlot - fires when player takes item from furnace
if (carried->id == Item::ironIngot_Id)
player->awardStat(GenericStats::acquireIron(), GenericStats::param_acquireIron());
// In FlintAndSteelItem - fires when player lights a nether portal
player->awardStat(GenericStats::InToTheNether(), GenericStats::param_InToTheNether());

These check accumulated stats before awarding. Used for things like “kill 10 creepers” or “visit 17 biomes”. The checks live in LocalPlayer::awardStat():

// Leader of the Pack: tame 5 wolves
if (stat == GenericStats::tamedEntity(eTYPE_WOLF))
{
if (pStats->getTotalValue(GenericStats::tamedEntity(eTYPE_WOLF)) >= 5)
{
awardStat(GenericStats::leaderOfThePack(), GenericStats::param_noArgs());
}
}
// Rainbow Collection: collect all 16 wool colors
bool justPickedupWool = false;
for (int i = 0; i < 16; i++)
if (stat == GenericStats::itemsCollected(Tile::cloth_Id, i))
justPickedupWool = true;
if (justPickedupWool)
{
unsigned int woolCount = 0;
for (unsigned int i = 0; i < 16; i++)
{
if (pStats->getTotalValue(GenericStats::itemsCollected(Tile::cloth_Id, i)) > 0)
woolCount++;
}
if (woolCount >= 16)
awardStat(GenericStats::rainbowCollection(), GenericStats::param_rainbowCollection());
}

Some achievements need multiple different things to happen. The Pot Planter achievement needs you to both craft AND place a flower pot:

Stat *craftFlowerpot = GenericStats::itemsCrafted(Item::flowerPot_Id);
Stat *placeFlowerpot = GenericStats::blocksPlaced(Tile::flowerPot_Id);
if (stat == craftFlowerpot || stat == placeFlowerpot)
{
if ((pStats->getTotalValue(craftFlowerpot) > 0) &&
(pStats->getTotalValue(placeFlowerpot) > 0))
{
awardStat(GenericStats::potPlanter(), GenericStats::param_potPlanter());
}
}

The most complex trigger. It builds a 4x5 grid of tool stats and checks that you’ve crafted at least one from each of the four tool categories:

// Builds a table: [shovel, pickaxe, axe, hoe] x [wood, stone, iron, diamond, gold]
Stat *toolStats[4][5];
toolStats[0][0] = GenericStats::itemsCrafted(Item::shovel_wood->id);
toolStats[0][1] = GenericStats::itemsCrafted(Item::shovel_stone->id);
// ... all 20 combinations ...
// Check: has the player crafted at least one tool from each row?
bool awardNow = true;
for (int i = 0; i < 4; i++)
{
bool craftedThisTool = false;
for (int j = 0; j < 5; j++)
{
if (pStats->getTotalValue(toolStats[i][j]) > 0)
craftedThisTool = true;
}
if (!craftedThisTool)
{
awardNow = false;
break;
}
}
if (awardNow)
awardStat(GenericStats::MOARTools(), GenericStats::param_noArgs());

Achievements sit on top of a broader stat tracking system. Here’s how it fits together.

ClassOffsetPurpose
GeneralStatID 2000+Distance traveled, kills, time played
ItemStatBLOCKS_MINED_OFFSET (0x1000000)Per-block mining counts
ItemStatITEMS_COLLECTED_OFFSET (0x1010000)Per-item pickup counts
ItemStatITEMS_CRAFTED_OFFSET (0x1020000)Per-item crafting counts
AchievementACHIEVEMENT_OFFSET (0x500000)Achievement unlocks
AdditionalADDITIONAL_STATS_OFFSET (0x5010000)Stats added in TU9+

StatsCounter is the per-player stats tracker. It stores a map from Stat* to values split by difficulty:

class StatsCounter {
struct StatContainer {
unsigned int stats[4]; // Peaceful, Easy, Normal, Hard
};
typedef unordered_map<Stat*, StatContainer> StatsMap;
StatsMap stats;
public:
void award(Stat *stat, unsigned int difficulty, unsigned int count);
bool hasTaken(Achievement *ach); // checks if achievement exists in map
bool canTake(Achievement *ach); // always returns true (dependencies disabled)
unsigned int getValue(Stat *stat, unsigned int difficulty);
unsigned int getTotalValue(Stat *stat); // sum across all difficulties
};

When award() is called with an Achievement, the difficulty gets forced to 0:

void StatsCounter::award(Stat* stat, unsigned int difficulty, unsigned int count)
{
if (stat->isAchievement())
difficulty = 0; // achievements don't vary by difficulty
// ... insert or increment the value ...
}
  1. Gameplay code calls player->awardStat(stat, paramBlob)
  2. LocalPlayer::awardStat() checks if it’s an achievement
  3. If it is: notify the platform award system (ProfileManager.Award()), then call StatsCounter::award()
  4. If it’s a regular stat: call StatsCounter::award(), then check if any cumulative achievements should unlock

Marks the achievement so it only awards on the local machine and doesn’t get sent to other players in multiplayer. Used for stat-based achievements that each player tracks independently:

Achievements::leaderOfThePack = (new Achievement(
eAward_LeaderOfThePack, L"leaderOfThePack",
0, 0, Tile::treeTrunk, (Achievement *) buildSword
))->setAwardLocallyOnly()->postConstruct();

Gives the achievement a golden frame on the achievement screen. Used for the harder or more notable ones like On A Rail, When Pigs Fly, and Sniper Duel:

Achievements::onARail = (new Achievement(
eAward_OnARail, L"onARail",
2, 3, Tile::rail, (Achievement *) acquireIron
))->setGolden()->postConstruct();

Lets you customize how the achievement description renders. Takes a DescFormatter* that can transform the i18n string:

class DescFormatter {
public:
virtual wstring format(const wstring& i18nValue);
};

The achievement screen is a scrollable map. It uses the x/y coordinates of each achievement (multiplied by ACHIEVEMENT_COORD_SCALE = 24 pixels) to place icons on a grid.

The background renders procedurally generated terrain tiles (dirt, stone, ores) that get darker as you scroll down. Achievement icons are drawn on top, connected by lines to their parent achievements.

Color coding:

  • Full brightness: Achievement has been taken
  • Pulsing green lines: Achievement can be taken (parent completed)
  • Dark/dimmed: Achievement is locked (parent not completed)

Golden achievements use a different sprite frame (blit offset 26,202 vs 0,202 from bg.png).

Hovering over an achievement shows its name and description. If it’s locked, it shows “Requires: [parent name]” instead.

When an achievement unlocks, a toast slides down from the top-right corner of the screen. It shows for 3 seconds:

void AchievementPopup::popup(Achievement *ach)
{
title = I18n::get(L"achievement.get"); // "Achievement Get!"
desc = ach->name;
startTime = System::currentTimeMillis();
this->ach = ach;
isHelper = false;
}

The popup animation uses a smooth ease-in-out curve. After 3 seconds (time > 1.0 where time = elapsed / 3000.0), it disappears.

Full Example: Adding a “Master Builder” Achievement

Section titled “Full Example: Adding a “Master Builder” Achievement”

Let’s add an achievement that triggers when a player places 1000 total blocks.

1. Add to enum (Console_Awards_enum.h):

eAward_masterBuilder,
eAward_Max,

2. Declare (Achievements.h):

static Achievement *masterBuilder;

3. Initialize (Achievements.cpp):

Achievement *Achievements::masterBuilder = NULL;
// In staticCtor():
Achievements::masterBuilder = (new Achievement(
eAward_masterBuilder,
L"masterBuilder",
5, -2, // position on achievement map
Tile::stoneBrick, // icon
(Achievement *) buildWorkbench // requires Benchmarking
))->setAwardLocallyOnly()->postConstruct();

4. GenericStats accessors (GenericStats.h and GenericStats.cpp):

.h
static Stat* masterBuilder();
static byteArray param_masterBuilder();
// .cpp
Stat* GenericStats::masterBuilder()
{
return instance->get_achievement(eAward_masterBuilder);
}
byteArray GenericStats::param_masterBuilder()
{
return instance->getParam_achievement(eAward_masterBuilder);
}

5. CommonStats mapping (CommonStats.cpp):

case eAward_masterBuilder:
return (Stat *) Achievements::masterBuilder;

6. Add a “total blocks placed” stat (Stats.cpp):

// In buildAdditionalStats():
Stats::totalBlocksPlaced = (new GeneralStat(offset++, L"stat.totalBlocksPlaced"))
->setAwardLocallyOnly()->postConstruct();

7. Track block placements (TileItem.cpp, in useOn()):

player->awardStat(GenericStats::totalBlocksPlaced(), GenericStats::param_noArgs());

8. Check threshold (LocalPlayer.cpp, in awardStat()):

// AWARD: Master Builder - place 1000 blocks
if (stat == GenericStats::totalBlocksPlaced())
{
if (pStats->getTotalValue(GenericStats::totalBlocksPlaced()) >= 1000)
{
awardStat(GenericStats::masterBuilder(), GenericStats::param_masterBuilder());
}
}

9. Add localization strings for achievement.masterBuilder and achievement.masterBuilder.desc in your language files.

That’s it. The achievement will show up on the map, track across save/load, and trigger the platform’s native award notification when the player hits 1000 placed blocks.

FileWhat’s in it
Minecraft.World/Achievement.hAchievement class definition
Minecraft.World/Achievements.hStatic registry of all achievements
Minecraft.World/Achievements.cppAchievement construction and tree setup
Minecraft.World/Stat.hBase stat class
Minecraft.World/Stats.cppAll stat registration (blocks mined, items crafted, etc.)
Minecraft.World/GenericStats.cppStatic accessor functions for stats/achievements
Minecraft.World/CommonStats.cppPlatform-specific stat mappings
Minecraft.Client/StatsCounter.hPer-player stat storage and queries
Minecraft.Client/LocalPlayer.cppAchievement trigger logic and cumulative checks
Minecraft.Client/AchievementScreen.cppAchievement map UI rendering
Minecraft.Client/AchievementPopup.cppToast notification rendering
Console_Awards_enum.hPlatform award ID enum
Minecraft.World/ResultSlot.cppCrafting-based achievement triggers