Skip to content

Core Concepts & Architecture

Previous: Quick Start in 5 Minutes · Back to: Getting Started

Once you understand this page, every later chapter becomes simpler. Here we lay out QI's core terms and data flow. For a complete glossary, see the Glossary.


The Three-Layer Data Model of an Item

                ┌─────────────────────────────────────┐
   YAML design  │  Definition (template)               │  shared by all items of the same ID
                │  id / type / material / lore /        │  lives in the in-memory registry
                │  providers / variables / options …    │
                └─────────────────────────────────────┘
                                 +
                ┌─────────────────────────────────────┐
 state of this  │  Instance (instance data)            │  written in this ItemStack's NBT
   one item     │  values (rolled random values) /      │  unique per item
                │  overrides / locks / seed /           │
                │  soulboundOwner …                     │
                └─────────────────────────────────────┘
                                 +
                ┌─────────────────────────────────────┐
   patches      │  Layers                              │  socketing / inlaying / enhancing / affixes
   after        │  base → variables → section → affix → │  has an owner domain + priority
   creation     │  external (stacked by order)          │
                └─────────────────────────────────────┘
                                 ↓ Assembly Pipeline
                       final ItemStack (the one in the player's hand)
  • Definition (template): the immutable design blueprint compiled from YAML, managed by ID via QinhItemRegistry. See Item Definition.
  • Instance (instance data): the mutable state written inside a single ItemStack's NBT. The key is qinhitems:instance, and its content is a chunk of YAML. See Layers & Assembly.
  • Layers: patch packs (QinhLayerPatchPack) appended after creation, stacked by the order of QinhItemLayerType: base(10) → variables(20) → section(35) → affix(36) → external(100). Protected by the Write Domain Policy (WriteDomainPolicy) to prevent out-of-scope modifications.

Assembly Pipeline

The process of combining the three layers above into an ItemStack is called assembly, driven by QinhItemAssemblyService, which runs a series of Layer Contributors in order:

OrderContributorWhat it does
10BaseLayerContributorBuilds the base ItemStack from material and applies base meta
20VariablesLayerContributorResolves all variables (template + instance + layer), renders them into Lore / name, handles locks
35SectionLayerContributorInjects Sections — prefix/suffix pools, affix pools
36AffixLayerContributorInjects Affixes
100External (plugin-registered)Third-party extensions

Two entry points:

  • build(...)fresh generation: allocates a new seed, rolls random values, runs all contributors.
  • rebuild(item)rebuild: keeps the existing seed / instance and re-renders (used to refresh after config changes).

For the developer API, see Layers & Assembly.


Provider

A Provider is an "external-system payload" attached to an item. It is an opaque key→value chunk of data, where the key is the external system's ID (e.g. ap, perm_effects, legendinlay, magicgem).

yaml
providers:
  ap:                                  # AttributePlus attribute payload
    value: '{"attack_damage":18}'
  legendinlay:                         # Legendinlay gem-socket payload
    value: '{"set":"...","sockets":["normal"]}'

QI itself does not interpret provider content; it only stores and passes it along. Interpretation is left to the corresponding Bridge. See Provider & Bridge.


ICVM and Attribute Mapping

ICVM is QI's internal "standard vocabulary" for core combat attributes (Internal Canonical Vocabulary). It maps internal keys (such as attack_damage) to the name you actually gave them in AttributePlus (such as 物理伤害). The mapping is configured in the attribute-mapping section of config.yml.

internal key attack_damage  ──(attribute-mapping)──►  AP display name "物理伤害"

Why have this mapping layer? Because QI wants to keep configs portable, while every server may name its attributes differently in AP. See Attributes & Numbers.


Variable

A variable is an item-level dynamic value, used for random numbers, quality words, star levels, etc., and can be inserted into Lore / name via the {variableName} placeholder.

yaml
variables:
  damage_roll: "15 - 25"      # range → each item rolls a random value
  tier_name: "传说"           # static string
lore:
  - "伤害:{damage_roll}"      # replaced with the rolled value at render time

Variables go through a four-stage pipeline of "Roll → Resolve → Render → Conflict resolution". Multiple sources (template / instance / layer / runtime override) are merged by priority and remain traceable. See Variables.


Action = Trigger + Handler

An item's "skills / active effects" are implemented by the action system:

player does something (left click) → trigger atom left_click fires
                  → check conditions (must all pass to continue)
                  → check cooldown
                  → check consume (must have enough to continue)
                  → execute each handler in refs in order (passing payload)
                  → any handler returns HANDLED → deduct consume, record cooldown
  • Trigger: 100+ built-in atoms (click, sneak, move, combat, container, entity interaction…) + sequence combos. See Triggers.
  • Handler: 10 built-in (qi:message / qi:sound / qi:title / qi:command / qi:give_item…) + ecosystem-registered (qinhskills:cast / combat:swing). See Handlers.

⚠️ You cannot write logic branches in YAML (if/else/switch) — this is a deliberate design boundary. For complex logic, please develop an action handler.


Type & Capability Matrix

Each item type (weapon / armor / ring / gem…) declares which capabilities (TypeCapability) it supports:

SKILL · ATTRIBUTE · GEM_SOCKET
SET · RENDER · CONSUMABLE · PROJECTILE

For example, weapon supports SKILL/ATTRIBUTE/GEM_SOCKET/RENDER, while currency supports only RENDER. The capability matrix determines whether a given type can have gem sockets or attributes. See Item Types.


Configuration File Overview

FileManagesChapter
config.ymlMain config (combat / soulbound / write-domains / attribute-mapping / gem…)Configuration Files
item_types.ymlItem types and capabilitiesItem Types
item_tiers.ymlQuality / TierQuality & Display
enchant_limits.ymlEnchantment limitsEnchantment Limits
items/*.ymlItem definitionsItem Definition
fragments/*.ymlFragments (reusable snippets)Fragments & Templates
sections/*.ymlSections / affixes / poolsSections / Affixes
sets/*.ymlSetsSets
integrations/*.ymlGem-socket types, bridges, model catalogGem Sockets / Integrations

Data Flow Overview Diagram

🖼️ [Image placeholder] End-to-end data flow diagram: YAML → TemplateCompiler → Definition → AssemblyService (Layer Contributors) → ItemStack → equip → EquipmentScanner → AttributePlus · suggested assets/dataflow-overview.png

Once you understand all this, you can pick your role and dive deeper: