# Facepunch.Steamworks: a C# Steamworks wrapper for Unity and .NET games

> Facepunch.Steamworks wraps Valve's Steamworks API in idiomatic C# so Unity and standalone .NET builds can call Steam features without a third-party native dll. It fits teams already shipping on Steam; it is not a general networking library.

**Facepunch/Facepunch.Steamworks** — Another fucking c# Steamworks implementation

- Repository: https://github.com/Facepunch/Facepunch.Steamworks
- Stars: 3,770 · Forks: 438
- Language: C#
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/facepunch-facepunch-steamworks

## The problem Facepunch.Steamworks solves for Steam-bound C# games

Valve ships Steamworks as a C++ SDK. A C# project that wants achievements, friends, cloud saves or workshop items either writes its own bindings or takes an existing wrapper. The README is blunt about why this one exists: the author states the Unity-compatible C# implementations he found were "not C#" but "just a collection of functions", were out of date, required a third-party native dll, could not be compiled into a standalone dll in Unity, were not free, or carried a restrictive licence.

The audience follows from that list. It is teams building a game in C# who intend to ship on Steam, and who want the Steam surface expressed as classes and async methods rather than flat exported functions. Unity is a first-class target: the repository carries a UnityPlugin/ directory alongside the main solution, and the feature table marks Unity and Unity IL2CPP support. Standalone .NET builds are covered too, since the table claims a single C# dll with "no native requirements apart from Steam". If you are not distributing through Steam, none of this applies to you.

## How the wrapper is put together and how calls flow

The repository is a solution with three parts worth knowing: Facepunch.Steamworks/ holds the library, Generator/ holds a code generator, and Facepunch.Steamworks.Test/ holds tests. The Generator/ directory is the structural tell. Steamworks is a large, versioned C++ surface, and hand-maintaining bindings for every interface would rot quickly. Generating the interop layer from the SDK means the C# side can be regenerated when Valve moves, which is a more honest answer to the "not up to date" complaint than a promise in a README.

At runtime the wrapper presents two interaction styles, and the README's feature table names both: "Async Callbacks (steam callresults)" and "Events (steam callbacks)". Callresults become awaitable methods, so SteamApps.GetFileDetailsAsync returns a value you await rather than a callback you register. Steam callbacks become events, as in SteamServer.OnValidateAuthTicketResponse. That split matters when you are deciding where Steam code lives in your game loop: awaits fit loading screens and menus, events fit long-lived session state on a server.

The API is organised by Steam's own domains rather than by a new abstraction. SteamClient, SteamFriends, SteamApps, SteamUserStats, SteamUser, SteamUtils, SteamUGC, SteamRemoteStorage, SteamInventory and SteamServer each map to a familiar area of Steam. If you have read Valve's documentation, the shape will be recognisable. If you have not, there is little here to shield you from learning what a callresult is.

## Installing Facepunch.Steamworks and a first working call

The README does not contain an install section, so the concrete steps have to be read off the repository layout rather than quoted. What is visible is a solution file, Facepunch.Steamworks.sln, a UnityPlugin/ directory, and a CompileFix.bat at the top level. Teams on plain .NET typically build the solution or consume a built dll from a release; Unity users take the plugin folder. Either way, Steam must be present, because the feature table lists "no native requirements apart from Steam".

Start by opening the solution and building the library project:

```bash
Facepunch.Steamworks.sln
```

Opening the solution in your IDE and building it produces the managed assembly. For Unity, the repository keeps a dedicated plugin directory rather than asking you to assemble one:

```bash
UnityPlugin/
```

Copy that directory's contents into your Unity project's Assets folder. The feature table lists Unity IL2CPP support, so an IL2CPP build is an intended path, not an afterthought.

Once referenced, the smallest useful call is reading your own identity, which the README shows as two properties:

```csharp
SteamClient.SteamId // Your SteamId
SteamClient.Name    // Your Name
```

If those return your account rather than zero or an empty string, the wrapper has initialised and is talking to a running Steam client. A second check that exercises the async path is the friends list, which the README iterates with SteamFriends.GetFriends(). If the enumeration is empty while you are logged in, suspect initialisation order rather than the wrapper.

## Where the abstraction leaks and where it is the wrong tool

The wrapper is a binding, not a reimplementation, and the README's own examples show it. SteamUser.GetAuthSessionTicket returns a ticket that you still have to move from client to server by whatever transport you already use; the README says only "Client sends ticket data to server somehow". The server half is equally manual: you call SteamServer.BeginAuthSession with ticket data and a Steam ID, and handle the response event yourself. Nothing here replaces your networking layer.

The same applies to voice. SteamUser.ReadVoiceData writes into a stream, and the README's comment is "Send Stream Data To Server or Something". That is honest, and it is also the boundary. If you were hoping for a voice chat solution, you get raw bytes and a transport problem.

