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.

Content pack assetServer/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.

defaults<pack<owner

Top level: triggerType, not type

Unlike a quest objective (which reads 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 - metaChildren is present. This bypasses triggerType/criteria parsing entirely and cascades to UNLOCKED once every listed child achievement is unlocked.
  • Normal achievement - single-criterion (top-level triggerType/target/requiredAmount) or multi-criterion (a criteria[] array, which makes the top-level trigger fields ignored).

Achievement fields

FieldTypeDefaultDescription
id*string-Rejects | = : # delimiters.
metaChildrenstring[]optionalPresence 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.
targetstring""Wildcard-aware: "*" or "any" (case-insensitive) both normalize to "" (match-all).
requiredAmountlong1Single-criterion top-level key - not amount.
matchMode"EXACT" | "CONTAINS" | "PREFIX"EXACTExplicit default, unlike quest objectives which default to CONTAINS. See the callout below.
qualifierstringnull
zonestringnull
displayNamestringechoes idDeprecated - prefer titleKey.
titleKeystringnullConvention: achievement.<id>.title.
descriptionstring""Deprecated - prefer descriptionKey.
descriptionKeystringnullConvention: achievement.<id>.desc.
titleArgs / descriptionArgsstring[][]
categorystring"misc"
subcategorystring""
enabledbooltrue
requiresFeaturesstring[] (or bare string)[]See Feature gating.
sortOrderint0
pointsint10Contributes to the player's total achievement-point gate/total. See Points & milestones.
hiddenboolfalseExcluded 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.
serverFirstboolfalseEnables the server-first race claim. See Server-first claims.
featOfStrengthboolfalseImplies 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).
announcementCommandstringnullConsole command run on unlock. Security note: arbitrary commands - review untrusted packs before installing.
chainIdstringnullGroups a tiered ladder (e.g. Bounty Hunter I/II/III) for chain-progress UI.
tierint0Position within chainId.
classRequiredstringnullReferences the unreleased Class System - do not author on shipped pack content yet.
iconstringresolvedFalls back through: chain icon, REACH_LEVEL skill icon, category default, first reward icon, generic icon.
legacySincestringnull
criteriacriterion[][]When present, the top-level triggerType/target/... fields are ignored entirely; each criterion is its own spec. See Criteria array.
autoClaimRewardsReward[][]Granted automatically on unlock.
manualClaimRewardsReward[][]Sit UNLOCKED until the player claims them in the UI.
* required

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

A criterion object accepts an 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.

Milestone 1
500 pts
Milestone 2
3,000 pts
Milestone 3
7,500 pts
Milestone 4
14,000 pts
Milestone 5
24,000 pts

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

Server/MMOSkillTree/Achievements/First_Kill.json
{
  "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)

Server/MMOSkillTree/AchievementTemplates/Bounty_Board_Counter.json
{
  "Name": "Bounty_Board_Counter",
  "Payload": {
    "triggerType": "COMPLETE_BOUNTY",
    "target": "{{board}}",
    "matchMode": "EXACT",
    "category": "quests",
    "subcategory": "bounties",
    "descriptionKey": "achievement.bounty_streak.{{board}}.desc",
    "descriptionArgs": ["@amount"]
  }
}
Server/MMOSkillTree/Achievements/Bounty_Daily_T1.json
{
  "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 field extraCriteria).
  • Achievements - the player-facing achievement UI and progress guide.