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 AttributePlus2. Adding Attributes to an Item: Two Ways
Way A: Write providers.ap directly (recommended for hand-writing)
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:
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
rateand 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:
demo_armor:
base_values:
base_attack_damage: 8
base_health: 40
base_defense: 12The three built-in base values:
| baseKey | Maps to ICVM | Display name | Editor icon |
|---|---|---|---|
base_attack_damage | attack_damage | Base Attack Damage | DIAMOND_SWORD |
base_health | health | Base Health | HEART_OF_THE_SEA |
base_defense | defense | Base Defense | SHIELD |
Base values and
providers.apare 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:
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 key | Default Chinese | ICVM key | Default Chinese |
|---|---|---|---|
attack_damage | Physical Damage | max_mana | Max Mana |
health | Health | mana_regen | Mana Regen |
defense | Defense | critical_rate | Crit Rate |
attack_speed | Attack Speed | dodge | Dodge |
magic_damage | Magic Damage | block_rate | Block Rate |
armor_penetration | Armor Penetration | lifesteal | Lifesteal |
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:*andqi: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:
| Backend | When used | Behavior |
|---|---|---|
AttributePlusBackend | AP detected (automatic) | Actually applies attributes; supports the AP 3.3.x source API and the legacy API |
NoopAttributeBackend | No AP | Always "succeeds" but does nothing |
In config.yml:
combat:
enabled: true # false = pure item-library mode (no attributes added)
attribute-backend: auto # auto | attributeplus | noopauto: uses AP if detected, otherwise noop.- The startup log shows
属性后端: attributeplus (已接入)ornoop.
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:
my_armor:
providers:
perm_effects:
value: '{"strength":1,"speed":0}' # effect name:amplifier level, 0 = level I- Applied by
PermEffectSyncafter 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
// 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)// All QI items the player has equipped
EquipmentScanner.equippedQinhStacks(player): List<ItemStack>
// Number of Set pieces
EquipmentScanner.countSetPieces(player, setId): IntFor a complete example of plugging in a custom attribute system, see Providers & Bridges and API Reference.
Next Step
- Variables: random numbers, dynamic text
- Set: set attributes / effects / skills
- Configuration File: full config for combat / attribute-mapping