Facepunch.Steamworks/README.md

355 lines
8.0 KiB
Markdown
Raw Normal View History

2016-10-03 22:41:41 +03:00
# Facepunch.Steamworks
Another fucking c# Steamworks implementation
[![Build Status](http://build.facepunch.com/buildStatus/icon?job=Facepunch/Facepunch.Steamworks/master)](http://build.facepunch.com/job/Facepunch/job/Facepunch.Steamworks/job/master/)
2019-04-30 14:58:47 +03:00
## Features
| Feature | Supported |
|----------|------------ |
| Windows | ✔ |
| Linux | ✔ |
| MacOS | ✔ |
| Unity Support | ✔ |
| Unity IL2CPP Support | ✔ |
| Async Callbacks (steam callresults) | ✔ |
| Events (steam callbacks) | ✔ |
| Single C# dll (no native requirements apart from Steam) | ✔ |
| Open Source | ✔ |
| MIT license | ✔ |
| Any 32bit OS | ❌ |
2016-10-03 22:41:41 +03:00
## Why
The 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.
* They're not C#, they're just a collection of functions.
* They're not up to date.
* They require a 3rd party native dll.
* They can't be compiled into a standalone dll (in Unity).
2019-04-30 14:58:47 +03:00
* They're not free
* They have a restrictive license.
2016-10-03 22:41:41 +03:00
C# is meant to make things easier. So lets try to wrap it up in a way that makes it all easier.
## What
2019-04-16 23:51:54 +03:00
### Get your own information
2016-10-03 22:41:41 +03:00
```csharp
2019-04-30 23:19:13 +03:00
SteamClient.SteamId // Your SteamId
SteamClient.Name // Your Name
2019-04-16 23:51:54 +03:00
```
### View your friends list
```csharp
foreach ( var friend in SteamFriends.GetFriends() )
2016-10-03 22:41:41 +03:00
{
2019-04-16 23:51:54 +03:00
Console.WriteLine( "{friend.Id}: {friend.Name}" );
Console.WriteLine( "{friend.IsOnline} / {friend.SteamLevel}" );
friend.SendMessage( "Hello Friend" );
2016-10-03 22:41:41 +03:00
}
```
2019-04-16 23:51:54 +03:00
### App Info
```csharp
2019-04-30 23:19:13 +03:00
Console.WriteLine( SteamApps.GameLanguage ); // Print the current game language
var installDir = SteamApps.AppInstallDir( 4000 ); // Get the path to the Garry's Mod install folder
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
var fileinfo = await SteamApps.GetFileDetailsAsync( "hl2.exe" ); // async get file details
DoSomething( fileinfo.SizeInBytes, fileinfo.Sha1 );
2019-04-16 23:51:54 +03:00
```
### Get Avatars
```csharp
2019-04-30 23:19:13 +03:00
var image = await SteamFriends.GetLargeAvatarAsync( steamid );
if ( !image.HasValue ) return DefaultImage;
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
return MakeTextureFromRGBA( image.Data, image.Width, image.Height );
2019-04-16 23:51:54 +03:00
```
### Get a list of servers
```csharp
using ( var list = new ServerList.Internet() )
{
list.AddFilter( "map", "de_dust" );
await list.RunQueryAsync();
foreach ( var server in list.Responsive )
{
Console.WriteLine( $"{server.Address} {server.Name}" );
}
}
```
### Achievements
List them
```csharp
2019-04-30 23:19:13 +03:00
foreach ( var a in SteamUserStats.Achievements )
{
Console.WriteLine( $"{a.Name} ({a.State}})" );
}
2019-04-16 23:51:54 +03:00
```
Unlock them
```csharp
2019-04-30 23:19:13 +03:00
var ach = new Achievement( "GM_PLAYED_WITH_GARRY" );
ach.Trigger();
2019-04-16 23:51:54 +03:00
```
### Voice
```csharp
2019-04-30 23:19:13 +03:00
SteamUser.VoiceRecord = KeyDown( "V" );
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
if ( SteamUser.HasVoiceData )
{
var bytesrwritten = SteamUser.ReadVoiceData( stream );
// Send Stream Data To Server or Something
}
```
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
### Auth
```csharp
// Client sends ticket data to server somehow
var ticket = SteamUser.GetAuthSessionTicket();
// server listens to event
SteamServer.OnValidateAuthTicketResponse += ( steamid, ownerid, rsponse ) =>
{
if ( rsponse == AuthResponse.OK )
TellUserTheyCanBeOnServer( steamid );
else
KickUser( steamid );
};
// server gets ticket data from client, calls this function.. which either returns
// false straight away, or will issue a TicketResponse.
if ( !SteamServer.BeginAuthSession( ticketData, clientSteamId ) )
{
KickUser( clientSteamId );
}
//
// Client is leaving, cancels their ticket OnValidateAuth is called on the server again
// this time with AuthResponse.AuthTicketCanceled
//
ticket.Cancel();
```
### Utils
```csharp
SteamUtils.SecondsSinceAppActive;
SteamUtils.SecondsSinceComputerActive;
SteamUtils.IpCountry;
SteamUtils.UsingBatteryPower;
SteamUtils.CurrentBatteryPower;
SteamUtils.AppId;
SteamUtils.IsOverlayEnabled;
SteamUtils.IsSteamRunningInVR;
SteamUtils.IsSteamInBigPictureMode;
2019-04-16 23:51:54 +03:00
```
2019-04-30 23:19:13 +03:00
### Workshop
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
Download a workshop item by ID
2019-04-16 23:51:54 +03:00
```csharp
2019-04-30 23:19:13 +03:00
SteamUGC.Download( 1717844711 );
```
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
Get a workshop item information
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
```csharp
var itemInfo = await Ugc.Item.Get( 1720164672 );
Console.WriteLine( $"Title: {itemInfo?.Title}" );
Console.WriteLine( $"IsInstalled: {itemInfo?.IsInstalled}" );
Console.WriteLine( $"IsDownloading: {itemInfo?.IsDownloading}" );
Console.WriteLine( $"IsDownloadPending: {itemInfo?.IsDownloadPending}" );
Console.WriteLine( $"IsSubscribed: {itemInfo?.IsSubscribed}" );
Console.WriteLine( $"NeedsUpdate: {itemInfo?.NeedsUpdate}" );
Console.WriteLine( $"Description: {itemInfo?.Description}" );
```
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
Query a list of workshop items
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
```csharp
var q = Ugc.Query.All
.WithTag( "Fun" )
.WithTag( "Movie" )
.MatchAllTags();
var result = await q.GetPageAsync( 1 );
Console.WriteLine( $"ResultCount: {result?.ResultCount}" );
Console.WriteLine( $"TotalCount: {result?.TotalCount}" );
foreach ( Ugc.Item entry in result.Value.Entries )
{
Console.WriteLine( $" {entry.Title}" );
}
```
Query items created by friends
2019-04-16 23:51:54 +03:00
2019-04-30 23:19:13 +03:00
```csharp
var q = Ugc.UserQuery.All
.CreatedByFriends();
2016-10-03 22:41:41 +03:00
```
2019-04-30 23:19:13 +03:00
Query items created by yourself
2019-04-16 23:51:54 +03:00
```csharp
2019-04-30 23:19:13 +03:00
var q = Ugc.UserQuery.All
.FromSelf();
```
Publish your own file
```csharp
var result = await Ugc.Editor.NewCommunityFile
.WithTitle( "My New FIle" )
.WithDescription( "This is a description" )
.WithContent( "c:/folder/addon/location" )
.WithTag( "awesome" )
.WithTag( "small" )
.SubmitAsync( iProgressBar );
```
### Steam Cloud
Write a cloud file
```csharp
SteamRemoteStorage.FileWrite( "file.txt", fileContents );
```
Read a cloud file
```csharp
var fileContents = SteamRemoteStorage.ReadFile( "file.txt" );
```
List all files
```csharp
foreach ( var file in SteamRemoteStorage.Files )
{
Console.WriteLine( $"{file} ({SteamRemoteStorage.FileSize(file)} {SteamRemoteStorage.FileTime( file )})" );
}
```
### Steam Inventory
Get item definitions
```csharp
foreach ( InventoryDef def in SteamInventory.Definitions )
{
Console.WriteLine( $"{def.Name}" );
}
```
Get items that are for sale in the item shop
```csharp
var defs = await SteamInventory.GetDefinitionsWithPricesAsync();
foreach ( var def in defs )
{
Console.WriteLine( $"{def.Name} [{def.LocalPriceFormatted}]" );
}
```
Get a list of your items
```csharp
var result = await SteamInventory.GetItems();
// result is disposable, good manners to dispose after use
using ( result )
{
var items = result?.GetItems( bWithProperties );
foreach ( InventoryItem item in items )
{
Console.WriteLine( $"{item.Id} / {item.Quantity} / {item.Def.Name} " );
}
}
2019-04-16 23:51:54 +03:00
```
2016-10-03 22:41:41 +03:00
2019-04-30 23:19:13 +03:00
# Getting Started
2016-10-03 22:41:41 +03:00
## Client
2019-04-16 23:56:29 +03:00
To initialize a client you can do this.
2016-10-03 22:41:41 +03:00
```csharp
2019-04-16 23:56:29 +03:00
using Steamworks;
2017-03-13 23:08:03 +03:00
2019-04-16 23:56:29 +03:00
// ...
2016-10-03 22:41:41 +03:00
2019-04-16 23:56:29 +03:00
try
{
SteamClient.Init( 4000 );
}
catch ( System.Exception e )
{
// Couldn't init for some reason (steam is closed etc)
}
2016-10-03 22:41:41 +03:00
```
2019-04-16 23:56:29 +03:00
Replace 4000 with the appid of your game. You shouldn't call any Steam functions before you initialize.
2016-10-03 22:41:41 +03:00
2019-04-16 23:56:29 +03:00
When you're done, when you're closing your game, just shutdown.
```csharp
2019-04-16 23:56:29 +03:00
SteamClient.Shutdown();
2016-10-03 22:41:41 +03:00
```
2019-04-16 23:56:29 +03:00
## Server
2017-08-01 09:54:32 +03:00
2019-04-16 23:56:29 +03:00
To create a server do this.
2017-08-01 09:54:32 +03:00
```csharp
2019-04-16 23:56:29 +03:00
var serverInit = new SteamServerInit( "gmod", "Garry Mode" )
2017-08-01 09:54:32 +03:00
{
2019-04-16 23:56:29 +03:00
GamePort = 28015,
Secure = true,
QueryPort = 28016
2017-08-01 09:54:32 +03:00
};
2017-03-23 12:31:29 +03:00
2019-04-16 23:56:29 +03:00
try
{
Steamworks.SteamServer.Init( 4000, serverInit );
}
catch ( System.Exception )
{
// Couldn't init for some reason (dll errors, blocked ports)
}
2017-03-23 12:31:29 +03:00
```
2016-10-03 22:41:41 +03:00
# Help
Wanna help? Go for it, pull requests, bug reports, yes, do it.
You can also hit up the [Steamworks Thread](http://steamcommunity.com/groups/steamworks/discussions/0/1319961618833314524/) for help/discussion.
2016-10-03 22:41:41 +03:00
# License
MIT - do whatever you want.