{"id":15160339,"url":"https://github.com/facepunch/facepunch.steamworks","last_synced_at":"2025-05-11T03:39:54.784Z","repository":{"id":40345269,"uuid":"62737176","full_name":"Facepunch/Facepunch.Steamworks","owner":"Facepunch","description":"Another fucking c# Steamworks implementation","archived":false,"fork":false,"pushed_at":"2025-03-20T21:44:21.000Z","size":68123,"stargazers_count":3160,"open_issues_count":193,"forks_count":377,"subscribers_count":75,"default_branch":"master","last_synced_at":"2025-05-11T03:39:38.666Z","etag":null,"topics":["cloud","dll","facepunch","game","steamworks","unity"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Facepunch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-06T16:38:16.000Z","updated_at":"2025-05-09T06:42:32.000Z","dependencies_parsed_at":"2023-02-08T04:45:15.900Z","dependency_job_id":"49532607-a47e-4e67-a9b6-d2ef1616aa5d","html_url":"https://github.com/Facepunch/Facepunch.Steamworks","commit_stats":{"total_commits":1158,"total_committers":76,"mean_commits":"15.236842105263158","dds":"0.49136442141623493","last_synced_commit":"eec3c05ecd402ee5a8a947bbfa327ba9114caba2"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Facepunch%2FFacepunch.Steamworks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Facepunch%2FFacepunch.Steamworks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Facepunch%2FFacepunch.Steamworks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Facepunch%2FFacepunch.Steamworks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Facepunch","download_url":"https://codeload.github.com/Facepunch/Facepunch.Steamworks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253514526,"owners_count":21920333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud","dll","facepunch","game","steamworks","unity"],"created_at":"2024-09-26T22:44:19.688Z","updated_at":"2025-05-11T03:39:54.764Z","avatar_url":"https://github.com/Facepunch.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Facepunch.Steamworks\n\n[Another fucking c# Steamworks implementation](https://wiki.facepunch.com/steamworks/)\n\n![Build All](https://github.com/Facepunch/Facepunch.Steamworks/workflows/Build%20All/badge.svg)\n\n## Features\n\n| Feature | Supported |\n|----------|------------ |\n| Windows | ✔ |\n| Linux | ✔ |\n| MacOS | ✔ |\n| Unity Support | ✔ |\n| Unity IL2CPP Support | ✔ |\n| Async Callbacks (steam callresults) | ✔ |\n| Events (steam callbacks) | ✔ |\n| Single C# dll (no native requirements apart from Steam) | ✔ |\n| Open Source | ✔ |\n| MIT license | ✔ |\n| Any 32bit OS | ✔  |\n\n## Why\n\nThe Steamworks C# implementations I found that were compatible with Unity have worked for a long time. But I hate them all. For a number of different reasons.\n\n* They're not C#, they're just a collection of functions.\n* They're not up to date.\n* They require a 3rd party native dll.\n* They can't be compiled into a standalone dll (in Unity).\n* They're not free\n* They have a restrictive license.\n\nC# is meant to make things easier. So lets try to wrap it up in a way that makes it all easier.\n\n## What\n\n### Get your own information\n\n```csharp\n    SteamClient.SteamId // Your SteamId\n    SteamClient.Name // Your Name\n```\n\n### View your friends list\n\n```csharp\nforeach ( var friend in SteamFriends.GetFriends() )\n{\n    Console.WriteLine( $\"{friend.Id}: {friend.Name}\" );\n    Console.WriteLine( $\"{friend.IsOnline} / {friend.SteamLevel}\" );\n    \n    friend.SendMessage( \"Hello Friend\" );\n}\n```\n\n\n### App Info\n\n```csharp\n    Console.WriteLine( SteamApps.GameLanguage ); // Print the current game language\n    var installDir = SteamApps.AppInstallDir( 4000 ); // Get the path to the Garry's Mod install folder\n\n    var fileinfo = await SteamApps.GetFileDetailsAsync( \"hl2.exe\" ); // async get file details\n    DoSomething( fileinfo.SizeInBytes, fileinfo.Sha1 );\n```\n\n### Get Avatars\n\n```csharp\n    var image = await SteamFriends.GetLargeAvatarAsync( steamid );\n    if ( !image.HasValue ) return DefaultImage;\n\n    return MakeTextureFromRGBA( image.Value.Data, image.Value.Width, image.Value.Height );\n```\n\n### Get a list of servers\n\n```csharp\nusing ( var list = new ServerList.Internet() )\n{\n    list.AddFilter( \"map\", \"de_dust\" );\n    await list.RunQueryAsync();\n\n    foreach ( var server in list.Responsive )\n    {\n        Console.WriteLine( $\"{server.Address} {server.Name}\" );\n    }\n}\n```\n\n### Achievements\n\nList them\n\n```csharp\n    foreach ( var a in SteamUserStats.Achievements )\n    {\n        Console.WriteLine( $\"{a.Name} ({a.State})\" );\n    }\t\n```\n\nUnlock them\n\n```csharp\n    var ach = new Achievement( \"GM_PLAYED_WITH_GARRY\" );\n    ach.Trigger();\n```\n\n### Voice\n\n```csharp\n    SteamUser.VoiceRecord = KeyDown( \"V\" );\n\n    if ( SteamUser.HasVoiceData )\n    {\n        var bytesrwritten = SteamUser.ReadVoiceData( stream );\n        // Send Stream Data To Server or Something\n    }\n```\n\n\n### Auth\n\n```csharp\n    // Client sends ticket data to server somehow\n    var ticket = SteamUser.GetAuthSessionTicket();\n\n    // server listens to event\n    SteamServer.OnValidateAuthTicketResponse += ( steamid, ownerid, rsponse ) =\u003e\n    {\n        if ( rsponse == AuthResponse.OK )\n            TellUserTheyCanBeOnServer( steamid );\n        else\n            KickUser( steamid );\n    };\n\n    // server gets ticket data from client, calls this function.. which either returns\n    // false straight away, or will issue a TicketResponse.\n    if ( !SteamServer.BeginAuthSession( ticketData, clientSteamId ) )\n    {\n        KickUser( clientSteamId );\n    }\n\n    //\n    // Client is leaving, cancels their ticket OnValidateAuth is called on the server again\n    // this time with AuthResponse.AuthTicketCanceled\n    //\n    ticket.Cancel();\n```\n\n### Utils\n\n```csharp\n    SteamUtils.SecondsSinceAppActive;\n    SteamUtils.SecondsSinceComputerActive;\n    SteamUtils.IpCountry;\n    SteamUtils.UsingBatteryPower;\n    SteamUtils.CurrentBatteryPower;\n    SteamUtils.AppId;\n    SteamUtils.IsOverlayEnabled;\n    SteamUtils.IsSteamRunningInVR;\n    SteamUtils.IsSteamInBigPictureMode;\n```\n\n### Workshop\n\nDownload a workshop item by ID\n\n```csharp\n    SteamUGC.Download( 1717844711 );\n```\n\nGet a workshop item information\n\n```csharp\n    var itemInfo = await Ugc.Item.Get( 1720164672 );\n\n    Console.WriteLine( $\"Title: {itemInfo?.Title}\" );\n    Console.WriteLine( $\"IsInstalled: {itemInfo?.IsInstalled}\" );\n    Console.WriteLine( $\"IsDownloading: {itemInfo?.IsDownloading}\" );\n    Console.WriteLine( $\"IsDownloadPending: {itemInfo?.IsDownloadPending}\" );\n    Console.WriteLine( $\"IsSubscribed: {itemInfo?.IsSubscribed}\" );\n    Console.WriteLine( $\"NeedsUpdate: {itemInfo?.NeedsUpdate}\" );\n    Console.WriteLine( $\"Description: {itemInfo?.Description}\" );\n```\n\nQuery a list of workshop items\n\n```csharp\n    var q = Ugc.Query.All\n                    .WithTag( \"Fun\" )\n                    .WithTag( \"Movie\" )\n                    .MatchAllTags();\n\n    var result = await q.GetPageAsync( 1 );\n\n    Console.WriteLine( $\"ResultCount: {result?.ResultCount}\" );\n    Console.WriteLine( $\"TotalCount: {result?.TotalCount}\" );\n\n    foreach ( Ugc.Item entry in result.Value.Entries )\n    {\n        Console.WriteLine( $\"{entry.Title}\" );\n    }\n```\n\nQuery items created by friends\n\n```csharp\n    var q = Ugc.UserQuery.All\n                        .CreatedByFriends();\n```\n\nQuery items created by yourself\n\n```csharp\n    var q = Ugc.UserQuery.All\n                        .FromSelf();\n```\n\nPublish your own file\n\n```csharp\n    var result = await Ugc.Editor.NewCommunityFile\n                      .WithTitle( \"My New FIle\" )\n                      .WithDescription( \"This is a description\" )\n                      .WithContent( \"c:/folder/addon/location\" )\n                      .WithTag( \"awesome\" )\n                      .WithTag( \"small\" )\n                      .SubmitAsync( iProgressBar );\n```\n\n### Steam Cloud\n\nWrite a cloud file\n\n```csharp\n    SteamRemoteStorage.FileWrite( \"file.txt\", fileContents );\n```\n\nRead a cloud file\n\n```csharp\n    var fileContents = SteamRemoteStorage.FileRead( \"file.txt\" );\n```\n\nList all files\n\n```csharp\n    foreach ( var file in SteamRemoteStorage.Files )\n    {\n        Console.WriteLine( $\"{file} ({SteamRemoteStorage.FileSize(file)} {SteamRemoteStorage.FileTime( file )})\" );\n    }\n```\n\n\n### Steam Inventory\n\nGet item definitions\n\n```csharp\n    foreach ( InventoryDef def in SteamInventory.Definitions )\n    {\n        Console.WriteLine( $\"{def.Name}\" );\n    }\n```\n\nGet items that are for sale in the item shop\n\n```csharp\n    var defs = await SteamInventory.GetDefinitionsWithPricesAsync();\n\n    foreach ( var def in defs )\n    {\n        Console.WriteLine( $\"{def.Name} [{def.LocalPriceFormatted}]\" );\n    }\n```\n\nGet a list of your items\n\n```csharp\n    var result = await SteamInventory.GetItems();\n\n    // result is disposable, good manners to dispose after use\n    using ( result )\n    {\n        var items = result?.GetItems( bWithProperties );\n\n        foreach ( InventoryItem item in items )\n        {\n            Console.WriteLine( $\"{item.Id} / {item.Quantity} / {item.Def.Name} \" );\n        }\n    }\n```\n\n# Getting Started\n\n## Client\n\nTo initialize a client you can do this.\n\n```csharp\nusing Steamworks;\n\n// ...\n\ntry \n{\n    SteamClient.Init( 4000 );\n}\ncatch ( System.Exception e )\n{\n    // Couldn't init for some reason (steam is closed etc)\n}\n```\n\nReplace 4000 with the appid of your game. You shouldn't call any Steam functions before you initialize.\n\nWhen you're done, when you're closing your game, just shutdown.\n\n```csharp\nSteamClient.Shutdown();\n```\n\n## Server\n\nTo create a server do this.\n\n```csharp\nvar serverInit = new SteamServerInit( \"gmod\", \"Garry Mode\" )\n{\n    GamePort = 28015,\n    Secure = true,\n    QueryPort = 28016\n};\n\ntry\n{\n    Steamworks.SteamServer.Init( 4000, serverInit );\n}\ncatch ( System.Exception )\n{\n    // Couldn't init for some reason (dll errors, blocked ports)\n}\n```\n\n# Help\n\nWanna help? Go for it, pull requests, bug reports, yes, do it.\n\nYou can also hit up the [Steamworks Thread](http://steamcommunity.com/groups/steamworks/discussions/0/1319961618833314524/) for help/discussion.\n\nWe also have [a wiki you can read](https://wiki.facepunch.com/steamworks/) and help fill out with examples and advice.\n\n# License\n\nMIT - do whatever you want.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffacepunch%2Ffacepunch.steamworks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffacepunch%2Ffacepunch.steamworks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffacepunch%2Ffacepunch.steamworks/lists"}