Fallout 4

Documentation: Complex Sorter Plugins

The Complex Sorter's plug-in system allows the processing system to be further customized.

A plugin is placed on top of the Complex Sorter's processing rule system, adding another layer of capabilities.
The plugins are highly customizable with definable user settings, trigger script rules, custom processing rules, requirements and even limited scripting support.


Basics

Each plugin is defined in a simple ini text file, e.g. "Plugins\Add Component Tags.ini".

The possible sections of the ini file are (See further down for a detailed description):

  • [Plugin] - Defines the basic properties of your plugin, such as name, author and so on.
  • [Settings] - Defines the user settings available via the main interface.
  • [Rules.{record type}(.prefilter)(.{priority})] - Injects processing rules for record types. Optional as pre-filter and optional priority.
  • [Rules.{record type}.afterMatch] - Adds processing rules which are processed AFTER normal processing found a TagIdent.
  • [Mod.{plugin file}.Rules.{record type}(.prefilter)] - Injects performant processing rules for a specific mod file. Optional as pre-filter.
  • [INNR.{dynamic naming ruleset name}(.extend or .replace)] - Extends or replace a dynamic naming ruleset
  • [INNRScript.{INNR EditorId}] - Executes INNR-Script on the given INNR
  • [TagSet.{tagset name}] - Add tags in the specified tagset.
  • [PluginScript.{script name}] - The scripts of your plugin

Beside [Plugin] all sections are optional.

Section [Plugin]

Defines the basic properties of your plugin.

Properties

id
The id of your plugin. This must be unique and contain no whitespaces (best
is to use only standard characters, underlines and numbers).
Example: id = cpp_addcomptags

name
The name of your plugin.
Example: name = Add Component Tags

desc
A description of your plugin, which will displayed to the user in  the main interface.
Example: desc = Adds component tags to scrappable items, which can be displayed by HUD mods while looting

author (optional)
The author's name.
Example: author = m8r98a4f2

type
The type of plugin. The standard is "pluginRecordModifier". Further possibilities: special, addon.
Example: type = pluginRecordModifier

cachable (optional)
Defines if the plugin output is cachable in the PluginScriptCache. The plugin cache automatically renews if the record or the user settings changed, so you only need to use "false" here, if you use external records.
Example: cachable = true

activeDefault (optional)
Defines if the plugin should be active by default for new users.
Example: activeDefault = true

visibleDefault (optional)
Defines the standard visibility of this plugin, so if it will be visible in the main GUI for easy activation.
Example: visibleDefault = true

task (optional)
You can give your plugin a separate processing process. If you don't specify "ItemSorterTags" here your processing will be completely separate from the item sorting. Also it can be executed on its own, so without adding item tags.
Format: [Task identifier]:[Task name]
Example: task = ItemSorterTags:Item sorter tags

defaultRulesPriority (optional)
Define the standard processing ruleset priority for all your plugins [Rules.*] sections (if not explicitly specified there).
Possible values: main, beforeMain, beforeAll, afterMatch
Example: defaultRulesPriority = beforeMain

useTagSet (optional)
Define the default TagSet to use when this plugin is activated. You will most likely only need this if you writing a own CS plugin for a new item sorter.
Example: useTagSet = FallUI

requiredFiles (optional)
Defines necessary fo4 plugin files for this CS plugin. The CS plugin won't be accessible if this condition is not matched.
Compared to requiredDataFiles this must be active real plugins in the load order.
You can define multiple disjuncture requirements separated by ",". Entries where all parts must exists are separated by "+". Prefix "NOT:" requires the plugin to be not existing.
Example: requiredFiles = CraftingFramework.esp,ECO.esp

requiredDataFiles (optional)
Defines necessary FO4 data files for this CS plugin (So files must exists in the Fallout 4 "Data\" directory). The CS plugin won't be accessible if this condition is not matched.
You can define multiple disjuncture requirements separated by ",". Entries where all parts must exists are separated by "+". Prefix "NOT:" requires the file to be not active.
Example: requiredFiles = CraftingFramework.esp,ECO.esp

requiredRecordTypes (optional)
Defines necessary active record types for this plugin. The plugin will be grayed out if not matched.
You can define multiple disjuncture requirements separated by ",". Entries where all parts must exists are separated by "+". Prefix "NOT:" requires the record type to be not selected.
Example: requiredRecordTypes = ARMO+INNR,ALCH,AMMO,BOOK,MISC,KEYM,NOTE

requiredPlugins (optional)
Defines necessary other CS plugins for this CS plugin. The plugin will be grayed out if the other plugins aren't active. Requires the plugin id as parameter.
You can specify multiple CS plugins separated by comma. Entries where all parts must exists are separated by "+". Prefix "NOT:" requires the CS plugin to be not active.
Example: requiredPlugins = cpp_itemSorterTags+NOT:cpp_fisItemSorter


Section [Settings]

Defines the user plugin settings of your plugin.
This will be available for the user trough the main graphical interface.
You can simply access the plugin settings via $settingName in the processing rules and in the script.

You can define unlimited number of entries with two basic types in here: Formtext elements and setting definitions.

Simple form text
Will be displayed to the user in the graphical interface
Example:
desc1 = form:text:Configuration of component tags. The default setting work for all common HUD mods.
Note: Because the base file is a ini file, the part before the "=" must be
unique. So just adding a random number to the ignored first part, e.g:
desc1, desc2 etc.

Plugin user setting
Defines the user plugin setting available.
The syntax is really simple, just define the new setting via:
yourPluginSettingName = setting

Of course your setting need a type, a name, a default value and maybe a
mouseover hint. You define the additional setting properties via:
yourPluginSettingName:type = bool
yourPluginSettingName:name = Name of my bool plugin setting
yourPluginSettingName:default = true
yourPluginSettingName:hint = A hint, that is displayed when the mouse is over the setting

Because I like short notation, there is a short notation available for the
required properties, so you don't need to specify them one by one:
yourPluginSettingName = setting:bool:true:Name of my bool plugin setting

Note: If your default value, name or hint contains a ":" you have to use the one by one notation.

Available plugin user setting types:
  • bool - A simple true or false
  • int - Full number
  • float - Floating point number
  • string - A text

Section [Rules.{record type}(.prefilter)(.{priority})]

Adds processing rules to the processing system.
Apart from the section name, the structure is exactly the same as the normal processing rules (see Processing Rules).

The optional ".prefilter" will add the rules to the prefilter rules instead of the normal rules.

The optional .{priority} allows you to specify the priority level at which your rules should be inserted. The default priority is "main".
Possible Priorities are:
  • beforeAll - Highest priority, can overwrite specific mod rules
  • beforeMain - Higher priority, take priority over other plugin rules
  • main - Default priority
  • afterMatch - Special: Called when a TagIdent is found.

Example
[Rules.ARMO]
EDID equals MyNewArmorEditorId = Armor

[Rules.ALCH.prefilter.beforeAll]
EDID equals BrokenItem = IGNORE

[Rules.WEAP.beforeMain]
EDID equals MyWeapon = MyPistol

Tip: Use mod-specific [Mod.{plugin file}.Rules...] if possible, as it will work much faster.

Section [Rules.{record type}.afterMatch]

You can add normal processing rules here, but most likely you will want to trigger your PluginScript with this.
The syntax is exactly the same as the normal processing rules. Type the desired target record type instead of the "*" in the section name. Of course, you can have multiple sections for multiple record types.

The processing rules will be executed after a TagIdent is found (that is where the name comes from ;) ).

You have additional possibilities in this section over the "normal" processing rules, as you can use your user settings as $userSetting.

Explanation by example

Lets explain the basics trough an example:
[Rules.ALCH.afterMatch]
"DATA - Weight" greaterThan 0, $bAlch equals true = PluginScript:ModDataWeight1

The section name defines the rules to be processed for all ALCH records (after the standard processing rules found a TagIdent).
The first condition checks if the record field "DATA - Weight" is greater than 0. If thats true, the second condition checks if the user activated the plugin setting $bAlch. If thats also true, the rule triggers the PluginScript "ModDataWeight1".

