Skip to content

Zingabopp/BeatSaberModdingTools.Tasks

Repository files navigation

BeatSaberModdingTools.Tasks

A set of MSBuild tasks for Beat Saber mods. Created for the templates in Beat Saber Modding Tools.

Default Targets (v2.0.0+)

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

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 is BSIPA. Future versions may include other options.
      • Default is BSIPA. Projects should set this explicitly.
    • 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).
    • 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.
    • 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 the csproj.user file (current, the value of BeatSaberDir will also be used, but this behavior is deprecated).
      • Projects should set this explicitly if GameReferences does not point to a Beat Saber install.
  • 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" />

BSIPA Targets Information

  • 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
  • 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"
  • BSMT_SetOutputs
    • This target sets OutputCopy if it does not already have items in it.
  • 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.
  • BSMT_ZipRelease
    • Creates a BeatMods compliant zip file for Release builds. The zip can be found in the zip folder of the output directory (Usually bin\Release\zip).
  • BSMT_CopyToPlugins
    • Copies the output files to your game directory (or BSIPA's Pending folder if the game is running).

Tasks

Current as of v1.3.2

CompareVersions

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.

GetAssemblyInfo

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.

GetCommitInfo

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.

GetManifestInfo

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").

IsProcessRunning

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.

ReplaceInFile

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 \\.

ZipDir

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.

GenerateManifest

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.

Special Types

Mod Identifier

  • Mod identifiers need to have an Include attribute (Mod ID from their manifest) and Version 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

  • String arrays are similar to Mod Identifiers except you only need the Include 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>

JSON Object String

  • 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>

SetActionOutput

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