X2WOTCCommunityHighlander Documentation
Current status of the Documentation
The documentation is freshly introduced. It will take us a while to document all old features, but it is expected that new features all come with their documentation page.
How to read
The nav bar has a list of features. Click on a feature to view that feature's documentation. Every feature has:
- A GitHub tracking issue for discussion
- A documented way to use it, for example with an event tuple
- Code references that link to HL source code where the documentation is
Documentation for the documentation tool
We place our documentation inside of the source code next to where the main change
for the given feature is. make_docs.py
extracts this documentation and renders
MarkDown pages, which MkDocs
in turn renders to a web page.
You can run the documentation tool locally by installing Python (recommended version 3.7) and running
python .\.scripts\make_docs.py --indirsfile .\docs_directories.txt --outdir .\target\ --docsdir .\docs_src\ --dumpelt .\target\CHL_Event_Compiletest.uc
or the makeDocs
task in VS Code. This creates Markdown files for the documentation; rendering HTML documentation requires
MkDocs
:
pip install mkdocs
cd .\target\
mkdocs serve
Whenever the master
branch is committed to, the documentation is built and deployed here.
Additionally, upon opening or updating a Pull Request, the documentation is built and uploaded as a GitHub artifact.
This can be used to easily check the resulting documentation for a Pull Request.
Inline Documentation
The core concept of the documentation script is "features". Documentation always relates to a given feature, and usually the feature name is the name of the function or event that is added. Every feature needs exactly one definition, and may have additional documentation scattered throughout other source files.
Syntax
Every block of comments starting with triple comment characters (///
for UnrealScript files and ;;;
for Ini files)
and an optional whitespace character (space or tab) will be considered for documentation. Additionally,
the first line must begin with HL-Docs:
. All directly following lines that start with the same triple comment
will be included until the first line that does not have that triple comment. Standard MarkDown syntax is expected
and supported.
You may include source code fragments directly from the game code by placing a single HL-Include:
in an otherwise empty triple comment line; all following lines until the next triple comment line will
be included as source code in the documentation.
Feature definitions
A feature definition has the following syntax:
HL-Docs: feature:<string>; issue:<int>; tags:<string>,<string>...
Feature references
If you have defined a feature somewhere but want to reference other parts of the source code, or want to spread the documentation for a feature across different files, you may place a reference:
HL-Docs: ref:<string>
All text from the reference block will be appended to the main documentation as well.
Complete example
(Taken from ArmorEquipRollDLCPartChance)
XComGameState_Unit.uc
:
/// HL-Docs: feature:ArmorEquipRollDLCPartChance; issue:155; tags:customization,compatibility
/// When a unit equips new armor, the game rolls from all customization options, even the ones where
/// the slider for the `DLCName` is set to `0`. The HL change fixes this, but if your custom armor only
/// has customization options with a `DLCName` set, the game may discard that `DLCName` (default: in 85% of cases)
/// which results in soldiers without torsos. If you want to keep having `DLCName`-only armor
/// (for example to display mod icons in `UICustomize`), you must disable that behavior
/// by creating the following lines in `XComGame.ini`:
///
/// ```ini
/// [XComGame.CHHelpers]
/// +CosmeticDLCNamesUnaffectedByRoll=MyDLCName
/// ```
XComGame.ini
:
;;; HL-Docs: ref:ArmorEquipRollDLCPartChance
Tags
You may tag your documentation with a number of built-in and custom tags.
strategy
and tactical
are built-in tags used to categorize features in
the navigation bar. If a feature has one tag and not the other, it'll land
in that category. Otherwise, it'll land in the misc
category.
Custom tags can be used, but need a custom page that serves as an index page
for that tag; for example the compatibility
tag has a page docs_src/compatibility.md
that describes what the tag is supposed to mean and (automatically generated) links
to all features with that tag.
Bugfixes
The Bugfixes
feature is owned by the documentation script and as such has
no definition in the game code. It is used for generating a page listing all
bugfixes that can be explained by a single line. It uses a slightly modified
reference syntax:
HL-Docs: ref:Bugfixes; issue:<int>
<string>
for example:
/// HL-Docs: ref:Bugfixes; issue:70
/// `CharacterPoolManager:CreateCharacter` now honors ForceCountry
Events
The Highlander triggers some events to pass data to and receive data from mods. We document these events with a special syntax and automatically generate a copy-pasteable listener template that developers can simply copy into their mod and fill out. Additionally, that listener template is printed into a CHL source file so that it can be tested whether it successfully compiles.
The syntax for events is the following
```event
EventID: OverridePromotionUIClass,
EventData: [in enum[CHLPromotionScreenType] PromotionScreenType, inout class[class<UIArmory_Promotion>] PromotionUIClass],
EventSource: XComHQPresentationLayer (Pres),
NewGameState: none
```
- Entries need to be comma-separated
EventData
orEventSource
specify the type, and then optionally in parentheses the variable name.EventData
can be an XComLWTuple. In that case, use[ inout int a, ... ]
- Tuple parameters can be
in
,out
, orinout
- In the template,
in
parameters will be copied from the tuple into a local property out
parameters will be copied from a local property into the tupleinout
parameters do both
- In the template,
- All
XComLWTuple
types are supportedenum
s can be typed withenum[EnumType]
class
es can be typed withclass[class<Type>]
- If the type is not a primitive, it's assumed to be an object
NewGameState
needs to be one of three values:yes
,maybe
ornone
The above example generates the following code
static function EventListenerReturn OnOverridePromotionUIClass(Object EventData, Object EventSource, XComGameState GameState, Name EventID, Object CallbackObject)
{
local XComHQPresentationLayer Pres;
local XComLWTuple Tuple;
local CHLPromotionScreenType PromotionScreenType;
local class<UIArmory_Promotion> PromotionUIClass;
Pres = XComHQPresentationLayer(EventSource);
Tuple = XComLWTuple(EventData);
PromotionScreenType = CHLPromotionScreenType(Tuple.Data[0].i);
PromotionUIClass = class<UIArmory_Promotion>(Tuple.Data[1].o);
// Your code here
Tuple.Data[1].o = PromotionUIClass;
return ELR_NoInterrupt;
}
All generated listeners will be dumped into CHL_Event_Compiletest.uc
,
which will only be included in normal compilation in "compiletest" tasks. CI automatically determines the changes your PR would make to that
file and posts a comment containing the diff for reviewers (and you). This comment will be updated whenever the PR is updated.
If you provide a better example listener, you can simply opt out of the template with ```event,notemplate
.