Add LabAPI plugin dotnet new template
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.cs]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
dotnet_sort_system_directives_first = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_prefer_braces = true:suggestion
|
||||
|
||||
# Naming and language conventions here reflect this project's own style; they
|
||||
# do not by themselves enforce the "no unsolicited comments" / "English by
|
||||
# default" rules in AGENTS.md / CLAUDE.md, which apply to any human or AI
|
||||
# contributor regardless of what an analyzer can mechanically check.
|
||||
|
||||
[*.{csproj,json,yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,4 @@
|
||||
bin/
|
||||
obj/
|
||||
*.user
|
||||
.vs/
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/template",
|
||||
"author": "Your name / organization",
|
||||
"classifications": [ "Common", "Library", "SCP:SL", "LabAPI", "Game Plugin" ],
|
||||
"identity": "SCPSL.LabApi.PluginTemplate",
|
||||
"name": "SCP: Secret Laboratory LabAPI Plugin",
|
||||
"shortName": "labapi-plugin",
|
||||
"tags": {
|
||||
"language": "C#",
|
||||
"type": "project"
|
||||
},
|
||||
"sourceName": "LabApiPluginTemplate",
|
||||
"preferNameDirectory": true,
|
||||
"symbols": {
|
||||
"LabApiVersion": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "1.1.7",
|
||||
"replaces": "1.1.7",
|
||||
"description": "Version of the Northwood.LabAPI NuGet package to install in the project."
|
||||
},
|
||||
"PluginAuthor": {
|
||||
"type": "parameter",
|
||||
"datatype": "string",
|
||||
"defaultValue": "YourName",
|
||||
"replaces": "YourName",
|
||||
"description": "Name used as the plugin's author (EntryPoint's Author property)."
|
||||
},
|
||||
"skipRestore": {
|
||||
"type": "parameter",
|
||||
"datatype": "bool",
|
||||
"description": "If set, skips running 'dotnet restore' automatically after creating the project.",
|
||||
"defaultValue": "false"
|
||||
}
|
||||
},
|
||||
"primaryOutputs": [
|
||||
{ "path": "LabApiPluginTemplate.csproj" }
|
||||
],
|
||||
"postActions": [
|
||||
{
|
||||
"condition": "(!skipRestore)",
|
||||
"description": "Restores the NuGet packages required by this project (including LabAPI).",
|
||||
"manualInstructions": [
|
||||
{ "text": "Run 'dotnet restore'" }
|
||||
],
|
||||
"actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
|
||||
"continueOnError": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
# AGENTS.md
|
||||
|
||||
This repo is the source of a `dotnet new` template (shortName `labapi-plugin`) that
|
||||
scaffolds SCP: Secret Laboratory LabAPI plugins. This file follows the
|
||||
editor/vendor-agnostic [agents.md](https://agents.md) convention for AI coding tools
|
||||
other than Claude Code (Cursor, Codex, etc.). **`CLAUDE.md` is this repo's primary,
|
||||
detailed instructions file** — read it first if your tooling can. What follows is the
|
||||
condensed subset any agent needs, kept in sync with `CLAUDE.md`.
|
||||
|
||||
## This is template source, not a plugin
|
||||
|
||||
This section applies only while `.template.config/` is present next to this file —
|
||||
i.e. you're editing the template repo itself, not a plugin already generated from it.
|
||||
|
||||
`.template.config/template.json` makes the dotnet templating engine do a **literal,
|
||||
repo-wide string replacement** at generation time (not semantic renaming): this
|
||||
folder's own name (`sourceName`) becomes whatever project name a consumer picks, the
|
||||
placeholder author name in `EntryPoint.cs` becomes their `--PluginAuthor`, and the
|
||||
LabAPI version pinned in the `.csproj`/`EntryPoint.cs` becomes their
|
||||
`--LabApiVersion`. See `template.json` for the exact current literals — don't repeat
|
||||
them verbatim in prose here, since this file ships inside every generated project and
|
||||
an exact match would get silently rewritten too. Don't introduce an exact match of
|
||||
one of those literals elsewhere in the repo unless you mean for it to be substituted;
|
||||
add a new `template.json` symbol instead of hardcoding a magic string. `EntryPoint`/
|
||||
`Config` (the class names) are intentionally **not** substituted — only the namespace
|
||||
tracks the project name.
|
||||
|
||||
## Never invent LabAPI API surface
|
||||
|
||||
Don't assume a LabAPI class/namespace/method/property/attribute exists. Verify it
|
||||
against the restored `Northwood.LabAPI` package (`LabApi.dll`/`LabApi.xml` under
|
||||
`%userprofile%\.nuget\packages\northwood.labapi\<version>\lib\net48\`) or
|
||||
https://github.com/northwood-studios/LabAPI first. If you can't verify a member,
|
||||
say so instead of guessing.
|
||||
|
||||
## Toolchain choices — don't change without being asked
|
||||
|
||||
`TargetFramework` is `netstandard2.1` on purpose (LabAPI itself only ships
|
||||
`net48`/`net481`), chosen so the plugin still loads under the game's Mono/.NET
|
||||
Framework 4.8 host. `LangVersion` is pinned to `14.0`. The `.csproj` suppresses
|
||||
exactly `NU1701` (scoped to the `Northwood.LabAPI` `PackageReference`) and `MSB3270`
|
||||
(via `ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch=None`) because of that
|
||||
netstandard2.1/net48-only-package combination — don't broaden either into a blanket
|
||||
suppression or remove them.
|
||||
|
||||
## Code style and language
|
||||
|
||||
No `//`, `/* */`, or `///` comments unless the user explicitly asks for them in that
|
||||
request; don't add comments restating self-explanatory code — `EntryPoint.cs`/
|
||||
`Config.cs` are already comment-free, follow the same standard for new files. All
|
||||
text embedded in code (log/console messages, exceptions, config descriptions,
|
||||
user-facing strings) defaults to English — e.g. `Logger.Info("Plugin initialized
|
||||
successfully")` — except identifiers the user requested (project name, namespace,
|
||||
class/method/property/variable names), which are never translated, and text the user
|
||||
explicitly asks to be in another language.
|
||||
|
||||
## Verifying a change
|
||||
|
||||
No automated tests exist. Verify by generating a real project and building it:
|
||||
|
||||
```bash
|
||||
dotnet new uninstall . && dotnet new install .
|
||||
dotnet new labapi-plugin -n VerifyPlugin -o ../_verify/VerifyPlugin
|
||||
cd ../_verify/VerifyPlugin && dotnet build
|
||||
```
|
||||
|
||||
Expect `Build succeeded. 0 Warning(s) 0 Error(s)`. See `CLAUDE.md` for the full
|
||||
verification notes (cache invalidation after editing `template.json`, Windows cleanup
|
||||
caveats).
|
||||
@@ -0,0 +1,142 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This repo **is** a `dotnet new` project template (identity `SCPSL.LabApi.PluginTemplate`,
|
||||
shortName `labapi-plugin`), not a runnable plugin. It scaffolds SCP: Secret Laboratory
|
||||
LabAPI plugins. `AGENTS.md` carries a shorter, tool-agnostic version of the essentials
|
||||
for non-Claude agents; this file is the authoritative one — keep both in sync when a
|
||||
rule below changes.
|
||||
|
||||
The next section only applies while you're editing **this template repository**
|
||||
(i.e. a `.template.config/` folder is present next to this file). It does not apply
|
||||
if you're instead looking at a plugin someone already generated from this template —
|
||||
that folder never contains `.template.config/`, and its `EntryPoint.cs`/`Config.cs`
|
||||
are ordinary project files at that point, not template scaffolding.
|
||||
|
||||
## Repo is template *source* — read before touching any file
|
||||
|
||||
`.template.config/template.json` sets this folder's name as the template's
|
||||
`sourceName` and defines two text-replacement `symbols` (plus a third, `skipRestore`,
|
||||
that only toggles the post-generation `dotnet restore` and replaces no text). The
|
||||
dotnet templating engine does a literal, repo-wide **string replacement** at
|
||||
generation time — not semantic renaming — driven by that config:
|
||||
|
||||
- The folder/project name (`sourceName` in `template.json`, currently this repo's own
|
||||
folder name) → whatever `-n`/`--name` the consumer passes to `dotnet new`.
|
||||
- The placeholder value of the `PluginAuthor` symbol (the string currently sitting in
|
||||
`EntryPoint.cs`'s `Author` property) → the consumer's `--PluginAuthor`.
|
||||
- The placeholder value of the `LabApiVersion` symbol (the version string currently in
|
||||
the `.csproj`'s `PackageReference` and in `EntryPoint.cs`'s `RequiredApiVersion`) →
|
||||
the consumer's `--LabApiVersion`.
|
||||
|
||||
Open `template.json` to see the exact current literal for each — don't hardcode them
|
||||
again here or anywhere else in prose, because this file itself ships inside every
|
||||
generated project and any exact match gets rewritten too (self-referential text like
|
||||
"the project is called X" would silently turn into nonsense after generation).
|
||||
|
||||
Consequences:
|
||||
- Never introduce an exact match of one of those three literals elsewhere in the repo
|
||||
unless you intend it to be substituted too.
|
||||
- If you add a new thing that should be configurable at generation time, add a symbol
|
||||
to `template.json` (`type: parameter`, `replaces: "<literal>"`) instead of
|
||||
hardcoding a magic string.
|
||||
- `EntryPoint` and `Config` (the class names) are **not** substituted and must stay
|
||||
literally named that — LabAPI's `PluginLoader` discovers plugins by type
|
||||
inheritance, not by name, and the file names `EntryPoint.cs`/`Config.cs` are a fixed
|
||||
part of this template's contract. Only the *namespace* tracks the project name.
|
||||
|
||||
## Repo layout (only what affects decisions)
|
||||
|
||||
- `.template.config/template.json` — template identity, the 3 symbols above,
|
||||
`primaryOutputs` (points at the project file using its pre-substitution literal
|
||||
name — that's correct and expected, not a bug), and a `postActions` restore step
|
||||
(the standard dotnet-templating "restore NuGet packages" action, id
|
||||
`210D431B-...`; skipped in Visual Studio, which restores on its own).
|
||||
- The `.csproj` at the repo root — the project file every generated plugin ships with.
|
||||
- `EntryPoint.cs` / `Config.cs` — the scaffolded plugin (`Plugin<Config>`) and its
|
||||
YAML-backed settings class.
|
||||
- `.editorconfig` — formatting/naming only (indentation, brace style). It does **not**
|
||||
enforce the comment/language rules below — those aren't analyzer-checkable.
|
||||
- No `.sln`, no test project, no CI, no packaging (`.nupkg`) project, no git repo, and
|
||||
no GitHub Copilot instructions file currently exist in this folder. Don't assume
|
||||
any of them.
|
||||
|
||||
## LabAPI contract (verified against northwood-studios/LabAPI source, not guessed)
|
||||
|
||||
`Plugin<TConfig>` (`LabApi.Loader.Features.Plugins`) requires implementing:
|
||||
`Name`, `Description`, `Author`, `RequiredApiVersion` (all abstract get-only) plus
|
||||
`Enable()`/`Disable()`. Overridable but optional: `Version` (defaults to the
|
||||
assembly's version), `Priority` (`LoadPriority`, defaults to `Medium`),
|
||||
`ConfigFileName` (defaults to `"config.yml"`). `Config` is a plain `class` with a
|
||||
public parameterless constructor and public get/set properties — the base class
|
||||
(de)serializes it via YamlDotNet automatically; don't hand-roll config I/O.
|
||||
|
||||
**Never invent a LabAPI class/namespace/method/property/attribute.** Before using one
|
||||
you haven't already seen in this repo, check the restored package (`LabApi.dll` +
|
||||
`LabApi.xml` under `%userprofile%\.nuget\packages\northwood.labapi\<version>\lib\net48\`)
|
||||
or https://github.com/northwood-studios/LabAPI. If you can't verify a member exists,
|
||||
say so instead of guessing. No Skill/plugin specific to C#, .NET, MSBuild, NuGet, or
|
||||
LabAPI exists in the Claude Code skill catalog as of this writing — check
|
||||
`ToolSearch`/`SearchSkills` for one before editing in case that has changed, but don't
|
||||
assume one exists.
|
||||
|
||||
## Toolchain choices — don't "fix" these without being asked
|
||||
|
||||
- The project's `TargetFramework` is `netstandard2.1` on purpose, even though
|
||||
LabAPI's own docs and the `Northwood.LabAPI` NuGet package only target
|
||||
`net48`/`net481`. This is a deliberate compatibility choice (compiled output still
|
||||
loads under the game's Mono/.NET Framework 4.8 host) that trades away some
|
||||
netstandard2.1 BCL/language surface .NET Framework can't actually run (e.g. default
|
||||
interface members). Don't switch it to `net48`, don't add multi-targeting, unless
|
||||
the user asks.
|
||||
- `LangVersion` is pinned explicitly (currently `14.0`) — don't let it drift to
|
||||
`latest`.
|
||||
- The `.csproj` suppresses exactly two warnings, both scoped as narrowly as MSBuild
|
||||
allows, because of the netstandard2.1/net48-only-package combination above:
|
||||
`NU1701` (via a per-`PackageReference` `<NoWarn>`, not a project-wide one) and
|
||||
`MSB3270` (via `ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch=None`). Don't
|
||||
broaden either into a blanket suppression and don't remove them without
|
||||
understanding why (comments sit next to both in the `.csproj`).
|
||||
|
||||
## Code style for anything you write here
|
||||
|
||||
- No `//`, `/* */`, or `///` comments unless the user explicitly asks for
|
||||
comments/documentation in that request. No comments restating self-explanatory code.
|
||||
`EntryPoint.cs`/`Config.cs` are already comment-free — keep them that way and follow
|
||||
the same standard for any new file.
|
||||
- All text embedded in code defaults to **English**: string/log/console messages,
|
||||
exception messages, `[Description]`/config text, any user-facing string. Example:
|
||||
`Logger.Info("Plugin initialized successfully")`, not a Spanish equivalent.
|
||||
- This never applies to identifiers the user picked — project name, namespace,
|
||||
class/method/property/variable names stay exactly as requested (standard C# casing
|
||||
rules aside). Honor an explicit request for a specific piece of text in another
|
||||
language.
|
||||
|
||||
## How to verify a change (no test suite exists — this is the actual check)
|
||||
|
||||
There is no automated test project. Verify any template change by actually
|
||||
generating a project from it and building that output. Replace `<repo-name>` below
|
||||
with this repo's actual folder name (the value you'd see in `sourceName`):
|
||||
|
||||
```bash
|
||||
dotnet new uninstall .
|
||||
dotnet new install .
|
||||
dotnet new labapi-plugin -n VerifyPlugin -o ../_verify/VerifyPlugin
|
||||
cd ../_verify/VerifyPlugin
|
||||
dotnet build
|
||||
```
|
||||
|
||||
Expect `Build succeeded. 0 Warning(s) 0 Error(s)`. If it isn't 0/0, the change broke
|
||||
either the template's own warning suppressions or something in `EntryPoint.cs`/
|
||||
`Config.cs`/the `.csproj`.
|
||||
|
||||
Notes:
|
||||
- Re-run `dotnet new uninstall .` + `dotnet new install .` after **any** edit to
|
||||
`.template.config/template.json` or the scaffolded files — the template cache
|
||||
keys off the installed path and stale content otherwise gets regenerated.
|
||||
- `dotnet build` also works directly inside `<repo-name>` (the placeholder project
|
||||
is itself valid and compilable), but that only proves the *unsubstituted*
|
||||
placeholder compiles — it does not exercise symbol substitution. Always additionally
|
||||
verify through an actual `dotnet new` generation before calling a change done.
|
||||
- On Windows, if cleaning up `../_verify` fails with "resource busy", run
|
||||
`dotnet build-server shutdown` first, then retry.
|
||||
- Delete the `../_verify` scratch output when done; it isn't part of the template.
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace LabApiPluginTemplate
|
||||
{
|
||||
public class Config
|
||||
{
|
||||
[Description("Whether the plugin is enabled.")]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using LabApi.Features.Console;
|
||||
using LabApi.Loader.Features.Plugins;
|
||||
using LabApi.Loader.Features.Plugins.Enums;
|
||||
|
||||
namespace LabApiPluginTemplate
|
||||
{
|
||||
public class EntryPoint : Plugin<Config>
|
||||
{
|
||||
public override string Name => "LabApiPluginTemplate";
|
||||
|
||||
public override string Description => "TODO: describe what this plugin does.";
|
||||
|
||||
public override string Author => "YourName";
|
||||
|
||||
public override Version RequiredApiVersion { get; } = new Version("1.1.7");
|
||||
|
||||
public override LoadPriority Priority => LoadPriority.Medium;
|
||||
|
||||
public override void Enable()
|
||||
{
|
||||
Logger.Info($"{Name} has been enabled.");
|
||||
}
|
||||
|
||||
public override void Disable()
|
||||
{
|
||||
Logger.Info($"{Name} has been disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- .NET Standard 2.1: the most modern ABI that can still be loaded inside the
|
||||
.NET Framework 4.8 / Mono process the SCP:SL dedicated server uses, letting the
|
||||
project use recent C# syntax (see LangVersion) while still producing an
|
||||
assembly compatible with the game's host runtime. -->
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
|
||||
<!-- C# language version explicitly requested by the project. -->
|
||||
<LangVersion>14.0</LangVersion>
|
||||
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<RootNamespace>LabApiPluginTemplate</RootNamespace>
|
||||
<AssemblyName>LabApiPluginTemplate</AssemblyName>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
|
||||
<!-- Northwood.LabAPI only ships net48/net481 binaries. Restoring it into a
|
||||
netstandard2.1 project makes NuGet fall back to that asset group and raise
|
||||
NU1701 to flag it. That's expected and safe here (the resulting assembly is
|
||||
still loaded by the server's .NET Framework/Mono runtime either way), so this
|
||||
suppresses just that one warning and only for this package. -->
|
||||
<NoWarn>$(NoWarn);NU1701</NoWarn>
|
||||
|
||||
<!-- LabAPI's prebuilt assembly (and the game's own managed assemblies it depends
|
||||
on) are built for .NET Framework, which on some SDK/platform combinations
|
||||
triggers a processor-architecture mismatch warning (MSB3270) when resolving
|
||||
references. It isn't an actual runtime problem, so this turns off just that
|
||||
specific check instead of every MSBuild warning. -->
|
||||
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Northwood.LabAPI" Version="1.1.7">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user