Note: Pre-release version names are Unix timestamps.
Imports nodeScripts or Folders nodes--resolve-ppj to --resolve-projectPath attribute support to <Match> nodesImpact Note: This fix resolves an issue where an exception was raised when
Matchnodes withoutInattributes were processed.
<Include> glob expressions<Include> glob expressions were always recursivePath attribute of <Include> nodes for packages<PreImportEvent> and <PostImportEvent> nodes were not initialized and parsedUseInBuild attribute of event nodes was never checkedPyro supports the use of <Match> nodes to include files in BSA/BA2 packages and ZIP files.
<Match In="SKSE">*.dll</Match>
<Match> nodes allow you to use wildcard file patterns, as well as file negation and directory exclusion patterns.
<Match In="." Exclude="docs" NoRecurse="false">*.md|*.txt|-README*</Match>
<Match> nodes are distinct from <Include> nodes, which use path matching and glob expressions.
<Include> nodes (e.g., <Include>Scripts</Include> would include all files in the Scripts folder recursively)<Include> nodes were not handled correctly<Include> nodes were not handled correctlyhttps://github.com/fireundubh/LibFire or https://github.com/fireundubh/LibFire.git)Folder paths--force-overwrite is passed)PreImportEvent and PostImportEvent elements have been added to the PyroProject XSD. These parent elements contain Command children.
How would these events be useful? In one use case, the user wants to automatically download the latest release of a mod from Nexus Mods, and the user wants to import script sources from that release. Pyro does not support the Nexus API; therefore, the user would need to call an external application to complete the first task, but without the pre-import event, to complete the second task, Pyro would have to become a child of that application's build cycle. With the pre-import event, however, the user can use Pyro to manage calls to that external application.
Description attribute can be used to clarify each event. This description will be printed in the build output.UseInBuild attribute can be used to toggle whether the event is used.| Event | Runs When |
|---|---|
| PRE | Immediately before import processing |
| POST | Immediately after import processing |
<PreImportEvent Description="Pre-Import Event Example" UseInBuild="true">
<Command>echo Hi! I'm a pre-import command!</Command>
</PreImportEvent>
<PostImportEvent Description="Post-Import Event Example" UseInBuild="true">
<Command>echo Hi! I'm a post-import command!</Command>
</PostImportEvent>
Pyro can read access tokens from a .secrets file placed in the program path. This feature allows you to:
The .secrets file is simply an INI file with this familiar format:
[github.com/fireundubh/LibFire]
access_token = your_personal_access_token
The access_token option supports user and system environment variables in Python syntax:
[github.com]
access_token = $ACCESS_TOKEN
Each section name is a host URL part that is matched case-insensitively against import URLs.
Host matches occur in sequential order. These host matching rules should be ordered top-down from narrowest to broadest.
If the --access-token argument is passed to Pyro, this argument will take priority over the .secrets file regardless of whether the file exists.
<Script> paths did not support current and parent directory symbolsA Path attribute was added to the Include element allowing you to specify where in the ZipFile the included file will be located.
<ZipFiles Output="@modpath">
<ZipFile Name="@modname" RootDir="@modpath" Compression="deflate">
<Include>@modpath\Auto Loot.esp</Include>
<Include>@modpath\Auto Loot - Main.ba2</Include>
<Include>@modpath\Non-Playable Flags Patch.esp</Include>
<Include Path="optional">@modpath\Auto Loot - UFO4P Components Patch.esp</Include>
</ZipFile>
</ZipFiles>
In the above example, the file Auto Loot - UFO4P Components Patch.esp will appear in a top-level folder named optional within the ZIP archive.
Note: You cannot rename files using this feature. The Path attribute is used only to create folders.
Folder parsing could fail due to unexpected inputPapyrusProject.Output path was not properly converted to absolute pathPackage.RootDir path was not properly converted to absolute pathThanks to Mr. Octopus (MrNeverLost) for reporting some of these issues!
An issue was fixed where scripts could not be downloaded from private GitHub remotes.
Thanks to Mr. Octopus (MrNeverLost) for reporting the issue!
--no-implicit-imports argument to disable implicit import discoveryFolder paths (e.g., <Folder>Scripts:Source:User</Folder>)An upstream issue with Nuitka 0.6.9.x causes Pyro to hang when executing workers. Each worker is actually crashing with an access violation. Recompiling Pyro through Nuitka 0.6.8.4 circumvents the issue. (Nuitka Issue 867)
Thanks to Exit_9B (Parapets) for reporting the issue.
--game-type argument value was not passed forward--zip-compression argument was not handled--game-type and --zip-compression argument values could be not lowercaseIn Skyrim Special Edition, an issue was recently discovered where packages containing textures can crash the game if they have the Embed File Names flag. To work around this issue, for SSE projects, Pyro will now detect whether packages will contain textures, and if so, pass an argument to BSArch to prevent this flag from being added to the package.
PreBuildEvent and PostBuildEvent elements have been added to the PyroProject XSD. These parent elements contain Command children.
Description attribute can be used to clarify each event. This description will be printed in the build output.UseInBuild attribute can be used to toggle whether the event is used.| Event | Runs When |
|---|---|
| PRE | Immediately prior to compilation |
| POST | Immediately after build success |
<PreBuildEvent Description="Pre-Build Event Example" UseInBuild="true">
<Command>echo Hi! I'm a pre-build command!</Command>
</PreBuildEvent>
<PostBuildEvent Description="Post-Build Event Example" UseInBuild="true">
<Command>echo Hi! I'm a post-build command!</Command>
</PostBuildEvent >
<Variable> element values<Variable> element valuesPyro now supports building multiple ZIP archives from a single PPJ. This is a breaking change.
ZipFile nodes must descend from the ZipFiles node, consistent with other top-level nodes.Output attribute was reassigned from the ZipFile node to its parent ZipFiles node.<ZipFiles Output="@MyProject">
<ZipFile Name="@ModName - Legendary Edition" RootDir="@MyProject" Compression="deflate">
<Include>@MyProject\@ModName - Legendary Edition.esp</Include>
<Include NoRecurse="true">*.bsa</Include>
</ZipFile>
<ZipFile Name="@ModName - Special Edition" RootDir="@MyProject" Compression="deflate">
<Include>@MyProject\@ModName - Special Edition.esp</Include>
<Include NoRecurse="true">*.bsa</Include>
</ZipFile>
</ZipFiles>
RootDir path resolution logged failures to wrong loggerpyro.exe MyProject.ppj)-i and --input-path will be phased out)Output attribute values could never be . even if desired by user. was not parsed as project path in Output attribute valuesWhen a PEX file is passed to Pyro, Pyro will dump the header to stdout.
Usage: pyro -i file.pex
When a PPJ file is passed to Pyro and the --resolve-ppj argument is provided, Pyro will resolve any variables and dump the contents to stdout.
Usage: pyro -i myproject.ppj --resolve-ppj
When a GitHub URL is used as an Import path, Pyro will download the respective files and use the download location as the import path.
<Import>https://github.com/fireundubh/skyui/tree/master/dist/Data/Scripts/Source</Import>
<Import>https://api.github.com/repos/fireundubh/skyui/contents/dist/Data/Scripts/Source?ref=master</Import>
To import from GitHub repositories, the following arguments have been added:
| Argument | Required | Type | Description | Default Value |
|---|---|---|---|---|
--access-token |
true (when using remotes) |
bool |
your personal access token (must have public_repo access scope) |
|
--force-overwrite |
false |
bool |
download remote files and overwrite existing files (default: skip download when remote folder exists) |
false |
--remote-temp-path |
false |
str |
relative or absolute path to temp folder for remote files (if relative, must be relative to project) |
{program_path}\remote |
RootDir path in Include nodesRootDir in Include nodesRootDir passed (e.g., @project\scripts)RootDir could be zippedVariable values were executed in only first-last orderVariable names to only alphanumeric charactersPyro now allows Variable values to reference themselves and other variables. For example:
<Variables>
<Variable Name="modname" Value="Auto Loot"/>
<Variable Name="modpath" Value="E:\ModOrganizer\Games\Fallout4\mods\@modname"/>
</Variables>
In addition, the following characters are reserved and cannot be used in Variable names or values:
! # $ % ^ & *
Whitespace, such as spaces and tabs, cannot be used in Variable names. The @ character is also reserved but can be used in Variable values.
Folder paths collected paths to all types of filesArchive attribute of the PapyrusProject node was removed.--anonymize and --bsarch arguments were removed.Pyro can now create multiple packages using the Packages node block.
<Packages Output="{relative or absolute path to output folder where BSA/BA2 packages will be written}">
<Package Name="{file name}" RootDir="{required - relative or absolute path to folder containing files or folders to include}">
<Include>{relative or absolute path to file or folder in RootDir, or simple glob pattern}</Include>
<Include NoRecurse="true">scripts</Include>
<Include NoRecurse="false">**/*.txt</Include>
</Package>
<Package Name="{file name}" RootDir="{required - relative or absolute path to folder containing includes}">
<Include NoRecurse="false">**/*.dds</Include>
</Package>
</Packages>
Note: Glob patterns are limited to "match everything" expressions, such as *.pex and **\*.psc.
| Node | Attribute | Default Value | Required |
|---|---|---|---|
Packages |
Output |
Path to pyro/dist folder |
No |
Package |
Name |
If the attribute is omitted: - the package file will be named after the project, - the extension will be appropriate to the game, and - subsequent package names will be suffixed with (1), (2), and so on. |
No |
Package |
RootDir |
Path to the project folder | Yes |
Include |
NoRecurse |
false | No |
Pyro can now create a ZIP archive containing specific files using the ZipFile node block.
<ZipFile
Name="{file name}"
RootDir="{required - relative or absolute path to folder containing files or folders to include}"
Output="{relative or absolute path to output folder where ZIP file will be written}"
Compression="{choices: 'store' or 'deflate' compression}">
<Include>{relative or absolute path to file or folder in RootDir, or simple glob pattern}</Include>
<Include>MyProject.esp</Include>
<Include NoRecurse="true">*.bsa</Include>
</ZipFile>
Note: Glob patterns are limited to "match everything" expressions, such as *.pex and **\*.psc.
| Node | Attribute | Default Value | Required |
|---|---|---|---|
ZipFile |
Name |
If the attribute is omitted, the ZIP file will be named after the project. | No |
ZipFile |
RootDir |
Path to the project folder | Yes |
ZipFile |
Output |
Path to pyro/dist folder |
No |
ZipFile |
Compression |
deflate | No |
Include |
NoRecurse |
false | No |
Pyro can substitute variables with defined values in PPJ paths and string attributes.
<Variables>
<Variable Name="namespace" Value="Master of Disguise"/>
<Variable Name="modname" Value="Master of Disguise - Special Edition"/>
<Variable Name="myproject" Value="E:\projects\skyrim\Master of Disguise - Special Edition"/>
</Variables>
Variables are prefixed with the @ symbol. The Name and Value attributes are required.
<ZipFile Name="@modname" RootDir="@myproject" Output="@myproject" Compression="deflate">
<Include>@myproject\@modname.esp</Include>
<Include NoRecurse="true">*.bsa</Include>
</ZipFile>
The Package and Zip boolean attributes have been added to allow enabling and disabling packaging and zipping.
<PapyrusProject
xmlns="PapyrusProject.xsd"
Flags="TESV_Papyrus_Flags.flg"
Output="@myproject\scripts"
Optimize="true" Anonymize="true" Package="true" Zip="true">
| Node | Attribute | Default Value | Required |
|---|---|---|---|
PapyrusProject |
Package |
false | No |
PapyrusProject |
Zip |
false | No |
Asm attribute due to case sensitivityInclude paths were not constrained to the RootDir directory--anonymize argument must be used or the Anonymize attribute must be set to true.--bsarch argument must be used or the CreateArchive attribute must be set to true.--no-anonymize and --no-bsarch arguments were removed.--registry-path argument.Game attribute value does not contain a valid game type.file:/ or file:// were not parsed correctly--registry-path was not handled correctlyxmlns attribute of the PapyrusProject node is set to a valid XML Schema path, Pyro will use that XSD file to validate the PPJ.NoRecurse attribute was removed from the Folders node. Each Folder node now has an independent NoRecurse attribute.Include nodes now support relative folder paths. Each Include node now has an independent NoRecurse attribute.<PapyrusProject xmlns="PapyrusProject.xsd">
Pyro will look for the file named PapyrusProject.xsd in the program path. If this attribute is omitted, Pyro will not validate the PPJ.
<Folders>
<Folder NoRecurse="true">Master of Disguise</Folder>
</Folders>
When NoRecurse is enabled, Pyro will not compile scripts in subfolders within the given folder. By default, NoRecurse is disabled.
<Includes Root="E:\projects\skyrim\Master of Disguise - Special Edition">
<Include NoRecurse="false">interface</Include>
</Includes>
When NoRecurse is disabled, Pyro will recursively add files in this folder and its subfolders to the output BSA/BA2. By default, NoRecurse is disabled.
<PapyrusProject
<!-- xmlns="PapyrusProject.xsd" -->
Game="sse"
Flags="<!-- TESV_Papyrus_Flags.flg -->"
Output="E:\projects\skyrim\Master of Disguise - Special Edition\scripts"
Archive="E:\projects\skyrim\Master of Disguise - Special Edition\Master of Disguise - Special Edition.bsa"
Optimize="true">
These are not valid XML comments because they appear within element tags and attribute values. XML-unsupported comments will cause validators and syntax highlighters to treat the PPJ as malformed. Pyro will strip all supported and unsupported comments virtually before parsing the PPJ to avoid parsing errors.
AutoLoot\Fragments\Terminals\TERM_AutoLoot_312_04001137.psc)--worker-limit argument to fine tune the maximum number of compiler processes spawned.xmlns attribute to be optionalCreateArchive and Anonymize default values were always usedRelease, Final, and Optimize values were not properly checked for 'true' or '1'