CS2OpenDev.Sdk 1.0.1

This package has a SemVer 2.0.0 package version: 1.0.1+cs.10673343.dump.2026-05-20.
dotnet add package CS2OpenDev.Sdk --version 1.0.1
                    
NuGet\Install-Package CS2OpenDev.Sdk -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CS2OpenDev.Sdk" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CS2OpenDev.Sdk" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="CS2OpenDev.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CS2OpenDev.Sdk --version 1.0.1
                    
#r "nuget: CS2OpenDev.Sdk, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CS2OpenDev.Sdk@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CS2OpenDev.Sdk&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=CS2OpenDev.Sdk&version=1.0.1
                    
Install as a Cake Tool

CS2OpenDev.Sdk

A strongly-typed C# SDK for the Counter-Strike 2 schema system. Every class, struct, and enum that CS2 reflects through its schema runtime is exposed as a C# type, with the original C++ field names and byte offsets preserved as attributes for native interop work.

The SDK is built from the community-enriched CS2OpenDev-Docs mirror of the DumpSource2 schema, pulled in via the upstream/ git submodule. The committed source under src/CS2OpenDev.Sdk/ is the canonical artifact — every file is auto-generated, but the regeneration pipeline lives in this repo so contributors can review what changed when CS2 patches the schema.


Using the SDK

Add the NuGet package to your project:

<PackageReference Include="CS2OpenDev.Sdk" Version="1.0.0" />

Then reference types out of the per-module namespaces. The root namespace is CS2OpenSchema; each schema module gets a child namespace (CS2OpenSchema.Client, CS2OpenSchema.Server, CS2OpenSchema.Common, etc.).

using CS2OpenSchema.Client;

CCSPlayerPawn pawn = new()
{
    Health = 100,
    ArmorValue = 50,
};

Native-interop attributes

Every property carries metadata that lets you bridge from the managed projection back to the native layout:

public partial class CCSPlayerPawn : CCSPlayerPawnBase
{
    [NativeOffset(0x83C)]
    [NativeName("m_iArmor")]
    public int ArmorValue { get; set; }
    // …
}
Attribute Where What it carries
[NativeName("…")] classes, properties, enum members The original C++ identifier as it appears in cs2_schema.json.
[NativeOffset(0x…)] properties Byte offset of the field within its native C++ type.
[NativeSize(N)] classes Informational size in bytes of the native type. Not a P/Invoke marshalling contract — the managed layout isn't required to match.
[NativeMetadata("Key", "Value")] properties, enum members Round-trips schema markers (MPropertyFriendlyName, MNotSaved, MNetworkVar, …) so downstream tooling can read them without re-parsing cs2_schema.json.

The reverse lookup — given a generated C# property name, recover the raw C++ field name without reflection — is available via the static SchemaNames table:

string nativeName = SchemaNames.CCSPlayerPawn.ArmorValue; // "m_iArmor"

Game events

Every .gameevents entry in the upstream registry is emitted as a public sealed record under CS2OpenSchema.Events. Each property's KV1 type tag (string, short, ehandle, player_controller_and_pawn, …) is preserved via [GameEventFieldType("...")] so demo parsers and dispatchers can recover the original wire shape; the C# property type is the SDK's projection of that tag.

using CS2OpenSchema.Events;

PlayerDeathEvent death = new()
{
    Userid = 7,        // KV1 tag: player_controller_and_pawn — raw userid
    Attacker = 12,
    Weapon = "ak47",
    Headshot = true,
    // …every field is `required init`, so the compiler enforces completeness
};

string nativeFieldName = SchemaEvents.PlayerDeathEvent.Weapon;  // "weapon"
string nativeEventName = SchemaEvents.PlayerDeathEvent.EventName; // "player_death"

Cross-file duplicates (15 events that appear in more than one source .gameevents file with different field shapes) follow source priority mod > game > core: the mod variant gets the unsuffixed type, others carry a source-name suffix (e.g. PlayerDeathEvent for the CS2 shape, PlayerDeathCoreEvent for the Source-2-base shape).

