BrewWikiGen, by Sean 'Balthazar' Wheeldon; automatic Github markdown style wiki page generation for Supreme Commander: Forged Alliance unit mods.
The script requires Lua 5.4 or greater to run. The uncompiled official download
for that is available here, however, I downloaded
pre-compiled binaries from here.
lua-5.4.2_Win64_bin.zip
to be specific.
For convenience, I execute from within Atom using the
LuaRunner plugin, downloadable from within
the Atom package manager. Ctrl-Shift-x opens the LuaRunner pane, point it at
lua54.exe, open and appropriately edit Run.lua
for your personal
environment, and run. Alternatively running a .bat
file containing:
"C:\Program Files (x86)\Lua\5.4.2\lua54.exe" C:\BrewWikiGen\Run.lua
pause
Edited as appropriate for your setup will also suffice for easy running. The pause
is optional, and is mostly so you can read the log output. You will still need to
edit Run.lua
.
The following are all the values read from Run.lua
. Some will need updating for
your setup:
-
OutputDirectory
should point to a clone of your mods wiki repository. If you don't have one, it at very least needs to be a valid folder. Use forward slashes/
, and include a trailing slash at the end. -
WikiGeneratorDirectory
should point to the folderMain.lua
is in, like:"C:/BrewWikiGen/"
. -
EnvironmentData
contains the following environmental values:-
location
optionally is a path for it to search for environmental blueprints. If it finds none it will use a shell link in there instead. Note this isn't recursive. -
GenerateWikiPages
, iftrue
, has the generator treat the environment as 'mod 0'. Otherwise it will just be used for added context for mod pages. -
RebuildBlueprints
, if notfalse
, and blueprint rebuild is enabled, it will rebuild environment blueprints. -
RunSanityChecks
, iftrue
, and blueprint sanity checks are enabled, it will give logs about potential errors in environment blueprints. -
Factions
, optionally, is a an array of custom factions formatted as sub-arrays containing the faction category then the faction name. For example:Factions = { {'NOMADS', 'Nomads'}, {'ARM', 'Arm'}, {'CORE', 'Core'}, },
The order is used for navigation sections and doesn't need to match the faction index in game. They are appended to the vanilla factions followed by 'Other', which is used for anything else and anything with multiple faction categories.
-
Lua
, optional, defines the location that contains the lua folder to try to loadlua/ui/help/unitdescription.lua
andlua/ui/help/tooltips.lua
from. They are expected to be valid Lua, and are sandboxed with no access to functions. If undefined, the generator comes with a default set of order tooltips. -
PreModBlueprints
, andPostModBlueprints
, optional arrays of functions to have run from the environments'lua/system/Blueprints.lua
file before and after mod hooklua/system/Blueprints.lua
WikiBlueprints
functions. IfPreModBlueprints
isn't populated it will try to run aWikiBlueprints
function from that file at that time instead. -
LOC
, optional, defines the location that contains the loc folder to try to loadloc/
Language/strings_db.lua
from. It is expected to be valid Lua and is sandboxed with no access to functions. -
name
,author
,version
, andicon
are for environment pseudo mod info. -
ExtraData
can point to an optional extra document of hand written content for specific sections of specific unit pages. It expects said document to be formatted as aUnitData
table, keyed with unit IDs (upper case, or however the bp files are named if they are anything other than entirely lower case), with table values containing keys that match the syntax[Section]Prefix
or[Section]Suffix
, where[Section]
matches the English names of sections, likeWeapons
orAdjacency
, orLeadSuffix
, with string values, or keyed withTrivia
with the value either being a string or an array of strings; a string included as-is, and an array being formatted as a bulleted list, or keyed withVideos
with an array of tables that match the format{YouTube = '[Video ID]', '[Display name]'}
, where[Video ID]
is the 11-ish character YouTube video ID, and[Display name]
is the link caption to display. You can also force a section to appear and/or overwrite the main contents of it with a[Section]
key, and either atrue
value to force it to appear, or a string value to force it to appear and overwrite the main body of the section. Prefix and suffix additions are still respected. Which is a very wordy way to say to look like this example:UnitData = { SSL0403 = { LeadSuffix = "Paragraph to appear after the generated lead paragraph.", AdjacencyPrefix = "Paragraph to appear before the Adjacency section.", Videos = { {YouTube = 'IInITjdtaPM', 'Time-lapse'}, }, Trivia = { 'This would appear as a bullet point in the trivia section.', 'As would this.', }, Balance = "This unit is mad OP because it's the only way I can get an er", }, }
If you don't have such a document, you can remove the
ExtraData
field or set it tofalse
. -
LoadExtraBlueprints
, optional, hash of extra blueprint types to actually load.Unit
andProjectile
are loaded by default, this allows loading ofBeam
,Mesh
,Prop
,Emitter
, andTrailEmitter
blueprints. -
base64
, optional, a table of flags for encoding image data as base 64. The only accepted flag is currentlyUnitIcons
, because after testing, GitHub wiki markdown strips base64src
fields of images, so it's not actually useful for its intended purpose of limiting how quickly unauthenticated users hit the rate and rest limits for GitHub API calls, so was never developed further.
-
-
WikiOptions
contains the following bool-ish options:-
Language
should be the two letter language code for which LOC files should be loaded. They are not ISO_639-1. Non-'US'
is only partially supported. -
GenerateHomePage
,GenerateSidebar
,GenerateModPages
,GenerateUnitPages
,GenerateProjectilesPage
andGenerateCategoryPages
;true
orfalse
: Generate those parts or not. -
IncludeStrategicIcon
;true
orfalse
: If true it will include the strategic icon in the infobox and automatically copy required icons into the output from the generator directory. The packaged icons are from the BrewLAN large icon mod. If you want something else, like the vanilla icons, that's on you. -
AbilityDescriptions
;true
orfalse
: If false it lists the abilities of the units verbatim in the abilities section. If true it will try to map them to tooltips in theabilityDesc
table in/Environment/Game.lua
. -
BalanceNote
appears at the bottom of Balance sections if they exist. It can be set to false or removed. The section will only appear on pages for blueprints that havebp.WikiBalance
be truthy. The auto generated content of balance requiresbp.WikiBalance.Affects
; expected to contain an array of blueprint sections affected by the script, and optionallybp.WikiBalance.ReferenceIDs
; expected to be an array containing 1 or 2 unit ID's, with it assuming the result is an average if both are defined.The section would be devoid of generated content if
BalanceNote
evaluates false andbp.WikiBalance
evaluates true, but has none of the expected content. This would allow you to fill it with your own content as detailed inExtraData
. -
ConstructionNote
appears at the top of Construction sections in unit pages. It can be set to false or removed. -
BuildListSaysModUnits
if true the build list refers to what can be built as "mod unit(s)" instead of "unit(s)". -
LocalRepuUnitPageBlueprintLink
andOnlineRepoUnitPageBlueprintLink
, if they exist, it create unit page links to the original.bp
files on the repo, using the the pair as a regex search and replace on the source location it found the reference.bp
files at.
-
-
CleanupOptions
(Depreciated) handles options for 'cleanup', which uses regex expressions to remove specific values from blueprint values. Contains the following bool options:-
CleanUnitBpFiles
;true
orfalse
: Enables or disables all.bp
file modifying scripts. Note it only applies to loaded.bp
files that would be given a wiki page. -
CleanUnitBpGeneral
,CleanUnitBpDisplay
,CleanUnitBpInterface
, andCleanUnitBpUseOOBTestZoom
;true
orfalse
: Removes obsolete vales. Specifically:- From
General
:Category
,Classification
,TechLevel
, andUnitWeight
. - From
Display
:PlaceholderMeshName
, andSpawnRandomRotation
. - The whole of
Interface
. - The value
UseOOBTestZoom
.
- From
-
CleanUnitBpThreat
;true
orfalse
: Updates the threat values based on an extensive formula.
-
-
RebuildBlueprintOptions
handles options for 'rebuild', which rebuilds blueprints by re-serializing loaded unit blueprints files. Beautifying them you might say. It contains the following bool options:-
RebuildBpFiles
; eithernil
/false
or a hash of blueprint types to rebuild, for example:{ Unit = true, Beam = false, Mesh = false, Prop = false, Emitter = false, Projectile = false, TrailEmitter = false, }
would have it rebuild just unit blueprints.
false
values can be removed/excluded. Said blueprint types need to be actually loaded. SeeLoadExtraBlueprints
. -
RemoveUnusedValues
, iftrue
, removes the unit blueprint values:bp.General.Category
bp.General.Classification
bp.General.TechLevel
bp.General.UnitWeight
bp.Display.PlaceholderMeshName
bp.Display.SpawnRandomRotation
bp.UseOOBTestZoom
bp.Interface
-
CleanupBuildOnLayerCaps
iftrue
does the following tobp.Physics.BuildOnLayerCaps
:- If the unit has a motion type that isn't
RULEUMT_None
, it removes the table; they don't use it, and you shouldn't trust anything it says. - If the unit has a motion type of
RULEUMT_None
and hasLAYER_Land
as the only true value it removes the table; that's the default. - Otherwise it removes any false values. This will leave an empty table if there are no true values. This is functionally different from having no table.
- If the unit has a motion type that isn't
-
CleanupGeneralBackgroundIcon
iftrue
and the unit has abp.General
table, changes thebp.General.Icon
value to correctly match what layers the unit can exist on, or to indicate what it can build if it's a factory structure. -
CleanupWreckageLayers
iftrue
, it will remove false values from wreckage layers. -
CleanupCommandCaps
iftrue
, it will remove false values from command caps, if there were no true values, it removes the table. -
CleanupIntelOverlayCategories
iftrue
, it will give theOVERLAYRADAR
,-SONAR
and-OMNI
categories to anything with ranges in those things greater than 0, and take it from anything else. It will do the same for theOVERLAYCOUNTERINTEL
category to anything that doesn't have a non-0 field radius for radar stealth, sonar stealth, or cloak, or a non-0 max jammer radius and more than 0 jammer blips. -
RemoveMilitaryOverlayCategories
iftrue
, it will remove theOVERLAY
categories forAIR
,NAVY
,DEFENSE
,DIRECTFIRE
, andINDIRECTFIRE
. They are not referenced inrangeoverlayparams.lua
. -
RemoveProductCategories
iftrue
, removes categories starting withPRODUCT
; in the core game they are only useful for easily restricting units added by patches and FA, which is a questionable use at best (and still attainable without the categories by checkingbp.Source
and the first letter of the ID), and in mods generally only indicates where the unit bp was originally copied from, or if updated to actually indicate the mod just occupies memory.Steps down off soap box
-
RecalculateThreat
iftrue
, recalculates the units threat, based onUtilities/Threat.lua
.
-
-
ModDirectories
should point to your local copies of the mod(s) you wish to load in the order you wish them to appear. It assumes, but doesn't require, multiple mods. It requires a validmod_info.lua
file directly in each. If a mod contains no units, then no page will be generated for it. -
BlueprintExclusions
is an array of regex matches for what to exclude from blueprint searches. They are matched against the whole path of any.bp
file. Lowercase. -
BlueprintIdExclusions
is an array of exact blueprint IDs to exclude. Case insensitive. -
FooterCategories
is a list of unit categories that the generator should create category pages for, and link to at the bottom of the relevant units. They appear on unit pages in the order written, so I tried to order them in a natural language order, or as close to as possible. If you have no units in a given category, no page will be generated. Add or remove as seems appropriate for your mods needs. -
Logging
contains several options for verbose logging of additional information which can be interesting or helpful in the case of any issues. -
Sanity
contains options for flagging anything in blueprints and their meshes that I consider anomalous or unnecessary. Exercise discretion when taking its advice.
If you have pre-existing pages for Home.md
, _Sidebar.md
or mods in your wiki
you can specify where and if the generator outputs in those pages specifically.
This can be done through specific xml tags read by the generator.
Behaviours on these pages are; if matching opening and closing tags exist (<tag>
and </tag>
) it will replace the contents with the new generation, if an empty
tag exists (<tag />
with the space) it will specifically not write that section,
otherwise it appends the content to the end surrounded by matching opening and
closing tags.
If you want it to not output on an entire class of page, that can be done via the
relevant WikiOptions
flags. Yes this makes <brewwikihome />
and <brewwikisidebar />
redundant, but it's the same code for all of them, so it's free.
Tags are:
<brewwikihome>
for the mod navigation forHome.md
.<brewwikisidebar>
for the mod drop downs for_Sidebar.md
.<brewwikimodinfobox>
for the infobox on mod pages.<brewwikileadtext>
for the lead text on mod pages.<brewwikimodunits>
for the unit navigation images on mod pages.
If you have important content in /hook/lua/system/Blueprints.lua
, you can have
the generator run it by adding a WikiBlueprints
function to that file called in
the same way as ModBlueprints
, except by the generator instead of the game.
This is easier to achieve if your Blueprints.lua
is formatted such that your
ModBlueprints
hook is populated with function calls rather than with code ran
directly within that hook. However, as outlined below, it needs to be valid Lua 5.4.
Since this generator runs mod files directly for data, any referenced .lua
file
must be valid for Lua 5.4. This notably means not using #
instead of --
,
not using !=
instead of ~=
, and probably several other things.
Code in required files that validates as Lua, but wouldn't run, ie: because it
runs a loop without defining an iterator like pairs
or ipairs
, or wouldn't
want to be ran for the wiki generation can be selectively ran by changing the
code to check _VERSION == "Lua 5.0.1"
first so that it only runs in-game.
I don't anticipate this being a huge issue, since these are generally data files and any code in them shouldn't need to be performed more than once.
Files this affects are as follows:
/mod_info.lua
/hook/lua/ui/help/tooltips.lua
/hook/lua/ui/help/unitdescription.lua
/hook/lua/system/blueprints.lua
/hook/loc/US/strings_db.lua
It will skip any mod that doesn't have a valid mod_info.lua
, and, while blueprint
files are sanitised, it will halt if it reaches a .bp
file that still doesn't
validate as Lua after sanitisation. For the other files it will continue with a
warning, but may have missing data on the pages.
Only blueprint files that end in _unit.bp
will be included, and only non-Merge
blueprints in those that contain defined Display
, Categories
, Defense
,
Physics
, and General
tables will be considered 'valid' and included.
The Github wiki image loading is case sensitive.
For mod icons if the mod in question has a mod_info.lua
icon
field it expects
a icons/mods/[mod-name].png
file and a images/mods/[mod-name].png
file, where
mod-name matches the mods written name in lowercase with spaces replaced with
hyphens and non-web-safe characters removed. It ignores the actual value of icon
,
because icon
has a high chance of pointing to something not-web-safe, and could
cause clashes. I recommend that the icon be 64x64px and the image be 512x512px.
It expects to find unit icons at icons/units/[ID]_icon.png
, it expects ID to
match the case of the original .bp
file, unless it's entirely lowercase, in
which case uppercase. If it doesn't find the icon it will use a default fall-back.
If you have files at images/units/[ID].jpg
in the output directory it will insert
them in the matching unit infoboxes, and if you have files at images/units/[ID]-n.jpg
where n
is a number from 1
onwards, it will create a gallery section for them
on said pages.
If you have mixed case unit icon files that don't match, this script can be used
to rename them to [uppercase ID]_icon.png
:
local folderdir = string.match(debug.getinfo(1, 'S').short_src, '.*\\')
print(folderdir)
local folder = io.popen(string.format('dir "%s" /b', folderdir))
for name in folder:lines() do
if string.lower(string.sub(name, -8)) == 'icon.png' then
local newname = string.upper(string.match(name, '(.+)_[iI][cC][oO][nN]'))..'_icon.png'
local file = io.open(folderdir..name, 'rb'):read('all')
io.open(folderdir..'test\\'..newname, 'wb'):write(file):close()
end
end
print("end")
To use it save it as .lua
in the images folder, create a /test/
subfolder and
run it. It creates renamed copies in the test folder.
If your unit blueprints themselves are mixed case then god help you.