There is a second limitation in the shape of the API. Because it mirrors Steam's domains, the wrapper inherits Steam's vocabulary: callresults, tickets, UGC queries, inventory definitions. A C# developer who has never integrated Steamworks will not be guided through those concepts by this library. It makes Steam feel like C#; it does not make Steam simple. And the feature table's "Any 32bit OS" row is a claim about the managed assembly, not a statement that every Steam feature behaves identically on every platform.

## Facepunch.Steamworks versus Steamworks.NET

Steamworks.NET is the other widely used C# binding, and the difference is philosophical rather than functional. Steamworks.NET historically tracks Valve's flat C API closely, exposing the same function-oriented surface the C++ SDK has. Facepunch.Steamworks deliberately does not. The README's first complaint about the alternatives is that "they're not C#, they're just a collection of functions", and the library's design follows from that: properties like SteamClient.Name, an awaitable SteamApps.GetFileDetailsAsync, a disposable ServerList.Internet() with AddFilter and RunQueryAsync, and a fluent Ugc.Editor.NewCommunityFile builder that ends in SubmitAsync.

The practical split is who pays the translation cost. With a function-oriented binding, you read Valve's documentation and call the matching function. With Facepunch.Steamworks, you learn this library's idioms and get code that reads like the rest of your C# project. Neither is free. The second approach means your Steam integration is coupled to this project's API decisions, and migrating away later is a rewrite rather than a rename. The README also lists "they require a 3rd party native dll" as a reason for existing, so if your build pipeline is sensitive to extra native binaries, that distinction is worth checking against whichever alternative you are weighing.

## Maintenance, licence and the cost of keeping up

The repository is not archived, and the last push was on 2026-09-15, so the project is being touched. Releases are versioned and recent: 2.5.2 on 2026-04-23, 2.5.1 on 2026-04-20, and 2.5.0 on 2026-02-27. That cadence suggests patch releases between larger ones, but the release notes are not summarised here, so treat them as something to read before upgrading rather than something taken on trust.

The licence is MIT, which the README also lists in its feature table. MIT is permissive: it allows use in closed-source commercial games, and it requires that the copyright notice and licence text be preserved. That is the general shape of the licence, not legal advice, and your own counsel should review distribution obligations, particularly if you are shipping a Unity plugin folder inside a commercial build.

The upgrade cost is the part teams underestimate. This library sits between your game and Valve's SDK, so a Steamworks SDK change can require a regenerated binding, and a wrapper release can change method signatures you already call. The Generator/ directory exists precisely because that surface moves. Pin a version, read the release notes for the version you move to, and keep your Steam integration behind a thin interface of your own so a wrapper upgrade does not ripple through gameplay code.

## Conclusion

Adopt it if you ship a C# or Unity game on Steam and want Steam features behind managed APIs instead of P/Invoke glue. Do not adopt it if you are not on Steam, or if you need the wrapper to stand in for your own netcode. Before committing, verify the Unity plugin layout under UnityPlugin/, confirm which Steamworks SDK version the Generator/ output targets, and check that the release you pick matches the branch you build against.

## FAQ

### How do I install Facepunch.Steamworks in Unity?

The repository keeps a UnityPlugin/ directory alongside the main solution. Copy that directory's contents into your Unity project's Assets folder; the feature table lists Unity and Unity IL2CPP support. Steam itself must be running, since the library has no native requirements apart from Steam.

### What is Facepunch.Steamworks?

It is a C# implementation of the Steamworks API, published under the MIT licence, that wraps Steam features such as friends, achievements, cloud storage, workshop and inventory in managed classes and async methods. The README describes it as an alternative to existing C# Steamworks implementations that it considers out of date or function-oriented.

### How do I use Facepunch.Steamworks?

Reference the built library (or the Unity plugin folder), then call into the Steam domain you need: SteamClient for your own identity, SteamFriends for the friends list, SteamUserStats for achievements, SteamRemoteStorage for cloud files, and SteamUGC for workshop items. Async operations are awaitable, and Steam callbacks are exposed as events.

### Do I need the Steamworks SDK to use Facepunch.Steamworks?

The README states the library is a single C# dll with no native requirements apart from Steam, and that it does not require a third-party native dll. The repository includes a Generator/ directory, which indicates bindings are generated from the Steamworks SDK surface rather than hand-written.

## Sources

- [Facepunch/Facepunch.Steamworks on GitHub](https://github.com/Facepunch/Facepunch.Steamworks)
- [Issues](https://github.com/Facepunch/Facepunch.Steamworks/issues)
- [License: MIT](https://github.com/Facepunch/Facepunch.Steamworks/blob/master/LICENSE)
- [README](https://github.com/Facepunch/Facepunch.Steamworks/blob/master/README.md)
- [Releases](https://github.com/Facepunch/Facepunch.Steamworks/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/facepunch-facepunch-steamworks
