A set of MSBuild tasks for Beat Saber mods. Created for the templates in Beat Saber Modding Tools.
BSMT.Tasks now automatically includes a set of build targets for your project (your project doesn't need its own Directory.Build.targets
file). This functionality can be disabled by setting ImportBSMTTargets
to false
in your project (<ImportBSMTTargets>False</ImportBSMTTargets>
in your csproj file).
Properties and ItemGroups can be set to alter the behavior of the default targets.
- Properties
ImportBSMTTargets
: Set to false to disable the automatically included targets if you want to create your own targets.BSMTProjectType
: Determines which set of default targets to run. Currently, the only option isBSIPA
. Future versions may include other options.- Default is
BSIPA
. Projects should set this explicitly.
- Default is
OutputAssemblyName
: Path to the output assembly (relative to project folder, no extension). This is used to copy the output assembly and PDB file to the artifact folder.- Default is
$(OutputPath)$(AssemblyName)
.
- Default is
ArtifactDestination
: Path to the artifact folder (relative to project folder). This is the folder that gets zipped for Release builds or CI builds.- Default is
$(OutputPath)Artifact
.
- Default is
ErrorOnMismatchedVersions
: If true, a build error will be raised if the project's assembly version doesn't match the manifest.- Default is true for Release builds, false otherwise
GameDirectory
: Path to an actual game install.- Default is
$(GameReferences)
.GameReferences
should be set by thecsproj.user
file (current, the value ofBeatSaberDir
will also be used, but this behavior is deprecated). - Projects should set this explicitly if
GameReferences
does not point to a Beat Saber install.
- Default is
- ItemGroups
OutputCopy
: The items in this group represent files to copy to the artifact folder and their relative path inside it. This can be used for non-standard outputs such as libraries or projects using ILRepack.Include
: The file to be copied.OutputPath
: Relative path of the copied file.- Example:
<OutputCopy Include="Plugin.dll" OutputPath="Plugins\Plugin.dll" />
- BSMT_BeforeBuild
- This is the first target that runs, all other BSMT targets will run after this one.
- Prints information to the build output (property names and values).
- BSMT_GetProjectInfo
- This target attempts to determine the plugin version, assembly version, game version, and git information. It also compares the assembly and plugin versions and errors/warns on a mismatch. The
ArtifactName
property is also set (used for naming the Release zip and GitHub Actions artifact). - Properties Set:
PluginVersion
,GameVersion
,CommitHash
,Branch
,Modified
,ArtifactName
- This target attempts to determine the plugin version, assembly version, game version, and git information. It also compares the assembly and plugin versions and errors/warns on a mismatch. The
- BSMT_AfterBuild
- This is the first BSMT target that runs after the build finishes, all other post-build BSMT targets run after this one.
- For ILRepack users, ensure your ILRepack task specifies
BeforeTargets="BSMT_AfterBuild"
- For ILRepack users, ensure your ILRepack task specifies
- This is the first BSMT target that runs after the build finishes, all other post-build BSMT targets run after this one.
- BSMT_SetOutputs
- This target sets
OutputCopy
if it does not already have items in it.
- This target sets
- BSMT_OutputForCI
- This target prints messages that can be read by GitHub Actions
filename
: Name for the artifact.assemblyname
: Name of the assembly (no extension).artifactpath
: Path to the artifact folder.
- This target prints messages that can be read by GitHub Actions
- BSMT_ZipRelease
- Creates a BeatMods compliant zip file for Release builds. The zip can be found in the
zip
folder of the output directory (Usuallybin\Release\zip
).
- Creates a BeatMods compliant zip file for Release builds. The zip can be found in the
- BSMT_CopyToPlugins
- Copies the output files to your game directory (or BSIPA's
Pending
folder if the game is running).
- Copies the output files to your game directory (or BSIPA's
Current as of v1.3.2
Compares an assembly and manifest version string. Logs an error and optionally fails if they don't match.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
PluginVersion | string | Yes | The mod or library's version as reported by the manifest file (must be SemVer). |
AssemblyVersion | string | Yes | The mod or library's version as reported by the assembly. |
ErrorOnMismatch | bool | No | If true, the task will report failure if the versions defined in the assembly and manifest don't match or can't be determined. |
Parses the AssemblyVersion from an AssemblyInfo.cs file.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
AssemblyInfoPath | string | No | Set to use an assembly info path other than Properties\AssemblyInfo.cs . |
FailOnError | bool | No | If true, the task will report failure if it cannot find or parse the AssemblyInfo file. |
Outputs:
Name | Type | Description |
---|---|---|
AssemblyVersion | string | The assembly's version as reported by the AssemblyInfo file. |
Gets information about the git repository and current commit.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
ProjectDir | string | Yes | The directory of the project. |
HashLength | int | No | The length of the CommitHash output. Default is 7. |
NoGit | bool | No | If true, reads git files manually instead of using the git executable. This is faster, but the Modified output will be unavailable. |
SkipStatus | bool | No | If true, does not attempt to check if files have been modified. |
Outputs:
Name | Type | Description |
---|---|---|
CommitHash | string | The first 8 characters of the current commit hash. Outputs local if project isn't using git source control. |
Branch | string | The current branch of the repository. |
IsPullRequest | bool | True if the current branch appears to be a pull request. |
Modified | string | Will be Modified if there are uncommitted changes, Unmodified if there aren't. Empty if it can't be determined. |
OriginUrl | string | The URL of the git repository. Empty if it can't be determined. |
GitUser | string | The GitHub username the repository belongs to (Extracted from OriginUrl). Empty if it can't be determined. |
Parses the mod or library's manifest and outputs the game and plugin versions.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
ManifestPath | string | No | Set to use a manifest file other than manifest.json in the project root. |
FailOnError | bool | No | If true, the task will report failure if it cannot find or parse the manifest file. |
Outputs:
Name | Type | Description |
---|---|---|
GameVersion | string | The Beat Saber game version defined in the manifest file. |
PluginVersion | string | The mod or library's version as reported by the manifest file. |
BasePluginVersion | string | The PluginVersion without any prerelease labels (i.e. "1.0.0-beta" -> "1.0.0"). |
Checks if the specified process is running.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
ProcessName | string | Yes | Name of the process to check. Case sensitive, do not include extension. |
Fallback | bool | No | Return this value if IsProcessRunning fails. Defaults to true. |
Outputs:
Name | Type | Description |
---|---|---|
IsRunning | bool | True if the process is running, false otherwise. |
Replaces text in a file that matches a pattern with a substitute.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
File | string | Yes | Path to target file. |
Pattern | string | Yes | Pattern to match for replacement (case sensitive). |
Substitute | string | Yes | String to replace matched patterns with. |
UseRegex | bool | No | If true, Pattern will be treated as a Regular Expression. |
RegexMultilineMode | bool | No | If true, changes '^' and '$ so they match the beginning and end of a line instead of the entire string. |
RegexSinglelineMode | bool | No | If true, changes the meaning of '.' so it matches every character except '\n' (newline). |
EscapeBackslash | bool | No | If true, escapes the \ character in Substitute with \\ . |
Creates a zip archive from the given directory.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
SourceDirectory | string | Yes | Directory to zip. |
DestinationFile | string | Yes | Path of the created zip. |
Outputs:
Name | Type | Description |
---|---|---|
ZipPath | string | Full path to the created zip file. Empty if the file could not be created. |
Added in 1.4.1
Generates a BSIPA manifest file.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
Id | string | Yes* | ID for the mod. Use this as the Mod Name on BeatMods (because BeatMods). |
Name | string | Yes* | A friendly name for the mod, usually the same or similar to the mod ID. |
Author | string | Yes* | The mod author. |
Version | string | Yes* | Mod version, should be in SemVer spec. |
GameVersion | string | Yes* | Beat Saber version the mod was built for. |
Description | string | Yes* | Description of what the mod does. |
Icon | string | No | Resource path to the icon. |
DependsOn | Mod Identifier | Yes** | Mods that need to be loaded for this mod to function. |
ConflictsWith | Mod Identifier | No | Mods cannot be loaded for this mod to function. |
Files | string[] | No | External files required by the mod or library (usually only used for libraries). |
LoadBefore | string[]] | No | List of mod IDs for mods that this mod should load before. |
LoadAfter | string[] | No | List of mod IDs that need to be loaded before this mod (this is implicit for mods in the DependsOn list. |
ProjectSource | string | No | Link to the mod's source repository. |
ProjectHome | string | No | Link to the mod's project web site. |
Donate | string | No | Donation link for the mod. |
Features | JSON Object String | No | A JSON object string to utilize BSIPA's Features architecture. |
Misc | JSON Object String | No | A JSON object string for miscellaneous properties.1.4.2 |
PluginHint | string | No | A hint for the loader for where to find the plugin type.1.4.2 |
BaseManifestPath | string | No | Path to a manifest file you want to use as a base. GenerateManifest will merge into this manifest. |
TargetPath | string | No | Output path (including filename) for the generated manifest. |
RequiresBsipa | bool | No | If true (default), GenerateManifest will error if you don't have BSIPA listed in DependsOn . |
*Properties are not required by the task if you are using a base manifest file (specified in BaseManifestPath
) that already has those properties.
**If a mod references BSIPA and uses its Plugin
architecture, you must have a DependsOn
for BSIPA.
Outputs:
Name | Type | Description |
---|---|---|
BasePluginVersion | string | Plugin version without any prerelease labels. |
PluginVersion | string | Plugin version written to the manifest. |
GameVersion | string | The Beat Saber game version the mod was built for. |
- Mod identifiers need to have an
Include
attribute (Mod ID from their manifest) andVersion
attribute (SemVer) - They are defined in one or more
<ItemGroup>
s. - Pass them to GenerateManifest using
TaskParameter="@(CollectionName)"
Example:
<Project>
<ItemGroup>
<Dependency Include="BSIPA" Version="^4.4.0"/>
<Dependency Include="SongCore" Version="^1.8.0"/>
</ItemGroup>
<Target Name="RunGenerateManifest" BeforeTargets="Build">
<GenerateManifest
<!-- Other Parameters -->
DependsOn="@(Dependency)"
<!-- Other Parameters -->
/>
</Target>
</Project>
- String arrays are similar to
Mod Identifiers
except you only need theInclude
attribute. - If you only need one item, you can pass a single string defined in a
PropertyGroup
as well. Example:
<Project>
<ItemGroup>
<RequiredFile Include="Libs/RequiredLibFile.dll"/>
<RequiredFile Include="Libs/OtherRequiredLibFile.dll"/>
</ItemGroup>
<Target Name="RunGenerateManifest" BeforeTargets="Build">
<GenerateManifest
<!-- Other Parameters -->
Files="@(RequiredFile)"
<!-- Other Parameters -->
/>
</Target>
</Project>
- A JSON string that defines an object.
- The string can be put into a
PropertyGroup
property. It seems you don't have to worry about escaping any characters. Example:
<Project>
<PropertyGroup>
<GameVersion>1.14.0</GameVersion>
<Description>Description...</Description>
<Features>
{
"CountersPlus.CustomCounter": {
"Name": "Nightscout Counter",
"Description": "Reads blood sugar from a nightscout site.",
"CounterLocation": "NightscoutCounter.Counters.NightscoutCounterCountersPlus",
"ConfigDefaults": {
"Enabled": true,
"Position": "AboveMultiplier",
"Distance": 0
},
"BSML": {
"Resource": "NightscoutCounter.UI.Views.NightscoutSettings.bsml",
"Host": "NightscoutCounter.UI.NightscoutSettingsHandler",
"Icon": "NightscoutCounter.UI.Images.nightscout-counter.png"
}
}
}
</Features>
</PropertyGroup>
<Target Name="RunGenerateManifest" BeforeTargets="Build">
<GenerateManifest
<!-- Other Parameters -->
Features="$(Features)"
<!-- Other Parameters -->
/>
</Target>
</Project>
Writes a property to GitHub Action runner's environment file.
Inputs:
Name | Type | Required? | Description |
---|---|---|---|
OutputName | string | Yes | Name of the output property. |
OutputValue | string | Yes | Value of the output property. |
OutputPath | string | No | Path to the output file. Default is value of GITHUB_OUTPUT |