Of course you can add multiple rules here. Also standard rules are allowed, which sets a new TagIdent or perform a "standard processing rule special action".
A further example:
[Rules.WEAP.afterMatch]
; Remove existing trailing {{{...}}}
$bRemoveExistingTags equals true, FULL contains "{{{" = SPECIAL:PregReplace:FULL:"(\s*\{\{\{[^{}]*\}\}\})":""
; Changes all TagIdent's "Unarmed" to "Melee" ... maybe you just don't
like hand icon tags .... (This is just an example, normally you would
change the final tag simply in tags.ini)
SPECIAL:TagIdent equals Unarmed = Melee


Section [Mod.{plugin file}.Rules.{record type}(.prefilter)]

This section allows you to add mod-specific processing rules. It works just like an ini file in the Rules (Mods)\ folder. These processing rules will be executed on every record that comes in contact with {plugin file}.
Using this section results in a much better performance compared to a normal [Rules...] section, which runs on every record.

The syntax is exactly the same as in the [Rules...] section.
Tip: When your plugin is just for a specific mod, you can easily optimize the speed of your plugin by pre-fixing the section with the plugin file.

Example
; Rules, that will be executed on all records in Fallout4.esm (Note: you can omit the extension ".esm" in the section name)
[Mod.Fallout4.Rules.ALCH.prefilter]
EDID equals HC_Antibiotics = KEEP

[Mod.Fallout4.Rules.ALCH]
EDID equals HC_Antibiotics = MedPills

; Rules, that will be executed on all records in DLCRobot.esm
[Mod.DLCRobot.Rules.ALCH]
EDID equals DLC01RepairKit = Device

; Rules, that will be executed on all records in Unofficial Fallout 4 Patch.esp
[Mod.Unofficial Fallout 4 Patch.Rules.ARMO.prefilter]
EDID equals Armor_MiningHelmet = IGNORE


Section [PluginScript.*]

Allows you to execute scripted actions on records.
Define as many scripts as you like. Replace "*" in the section name with your script name.

Special notation for script content

Because it is a ini file, the part before "=" must be unique. That doesn't really make sense for scripts, but as it is a ini file, you have to satisfy the ini syntax. This could simply fulfilled by adding a number prefix to the line, which is then completely ignored by Complex Sorter :-).

Example:
10 = first line of code
20 = second line of code
20 = NOTE: This line wont be processed, because it uses a non unique number!

Variables

Variables basic syntax is "$varname" for standard types and "@varname" for variables with record reference in it.
The user plugin settings are available as $settingName. (You should not change them, as for performance they are only set at begin)

You can define as many additional variables as you like. Just set them with the "set" command or assign record field references with the "assign" command. Then you can just use them with "$varname" or "@varname".

Record fields

You can access the current record fields with record."Record field name or path" .
Access to referenced records is done via @recordReferenceVar."Referenced record field name or path".
You can use that in any command which accepts values as parameter.  Also you can use the syntax to assign record sub fields to @variables.
See set command for examples on usage.

Commands

set - The most basic command. Set a variable or a record field to a value or the content of a variable.
Syntax: set [target $variable] = [source $variable or value] (optional: merging operator) (optional additional $variable or value)
Allows optional combination of two values with a merging operator. Possible merger are: (numerical:) "+", "-", "/", "*" (string concatenation:) "." (dot)
Examples:
10 = set $newName = record."FULL - Name" . $sStartTag
20 = set record."FULL - Name" = "My new item name"
30 = set record."DATA - Data\Weight" = 0
40 = set @comp."Field in another record" = $newValueForFieldInAnotherRecor


assign - Assign's the reference to a record or a record field to a script variable.
Syntax: assign [target @variable] = [source record or @variable]."[Record field name or path]"
Examples:
10 = assign @comps = record."Components"
20 = assign @comp = @comps."Component"


