Content Types & Merging
What packs can extend, and how pack content combines with the defaults and the server owner's files
How merging works
- By id, additive. Each content entry has an id. A pack entry with a new id adds content; an entry whose id already exists overrides it. If two packs define the same id, the last-loaded pack wins.
- The server owner always wins. Content the owner authored locally (their own files under
mods/mmoskilltree/) is never overridden or dropped by a pack. - Defaults < pack < owner. Packs override the plugin's built-in defaults, but not the owner's explicit customizations.
Add vs. replace (the Control file)
By default a pack adds to existing content. To make a pack replace the built-in defaults for a content type (e.g. a total-conversion quest pack), include a control file at Server/MMOSkillTree/Control/<YourPackName>.json:
{
"Name": "MyMmoPack",
"Quests": "replace",
"Achievements": "add"
}replace drops the plugin's default content for that type and uses the pack's instead, but the server owner's own authored content is still kept and still wins. The Name must match your manifest Name.
Valid type keys (PascalCase, like all asset JSON keys): Quests, Achievements, XpMaps, MobKillXp, LuckLoot, ItemRequirements, ActionRequirements, BoostTemplates, Masteries, Currencies, CommandRewards, Classes, UIThemes, BountyBoards, ShopEntries, ShopPools, Shops, ShopTemplates, Dialogues, QuestGivers, Abilities, PowerLevel. If your pack ships templates, also add the matching template store (MasteryTemplates, QuestTemplates, AchievementTemplates, CommandRewardTemplates, ClassTemplates, DialogueTemplates) as "add". Ability Mods (AbilityMods/) have no dedicated Control key - a pack simply ships the folder.
Feature gating (requiresFeatures)
Quests and achievements can declare a dependency on one or more server features. When any listed feature is disabled, the entry is hidden everywhere - it does not appear in the UI, accrues no progress, and cannot be claimed. Re-enable the feature (config flip + server restart) and the entry returns.
{
"Name": "mastery_tithe",
"Payload": {
"id": "mastery_tithe",
"displayName": "Mastery Tithe",
"requiresFeatures": ["mastery"],
"objectives": [ { "id": "kill", "type": "KILL_ENTITY", "target": "*", "amount": 10 } ],
"rewards": [ { "type": "CURRENCY", "currencyId": "mastery_point", "amount": 1 } ]
}
}| Feature id | Gates on |
|---|---|
mastery | Mastery system enabled |
abilities (alias active_abilities) | Active abilities enabled |
currency (alias currencies) | Currency system enabled |
xp_tokens (alias tokens) | XP tokens enabled |
command_rewards | Command rewards enabled |
item_requirements | Item requirements enabled |
action_requirements | Action requirements enabled |
bounty (alias bounties) | Bounty Board enabled and at least one board loaded |
shop (aliases tokenshop, token_shop) | Token Shop enabled and stocked |
spawn_hub (aliases hubnpc, hub_npc) | Adventurer's Guide hub NPC enabled |
questgivers (alias quest_givers) | Quest-giver NPC roles enabled and at least one defined |
taming (alias tamework) | Taming integration active (Alec's Animal Husbandry) |
No elite_mobs feature id
elite_mobs/elites is not a registered feature id - authoring requiresFeatures: ["elite_mobs"]fails closed (unknown id, entry hidden forever, a one-time startup warning). Open-world mob difficulty now comes from the optional companion mod MMO Mob Scaling, configured separately and not reachable through this gate.- Lenient parse. Either a bare string (
"mastery") or an array is accepted. - AND-combined. When multiple ids are listed, the entry is hidden if any one is off.
- Templates inherit. A template's
requiresFeaturesapplies to every entry that extends it; a concrete entry can override it (or set[]to ungate). - Unknown ids fail closed. An unrecognized feature id hides the entry and logs a one-time
Unknown feature idwarning at server start.
File formats
All content lives under Server/MMOSkillTree/<Type>/. Files may be nested in subfolders freely. Two payload styles are used.
Per-entry "payload" types
One file per entry; the asset key is derived from the filename (e.g. dragon_hunt.json → dragon_hunt), and the top-level Name field echoes that key. Payload is the entry as a nested JSON object.
| Type | Folder | Payload | Docs |
|---|---|---|---|
| Quests | Quests/ | A single quest object | Quests config |
| Achievements | Achievements/ | A single achievement object | Achievements |
| Masteries | Masteries/ | A single mastery-track object | Masteries |
| Currencies | Currencies/ | A single currency-definition object | below |
| Abilities (1.6.0) | Abilities/ | A single ability definition (Identity / Cooldown / Cost / Effects / Presentation / ...) | Ability authoring |
| Ability Mods (1.6.0) | AbilityMods/ | A grantable improvement to an existing ability (TargetAbility + Modifiers) | Ability Mods |
| Power Level (1.5.0) | PowerLevel/ | Formula-tuning for the power-level pillars/clamp/modes consumed by MMO Mob Scaling | Power Level |
| Bounty boards | BountyBoards/ | A single bounty-board definition (rotation pool + accept gates) | Bounty Board |
| Shop entries | ShopEntries/ | A single shop offer (cost + unified reward payout) | Shop |
| Shop pools | ShopPools/ | A single rotating shop pool | Shop |
| Shops | Shops/ | A single shop / board definition | Shop |
| Dialogues | Dialogues/ | A single branching NPC dialogue tree, attached to a quest giver by id | Dialogues |
| Quest givers | QuestGivers/ | A single quest-giver NPC role: spawn placement, appearance, and the dialogue it attaches | Quest Givers |
| Classes (Future) | Classes/ | A single class-definition object | below |
| UI Themes (Future) | UIThemes/ | A theme palette + per-class accents + optional template overrides | - |
Dialogues and quest givers are independent - a pack can ship a QuestGiver that falls back to the plain NPC quest list with no custom Dialogue, or a Dialogue attached from spawn-hub.json instead of a quest giver.
Ability precedence (unique to this type)
Abilities are the one content type with a full three-layer fold, all through the SAME codec:
- Defaults - the 91 jar-shipped abilities at
Server/MMOSkillTree/Abilities/*.json. - Pack - a pack file at the same path with a matching id overrides the default entirely, unless it uses
Parentto overlay just a few fields. - Owner -
mods/mmoskilltree/ability-overrides.jsonfolds last, per-leaf (the same overlay semantics asParent: overriding one field never nulls out the rest).
abilities.json is retired
mods/mmoskilltree/abilities.json was a hard break in 1.6.0. Any file found there at startup is moved to mods/mmoskilltree/backup/ with a warning and never read again. Re-author ability tuning in ability-overrides.json instead - see Ability authoring.
Per-pack "map" types
One file per pack; Name is your pack name and Payload is the config's natural map.
| Type | Folder | Payload shape | Docs |
|---|---|---|---|
| XP maps | XpMaps/ | { "SKILL": { "pattern": value } } | XP Values |
| Mob-kill XP | MobKillXp/ | { "MobPattern": value } | Mob Kill XP |
| Luck loot | LuckLoot/ | { "BlockPattern": "ItemId" } | Luck |
| Item requirements | ItemRequirements/ | { "ItemPattern": { …override… } } | Item Requirements |
| Action requirements | ActionRequirements/ | { "blockTool": {…}, "mobWeapon": {…} } | Item Requirements |
| Boost templates | BoostTemplates/ | { "templateId": { "multiplier": … } } | XP Boosts |
| Command rewards | CommandRewards/ | { "<SKILL|TOTAL|GLOBAL_SKILL>": { "<level>": [ … ] } } | Command Rewards |
// Server/MMOSkillTree/XpMaps/MyMmoPack.json
{
"Name": "MyMmoPack",
"Payload": { "MINING": { "Ore_Adamantite": 25.0 } }
}Masteries
A mastery track targets a skill (skill:MINING) or an ability (ability:fireball) and lists purchasable nodes. Each node has an id, tier, cost (a currency map plus optional raw items and an optional stat sacrifice), and modifiers. Repeatable Eternal nodes set maxPurchases: -1 with costScaling. See the player-facing Mastery guide for how this looks in-game.
// Server/MMOSkillTree/Masteries/Mining_Mastery.json
{
"Name": "Mining_Mastery",
"Payload": {
"target": "skill:MINING",
"displayName": "Mining Mastery",
"refundPercent": 50,
"requirements": { "skillLevels": [ { "skill": "MINING", "level": 5 } ] },
"nodes": [
{
"id": "min_t1", "tier": 1, "displayName": "Mining Mastery I",
"cost": {
"combine": "all",
"currencies": { "mastery_point": 2, "life_essence": 500 },
"items": [ { "id": "Ingredient_Crystal_Blue", "count": 1 } ]
},
"modifiers": [ { "shape": "PERCENT", "key": "lootMultiplier", "value": 0.03, "targetSkill": "MINING" } ]
},
{
"id": "min_eternal", "tier": 9, "displayName": "Mining Mastery: Eternal",
"maxPurchases": -1,
"costScaling": { "mode": "EXPONENTIAL", "multiplier": 1.1 },
"cost": { "combine": "all", "currencies": { "mastery_point": 1, "life_essence": 200 } },
"modifiers": [ { "shape": "PERCENT", "key": "lootMultiplier", "value": 0.005, "targetSkill": "MINING" } ]
}
]
}
}Currencies
Currencies come in two flavors. Counter-backed currencies are a number stored on the player (no inventory item) - set iconItemId for the display icon and leave hytaleItemId unset. Item-backed currencies wrap a real Hytale item - set hytaleItemId to the item id. The currency id is the filename, lowercased. See the player-facing Currencies guide.
// Counter-backed - Server/MMOSkillTree/Currencies/Mastery_Point.json
{
"Name": "Mastery_Point",
"Payload": {
"displayName": "Mastery Points",
"iconItemId": "Ingredient_Crystal_Purple",
"color": "#c08aff",
"cap": 0,
"showOnSidebar": true,
"showOnMasteryPage": true
}
}
// Item-backed - Server/MMOSkillTree/Currencies/Life_Essence.json
{
"Name": "Life_Essence",
"Payload": {
"displayName": "Life Essence",
"hytaleItemId": "Ingredient_Life_Essence",
"color": "#a7e0a7",
"cap": 0
}
}Grant currency from quests/achievements (CURRENCY reward), from command rewards, or from the admin command. Always use the named-arg form:
/mmocurrency give --player={player} --currency=mastery_point --amount=1Classes (Future)
The Class System is a future, unreleased feature; the schema below documents the planned content shape. The plugin ships no built-in classes, and without a class pack the class system stays dormant. A class definition carries base grants applied while the class is selected, plus additive advancements (ranks) unlocked by meeting prerequisites.
| Field | Type | Notes |
|---|---|---|
displayName / flavor / description / icon | string | UI surface; icon is a Hytale item id. |
unlockRequirements | PrerequisiteGroup | Gate selection (quests, skill levels, total level, achievements, currency). Empty = freely selectable. |
switchPolicy | SwitchPolicy | Per-class override of the global switch cost/cooldown. |
baseGrants | ClassGrants | Applied while the class is selected. |
advancements | ClassAdvancement[] | Additive ranks; grants deep-merge over base. |
ClassGrants (used by base and each advancement):
| Field | Notes |
|---|---|
xpMultipliers | map of skill → multiplier (0.0 = no XP, 1.25 = +25%). |
abilityWhitelist / abilityBlacklist | Gate which abilities are usable. Blacklist always wins. |
masteryWhitelist / masteryBlacklist | Gate mastery purchases (by trackId or trackId:nodeId). |
skillRewardWhitelist / skillRewardBlacklist | Gate skill-tree reward claims. |
passiveRewards | SkillRewards applied while the class is active. |
startingItems / startingMasteryNodes / classQuests | Granted/unlocked on selection. |
SwitchPolicy defaults: firstSwitchFree: true, costCurrencyId: "mastery_points", costAmount: 100, cooldownMs: 24h, escalationMultiplier: 1.0, permanentLock: false. Build classes from a template - see Template Extension.
Export as Pack
The in-game Export as Pack tool generates a correctly-formatted pack from your current server content - the recommended starting point, since it emits valid filenames, Name echoes, and Payload shapes for you. The /mmopacks admin command lists and inspects loaded packs (/mmopacks --action=list); exporting is driven by the Export as Pack tool, not a bare /mmopacks export subcommand.