This is a automated Build script setup you can use to automatically package your mods for Thunderstore. This uses dotnet publish to build the package.
This is released as Open-Source subject to the terms found within SML-1.0.0
TS-Build.bat.This script is built for C# mods for Thunderstore meaning that if your mods are any other language your unfortunately out of luck. For Java mods I reccomend using BlueAzures HytalePublisher. Do note its built primarily for Hytale mods, so you might have a better time forking this repository and modifying elements for where properties are fetched from.
This package essentially builds your mod, fetches you README, CHANGELOG, LICENSE, Manifest Fields, and any folders you wish to copy over into automatically built zips targetted for the Thunderstore ecosystem.
.bat file included in this repository and any other build script that may be present entitled TS-Build.CSProj to %~dp0{YOUR CSPROJ'S NAME}.csproj where {YOUR CSPROJ'S NAME} is the name of the literal file that holds the CSProj you wish to target, excluding the extension. The %~dp0 handles getting the full path based on where the bat file is. So as long as the bat's where it should be you don't need to worry about paths.This project uses several .csproj fields to configure how the script works, below is a table of CSProj Keys and what their values should be.
.CSProj Key |
.CSProj Value(s) |
|---|---|
<TargetFrameworks> |
This should be a list ; seperated of all netframeworks the mod works with, or just the primary one, No <TargetFramework> does not work with this. If its invalid the fallback is net6.0. |
<RuntimeIdentifiers> |
This should be a list ; seperated of all Runtime Identifiers the mod works with, or just the primary one. If its invalid the fallback is win-x64. |
<BuildCopyLocations> |
This should be a ; seperated list of all paths (root localized) in which should be copied directly to the package, keep in mind by directly we mean its root folder, not the plugins subfolder. If its invalid the fallback is hunderstore-Package-Elements. |
<BuildOutputLocations> |
This should be a ; seperated list of all paths (root localized) in which the package's mod should be published to for example <BuildOutputLocations>BepInEx/patchers;BepInEx/plugins</BuildOutputLocations> builds it to both the Plugins and the Patchers folder. If invalid, it will publish to root. This field is Optional. |
<CHANGELOGCopyLocation> |
The root localized path to the Changelog location. |
<READMECopyLocation> |
The root localized path to the README location. |
<LICENSECopyLocation> |
The root localized path to the LICENSE location. |
<DependenciesCopyLocations> |
The root localized path to the Dependencies location. Note these should be dependencies needed by your mod to function that aren't covered by the Mod Installation setup itself. For example NuGet packages. If invalid, it just skips creating the folders and copying. This field is Optional. |
<ReleaseMode> |
A string with the value of Release for Release Publishing or Debug for Debug Publishing (otherwise known as Prerelease). If the value is invalid the fallback is Debug. |
<ThunderstorePackageName> |
The Thunderstore Package Name. It must adhere to the following spec: Name of the mod, no spaces. Allowed characters: a-z A-Z 0-9 _ |
<ThunderstorePackageVersion> |
The Thunderstore Package Version. It must adhere to the following spec: Version number of the mod, following the semantic version format Major.Minor.Patch |
<ThunderstoreWebsiteURL> |
The Website URL in which your package should link to. It must adhere to the following spec: URL of the mod's website (e.g. GitHub repo). Can be left an empty string. |
<ThunderstorePackageDescription> |
The short description of your Package. It must adhere to the following spec: A short description of the mod, shown on the mod list. Max 250 characters. |
<ThunderstorePackageDependencyStrings> |
This should be a ; seperated list of Dependency strings, you can get the package string by visiting the given dependency page on https://thunderstore.io and copying the field value of: Dependency string. |
All fields should be treated as required.
An example setup is:
<!--Build System Properties-->
<PropertyGroup>
<!--Copy Locations-->
<BuildCopyLocations>Thunderstore-Package-Elements</BuildCopyLocations>
<BuildOutputLocations></BuildOutputLocations> <!--This field is Optional-->
<CHANGELOGCopyLocation>CHANGELOG.md</CHANGELOGCopyLocation>
<READMECopyLocation>README.md</READMECopyLocation>
<LICENSECopyLocation>LICENSE.md</LICENSECopyLocation>
<DependenciesCopyLocations>Dependencies/BepInEx-Required-Dependencies</DependenciesCopyLocations> <!--This field is Optional-->
<ReleaseMode>Release</ReleaseMode>
<!--Thunderstore Manifest Properties-->
<ThunderstorePackageName>JSONCardLoader</ThunderstorePackageName>
<ThunderstorePackageVersion>2.7.0</ThunderstorePackageVersion>
<ThunderstoreWebsiteURL>https://github.com/MADH95/JSONCardLoaderPlugin</ThunderstoreWebsiteURL>
<ThunderstorePackageDescription>A mod made for Incryption to create custom cards, sigils, starter decks, tribes, encounters and more using JSON files.</ThunderstorePackageDescription>
<ThunderstorePackageDependencyStrings>BepInEx-BepInExPack_Inscryption-5.4.1902;API_dev-API-2.23.7</ThunderstorePackageDependencyStrings>
</PropertyGroup>
Note that <TargetFrameworks> and <RuntimeIdentifiers> are not included in this block, that is because they are project wide fields thus they should be defined at the top of your .csproj file.
This system does not have a clean way of cleaning up the build output on its own, thats why we have a couple more properties in our .csproj system that come directly from the MSBuild system to help resolve this.
First add these 3 properties to the top section of your .csproj
SelfContained will make it so your executable mod is able to run on its ownCopyLocalLockFileAssemblies will make prevent local assemblies from being included in output when publishing or building your project (our build system handles this on its own via the configured property above)IncludeBuildOutput will make it so that BuildOutput itself won't be included when publishing (we only want the Assemblies we need). <SelfContained>true</SelfContained>
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
<IncludeBuildOutput>false</IncludeBuildOutput>
With Local Dependencies, if you want them to copy to the build folder add the following after referencing them in your .csproj
<Private>true</Private>
This should appear in the reference as follows:
<Reference Include="Antlr3.Runtime">
<HintPath>Dependencies\BepInEx-Required-Dependencies\Antlr3.Runtime.dll</HintPath>
<Private>true</Private>
</Reference>
Another item we have to help with Cleanup is the following Target:
<!--Cleanup Publish for our Build System-->
<Target Name="StripAllNuGetFromPublish" AfterTargets="ComputeFilesToPublish">
<ItemGroup>
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.Extension)' == '.dll' and '%(ResolvedFileToPublish.RelativePath)' != 'JSONLoader.dll'" />
</ItemGroup>
</Target>
This makes it so the Output will remove anything that is not JSONLoader in this case, Replace JSONLoader with the value of your .csproj's AssemblyName field.
When it comes to running you can either launch the script via Terminal (ideally Powershell) or you can do the following to setup a runner for your Mod. For launching via Terminal make sure to navigate to the folder TS-Build.bat resides in first before running it!
Add New Configuration or the Arrow next to the Configuration already selected.Edit Configuraion.+ icon than select Native Executable.Executable Path click the folder icon (Browse) and navigate to the TS-Build.bat and select the file.Exe Path and Working Directory should have updated.Store As Project File, this will add a file under .run the next time you load the project.Apply followed by Okay.Run. (Play Button).run.TS-Build.run.xml<component name="ProjectRunConfigurationManager">
<configuration default="false" name="TS-Build" type="RunNativeExe" factoryName="Native Executable">
<option name="EXE_PATH" value="$PROJECT_DIR$/{PROJECT FOLDER}/TS-Build.bat" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/{PROJECT FOLDER}" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="ENV_FILE_PATHS" value="" />
<option name="REDIRECT_INPUT_PATH" value="" />
<option name="MIXED_MODE_DEBUG" value="0" />
<method v="2" />
</configuration>
</component>
{PROJECT FOLDER} with the folder path leading to your Project for example JSONLoaderOld. $PROJECT_DIR$ will resolve all the way up to the Solution folder, you just need to add the rest of the path.TS-Build as a runner.They go either into a folder called GITHUB RELEASE or GITHUB PRERELEASE dependant of your configuration. Both folders are found in the root location of this script.
There will be 3 subfolders (2 of these NYI with the current TS-Build System but they will be available in the future)
NET: this is where any directive NET packages will resolve to.NATIVE: this is where any NativeAOT build packages will resolve to.NUGET: this is where any NUGET Packages will resolve to.All packages will appear in the folowing formats:
NET: {target-framework}-{runtime-identifier}-{release-mode}.zipNATIVE: Native-{target-framework}-{runtime-identifier}-{release-mode}.zipNUGET: The typical dotnet pack output.Chaosyr in Hytale Checkout, they will receive a portion of the Checkout proceeds.