Skip to content

Commit

Permalink
package as MSBuildSdk, rather than nuget package with build assets
Browse files Browse the repository at this point in the history
  • Loading branch information
Cryptoc1 committed Dec 19, 2023
1 parent cec92e2 commit 3736408
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 70 deletions.
117 changes: 69 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,101 @@
# Lethal Company Plugin SDK

Get modding Lethal Company easier, faster, and *better*.
An [MSBuild Sdk](https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2022) for creating Lethal Company mods that:

- Optimizes Build Defaults
- Enables Modern Language Features with [`PolySharp`](https://github.com/Sergio0694/PolySharp)
- References Publicized Binaries from [`LethalAPI.GameLibs`](https://github.com/dhkatz/LethalAPI.GameLibs)
- Creates Thunderstore Packages
- And More...


## Usage

- Add a reference to the `LethalCompany.Plugin.Sdk` package to an empty Class Library targeting `netstandard2.1`
To start using the Sdk, create a new Class Library:
```bash
$ dotnet new classlib -n {NAME}
```

In the new `.csproj`, update the `Sdk="Microsoft.NET.Sdk"` attribute at the top of the file to `Sdk="LethalCompany.Plugin.Sdk/{VERSION}"`, and replace any existing content with metadata about the plugin:
```xml
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="LethalCompany.Plugin.Sdk/1.0.0">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Title>Plugin Example</Title>
<Description>My example plugin!</Description>
<PluginId>example.plugin</PluginId>
<Version>1.0.0</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LethalCompany.Plugin.Sdk" Version="..." PrivateAssets="all" />
</ItemGroup>
</Project>
```

- Define your plugin metadata in your `.csproj`
```xml
<PropertyGroup>
<Title>Plugin Example</Title>
<Description>My example plugin!</Description>
<PluginId>example.plugin</PluginId>
<ThunderId>Example_Plugin</ThunderId>
<Version>1.0.0</Version>
</PropertyGroup>

<ItemGroup>
<ThunderReference Include="..." />
</ItemGroup>
```

- Create your plugin class
Add a new `.cs` file, and define the plugin:
```csharp
[BepInPlugin(GeneratedPluginInfo.Identifier, GeneratedPluginInfo.Name, GeneratedPluginInfo.Version)]
public sealed class SamplePlugin : BaseUnityPlugin
{
// ...
}
```
> _The Sdk creates a `GeneratedPluginInfo` class from the metadata provided in your project for usage in code._
> _The Sdk generates a `GeneratedPluginInfo` class from the metadata provided in your project for usage in code._
>
> _The name of the generated class can be changed using the `<PluginInfoTypeName>...</PluginInfoTypeName>` MSBuild property._

- Use `dotnet publish` to create a package that's ready for upload to Thunderstore
```
> dotnet publish -c Release -o package
...
Zipping directory ".\bin\Release\netstandard2.1\publish\" to ".\package\Example_Plugin-1.0.0.zip".
```


## Features
> _The name of the generated class can be changed using the `<PluginInfoTypeName></PluginInfoTypeName>` MSBuild property._
### Default Build Configuration
### Publish to Thunderstore

This Sdks provides out-of-the-box configuration of your project, ensuring proper Release builds when publishing, and default `TargetFramework` optimizations.
> _In order to create a Thunderstore Package, the Sdk requires that `icon.png`, `CHANGELOG.md` and `README.md` files exist at the project root._
### Use Modern Language Features
In the `.csproj` of the plugin, provide the metadata used to generate a `manifest.json` for publishing:
```xml
<Project Sdk="LethalCompany.Plugin.Sdk/1.0.0">

<PropertyGroup>
<!-- ... -->

This Sdk adds a reference to [PolySharp](https://github.com/Sergio0694/PolySharp) to your project, allowing you to use the latest language and compiler features, like `ImplicitUsings`, `Nullable`, and more (enabled by default).
<Description>My example plugin!</Description>
<ThunderId>ExamplePlugin</ThunderId>
<ThunderWebsiteUrl>https://example.com</ThunderWebsiteUrl>
<Version>1.0.0</Version>
</PropertyGroup>

### Game Library References
<ItemGroup>
<ThunderDependency Include="ExampleTeam-OtherPlugin-1.0.0" />
</ItemGroup>

This Sdk adds a reference to [`LethalAPI.GameLibs`](https://github.com/dhkatz/LethalAPI.GameLibs) to your project, allowing capabilities like CI/CD.
</Project>
```

### Publish to Thunderstore
The following `manifest.json` would be generated for the example metadata:
```json
{
"name": "ExamplePlugin",
"dependecies": ["BepInEx-BepInExPack-5.4.2100", "ExampleTeam-OtherPlugin-1.0.0"],
"description": "My example plugin!",
"version_number": "1.0.0",
"website_url": "https://example.com"
}
```

This Sdk provides custom build properties for generating a `manifest.json`, and extends publish targets to generate an archive from project assets that's ready for upload to Thunderstore.
To create a Thunderstore package, use `dotnet publish`:
```
$ dotnet publish
MSBuild version 17.8.3+195e7f5a3 for .NET
Determining projects to restore...
All projects are up-to-date for restore.
ExamplePlugin -> .\bin\Debug\netstandard2.1\ExamplePlugin.dll
ExamplePlugin -> .\bin\Debug\netstandard2.1\publish\
Zipping directory ".\bin\Debug\netstandard2.1\publish\" to ".\bin\Debug\netstandard2.1\ExamplePlugin-1.0.0.zi
p".
```

### Code Analysis
#### Specify Thunderstore Dependencies

This Sdk adds a reference to the [NETAnalyzers](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-8) to your project, and sets the default analysis level to `latest-recommended`.
To specify Thunderstore dependencies in the generated `manifest.json`, use the `ThunderDependency` item:
```xml
<ItemGroup>
<ThunderDependency Include="ExampleTeam-ExamplePlugin-1.0.0" />
</ItemGroup>
```

Additional analyzers, such as [`BepInEx.Analyzers`](https://github.com/BepInEx/BepInEx.Analyzers), are also included.
> _The Sdk specifies a default `ThunderDependency` on `BepInExPack`, specifying one yourself is unnecessary._
7 changes: 4 additions & 3 deletions src/LethalCompany.Plugin.Sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<DevelopmentDependency>true</DevelopmentDependency>
<NoWarn>$(NoWarn);NU5128;</NoWarn>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>

Expand All @@ -13,7 +14,8 @@
<Title>$(AssemblyName)</Title>
<PackageId>$(AssemblyName)</PackageId>
<PackageProjectUrl>https://github.com/cryptoc1/lc-plugin-sdk</PackageProjectUrl>
<PackageReadMe>README.md</PackageReadMe>
<PackageReadMeFile>README.md</PackageReadMeFile>
<PackageType>MSBuildSdk</PackageType>

<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand All @@ -26,8 +28,7 @@

<ItemGroup>
<Content Include="..\README.md" Pack="true" PackagePath="\" />
<Content Include="build\*" PackagePath="build\" />
<Content Include="buildMultiTargeting\*" PackagePath="buildMultiTargeting\" />
<Content Include="Sdk\*" PackagePath="Sdk\" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<Project>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" Condition=" '$(MicrosoftCommonPropsHasBeenImported)' != 'true' "/>

<!-- defaults -->
<PropertyGroup>
Expand Down Expand Up @@ -43,7 +44,7 @@

<!-- Thunderstore content -->
<ItemGroup>
<ThunderReference Include="BepInEx-BepInExPack-5.4.2100" />
<ThunderDependency Include="BepInEx-BepInExPack-5.4.2100" />

<Content Include="icon.png;CHANGELOG.md;README.md">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<Project>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

<Target Name="_GeneratePluginInfo" AfterTargets="PrepareForPluginCompile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)$(MSBuildProjectName).PluginInfo.g.cs">
<PropertyGroup>
Expand Down Expand Up @@ -27,10 +28,10 @@ public static class $(PluginInfoTypeName)
<PropertyGroup>
<_GeneratedManifestText><![CDATA[{
"name": "$(ThunderId)",
"dependencies": [$(ThunderReferences.Replace('%3B', ','))],
"dependencies": [$(ThunderDependencies.Replace('%3B', ','))],
"description": "$(PluginDescription)",
"version_number": "$(PluginVersion)",
"website_url": "$(PluginWebsiteUrl)"
"website_url": "$(ThunderWebsiteUrl)"
}]]></_GeneratedManifestText>

<_GeneratedManifestPath>$(IntermediateOutputPath)$(MSBuildProjectName).manifest.g.json</_GeneratedManifestPath>
Expand All @@ -47,7 +48,7 @@ public static class $(PluginInfoTypeName)
<Copy SourceFiles="$(_GeneratedManifestPath)" DestinationFiles="$(PublishDir)manifest.json" SkipUnchangedFiles="true" Condition=" Exists('$(_GeneratedManifestPath)') " />
</Target>

<Target Name="PrepareForPluginCompile" BeforeTargets="Compile;GenerateMSBuildEditorConfigFileShouldRun">
<Target Name="PrepareForPluginCompile" BeforeTargets="Compile;GenerateMSBuildEditorConfigFileShouldRun;PrepareForPluginPublish">
<!-- NOTE: set plugin prop defaults -->
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
Expand All @@ -62,14 +63,14 @@ public static class $(PluginInfoTypeName)
<PluginName Condition=" '$(PluginName)' == '' ">$(AssemblyName)</PluginName>

<PluginVersion Condition=" '$(PluginVersion)' == '' ">$(Version)</PluginVersion>
<PluginWebsiteUrl Condition=" '$(PluginWebsiteUrl)' == '' ">$(PackageProjectUrl)</PluginWebsiteUrl>

<ThunderId Condition=" '$(ThunderId)' == '' ">$(PluginId)</ThunderId>
<ThunderReferences>@(ThunderReference -> '"%(Filename)%(Extension)"')</ThunderReferences>
<ThunderDependencies>@(ThunderDependency -> '"%(Filename)%(Extension)"')</ThunderDependencies>
<ThunderWebsiteUrl Condition=" '$(ThunderWebsiteUrl)' == '' ">$(PackageProjectUrl)</ThunderWebsiteUrl>
</PropertyGroup>
</Target>

<Target Name="PrepareForPluginPublish" AfterTargets="PrepareForPluginCompile" BeforeTargets="PrepareForPublish">
<Target Name="PrepareForPluginPublish" BeforeTargets="PrepareForPublish">
<PropertyGroup>
<_PublishDir>$(PublishDir)</_PublishDir>
<PublishDir>$(OutputPath)publish\</PublishDir>
Expand Down
3 changes: 0 additions & 3 deletions src/buildMultiTargeting/LethalCompany.Plugin.Sdk.props

This file was deleted.

3 changes: 0 additions & 3 deletions src/buildMultiTargeting/LethalCompany.Plugin.Sdk.targets

This file was deleted.

9 changes: 5 additions & 4 deletions test/LethalCompany.SdkSample.csproj
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\src\build\LethalCompany.Plugin.Sdk.props" />
<Project>
<Import Project="..\src\Sdk\Sdk.props" />

<PropertyGroup>
<Title>Plugin SDK Sample</Title>
<Description>Test plugin generated using the LC-Plugin-Sdk</Description>
<Description>Test plugin generated using the LethalCompany.Plugin.Sdk</Description>
<PluginId>cryptoc1.lethalcompany.sdksample</PluginId>
<PluginInfoTypeName>SamplePluginInfo</PluginInfoTypeName>
<ThunderId>LC_SDK_SAMPLE</ThunderId>
<TargetFramework>netstandard2.1</TargetFramework>
<Version>1.0.0</Version>

<NoWarn>$(NoWarn);CA1822;</NoWarn>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

<Import Project="..\src\build\LethalCompany.Plugin.Sdk.targets" />
<Import Project="..\src\Sdk\Sdk.targets" />
</Project>
3 changes: 3 additions & 0 deletions test/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
}
},
"lethalcompany.plugin.sdk": {
"type": "Project"
}
}
}
Expand Down

0 comments on commit 3736408

Please sign in to comment.