if - Allows you to perform a conditional action. Only executes the last part if the condition is true.
Syntax: if [source $variable] [compare operator] [compare to $variable or value] then "[command statement]"
Possible compare operations for numbers: >, >=, <, <=, =, <>  and for strings: eq, neq, contains, ncontains
The last parameter must be "quoted". You can escape quotes in the "quotes" with ""double-quotes"", e.g.: "set $name=""new name"" . $tags"
Example:
10 = if $index > 0 then "set $newName = $newName . $sSeparator"

foreach - Executes the following script part till "endforeach" for every item in the specified source $reference. The item will be stored in @item (for record references) or $item (for value variables)
Syntax: foreach [source @reference] as (optional $index variable) (optional =>) [@item]
Example:
30 = foreach record."CVPA" as $index => @c
40 =  assign @c = linksto:@c."Component"
50 =  if $index > 0 then "set $newName = $newName . $sSeparator"
60 =  set $newName = $newName . @c."FULL - Name"
70 = endforeach


modset - Perform an enhanced set command with a modification function.
Syntax: modset [target $variable] = [Modificator] (dynamic parameters)
Currently there is only one modificator available: "PregReplace". The first parameter after "PregReplace" is the source $variable. The second parameter is a RegExp. The third parameter is the replacement text. The example code takes the content of $bodySlotFlag, looks for the matching RegExp, and replace the matched text by nothing. Then the result will be stored in $bodySlotFlagReplaced.
Example:
50 = modset $bodySlotFlagReplaced = PregReplace $bodySlotFlag "((?<=\d)\D.*)" ""


end- Ends the script.
Syntax: end
Example:
10 = if count:record."CVPA" = 0 then "end"



Special Prefixes

You can add special prefixes to variables or record fields to get special values or referenced records.
The available prefixes:

count:
Count the (child) elements of a record field.
Example:
10 = set $bodySlotCount = count:record."BOD2 - Biped Body Template\First Person Flags"

linksto:
Get the referenced record, which id is stored in the record field.
Example:
10 = assign @componentRecord = linksto:@componentLink."Component"
20 = assign @INNR_record = linksto:record."INRD"


flags:
Usable only in foreach command. Will iterate over all setted flags of a flag record field.
Example:
10 = foreach flags:record."BOD2 - Biped Body Template\First Person Flags" as $index => $bodySlotFlag



Section [INNR.{dynamic naming rules name}(.extend or .replace)]

Allows you to add or replace dynamic naming rules when your plugin is active.
Beside the section name this sections have the same syntax as rules-innr.ini.

Example:
[INNR.dn_CommonMelee.extend]
ma_Baton=BaseballBat


Section [INNRScript.{INNR EditorId}]

Executes a INNR-Script on the named INNR, which allows you to change most things in the INNR record - up to reordering all rules or adding whole new rulesets!

Exact documentation will be added soon. Until then, here's a short overview of calls in INNRScript:
Base calls
check [checksums]
neworder [neworder]
addRuleset
resetToMaster
resetToOverride [plugin file]

Selector calls - will mark rulesets and optional name for editing
find [fieldName] [equals|contains] [value]
ruleset [#index]
name [#index]

Modifications calls - for selected ruleset (and optional specific name)
addName
addDynamicNamesRuleset
set [fieldName] [value]
replace [fieldName] [from] [to]
pregReplace [fieldName] [from] [to]
deleteName
deleteRuleset
addKeyword [keyword]
removeKeyword
moveNameTo [#index]
moveRulesetTo [#index]


Section [TagSet.{tagset name}]

Just like a custom tags.ini, but direct in your plugin. You can add new tags or replace existing tags, like you desire.

Example:
[TagSet.FIS2]
Melee=[Melee]
BaseballBat=[BaseballBat]
; Tag for my new weapon!
MyNewTagIdent=[ImbaWeapon]

[TagSet.Fallbacks]
; Add a fallback for my new tag.
; CS will use the TagIdent "Melee", if "MyNewTagIdent" isn't defined in the users choosen tag set
MyNewTagIdent=Melee

Notes: The legacy TagSet "FallUI" is a synonym for "FIS1" and "FIS" is a synonym for "FIS2". Use the newer FIS1 and FIS2 to prevent confusion.

Article information

Added on

Edited on

Written by

m8r98a4f2

0 comments