Core Impact Framework 2.0 - API Usage
β οΈ Retro-compatibility: Every JSON file written for CIF V1 will continue to work as-is with CIF 2.0. On load, the framework automatically detects and converts V1 BipedMapping and V1-style flat Filters to the new V2 format in memory. Existing mods such as Sanguine Symphony do not require any update.
The reverse is not true: JSON files written for V2 (new filter axes, new modifiers, new Biped Mapping groups, logical operators) are not understood by CIF V1. If your mod targets V2-only features, it will require CIF 2.0 or later as a hard dependency.
Table of Contents
- Introduction
- What's New in 2.0
- Prerequisites
- Location of JSON Files
- Impact Mapping
- Hit Mapping
- Filters
- Modifiers
- Biped Mapping
- Legacy Conversion (V1 β V2)
- C++ API (ModAPI.h)
- Testing in the Game
π Introduction
The Core Impact Framework (CIF) is an advanced and modular overhaul of Skyrim's impact system, designed to offer fine-grained customization of interactions between weapons, projectiles, and actors in the game. This framework allows for the adjustment, modification, and enrichment of impact effects in a wide variety of situations, making combat more immersive and dynamic. With a flexible system of filters and modifiers, it gives mod creators precise control over how impacts are managed based on context.
Version 2.0 is a complete overhaul of the filter and mapping-selection systems. It splits filtering into three clear axes (Victim, Attacker, HitContext), introduces logical operators (OR / AND / NOR) inside every filter, adds a Trie-based selection engine for much better performance at scale, and exposes a C++ hook system (pre-hit / post-hit / post-deferred-hit) so multiple mods can cooperate cleanly on the same impact event.
π What's New in 2.0
- Filter axes: Filters are now split between
Victim,Attacker, andHitContext, instead of one flat object. Attacker-side filtering (e.g. "only when a Nord attacks") did not exist in V1. - Logical operators: Every filter list can now be prefixed to change its logic: no prefix = OR,
&= AND,!= NOR. This applies uniformly, including toGlobalesandConditions, which used to be hardcoded to AND in V1. - New filters:
Sex,Worn,WornKeywords,Perks,Spells,MagicEffects,Skeletons(Victim/Attacker);MagicItems,Sources,BipedLimbs,BipedNodes,BipedKeys,PercentageMult,MaxLimbHealth(HitContext). - New modifiers:
RemoveSound,Stagger,Disarm,Eject,DamageMult,Bloodpool. - Deferred Hit Mapping: A new
Deferredflag onHitMappingentries lets you delay their resolution until after all mods have had a chance to react to the hit. - Biped Mapping V2: Bone groups now have their own name,
Priority, list ofBipedSlots, and anIsLimbEntryflag, instead of one array of nodes per slot number. - Trie-based runtime selection: Mappings are pre-indexed into a tree instead of being scanned one by one, keeping performance stable even with roughly three times more filter combinations than V1.
- C++ hook API:
RegisterPreHitCallback,RegisterPostHitCallback, andRegisterPostDeferredHitCallbacklet other SKSE plugins read and modify hit data in a controlled, priority-ordered sequence. See the C++ API section.
πΉ Available Filters
Filters allow for further refinement of impact management based on several criteria:
- Global factors: Global variables, custom conditions, race, actor, material type, keywords.
- Attacker: The same range of criteria as the victim, but evaluated against the actor performing the hit.
- Equipment: Armor type (heavy, light, clothing), specific skins, worn items and worn keywords.
- Biped slot: Specific body slots, nodes, limbs, or custom keys the equipment/hit affects.
- Weapons & projectiles: Generic types (sword, axe, bow, magicβ¦) or specific weapons, magic items and projectiles.
- Type of attack: Normal hit, power attack, bash, hand source (right/left/dual/shout). Sneak or critical strike.
- Blocking: Heavy shield, light shield, parry with weapon, or unblockable hit.
- Target state: Alive, dying, in killmove, dead.
- Thresholds: Maximum health, minimum required damage, maximum limb health, and probability multipliers.
Thanks to this approach, CIF allows for deep customization, providing a more realistic, varied, and impactful combat experience.
πΉ Advanced Modifiers
The CIF modifiers offer in-depth customization of impacts with a multitude of options. You can not only adjust visual, sound, and dynamic effects but also influence elements such as blood splatter, objects appearing after a hit, dismemberment, stagger, disarm, or damage multipliers.
Here are some examples of possible modifiers:
- Dynamic blood splatter effects, and dynamic blood pools.
- Modifications of impact data (visual and physical effects).
- Preservation, replacement, or removal of sounds and decals.
- Adding additional or custom sounds.
- Applying spells on impact.
- Placing objects after the impact.
- Enabling a bounce effect on impacts (especially for arrows).
- Staggering, disarming, or ejecting equipment on hit.
- Multiplying overall or limb-specific damage.
- Triggering automatic dismemberment.
These modifiers offer maximum flexibility to make impacts even more immersive and varied.
π Prerequisites
Before starting this tutorial, and to save time, make sure you have the following skills:
- Basic knowledge of Creation Kit: You should understand the basics of Creation Kit, including creating and modifying elements within this environment.
- Basic knowledge of JSON: An understanding of JSON files and their structure is essential for correctly creating and modifying the files needed for the Core Impact Framework (CIF).
- Understanding of impacts in Skyrim: While not essential, a general knowledge of impact systems in Skyrim will help you better understand how the CIF interacts with the game.
- For the C++ API only: Basic knowledge of CommonLibSSE/SKSE plugin development and C++ if you intend to hook into CIF from your own plugin.
If you're not comfortable with any of these skills or tools, it is recommended to acquire them before following this tutorial.
Great, now that we're all set up, let's dive into using the Core Impact Framework API.
π Location of JSON Files
The JSON files should be placed in Data/SKSE/CoreImpactFramework. The exact organization of these files doesn't matter as long as they remain in this directory.
You are free to organize them in subfolders as you see fit.
Similarly, there are no specific rules for naming the files: you are completely free to name them however you like.
In summary: as long as they are in this folder, everything is fine. The rest is up to you! β
π Impact Mapping - Structure and Functioning
{
"ImpactMapping": [
{
"Comment": "Replaces the head impact with sparks for heavy armor when struck by ranged weapons, but never against Draugr.",
"Priority": 10,
"Filters": {
"Victim": {
"Materials": ["Skyrim.esm:0x12F3F"],
"!Races": ["DraugrRace"]
},
"HitContext": {
"BipedSlots": [31],
"ArmorClasses": ["Heavy"],
"WeaponTypes": ["Ranged"],
"Blocked": ["No"]
}
},
"Modifiers": {
"ImpactData": "Skyrim.esm:0xF69C4"
}
}
]
}
ImpactMapping is an array in your JSON file that allows you to define rules for customizing impacts.
Each object in this array contains:
- Filters (conditions): to check if the rule should apply, now split into
Victim,Attacker, andHitContext. - Modifiers (actions): defines the effect applied if the conditions are met.
- Priority (optional): defines the evaluation order when multiple rules are valid.
This system allows you to adapt impacts based on a multitude of in-game situations.
β οΈ Important: ImpactMapping is strictly intended to replace visual and sound elements related to impacts. It is crucial to adhere to this rule, as once overrides are processed, only a single compiled ImpactMapping will be retained. Misusing this system to apply third-party, non-visual effects may interfere with other mods attempting to display impact visuals, leading to missing or incorrect effects.
For any functionality you wish to implement that does not directly affect visuals or sounds (such as using a spell to launch a script or apply damage, for example), please use Hit Mapping instead. HitMapping is more permissive and supports stacking, allowing multiple entries to be executed together without overwriting each other.
πΉ Priority - Rule Priority
The Priority field defines the order in which rules in the ImpactMapping are processed.
A rule with a higher priority will be applied first and can override those with lower priority. Negative values are allowed.
This system allows for the addition of exceptions and specific behaviors based on the importance of the rules.
πΉ Filters - Conditions to Validate
When an impact occurs, the Filters are evaluated. All three axes (Victim, Attacker, HitContext) that are present must validate for the Modifiers to be applied.
π Important Notes:
- An empty, or absent, filter axis is always valid.
- Filters are inclusive: all axes present, and all filter keys within an axis, must be satisfied.
- Inside a filter, the logical operator depends on the key's prefix. See Logical Operators below.
πΉ Modifiers - Actions to Perform
The Modifiers are the actions that will be executed once the Filters have been validated.
These actions allow you to replace or enhance the impact effects, adding sound effects, visual effects, or modifying the behavior of the impacts in the game.
The specific details of each Modifier element are covered in the Modifiers section below.
πΉ Other parameters
Override : When this parameter is enabled (true), the framework continues to process objects even if the filters are valid.
The Modifiers of the highest-priority objects will be kept and will override those of subsequent objects. This allows for the merging of multiple rule sets for the same impact event, where the highest-priority Modifiers take precedence.
For example, one set of rules might replace the sound effect, while another sets a new decal to be displayed, all within a single impact event. You can use this parameter as many times as necessary to create layered and varied effects.
OverrideMerge : This parameter, used in conjunction with Override, is less commonly used but allows merging array-type elements (such as ExtraImpactData) with those of lower-level objects.
When OverrideMerge is enabled, the array elements will be added to those already present in the subsequent objects, rather than completely replacing them. This allows you to enrich effects without removing existing data, offering more flexibility in customizing impacts.
π Hit Mapping - Structure and Functioning
{
"HitMapping": [
{
"Comment": "Plays a sound and a slight magical effect upon impact, and staggers the victim.",
"Priority": 10,
"Class": "MyCustomEffects",
"Deferred": true,
"Filters": {
"Victim": {
"Materials": ["Skyrim.esm:0x12F3F"]
},
"HitContext": {
"Blocked": ["No"]
}
},
"Modifiers": {
"ExtraImpactData": ["Skyrim.esm:0x7331F"],
"ExtraSound": ["Skyrim.esm:0x51939"],
"Stagger": 0.5
}
},
{
"Comment": "When a hit is made to the head, in addition to the previous sound effect, the magical effect is replaced by a new one, resolved once all mods have reacted to the hit.",
"Priority": 20,
"Class": "MyCustomEffects",
"Override": true,
"Deferred": true,
"Filters": {
"Victim": {
"Materials": ["Skyrim.esm:0x12F3F"]
},
"HitContext": {
"BipedLimbs": ["Head"],
"Blocked": ["No"]
}
},
"Modifiers": {
"ExtraImpactData": ["Skyrim.esm:0x105F36"]
}
}
]
}
HitMapping is an array in your JSON file that defines additional rules for handling impacts, similar in structure to ImpactMapping but intended for different use cases.
While ImpactMapping is strictly reserved for replacing visual and sound effects related to impacts, HitMapping is specifically designed for gameplay-related modifications that do not directly affect visuals or sounds. It supports stacking, allowing multiple entries to coexist and be executed together without overwriting each other.
The elements of HitMapping are:
- Priority: sets the evaluation order of rules.
- Class: π₯ Only for
HitMapping. Groups entries together for theOverride/OverrideMergesystem. - Override: Replaces or adds modifiers from lower-priority objects if they are not present, keeping other properties intact.
- OverrideMerge: A less commonly used parameter that works with
Overrideto merge array-type elements from lower-priority objects. - Deferred: Only for
HitMapping. See below. - Filters: to determine if the rule applies, split into
Victim,Attacker,HitContext. - Modifiers: defines the effects applied if the conditions are met.
πΉ Class - Grouping and Overriding Objects
The Class parameter enables the use of the override system across multiple objects sharing the same class name. When you define a Class for an entry, it allows all objects with the same class name to either override or merge their modifiers depending on the Override setting. This provides greater control and flexibility when you want to apply specific behaviors or effects to a group of similar objects without needing to manually manage each individual entry.
πΉ Deferred - Delayed Resolution
Setting "Deferred": true on a HitMapping entry tells the framework to resolve and apply that entry's modifiers only after all registered mods have had the opportunity to react to the hit through the Pre-Hit and Post-Hit hooks, instead of immediately.
This is useful when your rule needs to take into account data that other plugins might still be adjusting (for example, a damage value modified by another mod's Post-Hit callback). Deferred entries are resolved via the dedicated RegisterPostDeferredHitCallback hook on the C++ side.
Possible Values: Boolean (default: false)
πΉ Filters - Conditions to Validate
Filters in HitMapping are identical to those used in ImpactMapping.
Please refer to that section for a detailed explanation of how filters work.
πΉ Modifiers - Actions to Perform
β οΈ Only specific modifiers are available for HitMapping. Modifiers that directly alter the primary visual or audio effects of an impact are reserved for ImpactMapping and cannot be used globally through HitMapping.
The following modifiers are available for use in HitMapping to customize the impact effects:
- BloodSpray: Casts a gore spell toward the impact direction with physics adjustments.
- ExtraImpactData: Adds extra visual impact effects without sounds or decals.
- ExtraSound: Plays additional sound effects on impact.
- Spells: Instantly casts spells on the hit target.
- PlacedObjects: Places objects at the exact point of impact.
- Stagger: Applies a stagger magnitude to the victim.
- Disarm: Disarms the victim.
- Eject: Ejects the weapon/item involved in the hit.
- DamageMult / DamageLimbMult: Multiplies overall or limb-specific damage.
- Bloodpool: Spawns a decal-based blood pool.
π Filters
Each filter is a condition that must be met for the modifiers to be applied. It's not necessary to declare all filters, only the ones you wish to use should be defined.
π Before moving on to the filter list, here are a few clarifications on the use of FormID and EditorID in the JSON:
FormID: Any FormID must be formatted as follows:"Skyrim.esm:0x123456". This format is valid for all filters where a game element is required. If a FormID is incorrect or cannot be found, an error will be logged in theCoreImpactFramework.logfile.EditorID: This is the name of the element as it appears in the Creation Kit. Unlike FormID, the EditorID does not require the plugin name where the element is located. However, its use is limited to certain types of variables, notably Global Variables and Races. If you are unsure of an EditorID's compatibility for a given filter, it is recommended to use a FormID to avoid any issues.
πΉ Logical Operators (New in 2.0)
In V1, list-based filters always worked as an OR, with the sole exception of Globales and Conditions, which were always evaluated as an AND. In V2, every filter key can now use one of three prefixes to control this behavior explicitly:
| Prefix | Logic | Meaning |
|---|---|---|
[no prefix] |
OR | At least one element in the list must be valid. |
& |
AND | Every element in the list must be valid. |
! |
NOR | No element in the list may be valid (exclusion). |
For example, "Keywords", "&Keywords", and "!Keywords" can be combined in the same filter block: "must have at least one of these general keywords, must have all of these specific keywords, and must have none of these excluded keywords."
Not every key supports all three prefixes, for example, thresholds like Percentage or MaxHealth are single values and have no OR/AND/NOR variant. The tables below indicate, for each key, which prefixes are supported.
Victim / Attacker Filters
These filters are placed under "Filters": { "Victim": { ... } } and/or "Filters": { "Attacker": { ... } }. Both share the exact same set of keys, Victim evaluates the actor being hit, Attacker evaluates the actor delivering the hit (when known).
| Parameter | Prefixes | Description and Possible Values |
|---|---|---|
Races |
none, ! |
Description: Restricts to specific actor races. Possible Values: Example:
|
Keywords |
none, !, & |
Description: Matches keywords on the actor. Possible Values: Example (all humanoid races except the bestial ones):
|
Skins |
none, ! |
Description: Checks if the actor has one of the listed skin armors equipped. Possible Values: Example:
|
Materials |
none, ! |
Description: Checks the actor's race material type. In most cases, this is the Possible Values: Example:
|
FormID |
none, ! |
Description: Filters based on the FormID of the actor, either the placed reference or its base object. Possible Values: Example:
|
Sex |
none, ! |
Description: Filters based on the actor's biological sex. Possible Values: Example:
|
Skeletons |
none, ! |
Description: Filters based on the path of the actor's skeleton (case-insensitive), useful for custom races/creature mods that share a common skeleton file without sharing a race. Possible Values: Example:
β οΈ JSON requires backslashes to be escaped, so write |
Worn |
none, !, & |
Description: Checks whether the actor currently has one (or all, with Possible Values: Example:
|
WornKeywords |
none, !, & |
Description: Matches keywords carried by the actor's currently worn items, rather than the actor itself. Possible Values: Example:
|
Perks |
none, !, & |
Description: Checks whether the actor has one (or all) of the listed perks, independently of the perk's own conditions. Possible Values: Example:
|
Spells |
none, !, & |
Description: Checks whether the actor knows/has one (or all) of the listed spells. Possible Values: Example:
|
MagicEffects |
none, !, & |
Description: Checks whether the actor is currently affected by one (or all) of the listed active magic effects. Possible Values: Example:
|
π Note: Globales and Conditions (perk-based scripted conditions) are only available under HitContext, since they usually need access to the full hit context (Target/Subject) rather than a single actor. See below.
HitContext Filters
These filters are placed under "Filters": { "HitContext": { ... } }. They evaluate everything about the hit itself: weapon, projectile, armor struck, biped location, attack type, and thresholds.
| Parameter | Prefixes | Description and Possible Values |
|---|---|---|
Globales |
none, &, ! |
Description: Conditions based on global game variables. Each entry has three elements: the global variable, a comparison operator, and a value. Possible Values: Array of 3 elements:
Example:
β οΈ In V1, |
Conditions |
none, &, !=None |
Description: Array of perk FormIDs used purely for their scripted Conditions (entry points are ignored). Possible Values: Example:
β οΈ In V1, |
BipedSlots |
none, !, & |
Description: Filters based on the affected body slot(s). Renamed from β οΈ Requires a proper Biped Mapping for the targeted actor. Vanilla creatures are covered by the mod already. Possible Values: Example:
|
BipedLimbs |
none, ! |
Description: Filters based on the biped bone group's limb identifier, as declared with Possible Values: Example:
|
BipedNodes |
none, ! |
Description: Filters based on the exact bone node name that was hit. Possible Values: Example:
|
BipedKeys |
none, !, & |
Description: Filters based on the custom bone-group name (key) declared in the Biped Mapping's Possible Values: Example:
|
ArmorClasses |
none, ! |
Description: Restricts conditions to certain armor types. Possible Values: Example:
|
ArmorKeywords |
none, !, & |
Description: Matches keywords against the relevant armor piece. Possible Values: Example:
|
Armors |
none, ! |
Description: Checks if the armor piece struck matches any in the provided list. Possible Values: Example:
|
WeaponTypes |
none, ! |
Description: Filters by weapon type. Renamed from Possible Values: Example:
|
WeaponKeywords |
none, !, & |
Description: Matches keywords against the weapon involved in the hit. Possible Values: Example:
|
Weapons |
none, ! |
Description: Checks if the weapon used matches any in the provided list. Possible Values: Example:
|
MagicItems |
none, ! |
Description: Checks if the spell/scroll/enchantment responsible for the hit matches any in the list. Separated from Possible Values: Example:
|
Projectiles |
none, ! |
Description: Applies conditions based on the projectile used (arrows, bolts, magical missiles, etc.). Possible Values: Example:
|
MagicEffects |
none, ! |
Description: Checks the magic effect directly responsible for the hit (e.g. the specific effect inside a spell that dealt damage). Possible Values: Example:
|
Attacks |
none, ! |
Description: Restricts to specific attack types. Possible Values: Example:
|
Sources |
none, ! |
Description: Restricts to the origin of the hit (which "hand" or channel produced it). Possible Values: Example:
|
Blocked |
none, ! |
Description: Determines whether the attack was blocked, and how. Possible Values: Example:
|
States |
none, ! |
Description: Filters based on the victim's state. Possible Values: Example:
|
Critical |
none, ! |
Description: Filters based on whether the hit was a critical attack. Renamed from Possible Values: Example:
|
Sneak |
none, ! |
Description: Filters based on whether the hit was delivered while sneaking. Renamed from Possible Values: Example:
|
Percentage |
single value |
Description: Chance for the condition to be valid. A random number between 0 and 100 is rolled; if lower than this value, the filter validates. Possible Values: Example:
|
PercentageMult |
single value |
Description: A multiplier applied on top of Possible Values: Example:
|
MaxHealth |
single value |
Description: Percentage of the victim's maximum health. Valid as long as current health is below this value. Possible Values: Example:
|
MinDamage |
single value |
Description: Minimum percentage of health that must be removed by the attack for the filter to validate. Possible Values: Example:
|
MaxLimbHealth |
single value |
Description: Same idea as Possible Values: Example:
|
π Modifiers
Once the filters are validated, the following modifiers may be applied.
| Parameter | Description and Possible Values |
|---|---|
ImpactData |
Description: The primary impact effect applied upon hit, replacing the game's original effect. Possible Values: Example:
β οΈ This modifier is only available for |
BloodSpray |
Description: This spell is cast toward the direction of the blood spray and is used to generate visual gore effects upon impact. Each Magic Effect in the spell must have a projectile assigned, as each one triggers an individual blood spray. The first effect is launched at full velocity, while subsequent ones use reduced speed to simulate realistic blood physics. The framework automatically adjusts the velocity, so there's no need to modify the projectiles properties yourself. Possible Values: Example:
|
Bloodpool |
Description: Array of blood pool / ground decal effects spawned at the exact node corresponding to the impacted limb. Possible Values: Example:
β οΈ The Dynamic Bloodpool Framework is required. |
ExtraImpactData |
Description: An array of additional impact effects applied upon hit. Each effect in the array will be played individually, but no sound or decal will be applied. Accepts either a Possible Values: Example:
|
ExtraSound |
Description: An array of additional sounds played upon hit. Possible Values: Example:
|
PreserveOriginalSound |
Description: Whether to keep the original impact sound in addition to the overridden one. This is only relevant if Possible Values: Example:
β οΈ This modifier is only available for |
PreserveOriginalDecal |
Description: Whether to keep the original impact decal in addition to the overridden one. This is only relevant if Possible Values: Example:
β οΈ This modifier is only available for |
SoundOverride |
Description: Sound effect that overrides the default impact sound, taking precedence over Possible Values: Example:
β οΈ This modifier is only available for |
DecalOverride |
Description: Decal effect that overrides the default impact decal. Possible Values: Example:
β οΈ This modifier is only available for |
RemoveDecal |
Description: Whether to remove the impact decal entirely. This takes precedence over all other settings related to decals. Possible Values: Example:
β οΈ This modifier is only available for |
RemoveSound |
Description: Whether to remove the impact sound entirely. This takes precedence over all other settings related to sound. Possible Values: Example:
β οΈ This modifier is only available for |
RemoveBloodSplatter |
Description: Determines whether to force the game to disable default blood splatter generation on impact. π Note: This does not affect dynamic blood sprays. Possible Values: Example:
β οΈ This modifier is only available for |
ImpactBounce |
Description: Whether to allow physical projectiles, such as arrows, to bounce upon impact. Possible Values: Example:
β οΈ This modifier is only available for |
Stagger |
Description: Applies an additional stagger effect to the victim on hit. Possible Values: Notes:
Example:
|
Disarm |
Description: Whether the hit should disarm the victim. Possible Values: Note: If the victim is blocking, their equipped weapon or shield will be disarmed with priority. Example:
|
Eject |
Description: Whether the victim's equipped item associated with the impacted body part should be ejected. Possible Values: Notes:
Example:
|
DamageMult |
Description: Multiplier applied to the overall damage of the hit. Possible Values: Example:
β οΈ This modifier does not work when the |
Spells |
Description: Array of spells cast when the modifier is triggered. The spells will be applied immediately, with the target being the actor hit and the subject being the one responsible for the hit. Possible Values: Example:
|
PlacedObjects |
Description: Array of objects placed in the world upon hit. These can be any visible object in the world. Most often, you will want to use explosions. The object will be placed precisely at the impact point. Possible Values: Example:
|
π Biped Mapping (For new races/creature only)
This section explains how to define the nodes associated with biped slots. These definitions enable the use of certain filters and features (BipedSlots, BipedNodes, BipedLimbs, BipedKeys). In most cases, only the biped slots of NPCs capable of wearing armor will be used, but nothing prevents you from creating your own mapping for specific custom creatures.
In V2, each bone group is declared under its own name (the "key"), and carries its own Priority, list of BipedSlots, and an IsLimbEntry flag, instead of a single node array per raw slot number as in V1.
Example: The following configuration shows how to define the mapping for Draugr.
{
"Filters": {
"Skeletons": ["Actors\\Draugr\\Character Assets\\Skeleton.nif", "Actors\\Draugr\\Character Assets\\SkeletonS.nif", "Actors\\Draugr\\Character Assets\\SkeletonF.nif"]
},
"BipedBones": {
"Head": {
"BipedSlots": [30, 31, 41, 42, 43],
"Nodes": ["NPC Head [Head]", "NPC Neck [Neck]"],
"IsLimbEntry": true,
"Priority": 10
},
"Torso": {
"BipedSlots": [32],
"Nodes": ["NPC Spine [Spn0]", "NPC Spine1 [Spn1]", "NPC Spine2 [Spn2]", "NPC COM [COM ]"],
"IsLimbEntry": true,
"Priority": 10
},
"ArmLeftUpper": {
"BipedSlots": [33],
"Nodes": ["NPC L UpperArm [LUar]"],
"Priority": 20
},
"ArmLeftLower": {
"BipedSlots": [33],
"Nodes": ["NPC L Forearm [LLar]", "NPC L Hand [LHnd]"],
"Priority": 30
},
"ArmLeft": {
"BipedSlots": [33],
"Nodes": ["NPC L UpperArm [LUar]", "NPC L Forearm [LLar]", "NPC L Hand [LHnd]"],
"IsLimbEntry": true,
"Priority": 10
},
"ArmRightUpper": {
"BipedSlots": [33],
"Nodes": ["NPC R UpperArm [RUar]"],
"Priority": 20
},
"ArmRightLower": {
"BipedSlots": [33],
"Nodes": ["NPC R Forearm [RLar]", "NPC R Hand [RHnd]"],
"Priority": 30
},
"ArmRight": {
"BipedSlots": [33],
"Nodes": ["NPC R UpperArm [RUar]", "NPC R Forearm [RLar]", "NPC R Hand [RHnd]"],
"IsLimbEntry": true,
"Priority": 10
},
"LegLeftUpper": {
"BipedSlots": [37],
"Nodes": ["NPC L Thigh [LThg]"],
"Priority": 20
},
"LegLeftLower": {
"BipedSlots": [37],
"Nodes": ["NPC L Calf [LClf]", "NPC L Foot [LLft ]"],
"Priority": 30
},
"LegLeft": {
"BipedSlots": [37],
"Nodes": ["NPC L Thigh [LThg]", "NPC L Calf [LClf]", "NPC L Foot [LLft ]"],
"IsLimbEntry": true,
"Priority": 10
},
"LegRightUpper": {
"BipedSlots": [37],
"Nodes": ["NPC R Thigh [RThg]"],
"Priority": 20
},
"LegRightLower": {
"BipedSlots": [37],
"Nodes": ["NPC R Calf [RClf]", "NPC R Foot [Rft ]"],
"Priority": 30
},
"LegRight": {
"BipedSlots": [37],
"Nodes": ["NPC R Thigh [RThg]", "NPC R Calf [RClf]", "NPC R Foot [Rft ]"],
"IsLimbEntry": true,
"Priority": 10
}
}
}
The table below shows the properties related to Biped Mapping. The priority system works the same way as for Impact Mapping, and the filters work in the same way as Victim filters above.
Priority |
Description: The priority of the biped mapping entry itself. Higher values will be applied first. Negative values can also be used. Possible Values: Example:
|
Filters |
Description: Filters that define the characters this biped mapping will apply to. Uses the same keys and logical-operator prefixes ( Example:
|
BipedBones |
Description: An object whose keys are free-form group names (the "biped key", usable with the
Example:
|
π Legacy Conversion (V1 β V2)
At startup, CIF 2.0 automatically converts legacy V1 filters into the new V2 format in memory. Nothing is written back to disk, ensuring full compatibility with existing V1 JSON files.
Your existing V1 filters will be transparently converted to their equivalent V2 structure and used normally by the framework.
π C++ API (ModAPI.h)
π Download the header file: API.h
CIF 2.0 exposes a native C++ API for other SKSE plugins, distributed as a single header (ModAPI.h) to include in your project. It lets your plugin: read/write CIF's own INI settings, resolve an actor's Biped Mapping, build a RuntimeHitContext on demand, trigger a CIF-compatible blood spray, and, most importantly, hook into the hit pipeline itself.
πΉ Retrieving the API
Include ModAPI.h in your project and request the interface once CIF has finished initializing (typically on kPostLoadGame / kNewGame):
SKSE::GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message)
{
switch (message->type)
{
case MessagingInterface::kPostLoadGame:
case MessagingInterface::kNewGame:
{
if (auto* api = static_cast<CIF_API::Interface*>(CIF_API::GetAPI())) {
logger::info("Core Impact Framework API v{} registered successfully.", api->GetVersion().string("."));
} else {
logger::warn("Core Impact Framework API not found.");
}
}
break;
}
});
CIF_API::GetAPI() locates CoreImpactFramework.dll, requests the interface through its exported RequestPluginAPI function, and caches the pointer for subsequent calls. It returns nullptr if CIF isn't installed or hasn't loaded yet.
πΉ Interface Methods
| Method | Description |
|---|---|
GetVersion() |
Returns the running CIF version as a REL::Version. |
GetIniValue(key_section, defaultValue) |
Reads a value from CIF's own INI settings. Returns an IniValue (std::variant<bool, int, float, std::string>), or defaultValue if not found. |
SetIniValue(key_section, value) |
Overrides a CIF INI setting at runtime. Returns true on success. |
GetBipedBonesMap(actor, limbEntriesOnly) |
Resolves and returns the BipedBonesMap (unordered_map<string, BipedBonesEntry>) applicable to the given actor, i.e. the compiled result of the JSON Biped Mapping. Set limbEntriesOnly to true to only get groups declared with IsLimbEntry: true. |
GenerateContext(victim, attacker = nullptr) |
Builds and returns a full RuntimeHitContext for the given pair of actors right now, without requiring an actual hit event. Useful to preview what CIF would resolve for a given situation. |
GetBloodCollisionLayer() |
Returns the RE::BGSCollisionLayer* used by CIF's own dynamic blood spray projectiles, so your own projectiles can share it. |
CastBloodSpray(caster, spell, position, direction, power, spread) |
Manually triggers a CIF-compatible blood spray spell at a given world position/direction, with optional power and spread overrides. |
RegisterPreHitCallback(eventName, priority, callback) |
Registers a callback invoked before CIF evaluates its filters, with a mutable reference to the vanilla RE::HitData. See Hooks below. |
RegisterPostHitCallback(eventName, priority, callback) |
Registers a callback invoked right after CIF has resolved a hit (immediate HitMapping/ImpactMapping entries), with the resulting RuntimeHitContext. |
RegisterPostDeferredHitCallback(eventName, priority, callback) |
Same as above, but fired after all Deferred HitMapping entries have also been resolved. |
π Registering a callback with an eventName that is already in use replaces the previous registration under that name for that hook. Within a hook, callbacks run in descending priority order (higher first), the exact same convention used by the Priority field in the JSON mappings.
πΉ Hooks - Pre-Hit, Post-Hit, Post-Deferred-Hit
These three hooks are the backbone of cross-mod cooperation in CIF 2.0. Instead of every mod hooking the game's hit pipeline independently and risking conflicts, they register with CIF and get called in a single, priority-ordered sequence:
- Pre-Hit: fired first, with a mutable
RE::HitData&, before CIF's own filters run. This is the place to alter the raw hit before anything is evaluated. - CIF evaluates its
ImpactMapping/HitMapping(non-deferred entries) and applies the resulting modifiers. - Post-Hit: fired with the resulting
RuntimeHitContext(read-only, passed by value), reflecting the immediate resolution. - Any
DeferredHitMappingentries are resolved. - Post-Deferred-Hit: fired last, with the final
RuntimeHitContextonce every mod has had a chance to react.
using namespace CIF_API;
if (auto* api = static_cast<Interface*>(GetAPI())) {
api->RegisterPreHitCallback("MyMod_PreHit", 0, [](const std::string eventName, RE::HitData& hitData) {
// Inspect or tweak the raw hit before CIF's filters run.
});
api->RegisterPostHitCallback("MyMod_PostHit", 0, [](const std::string eventName, const Interface::RuntimeHitContext context) {
if (context.state == Interface::Filter::StateFilter::kDead) {
// React to a killing blow, read context.bipedEntry, context.damageCalc, etc.
}
});
api->RegisterPostDeferredHitCallback("MyMod_PostDeferredHit", 0, [](const std::string eventName, const Interface::RuntimeHitContext context) {
// Final, fully-resolved context - safe place for dismemberment/localized-damage mods to act.
});
}
πΉ RuntimeHitContext
This structure summarizes everything CIF knows about a hit at the point the hook fires. It mirrors the JSON filter axes: victim-side fields, attacker-side fields, hit-context fields, and the resulting modifiers.
| Group | Fields |
|---|---|
| Victim | victimFormID, victimBaseFormID, victimRaceFormID, victimMaterialFormID, victimSkinFormID, victimWornFormIDs, victimWornKeywordsFormIDs, victimKeywordsFormIDs, victimPerksFormIDs, victimSpellsFormIDs, victimMagicEffectsFormIDs, victimSex |
| Attacker | attackerFormID, attackerBaseFormID, attackerRaceFormID, attackerMaterialFormID, attackerSkinFormID, attackerWornFormIDs, attackerWornKeywordsFormIDs, attackerKeywordsFormIDs, attackerPerksFormIDs, attackerSpellsFormIDs, attackerMagicEffectsFormIDs, attackerSex |
| HitContext | weaponFormID, weaponKeywordsFormIDs, magicItemFormID, projectileFormID, magicEffectFormID, armorFormID, armorKeywordsFormIDs, weaponType, armorClass, blocked, state, attack, source, criticalAttack, sneakAttack, percentHealth, percentDamage, limbHealth, bipedEntry, hitPosition, hitDirection |
| Modifiers | damageMult, damageCalc, damageLimbMult |
bipedEntry is a BipedEntry structure (bipedNode, bipedLimb, bipedKeys, bipedSlots) describing exactly which node/limb/group was struck, the runtime equivalent of the BipedNodes / BipedLimbs / BipedKeys / BipedSlots filters.
All the enums used by these fields (Filter::WeaponType, Filter::ArmorClassType, Filter::BlockedFilter, Filter::StateFilter, Filter::AttackFilter, Filter::SourceFilter, Filter::CriticalAttackFilter, Filter::SneakAttackFilter, Filter::ActorSex) live under CIF_API::Interface_V1::Filter and map 1:1 to the possible values documented in the Filters section above.
π Testing in the Game
After configuring your JSON files, it is crucial to test your changes in the game to ensure they work as intended. If you encounter a crash when launching the game, it likely means that the structure of one of your JSON files is malformed (possibly an extra comma). Feel free to use tools like JSON Formatter to validate your JSON files or find potential errors.
Once the game is running, be sure to check the CoreImpactFramework.log file (located in Documents\My Games\Skyrim Special Edition\SKSE) for any errors or issues with your JSON files, including the legacy-conversion log lines mentioned in the Legacy Conversion section. Regularly check this file during your testing to identify and quickly correct errors. This will help you refine your configuration and ensure smooth integration into the game.