Extending generated types

Every class is emitted as public partial class. To add your own methods or properties without losing them on regeneration, declare a partial extension in a different file that doesn't start with // <auto-generated/>:

// MyProject/CCSPlayerPawn.Extensions.cs
namespace CS2OpenSchema.Client;

public partial class CCSPlayerPawn
{
    public bool IsLowHealth => Health < 25;
}

The regeneration pipeline's stale-file sweep uses the // <auto-generated/> marker as the discriminator. Files without it are never touched.


Repo layout

src/
  CS2OpenDev.Sdk/             — the generated SDK (4k+ files; what the NuGet ships)
    Client/, Server/, Common/, …  — one file per reflected class/enum, grouped by module
    Events/                       — one record per `.gameevents` entry (288 events)
    SchemaNames.cs                — reverse-lookup table: C# property → native C++ field
    SchemaEvents.cs               — reverse-lookup table: C# event property → native KV1 name
  CS2OpenDev.Sdk.Generator/   — emitter library (consumes cs2_schema.json + gameevents_schema.json)
  CS2OpenDev.Sdk.Exporter/    — CLI that drives the emitters and writes the SDK to disk
test/
  CS2OpenDev.Sdk.Generator.Tests/
upstream/                      — git submodule → CS2OpenDev-Docs (refreshed every 4h upstream)
  docs/generated/downstream-codegen-schemas/
    cs2_schema.json            — entity classes/enums/fields (DumpSource2 mirror)
    gameevents_schema.json     — `.gameevents` registry (KV1)

The SDK targets net8.0 for broad consumer compatibility. The Generator and Exporter target net10.0.


Regenerating the SDK

Initialise the upstream submodule once after cloning:

git submodule update --init upstream

Refresh it to the latest CS2OpenDev-Docs revision (upstream updates every 4 hours) whenever you want a newer schema:

git submodule update --remote upstream

Then regenerate:

dotnet run --project src/CS2OpenDev.Sdk.Exporter

That single command builds the Generator and Exporter as needed, parses the schema, and writes the per-class layout into src/CS2OpenDev.Sdk/. Idempotent — running it twice produces no change.

Optional arguments for non-default paths (e.g. a custom dump or vendored copy):

dotnet run --project src/CS2OpenDev.Sdk.Exporter -- <schema-path> <output-dir>

The Exporter also prunes orphan generated files — classes that disappeared from the schema since the last regen — using the // <auto-generated/> first-line marker to discriminate emitter output from any hand-written partial-class extensions.

Versioning

Package versions follow SemVer 2 with build metadata identifying the upstream schema:

{Generator-MAJOR}.{Generator-MINOR}.{git-height}+cs.{cs2-revision}.dump.{yyyy-MM-dd}
Segment Where it comes from Who bumps it
MAJOR version.json Human — reserved for breaking SDK API changes
MINOR version.json Human — new emitter features
PATCH Git commit height since the last MAJOR.MINOR bump Automatic via Nerdbank.GitVersioning
Build metadata cs2_schema.json Automatic from CI at pack-time

pathFilters in version.json scopes the patch-bumping commits to src/CS2OpenDev.Sdk/ only, so every regen produces a monotonically newer version, while contributions to tests / docs / generator code that don't change the SDK content don't churn the version. Build metadata is informational — NuGet shows it in the package details, but ordering is determined by MAJOR.MINOR.PATCH alone, which is exactly what we want (every regen advances the SortKey).

Continuous integration

