Skip to content

feat(project): support projects that reference the Metaplay SDK as NuGet packages - #260

Draft
petrikero wants to merge 2 commits into
mainfrom
feat/sdk-packages
Draft

petrikero wants to merge 2 commits into
mainfrom
feat/sdk-packages

Conversation

@petrikero

@petrikero petrikero commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds a package mode: a project whose metaplay-project.yaml has no sdkRootDir references the Metaplay SDK as NuGet packages instead of having it in a MetaplaySDK/ directory. The CLI then reads the SDK version from the project, and takes the SDK files it needs from the Metaplay.Server package. No step needs .NET on the host.

The rationale, the design and the plan are on the SDK side, in metaplay/sdk#8872 and its docs/plans/2026-10-29-sdk-binary-delivery.md. That PR adds the packages, which this mode reads.

Draft: it goes together with metaplay/sdk#8872.

Changes

  • metaplay-project.yaml: sdkRootDir is optional. Without it, the project uses package mode (MetaplayProject.UsesSdkPackages()).
  • The SDK version is the MetaplaySDKVersion property in the project root's Directory.Build.props.
    • The CLI reads it as a literal from the XML, without evaluating MSBuild.
    • A missing value, a duplicate, an MSBuild expression or a condition is an error with a suggestion.
  • The SDK files come from the sdk/ directory of the Metaplay.Server package at that version (pkg/metaproj/sdk_package.go). It contains version.yaml, Dockerfile.server and the files the image build copies, and the web client presets. The CLI looks in two places, in order:
    1. The project's local package source, NuGetPackages/Metaplay.Server.<version>.nupkg. The CLI unpacks only sdk/ into its cache (<user cache>/metaplay/sdk-packages/), and unpacks again when the package file's size or modification time changes.
    2. NuGet's package cache ($NUGET_PACKAGES or ~/.nuget/packages), once NuGet's .nupkg.metadata marker shows it has finished extracting the package.
  • ResolveSdkDir() returns that directory, or sdkRootDir for a project with one. SdkMetadata(), build image and deploy webclient use it, so a failure to find the SDK is reported as an error.
  • build image in package mode passes the package's Dockerfile.server with -f, and its sdk/ directory with --build-context sdk=<dir>, which replaces the Dockerfile's sdk stage. Projects with sdkRootDir build as before.
  • A conflicting source SDK is an error. If a package-mode project also has MetaplaySDK/Backend/Metaplay.SourceReferences.targets, package mode fails. That file comes only with the SDK's sources, and a project's Directory.Build.targets imports it to build against them, so the build would use those sources while the CLI and the image use the packages. The error suggests setting sdkRootDir: MetaplaySDK or removing MetaplaySDK/.
  • Commands that need the SDK's sources refuse in package mode with an explicit error: update sdk, test system, test dotnet-unit, init dashboard and dev clean-dashboard-artifacts.

Not in this PR:

  • an embedded table of SDK release metadata with a major-version gate;
  • downloading the package from nuget.org;
  • package-mode support in the commands that now refuse.

Testing

  • Unit tests in pkg/metaproj:
    • the literal property parsing (7 cases);
    • unpacking from a local package;
    • the NuGet cache path, before and after the completion marker;
    • the not-found error;
    • the conflicting source SDK;
    • RequireSdkSources;
    • a project config without sdkRootDir.
  • go test ./... passes, and make reports 0 lint issues.
  • Against a Blazor game template published with the SDK as packages (metaplay/sdk#8872), starting from an empty NuGet cache:
    • metaplay build image with no dotnet on PATH: built in 1 m 43 s, of which unpacking sdk/ took 37 ms.
    • metaplay test integration: passed.
    • metaplay dev server: read the version metadata from the package and served the LiveOps Dashboard.
    • metaplay test system and metaplay update sdk: refused with the new error.
    • With MetaplaySDK/Backend/Metaplay.SourceReferences.targets added, metaplay build image failed with the conflicting-SDK error. With only MetaplaySDK/Backend/Cloud/Metaplay.Cloud.csproj added, it did not fail.
  • The NuGet cache path: with NuGetPackages/ moved aside, metaplay build image found the SDK files in NuGet's package cache.
  • Source mode: a monorepo project with sdkRootDir built its server image as before, in 2 m 16 s.

…Get packages

A project whose metaplay-project.yaml has no 'sdkRootDir' references the SDK as
NuGet packages instead of having it in a directory.

- The SDK version is the MetaplaySDKVersion property in the project's
  Directory.Build.props, read as a literal without evaluating MSBuild.
- The SDK files the CLI reads (version.yaml, Dockerfile.server and the files the
  image build copies, the web client presets) come from the sdk/ directory of
  the Metaplay.Server package at that version: from the project's NuGetPackages/
  local package source, unpacked into the CLI's cache, or else from NuGet's
  package cache. No step needs .NET.
- 'build image' passes the package's Dockerfile.server with -f, and its sdk/
  directory as the build context 'sdk'.
- When MetaplaySDK/ also has the SDK's sources, package mode fails, because the
  build would use those sources while the CLI and the image use the packages.
- 'update sdk', 'test system', 'test dotnet-unit', 'init dashboard' and
  'dev clean-dashboard-artifacts' need the SDK's sources, and refuse in package
  mode.
- 'sdkRootDir' is no longer required in metaplay-project.yaml.
…rgets

A project builds against the SDK's sources when its Directory.Build.targets
imports MetaplaySDK/Backend/Metaplay.SourceReferences.targets, which only the
sources have. Check for that file instead of Metaplay.Cloud.csproj, so that the
CLI and the build agree on the mode.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant