Authoring Achievements
Fields, the triggerType trap, criteria, points, and server-first claims
An achievement is a per-entry pack asset that tracks progress toward one trigger (or several, in multi-criteria mode) and awards points plus optional rewards on unlock. This page covers the Achievement schema; for the shared Requirements/Cost/Reward/ObjectiveSpec sub-schemas it reuses, see Shared Schemas.
Server/MMOSkillTree/Achievements/*.jsonAchievements/Filename is a PascalCase asset key (human echo only); the runtime id is the inner Payload.id. Templates live in Server/MMOSkillTree/AchievementTemplates/*.json.
Top level: triggerType, not type
type, aliased as triggerType), an achievement's top-level trigger key is triggerType only - type is not read there at all. This flips once you go inside criteria[]: a criterion object accepts both type and triggerType as aliases for the same field. Author triggerType at the top level and either key inside criteria to stay consistent.Meta vs. normal achievements
Two shapes coexist under the same Achievement type, decoded through AchievementConfig.parseAchievement:
- Meta achievement -
metaChildrenis present. This bypassestriggerType/criteriaparsing entirely and cascades to UNLOCKED once every listed child achievement is unlocked. - Normal achievement - single-criterion (top-level
triggerType/target/requiredAmount) or multi-criterion (acriteria[]array, which makes the top-level trigger fields ignored).
Achievement fields
| Field | Type | Default | Description |
|---|---|---|---|
id* | string | - | Rejects | = : # delimiters. |
metaChildren | string[] | optional | Presence alone makes this a META achievement; skips triggerType/criteria parsing entirely. |
triggerType* | ObjectiveType | - | Required unless metaChildren is set. Top level only - see the callout above. |
target | string | "" | Wildcard-aware: "*" or "any" (case-insensitive) both normalize to "" (match-all). |
requiredAmount | long | 1 | Single-criterion top-level key - not amount. |
matchMode | "EXACT" | "CONTAINS" | "PREFIX" | EXACT | Explicit default, unlike quest objectives which default to CONTAINS. See the callout below. |
qualifier | string | null | |
zone | string | null | |
displayName | string | echoes id | Deprecated - prefer titleKey. |
titleKey | string | null | Convention: achievement.<id>.title. |
description | string | "" | Deprecated - prefer descriptionKey. |
descriptionKey | string | null | Convention: achievement.<id>.desc. |
titleArgs / descriptionArgs | string[] | [] | |
category | string | "misc" | |
subcategory | string | "" | |
enabled | bool | true | |
requiresFeatures | string[] (or bare string) | [] | See Feature gating. |
sortOrder | int | 0 | |
points | int | 10 | Contributes to the player's total achievement-point gate/total. See Points & milestones. |
hidden | bool | false | Excluded from normal browse listings until unlocked (category counts, the "nearest" progress panel). Unlike featOfStrength, a hidden achievement's points still count toward the player's lifetime total - only featOfStrength is excluded from point totals. |
serverFirst | bool | false | Enables the server-first race claim. See Server-first claims. |
featOfStrength | bool | false | Implies hidden's browse-listing treatment, and is additionally excluded from the player's lifetime point total (the one exclusion hidden alone does not get - see Points & milestones). |
announcementCommand | string | null | Console command run on unlock. Security note: arbitrary commands - review untrusted packs before installing. |
chainId | string | null | Groups a tiered ladder (e.g. Bounty Hunter I/II/III) for chain-progress UI. |
tier | int | 0 | Position within chainId. |
classRequired | string | null | References the unreleased Class System - do not author on shipped pack content yet. |
icon | string | resolved | Falls back through: chain icon, REACH_LEVEL skill icon, category default, first reward icon, generic icon. |
legacySince | string | null | |
criteria | criterion[] | [] | When present, the top-level triggerType/target/... fields are ignored entirely; each criterion is its own spec. See Criteria array. |
autoClaimRewards | Reward[] | [] | Granted automatically on unlock. |
manualClaimRewards | Reward[] | [] | Sit UNLOCKED until the player claims them in the UI. |
Criteria array (multi-criterion achievements)
Each entry in criteria[] is its own ObjectiveSpec-shaped criterion: type (or triggerType alias - unlike the achievement top level, criteria accept both), target (wildcard-aware), amount (or requiredAmount alias, default 1), matchMode (default EXACT), qualifier, zone, displayText, textKey.
Criterion id is authoring-only
id key, but the runtime parser never reads it - it exists purely so criterionOverrides on a template-extending achievement can address a specific criterion. The live progress model addresses criteria by array index, not id, using a composite key of the form <achievementId>#<criterionIndex> in the player's achievement progress component. Reordering a shipped achievement's criteria[] array in a later pack update therefore re-indexes players' in-progress criteria - do not reorder existing criteria, only append.Points and milestones
Every achievement's points (default 10, whether or not it is hidden) adds to the player's lifetime achievement-point total, EXCEPT a featOfStrength achievement, which is excluded regardless of its authored points value (typically paired with points: 0 by convention, but the exclusion itself does not depend on that value). The plugin ships five built-in, fixed point-threshold milestones that fire automatically as the player's total crosses them - these are a Java-side default list, not a pack-authorable asset type.
Each milestone grants a scaling package of all-skill XP plus a global boost token on crossing (for example the 3,000-point milestone grants 1,500 all-skill XP and a 1.5x, 60-minute global boost; the thresholds and rewards scale up from there). A points gate is also available inside a PrerequisiteGroup via achievementPoints, for content that should only unlock after a player has racked up enough points.
Server-first claims
serverFirst: true enables a first-come-first-served race claim on that achievement: the first player to unlock it gets a permanent, server-wide first-claim record (surfaced in the achievement UI), and every later unlocker gets the normal achievement without the claim. Use this sparingly - it is meant for a handful of genuinely notable server milestones, not routine content.
Zero-point Feats of Strength
Set featOfStrength: true for a bragging-rights achievement that should never contribute to the player's point total or appear in normal browse listings until unlocked - the same listing treatment hidden gets, plus the point-total exclusion hidden alone does not get. Typically paired with points: 0 and a flavorful titleKey/descriptionKey, since the reward here is the title itself, not XP or currency.
Minimal example
{
"Name": "First_Kill",
"Payload": {
"id": "first_kill",
"triggerType": "KILL_ENTITY",
"target": "*",
"requiredAmount": 1,
"category": "combat",
"points": 10,
"autoClaimRewards": [ { "type": "XP", "skill": "SWORDS", "amount": 100 } ]
}
}Every-field example (real: a template + an extending entry)
{
"Name": "Bounty_Board_Counter",
"Payload": {
"triggerType": "COMPLETE_BOUNTY",
"target": "{{board}}",
"matchMode": "EXACT",
"category": "quests",
"subcategory": "bounties",
"descriptionKey": "achievement.bounty_streak.{{board}}.desc",
"descriptionArgs": ["@amount"]
}
}{
"Name": "Bounty_Daily_T1",
"Payload": {
"extends": "bounty_board_counter",
"id": "bounty_board_daily_t1",
"params": { "board": "daily" },
"requiredAmount": 5,
"sortOrder": 50,
"points": 15,
"chainId": "bounty_board_daily",
"tier": 1,
"manualClaimRewards": [ { "type": "CURRENCY", "currencyId": "bounty_token", "amount": 100 } ]
}
}See also
- Shared Schemas - ObjectiveSpec, Reward, PrerequisiteGroup, Requirements.
- Authoring Quests & Bounties - the matching quest-side objective schema, with the opposite matchMode default.
- Template Extension - the extends/params DSL (override field
criterionOverrides, extras fieldextraCriteria). - Achievements - the player-facing achievement UI and progress guide.