Workflow Trigger What it does
ci.yml PRs + pushes to main Build, test, regenerate, fail if the regen output diverges from committed SDK, verify pack succeeds
check-upstream.yml Cron (every 4h) + manual Bump the upstream submodule, regenerate, push to main if anything changed, then invoke the reusable pack-and-publish flow in the same run
release.yml Pushes to main that touch src/CS2OpenDev.Sdk/** or version.json + manual Invokes the reusable pack-and-publish flow (for human-driven version bumps and the post-merge case)
_pack-and-publish.yml workflow_call from the two above Packs the SDK with CS2 build metadata, uploads the .nupkg as a workflow artifact, and pushes to NuGet.org (gated on NUGET_API_KEY)

The bot identity used for automated pushes is CS2OpenDev-bot <bot@CS2OpenDev.invalid>. check-upstream.yml calls the publish workflow as a dependent job in the same run (via workflow_call) rather than relying on its push to fire release.yml — that's because GitHub blocks workflow-triggered pushes authenticated with the default GITHUB_TOKEN from triggering downstream workflows, and we'd rather skip the PAT-rotation burden.

To enable NuGet.org publishing, add a NUGET_API_KEY secret in Settings → Secrets and variables → Actions. Without it, the package is still built on every run and uploaded as a workflow artifact (downloadable from the run page) — useful for forks and during initial setup.

What ends up in the published artifact

NuGet's package filename uses only the SemVer 2 MAJOR.MINOR.PATCH segment — so 1.0.42+cs.10673343.dump.2026-05-20 is filed as CS2OpenDev.Sdk.1.0.42.nupkg. The build metadata is preserved inside the package's AssemblyInformationalVersion (visible via reflection or dotnet --info-style inspection), so consumers can recover which CS2 build their installed SDK was generated from without unpacking the nupkg.

Build commands

Task Command
Restore + build everything dotnet build
Build the generated SDK only dotnet build src/CS2OpenDev.Sdk
Run the test suite dotnet run --project test/CS2OpenDev.Sdk.Generator.Tests/
Run one test dotnet run --project test/CS2OpenDev.Sdk.Generator.Tests/ -- --treenode-filter "/*/*/*/TestName"
Regenerate the SDK dotnet run --project src/CS2OpenDev.Sdk.Exporter

The repo uses TUnit on the Microsoft Testing Platform; invoke tests with dotnet run, not dotnet test.

Diagnostics emitted by the regen pipeline

ID Severity Meaning
CS2_GEN_001 Error cs2_schema.json failed to parse. The Exporter exits with status 1.
CS2_GEN_002 Warning Both output/schemas.json and a repo-root schemas.json exist (legacy local-cache paths); the resolver chose the dump-layout copy. The new upstream submodule path is preferred when present.
CS2_GEN_003 Info A schema atomic type fell through every classification branch in TypeMapper. It was emitted as an empty stub class; adding it to the right set in TypeMapper.cs gives it a real C# projection.

Working on the generator

If you're changing how types are named, mapped, or emitted, the architecture lives in src/CS2OpenDev.Sdk.Generator/:

  • Emitters/ModuleEmitter.cs — the choke point. EmitAll(IGeneratorSink, SchemaRoot, ns) orchestrates classification (per-module vs Common), conflict propagation, per-class file emission, stub collection, and SchemaNames emission.
  • Emitters/ClassEmitter.cs / EnumEmitter.cs / SyntheticTypes.cs — produce one type's source. They append to a StringBuilder and return it; ModuleEmitter hands the result to the sink.
  • Emitters/TypeMapper.cs — C++ atomic type → C# type mapping. Adding a new atomic classification branch in MapAtomicCore must be mirrored in IsKnownAtomicName and (if it surfaces an inner type) AtomicProjectionUsesInner / AtomicProjectionUsesInner2.
  • Emitters/NameHelpers.cs — single source of truth for identifier/filename normalisation (Hungarian-prefix stripping, suffix handling, sanitisation).
  • IGeneratorSink.cs — output abstraction. The Exporter's DiskSink writes to the source tree; tests use a CapturingSink that retains output in memory.

Workflow: edit the relevant emitter, run the test suite, regenerate, review the SDK diff. The Exporter doesn't carry a parallel naming path — there's exactly one source of truth.


License

GPL-3.0 — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 31 5/22/2026