Note: Pre-release version names are Unix timestamps.
Imports
nodeScripts
or Folders
nodes--resolve-ppj
to --resolve-project
Path
attribute support to <Match>
nodesImpact Note: This fix resolves an issue where an exception was raised when
Match
nodes withoutIn
attributes 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'