Skip to content

Attributes & Numbers (AttributePlus Bridge)

Belongs to: Server Owner Guide · Related: Core Concepts · Configuration File

QI's attribute system is one of the things that sets it apart: QI does not compute combat numbers; it only attaches attributes to items and hands them off to AttributePlus (AP) to act on the player. This chapter explains the whole mechanism.


1. Three Key Terms

  • AP (AttributePlus): A third-party attribute plugin, QI's numbers backend. When an item is equipped, QI hands the attributes to AP, and AP actually adds them to the player's panel.
  • ICVM: QI's internal "standard vocabulary" for core attributes (such as attack_damage / health / defense).
  • Attribute mapping (attribute-mapping): Maps ICVM keys to the display names you actually use in AP.
item providers.ap = {"attack_damage":18}

        │ ICVM key attack_damage ──(config.yml attribute-mapping)──► AP display name "Physical Damage"

on equip → EquipmentScanner reads → formats into "Physical Damage: 18" → hands to AttributePlus

2. Adding Attributes to an Item: Two Ways

Attributes are a piece of JSON; the keys are AP display names or ICVM keys (depending on your mapping), and the values are numbers or ranges:

yaml
demo_guard_plate:
  type: armor
  material: iron_chestplate
  providers:
    ap:
      value: '{"defense":8,"health":40}'
  • A value can be a number (8) or a range ("10-20"; range values are not overwritten by base values).
  • Ratio types (containing rate and in 0–1) are shown as percentages.

Way B: Use base values base_values (common with the GUI)

Base values are three core attributes managed by QI; they are automatically compiled into the ap blob by AttributeCompiler:

yaml
demo_armor:
  base_values:
    base_attack_damage: 8
    base_health: 40
    base_defense: 12

The three built-in base values:

baseKeyMaps to ICVMDisplay nameEditor icon
base_attack_damageattack_damageBase Attack DamageDIAMOND_SWORD
base_healthhealthBase HealthHEART_OF_THE_SEA
base_defensedefenseBase DefenseSHIELD

Base values and providers.ap are merged: at compile time, base values are converted by ICVM→AP name and merged into the ap blob, but already-existing range values are not overwritten.


3. Configuring Attribute Mapping

In the attribute-mapping section of config.yml, map ICVM keys to the attribute display names in your AP:

yaml
attribute-mapping:
  # The core three (used for base values / growth calculation)
  attack_damage: "Physical Damage"
  health: "Health"
  defense: "Defense"
  # Optional (used by things like MMOItems imports)
  attack_speed: "Attack Speed"
  magic_damage: "Magic Damage"
  armor_penetration: "Armor Penetration"
  max_mana: "Max Mana"
  mana_regen: "Mana Regen"
  critical_rate: "Crit Rate"
  dodge: "Dodge"
  block_rate: "Block Rate"
  lifesteal: "Lifesteal"

Why map? Because every server names its attributes differently in AP. Mapping keeps your QI config portable: when you switch servers, you only change this one table, not every item.

On reload, QI queries AP for valid attribute names (ApAttributeReader); if you map to a name that does not exist in AP, the console will warn.


4. Built-in ICVM Standard Vocabulary

ICVM keyDefault ChineseICVM keyDefault Chinese
attack_damagePhysical Damagemax_manaMax Mana
healthHealthmana_regenMana Regen
defenseDefensecritical_rateCrit Rate
attack_speedAttack SpeeddodgeDodge
magic_damageMagic Damageblock_rateBlock Rate
armor_penetrationArmor PenetrationlifestealLifesteal

5. How Attributes Get Applied: Equipment Scanning

QI listens for equipment changes (wearing, swapping hands, clicking the inventory, picking up, armor changes, item breaking), and syncs attributes to the player via EquipmentWatcher + EquipmentScanner:

equipment change event → EquipmentWatcher compares whether the "equipment signature" changed
            → only refresh() if it changed
            → reads providers.ap of QI items slot by slot
            → parses into attribute lines → backend.apply(player, "qi:equip:mainhand", lines)
            → AttributePlus applies
  • Each of the six slots has an independent attribute source: qi:equip:mainhand / offhand / head / chest / legs / feet.
  • Set bonuses use a separate qi:set:<setId> source.
  • When the player quits, all qi:equip:* and qi:set:* sources are cleared.

Before applying attributes, QI checks whether the player meets the item's passive requirements; if not, that piece does not add its attributes.


6. What If AttributePlus Is Not Installed?

QI uses the AttributeBackend abstraction to shield the backend:

BackendWhen usedBehavior
AttributePlusBackendAP detected (automatic)Actually applies attributes; supports the AP 3.3.x source API and the legacy API
NoopAttributeBackendNo APAlways "succeeds" but does nothing

In config.yml:

yaml
combat:
  enabled: true              # false = pure item-library mode (no attributes added)
  attribute-backend: auto    # auto | attributeplus | noop
  • auto: uses AP if detected, otherwise noop.
  • The startup log shows 属性后端: attributeplus (已接入) or noop.

In pure item-library mode (combat.enabled: false or no AP): items are still crafted as usual, actions still trigger as usual, and Lore still displays attribute numbers — they just aren't actually added to the player's panel.


7. Permanent Potion Effects (perm_effects)

For potion effects that stay active while worn, use the perm_effects provider:

yaml
my_armor:
  providers:
    perm_effects:
      value: '{"strength":1,"speed":0}'   # effect name:amplifier level, 0 = level I
  • Applied by PermEffectSync after an equipment change, and refreshed/renewed every 6 seconds (120 ticks).
  • For the same effect across multiple pieces / a Set, the highest level is taken.
  • A Set can also provide perm effects; see Set.

7. (Supplement) Passive Requirements

Passive requirements are conditions that "don't grant attributes / effects unless met", such as level. Developers can use QinhItemsAPI.meetsPassiveRequirements(player, item) to check. Equipment scanning automatically skips pieces that aren't satisfied.


8. Developers: Reading Attributes

kotlin
// Whether combat is enabled
QinhCombatAPI.isEnabled(): Boolean
// Force-refresh a player's equipment attributes, returns the number of sources applied
QinhCombatAPI.refreshEquipmentAttributes(player): Int
// Current backend
QinhCombatAPI.activeAttributeBackend(): AttributeBackend
// Register a custom backend (to plug in another attribute system)
QinhCombatAPI.registerAttributeBackend(backend)
kotlin
// All QI items the player has equipped
EquipmentScanner.equippedQinhStacks(player): List<ItemStack>
// Number of Set pieces
EquipmentScanner.countSetPieces(player, setId): Int

For a complete example of plugging in a custom attribute system, see Providers & Bridges and API Reference.


Next Step