| title | API - Mutations |
|---|---|
| description | Read mutation catalogs, state, and player snapshots |
| published | true |
| date | 2026-09-04 00:00:00 UTC |
| tags | adapt |
| editor | markdown |
| dateCreated | 2026-08-09 00:00:00 UTC |
The mutation surface a third-party plugin can rely on is read-only. An immutable catalogue describes what mutations exist. Immutable snapshot and result types describe what a player currently has. Everything lives under art.arcane.adapt.api.mutation.
Adapt does not expose its live MutationManager as a Bukkit service. There is no supported way to reach one. The manager, the config, the combat lock, and the persisted player record are
public Java classes. Adapt's own commands, GUI, and runtime need them across
packages. They are not contracts. Constructing your own copy gives you disconnected state that Adapt never reconciles or publishes.
If what you want is "show me this player's mutations", read them through PlaceholderAPI instead. That path is snapshot-backed and thread-safe. It is documented in 47 - API - PlaceholderAPI.
MutationType is the enum of the fifteen mutations. Each constant carries its id, localized display name, its two domains, and the normalized MutationLineage pair. It also carries a Bukkit Material icon, five descriptive strings, whether it matters in PvP, and its permission node. MutationType.find(id) looks one up by id and accepts underscores in place of hyphens.
MutationCatalog.defaults() is the immutable catalogue built from that enum. It adds the domain-to-skill mapping that decides which skills qualify a player for which domain.
MutationPairingRules.evaluate(first, second) is pure. Hand it two types and it tells you whether they can share a loadout. It also tells which exclusive MutationClaim values that pair contends for, and a plain-language policy string. Nothing about a player is involved. It is safe to call from anywhere.
MutationProgression answers level questions. It tells which slots are
unlocked at a given master level and how many. It also tells whether the player
is at perfect adaptation and whether burdens are still active.
MutationLimits holds the hard safety ceilings the runtime and the config
profiles clamp against.
Do not call MutationType.keys() or MutationDomain.keys(). They exist to feed Adapt's localization pass. They return TextKey instances from VolmLib, which is relocated inside Adapt's shaded jar. The type you compile against is not the type you get at runtime.
MutationSnapshot is the immutable per-player view. It holds the two slot ids,
the expressed and discovered types, perfect state, and unlocked slot flags. It
also holds the cooperative opt-in, a MutationState per type with a reason
string, and per-type qualification data. MutationSnapshot.empty() builds the
"runtime unavailable" view where every type is LOCKED.
MutationQualification and MutationSelectionResult are the immutable result records the manager produces. Qualification reports overall and per-domain qualification with the adaptation ids that earned it. Selection reports success, a message, and any remaining cooldown. Both are useful to read. Neither gives you a way to reach the manager that produced it.
MutationType.permission() returns adapt.use.mutation.<mutation-id> with the id's hyphens intact, for example adapt.use.mutation.bastion-spine. Adapt registers all fifteen at startup with default true and lists them as children of adapt.use.*.
| Type | Supported use |
|---|---|
MutationType |
Fifteen constants. id(), localized displayName(), firstDomain(), secondDomain(), lineage(), Bukkit icon(), the descriptive strings benefit() / burden() / perfectResult() / tell() / control(), pvpRelevant(), permission(), static find(id). Do not call keys() |
MutationDomain |
BODY, HUNT, INDUSTRY, WILD, CRAFT, ANOMALY. displayName() is safe. Do not call keys() |
MutationLineage |
record(first, second). Build with of(first, second). Rejects two identical domains and reorders the pair into enum order |
MutationCatalog |
defaults() returns the shared immutable catalogue. mutations(), find(id), domainSkills(domain), domainSkills() |
MutationPairingRules |
evaluate(first, second) returns a PairResolution(compatible, exclusiveClaims, policy). Pure, no player state |
MutationProgression |
record(slotOneLevel, slotTwoLevel, perfectLevel, perfectEnabled) with isSlotUnlocked(level, slot), unlockedSlotCount(level), isPerfect(level), isBurdenActive(level) |
MutationLimits |
Public static final ceilings such as MAX_DURATION_MILLIS, MAX_DELAY_TICKS, QUALIFICATION_CANDIDATES_PER_DOMAIN, plus per-mutation caps |
| Type | Contract |
|---|---|
MutationSnapshot |
Immutable player view: slot ids, expressed and discovered types, perfect state, unlocked slots, cooperative opt-in, per-type state(type) and reason(type), and qualified(type) / qualifyingAdaptations(type) / qualificationReason(type). state(type) returns RESTRICTED for an unmapped type. empty() supplies the unavailable view |
MutationState |
LOCKED, AVAILABLE, EXPRESSED, DORMANT, DISABLED, RESTRICTED, CONFLICT. May gain constants |
MutationQualification |
Immutable record: qualified, firstDomainQualified, secondDomainQualified, qualifyingAdaptations, reason. rejected(reason) builds a negative result |
MutationSelectionResult |
Immutable record: success, message, cooldownRemainingMillis. Factories success(message), rejected(message), cooldown(message, remainingMillis) |
MutationClaim |
DAMAGE, COOLDOWN_RESET, DEATH_PREVENTION, ITEM_PRESERVATION, UTILITY_ECHO, REWARD, MOVEMENT, POSTURE, WORLD_STATE, COOPERATIVE_LINK, RECOVERY |